hare

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

ops.ha (4298B)


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