import logger from 'log' import {Result} from './result' const log = logger('option') export class Option { // ***************************************************************************************************************** // Constructors private constructor( private readonly data: T | null, private readonly _state: State, ) {} public static some(data: T) : Option { return new Option(data, State.Some) } public static none() : Option { return new Option(null, State.None) } // ***************************************************************************************************************** // some public is_some() : boolean { return this._state === State.Some } public is_some_and(f: (data: T) => boolean) : boolean { return this._state === State.Some && f(this.data as T) } public expect(msg: string) : T { log.trace("expect") if (this._state === State.Some) { return this.data as T } log.warn(msg) throw new Error(msg) } public unwrap() : T { log.trace("unwrap") return this.expect("called unwrap on a None value") } public unwrap_or(default_: T) : T { if (this._state === State.Some) return this.data as T return default_ } public unwrap_or_else(f: () => T) : T { if (this._state === State.Some) return this.data as T return f() } // ***************************************************************************************************************** // none public is_none() : boolean { return this._state === State.None } // ***************************************************************************************************************** // map public map(f: (data: T) => U) : Option { if (this._state === State.Some) return Option.some(f(this.data as T)) return Option.none() } public map_or(default_: U, f: (data: T) => U) : U { if (this._state === State.Some) return f(this.data as T) return default_ } public map_or_else(default_: () => U, f: (data: T) => U) : U { if (this._state === State.Some) return f(this.data as T) return default_() } public ok_or(err: E) : Result { if (this._state === State.Some) return Result.ok(this.data as T) return Result.error(err) } public ok_or_else(err: () => E) : Result { if (this._state === State.Some) return Result.ok(this.data as T) return Result.error(err()) } public and(optb: Option) : Option { if (this._state === State.Some) return optb return Option.none() } public and_then(f: (data: T) => Option) : Option { if (this._state === State.Some) return f(this.data as T) return Option.none() } public filter(f: (data: T) => boolean) : Option { if (this._state === State.Some && f(this.data as T)) return this return Option.none() } public or(optb: Option) : Option { if (this._state === State.Some) return this return optb } public or_else(f: () => Option) : Option { if (this._state === State.Some) return this return f() } public xor(optb: Option) : Option { if (this._state === optb._state) return Option.none() else if (this._state === State.Some) return this return optb } public get state() : State { return this._state } } export enum State { Some, None, }