1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>
use encoding::utf8;
use io;
use strings;
// Appends zero or more strings to an [[io::handle]]. The output needn't be a
// memio stream, but it's generally more efficient if it is. Returns the number
// of bytes written, or an error.
export fn concat(out: io::handle, strs: str...) (size | io::error) =
join(out, "", strs...);
@test fn concat() void = {
let st = dynamic();
defer io::close(&st)!;
let tests: [_]([]str, str) = [
([], ""),
([""], ""),
(["", ""], ""),
(["hello"], "hello"),
(["hello", " ", "world"], "hello world"),
(["", "hello", " ", "world"], "hello world"),
(["hello", " ", "world", ""], "hello world"),
(["hello", "", " ", "world"], "hello world")
];
for (let i = 0z; i < len(tests); i += 1) {
let ln = concat(&st, tests[i].0...) as size;
assert(ln == len(tests[i].1) && string(&st)! == tests[i].1);
reset(&st);
};
};
// Joins several strings together by a delimiter and writes them to a handle.
// The output needn't be a memio stream, but it's generally more efficient if it
// is. Returns the number of bytes written, or an error.
export fn join(out: io::handle, delim: str, strs: str...) (size | io::error) = {
let n = 0z;
let delim = strings::toutf8(delim);
for (let i = 0z; i < len(strs); i += 1) {
n += io::writeall(out, strings::toutf8(strs[i]))?;
if (len(delim) != 0 && i + 1 < len(strs)) {
n += io::writeall(out, delim)?;
};
};
return n;
};
@test fn join() void = {
let st = dynamic();
defer io::close(&st)!;
let tests: [_](str, []str, str) = [
("::", [], ""),
("::", [""], ""),
("::", ["", ""], "::"),
("::", ["", "", ""], "::::"),
("::", ["hello"], "hello"),
("::", ["hello", "world"], "hello::world"),
("::", ["", "hello", "world"], "::hello::world"),
("::", ["hello", "world", ""], "hello::world::"),
("::", ["hello", "", "world"], "hello::::world"),
];
for (let i = 0z; i < len(tests); i += 1) {
let ln = join(&st, tests[i].0, tests[i].1...) as size;
assert(ln == len(tests[i].2) && string(&st)! == tests[i].2);
reset(&st);
};
};
// Appends zero or more strings to an [[io::handle]], in reverse order. The
// output needn't be a memio stream, but it's generally more efficient if it is.
// Returns the number of bytes written, or an error.
export fn rconcat(out: io::handle, strs: str...) (size | io::error) =
rjoin(out, "", strs...);
@test fn rconcat() void = {
let st = dynamic();
defer io::close(&st)!;
let tests: [_]([]str, str) = [
([], ""),
([""], ""),
(["", ""], ""),
(["hello"], "hello"),
(["hello", " ", "world"], "world hello"),
(["", "hello", " ", "world"], "world hello"),
(["hello", " ", "world", ""], "world hello"),
(["hello", "", " ", "world"], "world hello")
];
for (let i = 0z; i < len(tests); i += 1) {
let ln = rconcat(&st, tests[i].0...) as size;
assert(ln == len(tests[i].1) && string(&st)! == tests[i].1);
reset(&st);
};
};
// Joins several strings together by a delimiter and writes them to a handle, in
// reverse order. The output needn't be a memio stream, but it's generally more
// efficient if it is. Returns the number of bytes written, or an error.
export fn rjoin(out: io::handle, delim: str, strs: str...) (size | io::error) = {
let n = 0z;
let delim = strings::toutf8(delim);
for (let i = len(strs); i > 0; i -= 1) {
n += io::writeall(out, strings::toutf8(strs[i - 1]))?;
if (len(delim) != 0 && i - 1 > 0) {
n += io::writeall(out, delim)?;
};
};
return n;
};
@test fn rjoin() void = {
let st = dynamic();
defer io::close(&st)!;
let tests: [_](str, []str, str) = [
("::", [], ""),
("::", [""], ""),
("::", ["", ""], "::"),
("::", ["", "", ""], "::::"),
("::", ["hello"], "hello"),
("::", ["hello", "world"], "world::hello"),
("::", ["", "hello", "world"], "world::hello::"),
("::", ["hello", "world", ""], "::world::hello"),
("::", ["hello", "", "world"], "world::::hello"),
];
for (let i = 0z; i < len(tests); i += 1) {
let ln = rjoin(&st, tests[i].0, tests[i].1...) as size;
assert(ln == len(tests[i].2) && string(&st)! == tests[i].2);
reset(&st);
};
};
// Appends a rune to a stream.
export fn appendrune(out: io::handle, r: rune) (size | io::error) =
io::writeall(out, utf8::encoderune(r));
|