rivo
Version:
🤖 The ultimate library you need for composable type-level programming in TypeScript, powered by HKT.
87 lines (81 loc) • 3.33 kB
TypeScript
import type { SDigit } from ".";
import type { Abs } from "./Abs";
import type { IsNeg } from "./IsNeg";
import type { IsPos } from "./IsPos";
import type { _CompareSDigit } from "./Nat/internal/_CompareSDigit";
import type { Arg0, Arg1, Fn } from "../HKT";
import type { ToChars } from "../Str/ToChars";
import type { And, AssertOrdering } from "../helpers";
import type { EQ, GT, LT, Ordering } from "../typeclass/Ord";
type _ToFloat<N extends number> =
`${N}` extends `${infer A}.${infer B}` ? readonly [A, B] : readonly [`${N}`, "0"];
type _CompareSDigits<NS extends readonly SDigit[], MS extends readonly SDigit[]> =
NS extends readonly [infer AHead extends SDigit, ...infer ATail extends readonly SDigit[]] ?
MS extends readonly [infer BHead extends SDigit, ...infer BTail extends readonly SDigit[]] ?
_CompareSDigit<AHead, BHead> extends 0 ?
_CompareSDigits<ATail, BTail>
: _CompareSDigit<AHead, BHead>
: _CompareSDigit<AHead, "0">
: EQ;
type _CompareListLength<NS extends readonly unknown[], MS extends readonly unknown[]> =
NS extends readonly [unknown, ...infer ATail extends readonly unknown[]] ?
MS extends readonly [unknown, ...infer BTail extends readonly unknown[]] ?
_CompareListLength<ATail, BTail>
: GT
: MS extends readonly [unknown, ...(readonly unknown[])] ? LT
: EQ;
/**
* Compare two numbers.
*
* Sig: `(n: number, m: number) => Ordering`
*/
export type Compare<N extends number, M extends number> = AssertOrdering<
[N] extends [never] ? never
: [M] extends [never] ? never
: And<IsPos<N>, IsNeg<M>> extends true ? GT
: And<IsNeg<N>, IsPos<M>> extends true ? LT
: (
Abs<N> extends infer N extends number ?
Abs<M> extends infer M extends number ?
readonly [_ToFloat<N>, _ToFloat<M>] extends readonly [infer NFloat, infer MFloat] ?
NFloat extends readonly [infer NInt extends string, infer NFrac extends string] ?
MFloat extends readonly [infer MInt extends string, infer MFrac extends string] ?
readonly [
ToChars<`${NInt}`>,
ToChars<`${NFrac}`>,
ToChars<`${MInt}`>,
ToChars<`${MFrac}`>,
] extends (
readonly [
infer AIntDigits extends readonly SDigit[],
infer AFracDigits extends readonly SDigit[],
infer BIntDigits extends readonly SDigit[],
infer BFracDigits extends readonly SDigit[],
]
) ?
_CompareListLength<AIntDigits, BIntDigits> extends EQ ?
_CompareSDigits<AIntDigits, BIntDigits> extends EQ ?
_CompareSDigits<AFracDigits, BFracDigits>
: _CompareSDigits<AIntDigits, BIntDigits>
: _CompareListLength<AIntDigits, BIntDigits>
: never
: never
: never
: never
: never
: never
) extends infer R extends Ordering ?
And<IsPos<N>, IsPos<M>> extends true ? R
: R extends GT ? LT
: R extends LT ? GT
: R
: never
>;
/**
* [Fn] Compare two numbers.
*
* Sig: `(n: number, m: number) => Ordering`
*/
export default interface CompareFn extends Fn<[number, number], Ordering> {
def: () => Compare<Arg0<this>, Arg1<this>>;
}