import type CompareFn from "./Compare"; import type { Call1, Fn1, Fn2, PartialApplyW } from "../../HKT"; import type { ValueOf } from "../../Obj/ValueOf"; import type { Eq, IsAny, Lazied, Lazied$Get } from "../../helpers"; /** * The result of comparing two {@link Ord} instances. */ export type Ordering = GT | EQ | LT; /** * An {@link Ordering} to represent that one is _greater than_ the other. */ export type GT = 1; /** * An {@link Ordering} to represent that one is _equal to_ the other. */ export type EQ = 0; /** * An {@link Ordering} to represent that one is _less than_ the other. */ export type LT = -1; /** * A type class for types that can be compared. */ export type Ord = Lazied$Get; /** * {@link Lazied} version of {@link Ord}. */ export type OrdL = Lazied; /** * Type class constraints for type class {@link Ord}. */ export interface TypeClass$$Ord { Compare: Fn2; } /** * Implementations for type class {@link Ord}. */ export interface OrdImpl {} /** * Helper type for implementing type class {@link Ord}. * * @example * ```typescript * import type { Args, Fn2, Ord, Ordering } from "rivo"; * import type { TypeClass$$Ord } from "rivo/typeclass"; * * interface MyType { * value: N; * } * * declare module "rivo/typeclass/Ord" { * interface OrdImpl { * MyType: ImplOrdFor; * // ^^^^^^ * // Can be any property key * } * } * * interface MyType$$Ord extends TypeClass$$Ord { * Compare: MyType$$Ord$Compare; * } * * interface MyType$$Ord$Compare extends Fn2 { * def: ([o1, o2]: Args) => Num.Compare<(typeof o1)["value"], (typeof o2)["value"]>; * } * * type R = Ord.Compare, MyType<1>>; * // ^?: EQ * ``` */ export type ImplOrdFor> = [T, TypeClass]; /** * Helper type for implementing type class {@link Ord} for generic types. * * @example * ```typescript * import type { Args, Cons, Fn1, Fn2, Lazied, Lazied$Get, Ord, OrdL, Ordering } from "rivo"; * import type { Ord$GetConstruct, TypeClass$$Ord } from "rivo/typeclass"; * import type { Compare } from "rivo/typeclass/Ord/Compare"; * // ^^^^^^^ * // The internal implementation for `Ord.Compare` that does not ensure type safety * * interface Boxed { * value: T; * } * interface BoxedL extends Boxed> {} * * declare module "rivo/typeclass/Ord" { * interface OrdImpl { * Boxed: ImplOrdForGeneric, Boxed$$Ord$$Relaxer, Boxed$$Ord$$Builder>; * // ^^^^^^^^^^^^ * // Lazied version of `Boxed` instead of `Boxed` to avoid circular reference error * } * } * * // Used to relax the type of `Ord` instance to its construct, e.g. `Boxed<42>` -> `Boxed`, * // `Boxed>` -> `Boxed>`, etc. * interface Boxed$$Ord$$Relaxer extends Fn1, Boxed>> { * def: ([b]: Args) => Boxed>; * } * * // Used to build type class instance for `Ord` instance, e.g. `Boxed<42>` -> `Boxed$$Ord`, * // `Boxed>` -> `Boxed$$Ord>`, etc. * interface Boxed$$Ord$$Builder extends Fn1>, Boxed$$Ord>> { * def: ([bCons]: Args) => Boxed$$Ord<(typeof bCons)["value"]>; * } * * interface Boxed$$Ord> extends TypeClass$$Ord> { * Compare: Boxed$$Ord$Compare; * } * interface Boxed$$Ord$Compare> extends Fn2, Boxed, Ordering> { * def: ([b1, b2]: Args) => Compare<(typeof b1)["value"], (typeof b2)["value"]>; * } * * type R = Ord.Compare, Boxed<42>>; * // ^?: EQ * ``` */ export type ImplOrdForGeneric< T, Relaxer extends Fn1, TypeClassBuilder extends Fn1>, > = [T, Relaxer, TypeClassBuilder]; /** * Get the matching entry of {@link OrdImpl} for `O`. * @private */ type _Ord$GetMatch = ValueOf<{ [P in keyof OrdImpl as O extends OrdImpl[P][0] ? P : never]: OrdImpl[P]; }>; /** * Get the construct of `O` from {@link OrdImpl}. * * @example * ```typescript * type R1 = Ord$GetConstruct<42>; * // ^?: number * type R2 = Ord$GetConstruct>; * // ^?: Option * type R3 = Ord$GetConstruct>>; * // ^?: Option> * ``` */ export type Ord$GetConstruct = Eq extends true ? Ord : _Ord$GetMatch extends [infer T, unknown] ? T : _Ord$GetMatch extends [unknown, infer Relaxer extends Fn1, unknown] ? Call1 : never; /** * The **unsafe** version of {@link Ord$GetConstruct} (i.e. no type checking with `O`). */ export type Ord$GetConstructW = O extends Ord ? Ord$GetConstruct : never; /** * Get the type class of `O` from {@link OrdImpl}. * * @example * ```typescript * type R1 = Ord$GetTypeClass<42>; * // ^?: Num$$Ord * type R2 = Ord$GetTypeClass>; * // ^?: Option$$Ord * type R3 = Ord$GetTypeClass>>; * // ^?: Option$$Ord> * ``` */ export type Ord$GetTypeClass = _Ord$GetMatch extends [unknown, infer TypeClass extends TypeClass$$Ord] ? TypeClass : _Ord$GetMatch extends ( [ unknown, infer Relaxer extends Fn1, infer TypeClassBuilder extends Fn1>, ] ) ? Call1> : never; /** * The **unsafe** version of {@link Ord$GetTypeClass} (i.e. no type checking with `O`). */ export type Ord$GetTypeClassW = O extends Ord ? Ord$GetTypeClass : never; /*********** * Methods * ***********/ /** * Methods for `Ord`. */ export namespace Ord { /** * [Fn] Compare two `Ord` instances. * * Sig: `>(o1: O, o2: O) => Ordering` * * @example * ```typescript * type R1 = $, 1, 2>; * // ^?: LT * type R2 = $, 2, 1>; * // ^?: GT * type R3 = $, 1, 1>; * // ^?: EQ * ``` */ export type Compare = CompareFn; /** * [Fn] Compare two `Ord` instances. * * Sig: `>[o2: O](o1: O) => Ordering` */ export type CompareWith = PartialApplyW< CompareFn< IsAny extends true ? Ord : Ord$GetConstruct extends infer Cons extends Ord ? Cons : never >, [O2], "_1" >; /** * [Fn] Compare two `Ord` instances. * * Sig: `>[o1: O](o2: O) => Ordering` */ export type CompareAgainst = PartialApplyW< CompareFn< IsAny extends true ? Ord : Ord$GetConstruct extends infer Cons extends Ord ? Cons : never >, [O1] >; }