1use core::ops::{Deref, DerefMut};
2
3#[cfg(feature = "serde")]
4use crate::utils::nulstr;
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8#[cfg(feature = "arbitrary")]
9use arbitrary::{Arbitrary, Unstructured};
10
11#[cfg_attr(feature = "serde", derive(Serialize))]
30#[cfg_attr(feature = "serde", serde(transparent))]
31#[derive(Debug, PartialEq, Clone, Copy)]
32pub struct CharArray<const N: usize> {
33 #[cfg_attr(
34 feature = "serde",
35 serde(serialize_with = "nulstr::serialize::<_, N>",)
36 )]
37 data: [u8; N],
38
39 #[cfg_attr(feature = "serde", serde(skip))]
40 str_len: usize,
41}
42
43impl<const N: usize> CharArray<N> {
44 pub const fn new(data: [u8; N]) -> Self {
45 let mut first_null = N;
48 let mut i = 0;
49 loop {
50 if i >= N {
51 break;
52 }
53 if data[i] == 0 {
54 first_null = i;
55 break;
56 }
57 i += 1;
58 }
59 Self {
60 data,
61 str_len: first_null,
62 }
63 }
64
65 pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
69 core::str::from_utf8(&self.data[..self.str_len])
70 }
71}
72
73impl<const N: usize> Deref for CharArray<N> {
74 type Target = [u8; N];
75
76 fn deref(&self) -> &Self::Target {
77 &self.data
78 }
79}
80
81impl<const N: usize> DerefMut for CharArray<N> {
82 fn deref_mut(&mut self) -> &mut Self::Target {
83 &mut self.data
84 }
85}
86
87impl<'a, const N: usize> IntoIterator for &'a CharArray<N> {
88 type Item = &'a u8;
89 type IntoIter = core::slice::Iter<'a, u8>;
90
91 fn into_iter(self) -> Self::IntoIter {
92 self.data.iter()
93 }
94}
95
96impl<const N: usize> From<[u8; N]> for CharArray<N> {
97 fn from(data: [u8; N]) -> Self {
98 Self::new(data)
99 }
100}
101
102impl<const N: usize> From<CharArray<N>> for [u8; N] {
103 fn from(value: CharArray<N>) -> Self {
104 value.data
105 }
106}
107
108impl<const N: usize> From<&str> for CharArray<N> {
109 fn from(s: &str) -> Self {
110 let mut data = [0u8; N];
111 let bytes = s.as_bytes();
112 let len = bytes.len().min(N);
113 data[..len].copy_from_slice(&bytes[..len]);
114 Self::new(data)
115 }
116}
117
118impl<const N: usize> crate::utils::RustDefault for CharArray<N> {
119 #[inline(always)]
120 fn rust_default() -> Self {
121 Self::new([0u8; N])
122 }
123}
124
125#[cfg(feature = "serde")]
126impl<'de, const N: usize> Deserialize<'de> for CharArray<N> {
127 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
128 where
129 D: serde::Deserializer<'de>,
130 {
131 let data: [u8; N] = nulstr::deserialize(deserializer)?;
132 Ok(Self::new(data))
133 }
134}
135
136#[cfg(feature = "arbitrary")]
137impl<'a, const N: usize> Arbitrary<'a> for CharArray<N> {
138 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
139 let mut data = [0u8; N];
140 u.fill_buffer(&mut data)?;
141 Ok(CharArray::new(data))
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::CharArray;
148
149 #[test]
150 fn char_array_to_str_handles_no_nulls() {
151 let data = *b"HELLOWORLD";
152 let ca = CharArray::new(data);
153 assert_eq!(ca.len(), 10);
154 assert_eq!(ca.to_str().unwrap(), "HELLOWORLD");
155 }
156
157 #[test]
158 fn char_array_to_str_trims_after_first_null() {
159 let mut data = [0u8; 10];
160 data[..3].copy_from_slice(b"abc");
161 let ca = CharArray::new(data);
163 assert_eq!(ca.len(), 10);
164 assert_eq!(ca.to_str().unwrap(), "abc");
165 }
166
167 #[test]
168 fn char_array_from_str_into_str() {
169 let ca: CharArray<10> = "HELLOWORLD".into();
170 assert_eq!(ca.len(), 10);
171 assert_eq!(ca.to_str().unwrap(), "HELLOWORLD");
172
173 let ca: CharArray<10> = "abc".into();
174 assert_eq!(ca.len(), 10);
175 assert_eq!(ca.to_str().unwrap(), "abc");
176 }
177}