I'm playing around a bit with writing a reactive programming lib for nim. Part 
of that means implementing Observers, which contain 3 callbacks: next, error 
and complete.

All 3 of these callbacks _must_ be async procs because they **might** contain 
async work done by the user. To keep that ability open I need to store them 
that way thusly and the type looks like this:
    
    
    type
      Observer*[T] = ref object
        next*: proc(value: T): Future[void] {.async.}
        error*: proc(error: ref CatchableError): Future[void] {.async.}
        complete*: proc(): Future[void] {.async.}
    
    
    Run

Now to keep the syntax convenient though, I want people to be able to just pass 
me synchronous callback functions and I convert them to asynchronous ones under 
the hood (well, really only for the type system because without await they'll 
be executing synchronously anyway and just return an immediately completed 
Future). So the code I want to allow looks like this:
    
    
    newObserver[int]((value: int) => echo "Value is: ", value)
    
    newObserver[int](
      proc(value: int) {.async.} =
        await asyncSleep(1000)
        echo "Value is: ", value
    )
    
    
    Run

My first draft of an implementation looks sth like this:
    
    
    proc newObserver*[T](
      next: proc(value: T) | proc(value: T) {.async.},
      error: proc(error: CatchableError) | proc(error: CatchableError) 
{.async.} = nil,
      complete: proc() | proc {.async.} = nil,
    ): Observer[T] =
      let nextProc = when next.isAsyncProc():
          next
        else:
          proc(value: T){.async.} = next(value)
      
      ... repeat this for error and complete to assign to errorProc and 
completeProc...
      
      Observer[T](
        next: nextProc,
        error: errorProc,
        complete: completeProc,
      )
    
    
    Run

Now the question is how to implement `isAsyncProc`. I know I could write a 
macro, but I feel like this should be solvable via simpler means.

These are the things I've already tried:
    
    
    import std/[asyncdispatch, macros]
    
    proc a() {.async.} = echo "Potato"
    
    echo a is proc(): Future[void] {.async.}
    echo a is proc(): Future[void]
    echo a is proc() {.async.}
    echo a.hasCustomPragma(async)
    
    
    Run

All of the above return false.

Reply via email to