diff --git a/doc/ru/scripting/io_stream.md b/doc/ru/scripting/io_stream.md index cc3403eda..2362682ad 100644 --- a/doc/ru/scripting/io_stream.md +++ b/doc/ru/scripting/io_stream.md @@ -188,6 +188,16 @@ io_stream:close() -- Вызывает ioLib.flush() в all flush-режиме io_stream:flush() +-- Создаёт новый поток из Bytearray. +-- Может использоваться одновременно как для чтения, так и для записи. +-- Результат записи будет записан в тот же Bytearray, что был передан в функцию. +io_stream.wrap_bytearray( + buffer: Bytearray, + + -- по-умолчанию равен true, поскольку функция из вводных аргументов + -- будет использоваться преимущественно для работы с двоичными данными. + [опционально] binaryMode: boolean = true + ) -> io_stream -- Создаёт новый поток с переданным дескриптором и использующим переданную I/O библиотеку. (Более подробно в core:io_stream.lua) io_stream.new( diff --git a/res/modules/internal/stream_providers/bytearray.lua b/res/modules/internal/stream_providers/bytearray.lua new file mode 100644 index 000000000..6909bdf5c --- /dev/null +++ b/res/modules/internal/stream_providers/bytearray.lua @@ -0,0 +1,126 @@ +local io_stream = require "core:io_stream" + +local lib = { } + +local buffers = { } +local positions = { } + +local nextDescriptor = 0 + +local function openDescriptor(buffer) + nextDescriptor = nextDescriptor + 1 + + buffers[nextDescriptor] = buffer + positions[nextDescriptor] = 1 + + return nextDescriptor +end + +local function requireDescriptor(descriptor) + if not buffers[descriptor] then + error("unknown descriptor") + end +end + +function lib.read(descriptor, length) + requireDescriptor(descriptor) + + local buf = buffers[descriptor] + local bufLength = #buf + local pos = positions[descriptor] + + local toRead = math.min(bufLength - pos + 1, length) + + if toRead <= 0 then + return Bytearray() + end + + local segment = buf:slice(pos, toRead) + + positions[descriptor] = pos + toRead + + return segment +end + +function lib.write(descriptor, data) + requireDescriptor(descriptor) + + local buf = buffers[descriptor] + local pos = positions[descriptor] + + local bufLength = #buf + local dataLength = #data + + local endPos = pos + dataLength - 1 + + -- size ensuring + if endPos > bufLength then + for i = bufLength + 1, endPos do + buf[i] = 0 + end + end + + for i = 1, dataLength do + buf[i + pos - 1] = data[i] + end + + positions[descriptor] = pos + dataLength +end + +function lib.seek(descriptor, mode, offset) + requireDescriptor(descriptor) + + local buf = buffers[descriptor] + local bufLength = #buf + + local base + + if mode == 'b' then + base = 1 + elseif mode == 'c' then + base = positions[descriptor] + elseif mode == 'e' then + base = bufLength + 1 + else error('invalid seek mode') end + + local newPos = base + offset + + if newPos < 1 then + error('failed to seek stream') + end + + positions[descriptor] = newPos +end + +function lib.tell(descriptor) + requireDescriptor(descriptor) + + return positions[descriptor] +end + +function lib.flush(descriptor) + requireDescriptor(descriptor) +end + +function lib.is_alive(descriptor) + return buffers[descriptor] ~= nil +end + +function lib.close(descriptor) + requireDescriptor(descriptor) + + buffers[descriptor] = nil + positions[descriptor] = nil +end + +return function(buffer, binaryMode) + if binaryMode == nil then + binaryMode = true + end + + return io_stream.new( + openDescriptor(buffer), + binaryMode, + lib + ) +end \ No newline at end of file diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 093501d75..17da8ba85 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -332,6 +332,8 @@ else os.pid = ffi.C.getpid() end +require("core:io_stream").wrap_bytearray = require "core:internal/stream_providers/bytearray" + math.randomseed(time.uptime() * 1536227939) rules = require "core:internal/rules"