summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/asyncdispatch.nim31
-rw-r--r--lib/pure/options.nim64
2 files changed, 83 insertions, 12 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index ab462c57b..110bc6d74 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1468,16 +1468,25 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   hint("Processing " & prc[0].getName & " as an async proc.")
 
   let returnType = prc[3][0]
+  var baseType: NimNode
   # Verify that the return type is a Future[T]
-  if returnType.kind == nnkIdent:
-    error("Expected return type of 'Future' got '" & $returnType & "'")
-  elif returnType.kind == nnkBracketExpr:
-    if $returnType[0] != "Future":
-      error("Expected return type of 'Future' got '" & $returnType[0] & "'")
+  if returnType.kind == nnkBracketExpr:
+    let fut = repr(returnType[0])
+    if fut != "Future":
+      error("Expected return type of 'Future' got '" & fut & "'")
+    baseType = returnType[1]
+  elif returnType.kind in nnkCallKinds and $returnType[0] == "[]":
+    let fut = repr(returnType[1])
+    if fut != "Future":
+      error("Expected return type of 'Future' got '" & fut & "'")
+    baseType = returnType[2]
+  elif returnType.kind == nnkEmpty:
+    baseType = returnType
+  else:
+    error("Expected return type of 'Future' got '" & repr(returnType) & "'")
 
   let subtypeIsVoid = returnType.kind == nnkEmpty or
-        (returnType.kind == nnkBracketExpr and
-         returnType[1].kind == nnkIdent and returnType[1].ident == !"void")
+        (baseType.kind == nnkIdent and returnType[1].ident == !"void")
 
   var outerProcBody = newNimNode(nnkStmtList, prc[6])
 
@@ -1485,7 +1494,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   var retFutureSym = genSym(nskVar, "retFuture")
   var subRetType =
     if returnType.kind == nnkEmpty: newIdentNode("void")
-    else: returnType[1]
+    else: baseType
   outerProcBody.add(
     newVarStmt(retFutureSym,
       newCall(
@@ -1509,7 +1518,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
       newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
 
     procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
-      newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
+      newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
 
     procBody.insert(2, newNimNode(nnkPragma).add(
       newIdentNode("pop"))) # -> {.pop.})
@@ -1550,8 +1559,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
-  if prc[0].getName == "hubConnectionLoop":
-    echo(toStrLit(result))
+  #if prc[0].getName == "hubConnectionLoop":
+  #  echo(toStrLit(result))
 
 macro async*(prc: stmt): stmt {.immediate.} =
   ## Macro which processes async procedures into the appropriate
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index ef01e1260..3122d58b1 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -108,6 +108,36 @@ proc get*[T](self: Option[T]): T =
     raise UnpackError(msg : "Can't obtain a value from a `none`")
   self.val
 
+proc get*[T](self: Option[T], otherwise: T): T =
+  ## Returns the contents of this option or `otherwise` if the option is none.
+  if self.isSome:
+    self.val
+  else:
+    otherwise
+
+
+proc map*[T](self: Option[T], callback: proc (input: T)) =
+  ## Applies a callback to the value in this Option
+  if self.has:
+    callback(self.val)
+
+proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] =
+  ## Applies a callback to the value in this Option and returns an option
+  ## containing the new value. If this option is None, None will be returned
+  if self.has:
+    some[R]( callback(self.val) )
+  else:
+    none(R)
+
+proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] =
+  ## Applies a callback to the value in this Option. If the callback returns
+  ## `true`, the option is returned as a Some. If it returns false, it is
+  ## returned as a None.
+  if self.has and not callback(self.val):
+    none(T)
+  else:
+    self
+
 
 proc `==`*(a, b: Option): bool =
   ## Returns ``true`` if both ``Option``s are ``none``,
@@ -115,8 +145,16 @@ proc `==`*(a, b: Option): bool =
   (a.has and b.has and a.val == b.val) or (not a.has and not b.has)
 
 
+proc `$`*[T]( self: Option[T] ): string =
+  ## Returns the contents of this option or `otherwise` if the option is none.
+  if self.has:
+    "Some(" & $self.val & ")"
+  else:
+    "None[" & T.name & "]"
+
+
 when isMainModule:
-  import unittest
+  import unittest, sequtils
 
   suite "optionals":
     # work around a bug in unittest
@@ -158,3 +196,27 @@ when isMainModule:
         check false
       when compiles(none(string) == none(int)):
         check false
+
+    test "get with a default value":
+      check( some("Correct").get("Wrong") == "Correct" )
+      check( stringNone.get("Correct") == "Correct" )
+
+    test "$":
+      check( $(some("Correct")) == "Some(Correct)" )
+      check( $(stringNone) == "None[string]" )
+
+    test "map with a void result":
+      var procRan = 0
+      some(123).map(proc (v: int) = procRan = v)
+      check procRan == 123
+      intNone.map(proc (v: int) = check false)
+
+    test "map":
+      check( some(123).map(proc (v: int): int = v * 2) == some(246) )
+      check( intNone.map(proc (v: int): int = v * 2).isNone )
+
+    test "filter":
+      check( some(123).filter(proc (v: int): bool = v == 123) == some(123) )
+      check( some(456).filter(proc (v: int): bool = v == 123).isNone )
+      check( intNone.filter(proc (v: int): bool = check false).isNone )
+