hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit a4370b1b1648c5fb1007bf5b3ffd11309088eb3e
parent 823a374f32bdb66044f2bf1b6301838c7df06159
Author: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
Date:   Wed, 10 Mar 2021 23:46:22 +0100

bufio::dynamic: implement seek()

Diffstat:
Mbufio/dynamic.ha | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 64 insertions(+), 7 deletions(-)

diff --git a/bufio/dynamic.ha b/bufio/dynamic.ha @@ -4,6 +4,7 @@ use io; type dynamic_stream = struct { stream: io::stream, buf: []u8, + pos: size, }; // Creates an [io::stream] which dynamically allocates a buffer to store writes @@ -23,9 +24,11 @@ export fn dynamic_from(in: []u8, mode: io::mode) *io::stream = { let s = alloc(dynamic_stream { stream = io::stream { closer = &dynamic_close, + seeker = &dynamic_seek, ... }, buf = in, + pos = 0, }): *io::stream; if (mode & io::mode::READ == io::mode::READ) { s.reader = &dynamic_read; @@ -38,16 +41,64 @@ export fn dynamic_from(in: []u8, mode: io::mode) *io::stream = { fn dynamic_write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *dynamic_stream; - append(s.buf, ...buf); + if (s.pos == len(s.buf)) { + append(s.buf, ...buf); + } else { + // TODO: update this after we add insert + let new: []u8 = alloc([], len(s.buf) + len(buf)); + new[..s.pos] = s.buf[..s.pos]; + new[s.pos..s.pos + len(buf)] = buf[..]; + new[s.pos + len(buf)..] = s.buf[s.pos..]; + free(s.buf); + s.buf = new; + }; + + s.pos += len(buf); return len(buf); }; fn dynamic_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { let s = s: *dynamic_stream; - const sz = if (len(buf) > len(s.buf)) len(s.buf) else len(buf); - buf[..sz] = s.buf[..sz]; - delete(s.buf[..sz]); - return if (sz == 0) io::EOF else sz; + if (len(s.buf) == s.pos && len(buf) != 0) { + return io::EOF; + }; + const n = if (len(s.buf) - s.pos < len(buf)) { + len(s.buf) - s.pos; + } else { + len(buf); + }; + buf[..n] = s.buf[s.pos..s.pos + n]; + s.pos += n; + return n; +}; + +fn dynamic_seek( + s: *io::stream, + off: io::off, + w: io::whence +) (io::off | io::error) = { + let stream = s: *dynamic_stream; + switch (w) { + io::whence::SET => { + if (len(stream.buf) < off: size) { + abort("invalid offset"); + }; + stream.pos = off: size; + }, + io::whence::CUR => { + if (stream.pos + off: size > len(stream.buf)) { + abort("invalid offset"); + }; + stream.pos += off: size; + }, + io::whence::END => { + if (len(stream.buf) - (-off): size < len(stream.buf)) { + abort("invalid offset"); + }; + stream.pos = len(stream.buf) - (-off): size; + }, + }; + return stream.pos: io::off; }; fn dynamic_close(s: *io::stream) void = { @@ -84,6 +135,7 @@ export fn reset(s: *io::stream) void = { abort("bufio::reset called on non-bufio stream"); }; const s = s: *dynamic_stream; + s.pos = 0; s.buf = s.buf[..0]; }; @@ -94,6 +146,7 @@ export fn truncate(s: *io::stream) (void | io::unsupported) = { return io::unsupported; }; let s = s: *dynamic_stream; + s.pos = 0; delete(s.buf[..]); }; @@ -105,11 +158,13 @@ export fn truncate(s: *io::stream) (void | io::unsupported) = { assert(io::write(s, [4, 5]) as size == 2); assert(bytes::equal(buffer(s), [1, 2, 3, 4, 5])); let buf: [2]u8 = [0...]; + assert(io::seek(s, 0, io::whence::SET) as io::off == 0: io::off); assert(io::read(s, buf[..]) as size == 2 && bytes::equal(buf, [1, 2])); assert(io::read(s, buf[..]) as size == 2 && bytes::equal(buf, [3, 4])); assert(io::read(s, buf[..]) as size == 1 && buf[0] == 5); assert(io::read(s, buf[..]) is io::EOF); - assert(io::write(s, [1, 2, 3]) as size == 3); + assert(io::write(s, [6, 7, 8]) as size == 3); + assert(bytes::equal(buffer(s), [1, 2, 3, 4, 5, 6, 7, 8])); reset(s); assert(len(buffer(s)) == 0); assert(io::write(s, [1, 2, 3]) as size == 3); @@ -118,6 +173,7 @@ export fn truncate(s: *io::stream) (void | io::unsupported) = { let sl: []u8 = alloc([1, 2, 3]); let s = dynamic_from(sl, io::mode::WRITE); + assert(io::seek(s, 0, io::whence::END) as io::off == 3: io::off); assert(io::write(s, [4, 5, 6]) as size == 3); assert(bytes::equal(buffer(s), [1, 2, 3, 4, 5, 6])); // TODO: this should check for io::unsupported (harec bug prevents that) @@ -126,7 +182,8 @@ export fn truncate(s: *io::stream) (void | io::unsupported) = { sl = alloc([1, 2]); let s = dynamic_from(sl, io::mode::READ); - assert(io::read(s, buf[..]) as size == 2 && bytes::equal(buf, [1, 2])); + assert(io::read(s, buf[..1]) as size == 1 && buf[0] == 1); + assert(io::seek(s, 1, io::whence::CUR) as io::off == 2: io::off); assert(io::read(s, buf[..]) is io::EOF); // TODO: this should check for io::unsupported (harec bug prevents that) assert(io::write(s, [1, 2]) is io::error);