Skip to main content

nifty_rt/abi/
strings.rs

1//! Strings, and building interpolated strings.
2
3use std::slice;
4
5use super::count;
6use crate::value::{self, Slot, TypeDesc};
7
8/// A string with a copy of `len` bytes of UTF-8 at `bytes`.
9///
10/// # Safety
11/// `bytes` points to `len` readable bytes.
12#[unsafe(no_mangle)]
13pub(crate) unsafe extern "C" fn nf_string_new(bytes: *const u8, len: usize) -> Slot {
14    // SAFETY: by the caller's contract.
15    let bytes = unsafe { slice::from_raw_parts(bytes, len) };
16    value::string_slot(String::from_utf8_lossy(bytes))
17}
18
19/// `a + b`, with both borrowed.
20#[unsafe(no_mangle)]
21pub(crate) extern "C" fn nf_string_concat(a: Slot, b: Slot) -> Slot {
22    value::string_slot([value::as_str(a), value::as_str(b)].concat())
23}
24
25/// How many characters the borrowed string holds.
26#[unsafe(no_mangle)]
27pub(crate) extern "C" fn nf_string_len(text: Slot) -> i64 {
28    count(value::as_str(text).chars().count())
29}
30
31/// Whether `a` sorts before (-1), with (0) or after (1) `b`, both borrowed.
32#[unsafe(no_mangle)]
33pub(crate) extern "C" fn nf_string_compare(a: Slot, b: Slot) -> i32 {
34    match value::as_str(a).cmp(value::as_str(b)) {
35        std::cmp::Ordering::Less => -1,
36        std::cmp::Ordering::Equal => 0,
37        std::cmp::Ordering::Greater => 1,
38    }
39}
40
41/// Starts an interpolated string, which `nf_text_finish` turns into a string.
42#[unsafe(no_mangle)]
43pub(crate) extern "C" fn nf_text_new() -> *mut String {
44    Box::into_raw(Box::default())
45}
46
47/// Appends `len` bytes of UTF-8 at `bytes`.
48///
49/// # Safety
50/// `text` came from `nf_text_new` and isn't finished; `bytes` points to `len` bytes.
51#[unsafe(no_mangle)]
52pub(crate) unsafe extern "C" fn nf_text_push_str(text: *mut String, bytes: *const u8, len: usize) {
53    // SAFETY: by the caller's contract.
54    let (text, bytes) = unsafe { (&mut *text, slice::from_raw_parts(bytes, len)) };
55    text.push_str(&String::from_utf8_lossy(bytes));
56}
57
58/// Appends the borrowed value as it reads inside a string.
59///
60/// # Safety
61/// `text` came from `nf_text_new` and isn't finished.
62#[unsafe(no_mangle)]
63pub(crate) unsafe extern "C" fn nf_text_push(text: *mut String, slot: Slot, ty: &TypeDesc) {
64    // SAFETY: by the caller's contract.
65    value::write(unsafe { &mut *text }, slot, ty);
66}
67
68/// # Safety
69/// `text` came from `nf_text_new` and isn't finished; it is finished after this.
70#[unsafe(no_mangle)]
71pub(crate) unsafe extern "C" fn nf_text_finish(text: *mut String) -> Slot {
72    // SAFETY: by the caller's contract, ownership of the builder passes back here.
73    let text = unsafe { Box::from_raw(text) };
74    value::string_slot(*text)
75}