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