1#![crate_type = "dylib"]
2#![deny(clippy::correctness, clippy::perf, clippy::style, clippy::suspicious)]
3#![allow(unused)]
4#![allow(non_camel_case_types)]
5#![allow(non_snake_case)]
6#![allow(non_upper_case_globals)]
7#![allow(unsafe_op_in_unsafe_fn)] #![allow(clippy::missing_safety_doc)] #![allow(clippy::ptr_offset_with_cast)] #![allow(clippy::unnecessary_cast)] #![allow(clippy::useless_transmute)] #[cfg(any(feature = "source-static", feature = "source-shared"))]
14extern crate libddwaf_src;
15
16use std::alloc::Layout;
17use std::ptr::null;
18use std::slice;
19
20include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
21
22#[cfg(libddwaf_windows_dll)]
23#[no_mangle]
24pub unsafe extern "C" fn ddwaf_object_set_string_nocopy(
25 object: *mut ddwaf_object,
26 string: *const std::os::raw::c_char,
27 length: u32,
28) -> *mut ddwaf_object {
29 if object.is_null() || string.is_null() {
30 return std::ptr::null_mut();
31 }
32
33 unsafe {
34 (*object).via.str_ = _ddwaf_object_string {
35 type_: DDWAF_OBJ_STRING as u8,
36 size: length,
37 ptr: string.cast_mut(),
38 };
39 }
40 object
41}
42
43#[cfg(feature = "dynamic")]
44mod dylib;
45#[cfg(feature = "dynamic")]
46pub use dylib::*;
47
48unsafe impl Send for ddwaf_object {}
51unsafe impl Sync for ddwaf_object {}
52
53#[warn(clippy::pedantic)]
54impl ddwaf_object {
55 pub unsafe fn drop_array(&mut self) {
67 debug_assert!(self.is_array());
68 let size = self.array_len();
69 let capacity = self.array_capacity();
70 if capacity == 0 {
71 return;
72 }
73 let ptr = self.array_ptr();
74 for i in 0..size {
75 let elem = unsafe { &mut *ptr.add(i) };
76 unsafe { elem.drop_object() };
77 }
78 let layout = Layout::array::<ddwaf_object>(capacity).unwrap();
79 unsafe { std::alloc::dealloc(ptr.cast(), layout) };
80 }
81
82 pub unsafe fn drop_map(&mut self) {
94 debug_assert!(self.is_map());
95 let size = self.map_len();
96 let capacity = self.map_capacity();
97 if capacity == 0 {
98 return;
99 }
100 let ptr = self.map_ptr();
101 for i in 0..size {
102 let elem = unsafe { &mut *ptr.add(i) };
103 unsafe { elem.key.drop_object() };
104 unsafe { elem.val.drop_object() };
105 }
106 let layout = Layout::array::<_ddwaf_object_kv>(capacity).unwrap();
107 unsafe { std::alloc::dealloc(ptr.cast(), layout) };
108 }
109
110 pub unsafe fn drop_object(&mut self) {
118 match self.obj_type() {
119 DDWAF_OBJ_STRING => unsafe { self.drop_string() },
120 DDWAF_OBJ_ARRAY | DDWAF_OBJ_LARGE_ARRAY => unsafe { self.drop_array() },
121 DDWAF_OBJ_MAP | DDWAF_OBJ_LARGE_MAP => unsafe { self.drop_map() },
122 _ => { }
123 }
124 }
125
126 #[allow(clippy::missing_panics_doc)]
134 pub unsafe fn drop_string(&mut self) {
135 debug_assert_eq!(self.obj_type(), DDWAF_OBJ_STRING);
136 let sval = unsafe { self.via.str_.ptr };
137 if sval.is_null() {
138 return;
139 }
140 unsafe {
141 std::alloc::dealloc(
142 sval.cast(),
143 Layout::array::<::std::os::raw::c_char>(self.via.str_.size as usize).unwrap(),
144 );
145 }
146 }
147
148 #[must_use]
150 pub fn obj_type(&self) -> DDWAF_OBJ_TYPE {
151 DDWAF_OBJ_TYPE::from(unsafe { self.type_ })
152 }
153
154 #[must_use]
156 pub fn is_string(&self) -> bool {
157 (self.obj_type() & DDWAF_OBJ_STRING) != 0
158 }
159
160 #[must_use]
162 pub fn is_array(&self) -> bool {
163 matches!(self.obj_type(), DDWAF_OBJ_ARRAY | DDWAF_OBJ_LARGE_ARRAY)
164 }
165
166 #[must_use]
168 pub fn is_map(&self) -> bool {
169 matches!(self.obj_type(), DDWAF_OBJ_MAP | DDWAF_OBJ_LARGE_MAP)
170 }
171
172 #[must_use]
177 #[allow(clippy::cast_possible_truncation)]
178 pub fn array_len(&self) -> usize {
179 match self.obj_type() {
180 DDWAF_OBJ_ARRAY => usize::from(unsafe { self.via.array.size }),
181 DDWAF_OBJ_LARGE_ARRAY => unsafe { self.via.large_array.size() as usize },
182 object_type => panic!("object of type {object_type} is not an array"),
183 }
184 }
185
186 #[must_use]
191 #[allow(clippy::cast_possible_truncation)]
192 pub fn array_capacity(&self) -> usize {
193 match self.obj_type() {
194 DDWAF_OBJ_ARRAY => usize::from(unsafe { self.via.array.capacity }),
195 DDWAF_OBJ_LARGE_ARRAY => unsafe { self.via.large_array.capacity() as usize },
196 object_type => panic!("object of type {object_type} is not an array"),
197 }
198 }
199
200 #[must_use]
205 pub fn array_ptr(&self) -> *mut ddwaf_object {
206 match self.obj_type() {
207 DDWAF_OBJ_ARRAY => unsafe { self.via.array.ptr },
208 DDWAF_OBJ_LARGE_ARRAY => unsafe { self.via.large_array.ptr },
209 object_type => panic!("object of type {object_type} is not an array"),
210 }
211 }
212
213 pub unsafe fn set_array_len(&mut self, new_len: usize) {
221 assert!(new_len <= self.array_capacity());
222 match self.obj_type() {
223 DDWAF_OBJ_ARRAY => {
224 self.via.array.size = new_len.try_into().expect("compact array length overflow");
225 }
226 DDWAF_OBJ_LARGE_ARRAY => unsafe {
227 self.via.large_array.set_size(new_len as u64);
228 },
229 _ => unreachable!(),
230 }
231 }
232
233 #[must_use]
238 #[allow(clippy::cast_possible_truncation)]
239 pub fn map_len(&self) -> usize {
240 match self.obj_type() {
241 DDWAF_OBJ_MAP => usize::from(unsafe { self.via.map.size }),
242 DDWAF_OBJ_LARGE_MAP => unsafe { self.via.large_map.size() as usize },
243 object_type => panic!("object of type {object_type} is not a map"),
244 }
245 }
246
247 #[must_use]
252 #[allow(clippy::cast_possible_truncation)]
253 pub fn map_capacity(&self) -> usize {
254 match self.obj_type() {
255 DDWAF_OBJ_MAP => usize::from(unsafe { self.via.map.capacity }),
256 DDWAF_OBJ_LARGE_MAP => unsafe { self.via.large_map.capacity() as usize },
257 object_type => panic!("object of type {object_type} is not a map"),
258 }
259 }
260
261 #[must_use]
266 pub fn map_ptr(&self) -> *mut _ddwaf_object_kv {
267 match self.obj_type() {
268 DDWAF_OBJ_MAP => unsafe { self.via.map.ptr },
269 DDWAF_OBJ_LARGE_MAP => unsafe { self.via.large_map.ptr },
270 object_type => panic!("object of type {object_type} is not a map"),
271 }
272 }
273
274 pub unsafe fn set_map_len(&mut self, new_len: usize) {
282 assert!(new_len <= self.map_capacity());
283 match self.obj_type() {
284 DDWAF_OBJ_MAP => {
285 self.via.map.size = new_len.try_into().expect("compact map length overflow");
286 }
287 DDWAF_OBJ_LARGE_MAP => unsafe {
288 self.via.large_map.set_size(new_len as u64);
289 },
290 _ => unreachable!(),
291 }
292 }
293
294 unsafe fn string_vec(&self) -> &[u8] {
299 debug_assert!(self.is_string());
300
301 if self.obj_type() == DDWAF_OBJ_STRING || self.obj_type() == DDWAF_OBJ_LITERAL_STRING {
302 let str = unsafe { self.via.str_ };
303 if str.size == 0 {
304 return &[];
305 }
306 unsafe { slice::from_raw_parts(str.ptr.cast(), str.size as usize) }
307 } else {
308 let sstr = unsafe { &self.via.sstr };
309 let data = &sstr.data[..sstr.size as usize];
310 unsafe { std::slice::from_raw_parts(data.as_ptr().cast(), data.len()) }
312 }
313 }
314}
315
316impl std::cmp::PartialEq<ddwaf_object> for ddwaf_object {
317 fn eq(&self, other: &ddwaf_object) -> bool {
318 if self.is_string() && other.is_string() {
319 let left = unsafe { self.string_vec() };
320 let right = unsafe { other.string_vec() };
321 return left == right;
322 }
323
324 if self.is_array() && other.is_array() {
325 if self.array_len() != other.array_len() {
326 return false;
327 }
328 for i in 0..self.array_len() {
329 let left = unsafe { &*self.array_ptr().add(i) };
330 let right = unsafe { &*other.array_ptr().add(i) };
331 if left != right {
332 return false;
333 }
334 }
335 return true;
336 }
337
338 if self.is_map() && other.is_map() {
339 if self.map_len() != other.map_len() {
340 return false;
341 }
342 for i in 0..self.map_len() {
343 let left = unsafe { &*self.map_ptr().add(i) };
344 let right = unsafe { &*other.map_ptr().add(i) };
345 if left.key != right.key || left.val != right.val {
346 return false;
347 }
348 }
349 return true;
350 }
351
352 if unsafe { self.type_ != other.type_ } {
353 return false;
354 }
355 match self.obj_type() {
356 DDWAF_OBJ_INVALID | DDWAF_OBJ_NULL => true,
357 DDWAF_OBJ_SIGNED => unsafe { self.via.i64_.val == other.via.i64_.val },
358 DDWAF_OBJ_UNSIGNED => unsafe { self.via.u64_.val == other.via.u64_.val },
359 DDWAF_OBJ_BOOL => unsafe { self.via.b8.val == other.via.b8.val },
360 DDWAF_OBJ_FLOAT => unsafe { self.via.f64_.val == other.via.f64_.val },
361 _ => false,
362 }
363 }
364}
365impl std::fmt::Debug for ddwaf_object {
366 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
367 let mut dbg = f.debug_struct("ddwaf_object");
368 match self.obj_type() {
369 DDWAF_OBJ_BOOL => dbg
370 .field("type", &stringify!(DDWAF_OBJ_BOOL))
371 .field("boolean", unsafe { &self.via.b8.val }),
372 DDWAF_OBJ_FLOAT => dbg
373 .field("type", &stringify!(DDWAF_OBJ_FLOAT))
374 .field("f64", unsafe { &self.via.f64_.val }),
375 DDWAF_OBJ_SIGNED => dbg
376 .field("type", &stringify!(DDWAF_OBJ_SIGNED))
377 .field("int", unsafe { &self.via.i64_.val }),
378 DDWAF_OBJ_UNSIGNED => dbg
379 .field("type", &stringify!(DDWAF_OBJ_UNSIGNED))
380 .field("uint", unsafe { &self.via.u64_.val }),
381 DDWAF_OBJ_STRING | DDWAF_OBJ_LITERAL_STRING => {
382 let sval = unsafe { self.string_vec() };
383 let sval = String::from_utf8_lossy(sval);
384 dbg.field(
385 "type",
386 if self.obj_type() == DDWAF_OBJ_STRING {
387 &stringify!(DDWAF_OBJ_STRING)
388 } else {
389 &stringify!(DDWAF_OBJ_LITERAL_STRING)
390 },
391 )
392 .field("string", &sval)
393 }
394 DDWAF_OBJ_SMALL_STRING => {
395 let sval = unsafe { self.string_vec() };
396 let sval = String::from_utf8_lossy(sval);
397 dbg.field("type", &stringify!(DDWAF_OBJ_SMALL_STRING))
398 .field("string", &sval)
399 }
400 DDWAF_OBJ_ARRAY | DDWAF_OBJ_LARGE_ARRAY => {
401 let array: &[ddwaf_object] = if self.array_len() == 0 {
402 &[]
403 } else {
404 unsafe { slice::from_raw_parts(self.array_ptr(), self.array_len()) }
405 };
406 let object_type = if self.obj_type() == DDWAF_OBJ_ARRAY {
407 stringify!(DDWAF_OBJ_ARRAY)
408 } else {
409 stringify!(DDWAF_OBJ_LARGE_ARRAY)
410 };
411 dbg.field("type", &object_type).field("array", &array)
412 }
413 DDWAF_OBJ_MAP | DDWAF_OBJ_LARGE_MAP => {
414 let map: &[_ddwaf_object_kv] = if self.map_len() == 0 {
415 &[]
416 } else {
417 unsafe { slice::from_raw_parts(self.map_ptr(), self.map_len()) }
418 };
419 let object_type = if self.obj_type() == DDWAF_OBJ_MAP {
420 stringify!(DDWAF_OBJ_MAP)
421 } else {
422 stringify!(DDWAF_OBJ_LARGE_MAP)
423 };
424 dbg.field("type", &object_type).field("map", &map)
425 }
426 DDWAF_OBJ_NULL => dbg.field("type", &stringify!(DDWAF_OBJ_NULL)),
427 DDWAF_OBJ_INVALID => dbg.field("type", &stringify!(DDWAF_OBJ_INVALID)),
428 unknown => dbg.field("type", &unknown),
429 };
430
431 dbg.finish_non_exhaustive()
432 }
433}
434
435impl std::fmt::Debug for _ddwaf_object_kv {
436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437 let mut dbg = f.debug_struct("ddwaf_object_kv");
438 dbg.field("key", &self.key)
439 .field("val", &self.val)
440 .finish_non_exhaustive()
441 }
442}