hare

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

ops.ha (4376B)


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