aboutsummaryrefslogtreecommitdiff
path: root/std/prelude/results.pk
blob: 81bccf01301da17b823bdce120a1f85aae890f74 (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
140
141
## 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 interface. Useful for dynamically dispatching errors.
pub type Err = interface
  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[Unit, 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]): Option[T] =
  if self of Okay(x):
    Some(x)
  else:
    None()
## Converts from a `Result[T, E]` to an `Option[E]`.
pub func err[T, E](self: Result[T, E]): Option[E] =
  if self of Error(x):
    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):
    Okay(fn(x))
  of Error(e):
    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):
    Error(fn(e))
  of Okay(x):
    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):
    fn(x)
  of Error(e):
    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)):
    Okay(x)
  of Okay(Error(e)), Error(e):
    Error(e)

## Transposes a `Result[Option[T], E]` to an `Option[Result[T, E]]`.
pub func transpose[T, E](self: Result[Option[T], E]): Option[Result[T, E]] =
  match self
  of Okay(Some(x)):
    Some(Okay(x))
  of Okay(None()), Error(_):
    None()
## Transposes an `Option[Result[T, E]]` to a `Result[Option[T], E]`. Takes a default error.
pub func transpose[T, E](self: Option[Result[T, E]], error: E): Result[Option[T], E] =
  match self
  of Some(Okay(x)):
    Okay(Some(x))
  of Some(Error(e)):
    Error(e)
  of None():
    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): 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): x
  of Error(e): 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): e
  of Okay(x): raise x

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

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

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

## Overloads the `str()` function for use on Results.
pub func str[T, E](self: Result[T, E]): str =
  match self
  of Some(x):
    fmt("Okay({})", x.str)
  of Error(e):
    fmt("Error({})", 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