class_name Result extends RefCounted

static var Unit: Result = Result.ok(null)

static func ok(value: Variant) -> Result:
    return Ok.new(value)

static func err(error: Variant) -> Result:
    return Err.new(error)

static func collect_ok(results: Array[Result], ignore_err: bool = false) -> Result:
        var res = []

        for result in results:
            if result.is_ok():
                res.push_back(result.unwrap())
            elif not ignore_err:
                return result

        return Result.ok(res)

class Ok extends Result:
    var value: Variant

    func _init(value):
        self.value = value

    func to_option() -> Option:
        return Option.some(value)

    func chain(fn: Callable) -> Result:
        return fn.call(value)

    func filter(fn: Callable, fail) -> Result:
        if fn.call(value):
            return self
        else:
            return Result.err(fail)

    func map(fn: Callable) -> Result:
        return Result.ok(fn.call(value))

    func is_ok() -> bool:
        return true

    func is_err() -> bool:
        return false

    func or_default(_default_value: Variant) -> Variant:
        return value

    func or_else(_fn: Callable) -> Variant:
        return value

    func unwrap() -> Variant:
        return value

    func unwrap_err() -> Variant:
        return null

class Err extends Result:
    var error: Variant

    func _init(error) -> void:
        self.error = error

    func to_option() -> Option:
        return Option.none

    func chain(_fn: Callable) -> Result:
        return self

    func filter(_fn: Callable, fail) -> Result:
        return Result.err(fail)

    func map(fn: Callable) -> Result:
        return self

    func is_ok() -> bool:
        return false

    func is_err() -> bool:
        return true

    func or_default(default_value: Variant) -> Variant:
        return default_value

    func or_else(fn: Callable) -> Variant:
        return fn.call()

    func unwrap() -> Variant:
        return null

    func unwrap_err() -> Variant:
        return error
