libddwaf_sys/
lib.rs

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)] // Bindgen generates some offending code...
8
9use 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
20// Implement [Send] and [Sync] for [ddwaf_object]. There is nothing thread unsafe about these unless
21// its pointers are dereferences, which is inherently unsafe anyway.
22unsafe impl Send for ddwaf_object {}
23unsafe impl Sync for ddwaf_object {}
24
25#[warn(clippy::pedantic)]
26impl ddwaf_object {
27    /// Drops the key associated with the receiving [`ddwaf_object`].
28    ///
29    /// # Safety
30    /// The key, if present, must be a raw-converted [`Box<[u8]>`]. After this method returns, the
31    /// values of [`ddwaf_object::parameterName`] and [`ddwaf_object::parameterNameLength`] must be
32    /// replaced as they will no longer be valid.
33    ///
34    /// # Panics
35    /// If the key is too large for this platform (can only happens on 32-bit platforms).
36    pub unsafe fn drop_key(&mut self) {
37        if self.parameterName.is_null() {
38            return;
39        }
40        let len =
41            usize::try_from(self.parameterNameLength).expect("key is too large for this platform");
42        let slice: &mut [u8] = unsafe {
43            std::slice::from_raw_parts_mut(self.parameterName.cast::<u8>().cast_mut(), len)
44        };
45        drop(unsafe { Box::from_raw(std::ptr::from_mut(slice)) });
46    }
47
48    /// Drops the array data associated with the receiving [`ddwaf_object`].
49    ///
50    /// # Safety
51    /// - The [`ddwaf_object`] must be a valid representation of an array.
52    /// - The array must be an [`std::alloc::alloc`]ated array of [`ddwaf_object`] of the proper size.
53    /// - The individual elements of the array must be valid [`ddwaf_object`]s that can be dropped
54    ///   with [`ddwaf_object::drop_object`].
55    ///
56    /// # Panics
57    /// If the array is too large for this platform (can only happens on 32-bit platforms).
58    pub unsafe fn drop_array(&mut self) {
59        debug_assert_eq!(self.type_, DDWAF_OBJ_ARRAY);
60        if self.nbEntries == 0 {
61            return;
62        }
63        let array = unsafe { self.__bindgen_anon_1.array };
64        let len = isize::try_from(self.nbEntries).expect("array is too large for this platform");
65        for i in 0..len {
66            let elem = unsafe { &mut *array.offset(i) };
67            unsafe { elem.drop_object() };
68        }
69        #[allow(clippy::cast_possible_truncation)] // We could cast to isize, and usize is wider.
70        let layout = Layout::array::<ddwaf_object>(self.nbEntries as usize).unwrap();
71        unsafe { std::alloc::dealloc(array.cast(), layout) };
72    }
73
74    /// Drops the map data associated with the receiving [`ddwaf_object`].
75    ///
76    /// # Safety
77    /// - The [`ddwaf_object`] must be a valid representation of a map.
78    /// - The map must be an [`std::alloc::alloc`]ated array of [`ddwaf_object`] of the proper size.
79    /// - The individual elements of the map must be valid [`ddwaf_object`]s that can be dropped with
80    ///   both [`ddwaf_object::drop_object`] and [`ddwaf_object::drop_key`].
81    ///
82    /// # Panics
83    /// If the map is too large for this platform (can only happens on 32-bit platforms).
84    pub unsafe fn drop_map(&mut self) {
85        debug_assert_eq!(self.type_, DDWAF_OBJ_MAP);
86        if self.nbEntries == 0 {
87            return;
88        }
89        let array = unsafe { self.__bindgen_anon_1.array };
90        let len = isize::try_from(self.nbEntries).expect("map is too large for this platform");
91        for i in 0..len {
92            let elem = unsafe { &mut *array.offset(i) };
93            unsafe { elem.drop_key() };
94            unsafe { elem.drop_object() };
95        }
96        #[allow(clippy::cast_possible_truncation)] // We could cast to isize, and usize is wider.
97        let layout = Layout::array::<ddwaf_object>(self.nbEntries as usize).unwrap();
98        unsafe { std::alloc::dealloc(array.cast(), layout) };
99    }
100
101    /// Drops the value associated with the receiving [`ddwaf_object`].
102    ///
103    /// # Safety
104    /// If the [`ddwaf_object`] is a string, array, or map, the respective requirements of the
105    /// [`ddwaf_object::drop_string`], [`ddwaf_object::drop_array`], or [`ddwaf_object::drop_map`]
106    /// methods apply.
107    pub unsafe fn drop_object(&mut self) {
108        match self.type_ {
109            DDWAF_OBJ_STRING => unsafe { self.drop_string() },
110            DDWAF_OBJ_ARRAY => unsafe { self.drop_array() },
111            DDWAF_OBJ_MAP => unsafe { self.drop_map() },
112            _ => { /* nothing to do */ }
113        }
114    }
115
116    /// Drops the string associated with the receiving [`ddwaf_object`].
117    ///
118    /// # Safety
119    /// - The [`ddwaf_object`] must be a valid representation of a string
120    /// - The [`ddwaf_object::__bindgen_anon_1`] field must have a
121    ///   [`_ddwaf_object__bindgen_ty_1::stringValue`] set from a raw-converted [`Box<[u8]>`]
122    ///
123    /// # Panics
124    /// If the string is too large for this platform (can only happens on 32-bit platforms).
125    pub unsafe fn drop_string(&mut self) {
126        debug_assert_eq!(self.type_, DDWAF_OBJ_STRING);
127        let sval = unsafe { self.__bindgen_anon_1.stringValue };
128        if sval.is_null() {
129            return;
130        }
131        let len = usize::try_from(self.nbEntries).expect("string is too large for this platform");
132        let slice: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(sval as *mut _, len) };
133        drop(unsafe { Box::from_raw(slice) });
134    }
135}
136impl std::cmp::PartialEq<ddwaf_object> for ddwaf_object {
137    fn eq(&self, other: &ddwaf_object) -> bool {
138        if self.type_ != other.type_ {
139            return false;
140        }
141        match self.type_ {
142            DDWAF_OBJ_INVALID | DDWAF_OBJ_NULL => true,
143            DDWAF_OBJ_SIGNED => unsafe {
144                self.__bindgen_anon_1.intValue == other.__bindgen_anon_1.intValue
145            },
146            DDWAF_OBJ_UNSIGNED => unsafe {
147                self.__bindgen_anon_1.uintValue == other.__bindgen_anon_1.uintValue
148            },
149            DDWAF_OBJ_BOOL => unsafe {
150                self.__bindgen_anon_1.boolean == other.__bindgen_anon_1.boolean
151            },
152            DDWAF_OBJ_FLOAT => unsafe {
153                // We do an exact comparison here, which ought to be okay as we normally don't do math here...
154                self.__bindgen_anon_1.f64_ == other.__bindgen_anon_1.f64_
155            },
156
157            // Strings are a pointer, we need to compare the data they point to...
158            DDWAF_OBJ_STRING => unsafe {
159                if self.nbEntries != other.nbEntries {
160                    return false;
161                }
162                if self.nbEntries == 0 {
163                    return true;
164                }
165                let len =
166                    usize::try_from(self.nbEntries).expect("string is too large for this platform");
167                let left = slice::from_raw_parts(self.__bindgen_anon_1.stringValue, len);
168                let right = slice::from_raw_parts(other.__bindgen_anon_1.stringValue, len);
169                left == right
170            },
171
172            // Arrays and maps are pointers to collections, we need to compare the data they point to...
173            DDWAF_OBJ_ARRAY | DDWAF_OBJ_MAP => unsafe {
174                if self.nbEntries != other.nbEntries {
175                    return false;
176                }
177                if self.nbEntries == 0 {
178                    return true;
179                }
180
181                let left = slice::from_raw_parts(
182                    self.__bindgen_anon_1.array,
183                    usize::try_from(self.nbEntries)
184                        .expect("array/map is too large for this platform"),
185                );
186                let right = slice::from_raw_parts(
187                    other.__bindgen_anon_1.array,
188                    usize::try_from(other.nbEntries)
189                        .expect("array/map is too large for this platform"),
190                );
191                for (left, right) in left.iter().zip(right.iter()) {
192                    if self.type_ == DDWAF_OBJ_MAP {
193                        if left.parameterNameLength != right.parameterNameLength {
194                            return false;
195                        }
196                        let len = usize::try_from(left.parameterNameLength)
197                            .expect("key is too large for this platform");
198                        if len > 0 {
199                            let left_key = slice::from_raw_parts(left.parameterName, len);
200                            let right_key = slice::from_raw_parts(right.parameterName, len);
201                            if left_key != right_key {
202                                return false;
203                            }
204                        }
205                    }
206                    if left != right {
207                        return false;
208                    }
209                }
210                true
211            },
212
213            _ => false,
214        }
215    }
216}
217impl std::fmt::Debug for ddwaf_object {
218    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219        let mut dbg = f.debug_struct("ddwaf_object");
220        let dbg = match usize::try_from(self.parameterNameLength) {
221            Ok(0) => &mut dbg,
222            Ok(len) => {
223                let key = unsafe { slice::from_raw_parts(self.parameterName.cast(), len) };
224                let key = String::from_utf8_lossy(key);
225                dbg.field("parameterName", &key)
226            }
227            Err(_) => {
228                let key = unsafe { slice::from_raw_parts(self.parameterName.cast(), usize::MAX) };
229                let key = String::from_utf8_lossy(key);
230                dbg.field("parameterName(trunc)", &key)
231            }
232        };
233        let dbg = match self.type_ {
234            DDWAF_OBJ_BOOL => dbg
235                .field("type", &stringify!(DDWAF_OBJ_BOOL))
236                .field("boolean", unsafe { &self.__bindgen_anon_1.boolean }),
237            DDWAF_OBJ_FLOAT => dbg
238                .field("type", &stringify!(DDWAF_OBJ_FLOAT))
239                .field("f64", unsafe { &self.__bindgen_anon_1.f64_ }),
240            DDWAF_OBJ_SIGNED => dbg
241                .field("type", &stringify!(DDWAF_OBJ_SIGNED))
242                .field("int", unsafe { &self.__bindgen_anon_1.intValue }),
243            DDWAF_OBJ_UNSIGNED => dbg
244                .field("type", &stringify!(DDWAF_OBJ_UNSIGNED))
245                .field("uint", unsafe { &self.__bindgen_anon_1.uintValue }),
246            DDWAF_OBJ_STRING => {
247                let (field, len) = match usize::try_from(self.nbEntries) {
248                    Ok(len) => ("string", len),
249                    Err(_) => ("string(trunc)", usize::MAX),
250                };
251                let sval =
252                    unsafe { slice::from_raw_parts(self.__bindgen_anon_1.stringValue.cast(), len) };
253                let sval = String::from_utf8_lossy(sval);
254                dbg.field("type", &stringify!(DDWAF_OBJ_STRING))
255                    .field(field, &sval)
256            }
257            DDWAF_OBJ_ARRAY => {
258                let (field, len) = match usize::try_from(self.nbEntries) {
259                    Ok(len) => ("array", len),
260                    Err(_) => ("array(trunc)", usize::MAX),
261                };
262                let array: &[ddwaf_object] =
263                    unsafe { slice::from_raw_parts(self.__bindgen_anon_1.array.cast(), len) };
264                dbg.field("type", &stringify!(DDWAF_OBJ_ARRAY))
265                    .field(field, &array)
266            }
267            DDWAF_OBJ_MAP => {
268                let (field, len) = match usize::try_from(self.nbEntries) {
269                    Ok(len) => ("map", len),
270                    Err(_) => ("map(trunc)", usize::MAX),
271                };
272                let array: &[ddwaf_object] =
273                    unsafe { slice::from_raw_parts(self.__bindgen_anon_1.array.cast(), len) };
274                dbg.field("type", &stringify!(DDWAF_OBJ_MAP))
275                    .field(field, &array)
276            }
277            DDWAF_OBJ_NULL => dbg.field("type", &stringify!(DDWAF_OBJ_NULL)),
278            DDWAF_OBJ_INVALID => dbg.field("type", &stringify!(DDWAF_OBJ_INVALID)),
279            unknown => dbg.field("type", &unknown),
280        };
281
282        dbg.finish_non_exhaustive()
283    }
284}