cairo_lang_runner/
short_string.rs

1use num_traits::Zero;
2use starknet_types_core::felt::Felt as Felt252;
3
4/// Converts a bigint representing a felt252 to a Cairo short-string.
5pub fn as_cairo_short_string(value: &Felt252) -> Option<String> {
6    let mut as_string = String::default();
7    let mut is_end = false;
8    for byte in value.to_biguint().to_bytes_be() {
9        if byte == 0 {
10            is_end = true;
11        } else if is_end {
12            return None;
13        } else if byte.is_ascii_graphic() || byte.is_ascii_whitespace() {
14            as_string.push(byte as char);
15        } else {
16            return None;
17        }
18    }
19    Some(as_string)
20}
21
22/// Converts a bigint representing a felt252 to a Cairo short-string of the given length.
23/// Nulls are allowed and length must be <= 31.
24pub fn as_cairo_short_string_ex(value: &Felt252, length: usize) -> Option<String> {
25    if length == 0 {
26        return if value.is_zero() { Some("".to_string()) } else { None };
27    }
28    if length > 31 {
29        // A short string can't be longer than 31 bytes.
30        return None;
31    }
32
33    // We pass through biguint as felt252.to_bytes_be() does not trim leading zeros.
34    let bytes = value.to_biguint().to_bytes_be();
35    let bytes_len = bytes.len();
36    if bytes_len > length {
37        // `value` has more bytes than expected.
38        return None;
39    }
40
41    let mut as_string = "".to_string();
42    for byte in bytes {
43        if byte == 0 {
44            as_string.push_str(r"\0");
45        } else if byte.is_ascii_graphic() || byte.is_ascii_whitespace() {
46            as_string.push(byte as char);
47        } else {
48            as_string.push_str(format!(r"\x{byte:02x}").as_str());
49        }
50    }
51
52    // `to_bytes_be` misses starting nulls. Prepend them as needed.
53    let missing_nulls = length - bytes_len;
54    as_string.insert_str(0, &r"\0".repeat(missing_nulls));
55
56    Some(as_string)
57}