Advertisement
Antwanr942

ltn12 OC

Jul 19th, 2019
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.43 KB | None | 0 0
  1. -----------------------------------------------------------------------------
  2. -- LTN12 - Filters, sources, sinks and pumps.
  3. -- LuaSocket toolkit.
  4. -- Author: Diego Nehab
  5. -----------------------------------------------------------------------------
  6.  
  7. -----------------------------------------------------------------------------
  8. -- Declare module
  9. -----------------------------------------------------------------------------
  10. local string = require("string")
  11. local table = require("table")
  12. local base = _G
  13. local _M = {}
  14. if module then -- heuristic for exporting a global package table
  15.     ltn12 = _M
  16. end
  17. local filter,source,sink,pump = {},{},{},{}
  18.  
  19. _M.filter = filter
  20. _M.source = source
  21. _M.sink = sink
  22. _M.pump = pump
  23.  
  24. -- 2048 seems to be better in windows...
  25. _M.BLOCKSIZE = 2048
  26. _M._VERSION = "LTN12 1.0.3"
  27.  
  28. -----------------------------------------------------------------------------
  29. -- Filter stuff
  30. -----------------------------------------------------------------------------
  31. -- returns a high level filter that cycles a low-level filter
  32. function filter.cycle(low, ctx, extra)
  33.     base.assert(low)
  34.     return function(chunk)
  35.         local ret
  36.         ret, ctx = low(ctx, chunk, extra)
  37.         return ret
  38.     end
  39. end
  40.  
  41. -- chains a bunch of filters together
  42. -- (thanks to Wim Couwenberg)
  43. function filter.chain(...)
  44.     local arg = {...}
  45.     local n = select('#',...)
  46.     local top, index = 1, 1
  47.     local retry = ""
  48.     return function(chunk)
  49.         retry = chunk and retry
  50.         while true do
  51.             if index == top then
  52.                 chunk = arg[index](chunk)
  53.                 if chunk == "" or top == n then return chunk
  54.                 elseif chunk then index = index + 1
  55.                 else
  56.                     top = top+1
  57.                     index = top
  58.                 end
  59.             else
  60.                 chunk = arg[index](chunk or "")
  61.                 if chunk == "" then
  62.                     index = index - 1
  63.                     chunk = retry
  64.                 elseif chunk then
  65.                     if index == n then return chunk
  66.                     else index = index + 1 end
  67.                 else base.error("filter returned inappropriate nil") end
  68.             end
  69.         end
  70.     end
  71. end
  72.  
  73. -----------------------------------------------------------------------------
  74. -- Source stuff
  75. -----------------------------------------------------------------------------
  76. -- create an empty source
  77. local function empty()
  78.     return nil
  79. end
  80.  
  81. function source.empty()
  82.     return empty
  83. end
  84.  
  85. -- returns a source that just outputs an error
  86. function source.error(err)
  87.     return function()
  88.         return nil, err
  89.     end
  90. end
  91.  
  92. -- creates a file source
  93. function source.file(handle, io_err)
  94.     if handle then
  95.         return function()
  96.             local chunk = handle:read(_M.BLOCKSIZE)
  97.             if not chunk then handle:close() end
  98.             return chunk
  99.         end
  100.     else return source.error(io_err or "unable to open file") end
  101. end
  102.  
  103. -- turns a fancy source into a simple source
  104. function source.simplify(src)
  105.     base.assert(src)
  106.     return function()
  107.         local chunk, err_or_new = src()
  108.         src = err_or_new or src
  109.         if not chunk then return nil, err_or_new
  110.         else return chunk end
  111.     end
  112. end
  113.  
  114. -- creates string source
  115. function source.string(s)
  116.     if s then
  117.         local i = 1
  118.         return function()
  119.             local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1)
  120.             i = i + _M.BLOCKSIZE
  121.             if chunk ~= "" then return chunk
  122.             else return nil end
  123.         end
  124.     else return source.empty() end
  125. end
  126.  
  127. -- creates rewindable source
  128. function source.rewind(src)
  129.     base.assert(src)
  130.     local t = {}
  131.     return function(chunk)
  132.         if not chunk then
  133.             chunk = table.remove(t)
  134.             if not chunk then return src()
  135.             else return chunk end
  136.         else
  137.             table.insert(t, chunk)
  138.         end
  139.     end
  140. end
  141.  
  142. function source.chain(src, f)
  143.     base.assert(src and f)
  144.     local last_in, last_out = "", ""
  145.     local state = "feeding"
  146.     local err
  147.     return function()
  148.         if not last_out then
  149.             base.error('source is empty!', 2)
  150.         end
  151.         while true do
  152.             if state == "feeding" then
  153.                 last_in, err = src()
  154.                 if err then return nil, err end
  155.                 last_out = f(last_in)
  156.                 if not last_out then
  157.                     if last_in then
  158.                         base.error('filter returned inappropriate nil')
  159.                     else
  160.                         return nil
  161.                     end
  162.                 elseif last_out ~= "" then
  163.                     state = "eating"
  164.                     if last_in then last_in = "" end
  165.                     return last_out
  166.                 end
  167.             else
  168.                 last_out = f(last_in)
  169.                 if last_out == "" then
  170.                     if last_in == "" then
  171.                         state = "feeding"
  172.                     else
  173.                         base.error('filter returned ""')
  174.                     end
  175.                 elseif not last_out then
  176.                     if last_in then
  177.                         base.error('filter returned inappropriate nil')
  178.                     else
  179.                         return nil
  180.                     end
  181.                 else
  182.                     return last_out
  183.                 end
  184.             end
  185.         end
  186.     end
  187. end
  188.  
  189. -- creates a source that produces contents of several sources, one after the
  190. -- other, as if they were concatenated
  191. -- (thanks to Wim Couwenberg)
  192. function source.cat(...)
  193.     local arg = {...}
  194.     local src = table.remove(arg, 1)
  195.     return function()
  196.         while src do
  197.             local chunk, err = src()
  198.             if chunk then return chunk end
  199.             if err then return nil, err end
  200.             src = table.remove(arg, 1)
  201.         end
  202.     end
  203. end
  204.  
  205. -----------------------------------------------------------------------------
  206. -- Sink stuff
  207. -----------------------------------------------------------------------------
  208. -- creates a sink that stores into a table
  209. function sink.table(t)
  210.     t = t or {}
  211.     local f = function(chunk, err)
  212.         if chunk then table.insert(t, chunk) end
  213.         return 1
  214.     end
  215.     return f, t
  216. end
  217.  
  218. -- turns a fancy sink into a simple sink
  219. function sink.simplify(snk)
  220.     base.assert(snk)
  221.     return function(chunk, err)
  222.         local ret, err_or_new = snk(chunk, err)
  223.         if not ret then return nil, err_or_new end
  224.         snk = err_or_new or snk
  225.         return 1
  226.     end
  227. end
  228.  
  229. -- creates a file sink
  230. function sink.file(handle, io_err)
  231.     if handle then
  232.         return function(chunk, err)
  233.             if not chunk then
  234.                 handle:close()
  235.                 return 1
  236.             else return handle:write(chunk) end
  237.         end
  238.     else return sink.error(io_err or "unable to open file") end
  239. end
  240.  
  241. -- creates a sink that discards data
  242. local function null()
  243.     return 1
  244. end
  245.  
  246. function sink.null()
  247.     return null
  248. end
  249.  
  250. -- creates a sink that just returns an error
  251. function sink.error(err)
  252.     return function()
  253.         return nil, err
  254.     end
  255. end
  256.  
  257. -- chains a sink with a filter
  258. function sink.chain(f, snk)
  259.     base.assert(f and snk)
  260.     return function(chunk, err)
  261.         if chunk ~= "" then
  262.             local filtered = f(chunk)
  263.             local done = chunk and ""
  264.             while true do
  265.                 local ret, snkerr = snk(filtered, err)
  266.                 if not ret then return nil, snkerr end
  267.                 if filtered == done then return 1 end
  268.                 filtered = f(done)
  269.             end
  270.         else return 1 end
  271.     end
  272. end
  273.  
  274. -----------------------------------------------------------------------------
  275. -- Pump stuff
  276. -----------------------------------------------------------------------------
  277. -- pumps one chunk from the source to the sink
  278. function pump.step(src, snk)
  279.     local chunk, src_err = src()
  280.     local ret, snk_err = snk(chunk, src_err)
  281.     if chunk and ret then return 1
  282.     else return nil, src_err or snk_err end
  283. end
  284.  
  285. -- pumps all data from a source to a sink, using a step function
  286. function pump.all(src, snk, step)
  287.     base.assert(src and snk)
  288.     step = step or pump.step
  289.     while true do
  290.         local ret, err = step(src, snk)
  291.         if not ret then
  292.             if err then return nil, err
  293.             else return 1 end
  294.         end
  295.     end
  296. end
  297.  
  298. return _M
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement