1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
local lanes = require "lanes"
local fixture = require "fixture"
lanes.finally(fixture.throwing_finalizer)
local utils = lanes.require "_utils"
local PRINT = utils.MAKE_PRINT()
if true then
-- a lane body that just returns some value
local lane = function(msg_)
local utils = lanes.require "_utils"
local PRINT = utils.MAKE_PRINT()
PRINT "In lane"
assert(msg_ == "hi")
return "bye"
end
-- the generator
local g1 = lanes.coro("*", {name = "auto"}, lane)
-- launch lane
local h1 = g1("hi")
local r = h1[1]
assert(r == "bye")
end
-- a lane coroutine that yields back what got in, one element at a time
local yielder = function(...)
local utils = lanes.require "_utils"
local PRINT = utils.MAKE_PRINT()
PRINT "In lane"
for _i = 1, select('#', ...) do
local _val = select(_i, ...)
PRINT("yielding #", _i, _val)
local _ack = coroutine.yield(_val)
assert(_ack == _i)
end
return "done!"
end
if true then
-- if we start a non-coroutine lane with a yielding function, we should get an error, right?
local fun_g = lanes.gen("*", {name = "auto"}, yielder)
local h = fun_g("hello", "world", "!")
local err, status, stack = h:join()
PRINT(err, status, stack)
-- the actual error message is not the same for Lua 5.1
-- of course, it also has to be different for LuaJIT as well
-- also, LuaJIT prepends a file:line to the actual error message, which Lua5.1 does not.
local msgs = {
["Lua 5.1"] = jit and "attempt to yield across C-call boundary" or "attempt to yield across metamethod/C-call boundary",
["Lua 5.2"] = "attempt to yield from outside a coroutine",
["Lua 5.3"] = "attempt to yield from outside a coroutine",
["Lua 5.4"] = "attempt to yield from outside a coroutine"
}
local expected_msg = msgs[_VERSION]
PRINT("expected_msg = " .. expected_msg)
assert(err == nil and string.find(status, expected_msg, 1, true) and stack == nil, "status = " .. status)
end
-- the generator
local coro_g = lanes.coro("*", {name = "auto"}, yielder)
if true then
-- launch coroutine lane
local h2 = coro_g("hello", "world", "!")
-- read the yielded values, sending back the expected index
assert(h2:resume(1) == "hello")
assert(h2:resume(2) == "world")
assert(h2:resume(3) == "!")
-- the lane return value is available as usual
local r = h2[1]
assert(r == "done!")
end
if true then
-- another coroutine lane
local h3 = coro_g("hello", "world", "!")
-- yielded values are available as regular return values
assert(h3[1] == "hello" and h3.status == "suspended")
-- since we consumed the returned values, they should not be here when we resume
assert(h3:resume(1) == nil)
-- similarly, we can get them with join()
assert(h3:join() == "world" and h3.status == "suspended")
-- since we consumed the returned values, they should not be here when we resume
assert(h3:resume(2) == nil)
-- the rest should work as usual
assert(h3:resume(3) == "!")
-- the final return value of the lane body remains to be read
assert(h3:join() == "done!" and h3.status == "done")
end
|