taos_query/util/
inline_nchar.rs

1use std::fmt;
2
3use super::Inlinable;
4
5#[repr(C)]
6#[repr(packed(1))]
7pub struct InlineNChar<T = u16> {
8    len: T,
9    data: [u8; 0],
10}
11
12pub struct Chars<'a, T = u16> {
13    data: &'a InlineNChar<T>,
14    i: T,
15}
16
17macro_rules! _impl_inline_str {
18    ($($ty:ty) *) => {
19        $(
20
21            impl fmt::Debug for InlineNChar<$ty> {
22                #[inline]
23                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24                    f.debug_struct("InlineNChar")
25                        .field("chars_len", &self.chars_len())
26                        .field("len", &self.len())
27                        .field("data", &self.to_string())
28                        .finish()
29                }
30            }
31
32            impl fmt::Display for InlineNChar<$ty> {
33                #[inline]
34                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35                    f.write_str(&self.to_string())
36                }
37            }
38
39            impl AsRef<[u8]> for InlineNChar<$ty> {
40                #[inline]
41                fn as_ref(&self) -> &[u8] {
42                    self.as_bytes()
43                }
44            }
45            impl<'a> Iterator for Chars<'a, $ty> {
46                type Item = char;
47                #[inline]
48                fn next(&mut self) -> Option<Self::Item> {
49                    if self.i < self.data.chars_len() as $ty {
50                        let c = unsafe { std::ptr::read_unaligned(self.data.data.as_ptr().add(self.i as usize * std::mem::size_of::<char>()) as *const char) };
51                        self.i += 1;
52                        Some(c)
53                    } else {
54                        None
55                    }
56                }
57            }
58
59            impl Inlinable for InlineNChar<$ty> {
60                #[inline]
61                fn write_inlined<W: std::io::Write>(&self, wtr: &mut W) -> std::io::Result<usize> {
62                    let l = wtr.write(&self.len.to_le_bytes())?;
63                    Ok(l + wtr.write(self.as_bytes())?)
64                }
65
66                #[inline]
67                fn read_inlined<R: std::io::Read>(_: &mut R) -> std::io::Result<Self> {
68                    Err(std::io::Error::new(std::io::ErrorKind::Other, "can't read into a inlined string"))
69                }
70            }
71
72            impl InlineNChar<$ty> {
73                #[inline]
74                /// # Safety
75                ///
76                /// Do not use it directly.
77                pub unsafe fn from_ptr<'a>(ptr: *const u8) -> &'a Self {
78                    // std::mem::transmute::<*const u8, &InlineNChar<$ty>>(ptr)
79                    &*ptr.cast::<InlineNChar<$ty>>()
80                }
81                #[inline]
82                #[rustversion::attr(nightly, const)]
83                pub fn as_bytes(&self) -> &[u8] {
84                    unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.len()) }
85                }
86                #[inline]
87                pub fn to_string(&self) -> String {
88                    self.chars().collect()
89                }
90
91                #[inline]
92                pub const fn len(&self) -> usize {
93                    self.len as _
94                }
95                #[inline]
96                pub const fn chars_len(&self) -> usize {
97                    self.len() / std::mem::size_of::<char>()
98                }
99
100                // #[inline]
101                // #[rustversion::attr(nightly, const)]
102                pub fn chars(&self) -> Chars<$ty> {
103                    Chars {
104                        data: self,
105                        i: 0,
106                    }
107                }
108
109                #[inline]
110                #[allow(mutable_transmutes)]
111                /// # Safety
112                ///
113                /// Do not use it directly.
114                pub unsafe fn into_inline_str(&self) -> &super::InlineStr<$ty> {
115                    if self.len() == 0 {
116                        return std::mem::transmute(self);
117                    }
118                    let chars_len = self.chars_len();
119                    let v: &mut super::InlineStr<$ty> = std::mem::transmute(self);
120                    // let ptr = self.data.as_ptr() as *mut u8;
121                    let ptr = v.as_mut_ptr();
122                    let mut len = 0usize;
123                    for i in 0..chars_len {
124                        let c = std::ptr::read_unaligned(ptr.add(i * std::mem::size_of::<char>()) as *mut char);
125                        let mut b = [0; 4];
126                        let s = c.encode_utf8(&mut b);
127                        debug_assert!(s.len() <= 4);
128                        v.replace_utf8(&s, len);
129                        len += s.len();
130                    }
131                    v.set_len(len);
132                    v
133                }
134            }
135        )*
136    };
137}
138_impl_inline_str!(u8 u16 u32 u64 usize);
139
140macro_rules! _impl_test_inline_str {
141    ($ty:ty, $bytes:literal, $print:literal) => {{
142        let bytes = $bytes.to_vec();
143        let bytes = bytes.as_slice();
144        let inline = unsafe { InlineNChar::<$ty>::from_ptr(bytes.as_ptr()) };
145        dbg!(inline);
146        assert_eq!(inline.len(), 16);
147        assert_eq!(format!("{}", inline), "abcd");
148        assert_eq!(inline.inlined(), bytes);
149        assert_eq!(inline.printable_inlined(), $print);
150        dbg!(unsafe { inline.into_inline_str() });
151    }};
152}
153
154#[test]
155fn test_inline_nchar() {
156    _impl_test_inline_str!(
157        u8,
158        b"\x10a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00d\x00\x00\x00",
159        "\\x10a\\x00\\x00\\x00b\\x00\\x00\\x00c\\x00\\x00\\x00d\\x00\\x00\\x00"
160    );
161    _impl_test_inline_str!(
162        u16,
163        b"\x10\x00a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00d\x00\x00\x00",
164        "\\x10\\x00a\\x00\\x00\\x00b\\x00\\x00\\x00c\\x00\\x00\\x00d\\x00\\x00\\x00"
165    );
166    _impl_test_inline_str!(
167        u32,
168        b"\x10\x00\0\0a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00d\x00\x00\x00",
169        "\\x10\\x00\\x00\\x00a\\x00\\x00\\x00b\\x00\\x00\\x00c\\x00\\x00\\x00d\\x00\\x00\\x00"
170    );
171    _impl_test_inline_str!(
172        u64,
173        b"\x10\0\0\0\0\0\0\0a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00d\x00\x00\x00",
174        "\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x00a\\x00\\x00\\x00b\\x00\\x00\\x00c\\x00\\x00\\x00d\\x00\\x00\\x00"
175    );
176}
177
178#[test]
179fn test_inline_nchar_2() {
180    let mut bytes: [u8; 10] = [8, 0, 45, 78, 0, 0, 135, 101, 0, 0];
181    let bytes = bytes.as_mut_slice();
182    let inline = unsafe { InlineNChar::<u16>::from_ptr(bytes.as_mut_ptr()) };
183    dbg!(&inline);
184    // assert_eq!(inline.len(), 8);
185    assert_eq!(inline.inlined(), bytes);
186    dbg!(inline.printable_inlined().as_str());
187    let p = unsafe { inline.into_inline_str().as_str() };
188    println!("{}", p);
189}