commit fba5c36a64ffcf04660dc7fe0449bb267a783ea0
parent f6760e9e25d5607c430e6b204ea80f2db68679f0
Author: Alexey Yerin <yyp@disroot.org>
Date: Sun, 2 Jan 2022 12:59:55 +0300
strio: use caller allocation
Instead of allocated io::handle strio::dynamic() returns dynamic_stream
and strio::fixed() returns fixed_stream.
Also, strio::finish() is gone and should be replaced by strio::string(),
since the stream itself doesn't need to be freed.
Another update necessary is adding '&' to uses of strio streams:
let s = strio::dynamic();
// Previously: fmt::fprint(s, "Hiya")!;
fmt::fprint(&s, "Hiya")!;
// io::close(s);
io::close(&s);
Signed-off-by: Alexey Yerin <yyp@disroot.org>
Diffstat:
24 files changed, 172 insertions(+), 215 deletions(-)
diff --git a/cmd/haredoc/docstr.ha b/cmd/haredoc/docstr.ha
@@ -82,7 +82,7 @@ fn scantext(par: *parser) (token | void) = {
bufio::unreadrune(par.src, rn);
break;
case '\n' =>
- strio::appendrune(buf, rn)!;
+ strio::appendrune(&buf, rn)!;
const rn = match (bufio::scanrune(par.src)!) {
case io::EOF => break;
case let rn: rune =>
@@ -94,10 +94,10 @@ fn scantext(par: *parser) (token | void) = {
};
bufio::unreadrune(par.src, rn);
case =>
- strio::appendrune(buf, rn)!;
+ strio::appendrune(&buf, rn)!;
};
};
- let result = strio::finish(buf);
+ let result = strio::string(&buf);
if (len(result) == 0) {
return;
};
@@ -124,7 +124,7 @@ fn scanref(par: *parser) (token | void) = {
};
const buf = strio::dynamic();
- defer io::close(buf);
+ defer io::close(&buf);
// TODO: Handle invalid syntax here
for (true) {
match (bufio::scanrune(par.src)!) {
@@ -134,12 +134,12 @@ fn scanref(par: *parser) (token | void) = {
bufio::scanrune(par.src) as rune; // ]
break;
case =>
- strio::appendrune(buf, rn)!;
+ strio::appendrune(&buf, rn)!;
};
case io::EOF => break;
};
};
- let id = parse::identstr(strio::string(buf)) as ast::ident;
+ let id = parse::identstr(strio::string(&buf)) as ast::ident;
return id: reference;
};
@@ -175,9 +175,9 @@ fn scansample(par: *parser) (token | void) = {
};
switch (rn) {
case '\n' =>
- strio::appendrune(buf, rn)!;
+ strio::appendrune(&buf, rn)!;
case =>
- strio::appendrune(buf, rn)!;
+ strio::appendrune(&buf, rn)!;
continue;
};
@@ -192,7 +192,7 @@ fn scansample(par: *parser) (token | void) = {
case '\t' =>
i += 8;
case '\n' =>
- strio::appendrune(buf, rn)!;
+ strio::appendrune(&buf, rn)!;
i = 0;
case =>
bufio::unreadrune(par.src, rn);
@@ -203,7 +203,7 @@ fn scansample(par: *parser) (token | void) = {
};
};
- let buf = strio::finish(buf);
+ let buf = strio::string(&buf);
// Trim trailing newlines
for (strings::hassuffix(buf, "\n")) {
diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha
@@ -42,19 +42,19 @@ fn html_escape(out: io::handle, in: str) (size | io::error) = {
@test fn html_escape() void = {
let sink = strio::dynamic();
- defer io::close(sink);
- html_escape(sink, "hello world!")!;
- assert(strio::string(sink) == "hello world!");
+ defer io::close(&sink);
+ html_escape(&sink, "hello world!")!;
+ assert(strio::string(&sink) == "hello world!");
let sink = strio::dynamic();
- defer io::close(sink);
- html_escape(sink, "\"hello world!\"")!;
- assert(strio::string(sink) == ""hello world!"");
+ defer io::close(&sink);
+ html_escape(&sink, "\"hello world!\"")!;
+ assert(strio::string(&sink) == ""hello world!"");
let sink = strio::dynamic();
- defer io::close(sink);
- html_escape(sink, "<hello & 'world'!>")!;
- assert(strio::string(sink) == "<hello & 'world'!>");
+ defer io::close(&sink);
+ html_escape(&sink, "<hello & 'world'!>")!;
+ assert(strio::string(&sink) == "<hello & 'world'!>");
};
// Formats output as HTML
@@ -66,7 +66,7 @@ fn emit_html(ctx: *context) (void | error) = {
if (ctx.template) head(ctx.ident)?;
if (len(ident) == 0) {
- fmt::fprintf(ctx.out,
+ fmt::fprintf(ctx.out,
"<h2>The Hare standard library <span class='heading-extra'>",
ident)?;
} else {
@@ -567,10 +567,10 @@ fn type_html(
brief: bool,
) (size | io::error) = {
let buf = strio::dynamic();
- defer io::close(buf);
- unparse::_type(buf, indent, _type)?;
+ defer io::close(&buf);
+ unparse::_type(&buf, indent, _type)?;
if (brief) {
- return html_escape(out, strio::string(buf))?;
+ return html_escape(out, strio::string(&buf))?;
};
// TODO: More detailed formatter which can find aliases nested deeper in
@@ -711,14 +711,14 @@ fn breadcrumb(ident: ast::ident) str = {
return "";
};
let buf = strio::dynamic();
- fmt::fprintf(buf, "<a href='/'>stdlib</a> » ")!;
+ fmt::fprintf(&buf, "<a href='/'>stdlib</a> » ")!;
for (let i = 0z; i < len(ident) - 1; i += 1) {
let ipath = module::identpath(ident[..i+1]);
defer free(ipath);
- fmt::fprintf(buf, "<a href='/{}'>{}</a>::", ipath, ident[i])!;
+ fmt::fprintf(&buf, "<a href='/{}'>{}</a>::", ipath, ident[i])!;
};
- fmt::fprint(buf, ident[len(ident) - 1])!;
- return strio::finish(buf);
+ fmt::fprint(&buf, ident[len(ident) - 1])!;
+ return strio::string(&buf);
};
fn head(ident: ast::ident) (void | error) = {
@@ -731,7 +731,7 @@ fn head(ident: ast::ident) (void | error) = {
const title =
if (len(id) == 0)
fmt::asprintf("Hare documentation")
- else
+ else
fmt::asprintf("{} — Hare documentation", id);
defer free(title);
@@ -848,7 +848,7 @@ h4:target + pre {
details {
background: #eee;
- margin: 1rem -1rem 1rem;
+ margin: 1rem -1rem 1rem;
}
summary {
diff --git a/crypto/blake2b/+test.ha b/crypto/blake2b/+test.ha
@@ -23,8 +23,9 @@ use strio;
};
hash::finish(&blake, sum);
let out = strio::dynamic();
- hex::encode(out, sum)!;
- assert(strio::string(out) == vectors[i].out);
+ defer io::close(&out);
+ hex::encode(&out, sum)!;
+ assert(strio::string(&out) == vectors[i].out);
};
let blake = blake2b([], 64);
@@ -49,15 +50,15 @@ use strio;
hash::sum(&blake, sum);
let hex = strio::dynamic();
- defer io::close(hex);
+ defer io::close(&hex);
for (let j = 0z; j < len(sum); j += 1) {
- fmt::fprintf(hex, "{:02x}", sum[j])!;
+ fmt::fprintf(&hex, "{:02x}", sum[j])!;
};
- if (strio::string(hex) != vector.1) {
+ if (strio::string(&hex) != vector.1) {
fmt::errorfln("Vector {}: {} != {}",
- i, strio::string(hex), vector.1)!;
+ i, strio::string(&hex), vector.1)!;
abort();
};
};
diff --git a/encoding/base64/base64.ha b/encoding/base64/base64.ha
@@ -73,8 +73,8 @@ export fn encode(
// returns it. The caller must free the return value.
export fn encodestr(alphabet: []u8, b: []u8) str = {
let sink = strio::dynamic();
- encode(alphabet, sink, b) as size;
- return strio::finish(sink);
+ encode(alphabet, &sink, b) as size;
+ return strio::string(&sink);
};
@test fn encode() void = {
diff --git a/encoding/hex/hex.ha b/encoding/hex/hex.ha
@@ -27,8 +27,8 @@ export fn encode(sink: io::handle, b: []u8) (size | io::error) = {
// free the return value.
export fn encodestr(b: []u8) str = {
let sink = strio::dynamic();
- encode(sink, b) as size;
- return strio::finish(sink);
+ encode(&sink, b) as size;
+ return strio::string(&sink);
};
@test fn encode() void = {
@@ -111,9 +111,10 @@ export fn dump(out: io::handle, data: []u8) (void | io::error) = {
];
let sink = strio::dynamic();
- dump(sink, in) as void;
+ defer io::close(&sink);
+ dump(&sink, in) as void;
- let s = strio::finish(sink);
+ let s = strio::string(&sink);
assert(s ==
"00000000 7f 45 4c 46 02 01 01 00 ca fe ba be de ad f0 0d |.ELF............|\n"
"00000010 ce fe ba be de ad f0 0d |........|\n");
diff --git a/format/xml/parser.ha b/format/xml/parser.ha
@@ -43,9 +43,9 @@ export fn parser_free(par: *parser) void = {
if (par.close) {
io::close(par.in);
};
- io::close(par.namebuf);
- io::close(par.entbuf);
- io::close(par.textbuf);
+ io::close(&par.namebuf);
+ io::close(&par.entbuf);
+ io::close(&par.textbuf);
for (let i = 0z; i < len(par.tags); i += 1) {
free(par.tags[i]);
};
@@ -126,16 +126,16 @@ fn poptag(par: *parser, expect: str) (str | error) = {
if (expect != "" && expect != pop) {
return syntaxerr;
};
- strio::reset(par.namebuf);
- strio::concat(par.namebuf, pop)!;
- return strio::string(par.namebuf);
+ strio::reset(&par.namebuf);
+ strio::concat(&par.namebuf, pop)!;
+ return strio::string(&par.namebuf);
};
fn scan_attr(par: *parser) (token | error) = {
- let name = scan_name(par, par.namebuf)?;
+ let name = scan_name(par, &par.namebuf)?;
want(par, OPTWS, '=', OPTWS)?;
let quot = quote(par)?;
- strio::reset(par.textbuf);
+ strio::reset(&par.textbuf);
for (true) match (bufio::scanrune(par.in)?) {
case io::EOF =>
return syntaxerr;
@@ -150,9 +150,9 @@ fn scan_attr(par: *parser) (token | error) = {
yield rn;
};
if (rn == quot) break;
- strio::appendrune(par.textbuf, rn)?;
+ strio::appendrune(&par.textbuf, rn)?;
};
- return (name, strio::string(par.textbuf)): attribute;
+ return (name, strio::string(&par.textbuf)): attribute;
};
fn scan_comment(par: *parser) (token | void | error) = {
@@ -201,7 +201,7 @@ fn scan_comment(par: *parser) (token | void | error) = {
};
fn scan_cdata(par: *parser) (text | error) = {
- strio::reset(par.textbuf);
+ strio::reset(&par.textbuf);
for (true) {
const rn = match (bufio::scanrune(par.in)?) {
case io::EOF =>
@@ -210,7 +210,7 @@ fn scan_cdata(par: *parser) (text | error) = {
yield rn;
};
if (rn != ']') {
- strio::appendrune(par.textbuf, rn)!;
+ strio::appendrune(&par.textbuf, rn)!;
continue;
};
const rn = match (bufio::scanrune(par.in)?) {
@@ -220,7 +220,7 @@ fn scan_cdata(par: *parser) (text | error) = {
yield rn;
};
if (rn != ']') {
- strio::appendrune(par.textbuf, rn)!;
+ strio::appendrune(&par.textbuf, rn)!;
continue;
};
const rn = match (bufio::scanrune(par.in)?) {
@@ -230,13 +230,13 @@ fn scan_cdata(par: *parser) (text | error) = {
yield rn;
};
if (rn == '>') break;
- strio::appendrune(par.textbuf, rn)!;
+ strio::appendrune(&par.textbuf, rn)!;
};
- return strio::string(par.textbuf): text;
+ return strio::string(&par.textbuf): text;
};
fn scan_content(par: *parser) (text | error) = {
- strio::reset(par.textbuf);
+ strio::reset(&par.textbuf);
for (true) match (bufio::scanrune(par.in)?) {
case io::EOF =>
break;
@@ -251,9 +251,9 @@ fn scan_content(par: *parser) (text | error) = {
case =>
yield rn;
};
- strio::appendrune(par.textbuf, rn)?;
+ strio::appendrune(&par.textbuf, rn)?;
};
- return strio::string(par.textbuf);
+ return strio::string(&par.textbuf);
};
fn scan_element(par: *parser) (token | error) = {
@@ -270,7 +270,7 @@ fn scan_element(par: *parser) (token | error) = {
bufio::unreadrune(par.in, rn);
};
};
- let name = scan_name(par, par.namebuf)?;
+ let name = scan_name(par, &par.namebuf)?;
if (close) {
poptag(par, name)?;
return name: elementend;
@@ -312,7 +312,7 @@ fn scan_charref(par: *parser) (rune | error) = {
};
};
- strio::reset(par.entbuf);
+ strio::reset(&par.entbuf);
for (true) {
let rn = match (bufio::scanrune(par.in)?) {
case io::EOF =>
@@ -321,17 +321,17 @@ fn scan_charref(par: *parser) (rune | error) = {
yield rn;
};
if (ascii::isdigit(rn)) {
- strio::appendrune(par.entbuf, rn)?;
+ strio::appendrune(&par.entbuf, rn)?;
} else if (rn == ';') {
break;
} else {
return syntaxerr;
};
};
- if (len(strio::string(par.entbuf)) == 0) {
+ if (len(strio::string(&par.entbuf)) == 0) {
return syntaxerr;
};
- match (strconv::stou32b(strio::string(par.entbuf), base)) {
+ match (strconv::stou32b(strio::string(&par.entbuf), base)) {
case let u: u32 =>
return u: rune;
case (strconv::invalid | strconv::overflow) =>
@@ -340,7 +340,7 @@ fn scan_charref(par: *parser) (rune | error) = {
};
fn scan_namedent(par: *parser) (rune | error) = {
- const name = scan_name(par, par.entbuf)?;
+ const name = scan_name(par, &par.entbuf)?;
want(par, ';')?;
const map = [
("lt", '<'),
@@ -359,7 +359,7 @@ fn scan_namedent(par: *parser) (rune | error) = {
return syntaxerr;
};
-fn scan_name(par: *parser, buf: io::handle) (str | error) = {
+fn scan_name(par: *parser, buf: *strio::dynamic_stream) (str | error) = {
strio::reset(buf);
const rn = match (bufio::scanrune(par.in)?) {
diff --git a/format/xml/types.ha b/format/xml/types.ha
@@ -1,6 +1,7 @@
use encoding::utf8;
use io;
use os;
+use strio;
export type parser = struct {
in: io::handle,
@@ -10,9 +11,9 @@ export type parser = struct {
tags: []str,
// strio buffers:
- namebuf: io::handle,
- entbuf: io::handle,
- textbuf: io::handle,
+ namebuf: strio::dynamic_stream,
+ entbuf: strio::dynamic_stream,
+ textbuf: strio::dynamic_stream,
};
export type state = enum {
diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha
@@ -229,7 +229,7 @@ fn lex_string(lex: *lexer, loc: location) (token | error) = {
else {
unget(lex, r);
let r = lex_rune(lex, loc)?;
- strio::appendrune(buf, r)?;
+ strio::appendrune(&buf, r)?;
};
};
match (nextw(lex)?) {
@@ -238,13 +238,13 @@ fn lex_string(lex: *lexer, loc: location) (token | error) = {
if (r.0 == '"') {
const tok = lex_string(lex, loc)?;
const next = tok.1 as str;
- strio::concat(buf, next)!;
+ strio::concat(&buf, next)!;
free(next);
} else {
unget(lex, r);
};
};
- return (ltok::LIT_STR, strio::finish(buf), loc);
+ return (ltok::LIT_STR, strio::string(&buf), loc);
};
fn lex_rn_str(lex: *lexer) (token | error) = {
@@ -281,7 +281,7 @@ fn lex_name(lex: *lexer, loc: location, label: bool) (token | error) = {
match (next(lex)) {
case let r: (rune, location) =>
assert(is_name(r.0, false));
- strio::appendrune(buf, r.0)!;
+ strio::appendrune(&buf, r.0)!;
case (io::EOF | io::error) =>
abort();
};
@@ -293,10 +293,10 @@ fn lex_name(lex: *lexer, loc: location, label: bool) (token | error) = {
unget(lex, r);
break;
};
- strio::appendrune(buf, r.0)?;
+ strio::appendrune(&buf, r.0)?;
};
- let n = strio::finish(buf);
+ let n = strio::string(&buf);
if (label) {
return (ltok::LABEL, n, loc);
};
@@ -327,17 +327,17 @@ fn lex_comment(lexr: *lexer) (token | error) = {
};
let buf = strio::dynamic();
- defer io::close(buf);
+ defer io::close(&buf);
for (true) match (next(lexr)?) {
case io::EOF =>
break;
case let r: (rune, location) =>
- strio::appendrune(buf, r.0)!;
+ strio::appendrune(&buf, r.0)!;
if (r.0 == '\n') {
break;
};
};
- let new = strings::concat(lexr.comment, strio::string(buf));
+ let new = strings::concat(lexr.comment, strio::string(&buf));
free(lexr.comment);
lexr.comment = new;
return lex(lexr);
diff --git a/hare/module/context.ha b/hare/module/context.ha
@@ -99,11 +99,11 @@ export fn identpath(name: ast::ident) str = {
export fn identuscore(ident: ast::ident) str = {
let buf = strio::dynamic();
for (let i = 0z; i < len(ident); i += 1) {
- fmt::fprintf(buf, "{}{}", ident[i],
+ fmt::fprintf(&buf, "{}{}", ident[i],
if (i + 1 < len(ident)) "_"
else "") as size;
};
- return strio::finish(buf);
+ return strio::string(&buf);
};
@test fn identuscore() void = {
diff --git a/hare/module/scan.ha b/hare/module/scan.ha
@@ -419,13 +419,13 @@ export fn parsetags(in: str) ([]tag | void) = {
break;
case let r: rune =>
if (ascii::isalnum(r) || r == '_') {
- strio::appendrune(buf, r)!;
+ strio::appendrune(&buf, r)!;
} else {
strings::push(&iter, r);
break;
};
};
- t.name = strio::finish(buf);
+ t.name = strio::string(&buf);
append(tags, t);
};
return tags;
diff --git a/hare/parse/+test/roundtrip.ha b/hare/parse/+test/roundtrip.ha
@@ -24,9 +24,9 @@ fn roundtrip(src: str) void = {
};
defer ast::subunit_free(u);
let out = strio::dynamic();
- unparse::subunit(out, u) as size;
- let unsrc = strio::finish(out);
- defer free(unsrc);
+ defer io::close(&out);
+ unparse::subunit(&out, u) as size;
+ let unsrc = strio::string(&out);
if (unsrc != src) {
fmt::errorfln("=== wanted\n{}", src)!;
fmt::errorfln("=== got\n{}", unsrc)!;
diff --git a/hare/parse/parse.ha b/hare/parse/parse.ha
@@ -34,16 +34,16 @@ fn want(lexer: *lex::lexer, want: lex::ltok...) (lex::token | error) = {
};
let buf = strio::dynamic();
- defer io::close(buf);
+ defer io::close(&buf);
for (let i = 0z; i < len(want); i += 1) {
const tstr = lex::tokstr((want[i], void, lex::mkloc(lexer)));
- fmt::fprintf(buf, "'{}'", tstr)!;
+ fmt::fprintf(&buf, "'{}'", tstr)!;
if (i + 1 < len(want)) {
- fmt::fprint(buf, ", ")!;
+ fmt::fprint(&buf, ", ")!;
};
};
return syntaxerr(lex::mkloc(lexer), "Unexpected '{}', was expecting {}",
- lex::tokstr(tok), strio::string(buf));
+ lex::tokstr(tok), strio::string(&buf));
};
// Looks for a matching ltok from the lexer, and if not present, unlexes the
diff --git a/hare/unparse/decl.ha b/hare/unparse/decl.ha
@@ -89,8 +89,8 @@ export fn decl(out: io::handle, d: ast::decl) (size | io::error) = {
fn decl_test(d: ast::decl, expected: str) bool = {
let buf = strio::dynamic();
- decl(buf, d) as size;
- let s = strio::finish(buf);
+ decl(&buf, d) as size;
+ let s = strio::string(&buf);
defer free(s);
return s == expected;
};
diff --git a/hare/unparse/ident.ha b/hare/unparse/ident.ha
@@ -17,8 +17,8 @@ export fn ident(out: io::handle, id: ast::ident) (size | io::error) = {
// Unparses an identifier into a string. The caller must free the return value.
export fn identstr(id: ast::ident) str = {
let buf = strio::dynamic();
- ident(buf, id)!;
- return strio::finish(buf);
+ ident(&buf, id)!;
+ return strio::string(&buf);
};
@test fn ident() void = {
diff --git a/hare/unparse/import.ha b/hare/unparse/import.ha
@@ -29,24 +29,24 @@ export fn import(out: io::handle, i: ast::import) (size | io::error) = {
@test fn import() void = {
let buf = strio::dynamic();
- import(buf, ["foo", "bar", "baz"]) as size;
- let s = strio::finish(buf);
+ import(&buf, ["foo", "bar", "baz"]) as size;
+ let s = strio::string(&buf);
assert(s == "use foo::bar::baz;");
free(s);
buf = strio::dynamic();
- import(buf, ast::import_alias {
+ import(&buf, ast::import_alias {
ident = ["foo"],
alias = "bar",
}) as size;
- s = strio::finish(buf);
+ s = strio::string(&buf);
assert(s == "use bar = foo;");
free(s);
buf = strio::dynamic();
- import(buf, ast::import_objects {
+ import(&buf, ast::import_objects {
ident = ["foo"],
objects = ["bar", "baz"],
}) as size;
- s = strio::finish(buf);
+ s = strio::string(&buf);
assert(s == "use foo::{bar, baz};");
free(s);
};
diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha
@@ -224,8 +224,8 @@ export fn _type(
fn type_test(t: ast::_type, expected: str) bool = {
let buf = strio::dynamic();
- _type(buf, 0, t) as size;
- let s = strio::finish(buf);
+ _type(&buf, 0, t) as size;
+ let s = strio::string(&buf);
defer free(s);
return s == expected;
};
diff --git a/net/ip/ip.ha b/net/ip/ip.ha
@@ -338,8 +338,8 @@ export fn string(item: (...addr | subnet)) str = {
// Maximum length of an IPv6 address plus its netmask in hexadecimal
static let buf: [64]u8 = [0...];
let stream = strio::fixed(buf);
- fmt(stream, item) as size;
- return strio::string(stream);
+ fmt(&stream, item) as size;
+ return strio::string(&stream);
};
fn wanttoken(tok: *strings::tokenizer) (str | invalid) = {
diff --git a/shlex/split.ha b/shlex/split.ha
@@ -36,18 +36,18 @@ export fn split(in: const str) ([]str | syntaxerr) = {
break;
};
if (!first) {
- append(slice, strio::finish(s));
+ append(slice, strio::string(&s));
s = strio::dynamic();
};
dirty = false;
case '\\' =>
- scan_backslash(s, &iter)?;
+ scan_backslash(&s, &iter)?;
case '"' =>
- scan_double(s, &iter)?;
+ scan_double(&s, &iter)?;
case '\'' =>
- scan_single(s, &iter)?;
+ scan_single(&s, &iter)?;
case =>
- strio::appendrune(s, r)!;
+ strio::appendrune(&s, r)!;
};
if (first) {
@@ -56,7 +56,7 @@ export fn split(in: const str) ([]str | syntaxerr) = {
};
if (dirty) {
- append(slice, strio::finish(s));
+ append(slice, strio::string(&s));
};
return slice;
diff --git a/strio/dynamic.ha b/strio/dynamic.ha
@@ -2,7 +2,7 @@ use errors;
use io;
use strings;
-type dynamic_stream = struct {
+export type dynamic_stream = struct {
stream: io::stream,
buf: []u8,
};
@@ -10,53 +10,30 @@ type dynamic_stream = struct {
// Creates a write-only string stream using an allocated buffer for storage, for
// efficiently building strings.
//
-// Calling [[io::close]] on this stream will free the buffer. Call [[strio::finish]]
-// instead to free up resources associated with the stream, but transfer
-// ownership of the buffer to the caller.
-export fn dynamic() io::handle = {
- let s = alloc(dynamic_stream {
+// Calling [[io::close]] on this stream will free the buffer. If stream's data
+// is transfered via [[string]], it shouldn't be closed as long if the data is
+// freed.
+export fn dynamic() dynamic_stream = {
+ return dynamic_stream {
stream = io::stream {
writer = &dynamic_write,
closer = &dynamic_close,
...
},
buf = [],
- });
- return &s.stream;
-};
-
-fn get_dynamic_stream(in: io::handle) *dynamic_stream = {
- match (in) {
- case io::file =>
- abort("Invalid use of strio on io::file");
- case let st: *io::stream =>
- assert(st.writer == &dynamic_write,
- "Invalid use of strio on non-strio I/O stream");
- return st: *dynamic_stream;
};
};
-// Closes the stream without freeing the buffer, instead transferring ownership
-// of it to the caller.
-export fn finish(in: io::handle) str = {
- let s = get_dynamic_stream(in);
- let buf = s.buf;
- free(s);
- return strings::fromutf8(buf);
-};
-
// Resets the buffer's length to zero, but keeps the allocated memory around for
// future writes.
-export fn reset(in: io::handle) void = {
- const s = get_dynamic_stream(in);
- s.buf = s.buf[..0];
+export fn reset(in: *dynamic_stream) void = {
+ in.buf = in.buf[..0];
};
// Truncates the buffer, freeing memory associated with it and setting its
// length to zero.
-export fn truncate(in: io::handle) void = {
- let s = get_dynamic_stream(in);
- delete(s.buf[..]);
+export fn truncate(in: *dynamic_stream) void = {
+ delete(in.buf[..]);
};
fn dynamic_write(s: *io::stream, buf: const []u8) (size | io::error) = {
@@ -68,15 +45,12 @@ fn dynamic_write(s: *io::stream, buf: const []u8) (size | io::error) = {
fn dynamic_close(s: *io::stream) void = {
const s = s: *dynamic_stream;
free(s.buf);
- free(s);
};
@test fn dynamic() void = {
let stream = dynamic();
- io::write(stream, strings::toutf8("hello ")) as size;
- io::write(stream, strings::toutf8("world")) as size;
- assert(string(stream) == "hello world");
- let s = finish(stream);
- assert(s == "hello world");
- free(s);
+ defer io::close(&stream);
+ io::write(&stream, strings::toutf8("hello ")) as size;
+ io::write(&stream, strings::toutf8("world")) as size;
+ assert(string(&stream) == "hello world");
};
diff --git a/strio/fixed.ha b/strio/fixed.ha
@@ -1,46 +1,35 @@
use io;
use strings;
-type fixed_stream = struct {
+export type fixed_stream = struct {
stream: io::stream,
buf: []u8,
cur: []u8,
};
// Creates a write-only string stream using the provided buffer for storage.
-// The program aborts if writes would exceed the buffer's capacity.
-export fn fixed(in: []u8) io::handle = {
- let s = alloc(fixed_stream {
+// The program aborts if writes would exceed the buffer's capacity. The stream
+// doesn't need to be closed.
+export fn fixed(in: []u8) fixed_stream = {
+ return fixed_stream {
stream = io::stream {
writer = &fixed_write,
- closer = &fixed_close,
...
},
buf = in,
cur = in,
- });
- return &s.stream;
+ };
};
// Returns the current contents of the buffer as a string. Aborts the program if
// invalid UTF-8 has been written to the buffer.
-export fn string(in: io::handle) str = {
- let stream = match (in) {
- case io::file =>
- abort("Invalid use of strio with io::file");
- case let st: *io::stream =>
- yield st;
- };
-
- if (stream.writer == &fixed_write) {
- let stream = stream: *fixed_stream;
- const n = len(stream.buf) - len(stream.cur);
- return strings::fromutf8(stream.buf[..n]);
- } else if (stream.writer == &dynamic_write) {
- let stream = stream: *dynamic_stream;
- return strings::fromutf8(stream.buf);
- } else {
- abort("strio::string called on non-strio stream");
+export fn string(in: (*fixed_stream | *dynamic_stream)) str = {
+ match (in) {
+ case let s: *fixed_stream =>
+ const n = len(s.buf) - len(s.cur);
+ return strings::fromutf8(s.buf[..n]);
+ case let s: *dynamic_stream =>
+ return strings::fromutf8(s.buf);
};
};
@@ -55,15 +44,10 @@ fn fixed_write(s: *io::stream, buf: const []u8) (size | io::error) = {
return n;
};
-fn fixed_close(s: *io::stream) void = {
- free(s);
-};
-
@test fn fixed() void = {
static let buf: [1024]u8 = [0...];
let stream = fixed(buf);
- defer io::close(stream);
- io::write(stream, strings::toutf8("hello ")) as size;
- io::write(stream, strings::toutf8("world")) as size;
- assert(string(stream) == "hello world");
+ io::write(&stream, strings::toutf8("hello ")) as size;
+ io::write(&stream, strings::toutf8("world")) as size;
+ assert(string(&stream) == "hello world");
};
diff --git a/strio/ops.ha b/strio/ops.ha
@@ -21,10 +21,10 @@ export fn concat(out: io::handle, strs: str...) (size | io::error) = {
@test fn concat() void = {
let st = dynamic();
- defer io::close(st);
- concat(st, "hello") as size;
- concat(st, " ", "world") as size;
- assert(string(st) == "hello world");
+ defer io::close(&st);
+ concat(&st, "hello") as size;
+ concat(&st, " ", "world") as size;
+ assert(string(&st) == "hello world");
};
// Joins several strings together by a delimiter and writes them to a handle.
@@ -55,15 +55,15 @@ export fn join(out: io::handle, delim: str, strs: str...) (size | io::error) = {
@test fn join() void = {
let st = dynamic();
- defer io::close(st);
- join(st, "::", "hello", "world") as size;
- assert(string(st) == "hello::world");
- truncate(st);
- join(st, "::") as size;
- assert(string(st) == "");
- truncate(st);
- join(st, "::", "foo") as size;
- assert(string(st) == "foo");
+ defer io::close(&st);
+ join(&st, "::", "hello", "world") as size;
+ assert(string(&st) == "hello::world");
+ truncate(&st);
+ join(&st, "::") as size;
+ assert(string(&st) == "");
+ truncate(&st);
+ join(&st, "::", "foo") as size;
+ assert(string(&st) == "foo");
};
// Joins several strings together by a delimiter and writes them to a handle, in
@@ -94,15 +94,15 @@ export fn rjoin(out: io::handle, delim: str, strs: str...) (size | io::error) =
@test fn rjoin() void = {
let st = dynamic();
- defer io::close(st);
- rjoin(st, "::", "hello", "world") as size;
- assert(string(st) == "world::hello");
- truncate(st);
- rjoin(st, "::") as size;
- assert(string(st) == "");
- truncate(st);
- rjoin(st, "::", "foo") as size;
- assert(string(st) == "foo");
+ defer io::close(&st);
+ rjoin(&st, "::", "hello", "world") as size;
+ assert(string(&st) == "world::hello");
+ truncate(&st);
+ rjoin(&st, "::") as size;
+ assert(string(&st) == "");
+ truncate(&st);
+ rjoin(&st, "::", "foo") as size;
+ assert(string(&st) == "foo");
};
// Appends a rune to a stream.
diff --git a/temp/+freebsd.ha b/temp/+freebsd.ha
@@ -85,9 +85,8 @@ export fn dir() str = {
random::buffer(buf[..]);
let sink = strio::fixed(name);
- defer io::close(sink);
- hex::encode(sink, buf) as size;
- let name = strio::string(sink);
+ hex::encode(&sink, buf) as size;
+ let name = strio::string(&sink);
let path = path::join(get_tmpdir(), name);
match (os::mkdir(path)) {
diff --git a/temp/+linux.ha b/temp/+linux.ha
@@ -99,9 +99,8 @@ export fn dir() str = {
random::buffer(buf[..]);
let sink = strio::fixed(name);
- defer io::close(sink);
- hex::encode(sink, buf) as size;
- let name = strio::string(sink);
+ hex::encode(&sink, buf) as size;
+ let name = strio::string(&sink);
let path = path::join(get_tmpdir(), name);
match (os::mkdir(path)) {
diff --git a/uuid/uuid.ha b/uuid/uuid.ha
@@ -82,9 +82,8 @@ export fn uri(out: io::handle, in: uuid) (size | io::error) = {
export fn encodestr(in: uuid) str = {
static let buf: [UUID_STRLEN]u8 = [0...];
let sink = strio::fixed(buf);
- defer io::close(sink);
- encode(sink, in) as size;
- return strio::string(sink);
+ encode(&sink, in) as size;
+ return strio::string(&sink);
};
// Encodes a UUID as a string. The return value is statically allocated, the
@@ -92,9 +91,8 @@ export fn encodestr(in: uuid) str = {
export fn encodeuri(in: uuid) str = {
static let buf: [UUID_URILEN]u8 = [0...];
let sink = strio::fixed(buf);
- defer io::close(sink);
- uri(sink, in) as size;
- return strio::string(sink);
+ uri(&sink, in) as size;
+ return strio::string(&sink);
};
@test fn encode() void = {