Skip to content
This repository was archived by the owner on Apr 7, 2025. It is now read-only.

Commit 7e8c911

Browse files
committed
init
0 parents  commit 7e8c911

File tree

6 files changed

+264
-0
lines changed

6 files changed

+264
-0
lines changed

Diff for: LICENCE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Luca
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Diff for: README.md

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# resultutils
2+
[resultutils](https://github.com/nonnil/resultutils) to make [Result](https://github.com/arnetheduck/nim-result) handling easier.
3+
4+
inspired by [optionsutils](https://github.com/PMunch/nim-optionsutils).
5+
6+
## Usage
7+
8+
```nim
9+
import results, resultutils
10+
11+
func greet(name: string): Result[string, string] =
12+
if name.len > 0:
13+
return ok("hi, " & name)
14+
return err("No name? 😐")
15+
16+
let hiNim: string = match greet "Nim":
17+
Ok(greet):
18+
greet
19+
Err(_):
20+
"Oh no! something went wrong 😨"
21+
22+
assert hiNim == "hi, Nim"
23+
```
24+
25+
more code examples can be found [here](https://github.com/nonnil/resultutils/tree/main/tests)
26+
27+
## Installation
28+
```bash
29+
nimble install https://github.com/nonnil/resultutils
30+
```

Diff for: resultsutils.nimble

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Package
2+
3+
version = "0.1.0"
4+
author = "Luca (@nonnil)"
5+
description = "Utility macros for easier handling of Result"
6+
license = "MIT"
7+
srcDir = "src"
8+
9+
10+
# Dependencies
11+
requires "result >= 0.3.0"
12+
13+
requires "nim >= 1.6.0"

Diff for: src/resultutils.nim

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
## Utility macros for easier handling of Result
2+
import std / [ macros ]
3+
import results
4+
5+
macro match*(results: untyped, node: untyped): untyped =
6+
## It can be used like a general ``case`` branch, but expect ``Result`` as the first argument.
7+
##
8+
## Use ``_`` ident for the return value discard.
9+
##
10+
## ``ident`` is not required for ``void`` type.
11+
##
12+
## .. code-block:: nim
13+
## func example(): Result[string, void] =
14+
## ok("something is ok")
15+
##
16+
## match example():
17+
## Ok(someOk):
18+
## assert someOk == "something is ok"
19+
## # not required an ident
20+
## Err():
21+
## break
22+
##
23+
## Assign a content of ``Result`` directly from ``match`` to a variable:
24+
##
25+
## .. code-block:: nim
26+
## func greet(name: string): Result[string, string] =
27+
## if name.len > 0:
28+
## return ok("hi, " & name)
29+
##
30+
## return err("No name? 😐")
31+
##
32+
## let msg: string = match greet "Nim":
33+
## Ok(greet):
34+
## greet
35+
## # discard an error content
36+
## Err(_):
37+
## "Oh no! something went wrong 😨"
38+
##
39+
## assert msg == "hi, Nim"
40+
##
41+
## more code examples can be found `here<https://github.com/nonnil/resultutils/blob/main/tests/test_match.nim>`_
42+
43+
expectKind results, { nnkCall, nnkIdent, nnkCommand, nnkDotExpr }
44+
expectKind node, nnkStmtList
45+
46+
type
47+
ResultKind = enum
48+
Ok
49+
Err
50+
51+
func isResultKind(str: string): bool =
52+
case str
53+
of $Ok, $Err:
54+
true
55+
56+
else: false
57+
58+
var
59+
okIdent, okBody: NimNode
60+
errIdent, errBody: NimNode
61+
62+
for child in node:
63+
expectKind child, nnkCall
64+
# a case label. expect `Ok` or `Err`.
65+
expectKind child[0], nnkIdent
66+
67+
let resultType = $child[0]
68+
var resultIdent, body: NimNode = nil
69+
70+
# an ident
71+
if child[1].kind == nnkIdent:
72+
# a body
73+
expectKind child[2], nnkStmtList
74+
resultIdent = child[1]
75+
body = child[2]
76+
77+
# if ident is not passed on
78+
else:
79+
expectKind child[1], nnkStmtList
80+
body = child[1]
81+
82+
if not resultType.isResultKind(): error "Only \"Err\" and \"Ok\" are allowed as case labels"
83+
case resultType
84+
of $Ok:
85+
okIdent = if (resultIdent.isNil) or ($resultIdent == "_"): nil
86+
else: resultIdent
87+
okBody = body
88+
89+
of $Err:
90+
errIdent = if (resultIdent.isNil) or ($resultIdent == "_"): nil
91+
else: resultIdent
92+
errBody = body
93+
94+
let
95+
tmp = genSym(nskLet)
96+
getSym = bindSym"get"
97+
errorSym = bindSym"error"
98+
99+
# ignore assign if the ident is `_` or nil
100+
okAssign = if okIdent.isNil: newEmptyNode()
101+
else: quote do:
102+
let `okIdent` = `getSym`(`tmp`)
103+
104+
# ignore assign if the ident is `_` or nil
105+
errAssign = if errIdent.isNil: newEmptyNode()
106+
else: quote do:
107+
let `errIdent` = `errorSym`(`tmp`)
108+
109+
result = quote do:
110+
let `tmp` = `results`
111+
if `tmp`.isOk:
112+
`okAssign`
113+
`okBody`
114+
115+
else:
116+
`errAssign`
117+
`errBody`

Diff for: tests/config.nims

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
switch("path", "$projectDir/../src")

Diff for: tests/test_match.nim

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import std / [ unittest ]
2+
import results
3+
import ../ src / resultutils
4+
5+
suite "match macro":
6+
7+
func example(): Result[string, void] =
8+
ok("something is ok")
9+
10+
func greet(name: string): Result[string, string] =
11+
if name.len > 0:
12+
return ok("hi, " & name)
13+
return err("No name? 😐")
14+
15+
test "general":
16+
17+
match example():
18+
Ok(someOk):
19+
check:
20+
someOk == "something is ok"
21+
Err(_):
22+
fail
23+
24+
test "with void type":
25+
26+
func returnVoid(flag: bool): Result[void, void] =
27+
if flag:
28+
ok()
29+
30+
else:
31+
err()
32+
33+
match returnVoid(true):
34+
Ok():
35+
checkpoint("void ok")
36+
Err():
37+
fail
38+
39+
match returnVoid(false):
40+
Ok():
41+
fail
42+
Err():
43+
checkpoint("void err")
44+
45+
test "assigned from match":
46+
47+
let msg: string = match example():
48+
Ok(someOk):
49+
"ok msg"
50+
Err():
51+
"sorry, error"
52+
53+
check:
54+
msg == "ok msg"
55+
56+
# test with nnkCommand
57+
let hiNim: string = match greet "Nim":
58+
Ok(greet):
59+
greet
60+
Err(_):
61+
"Oh no! something went wrong 😨"
62+
63+
check:
64+
hiNim == "hi, Nim"
65+
66+
test "nested":
67+
let msg = match example():
68+
Ok(_):
69+
let inside = match "Rust".greet():
70+
Ok(greet):
71+
# check:
72+
# greeted == "hi, Rust"
73+
greet
74+
Err(_):
75+
"internal error"
76+
inside
77+
Err():
78+
fail
79+
"external error"
80+
81+
check:
82+
msg == "hi, Rust"

0 commit comments

Comments
 (0)