@@ -379,3 +379,141 @@ 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
+ 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