@@ -74,7 +74,7 @@ when defined(nimHasEffectsOf):
7474else :
7575  {.pragma : effectsOf.}
7676
77- import  std/ typetraits
77+ import  std/ [ typetraits, macros] 
7878
7979when  defined (nimPreviewSlimSystem):
8080  import  std/ assertions
@@ -379,3 +379,129 @@ 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+ macro  evalOnceAs (expAlias, exp: untyped ): untyped  = 
384+   # # Injects `expAlias` in caller scope, evaluating it only once and ensuring no copies are made.
385+   expectKind (expAlias, nnkIdent)
386+   return  if  exp.kind !=  nnkSym:
387+     newLetStmt (expAlias, exp)
388+   else :
389+     newProc (name =  genSym (nskTemplate, $ expAlias), params =  [getType (untyped )],
390+       body =  exp, procType =  nnkTemplateDef)
391+ 
392+ template  withValue * [T](source: Option [T]; varname, ifExists, ifAbsent: untyped ) = 
393+   # # Reads a value from an Option, assigns it to a variable, and calls `ifExists` when it is `some`.
394+   # # If the value is `none`, it calls `ifAbsent`.
395+   runnableExamples:
396+     some (" abc" withValue (foo):
397+       assert  foo ==  " abc" 
398+     do :
399+       assert  false 
400+ 
401+     var  absentCalled: bool 
402+     none (int ).withValue (foo):
403+       assert  false 
404+     do :
405+       absentCalled =  true 
406+     assert  absentCalled
407+ 
408+   block :
409+     evalOnceAs (local, source)
410+     if  local.isSome:
411+       template  varname (): auto  {.inject , used .} =  unsafeGet (local)
412+       ifExists
413+     else :
414+       ifAbsent
415+ 
416+ template  withValue * [T](source: Option [T]; varname, ifExists: untyped ) = 
417+   # # Reads a value from an Option, assigns it to a variable, and calls `ifExists` when it is `some`.
418+   runnableExamples:
419+     some (" abc" withValue (foo):
420+       assert  foo ==  " abc" 
421+ 
422+     none (int ).withValue (foo):
423+       assert  false 
424+ 
425+   source.withValue (varname, ifExists):
426+     discard 
427+ 
428+ template  mapIt * [T](value: Option [T], action: untyped ): untyped  = 
429+   # # Applies an action to the value of the `Option`, if it has one.
430+   runnableExamples:
431+     assert  some (42 ).mapIt (it *  2 ).mapIt ($ it) ==  some (" 84" 
432+     assert  none (int ).mapIt (it *  2 ).mapIt ($ it) ==  none (string )
433+ 
434+   block :
435+     type InnerType  =  typeof (
436+       block :
437+         var  it {.inject , used .}: typeof (value.get ())
438+         action
439+     )
440+ 
441+     var  outcome: Option [InnerType ]
442+     value.withValue (it):
443+       outcome =  some (action)
444+     outcome
445+ 
446+ template  flatMapIt * [T](value: Option [T], action: untyped ): untyped  = 
447+   # # Executes an action on the value of the `Option`, where that action can also return an `Option`.
448+   runnableExamples:
449+     assert  some (42 ).flatMapIt (some ($ it)) ==  some (" 42" 
450+     assert  some (42 ).flatMapIt (none (string )) ==  none (string )
451+     assert  none (int ).flatMapIt (some ($ it)) ==  none (string )
452+     assert  none (int ).flatMapIt (none (string )) ==  none (string )
453+ 
454+   block :
455+     type InnerType  =  typeof (
456+       block :
457+         var  it {.inject , used .}: typeof (value.get ())
458+         action.get ()
459+     )
460+ 
461+     var  outcome: Option [InnerType ]
462+     value.withValue (it):
463+       outcome =  action
464+     outcome
465+ 
466+ template  filterIt * [T](value: Option [T], action: untyped ): Option [T] = 
467+   # # Tests the value of the `Option` with a predicate, returning a `none` if it fails.
468+   runnableExamples:
469+     assert  some (42 ).filterIt (it >  0 ) ==  some (42 )
470+     assert  none (int ).filterIt (it >  0 ) ==  none (int )
471+     assert  some (- 11 ).filterIt (it >  0 ) ==  none (int )
472+ 
473+   block :
474+     var  outcome =  value
475+     outcome.withValue (it):
476+       if  not  action:
477+         outcome =  none (T)
478+     do :
479+       outcome =  none (T)
480+     outcome
481+ 
482+ template  applyIt * [T](value: Option [T], action: untyped ) = 
483+   # # Executes a code block if the `Option` is `some`, assigning the value to a variable named `it`
484+   runnableExamples:
485+     var  value: string 
486+     some (" foo" 
487+       value =  it
488+     assert  value ==  " foo" 
489+ 
490+     none (string ).applyIt:
491+       assert  false 
492+ 
493+   value.withValue (it):
494+     action
495+ 
496+ template  `or` * [T](a, b: Option [T]): Option [T] = 
497+   # # Returns the value of the `Option` if it has one, otherwise returns the other `Option`.
498+   runnableExamples:
499+     assert ((some (42 ) or  some (9999 )) ==  some (42 ))
500+     assert ((none (int ) or  some (9999 )) ==  some (9999 ))
501+     assert ((none (int ) or  none (int )) ==  none (int ))
502+   block :
503+     evalOnceAs (local, a)
504+     if  local.isSome:
505+       local
506+     else :
507+       b
0 commit comments