tal/mod/pipes.lua
2025-02-06 02:30:52 +02:00

146 lines
2.9 KiB
Lua

local io = io or require "io";
local exports = {};
--- The default buffer size used by read operations
exports.BUFF_SIZE = 4096;
--- @alias Reader fun(n: number, no_throw?: boolean): string?, string?
--- @alias Writer fun(data: string | nil, no_throw?: boolean): true?, string?
--- Creates a reader from the path
--- @param path string
--- @return Reader? result
function exports.reader(path, force_file)
if path == "-" and not force_file then return exports.stdin end
return exports.reader_from(io.open(path, "rb"))
end
--- @param f? file*
--- @return Reader? result
function exports.reader_from(f, ...)
f = assert(f, ...);
return function (n)
if n == nil then n = exports.BUFF_SIZE end
if n < 0 then
if f ~= nil then
f:close();
f = nil;
end
elseif f == nil then
error("File closed", 2);
else
local res = f:read(n);
if res == nil then
f:close();
f = nil;
return "";
else
return res;
end
end
end
end
--- Creates a writer from the path
--- @param path string
--- @return Writer? result
function exports.writer(path, force_file)
if path == "-" and not force_file then return exports.stdout end
return exports.writer_from(io.open(path, "wb"))
end
--- @param f? file*
--- @return Writer? result
function exports.writer_from(f, ...)
f = assert(f, ...);
return function (data)
if data == nil then
if f ~= nil then
f:close();
f = nil;
end
return true, nil;
elseif f == nil then
error("File closed", 2);
else
local res, w_err = f:write(data);
if res == nil then
error(w_err, 2);
else
return true;
end
end
end
end
--- Writes the full contents of src to dst. Since src is read until its end, it will be closed after this function
--- @param src Reader
--- @param dst Writer
--- @param close_dst boolean? Wether or not to close dst after copying
function exports.copy(src, dst, close_dst)
local res, buff, err, failed;
while true do
buff, err = src(4096, true);
if buff == nil and err ~= nil then
error(err, 2);
elseif buff == nil or buff == "" then
break;
else
res, err = dst(buff, true)
if res == nil then
error(err, 2);
end
end
end
if close_dst then
res, err = dst(nil, true);
if res == nil then
error(err, 2);
end
end
if failed then
error(err, 2);
end
end
function exports.loader(...)
local arr = {...};
local i = 1;
return function ()
while true do
local el = arr[i];
if el == "" then
i = i + 1;
elseif el == nil then
return nil;
elseif type(el) == "function" then
local buff = el();
if buff ~= "" then
return buff;
else
i = i + 1;
end
elseif type(el) == "string" then
i = i + 1;
return el;
else
error("Loader may consist only of strings and functions");
end
end
end
end
exports.stdin = exports.writer_from(io.stdin);
exports.stdout = exports.writer_from(io.stdout);
exports.stderr = exports.writer_from(io.stderr);