hare

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

commit 0c7d20e3f19c5ca2c953027c57c3ad6ff2f3f5f5
parent a0bb2f51b8c5092304c7f7be1f30d783dfaee762
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 23 Feb 2021 09:41:56 -0500

bufio: add bufio::finish

Diffstat:
Mbufio/dynamic.ha | 47++++++++++++++++++++++++++++++++---------------
1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/bufio/dynamic.ha b/bufio/dynamic.ha @@ -6,57 +6,74 @@ type dynamic_stream = struct { buf: []u8, }; -fn dynamic_write(_s: *io::stream, buf: const []u8) (size | io::error) = { - const s = _s: *dynamic_stream; +fn dynamic_write(s: *io::stream, buf: const []u8) (size | io::error) = { + let s = s: *dynamic_stream; append(s.buf, ...buf); return len(buf); }; -fn dynamic_read(_s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { - const s = _s: *dynamic_stream; +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; }; -fn dynamic_close(_s: *io::stream) void = { - const s = _s: *dynamic_stream; +fn dynamic_close(s: *io::stream) void = { + const s = s: *dynamic_stream; free(s.buf); + free(s); +}; + +// Closes the stream without freeing the buffer, instead transferring ownership +// of it to the caller. +export fn finish(s: *io::stream) ([]u8 | io::unsupported) = { + if (s.writer != &dynamic_write || s.closer != &dynamic_close) { + return io::unsupported; + }; + let s = s: *dynamic_stream; + let buf = s.buf; + free(s); + return s.buf; }; // Returns the current buffer. -export fn buffer(_s: *io::stream) ([]u8 | io::unsupported) = { - if (_s.writer != &dynamic_write || _s.closer != &dynamic_close) { +export fn buffer(s: *io::stream) ([]u8 | io::unsupported) = { + if (s.writer != &dynamic_write || s.closer != &dynamic_close) { return io::unsupported; }; - const s = _s: *dynamic_stream; + let s = s: *dynamic_stream; return s.buf; }; // Resets the buffer's length to zero, but keeps the allocated memory around for // future writes. -export fn reset(_s: *io::stream) (void | io::unsupported) = { - if (_s.writer != &dynamic_write || _s.closer != &dynamic_close) { +export fn reset(s: *io::stream) (void | io::unsupported) = { + if (s.writer != &dynamic_write || s.closer != &dynamic_close) { return io::unsupported; }; - const s = _s: *dynamic_stream; + const s = s: *dynamic_stream; s.buf = s.buf[..0]; }; // Truncates the buffer, freeing memory associated with it and setting its // length to zero. -export fn truncate(_s: *io::stream) (void | io::unsupported) = { - if (_s.writer != &dynamic_write || _s.closer != &dynamic_close) { +export fn truncate(s: *io::stream) (void | io::unsupported) = { + if (s.writer != &dynamic_write || s.closer != &dynamic_close) { return io::unsupported; }; - const s = _s: *dynamic_stream; + let s = s: *dynamic_stream; delete(s.buf[..]); }; // Creates an [io::stream] which dynamically allocates a buffer to store writes // into. Subsequent reads will consume the buffered data. Upon failure to // allocate sufficient memory to store writes, the program aborts. +// +// Calling [io::close] on this stream will free the buffer. Call [bufio::finish] +// instead to free up resources associated with the stream, but transfer +// ownership of the buffer to the caller. export fn dynamic() *io::stream = alloc(dynamic_stream { stream = io::stream { writer = &dynamic_write,