Skip to content

Commit 09b3e11

Browse files
authored
fix: valueOr and withValue utilities (#1079)
1 parent 03f67d3 commit 09b3e11

File tree

2 files changed

+97
-8
lines changed

2 files changed

+97
-8
lines changed

libp2p/utility.nim

+11-8
Original file line numberDiff line numberDiff line change
@@ -112,24 +112,27 @@ template withValue*[T](self: Opt[T] | Option[T], value, body: untyped): untyped
112112
let value {.inject.} = temp.get()
113113
body
114114

115-
macro withValue*[T](self: Opt[T] | Option[T], value, body, body2: untyped): untyped =
116-
let elseBody = body2[0]
115+
macro withValue*[T](self: Opt[T] | Option[T], value, body, elseStmt: untyped): untyped =
116+
let elseBody = elseStmt[0]
117117
quote do:
118-
if `self`.isSome:
119-
let `value` {.inject.} = `self`.get()
118+
let temp = (`self`)
119+
if temp.isSome:
120+
let `value` {.inject.} = temp.get()
120121
`body`
121122
else:
122123
`elseBody`
123124

124125
template valueOr*[T](self: Option[T], body: untyped): untyped =
125-
if self.isSome:
126-
self.get()
126+
let temp = (self)
127+
if temp.isSome:
128+
temp.get()
127129
else:
128130
body
129131

130132
template toOpt*[T, E](self: Result[T, E]): Opt[T] =
131-
if self.isOk:
133+
let temp = (self)
134+
if temp.isOk:
132135
when T is void: Result[void, void].ok()
133-
else: Opt.some(self.unsafeGet())
136+
else: Opt.some(temp.unsafeGet())
134137
else:
135138
Opt.none(type(T))

tests/testutility.nim

+86
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# This file may not be copied, modified, or distributed except according to
1010
# those terms.
1111

12+
import options
1213
import ./helpers
1314
import ../libp2p/utility
1415

@@ -71,3 +72,88 @@ suite "Utility":
7172
test "unsuccessful safeConvert from uint to int":
7273
check not (compiles do:
7374
result: uint = safeConvert[int, uint](11.uint))
75+
76+
suite "withValue and valueOr templates":
77+
type
78+
TestObj = ref object
79+
x: int
80+
81+
proc objIncAndOpt(self: TestObj): Opt[TestObj] =
82+
self.x.inc()
83+
return Opt.some(self)
84+
85+
proc objIncAndOption(self: TestObj): Option[TestObj] =
86+
self.x.inc()
87+
return some(self)
88+
89+
test "withValue calls right branch when Opt/Option is none":
90+
var counter = 0
91+
# check Opt/Option withValue with else
92+
Opt.none(TestObj).withValue(v):
93+
fail()
94+
else:
95+
counter.inc()
96+
none(TestObj).withValue(v):
97+
fail()
98+
else:
99+
counter.inc()
100+
check counter == 2
101+
102+
# check Opt/Option withValue without else
103+
Opt.none(TestObj).withValue(v):
104+
fail()
105+
none(TestObj).withValue(v):
106+
fail()
107+
108+
test "withValue calls right branch when Opt/Option is some":
109+
var counter = 1
110+
# check Opt/Option withValue with else
111+
Opt.some(counter).withValue(v):
112+
counter.inc(v)
113+
else:
114+
fail()
115+
some(counter).withValue(v):
116+
counter.inc(v)
117+
else:
118+
fail()
119+
120+
# check Opt/Option withValue without else
121+
Opt.some(counter).withValue(v):
122+
counter.inc(v)
123+
some(counter).withValue(v):
124+
counter.inc(v)
125+
check counter == 16
126+
127+
test "withValue calls right branch when Opt/Option is some with proc call":
128+
var obj = TestObj(x: 0)
129+
# check Opt/Option withValue with else
130+
objIncAndOpt(obj).withValue(v):
131+
v.x.inc()
132+
else:
133+
fail()
134+
objIncAndOption(obj).withValue(v):
135+
v.x.inc()
136+
else:
137+
fail()
138+
139+
# check Opt/Option withValue without else
140+
objIncAndOpt(obj).withValue(v):
141+
v.x.inc()
142+
objIncAndOption(obj).withValue(v):
143+
v.x.inc()
144+
145+
check obj.x == 8
146+
147+
test "valueOr calls with and without proc call":
148+
var obj = none(TestObj).valueOr:
149+
TestObj(x: 0)
150+
check obj.x == 0
151+
obj = some(TestObj(x: 2)).valueOr:
152+
fail()
153+
return
154+
check obj.x == 2
155+
156+
obj = objIncAndOpt(obj).valueOr:
157+
fail()
158+
return
159+
check obj.x == 3

0 commit comments

Comments
 (0)