-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Extend options stdlib #24849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: devel
Are you sure you want to change the base?
Extend options stdlib #24849
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -74,7 +74,7 @@ when defined(nimHasEffectsOf): | |||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||
{.pragma: effectsOf.} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
import std/typetraits | ||||||||||||||||||||||||||||||||
import std/[typetraits, macros] | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
when defined(nimPreviewSlimSystem): | ||||||||||||||||||||||||||||||||
import std/assertions | ||||||||||||||||||||||||||||||||
|
@@ -379,3 +379,129 @@ proc unsafeGet*[T](self: Option[T]): lent T {.inline.}= | |||||||||||||||||||||||||||||||
## Generally, using the `get proc <#get,Option[T]>`_ is preferred. | ||||||||||||||||||||||||||||||||
assert self.isSome | ||||||||||||||||||||||||||||||||
result = self.val | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
macro evalOnceAs(expAlias, exp: untyped): untyped = | ||||||||||||||||||||||||||||||||
## Injects `expAlias` in caller scope, evaluating it only once and ensuring no copies are made. | ||||||||||||||||||||||||||||||||
expectKind(expAlias, nnkIdent) | ||||||||||||||||||||||||||||||||
return if exp.kind != nnkSym: | ||||||||||||||||||||||||||||||||
newLetStmt(expAlias, exp) | ||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||
newProc(name = genSym(nskTemplate, $expAlias), params = [getType(untyped)], | ||||||||||||||||||||||||||||||||
body = exp, procType = nnkTemplateDef) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
template withValue*[T](source: Option[T]; varname, ifExists, ifAbsent: untyped) = | ||||||||||||||||||||||||||||||||
## Reads a value from an Option, assigns it to a variable, and calls `ifExists` when it is `some`. | ||||||||||||||||||||||||||||||||
## If the value is `none`, it calls `ifAbsent`. | ||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
some("abc").withValue(foo): | ||||||||||||||||||||||||||||||||
assert foo == "abc" | ||||||||||||||||||||||||||||||||
do: | ||||||||||||||||||||||||||||||||
assert false | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
var absentCalled: bool | ||||||||||||||||||||||||||||||||
none(int).withValue(foo): | ||||||||||||||||||||||||||||||||
assert false | ||||||||||||||||||||||||||||||||
do: | ||||||||||||||||||||||||||||||||
absentCalled = true | ||||||||||||||||||||||||||||||||
assert absentCalled | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
block: | ||||||||||||||||||||||||||||||||
evalOnceAs(local, source) | ||||||||||||||||||||||||||||||||
if local.isSome: | ||||||||||||||||||||||||||||||||
template varname(): auto {.inject, used.} = unsafeGet(local) | ||||||||||||||||||||||||||||||||
ifExists | ||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||
ifAbsent | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
template withValue*[T](source: Option[T]; varname, ifExists: untyped) = | ||||||||||||||||||||||||||||||||
## Reads a value from an Option, assigns it to a variable, and calls `ifExists` when it is `some`. | ||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
some("abc").withValue(foo): | ||||||||||||||||||||||||||||||||
assert foo == "abc" | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
none(int).withValue(foo): | ||||||||||||||||||||||||||||||||
assert false | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
source.withValue(varname, ifExists): | ||||||||||||||||||||||||||||||||
discard | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
template mapIt*[T](value: Option[T], action: untyped): untyped = | ||||||||||||||||||||||||||||||||
## Applies an action to the value of the `Option`, if it has one. | ||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
assert some(42).mapIt(it * 2).mapIt($it) == some("84") | ||||||||||||||||||||||||||||||||
assert none(int).mapIt(it * 2).mapIt($it) == none(string) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
block: | ||||||||||||||||||||||||||||||||
type InnerType = typeof( | ||||||||||||||||||||||||||||||||
block: | ||||||||||||||||||||||||||||||||
var it {.inject, used.}: typeof(value.get()) | ||||||||||||||||||||||||||||||||
action | ||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
var outcome: Option[InnerType] | ||||||||||||||||||||||||||||||||
value.withValue(it): | ||||||||||||||||||||||||||||||||
outcome = some(action) | ||||||||||||||||||||||||||||||||
outcome | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
template flatMapIt*[T](value: Option[T], action: untyped): untyped = | ||||||||||||||||||||||||||||||||
## Executes an action on the value of the `Option`, where that action can also return an `Option`. | ||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
assert some(42).flatMapIt(some($it)) == some("42") | ||||||||||||||||||||||||||||||||
assert some(42).flatMapIt(none(string)) == none(string) | ||||||||||||||||||||||||||||||||
assert none(int).flatMapIt(some($it)) == none(string) | ||||||||||||||||||||||||||||||||
assert none(int).flatMapIt(none(string)) == none(string) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
block: | ||||||||||||||||||||||||||||||||
type InnerType = typeof( | ||||||||||||||||||||||||||||||||
block: | ||||||||||||||||||||||||||||||||
var it {.inject, used.}: typeof(value.get()) | ||||||||||||||||||||||||||||||||
action.get() | ||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
var outcome: Option[InnerType] | ||||||||||||||||||||||||||||||||
value.withValue(it): | ||||||||||||||||||||||||||||||||
outcome = action | ||||||||||||||||||||||||||||||||
outcome | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
template filterIt*[T](value: Option[T], action: untyped): Option[T] = | ||||||||||||||||||||||||||||||||
## Tests the value of the `Option` with a predicate, returning a `none` if it fails. | ||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
assert some(42).filterIt(it > 0) == some(42) | ||||||||||||||||||||||||||||||||
assert none(int).filterIt(it > 0) == none(int) | ||||||||||||||||||||||||||||||||
assert some(-11).filterIt(it > 0) == none(int) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
block: | ||||||||||||||||||||||||||||||||
var outcome = value | ||||||||||||||||||||||||||||||||
outcome.withValue(it): | ||||||||||||||||||||||||||||||||
if not action: | ||||||||||||||||||||||||||||||||
outcome = none(T) | ||||||||||||||||||||||||||||||||
do: | ||||||||||||||||||||||||||||||||
outcome = none(T) | ||||||||||||||||||||||||||||||||
outcome | ||||||||||||||||||||||||||||||||
Comment on lines
+473
to
+480
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just?
Suggested change
You can't simply use |
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
template applyIt*[T](value: Option[T], action: untyped) = | ||||||||||||||||||||||||||||||||
## Executes a code block if the `Option` is `some`, assigning the value to a variable named `it` | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To follow the common
Then the docs should clearly draw attention to Apply should return the same type being passed to it, but this just does whatever (or doesn't?). To think more about it, Option is not exactly a container, this template looks confusing applied to it and redundant. |
||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
var value: string | ||||||||||||||||||||||||||||||||
some("foo").applyIt: | ||||||||||||||||||||||||||||||||
value = it | ||||||||||||||||||||||||||||||||
assert value == "foo" | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
none(string).applyIt: | ||||||||||||||||||||||||||||||||
assert false | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
value.withValue(it): | ||||||||||||||||||||||||||||||||
action | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
template `or`*[T](a, b: Option[T]): Option[T] = | ||||||||||||||||||||||||||||||||
## Returns the value of the `Option` if it has one, otherwise returns the other `Option`. | ||||||||||||||||||||||||||||||||
runnableExamples: | ||||||||||||||||||||||||||||||||
assert((some(42) or some(9999)) == some(42)) | ||||||||||||||||||||||||||||||||
assert((none(int) or some(9999)) == some(9999)) | ||||||||||||||||||||||||||||||||
assert((none(int) or none(int)) == none(int)) | ||||||||||||||||||||||||||||||||
block: | ||||||||||||||||||||||||||||||||
evalOnceAs(local, a) | ||||||||||||||||||||||||||||||||
if local.isSome: | ||||||||||||||||||||||||||||||||
local | ||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||
b |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better rename the
action
topred
for consistency with other filter templates in stdlib