@@ -379,3 +379,142 @@ 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+ var outcome = value
465+ outcome.withValue (it):
466+ if not action:
467+ outcome = none (T)
468+ do :
469+ outcome = none (T)
470+ outcome
471+
472+ template applyIt * [T](value: Option [T], action: untyped ) =
473+ # # Executes a code block if the `Option` is `some`, assigning the value to a variable named `it`
474+ runnableExamples:
475+ var value: string
476+ some (" foo" ).applyIt:
477+ value = it
478+ assert value == " foo"
479+
480+ none (string ).applyIt:
481+ assert false
482+
483+ value.withValue (it):
484+ action
485+
486+ template valueOr * [T](value: Option [T], otherwise: untyped ): T =
487+ # # Returns the value in an option if it is set. Otherwise, executes a code block. This is
488+ # # useful for executing side effects when the option is empty.
489+ runnableExamples:
490+ let a = some (" foo" ).valueOr:
491+ assert false
492+ assert a == " foo"
493+
494+ let b = none (string ).valueOr:
495+ " bar"
496+ assert b == " bar"
497+
498+ block :
499+ var outcome: T
500+ value.withValue (it):
501+ outcome = it
502+ do :
503+ when typeof (otherwise) is T:
504+ outcome = otherwise
505+ else :
506+ otherwise
507+ outcome
508+
509+ template `or` * [T](a, b: Option [T]): Option [T] =
510+ # # Returns the value of the `Option` if it has one, otherwise returns the other `Option`.
511+ runnableExamples:
512+ assert ((some (42 ) or some (9999 )) == some (42 ))
513+ assert ((none (int ) or some (9999 )) == some (9999 ))
514+ assert ((none (int ) or none (int )) == none (int ))
515+ block :
516+ let local = a
517+ if local.isSome:
518+ local
519+ else :
520+ b
0 commit comments