UNPKG

perlica

Version:

> [!WARNING] > 🚧 Work in progress!

289 lines (226 loc) • 8.72 kB
/** * |-----------------------|-------------------| * | Rust methods | Perlica | * |-----------------------|-------------------| * | and | and | * | and_then | andThen | * | as_deref | | * | as_deref_mut | | * | as_mut | | * | as_mut_slice | | * | as_pin_mut | | * | as_pin_ref | | * | as_ref | | * | as_slice | | * | cloned | | * | copied | | * | expect | expect | * | filter | filter | * | flatten | flatten | * | get_or_insert | | * | get_or_insert_default | | * | get_or_insert_with | | * | insert | | * | inspect | inspect | * | is_none | isNone | * | is_none_or | isNoneOr | * | is_some | isSome | * | is_some_and | isSomeAnd | * | iter | | * | iter_mut | | * | map | map | * | map_or | mapOr | * | map_or_else | mapOrElse | * | ok_or | okOr | * | ok_or_else | okOrElse | * | or | or | * | or_else | orElse | * | replace | | * | take | | * | take_if | | * | transpose | transpose | * | unwrap | unwrap | * | unwrap_or | unwrapOr | * | unwrap_or_default | | * | unwrap_or_else | unwrapOrElse | * | unwrap_unchecked | | * | unzip | | * | xor | xor | * | zip | | * | zip_with | | * |-----------------------|-------------------| */ import { OnceIterator } from "./Iterator"; import { err, isErr, ok, type Result } from "./Result"; export type SomeType<R> = R extends Option<infer T> ? T : any; export interface OptionTrait<T> { and<U, T>(this: Option<T>, v: Option<U>): Option<U>; andThen<U, T>(this: Option<T>, f: (v: T) => Option<U>): Option<U>; expect<T>(this: Option<T>, msg: string): T; filter<T>(this: Option<T>, f: (v: T) => boolean): Option<T>; flatten<T>(this: Option<Option<T>>): Option<T>; inspect<T>(this: Option<T>, f: (v: T) => void): Option<T>; isNone<T>(this: Option<T>): boolean; isNoneOr<T>(this: Option<T>, f: (v: T) => boolean): boolean; isSome<T>(this: Option<T>): boolean; isSomeAnd<T>(this: Option<T>, f: (v: T) => boolean): boolean; map<U, T>(this: Option<T>, f: (v: T) => U): Option<U>; mapOr<U, T>(this: Option<T>, def: U, f: (v: T) => U): U; mapOrElse<U, T>(this: Option<T>, d: () => U, f: (v: T) => U): U; okOr<T, E>(this: Option<T>, v: E): Result<T, E>; okOrElse<T, E>(this: Option<T>, f: () => E): Result<T, E>; or<T>(this: Option<T>, v: Option<T>): Option<T>; orElse<T>(this: Option<T>, f: () => Option<T>): Option<T>; transpose<T, E>(this: Option<Result<T, E>>): Result<Option<T>, E>; unwrap: <T>(this: Option<T>) => T; unwrapOr<T>(this: Option<T>, def: T): T; unwrapOrElse<T>(this: Option<T>, def: () => T): T; xor<T>(this: Option<T>, v: Option<T>): Option<T>; [Symbol.iterator](this: Option<T>): OnceIterator<Option<T>, T>; } export const isSome = <T>(r: Option<T>): r is Some<T> => r.tag === "some"; export const isNone = <T>(r: Option<T>): r is None => r.tag === "none"; export interface Some<T> extends OptionTrait<T> { value: T; tag: "some"; } export interface None extends OptionTrait<never> { tag: "none"; } export type Option<T> = Some<T> | None; export const OptionProto = <T>(): OptionTrait<T> => ({ and<U, T>(this: Option<T>, v: Option<U>): Option<U> { return isSome(this) ? v : none(); }, andThen<T, U>(this: Option<T>, f: (v: T) => Option<U>): Option<U> { return isSome(this) ? f(this.value) : none(); }, expect<T>(this: Option<T>, msg: string): T { if (isSome(this)) { return this.value; } else { throw new Error(msg); } }, filter<T>(this: Option<T>, f: (v: T) => boolean): Option<T> { return isNone(this) ? none() : f(this.value) ? this : none(); }, flatten<T>(this: Option<Option<T>>): Option<T> { return isSome(this) ? this.value : none(); }, inspect<T>(this: Option<T>, f: (v: T) => void): Option<T> { if (isSome(this)) { f(this.value); return some(this.value); } else { return none(); } }, isNone<T>(this: Option<T>): boolean { return isNone(this); }, isNoneOr<T>(this: Option<T>, f: (v: T) => boolean): boolean { return isNone(this) || f(this.value); }, isSome<T>(this: Option<T>): boolean { return isSome(this); }, isSomeAnd<T>(this: Option<T>, f: (v: T) => boolean): boolean { return isNone(this) ? false : f(this.value); }, map<T, U>(this: Option<T>, f: (v: T) => U): Option<U> { return isSome(this) ? some(f(this.value)) : none(); }, mapOr<U, T>(this: Option<T>, def: U, f: (v: T) => U): U { return isSome(this) ? f(this.value) : def; }, mapOrElse<U, T>(this: Option<T>, d: () => U, f: (v: T) => U): U { return isSome(this) ? f(this.value) : d(); }, okOr<T, E>(this: Option<T>, v: E): Result<T, E> { return isSome(this) ? ok(this.value) : err(v); }, okOrElse<T, E>(this: Option<T>, f: () => E): Result<T, E> { return isSome(this) ? ok(this.value) : err(f()); }, or<T>(this: Option<T>, v: Option<T>): Option<T> { return isSome(this) ? this : v; }, orElse<T>(this: Option<T>, f: () => Option<T>): Option<T> { return isSome(this) ? this : f(); }, transpose<T, E>(this: Option<Result<T, E>>): Result<Option<T>, E> { return isNone(this) ? ok(none()) : isErr(this.value) ? err(this.value.value) : ok(some(this.value.value)); }, unwrap<T>(this: Option<T>): T { if (isSome(this)) { return this.value; } else { throw new Error("called `Option.unwrap()` on a `None` value"); } }, unwrapOr<T>(this: Option<T>, def: T): T { return isSome(this) ? this.value : def; }, unwrapOrElse<T>(this: Option<T>, def: () => T): T { return isSome(this) ? this.value : def(); }, xor<T>(this: Option<T>, v: Option<T>): Option<T> { return isSome(this) && isSome(v) ? this : isNone(this) && isSome(v) ? v : none(); }, [Symbol.iterator]() { return new OnceIterator(this); }, }); export const fromNullable = <T>(v: T): Option<NonNullable<T>> => v == null ? none() : some(v as NonNullable<T>); export const fromResult = <T, E>(v: Result<T, E>): Option<T> => v.ok(); export const tryCatch = <T>(f: () => T): Option<T> => { try { return some(f()); } catch (_) { return none(); } }; export const tryPromise = async <T>(v: Promise<T>): Promise<Option<T>> => v.then(s => some(s)).catch(_ => none()); export const some = <T = never>(v: T): Option<T> => { const a = Object.create(OptionProto<T>()); a.value = v; a.tag = "some"; return a; }; export const none = <T = never>(): Option<T> => { const a = Object.create(OptionProto<T>()); a.tag = "none"; return a; }; interface Bind { <T extends Option<any>, R>( fn: () => Generator<T, R>, ): Option<R>; } export const bind: Bind = fn => { const iter = fn(); let result = iter.next(); while (true) { if (result.done) { return some(result.value); } if (isSome(result.value)) { result = iter.next(result.value.value); } else { return result.value; } } };