hare

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

strings.ha (3270B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use encoding::utf8;
      5 use types;
      6 
      7 let empty: [_]u8 = [0];
      8 
      9 // An empty NUL-terminated C string.
     10 export let empty_string: *const char = &empty[0]: *const char;
     11 
     12 // Computes the length of a NUL-terminated C string, in octets, in O(n). The
     13 // computed length does not include the NUL terminator.
     14 export fn strlen(cstr: *const char) size = {
     15 	const ptr = cstr: *[*]u8;
     16 	let ln = 0z;
     17 	for (ptr[ln] != 0; ln += 1) void;
     18 	return ln;
     19 };
     20 
     21 // Computes the length of a NUL-terminated C string, only looking at the first
     22 // maxlen bytes. The computed length does not include the NUL terminator.
     23 export fn strnlen(cstr: *const char, maxlen: size) size = {
     24 	const ptr = cstr: *[*]u8;
     25 	let ln = 0z;
     26 	for (ln < maxlen && ptr[ln] != 0; ln += 1) void;
     27 	return ln;
     28 };
     29 
     30 // Converts a C string to a Hare string in O(n), and does not check if it's
     31 // valid UTF-8.
     32 export fn tostr_unsafe(cstr: *const char) const str = {
     33 	return tostrn_unsafe(cstr, strlen(cstr));
     34 };
     35 
     36 // Converts a C string with a given length to a Hare string, and does not check
     37 // if it's valid UTF-8.
     38 export fn tostrn_unsafe(cstr: *const char, length: size) const str = {
     39 	const s = types::string {
     40 		data = cstr: *[*]u8,
     41 		length = length,
     42 		capacity = length + 1,
     43 	};
     44 	return *(&s: *const str);
     45 };
     46 
     47 // Converts a C string to a Hare string in O(n). If the string is not valid
     48 // UTF-8, return [[encoding::utf8::invalid]].
     49 export fn tostr(cstr: *const char) (const str | utf8::invalid) = {
     50 	return tostrn(cstr, strlen(cstr));
     51 };
     52 
     53 // Converts a C string with a given length to a Hare string. If the string is
     54 // not valid UTF-8, return [[encoding::utf8::invalid]].
     55 export fn tostrn(cstr: *const char, length: size) (const str | utf8::invalid) = {
     56 	utf8::validate((cstr: *[*]u8)[..length])?;
     57 	return tostrn_unsafe(cstr, length);
     58 };
     59 
     60 // Converts a Hare string to a C string. The result is allocated; the caller
     61 // must free it when they're done.
     62 export fn fromstr(s: const str) *char = {
     63 	let slice: []char = alloc([0...], len(s) + 1)!;
     64 	return fromstr_buf(s, slice);
     65 };
     66 
     67 // Converts a Hare string to a C string. The result is stored into a
     68 // user-supplied buffer.
     69 export fn fromstr_buf(s: const str, sl: []char) *char = {
     70 	if (len(sl) < len(s) + 1) {
     71 		abort("types::c::fromstr_buf: buffer has insufficient space for string plus NUL");
     72 	};
     73 
     74 	const s = &s: *[]char;
     75 	sl[..len(s)] = s[..];
     76 	sl[len(s)] = 0;
     77 
     78 	return (*(&sl: *types::slice)).data: *char;
     79 };
     80 
     81 // Converts a NUL-terminated Hare string to a C string. Aborts if the input
     82 // string isn't NUL-terminated. The result is borrowed from the input.
     83 export fn nulstr(s: const str) *const char = {
     84 	let s = &s: *types::string;
     85 	let data = s.data as *[*]u8;
     86 	assert(data[s.length - 1] == '\0', "types::c::nulstr input must be NUL-terminated");
     87 	return s.data: *const char;
     88 };
     89 
     90 // Converts a non-NUL-terminated Hare string to a *const [[char]]. The return
     91 // value is borrowed from the input, except in the case of an empty string, in
     92 // which case it is statically allocated.
     93 //
     94 // Use with caution!
     95 export fn unterminatedstr(s: const str) *const char = {
     96 	let s = &s: *types::string;
     97 	if (s.data == null) {
     98 		return empty_string;
     99 	};
    100 	let data = s.data as *[*]u8;
    101 	return data: *const char;
    102 };