Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how can i pass continuation proc as an argument? #323

Closed
blackmius opened this issue Feb 26, 2024 · 7 comments
Closed

how can i pass continuation proc as an argument? #323

blackmius opened this issue Feb 26, 2024 · 7 comments

Comments

@blackmius
Copy link

blackmius commented Feb 26, 2024

I want to pass cps proc to another proc to be called

proc a(fn: proc(): int {.cps: Continuation.}) {.cps: Continuation} =
  let res = fn()
  echo res
proc b(): int {.cps: Continuation.} =
  jield()
  return 10
a(b)

a bit extended example why i want it

import std/httpcore
import std/uri
import pkg/cps

import uasync
import socket

type
  ServeOptions = object
    port: int
    hostname: string
  Request = ref object
    socket: Socket
    `method`: string
    url: Uri
  Response = ref object
    a: int
  ServeHandler = proc (req: Request): Response {.cps: Continuation.}
  HttpServer = ref object
    socket: Socket

proc serve(options: ServeOptions, handler: ServeHandler): HttpServer {.cps: Continuation.} =
  new result
  let socket = newSocket()
  result.socket = socket
  socket.bindAddr(options.port.Port, options.hostname)
  socket.listen()
  while true:
    var conn = socket.accept()
    let resp = handler(Request(socket: conn, `method`: "heh", url: "https://google.com/".parseUri))
    conn.close()

when isMainModule:
  proc cb(req: Request): Response {.cps: Continuation.} =
      let data = req.socket.recv(100)
      echo data
      return nil
  discard serve(
    ServeOptions(port: 8000, hostname: "0.0.0.0"),
    cb
  )
  run()

So its some function that creates new continuation which result i can await in other continuation

@blackmius blackmius changed the title how to pass continuation procs as argument? how can i pass continuation proc as an argument? Feb 26, 2024
@alaviss
Copy link
Contributor

alaviss commented Feb 26, 2024

Use whelp to get a callable callback, similar to this test:

cps/tests/t30_cc.nim

Lines 62 to 81 in 0710578

block:
## run a callback from inside cps with callback type
var k = newKiller 4
type
ContCall = proc(a: int): int {.cps: Cont.}
proc bar(a: int): int {.cps: Cont.} =
noop()
step 3
return a * 2
proc foo(c: ContCall) {.cps: Cont.} =
step 1
var x = c.call(4)
step 2
check c.recover(x) == 8
step 4
foo: whelp bar

@blackmius
Copy link
Author

not working if continuation postpones in event loop

import pkg/cps

var wait: Continuation

proc noop(c: Continuation): Continuation {.cpsMagic.} =
  wait = c
  return nil

proc a(x: int): int {.cps: Continuation.} =
  noop()
  return x * 2
proc b(c: proc(x: int): int {.cps: Continuation.}) {.cps: Continuation.} =
  var y = c.call(10)
  echo c.recover(y)

b(whelp a)
discard trampoline wait
Hint: mm: orc; threads: on; opt: none (DEBUG BUILD, `-d:release` generates faster code)
54752 lines; 0.961s; 109.219MiB peakmem; proj: /home/user/projects/uasync/a.nim; out: /home/user/.cache/nim/a_d/a_6BFA856DD2FEC1A5D9900307EDBFB2556F9F1100 [SuccessX]
Hint: /home/user/.cache/nim/a_d/a_6BFA856DD2FEC1A5D9900307EDBFB2556F9F1100 [Exec]
/home/user/projects/uasync/a.nim(16) a
/home/user/projects/uasync/a.nim(12) b
/home/user/.nimble/pkgs/cps-0.10.2/cps/spec.nim(519) trampoline
/home/user/projects/uasync/a.nim(14) b_520095937
/home/user/.nimble/pkgs/cps-0.10.2/cps/spec.nim(648) recover
/home/user/.nimble/pkgs/cps-0.10.2/cps/environment.nim(484) cps:a() recover
/home/user/.nimble/pkgs/cps-0.10.2/cps/environment.nim(476) cps:a() recover
Error: unhandled exception: dismissed continuations have no result [Defect]
``

@blackmius
Copy link
Author

also is it possible to pass either a continuation or a regular function?

something like that

proc a(b: proc(x:int):int) {.cps: C}
proc a(b: proc(x:int):int {.cps: C}) {.cps: C}

@disruptek
Copy link
Contributor

Try the cc2 branch, which improves callback mechanics. Note that only natural call syntax is supported; the tests/t30_cc.nim has been updated.

@disruptek
Copy link
Contributor

Here's the updated form of your test, which prints 20:

import pkg/cps

var wait: Continuation

proc noop(c: Continuation): Continuation {.cpsMagic.} =
  wait = c
  return nil

proc a(x: int): int {.cps: Continuation.} =
  noop()
  return x * 2

type
  A = proc (x: int): int {.cps: Continuation.}

proc b(c: A) {.cps: Continuation.} =
  echo c(10)

b(whelp a)
discard trampoline wait

@disruptek
Copy link
Contributor

Also, yes, it is possible to overload a and then disambiguate with whelp(A, a) syntax to instantiate a particular form of callback.

@blackmius
Copy link
Author

blackmius commented Mar 8, 2024

Not working with lambdas, I think #218 related

import cps

proc a(b: proc() {.cps: Continuation.}) {.cps: Continuation.} =
  b()

a(proc () {.cps: Continuation.} =
  echo 1
)

Error: Expected a node of kind nnkProcDef, got nnkLambda

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants