@@ -379,3 +379,142 @@ proc unsafeGet*[T](self: Option[T]): lent T {.inline.}=
379
379
## Generally, using the `get proc <#get,Option[T]>`_ is preferred.
380
380
assert self.isSome
381
381
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