rivo
Version:
🤖 The ultimate library you need for composable type-level programming in TypeScript, powered by HKT.
63 lines (59 loc) • 2.18 kB
TypeScript
import type { Nat } from ".";
import type { _AddDigit } from "./internal/_AddDigit";
import type { _CompareDigit } from "./internal/_CompareDigit";
import type { _RemoveStrPaddingZeroes } from "./internal/_RemoveStrPaddingZeroes";
import type { _SubDigit } from "./internal/_SubDigit";
import type { Digit } from "..";
import type { Arg0, Arg1, Fn } from "../../HKT";
import type { Reverse } from "../../Str/Reverse";
import type { EQ, GT } from "../../typeclass/Ord";
import type { _StrToNum } from "../internal/_StrToNum";
/**
* Subtract two {@link Nat}s.
*
* Sig: `(n: Nat, m: Nat) => Nat`
*
* **⚠️ Warning:** `N` must be greater than or equal to `M`.
*/
export type Sub<N extends Nat, M extends Nat> = _StrToNum<SSub<`${N}`, `${M}`>>;
/**
* Subtract two string representations of {@link Nat}s.
*
* **⚠️ Warning:** `N` must be greater than or equal to `M`.
* @private
*/
type SSub<N extends string, M extends string> = _RemoveStrPaddingZeroes<
Reverse<_SSub<Reverse<N>, Reverse<M>>>
>;
type _SSub<
N extends string,
M extends string,
Borrow extends 0 | 1 = 0,
Result extends string = "",
> =
N extends `${infer F extends Digit}${infer R}` ?
M extends `${infer G extends Digit}${infer S}` ?
Borrow extends 0 ?
_CompareDigit<F, G> extends EQ | GT ?
_SSub<R, S, 0, `${Result}${_SubDigit<F, G>}`>
: // prettier-ignore
_SSub<R, S, 1, `${Result}${_AddDigit<_AddDigit<_SubDigit<9, G>, 1> extends infer U extends Digit ? U : never, F>}`>
: F extends 0 ? _SSub<R, S, 1, `${Result}${_SubDigit<9, G>}`>
: _CompareDigit<_SubDigit<F, 1>, G> extends EQ | GT ?
_SSub<R, S, 0, `${Result}${_SubDigit<_SubDigit<F, 1>, G>}`>
: // prettier-ignore
_SSub<R, S, 1, `${Result}${_AddDigit<_SubDigit<9, G>, F>}`>
: Borrow extends 1 ? `${Result}${_SSub<N, "1">}`
: `${Result}${N}`
: Borrow extends 1 ? `${Result}1`
: Result;
/**
* [Fn] Subtract two {@link Nat}s.
*
* Sig: `(n: Nat, m: Nat) => Nat`
*
* **⚠️ Warning:** `N` must be greater than or equal to `M`.
*/
export default interface SubFn extends Fn<[Nat, Nat], Nat> {
def: () => Sub<Arg0<this>, Arg1<this>>;
}