aboutsummaryrefslogtreecommitdiff
path: root/std/prelude/results.pk
blob: 61b0c8ab27516a8247c88f1c5ef08bc3bf207087 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
## std.results: Result types.
## This module is imported by default.

use std.[options, format]

## The Result type. Represents either success or failure.
pub type Result[T, E] = union
  Okay(T)
  Error(E)

## The Err class. Useful for dynamically dispatching errors.
pub type Err = class
  str(Self): str
  dbg(Self): str

## A `Result` type that uses dynamically dispatched errors.
## The `Error` may be any type implementing `Err`.
pub type Result[T] = Result[T, ref Err]
## A `Result` type that only checks for success.
## Does not contain a value.
# pub type Success[E] = Result[void, E]
## A `Result` type that only checks for success.
## Does not contain a value. Dynamically dispatched.
# pub type Success = Result[void]

## Syntactic sugar for dynamic result type declarations.
pub macro !(T: type) =
  quote Result[`T`]

## Indirect access. Propagates `Error`.
pub macro ?[T, E](self: Result[T, E]) =
  quote
    match `self`
    of Okay(x) then x
    of Error(e) then return Error(e)

## Checks if a `Result` type was successful.
pub func is_ok[T, E](self: Result[T, E]): bool =
  self of Okay(_)
## Checks if a `Result` type was not successful.
pub func is_err[T, E](self: Result[T, E]): bool =
  self of Error(_)

## Converts from a `Result[T, E]` to an `Option[T]`.
pub func ok[T, E](self: Result[T, E]): T? =
  if self of Okay(x) then
    Some(x)
  else
    None
## Converts from a `Result[T, E]` to an `Option[E]`.
pub func err[T, E](self: Result[T, E]): E? =
  if self of Error(x) then
    Some(x)
  else
    None

## Applies a function to `T`, if self is `Okay`.
pub func map[T, E, U](self: Result[T, E], fn: T -> U): Result[U, E] =
  match self
  of Okay(x) then
    Okay(fn(x))
  of Error(e) then
    Error(e)
## Applies a function to `E`, if self is `Error`.
pub func map_err[T, E, F](self: Result[T, E], fn: E -> F): Result[T, F] =
  match self
  of Error(e) then
    Error(fn(e))
  of Okay(x) then
    Okay(x)

## Applies a function to `T`, if it exists. Equivalent to `self.map(fn).flatten`.
pub func flatmap[T, E, U](self: Result[T, E], fn: T -> Result[U, E]): Result[U, E] =
  match self
  of Okay(x) then
    fn(x)
  of Error(e) then
    Error(e)
## Converts from a `Result[Result[T, E], E]` to a `Result[T, E]`.
pub func flatten[T, E](self: Result[Result[T, E], E]): Result[T, E] =
  match self
  of Okay(Okay(x)) then
    Okay(x)
  of Okay(Error(e)), Error(e) then
    Error(e)

## Transposes a `Result[Option[T], E]` to an `Option[Result[T, E]]`.
pub func transpose[T, E](self: Result[T?, E]): Result[T, E]? =
  match self
  of Okay(Some(x)) then
    Some(Okay(x))
  of Okay(None), Error(_) then
    None
## Transposes an `Option[Result[T, E]]` to a `Result[Option[T], E]`. Takes a default error.
pub func transpose[T, E](self: Result[T, E]?, error: E): Result[T?, E] =
  match self
  of Some(Okay(x)) then Okay(Some(x))
  of Some(Error(e)) then Error(e)
  of None then Error(error)

## Returns the inner value or a default.
pub func get_or[T, E](self: Result[T, E], default: T): T =
  if self of Okay(x) then x
  else default

## Directly accesses the inner value. Throws an exception if `Error`.
pub func ![T, E](self: Result[T, E]): T =
  match self
  of Okay(x) then x
  of Error(e) then raise e
## Directly accesses the inner error. Throws an exception of type T if `Okay`.
pub func get_err[T, E](self: Result[T, E]): E =
  match self
  of Error(e) then e
  of Okay(x) then raise x

## Overloads the `==` operation for use on Results.
pub func ==[T, E, F](a: Result[T, E], b: Result[T, F]): bool =
  if (a, b) of (Okay(x), Okay(y)) then
    x == y
  else
    false

## Overloads the `str()` function for use on Results.
pub func str[T: Display, E: Display](self: Result[T, E]): str =
  match self
  of Some(x) then
    "Okay({})".fmt(x.str)
  of Error(e) then
    "Error({})".fmt(e.str)

examples
  let x: Error("fuck") = Okay(42)
  func idk: Result[int, string]

# references:
# https://doc.rust-lang.org/std/result/enum.Result.html
# https://github.com/arnetheduck/nim-results
# https://github.com/codex-storage/questionable