diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2022-03-16 17:03:38 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2022-03-16 17:03:38 -0700 |
commit | b9c187d2594953267357ef37e352d425c7fbeafe (patch) | |
tree | 7c0ff7f3814475ac46c9af93d1b79d9e80f4bff6 /src | |
parent | ab89be1ed37351f4ff0a338b158d313e000751e3 (diff) | |
download | teliva-b9c187d2594953267357ef37e352d425c7fbeafe.tar.gz |
stop using tasks in start_reading/start_writing
We just need queues/streams for file I/O. No need to complect concurrency concerns with them.
Diffstat (limited to 'src')
-rw-r--r-- | src/file.lua | 79 | ||||
-rw-r--r-- | src/jsonf.lua | 28 |
2 files changed, 36 insertions, 71 deletions
diff --git a/src/file.lua b/src/file.lua index 81fe68d..2ac840f 100644 --- a/src/file.lua +++ b/src/file.lua @@ -1,42 +1,43 @@ -- primitive for reading files from a file system (or, later, network) --- returns a channel or nil on error --- read lines from the channel using :recv() --- recv() on the channel will indicate end of file. +-- returns an object or nil on error +-- read lines from the object using .read() with args similar to file:read() +-- read() will indicate end of file by returning nil. function start_reading(fs, filename) - local result = task.Channel:new() local infile = io.open(filename) if infile == nil then return nil end - task.spawn(reading_task, infile, result) - return result -end - -function reading_task(infile, chanout) - for line in infile:lines() do - chanout:send(line) - end - chanout:send(nil) -- eof + return { + read = coroutine.wrap(function(format) + while true do + if format == nil then format = '*l' end + format = coroutine.yield(infile:read(format)) + end + end), + } end -- primitive for writing files to a file system (or, later, network) --- returns a channel or nil on error --- write to the channel using :send() --- indicate you're done writing by calling :close() --- file will not be externally visible until :close() +-- returns an object or nil on error +-- write to the object using .write() +-- indicate you're done writing by calling .close() +-- file will not be externally visible until .close() function start_writing(fs, filename) if filename == nil then error('start_writing requires two arguments: a file-system (nil for real disk) and a filename') end - local result = task.Channel:new() local initial_filename = temporary_filename_in_same_volume(filename) local outfile = io.open(initial_filename, 'w') if outfile == nil then return nil end - result.close = function() - result:send(nil) -- end of file - outfile:close() - os.rename(initial_filename, filename) - end - task.spawn(writing_task, outfile, result) - return result + return { + write = coroutine.wrap(function(x) + while true do + x = coroutine.yield(outfile:write(x)) + end + end), + close = function() + outfile:close() + os.rename(initial_filename, filename) + end, + } end function temporary_filename_in_same_volume(filename) @@ -57,31 +58,3 @@ function temporary_filename_in_same_volume(filename) i = i+1 end end - -function writing_task(outfile, chanin) - while true do - local line = chanin:recv() - if line == nil then break end -- end of file - outfile:write(line) - end -end - --- start_reading reads line by line by default --- this helper permits character-by-character reading -function character_by_character(chanin, buffer_size) - local chanout = task.Channel:new(buffer_size or 50) - task.spawn(character_splitting_task, chanin, chanout) - return chanout -end - -function character_splitting_task(chanin, chanout) - while true do - local line = chanin:recv() - if line == nil then break end - local linesz = line:len() - for i=1,linesz do - chanout:send(line:sub(i, i)) - end - end - chanout:send(nil) -- end of file -end diff --git a/src/jsonf.lua b/src/jsonf.lua index 25e0c6e..aec0e0a 100644 --- a/src/jsonf.lua +++ b/src/jsonf.lua @@ -67,7 +67,7 @@ local literal_map = { local function skip_spaces(infile) while true do - local c = infile:recv() + local c = infile.read(1) if c == nil then break end if space_chars[c] == nil then return c end end @@ -79,7 +79,7 @@ local function next_chars(infile, set, firstc) local res = {firstc} local nextc while true do - nextc = infile:recv() + nextc = infile.read(1) if nextc == nil then break end if set[nextc] then break end table.insert(res, nextc) @@ -121,27 +121,27 @@ local function parse_string(infile, firstc) local res = {} while true do - local chr = infile:recv() + local chr = infile.read(1) if chr == nil then break end local x = chr:byte() if x < 32 then error("control character in string") elseif chr == '\\' then - local c = infile:recv() + local c = infile.read(1) if c == nil then break end if c == "u" then local hex = '' - c = infile:recv() + c = infile.read(1) if c == nil then break end hex = hex..c - c = infile:recv() + c = infile.read(1) if c == nil then break end hex = hex..c - c = infile:recv() + c = infile.read(1) if c == nil then break end hex = hex..c - c = infile:recv() + c = infile.read(1) if c == nil then break end hex = hex..c if not hex:match('^%x%x%x%x') then @@ -155,7 +155,7 @@ local function parse_string(infile, firstc) table.insert(res, escape_char_map_inv[c]) end elseif chr == '"' then - return table.concat(res), infile:recv() + return table.concat(res), infile.read(1) else table.insert(res, chr) end @@ -170,7 +170,7 @@ local function parse_number(infile, firstc) local res = {firstc} local nextc while true do - nextc = infile:recv() + nextc = infile.read(1) if nextc == nil then break end if delim_chars[nextc] then break end table.insert(res, nextc) @@ -295,14 +295,6 @@ end function jsonf.decode(infile) - return decode2(character_by_character(infile)) -end - - -function decode2(infile) - if not ischannel(infile) then - error("expected channel, got " .. type(f)) - end local firstc = skip_spaces(infile) local res, nextc = parse(infile, firstc) if nextc then |