float_pigment_css/sheet/
str_store.rs

1//! String utilities for the binary format.
2
3use alloc::{boxed::Box, rc::Rc, string::String, vec::Vec};
4use core::fmt::Debug;
5
6use serde::{Deserialize, Serialize};
7
8use super::*;
9use inner::StrBufferInner;
10
11#[cfg(all(not(feature = "std"), not(feature = "no-std-lock")))]
12compile_error!("One of the `std` or `no-std-lock` features should be enabled");
13
14// HACK
15// Currently there is no global state for a ser/de call, but we need it to handle `StrRef` .
16// To resolve this in a simple way, we use a thread-global state instead.
17// Because there cannot be two ser/de in progressing in a single thread.
18// However, this does not work on `no_std` env.
19// So we just use a spin lock to prevent two ser/de in progressing in multiple `no_std` thread.
20// This should be finally resolved by customizing ser/de process.
21pub(super) enum SerdeThreadGlobalState {
22    None,
23    Ser(SerdeThreadGlobalStateSer),
24    De(SerdeThreadGlobalStateDe),
25    DePrepare {
26        zero_copy: Box<dyn 'static + FnOnce()>,
27    },
28}
29
30pub(super) struct SerdeThreadGlobalStateSer {
31    str_buffer: Rc<StrBufferInner>,
32    offset_gen: Vec<usize>,
33    offsets: Option<alloc::vec::IntoIter<usize>>,
34}
35
36pub(super) struct SerdeThreadGlobalStateDe {
37    str_buffer: Rc<StrBufferInner>,
38    pub(super) zero_copy: Option<Box<dyn 'static + FnOnce()>>,
39}
40
41// It is safe because it will not be used across threads!
42unsafe impl Send for SerdeThreadGlobalState {}
43unsafe impl Sync for SerdeThreadGlobalState {}
44
45impl SerdeThreadGlobalState {
46    #[cfg(feature = "std")]
47    #[allow(dead_code)]
48    fn get<R>(f: impl FnOnce(&mut SerdeThreadGlobalState) -> R) -> R {
49        thread_local! {
50            static SERDE_THREAD_GLOBAL_STATE: RefCell<SerdeThreadGlobalState> = const { core::cell::RefCell::new(SerdeThreadGlobalState::None) };
51        }
52        SERDE_THREAD_GLOBAL_STATE.with(|x| {
53            let mut x = x.borrow_mut();
54            f(&mut x)
55        })
56    }
57
58    #[cfg(all(not(feature = "std"), feature = "no-std-lock"))]
59    #[allow(dead_code)]
60    fn get<R>(f: impl FnOnce(&mut SerdeThreadGlobalState) -> R) -> R {
61        static SERDE_THREAD_GLOBAL_STATE: spin::Lazy<spin::Mutex<SerdeThreadGlobalState>> =
62            spin::Lazy::new(|| spin::Mutex::new(SerdeThreadGlobalState::None));
63        f(&mut SERDE_THREAD_GLOBAL_STATE.lock())
64    }
65
66    #[allow(dead_code)]
67    pub(super) fn ser<R>(ser: SerdeThreadGlobalStateSer, f: impl FnOnce() -> R) -> R {
68        Self::get(|state| {
69            let SerdeThreadGlobalState::None = state else {
70                panic!("Invalid SerdeThreadGlobalState state");
71            };
72            *state = SerdeThreadGlobalState::Ser(ser);
73        });
74        let ret = f();
75        Self::get(|state| {
76            *state = SerdeThreadGlobalState::None;
77        });
78        ret
79    }
80
81    #[allow(dead_code)]
82    pub(super) fn get_ser<R>(f: impl FnOnce(&mut SerdeThreadGlobalStateSer) -> R) -> R {
83        Self::get(|state| {
84            let SerdeThreadGlobalState::Ser(ser) = state else {
85                panic!("Invalid SerdeThreadGlobalState state");
86            };
87            f(ser)
88        })
89    }
90
91    #[allow(dead_code)]
92    pub(super) fn de_prepare<R>(
93        zero_copy: Box<dyn 'static + FnOnce()>,
94        f: impl FnOnce() -> R,
95    ) -> R {
96        Self::get(|state| {
97            let SerdeThreadGlobalState::None = state else {
98                panic!("Invalid SerdeThreadGlobalState state");
99            };
100            *state = SerdeThreadGlobalState::DePrepare { zero_copy };
101        });
102        let ret = f();
103        Self::get(|state| {
104            *state = SerdeThreadGlobalState::None;
105        });
106        ret
107    }
108
109    #[allow(dead_code)]
110    pub(super) fn de<R>(mut de: SerdeThreadGlobalStateDe, f: impl FnOnce() -> R) -> R {
111        Self::get(|state| {
112            let old_state = core::mem::replace(state, SerdeThreadGlobalState::None);
113            de.zero_copy = match old_state {
114                SerdeThreadGlobalState::None => None,
115                SerdeThreadGlobalState::DePrepare { zero_copy } => Some(zero_copy),
116                _ => panic!("Invalid SerdeThreadGlobalState state"),
117            };
118            *state = SerdeThreadGlobalState::De(de);
119        });
120        let ret = f();
121        Self::get(|state| {
122            *state = SerdeThreadGlobalState::None;
123        });
124        ret
125    }
126
127    #[allow(dead_code)]
128    pub(super) fn get_de<R>(f: impl FnOnce(&mut SerdeThreadGlobalStateDe) -> R) -> R {
129        Self::get(|state| {
130            let SerdeThreadGlobalState::De(de) = state else {
131                panic!("Invalid SerdeThreadGlobalState state");
132            };
133            f(de)
134        })
135    }
136
137    #[allow(dead_code)]
138    pub(super) fn get_de_optional<R>(
139        f: impl FnOnce(Option<&mut SerdeThreadGlobalStateDe>) -> R,
140    ) -> R {
141        Self::get(|state| {
142            if let SerdeThreadGlobalState::De(de) = state {
143                f(Some(de))
144            } else {
145                f(None)
146            }
147        })
148    }
149}
150
151pub(crate) fn str_buffer_de_env<R>(str_buffer: &StrBuffer, f: impl FnOnce() -> R) -> R {
152    SerdeThreadGlobalState::de(
153        SerdeThreadGlobalStateDe {
154            str_buffer: str_buffer.inner.clone(),
155            zero_copy: None,
156        },
157        f,
158    )
159}
160
161pub(crate) fn str_buffer_ser_env<R, T>(
162    first_gen_f: impl FnOnce() -> T,
163    final_gen_f: impl FnOnce(T, StrBuffer) -> R,
164) -> R {
165    SerdeThreadGlobalState::ser(
166        SerdeThreadGlobalStateSer {
167            str_buffer: Rc::new(StrBufferInner::new()),
168            offset_gen: vec![],
169            offsets: None,
170        },
171        || {
172            let r = first_gen_f();
173            let buf = SerdeThreadGlobalState::get_ser(|state| {
174                let buf = state.str_buffer.clone();
175                let offset_gen = core::mem::take(&mut state.offset_gen);
176                buf.freeze();
177                state.offsets = Some(offset_gen.into_iter());
178                buf
179            });
180            final_gen_f(r, StrBuffer { inner: buf })
181        },
182    )
183}
184
185pub(crate) mod inner {
186    use alloc::{boxed::Box, vec::Vec};
187    use core::cell::{Cell, UnsafeCell};
188
189    pub(crate) struct StrBufferInner {
190        writable: Cell<bool>,
191        static_borrowed: Option<Box<dyn 'static + FnOnce()>>,
192        buf: UnsafeCell<Vec<u8>>,
193    }
194
195    impl Drop for StrBufferInner {
196        fn drop(&mut self) {
197            if let Some(f) = self.static_borrowed.take() {
198                let buf = unsafe { &mut *self.buf.get() };
199                let mut empty = vec![];
200                core::mem::swap(&mut empty, buf);
201                let _ = Box::into_raw(empty.into_boxed_slice());
202                f();
203            }
204        }
205    }
206
207    impl core::fmt::Debug for StrBufferInner {
208        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
209            write!(
210                f,
211                "StrBufferInner {{ writable: {}, buf: [...] }}",
212                self.writable.get()
213            )
214        }
215    }
216
217    impl StrBufferInner {
218        pub(super) fn new() -> Self {
219            Self {
220                writable: Cell::new(true),
221                static_borrowed: None,
222                buf: UnsafeCell::new(vec![]),
223            }
224        }
225
226        pub(super) fn new_with_buf(buf: Vec<u8>) -> Self {
227            Self {
228                writable: Cell::new(false),
229                static_borrowed: None,
230                buf: UnsafeCell::new(buf),
231            }
232        }
233
234        pub(super) unsafe fn new_static_borrowed(
235            buf: *mut [u8],
236            drop_callback: Box<dyn 'static + FnOnce()>,
237        ) -> Self {
238            Self {
239                writable: Cell::new(false),
240                static_borrowed: Some(Box::new(drop_callback)),
241                buf: UnsafeCell::new(Box::from_raw(buf).into_vec()),
242            }
243        }
244
245        pub(super) fn freeze(&self) {
246            self.writable.set(false);
247        }
248
249        pub(super) fn append(&self, s: &str) -> usize {
250            if !self.writable.get() {
251                panic!("StrBuffer is not in writable stage");
252            }
253            let buf = unsafe { &mut *self.buf.get() };
254            let offset = buf.len();
255            buf.append(&mut Vec::from(s.as_bytes()));
256            offset
257        }
258
259        pub(super) fn read(&self) -> &[u8] {
260            if self.writable.get() {
261                panic!("StrBuffer is not in writable stage");
262            }
263            let buf = unsafe { &mut *self.buf.get() };
264            buf.as_slice()
265        }
266
267        pub(super) fn len(&self) -> usize {
268            let buf = unsafe { &mut *self.buf.get() };
269            buf.len()
270        }
271    }
272}
273
274/// cbindgen:ignore
275#[repr(C)]
276#[derive(Debug, Clone)]
277pub struct StrBuffer {
278    inner: Rc<StrBufferInner>,
279}
280
281impl StrBuffer {
282    #[cfg(feature = "serialize")]
283    pub(crate) fn new() -> Self {
284        Self {
285            inner: Rc::new(StrBufferInner::new()),
286        }
287    }
288
289    pub(crate) fn new_with_buf(buf: Vec<u8>) -> Self {
290        Self {
291            inner: Rc::new(StrBufferInner::new_with_buf(buf)),
292        }
293    }
294
295    pub(crate) unsafe fn new_static_borrowed(
296        buf: *mut [u8],
297        drop_callback: Box<dyn 'static + FnOnce()>,
298    ) -> Self {
299        Self {
300            inner: Rc::new(StrBufferInner::new_static_borrowed(buf, drop_callback)),
301        }
302    }
303
304    #[cfg(feature = "serialize")]
305    pub(crate) fn freeze(&mut self) {
306        self.inner.freeze()
307    }
308
309    pub(crate) fn whole_buffer(&self) -> &[u8] {
310        self.inner.read()
311    }
312}
313
314/// An string format which is compatible with the binary format.
315///
316/// cbindgen:ignore
317#[repr(C)]
318#[derive(Clone)]
319pub struct StrRef {
320    offset: usize,
321    len: usize,
322    buf: Rc<StrBufferInner>,
323}
324
325impl StrRef {
326    /// Convert it to `[u8]`.
327    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
328        let buf = self.buf.read();
329        unsafe {
330            let ptr = (buf as *const [u8] as *const u8).add(self.offset);
331            core::slice::from_raw_parts::<'a, u8>(ptr, self.len)
332        }
333    }
334
335    /// Convert it to `str`.
336    pub fn as_str(&self) -> &str {
337        core::str::from_utf8(self.as_slice()).unwrap_or_default()
338    }
339
340    #[doc(hidden)]
341    /// # Safety
342    ///
343    pub unsafe fn as_str_unchecked(&self) -> &str {
344        core::str::from_utf8_unchecked(self.as_slice())
345    }
346
347    /// Convert it to `String`.
348    #[allow(clippy::inherent_to_string)]
349    pub fn to_string(&self) -> String {
350        String::from_utf8_lossy(self.as_slice()).into_owned()
351    }
352
353    /// Compare it with `str`.
354    pub fn equal(&self, s: &str) -> bool {
355        self.as_slice() == s.as_bytes()
356    }
357
358    #[doc(hidden)]
359    #[cfg(feature = "ffi")]
360    #[no_mangle]
361    pub extern "C" fn str_ptr(&self) -> *const u8 {
362        let buf = self.buf.read();
363        unsafe { (buf as *const [u8] as *const u8).add(self.offset) }
364    }
365
366    #[doc(hidden)]
367    #[cfg(feature = "ffi")]
368    #[no_mangle]
369    pub extern "C" fn str_len(&self) -> usize {
370        self.len
371    }
372}
373
374impl<T: alloc::string::ToString> From<T> for StrRef {
375    fn from(s: T) -> Self {
376        let s = s.to_string();
377        let len = s.len();
378        let buf = Rc::new(StrBufferInner::new_with_buf(s.into_bytes()));
379        Self {
380            offset: 0,
381            len,
382            buf,
383        }
384    }
385}
386
387impl Default for StrRef {
388    fn default() -> Self {
389        Self::from(String::new())
390    }
391}
392
393impl PartialEq for StrRef {
394    fn eq(&self, other: &Self) -> bool {
395        self.as_slice() == other.as_slice()
396    }
397}
398
399impl Serialize for StrRef {
400    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
401    where
402        S: serde::Serializer,
403    {
404        let offset = SerdeThreadGlobalState::get_ser(|state| {
405            if let Some(offsets) = state.offsets.as_mut() {
406                offsets.next().unwrap_or_default()
407            } else {
408                let x = state.str_buffer.append(self.as_str());
409                state.offset_gen.push(x);
410                0
411            }
412        });
413        (offset, self.len).serialize(ser)
414    }
415}
416
417impl<'de> Deserialize<'de> for StrRef {
418    fn deserialize<D>(de: D) -> Result<Self, D::Error>
419    where
420        D: serde::Deserializer<'de>,
421    {
422        let buf = SerdeThreadGlobalState::get_de(|state| state.str_buffer.clone());
423        let (offset, len) = <(usize, usize)>::deserialize(de)?;
424        let offset = offset.min(buf.len());
425        Ok(Self { offset, len, buf })
426    }
427}
428impl Debug for StrRef {
429    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
430        write!(f, "{}", self.as_str())
431    }
432}
433#[cfg(debug_assertions)]
434impl crate::CompatibilityCheck for StrRef {
435    fn check() {}
436}