1use std::fmt;
6
7#[derive(Clone)]
13pub struct Query {
14 ptr: Option<*const u8>,
16 length: usize,
18 id: usize,
20}
21
22impl fmt::Debug for Query {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 f.debug_struct("Query")
26 .field("ptr", &self.ptr.map(|_| "..."))
27 .field("length", &self.length)
28 .field("id", &self.id)
29 .finish()
30 }
31}
32
33impl Default for Query {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl Query {
40 pub fn new() -> Self {
42 Query {
43 ptr: None,
44 length: 0,
45 id: 0,
46 }
47 }
48
49 pub fn get(&self, i: usize) -> u8 {
55 assert!(i < self.length, "Index out of bounds");
56 if let Some(ptr) = self.ptr {
57 unsafe { *ptr.add(i) }
58 } else {
59 panic!("Query has no string data");
60 }
61 }
62
63 pub fn set_str(&mut self, s: &str) {
65 self.ptr = Some(s.as_ptr());
66 self.length = s.len();
67 }
68
69 pub fn set_bytes(&mut self, bytes: &[u8]) {
71 if bytes.is_empty() {
72 self.ptr = None;
73 self.length = 0;
74 } else {
75 self.ptr = Some(bytes.as_ptr());
76 self.length = bytes.len();
77 }
78 }
79
80 pub fn set_id(&mut self, id: usize) {
82 self.id = id;
83 }
84
85 pub fn as_bytes(&self) -> &[u8] {
89 if let Some(ptr) = self.ptr {
90 unsafe { std::slice::from_raw_parts(ptr, self.length) }
91 } else {
92 &[]
93 }
94 }
95
96 pub fn as_str(&self) -> &str {
102 std::str::from_utf8(self.as_bytes()).expect("Invalid UTF-8 in query")
103 }
104
105 pub fn ptr(&self) -> Option<*const u8> {
107 self.ptr
108 }
109
110 pub fn length(&self) -> usize {
112 self.length
113 }
114
115 pub fn id(&self) -> usize {
117 self.id
118 }
119
120 pub fn clear(&mut self) {
122 *self = Query::new();
123 }
124
125 pub fn swap(&mut self, other: &mut Query) {
127 std::mem::swap(self, other);
128 }
129}
130
131unsafe impl Send for Query {}
134unsafe impl Sync for Query {}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_query_new() {
142 let query = Query::new();
143 assert_eq!(query.length(), 0);
144 assert_eq!(query.id(), 0);
145 assert_eq!(query.as_bytes(), &[]);
146 }
147
148 #[test]
149 fn test_query_default() {
150 let query = Query::default();
151 assert_eq!(query.length(), 0);
152 }
153
154 #[test]
155 fn test_query_set_str() {
156 let s = "hello";
157 let mut query = Query::new();
158 query.set_str(s);
159
160 assert_eq!(query.length(), 5);
161 assert_eq!(query.as_str(), "hello");
162 assert_eq!(query.as_bytes(), b"hello");
163 }
164
165 #[test]
166 fn test_query_set_bytes() {
167 let bytes = b"world";
168 let mut query = Query::new();
169 query.set_bytes(bytes);
170
171 assert_eq!(query.length(), 5);
172 assert_eq!(query.as_bytes(), b"world");
173 }
174
175 #[test]
176 fn test_query_set_empty_bytes() {
177 let mut query = Query::new();
178 query.set_str("test");
179 query.set_bytes(&[]);
180
181 assert_eq!(query.length(), 0);
182 assert_eq!(query.as_bytes(), &[]);
183 }
184
185 #[test]
186 fn test_query_get() {
187 let s = "test";
188 let mut query = Query::new();
189 query.set_str(s);
190
191 assert_eq!(query.get(0), b't');
192 assert_eq!(query.get(1), b'e');
193 assert_eq!(query.get(2), b's');
194 assert_eq!(query.get(3), b't');
195 }
196
197 #[test]
198 #[should_panic(expected = "Index out of bounds")]
199 fn test_query_get_out_of_bounds() {
200 let s = "test";
201 let mut query = Query::new();
202 query.set_str(s);
203 query.get(4);
204 }
205
206 #[test]
207 fn test_query_set_id() {
208 let mut query = Query::new();
209 query.set_id(42);
210 assert_eq!(query.id(), 42);
211 }
212
213 #[test]
214 fn test_query_clear() {
215 let mut query = Query::new();
216 query.set_str("test");
217 query.set_id(10);
218
219 query.clear();
220
221 assert_eq!(query.length(), 0);
222 assert_eq!(query.id(), 0);
223 assert_eq!(query.as_bytes(), &[]);
224 }
225
226 #[test]
227 fn test_query_swap() {
228 let s1 = "hello";
229 let s2 = "world";
230
231 let mut q1 = Query::new();
232 q1.set_str(s1);
233 q1.set_id(1);
234
235 let mut q2 = Query::new();
236 q2.set_str(s2);
237 q2.set_id(2);
238
239 q1.swap(&mut q2);
240
241 assert_eq!(q1.as_str(), "world");
242 assert_eq!(q1.id(), 2);
243 assert_eq!(q2.as_str(), "hello");
244 assert_eq!(q2.id(), 1);
245 }
246
247 #[test]
248 fn test_query_with_unicode() {
249 let s = "こんにちは";
250 let mut query = Query::new();
251 query.set_str(s);
252
253 assert_eq!(query.length(), s.len());
254 assert_eq!(query.as_str(), "こんにちは");
255 }
256}