taos_query/util/
inline_nchar.rs1use 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 pub unsafe fn from_ptr<'a>(ptr: *const u8) -> &'a Self {
78 &*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 pub fn chars(&self) -> Chars<$ty> {
103 Chars {
104 data: self,
105 i: 0,
106 }
107 }
108
109 #[inline]
110 #[allow(mutable_transmutes)]
111 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 = 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.inlined(), bytes);
186 dbg!(inline.printable_inlined().as_str());
187 let p = unsafe { inline.into_inline_str().as_str() };
188 println!("{}", p);
189}