1#![cfg_attr(not(test), no_std)]
23
24use heapless::{Vec, String};
25
26#[cfg(not(feature = "ufmt"))]
27use core::fmt;
28use core::ops::{Deref, DerefMut};
29
30#[cfg(feature = "ufmt")]
31use ufmt::uWrite;
32
33#[derive(Default, Clone, Debug)]
34pub struct WriteBuf<const N: usize> {
35 buffer: Vec<u8, N>,
36}
37
38impl<const N: usize> WriteBuf<N> {
39 pub const fn new() -> Self {
40 Self {
41 buffer: Vec::new()
42 }
43 }
44
45 pub fn to_str(&self) -> Result<&str, ()> {
47 core::str::from_utf8(self.buffer.as_slice()).map_err(|_e| ())
48 }
49
50 pub fn into_ascii_lossy(self) -> String<N> {
52 let mut s = String::<N>::new();
53 for &c in self.iter() {
54 if c >= 0x80 {
55 s.push('~').ok();
56 } else {
57 s.push(c as char).ok();
58 }
59 }
60 s
61 }
62}
63
64impl<T: AsRef<[u8]>, const N: usize> From<T> for WriteBuf<N> {
65 fn from(value: T) -> Self {
66 let data = value.as_ref();
67 let mut buf = Self::new();
68 buf.extend_from_slice(&data[..core::cmp::min(data.len(), N)]).ok();
69 buf
70 }
71}
72
73impl<const N: usize> Deref for WriteBuf<N> {
74 type Target = Vec<u8, N>;
75
76 fn deref(&self) -> &Self::Target {
77 &self.buffer
78 }
79}
80
81impl<const N: usize> DerefMut for WriteBuf<N> {
82 fn deref_mut(&mut self) -> &mut Self::Target {
83 &mut self.buffer
84 }
85}
86
87#[cfg(not(feature = "ufmt"))]
88impl<const N: usize> fmt::Write for WriteBuf<N> {
89 fn write_str(&mut self, s: &str) -> fmt::Result {
90 self.buffer.write_str(s)
91 }
92}
93
94#[cfg(feature = "ufmt")]
95impl<const N: usize> uWrite for WriteBuf<N> {
96 type Error = ();
97
98 fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
99 self.buffer.write_str(s)
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_write() {
109 let buf = WriteBuf::<10>::from("1000");
110 assert_eq!(buf.to_str().unwrap(), "1000");
111 }
112
113 #[test]
114 fn test_full() {
115 let mut buf = WriteBuf::<10>::from("123456789");
116 buf.write_str("abc").err();
117 assert_eq!(buf.to_str().unwrap(), "123456789");
118 }
119
120 #[test]
121 fn test_into_ascii_lossy() {
122 let mut buf = WriteBuf::<10>::from("123456789");
123 buf.resize_default(10).ok();
124 buf[9] = 0x80u8;
125 assert_eq!(buf.into_ascii_lossy(), "123456789~");
126 }
127}