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)] use std::alloc::Layout;
10use std::ptr::null;
11use std::slice;
12
13include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
14
15#[cfg(feature = "dynamic")]
16mod dylib;
17#[cfg(feature = "dynamic")]
18pub use dylib::*;
19
20unsafe impl Send for ddwaf_object {}
23unsafe impl Sync for ddwaf_object {}
24
25#[warn(clippy::pedantic)]
26impl ddwaf_object {
27 #[allow(clippy::missing_panics_doc)]
35 pub unsafe fn drop_array(&mut self) {
36 debug_assert_eq!(self.obj_type(), DDWAF_OBJ_ARRAY);
37 let array = unsafe { self.via.array };
38 if array.capacity == 0 {
39 return;
40 }
41 for i in 0..array.size {
42 #[allow(clippy::cast_possible_wrap)]
44 let elem = unsafe { &mut *array.ptr.offset(i as isize) };
45 unsafe { elem.drop_object() };
46 }
47 let layout = Layout::array::<ddwaf_object>(array.capacity as usize).unwrap();
50 unsafe { std::alloc::dealloc(array.ptr.cast(), layout) };
51 }
52
53 #[allow(clippy::missing_panics_doc)]
61 pub unsafe fn drop_map(&mut self) {
62 debug_assert_eq!(self.obj_type(), DDWAF_OBJ_MAP);
63 let map = unsafe { self.via.map };
64 if map.capacity == 0 {
65 return;
66 }
67 for i in 0..map.size {
68 #[allow(clippy::cast_possible_wrap)]
69 let elem = unsafe { &mut *map.ptr.offset(i as isize) };
70 unsafe { elem.key.drop_object() };
71 unsafe { elem.val.drop_object() };
72 }
73 let layout = Layout::array::<_ddwaf_object_kv>(map.capacity as usize).unwrap();
74 unsafe { std::alloc::dealloc(map.ptr.cast(), layout) };
75 }
76
77 pub unsafe fn drop_object(&mut self) {
85 match self.obj_type() {
86 DDWAF_OBJ_STRING => unsafe { self.drop_string() },
87 DDWAF_OBJ_ARRAY => unsafe { self.drop_array() },
88 DDWAF_OBJ_MAP => unsafe { self.drop_map() },
89 _ => { }
90 }
91 }
92
93 #[allow(clippy::missing_panics_doc)]
101 pub unsafe fn drop_string(&mut self) {
102 debug_assert_eq!(self.obj_type(), DDWAF_OBJ_STRING);
103 let sval = unsafe { self.via.str_.ptr };
104 if sval.is_null() {
105 return;
106 }
107 unsafe {
108 std::alloc::dealloc(
109 sval.cast(),
110 Layout::array::<::std::os::raw::c_char>(self.via.str_.size as usize).unwrap(),
111 );
112 }
113 }
114
115 #[must_use]
117 pub fn obj_type(&self) -> DDWAF_OBJ_TYPE {
118 DDWAF_OBJ_TYPE::from(unsafe { self.type_ })
119 }
120
121 #[must_use]
123 pub fn is_string(&self) -> bool {
124 (self.obj_type() & DDWAF_OBJ_STRING) != 0
125 }
126
127 unsafe fn string_vec(&self) -> &[u8] {
132 debug_assert!(self.is_string());
133
134 if self.obj_type() == DDWAF_OBJ_STRING || self.obj_type() == DDWAF_OBJ_LITERAL_STRING {
135 let str = unsafe { self.via.str_ };
136 if str.size == 0 {
137 return &[];
138 }
139 unsafe { slice::from_raw_parts(str.ptr.cast(), str.size as usize) }
140 } else {
141 let sstr = unsafe { &self.via.sstr };
142 let data = &sstr.data[..sstr.size as usize];
143 unsafe { std::slice::from_raw_parts(data.as_ptr().cast(), data.len()) }
145 }
146 }
147}
148
149impl std::cmp::PartialEq<ddwaf_object> for ddwaf_object {
150 fn eq(&self, other: &ddwaf_object) -> bool {
151 if self.is_string() && other.is_string() {
152 let left = unsafe { self.string_vec() };
153 let right = unsafe { other.string_vec() };
154 return left == right;
155 }
156
157 if unsafe { self.type_ != other.type_ } {
158 return false;
159 }
160 match self.obj_type() {
161 DDWAF_OBJ_INVALID | DDWAF_OBJ_NULL => true,
162 DDWAF_OBJ_SIGNED => unsafe { self.via.i64_.val == other.via.i64_.val },
163 DDWAF_OBJ_UNSIGNED => unsafe { self.via.u64_.val == other.via.u64_.val },
164 DDWAF_OBJ_BOOL => unsafe { self.via.b8.val == other.via.b8.val },
165 DDWAF_OBJ_FLOAT => unsafe { self.via.f64_.val == other.via.f64_.val },
166 DDWAF_OBJ_ARRAY => {
167 let left = unsafe { self.via.array };
168 let right = unsafe { other.via.array };
169 if left.size != right.size {
170 return false;
171 }
172 if left.size == 0 {
173 return true;
174 }
175 for i in 0..left.size {
176 let left = unsafe { &*left.ptr.offset(i as isize) };
177 let right = unsafe { &*right.ptr.offset(i as isize) };
178 if left != right {
179 return false;
180 }
181 }
182 true
183 }
184 DDWAF_OBJ_MAP => {
185 let left = unsafe { self.via.map };
186 let right = unsafe { other.via.map };
187 if left.size != right.size {
188 return false;
189 }
190 if left.size == 0 {
191 return true;
192 }
193 for i in 0..left.size {
194 let left = unsafe { &*left.ptr.offset(i as isize) };
195 let right = unsafe { &*right.ptr.offset(i as isize) };
196 if left.key != right.key || left.val != right.val {
197 return false;
198 }
199 }
200 true
201 }
202
203 _ => false,
204 }
205 }
206}
207impl std::fmt::Debug for ddwaf_object {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 let mut dbg = f.debug_struct("ddwaf_object");
210 match self.obj_type() {
211 DDWAF_OBJ_BOOL => dbg
212 .field("type", &stringify!(DDWAF_OBJ_BOOL))
213 .field("boolean", unsafe { &self.via.b8.val }),
214 DDWAF_OBJ_FLOAT => dbg
215 .field("type", &stringify!(DDWAF_OBJ_FLOAT))
216 .field("f64", unsafe { &self.via.f64_.val }),
217 DDWAF_OBJ_SIGNED => dbg
218 .field("type", &stringify!(DDWAF_OBJ_SIGNED))
219 .field("int", unsafe { &self.via.i64_.val }),
220 DDWAF_OBJ_UNSIGNED => dbg
221 .field("type", &stringify!(DDWAF_OBJ_UNSIGNED))
222 .field("uint", unsafe { &self.via.u64_.val }),
223 DDWAF_OBJ_STRING | DDWAF_OBJ_LITERAL_STRING => {
224 let sval = unsafe { self.string_vec() };
225 let sval = String::from_utf8_lossy(sval);
226 dbg.field(
227 "type",
228 if self.obj_type() == DDWAF_OBJ_STRING {
229 &stringify!(DDWAF_OBJ_STRING)
230 } else {
231 &stringify!(DDWAF_OBJ_LITERAL_STRING)
232 },
233 )
234 .field("string", &sval)
235 }
236 DDWAF_OBJ_SMALL_STRING => {
237 let sval = unsafe { self.string_vec() };
238 let sval = String::from_utf8_lossy(sval);
239 dbg.field("type", &stringify!(DDWAF_OBJ_SMALL_STRING))
240 .field("string", &sval)
241 }
242 DDWAF_OBJ_ARRAY => {
243 let array = unsafe { self.via.array };
244 let array: &[ddwaf_object] =
245 unsafe { slice::from_raw_parts(array.ptr.cast(), array.size as usize) };
246 dbg.field("type", &stringify!(DDWAF_OBJ_ARRAY))
247 .field("array", &array)
248 }
249 DDWAF_OBJ_MAP => {
250 let map = unsafe { self.via.map };
251 let map: &[_ddwaf_object_kv] =
252 unsafe { slice::from_raw_parts(map.ptr.cast(), map.size as usize) };
253 dbg.field("type", &stringify!(DDWAF_OBJ_MAP))
254 .field("map", &map)
255 }
256 DDWAF_OBJ_NULL => dbg.field("type", &stringify!(DDWAF_OBJ_NULL)),
257 DDWAF_OBJ_INVALID => dbg.field("type", &stringify!(DDWAF_OBJ_INVALID)),
258 unknown => dbg.field("type", &unknown),
259 };
260
261 dbg.finish_non_exhaustive()
262 }
263}
264
265impl std::fmt::Debug for _ddwaf_object_kv {
266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 let mut dbg = f.debug_struct("ddwaf_object_kv");
268 dbg.field("key", &self.key)
269 .field("val", &self.val)
270 .finish_non_exhaustive()
271 }
272}