1use alloc::vec::Vec;
4use core::fmt;
5
6pub fn c_string(text: &str) -> Vec<u8> {
8 let mut bytes: Vec<u8> = text.bytes().filter(|&byte| byte != 0).collect();
9 bytes.push(0);
10 bytes
11}
12
13#[derive(Debug)]
18pub struct FixedText<const N: usize> {
19 bytes: [u8; N],
20 len: usize,
21 full: bool,
24}
25
26impl<const N: usize> FixedText<N> {
27 pub const fn new() -> Self {
29 Self {
30 bytes: [0; N],
31 len: 0,
32 full: false,
33 }
34 }
35
36 pub fn as_c_bytes(&self) -> &[u8] {
38 &self.bytes[..=self.len]
39 }
40}
41
42impl<const N: usize> Default for FixedText<N> {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl<const N: usize> fmt::Write for FixedText<N> {
49 fn write_str(&mut self, text: &str) -> fmt::Result {
50 if self.full {
51 return Ok(());
52 }
53 for ch in text.chars().filter(|&ch| ch != '\0') {
54 let mut utf8 = [0; 4];
55 let encoded = ch.encode_utf8(&mut utf8).as_bytes();
56 let end = self.len + encoded.len();
58 if end + 1 > N {
59 self.full = true;
60 return Ok(());
61 }
62 self.bytes[self.len..end].copy_from_slice(encoded);
63 self.len = end;
64 }
65 Ok(())
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use core::fmt::Write as _;
72
73 use super::*;
74
75 #[test]
76 fn a_c_string_has_one_nul_at_its_end() {
77 assert_eq!(c_string("a\0b"), b"ab\0");
78 assert_eq!(c_string(""), b"\0");
79 }
80
81 #[test]
82 fn fixed_text_keeps_a_byte_for_its_nul() {
83 let mut text = FixedText::<4>::new();
84 let _ = write!(text, "abcd");
85 assert_eq!(text.as_c_bytes(), b"abc\0");
86 }
87
88 #[test]
89 fn fixed_text_is_cut_at_a_character_and_stays_cut() {
90 let mut text = FixedText::<5>::new();
91 let _ = write!(text, "ab\0é");
92 assert_eq!(text.as_c_bytes(), "abé\0".as_bytes());
93 let _ = write!(text, "é");
94 let _ = write!(text, "c");
95 assert_eq!(text.as_c_bytes(), "abé\0".as_bytes());
96 }
97}