[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: How to convert to-be-closed variable to normal one in runtime?
- From: Andrew Gierth <andrew@...>
- Date: Tue, 21 Jul 2020 13:13:47 +0100
>>>>> "Egor" == Egor Skriptunoff <egor.skriptunoff@gmail.com> writes:
Egor> Hi!
Egor> I have a problem while trying to use a to-be-closed variable as
Egor> usual upvalue. An upvalue's lifespan might go beyond the current
Egor> block, and the lifespan is unknown at compile time.
The approach I've been looking into is to make the equivalent of a C++
auto_ptr, i.e. an object whose sole responsibility is to proxy the
__close of another object.
I have a C implementation, because I also wanted to be able to do some
stuff from C modules with lua_toclose in a reasonably portable (between
5.3 and 5.4) way and almost all the code was the same, but a simple Lua
implementation could be done too (this is largely untested, but uses the
same API as the C version I have):
-- auto_close.lua
local emptytab = {}
local function get_close_method(o)
if type(o) == 'function' then
return o
end
-- relies on o's metatable not being hidden by __metatable
-- use debug.getmetatable or the C version if this is an issue
return (getmetatable(o or emptytab) or emptytab).__close or function()end
end
local function do_close(o,...)
local refobj = o.refobj
o.refobj = nil
return get_close_method(refobj)(refobj,...)
end
local function do_get(o)
return o.refobj
end
local function do_release(o)
local refobj = o.refobj
o.refobj = nil
return refobj
end
local meta = {
__close = do_close,
__call = do_get, -- just a convenience shorthand for :get()
__index = {
get = do_get,
release = do_release,
close = do_close
}
}
return function(o,...)
return setmetatable({ refobj = o }, meta), o, ...
end
--
Intended usage:
local auto_close = require 'auto_close'
-- note that this returns both the new close object _and_ all of
-- the original results
local fc <close>, f, err, errno = auto_close(io.open(whatever))
-- do stuff either with f, or fc() or fc:get() to access the file
-- then use fc:release() to release the underlying file from
-- the auto_close object
--
Andrew.