taos_query/util/
inline_str.rs1use std::fmt;
2
3use tokio::io::*;
5
6#[repr(C)]
7#[repr(packed(1))]
8pub struct InlineStr<T = u16> {
9 len: T,
10 data: [u8; 0],
11}
12macro_rules! _impl_inline_str {
13 ($($ty:ty) *) => {
14 $(
15
16 impl fmt::Debug for InlineStr<$ty> {
17 #[inline]
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 f.debug_struct("InlineStr")
20 .field("len", &self.len())
21 .field("data", &self.as_str())
22 .finish()
23 }
24 }
25
26 impl fmt::Display for InlineStr<$ty> {
27 #[inline]
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 f.write_str(self.as_str())
30 }
31 }
32
33 impl AsRef<str> for InlineStr<$ty> {
34 #[inline]
35 fn as_ref(&self) -> &str {
36 self.as_str()
37 }
38 }
39
40 impl AsRef<[u8]> for InlineStr<$ty> {
41 #[inline]
42 fn as_ref(&self) -> &[u8] {
43 self.as_bytes()
44 }
45 }
46
47 impl super::Inlinable for InlineStr<$ty> {
48 #[inline]
49 fn write_inlined<W: std::io::Write>(&self, wtr: &mut W) -> std::io::Result<usize> {
50 let l = wtr.write(&self.len.to_le_bytes())?;
51 Ok(l + wtr.write(self.as_bytes())?)
52 }
53
54 #[inline]
55 fn read_inlined<R: std::io::Read>(_: &mut R) -> std::io::Result<Self> {
56 Err(std::io::Error::new(std::io::ErrorKind::Other, "can't read into a inlined string"))
57 }
58 }
59
60 #[async_trait::async_trait]
61 impl super::AsyncInlinable for InlineStr<$ty> {
62 #[inline]
63 async fn write_inlined<W: AsyncWrite + Unpin + Send>(&self, wtr: &mut W) -> std::io::Result<usize> {
64 let l = wtr.write(&self.len.to_le_bytes()).await?;
65 Ok(l + wtr.write(self.as_bytes()).await?)
66 }
67
68 async fn read_inlined<R: AsyncRead + Send + Unpin>(_: &mut R) -> std::io::Result<Self> {
69 Err(std::io::Error::new(std::io::ErrorKind::Other, "can't read into a inlined string"))
70 }
71 }
72
73 impl InlineStr<$ty> {
74
75 pub unsafe fn from_ptr<'a>(ptr: *const u8) -> &'a Self {
79 &*std::mem::transmute::<*const u8, *const InlineStr<$ty>>(ptr)
80 }
81
82 #[inline]
83 pub const fn as_ptr(&self) -> *const u8 {
84 self.data.as_ptr()
85 }
86 #[inline]
87 pub fn as_mut_ptr(&mut self) -> *mut u8 {
88 self.data.as_mut_ptr()
89 }
90
91 #[inline]
92 #[rustversion::attr(nightly, const)]
93 pub fn as_bytes(&self) -> &[u8] {
94 if self.len() == 0 {
95 return &[]
96 }
97 unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.len()) }
98 }
99
100 #[inline]
101 #[rustversion::attr(nightly, const)]
102 pub fn as_str(&self) -> &str {
103 unsafe { std::str::from_utf8_unchecked(self.as_bytes()) }
104 }
105
106 #[inline]
107 pub const fn len(&self) -> usize {
108 self.len as _
109 }
110
111 #[inline]
112 pub const fn is_empty(&self) -> bool {
113 self.len == 0
114 }
115
116 #[inline(never)]
117 pub(crate) unsafe fn set_len(&mut self, len: usize) {
118 self.len = len as _;
119 }
120 #[inline(never)]
121 pub(crate) unsafe fn replace_utf8(&mut self, s: &str, pos: usize) {
122 std::ptr::copy(s.as_ptr(), self.as_mut_ptr().add(pos), s.len());
123 }
124 }
125 )*
126 };
127}
128_impl_inline_str!(u8 u16 u32 u64 usize);
129
130macro_rules! _impl_test_inline_str {
131 ($ty:ty, $bytes:literal, $print:literal) => {{
132 let bytes = $bytes;
133 use super::Inlinable;
134 let inline = unsafe { InlineStr::<$ty>::from_ptr(bytes.as_ptr()) };
135 dbg!(inline);
136 assert_eq!(inline.len(), 4);
137 assert_eq!(inline.as_str(), "abcd");
138 assert_eq!(format!("{}", inline), "abcd");
139 assert_eq!(inline.inlined(), bytes);
140 assert_eq!(inline.printable_inlined(), $print);
141 }};
142}
143
144#[test]
145fn test_inline_str() {
146 _impl_test_inline_str!(u8, b"\x04abcd", "\\x04abcd");
147 _impl_test_inline_str!(u16, b"\x04\x00abcd", "\\x04\\x00abcd");
148 _impl_test_inline_str!(u32, b"\x04\x00\x00\x00abcd", "\\x04\\x00\\x00\\x00abcd");
149 _impl_test_inline_str!(
150 u64,
151 b"\x04\x00\x00\x00\x00\x00\x00\x00abcd",
152 "\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00abcd"
153 );
154}
155
156#[test]
157fn test_empty_inline() {
158 let inline = unsafe { InlineStr::<u8>::from_ptr(b"\0".as_ptr()) };
159 dbg!(inline);
160}