1use std::{borrow::Cow, fmt, str, string};
2
3use thiserror::Error;
4
5#[derive(Error, Debug)]
7pub enum SizedCStringError {
8 #[error("Input string too big to fit into storage")]
9 TooBig,
10}
11
12#[derive(Clone)]
15#[repr(transparent)]
16pub struct SizedCString<const SIZE: usize>([u8; SIZE]);
17
18impl<const SIZE: usize> SizedCString<SIZE> {
19 #[must_use]
22 pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
23 str::from_utf8(&self.0)
24 }
25 #[must_use]
28 pub fn to_string_lossy(&self) -> Cow<'_, str> {
29 String::from_utf8_lossy(&self.0)
30 }
31 #[must_use]
33 pub fn is_zero(&self) -> bool {
34 self.0.iter().all(|v| *v == 0)
35 }
36 #[must_use]
38 pub fn data(&self) -> &[u8] {
39 &self.0
40 }
41}
42
43impl<const SIZE: usize> From<[u8; SIZE]> for SizedCString<SIZE> {
44 fn from(other: [u8; SIZE]) -> SizedCString<SIZE> {
45 SizedCString(other)
46 }
47}
48
49#[derive(Clone)]
51#[repr(C)]
52pub struct SizedCStringUtf16<const SIZE: usize> {
53 data: [u16; SIZE],
54}
55
56impl<const SIZE: usize> SizedCStringUtf16<SIZE> {
57 #[must_use]
60 pub fn to_string(&self) -> Result<String, string::FromUtf16Error> {
61 String::from_utf16(&self.data)
62 }
63 #[must_use]
67 pub fn to_string_lossy(&self) -> String {
68 String::from_utf16_lossy(&self.data)
69 }
70 #[must_use]
72 pub fn is_zero(&self) -> bool {
73 self.data.iter().all(|v| *v == 0)
74 }
75 #[must_use]
77 pub fn data(&self) -> &[u16] {
78 &self.data
79 }
80}
81
82impl<const SIZE: usize> TryFrom<&str> for SizedCStringUtf16<SIZE> {
83 type Error = SizedCStringError;
84
85 fn try_from(value: &str) -> Result<Self, Self::Error> {
86 let mut data: Vec<u16> = value.encode_utf16().collect();
87 if data.len() > SIZE {
88 return Err(SizedCStringError::TooBig);
89 }
90 data.resize(SIZE, 0u16);
91 Ok(Self { data: data.try_into().unwrap() })
92 }
93}
94
95impl<const SIZE: usize> fmt::Debug for SizedCString<SIZE> {
96 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
97 fmt.write_fmt(format_args!("\"{}\"", self.to_string_lossy()))
98 }
99}
100
101impl<const SIZE: usize> fmt::Debug for SizedCStringUtf16<SIZE> {
102 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
103 fmt.write_fmt(format_args!("\"{}\"", self.to_string_lossy()))
104 }
105}