@@ -379,3 +379,141 @@ proc unsafeGet*[T](self: Option[T]): lent T {.inline.}=
379379 # # Generally, using the `get proc <#get,Option[T]>`_ is preferred.
380380 assert self.isSome
381381 result = self.val
382+
383+ template withValue * [T](source: Option [T]; varname, ifExists, ifAbsent: untyped ) =
384+ # # Reads a value from an Option, assigns it to a variable, and calls `ifExists` when it is `some`.
385+ # # If the value is `none`, it calls `ifAbsent`.
386+ runnableExamples:
387+ some (" abc" ).withValue (foo):
388+ assert foo == " abc"
389+ do :
390+ assert false
391+
392+ var absentCalled: bool
393+ none (int ).withValue (foo):
394+ assert false
395+ do :
396+ absentCalled = true
397+ assert absentCalled
398+
399+ let local = source
400+ if local.isSome:
401+ let varname {.inject , used .} = unsafeGet (local)
402+ ifExists
403+ else :
404+ ifAbsent
405+
406+ template withValue * [T](source: Option [T]; varname, ifExists: untyped ) =
407+ # # Reads a value from an Option, assigns it to a variable, and calls `ifExists` when it is `some`.
408+ runnableExamples:
409+ some (" abc" ).withValue (foo):
410+ assert foo == " abc"
411+
412+ none (int ).withValue (foo):
413+ assert false
414+
415+ source.withValue (varname, ifExists):
416+ discard
417+
418+ template mapIt * [T](value: Option [T], action: untyped ): untyped =
419+ # # Applies an action to the value of the `Option`, if it has one.
420+ runnableExamples:
421+ assert some (42 ).mapIt (it * 2 ).mapIt ($ it) == some (" 84" )
422+ assert none (int ).mapIt (it * 2 ).mapIt ($ it) == none (string )
423+
424+ block :
425+ type InnerType = typeof (
426+ block :
427+ var it {.inject , used .}: typeof (value.get ())
428+ action
429+ )
430+
431+ var outcome: Option [InnerType ]
432+ value.withValue (it):
433+ outcome = some (action)
434+ outcome
435+
436+ template flatMapIt * [T](value: Option [T], action: untyped ): untyped =
437+ # # Executes an action on the value of the `Option`, where that action can also return an `Option`.
438+ runnableExamples:
439+ assert some (42 ).flatMapIt (some ($ it)) == some (" 42" )
440+ assert some (42 ).flatMapIt (none (string )) == none (string )
441+ assert none (int ).flatMapIt (some ($ it)) == none (string )
442+ assert none (int ).flatMapIt (none (string )) == none (string )
443+
444+ block :
445+ type InnerType = typeof (
446+ block :
447+ var it {.inject , used .}: typeof (value.get ())
448+ action.get ()
449+ )
450+
451+ var outcome: Option [InnerType ]
452+ value.withValue (it):
453+ outcome = action
454+ outcome
455+
456+ template filterIt * [T](value: Option [T], action: untyped ): Option [T] =
457+ # # Tests the value of the `Option` with a predicate, returning a `none` if it fails.
458+ runnableExamples:
459+ assert some (42 ).filterIt (it > 0 ) == some (42 )
460+ assert none (int ).filterIt (it > 0 ) == none (int )
461+ assert some (- 11 ).filterIt (it > 0 ) == none (int )
462+
463+ block :
464+ let local = value
465+ var outcome: Option [T]
466+ local.withValue (it):
467+ if action:
468+ outcome = local
469+ outcome
470+
471+ template applyIt * [T](value: Option [T], action: untyped ) =
472+ # # Executes a code block if the `Option` is `some`, assigning the value to a variable named `it`
473+ runnableExamples:
474+ var value: string
475+ some (" foo" ).applyIt:
476+ value = it
477+ assert value == " foo"
478+
479+ none (string ).applyIt:
480+ assert false
481+
482+ value.withValue (it):
483+ action
484+
485+ template valueOr * [T](value: Option [T], otherwise: untyped ): T =
486+ # # Returns the value in an option if it is set. Otherwise, executes a code block. This is
487+ # # useful for executing side effects when the option is empty.
488+ runnableExamples:
489+ let a = some (" foo" ).valueOr:
490+ assert false
491+ assert a == " foo"
492+
493+ let b = none (string ).valueOr:
494+ " bar"
495+ assert b == " bar"
496+
497+ block :
498+ var outcome: T
499+ value.withValue (it):
500+ outcome = it
501+ do :
502+ when typeof (otherwise) is T:
503+ outcome = otherwise
504+ else :
505+ otherwise
506+ outcome
507+
508+ template `or` * [T](a, b: Option [T]): Option [T] =
509+ # # Returns the value of the `Option` if it has one, otherwise returns the other `Option`.
510+ runnableExamples:
511+ assert ((some (42 ) or some (9999 )) == some (42 ))
512+ assert ((none (int ) or some (9999 )) == some (9999 ))
513+ assert ((none (int ) or none (int )) == none (int ))
514+ block :
515+ let local = a
516+ if local.isSome:
517+ local
518+ else :
519+ b
0 commit comments