module Std::Result {
    import Std::Io::{PrintLine};

    extern func bux_exit(code: int);

    enum Result {
        Ok(int),
        Err(String),
    }

    func Result_NewOk(value: int) -> Result {
        let r: Result = Result { tag: Result_Ok };
        r.data.Ok_0 = value;
        return r;
    }

    func Result_NewErr(msg: String) -> Result {
        let r: Result = Result { tag: Result_Err };
        r.data.Err_0 = msg;
        return r;
    }

    func Result_IsOk(r: Result) -> bool {
        return r.tag == Result_Ok;
    }

    func Result_IsErr(r: Result) -> bool {
        return r.tag == Result_Err;
    }

    func Result_Unwrap(r: Result) -> int {
        if r.tag != Result_Ok {
            PrintLine("panic: unwrap on Err");
            return 0;
        }
        return r.data.Ok_0;
    }

    func Result_UnwrapOr(r: Result, fallback: int) -> int {
        if r.tag == Result_Ok {
            return r.data.Ok_0;
        }
        return fallback;
    }

    /* Unwrap Ok or panic with a custom message */
    func Result_Expect(r: Result, msg: String) -> int {
        if r.tag != Result_Ok {
            PrintLine(msg);
            bux_exit(1);
        }
        return r.data.Ok_0;
    }

    /* Extract Err payload (panics if Ok) */
    func Result_UnwrapErr(r: Result) -> String {
        if r.tag != Result_Err {
            PrintLine("panic: unwrap_err on Ok");
            return "";
        }
        return r.data.Err_0;
    }

    /* If r is Ok return it, otherwise return other */
    func Result_Or(r: Result, other: Result) -> Result {
        if r.tag == Result_Ok {
            return r;
        }
        return other;
    }

}
