diff --git a/questionable/options.nim b/questionable/options.nim index 19a5603..ecbed7b 100644 --- a/questionable/options.nim +++ b/questionable/options.nim @@ -23,17 +23,19 @@ template `->?`*[T,U,V](options: (?T, ?U), expression: V): ?V = else: V.none -template `=?`*[T](name: untyped{nkIdent}, option: ?T): bool = +template `=?`*[T](name: untyped{nkIdent}, expression: ?T): bool = + let option = expression template name: T {.used.} = option.unsafeGet() option.isSome -macro `=?`*[T](variable: untyped{nkVarTy}, option: ?T): bool = +macro `=?`*[T](variable: untyped{nkVarTy}, expression: ?T): bool = let name = variable[0] quote do: - var `name` : typeof(`option`.unsafeGet()) - if `option`.isSome: - `name` = `option`.unsafeGet() - `option`.isSome + let option = `expression` + var `name` : typeof(option.unsafeGet()) + if option.isSome: + `name` = option.unsafeGet() + option.isSome template `|?`*[T](option: ?T, fallback: T): T = if option.isSome: diff --git a/questionable/results.nim b/questionable/results.nim index 6def9f6..89fc2de 100644 --- a/questionable/results.nim +++ b/questionable/results.nim @@ -38,17 +38,19 @@ template `->?`*[T,U,V](values: (?!T, ?!U), expression: V): ?!V = template `|?`*[T](value: ?!T, fallback: T): T = value.valueOr(fallback) -template `=?`*[T](name: untyped{nkIdent}, value: ?!T): bool = +template `=?`*[T](name: untyped{nkIdent}, expression: ?!T): bool = + let value = expression template name: T {.used.} = value.unsafeGet() value.isOk -macro `=?`*[T](variable: untyped{nkVarTy}, option: ?!T): bool = +macro `=?`*[T](variable: untyped{nkVarTy}, expression: ?!T): bool = let name = variable[0] quote do: - var `name` : typeof(`option`.unsafeGet()) - if `option`.isOk: - `name` = `option`.unsafeGet() - `option`.isOk + let value = `expression` + var `name` : typeof(value.unsafeGet()) + if value.isOk: + `name` = value.unsafeGet() + value.isOk proc option*[T,E](value: Result[T,E]): ?T = if value.isOk: diff --git a/testmodules/options/test.nim b/testmodules/options/test.nim index 8003e6b..6a13240 100644 --- a/testmodules/options/test.nim +++ b/testmodules/options/test.nim @@ -87,6 +87,17 @@ suite "optionals": if var a =? int.none: fail + test "=? evaluates optional expression only once": + var count = 0 + if a =? (inc count; 42.some): + let b {.used.} = a + check count == 1 + + count = 0 + if var a =? (inc count; 42.some): + let b {.used.} = a + check count == 1 + test "unary operator `-` works for options": check -(-42.some) == 42.some check -(int.none) == int.none diff --git a/testmodules/result/test.nim b/testmodules/result/test.nim index 0af83ad..a77d29e 100644 --- a/testmodules/result/test.nim +++ b/testmodules/result/test.nim @@ -91,6 +91,17 @@ suite "result": if var a =? int.failure(error): fail + test "=? evaluates optional expression only once": + var count = 0 + if a =? (inc count; 42.success): + let b {.used.} = a + check count == 1 + + count = 0 + if var a =? (inc count; 42.success): + let b {.used.} = a + check count == 1 + test "catch can be used to convert exceptions to results": check parseInt("42").catch == 42.success check parseInt("foo").catch.error of ValueError