import logger from 'log' import {Option} from './option' const log = logger('result') export class Result { public constructor(protected readonly _data: T | E, private readonly _state: State) {} // Constructors static ok(data: T): Result { log.trace('New Ok') return new Result(data, State.OK) } static error(err: E): Result { log.trace('New Error') log.debug(`Error : ${err}`) return new Result(err, State.ERROR) } static fromObject(res: Result): Result { // @ts-expect-error return new Result(res._data, res._state) } public as_error(): Result { return Result.error(this.unwrap_err()) } // Getters public state(): State { return this._state } // TODO : implements Iterable<...> // ***************************************************************************************************************** // Ok public is_ok(): boolean { return this._state === State.OK } public is_ok_and(f: (data: T) => boolean): boolean { return this._state === State.OK && f(this._data as T) } public expect(msg: string): T { log.trace('expect') if (this._state === State.ERROR) { log.error('unwrapped an Error') log.error(msg) log.debug(`Error : ${this._data}`) throw msg } return this._data as T } public unwrap(): T { log.trace('unwrap') if (this._state === State.ERROR) { log.error('Unwrapped an Error') log.debug(`Error : ${this._data}`) throw 'Unwrapped an Error' } return this._data as T } public ok(): Option { if (this._state === State.OK) { return Option.some(this._data as T) } else { return Option.none() } } public map(f: (data: T) => U): Result { if (this._state === State.OK) { return Result.ok(f(this._data as T)) } else { return Result.error(this._data as E) } } public map_or(default_: U, f: (data: T) => U): U { if (this._state === State.OK) { return f(this._data as T) } else { return default_ } } public map_or_else(fe: (err: E) => U, f: (data: T) => U): U { if (this._state === State.OK) { return f(this._data as T) } else { return fe(this._data as E) } } public inspect(f: (data: T) => void): Result { if (this._state === State.OK) { f(this._data as T) } return this } public unwrap_or(default_: T): T { if (this._state === State.OK) { return this._data as T } else { return default_ } } public unwrap_or_else(f: (err: E) => T): T { if (this._state === State.OK) { return this._data as T } else { return f(this._data as E) } } // ***************************************************************************************************************** // Errors public is_err(): boolean { return this._state === State.ERROR } public is_err_and(f: (err: E) => boolean): boolean { return this._state === State.ERROR && f(this._data as E) } public expect_err(msg: string): E { log.trace('expect_err') if (this._state === State.OK) { log.error('expect_err on Ok') log.error(msg) throw msg } return this._data as E } public unwrap_err(): E { log.trace('unwrap_err') if (this._state === State.OK) { log.error('unwrap_err on Ok') throw "Result wasn't in error" } return this._data as E } public err(): Option { if (this._state === State.ERROR) { return Option.some(this._data as E) } else { return Option.none() } } public map_err(f: (err: E) => F): Result { if (this._state === State.ERROR) { return Result.error(f(this._data as E)) } else { return Result.ok(this._data as T) } } public inspect_err(f: (err: E) => void): Result { if (this._state === State.ERROR) { f(this._data as E) } return this } // ***************************************************************************************************************** // Combine public and(res: Result): Result { if (this._state === State.OK) { return res } else { return Result.error(this._data as E) } } public and_then(f: (data: T) => Result): Result { if (this._state === State.OK) { return f(this._data as T) } else { return Result.error(this._data as E) } } public or(res: Result): Result { if (this._state === State.OK) { return new Result(this._data as T, State.OK) } else { return res } } public or_else(f: (err: E) => Result): Result { if (this._state === State.OK) { return Result.ok(this._data as T) } else { return f(this._data as E) } } } export const enum State { OK, ERROR }