Skip to main content

ferrilog_core/encode/
strings.rs

1use super::{
2    Encode, EncodeFast, FORMAT_ALIGN_LEFT, FORMAT_PRECISION_NONE,
3    format::{append_padded_const, append_str_with_spec, truncate_to_boundary},
4    traits::EncodeConstDefaultFormat,
5};
6
7// --- Layer 2: Fast String Path (length-prefixed) ---
8
9impl Encode for &str {
10    #[inline(always)]
11    fn encoded_size(&self) -> usize {
12        4 + self.len() // u32 length prefix + content bytes
13    }
14
15    #[inline(always)]
16    unsafe fn encode(&self, buffer: *mut u8, offset: &mut usize) {
17        unsafe {
18            // Write u32 length prefix
19            buffer.add(*offset).cast::<u32>().write_unaligned(self.len() as u32);
20            *offset += 4;
21            // Write content bytes
22            core::ptr::copy_nonoverlapping(self.as_ptr(), buffer.add(*offset), self.len());
23        }
24        *offset += self.len();
25    }
26
27    #[inline]
28    unsafe fn decode_and_format(
29        buffer: *const u8,
30        offset: &mut usize,
31        output: &mut Vec<u8>,
32        format_spec: &str,
33    ) {
34        unsafe {
35            let length = buffer.add(*offset).cast::<u32>().read_unaligned() as usize;
36            *offset += 4;
37            let value = core::str::from_utf8_unchecked(core::slice::from_raw_parts(
38                buffer.add(*offset),
39                length,
40            ));
41            if format_spec.is_empty() {
42                output.extend_from_slice(value.as_bytes());
43            } else {
44                append_str_with_spec(output, value, format_spec);
45            }
46            *offset += length;
47        }
48    }
49}
50unsafe impl EncodeFast for &str {}
51
52impl EncodeConstDefaultFormat for &str {
53    #[inline]
54    unsafe fn decode_append_default_format<
55        const FILL: u8,
56        const ALIGN: u8,
57        const WIDTH: usize,
58        const PRECISION: usize,
59        const ZERO_PAD: bool,
60    >(
61        buffer: *const u8,
62        offset: &mut usize,
63        output: &mut Vec<u8>,
64    ) {
65        let length = unsafe { buffer.add(*offset).cast::<u32>().read_unaligned() as usize };
66        *offset += 4;
67        let value = unsafe {
68            core::str::from_utf8_unchecked(core::slice::from_raw_parts(buffer.add(*offset), length))
69        };
70        let body = if PRECISION == FORMAT_PRECISION_NONE {
71            value
72        } else {
73            truncate_to_boundary(value, PRECISION)
74        };
75        append_padded_const::<FILL, ALIGN, WIDTH, ZERO_PAD, { FORMAT_ALIGN_LEFT }>(
76            output,
77            body.as_bytes(),
78        );
79        *offset += length;
80    }
81}
82
83impl Encode for String {
84    #[inline(always)]
85    fn encoded_size(&self) -> usize {
86        self.as_str().encoded_size()
87    }
88
89    #[inline(always)]
90    unsafe fn encode(&self, buffer: *mut u8, offset: &mut usize) {
91        unsafe {
92            self.as_str().encode(buffer, offset);
93        }
94    }
95
96    #[inline]
97    unsafe fn decode_and_format(
98        buffer: *const u8,
99        offset: &mut usize,
100        output: &mut Vec<u8>,
101        format_spec: &str,
102    ) {
103        unsafe {
104            <&str as Encode>::decode_and_format(buffer, offset, output, format_spec);
105        }
106    }
107}
108unsafe impl EncodeFast for String {}
109
110impl EncodeConstDefaultFormat for String {
111    #[inline]
112    unsafe fn decode_append_default_format<
113        const FILL: u8,
114        const ALIGN: u8,
115        const WIDTH: usize,
116        const PRECISION: usize,
117        const ZERO_PAD: bool,
118    >(
119        buffer: *const u8,
120        offset: &mut usize,
121        output: &mut Vec<u8>,
122    ) {
123        unsafe {
124            <&str as EncodeConstDefaultFormat>::decode_append_default_format::<
125                FILL,
126                ALIGN,
127                WIDTH,
128                PRECISION,
129                ZERO_PAD,
130            >(buffer, offset, output);
131        }
132    }
133}