Skip to main content

gc_alloc/
string.rs

1use std::{fmt::Write, ptr::NonNull};
2
3use crate::gc;
4
5pub fn from_str(s: &str) -> &'static mut str {
6    let ptr = alloc(s.len());
7    unsafe { std::ptr::copy_nonoverlapping(s.as_ptr(), ptr.as_ptr(), s.len()) };
8    unsafe { std::str::from_utf8_unchecked_mut(std::slice::from_raw_parts_mut(ptr.as_ptr(), s.len())) }
9}
10
11pub fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> &'static str {
12    let iter = iter.into_iter();
13    let (lower, _) = iter.size_hint();
14
15    let mut formatter = Formatter::with_capacity(lower);
16    for c in iter {
17        let _ = formatter.write_char(c);
18    }
19    formatter.finish()
20}
21
22pub struct Formatter {
23    buf: NonNull<u8>,
24    len: usize,
25    cap: usize,
26}
27
28impl Formatter {
29    pub fn new() -> Self {
30        Self {
31            buf: NonNull::dangling(),
32            len: 0,
33            cap: 0,
34        }
35    }
36
37    pub fn with_capacity(cap: usize) -> Self {
38        let buf = if cap == 0 {
39            NonNull::dangling()
40        } else {
41            alloc(cap)
42        };
43        Self { buf, len: 0, cap }
44    }
45}
46
47impl Write for Formatter {
48    #[inline]
49    fn write_str(&mut self, s: &str) -> std::fmt::Result {
50        let mut cap = self.cap;
51        while self.len + s.len() > cap {
52            cap = cap.max(1).checked_mul(2).expect("Capacity overflow");
53        }
54        if cap != self.cap {
55            let new_buf = alloc(cap);
56            unsafe { std::ptr::copy_nonoverlapping(self.buf.as_ptr(), new_buf.as_ptr(), self.len) };
57            self.buf = new_buf;
58            self.cap = cap;
59        }
60        unsafe {
61            std::ptr::copy_nonoverlapping(s.as_ptr(), self.buf.add(self.len).as_ptr(), s.len())
62        };
63        self.len += s.len();
64        Ok(())
65    }
66}
67
68impl Formatter {
69    pub fn finish(self) -> &'static str {
70        if self.len == 0 {
71            return "";
72        }
73        unsafe {
74            std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.buf.as_ptr(), self.len))
75        }
76    }
77}
78
79impl Default for Formatter {
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85#[macro_export]
86#[doc(hidden)]
87macro_rules! format {
88    ($($arg:tt)*) => {{
89        let mut formatter = $crate::string::Formatter::new();
90        let _ = std::fmt::write(&mut formatter, format_args!($($arg)*));
91        formatter.finish()
92    }};
93}
94
95pub use crate::format;
96
97fn alloc(cap: usize) -> NonNull<u8> {
98    let ptr = unsafe { gc::GC_malloc_atomic(cap) as *mut u8 };
99    std::ptr::NonNull::new(ptr).expect("GC_malloc_atomic failed")
100}