@@ -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