114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
import logger from 'log'
|
|
import {Result} from './result'
|
|
|
|
const log = logger('option')
|
|
|
|
export class Option<T> {
|
|
// *****************************************************************************************************************
|
|
// Constructors
|
|
private constructor(
|
|
private readonly data: T | null,
|
|
private readonly _state: State,
|
|
) {}
|
|
public static some<T>(data: T) : Option<T> {
|
|
return new Option(data, State.Some)
|
|
}
|
|
public static none<T>() : Option<T> {
|
|
return new Option<T>(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<U>(f: (data: T) => U) : Option<U> {
|
|
if (this._state === State.Some) return Option.some(f(this.data as T))
|
|
return Option.none()
|
|
}
|
|
public map_or<U>(default_: U, f: (data: T) => U) : U {
|
|
if (this._state === State.Some) return f(this.data as T)
|
|
return default_
|
|
}
|
|
public map_or_else<U>(default_: () => U, f: (data: T) => U) : U {
|
|
if (this._state === State.Some) return f(this.data as T)
|
|
return default_()
|
|
}
|
|
public ok_or<E>(err: E) : Result<T, E> {
|
|
if (this._state === State.Some) return Result.ok(this.data as T)
|
|
return Result.error(err)
|
|
}
|
|
public ok_or_else<E>(err: () => E) : Result<T, E> {
|
|
if (this._state === State.Some) return Result.ok(this.data as T)
|
|
return Result.error(err())
|
|
}
|
|
public and<U>(optb: Option<U>) : Option<U> {
|
|
if (this._state === State.Some) return optb
|
|
return Option.none()
|
|
}
|
|
public and_then<U>(f: (data: T) => Option<U>) : Option<U> {
|
|
if (this._state === State.Some) return f(this.data as T)
|
|
return Option.none()
|
|
}
|
|
public filter(f: (data: T) => boolean) : Option<T> {
|
|
if (this._state === State.Some && f(this.data as T)) return this
|
|
return Option.none()
|
|
}
|
|
public or(optb: Option<T>) : Option<T> {
|
|
if (this._state === State.Some) return this
|
|
return optb
|
|
}
|
|
public or_else(f: () => Option<T>) : Option<T> {
|
|
if (this._state === State.Some) return this
|
|
return f()
|
|
}
|
|
public xor(optb: Option<T>) : Option<T> {
|
|
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,
|
|
}
|