Skip to content

Instantly share code, notes, and snippets.

@copygirl
Created October 1, 2018 21:28
Show Gist options
  • Save copygirl/fd886e0a739b66a93aee312b411abc0a to your computer and use it in GitHub Desktop.
Save copygirl/fd886e0a739b66a93aee312b411abc0a to your computer and use it in GitHub Desktop.
import
future,
macros,
options
export UnpackError
type
Result*[T,Err] = object
## A type which stores the result value of a procedure, or error if one occurred.
case suc: bool
of true: val: T
of false: err: Err
proc isSuccess*[T,Err](res: Result[T,Err]): bool =
res.suc
proc isFail*[T,Err](res: Result[T,Err]): bool = not
res.suc
proc getValue*[T,Err](res: Result[T,Err]): T =
## Returns the success value of the Result. If it failed, `UnpackError` is raised.
if res.isFail: raise newException(UnpackError, "Can't obtain value from a failed `Result`")
res.val
proc getError*[T,Err](res: Result[T,Err]): Err =
## Returns the error of the Result. If it succeeded, `UnpackError` is raised.
if res.isSuccess: raise newException(UnpackError, "Can't obtain error from a successful `Result`")
res.err
template success*[T](value: T, Err: typedesc): Result[T,Err] =
## Creates a `Result` that contains a successful result `value`.
Result[T,Err](suc: true, val: value)
template error*[Err](err: Err, T: typedesc): Result[T,Err] =
## Creates a `Result` that contains the error `err`.
Result[T,Err](suc: false, err: err)
proc errorIfNil*[T,Err](value: T, err: Err): Result[T,Err] =
## Returns a `Result` that contains `value` if it's not nil, otherwise `err`.
if not value.isNil: Result[T,Err](suc: true, val: value) #value.success(Err)
else: Result[T,Err](suc: false, err: err) #err.error(T)
proc errorIfNil*[T,Err](value: T, errFunc: () -> Err): Result[T,Err] =
## Returns a `Result` that contains `value` if it's
## not nil, otherwise an error created from `errFunc`.
if not value.isNil: value.success(Err)
else: errFunc().error(T)
proc option*[T,Err](res: Result[T, Err]): Option[T] =
## Transforms the `Result` into an `Option`, dropping potential error information.
if res.isSuccess: res.val.some
else: T.none
proc result*[T,Err](opt: Option[T], err: Err): Result[T,Err] =
## Transforms the `Option` into a `Result`, using `err` as its error if `none`.
if opt.isSome: opt.get().success(Err)
else: err.error(T)
proc result*[T,Err](opt: Option[T], errFunc: () -> Err): Result[T,Err] =
## Transforms the `Option` into a `Result`, using `errFunc` as its error if `none`.
if opt.isSome: opt.get().success(Err)
else: errFunc().error(T)
proc orValue*[T,Err](res: Result[T,Err], default: T): T =
## Returns the success value of the Result, or `default` if it failed.
if res.isSuccess: res.val
else: default
proc orValue*[T,Err](res: Result[T,Err], defaultFunc: Err -> T): T =
## Returns the success value of the Result, or the result of `defaultFunc` if it failed.
if res.isSuccess: res.val
else: defaultFunc(res.err)
proc orRaise*[T,Err:Exception](res: Result[T,Err]): T =
## Returns the success value of the Result, or raise the error if it failed.
if res.isFail: raise res.err
res.val
proc orRaise*[T,Err,Excp:Exception](res: Result[T,Err], errFunc: Err -> Excp): T =
## Returns the success value of the Result, or raise an error created by `errFunc`.
if res.isFail: raise errFunc(res.err)
res.val
proc map*[T,Err](res: Result[T,Err], callback: T -> void) =
## Runs `callback` if the Result succeeded.
if res.isSuccess: callback(res.val)
proc map*[T,R,Err](res: Result[T,Err], mapFunc: T -> R): Result[R,Err] =
## Returns a `Result` with `mapFunc` applied to its success
## value if it succeeded, or passing through its error.
if res.isSuccess: mapFunc(res.val).success(Err)
else: res.err.error(T)
proc map*[T,R,Err](res: Result[T,Err], mapFunc: T -> Result[R,Err]): Result[R,Err] =
## Returns a `Result` with `mapFunc` applied to its success
## value if it succeeded, or passing through its error.
if res.isSuccess: mapFunc(res.val)
else: res.err.error(T)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment