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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
-- lib/supple/request.lua
--
-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine
--
-- Contextual object storage and identification. Wrapping and unwrapping.
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
-- For licence terms, see COPYING
--
local gc = collectgarbage
local capi = require 'supple.capi'
local my_objects_by_obj = {}
local my_objects_by_tag = {}
local my_name = "UNSET"
local my_counter = 0
local their_objects_by_tag = setmetatable({}, { __mode="v" })
local their_objects_by_obj = setmetatable({}, { __mode="k" })
local proc_call = nil
local type = capi.rawtype
local function clean_down(call_other_end)
-- And force a full GC
gc "collect"
gc "collect"
gc "collect"
-- Call the other end if needed
if call_other_end then
proc_call("supple:clean_down", "__call")
end
-- And forget all our local objects
my_objects_by_obj = {}
my_objects_by_tag = {}
end
local function set_name(newname)
my_name = newname
end
local function get_name()
return my_name
end
local function set_proc_call(pc)
proc_call = pc
end
local integral = {
["nil"] = true,
boolean = true,
string = true,
number = true,
}
local function new_tag(special_tag)
local retstr = special_tag
if not retstr then
if not my_name:match("%%d") then
retstr = ("%s:%d"):format(my_name, my_counter)
else
retstr = my_name:format(my_counter)
end
my_counter = my_counter + 1
end
return retstr
end
local function give(obj, special_tag)
-- If the object is integral, return it directly
if integral[type(obj)] then
return obj
end
-- If the passed object is one of their objects then "unwrap" it by
-- returning their tag.
local tag = their_objects_by_obj[obj];
if tag then
return { tag = tag }
end
-- If it's one of our objects which has already been wrapped, return our
-- tag
local tag = my_objects_by_obj[obj]
if tag then
return { tag = tag }
end
-- otherwise wrap it freshly for us and return that.
local tag = new_tag(special_tag)
local expn = capi.explain(obj, tag)
my_objects_by_obj[obj] = tag
my_objects_by_tag[tag] = obj
return expn
end
local function receive(obj)
-- If the object is integral, return it directly
if integral[type(obj)] then
return obj
end
-- It's not integral, so it must be a tagged object
assert(type(obj) == "table")
assert(type(obj.tag) == "string")
local tag = obj.tag
-- First up, is it one of our objects?
local ret = my_objects_by_tag[tag]
if ret then
return ret
end
-- Now is it a known one of their objects?
ret = their_objects_by_tag[tag]
if ret then
return ret
end
-- Okay, prepare a proxy?
assert(type(obj.type) == "string")
local proxy, mt = capi.new_proxy(obj.type)
assert(capi.type(proxy) == obj.type)
their_objects_by_tag[tag] = proxy
their_objects_by_obj[proxy] = tag
-- Fill out the metatable
obj.methods = obj.methods or {}
obj.methods[#obj.methods+1] = "__gc"
if obj.type == "function" then
obj.methods[#obj.methods+1] = "__call"
end
if obj.type == "table" then
obj.methods[#obj.methods+1] = "__len"
obj.methods[#obj.methods+1] = "__index"
obj.methods[#obj.methods+1] = "__newindex"
end
for _, name in ipairs(obj.methods or {}) do
local function meta_func(mobj, ...)
return proc_call(tag, name, ...)
end
mt[name] = meta_func
end
-- And return the proxy object
return proxy
end
local function forget_mine(tag)
local obj = my_objects_by_tag[tag]
my_objects_by_tag[tag] = nil
my_objects_by_obj[obj] = nil
end
local function find_tag(obj)
if my_objects_by_obj[obj] then
return "my", my_objects_by_obj[obj]
end
if their_objects_by_obj[obj] then
return "their", their_objects_by_obj[obj]
end
end
return {
set_name = set_name,
get_name = get_name,
set_proc_call = set_proc_call,
give = give,
receive = receive,
clean_down = clean_down,
forget_mine = forget_mine,
find_tag = find_tag,
}
|