cstr
import cstr from "cstr";
let home: []const u8 = cstr.as_view(getenv_from_c("HOME")); // view a C string
let p: *u8 = cstr.from_view("hello"); // make one for C
c_puts(p);
cstr.free(p);C libraries and the operating system pass text as a pointer to bytes ending
in a NUL (*u8, or *const u8 where C only reads it). The rest of the
standard library takes []const u8 views. cstr converts between the two
at the edge of your program. A tape string has no terminating NUL and never
converts to a pointer: from_view is how one reaches C (a string literal can
also go straight to a *const u8 parameter).
Reading C strings
| Function | Returns |
|---|---|
len(p: *const u8) -> i64 | Bytes before the NUL; 0 for null |
as_view(p: *const u8) -> []const u8 | The bytes before the NUL, as a view (empty for null) |
as_view doesn’t copy: the view points at the C string’s memory, so it
must not outlive it. Copy it with str.from_view when you need to keep it.
let v: []const u8 = cstr.as_view(name_from_c);
io.println("got {v}");
let kept: string = str.from_view(v);Making C strings
| Function | Returns |
|---|---|
from_view(s: []const u8) -> *u8 | A new NUL-terminated copy of s |
from_i64(v: i64) -> *u8 | v in decimal as a new C string |
free(p: *u8) | Releases a C string made by from_view or from_i64 |
The C string belongs to you until you free it; free(null) does nothing.
Only free C strings that cstr made: memory a C library returns is
released however that library says.
from_view stops the program with a trap
when the text contains a NUL byte, since C would only see the part before
it.
let label: *u8 = cstr.from_i64(count); // e.g. for a widget that takes *u8
defer cstr.free(label);Deprecated: the old str functions
Before 2.1, str worked on *u8 pointers with u32 lengths. Those
functions now live in cstr, unchanged, and are deprecated: they will be
removed in a later minor release. Each has a replacement that takes views:
| Deprecated | Use instead |
|---|---|
cstr.is_digit, is_alpha, is_space | ascii.is_digit, is_alpha, is_space |
cstr.char_at(s, len, i) | cstr.as_view(s)[i] |
cstr.equal(a, a_len, b, b_len) | bytes.eq |
cstr.starts_with, ends_with, contains | bytes.starts_with, ends_with, contains |
cstr.index_of (returns -1 when absent) | bytes.index_of (returns null) |
cstr.copy(dst, src, n) | bytes.copy |
cstr.concat(a, a_len, b, b_len) | interpolation "{a}{b}" or str.join |
cstr.to_upper(s, len), to_lower (in place) | str.to_upper, str.to_lower |
cstr.trim_left, trim_right (return offsets) | bytes.trim_left, bytes.trim_right |
cstr.parse_i64(s, len) | conv.parse_i64 |
cstr.i64_to_str(v, buf, len) | conv.fmt_i64 |
cstr.i64_to_cstr(v) | cstr.from_i64 |
The old str.len is cstr.len, which now returns i64.
Last modified: