musli_common/buf/
buf_string.rs1use core::fmt::{self, Write};
2use core::ops::Deref;
3use core::str;
4
5use musli::{Buf, Context};
6
7use crate::fixed::CapacityError;
8
9pub struct BufString<B> {
11 buf: B,
12}
13
14pub fn collect_string<C, T>(cx: &C, value: T) -> Result<BufString<C::Buf<'_>>, C::Error>
16where
17 C: ?Sized + Context,
18 T: fmt::Display,
19{
20 let Some(buf) = cx.alloc() else {
21 return Err(cx.message("Failed to allocate"));
22 };
23
24 let mut string = BufString::new(buf);
25
26 if write!(string, "{value}").is_err() {
27 return Err(cx.message("Failed to write to string"));
28 }
29
30 Ok(string)
31}
32
33pub fn try_collect_string<C, T>(cx: &C, value: T) -> Option<BufString<C::Buf<'_>>>
35where
36 C: ?Sized + Context,
37 T: fmt::Display,
38{
39 let buf = cx.alloc()?;
40 let mut string = BufString::new(buf);
41 write!(string, "{value}").ok()?;
42 Some(string)
43}
44
45impl<B> BufString<B>
46where
47 B: Buf,
48{
49 pub const fn new(buf: B) -> BufString<B> {
51 BufString { buf }
52 }
53
54 fn as_str(&self) -> &str {
55 unsafe { str::from_utf8_unchecked(self.buf.as_slice()) }
57 }
58
59 fn try_push(&mut self, c: char) -> Result<(), CapacityError> {
60 if !self.buf.write(c.encode_utf8(&mut [0; 4]).as_bytes()) {
61 return Err(CapacityError);
62 }
63
64 Ok(())
65 }
66
67 fn try_push_str(&mut self, s: &str) -> Result<(), CapacityError> {
68 if !self.buf.write(s.as_bytes()) {
69 return Err(CapacityError);
70 }
71
72 Ok(())
73 }
74}
75
76impl<B> fmt::Write for BufString<B>
77where
78 B: Buf,
79{
80 fn write_char(&mut self, c: char) -> fmt::Result {
81 self.try_push(c).map_err(|_| fmt::Error)
82 }
83
84 fn write_str(&mut self, s: &str) -> fmt::Result {
85 self.try_push_str(s).map_err(|_| fmt::Error)
86 }
87}
88
89impl<B> Deref for BufString<B>
90where
91 B: Buf,
92{
93 type Target = str;
94
95 #[inline]
96 fn deref(&self) -> &str {
97 unsafe { str::from_utf8_unchecked(self.buf.as_slice()) }
98 }
99}
100
101impl<B> fmt::Display for BufString<B>
102where
103 B: Buf,
104{
105 #[inline]
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 self.as_str().fmt(f)
108 }
109}
110
111impl<B> AsRef<str> for BufString<B>
112where
113 B: Buf,
114{
115 #[inline]
116 fn as_ref(&self) -> &str {
117 self.as_str()
118 }
119}