seasick/
_array.rs

1use core::{
2    borrow::{Borrow, BorrowMut},
3    cmp,
4    ffi::{CStr, c_char},
5    fmt,
6    hash::{Hash, Hasher},
7    ops, slice,
8};
9
10/// A fixed-sized array that may be truncated by an interior null.
11#[derive(Clone, Copy)]
12#[repr(transparent)]
13pub struct SeaArray<const N: usize>(pub [c_char; N]);
14
15impl<const N: usize> fmt::Display for SeaArray<N> {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        crate::display_bytes(self.bytes(), f)
18    }
19}
20
21impl<const N: usize> fmt::Debug for SeaArray<N> {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        crate::debug_bytes(self.bytes(), f)
24    }
25}
26
27impl<const N: usize> SeaArray<N> {
28    pub const fn new(a: [c_char; N]) -> Self {
29        Self(a)
30    }
31    pub const fn new_ref(a: &[c_char; N]) -> &Self {
32        let ptr = a as *const [c_char; N] as *const Self;
33        unsafe { &*ptr }
34    }
35    pub const fn new_mut(a: &mut [c_char; N]) -> &mut Self {
36        let ptr = a as *mut [c_char; N] as *mut Self;
37        unsafe { &mut *ptr }
38    }
39    /// Return up to the nul-terminator, or the entire contents.
40    pub const fn bytes(&self) -> &[u8] {
41        let bytes = self.all_bytes();
42        match CStr::from_bytes_until_nul(bytes) {
43            Ok(cstr) => cstr.to_bytes(),
44            Err(_) => bytes,
45        }
46    }
47    /// Return up to the nul-terminator, or the entire contents.
48    pub const fn bytes_mut(&mut self) -> &mut [u8] {
49        let ptr = self.all_bytes_mut().as_mut_ptr();
50        let len = self.bytes().len();
51        unsafe { slice::from_raw_parts_mut(ptr, len) }
52    }
53    /// Return the entire inner array, as bytes.
54    pub const fn all_bytes(&self) -> &[u8; N] {
55        let ptr = self as *const Self as *const [u8; N];
56        unsafe { &*ptr }
57    }
58    /// Return the entire inner array, as bytes.
59    pub const fn all_bytes_mut(&mut self) -> &mut [u8; N] {
60        let ptr = self as *mut Self as *mut [u8; N];
61        unsafe { &mut *ptr }
62    }
63}
64
65impl<const N: usize> PartialEq for SeaArray<N> {
66    fn eq(&self, other: &Self) -> bool {
67        self.bytes() == other.bytes()
68    }
69}
70impl<const N: usize> Eq for SeaArray<N> {}
71impl<const N: usize> Hash for SeaArray<N> {
72    fn hash<H: Hasher>(&self, state: &mut H) {
73        self.bytes().hash(state);
74    }
75}
76impl<const N: usize> Ord for SeaArray<N> {
77    fn cmp(&self, other: &Self) -> cmp::Ordering {
78        self.bytes().cmp(other.bytes())
79    }
80}
81impl<const N: usize> PartialOrd for SeaArray<N> {
82    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
83        Some(self.cmp(other))
84    }
85}
86impl<const N: usize> AsRef<[u8]> for SeaArray<N> {
87    fn as_ref(&self) -> &[u8] {
88        self.bytes()
89    }
90}
91impl<const N: usize> Borrow<[u8]> for SeaArray<N> {
92    fn borrow(&self) -> &[u8] {
93        self.bytes()
94    }
95}
96impl<const N: usize> AsMut<[u8]> for SeaArray<N> {
97    fn as_mut(&mut self) -> &mut [u8] {
98        self.bytes_mut()
99    }
100}
101impl<const N: usize> BorrowMut<[u8]> for SeaArray<N> {
102    fn borrow_mut(&mut self) -> &mut [u8] {
103        self.bytes_mut()
104    }
105}
106
107impl<const N: usize> ops::Deref for SeaArray<N> {
108    type Target = [u8];
109    fn deref(&self) -> &Self::Target {
110        self.bytes()
111    }
112}
113impl<const N: usize> ops::DerefMut for SeaArray<N> {
114    fn deref_mut(&mut self) -> &mut Self::Target {
115        self.bytes_mut()
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122    #[test]
123    fn test() {
124        let mut arr = SeaArray([0; 64]);
125        assert_eq!(arr.len(), 0);
126
127        let Some(prefix) = arr.all_bytes_mut().first_chunk_mut() else {
128            unreachable!()
129        };
130        *prefix = *b"hello";
131
132        assert_eq!(&*arr, b"hello");
133    }
134}