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}