Skip to content

Commit

Permalink
fix: valueOr and withValue utilities (#1079)
Browse files Browse the repository at this point in the history
  • Loading branch information
lchenut authored Apr 4, 2024
1 parent 03f67d3 commit 09b3e11
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 8 deletions.
19 changes: 11 additions & 8 deletions libp2p/utility.nim
Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,27 @@ template withValue*[T](self: Opt[T] | Option[T], value, body: untyped): untyped
let value {.inject.} = temp.get()
body

macro withValue*[T](self: Opt[T] | Option[T], value, body, body2: untyped): untyped =
let elseBody = body2[0]
macro withValue*[T](self: Opt[T] | Option[T], value, body, elseStmt: untyped): untyped =
let elseBody = elseStmt[0]
quote do:
if `self`.isSome:
let `value` {.inject.} = `self`.get()
let temp = (`self`)
if temp.isSome:
let `value` {.inject.} = temp.get()
`body`
else:
`elseBody`

template valueOr*[T](self: Option[T], body: untyped): untyped =
if self.isSome:
self.get()
let temp = (self)
if temp.isSome:
temp.get()
else:
body

template toOpt*[T, E](self: Result[T, E]): Opt[T] =
if self.isOk:
let temp = (self)
if temp.isOk:
when T is void: Result[void, void].ok()
else: Opt.some(self.unsafeGet())
else: Opt.some(temp.unsafeGet())
else:
Opt.none(type(T))
86 changes: 86 additions & 0 deletions tests/testutility.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# This file may not be copied, modified, or distributed except according to
# those terms.

import options
import ./helpers
import ../libp2p/utility

Expand Down Expand Up @@ -71,3 +72,88 @@ suite "Utility":
test "unsuccessful safeConvert from uint to int":
check not (compiles do:
result: uint = safeConvert[int, uint](11.uint))

suite "withValue and valueOr templates":
type
TestObj = ref object
x: int

proc objIncAndOpt(self: TestObj): Opt[TestObj] =
self.x.inc()
return Opt.some(self)

proc objIncAndOption(self: TestObj): Option[TestObj] =
self.x.inc()
return some(self)

test "withValue calls right branch when Opt/Option is none":
var counter = 0
# check Opt/Option withValue with else
Opt.none(TestObj).withValue(v):
fail()
else:
counter.inc()
none(TestObj).withValue(v):
fail()
else:
counter.inc()
check counter == 2

# check Opt/Option withValue without else
Opt.none(TestObj).withValue(v):
fail()
none(TestObj).withValue(v):
fail()

test "withValue calls right branch when Opt/Option is some":
var counter = 1
# check Opt/Option withValue with else
Opt.some(counter).withValue(v):
counter.inc(v)
else:
fail()
some(counter).withValue(v):
counter.inc(v)
else:
fail()

# check Opt/Option withValue without else
Opt.some(counter).withValue(v):
counter.inc(v)
some(counter).withValue(v):
counter.inc(v)
check counter == 16

test "withValue calls right branch when Opt/Option is some with proc call":
var obj = TestObj(x: 0)
# check Opt/Option withValue with else
objIncAndOpt(obj).withValue(v):
v.x.inc()
else:
fail()
objIncAndOption(obj).withValue(v):
v.x.inc()
else:
fail()

# check Opt/Option withValue without else
objIncAndOpt(obj).withValue(v):
v.x.inc()
objIncAndOption(obj).withValue(v):
v.x.inc()

check obj.x == 8

test "valueOr calls with and without proc call":
var obj = none(TestObj).valueOr:
TestObj(x: 0)
check obj.x == 0
obj = some(TestObj(x: 2)).valueOr:
fail()
return
check obj.x == 2

obj = objIncAndOpt(obj).valueOr:
fail()
return
check obj.x == 3

0 comments on commit 09b3e11

Please sign in to comment.