Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- if not love or not love.filesystem or not love.thread then
- error('This plugin for LOVE2D framework, and not works with other lua-builds'..
- 'Also it requires love.filesystem and love.thread modules', 2)
- end
- local thread = {}
- -- List for storing all thread names and checking unique names (links)
- local namelist = {}
- function namelist:checkName(name)
- for i, v in ipairs(self) do
- if name == v then return true end
- end
- end
- function namelist:removeName(name)
- for i, v in ipairs(threadlist) do
- if name == v then
- table.remove(threadlist, i)
- break
- end
- end
- end
- setmetatable(thread, {__call =
- function(self, name, userfunction, callbackList)
- --assertions
- name = type(name) == 'string' and name
- or error('Thread: arg#1 name as string expected, got '..type(name), 2)
- userfunction = type(userfunction) == 'string' and userfunction
- or error('Thread: arg#2 thread function as string expected, got '..type(userfunction), 2)
- --checking name
- if namelist:checkName(name) then error('Thread with this name "'..name..'" already exists', 2)
- else table.insert(namelist, name) end
- --check callbacks as functions
- if callbackList then
- for k, v in pairs(callbackList) do
- if type(v) ~= 'function' then v = nil end
- end
- end
- --if function is path to file - load it
- if love.filesystem.isFile(userfunction) then
- userfunction = love.filesystem.read(userfunction)
- end
- local o = {}
- o.name = name
- --class with set of thread functions
- local class = [[
- do
- arg = {...}
- local t = {}
- t.name = "REG_NAME"
- t.inner = love.thread.getChannel(t.name.."_i")
- t.outer = love.thread.getChannel(t.name.."_o")
- thread = {}
- function thread:push(data) t.outer:push(data) end
- local link = {}
- function link:new(inner, outer)
- return setmetatable({inner = inner, outer = outer}, {__index = link})
- end
- function link:clear()
- self.inner:clear()
- self.outer:clear()
- end
- function link:push(data) self.outer:push(data) end
- function link:pop() return self.inner:pop() end
- function thread:newLink(threadname)
- print(self:getName()..' create link to '..threadname)
- local nameA, nameB = self:getName(), threadname
- return nameA > nameB and
- link:new(
- love.thread.getChannel(nameA..nameB..'_blue'),
- love.thread.getChannel(nameA..nameB..'_red')
- )
- or
- link:new(
- love.thread.getChannel(nameB..nameA..'_red'),
- love.thread.getChannel(nameB..nameA..'_blue')
- )
- end
- function thread:clear() t.inner:clear(); t.outer:clear() end
- function thread:pop() return t.inner.pop() end
- function thread:getName() return t.name end
- function thread:getCount() return t.inner:getCount() end
- function thread:popAll()
- local o = {}
- local data = thread:pop()
- while data do
- table.insert(o, data)
- data = thread:pop()
- end
- return o
- end
- end
- ]]
- --set name of thread
- class = class:gsub('REG_NAME', o.name)
- --[[Replace all newline characters for make code-oneliner.
- Errors returns string number, but a lot of code before user
- functions make it difficult to find the line with the
- error is returned.]]
- class = class:gsub('[\n\r$]+', ' ')
- --remove all tab characters because i want it
- class = class:gsub('[ ]+', '')
- --i love gsub so much!
- o.thread = love.thread.newThread(class..userfunction..'\n\n\n\n'); class = nil
- o.callback = callbackList or {}
- o.channel = {}
- o.channel.i = love.thread.getChannel(o.name.."_i") --main --in channel--> thread
- o.channel.o = love.thread.getChannel(o.name.."_o") --main <-out channel-- thread
- o.dbg = true
- self.__index = self
- return setmetatable(o, self)
- end,})
- local cbNames = {'receive', 'finish', 'error', 'kill'}
- local function checkCallback(name)
- if not name or type(name) ~= 'string' then error('Thread:setCallback(name, func) arg#1 string expected got '..type(name), 3) end
- for i, v in ipairs(cbNames) do
- if v == name:lower() then return true end
- end
- end
- function thread:setCallback(name, f)
- if not checkCallback(name) then error('Thread:setCallback(name, func) arg#1 name must be '..table.concat(cbNames, ' or '), 2) end
- if type(f) ~= 'function' then error('Thread:setCallback(name, func) arg#2 func must be function', 2) end
- --List of name:
- ---receive: function(self, msg) Calls if thread send the message to parent program.
- ---finish: function(self, ...) Calls if thread finish self work. '...' contain all unreaded messages
- ---error: function(self, err) Calls if thread got error.
- ---kill: function(self) Calls if parent program kill the thread.
- self.callback[name:lower()] = f
- end
- function thread:start(...)
- self.thread:start(...)
- self.state = 'run'
- end
- function thread:kill()
- namelist:removeName(self.name)
- self.thread:kill()
- self:clear()
- local res = self.callback.kill and {self.callback.kill(self, self:receiveAll())}
- self = nil
- return unpack(res)
- end
- function thread:wait()
- self.state = 'wait'
- self.thread:wait()
- end
- function thread:isRunning()
- return self.thread:isRunning()
- end
- function thread:getError()
- return self.thread:getError()
- end
- function thread:send(data)
- self.channel.i:push(data)
- end
- function thread:supply(data)
- self.channel.i:supply(data)
- end
- function thread:receive()
- return self.channel.o:pop()
- end
- function thread:receiveAll()
- local o = {}
- for i = 1, self.channel.o:getCount() do
- table.insert(o, self:receive())
- end
- return o
- end
- function thread:clear()
- self.channel.i:clear()
- self.channel.o:clear()
- end
- function thread:getCount()
- return self.channel.o:getCount()
- end
- function thread:getChannel(name)
- return love.thread.getChannel(name)
- end
- function thread:debug(v)
- self.dbg = not not v
- end
- function thread:update()
- if self.state == 'run' then
- if not self.thread:isRunning() then
- self.state = 'finish'
- if self.callback.finish then
- self.callback.finish(self, self:receiveAll())
- self:clear()
- end
- end
- local err = self.thread:getError()
- if err and self.dbg then print('Thread "'..self.name..'" err: '..tostring(err)) end
- if err and self.callback.error then
- self.callback.error(self, err)
- elseif err then
- self:kill()
- end
- end
- if self.callback.receive then
- for _, data in ipairs(self:receiveAll()) do
- self.callback.receive(self, data)
- if self.dbg then
- print('Thread send msg: '..tostring(data))
- end
- end
- end
- end
- return thread
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement