1#![doc = "Data model for exchanging data with the in-app WAF."]
2
3use std::alloc::Layout;
4use std::mem::ManuallyDrop;
5use std::ops::{Deref, DerefMut, Index, IndexMut};
6use std::ptr::null_mut;
7use std::sync::OnceLock;
8use std::{cmp, fmt};
9
10mod iter;
11#[doc(inline)]
12pub use iter::*;
13
14#[non_exhaustive]
16#[derive(Copy, Clone, Debug, PartialEq, Eq)]
17pub enum WafObjectType {
18 Invalid,
21 Signed,
23 Unsigned,
25 String,
27 Array,
29 Map,
31 Bool,
33 Float,
35 Null,
37}
38impl WafObjectType {
39 const fn as_raw(self) -> libddwaf_sys::DDWAF_OBJ_TYPE {
41 match self {
42 WafObjectType::Invalid => libddwaf_sys::DDWAF_OBJ_INVALID,
43 WafObjectType::Signed => libddwaf_sys::DDWAF_OBJ_SIGNED,
44 WafObjectType::Unsigned => libddwaf_sys::DDWAF_OBJ_UNSIGNED,
45 WafObjectType::String => libddwaf_sys::DDWAF_OBJ_STRING,
46 WafObjectType::Array => libddwaf_sys::DDWAF_OBJ_ARRAY,
47 WafObjectType::Map => libddwaf_sys::DDWAF_OBJ_MAP,
48 WafObjectType::Bool => libddwaf_sys::DDWAF_OBJ_BOOL,
49 WafObjectType::Float => libddwaf_sys::DDWAF_OBJ_FLOAT,
50 WafObjectType::Null => libddwaf_sys::DDWAF_OBJ_NULL,
51 }
52 }
53}
54impl TryFrom<libddwaf_sys::DDWAF_OBJ_TYPE> for WafObjectType {
55 type Error = UnknownObjectTypeError;
56 fn try_from(value: libddwaf_sys::DDWAF_OBJ_TYPE) -> Result<Self, UnknownObjectTypeError> {
57 match value {
58 libddwaf_sys::DDWAF_OBJ_INVALID => Ok(WafObjectType::Invalid),
59 libddwaf_sys::DDWAF_OBJ_SIGNED => Ok(WafObjectType::Signed),
60 libddwaf_sys::DDWAF_OBJ_UNSIGNED => Ok(WafObjectType::Unsigned),
61 libddwaf_sys::DDWAF_OBJ_STRING
62 | libddwaf_sys::DDWAF_OBJ_LITERAL_STRING
63 | libddwaf_sys::DDWAF_OBJ_SMALL_STRING => Ok(WafObjectType::String),
64 libddwaf_sys::DDWAF_OBJ_ARRAY => Ok(WafObjectType::Array),
65 libddwaf_sys::DDWAF_OBJ_MAP => Ok(WafObjectType::Map),
66 libddwaf_sys::DDWAF_OBJ_BOOL => Ok(WafObjectType::Bool),
67 libddwaf_sys::DDWAF_OBJ_FLOAT => Ok(WafObjectType::Float),
68 libddwaf_sys::DDWAF_OBJ_NULL => Ok(WafObjectType::Null),
69 unknown => Err(UnknownObjectTypeError(unknown)),
70 }
71 }
72}
73
74#[derive(Copy, Clone, Debug)]
76pub struct UnknownObjectTypeError(libddwaf_sys::DDWAF_OBJ_TYPE);
77impl std::error::Error for UnknownObjectTypeError {}
78impl std::fmt::Display for UnknownObjectTypeError {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(f, "Unknown object type: {:?}", self.0)
81 }
82}
83
84#[derive(Copy, Clone, Debug)]
86pub struct ObjectTypeError {
87 pub expected: WafObjectType,
88 pub actual: WafObjectType,
89}
90impl std::error::Error for ObjectTypeError {}
91impl std::fmt::Display for ObjectTypeError {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 write!(
94 f,
95 "Invalid object type (expected {:?}, got {:?})",
96 self.expected, self.actual
97 )
98 }
99}
100
101#[derive(Copy, Clone, Debug)]
105pub struct LengthTooLargeError {
106 pub length: usize,
108 pub max_length: usize,
110}
111impl std::error::Error for LengthTooLargeError {}
112impl std::fmt::Display for LengthTooLargeError {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 write!(
115 f,
116 "Length {} exceeds maximum allowed {}",
117 self.length, self.max_length
118 )
119 }
120}
121
122#[doc(hidden)]
125pub trait AsRawMutObject: crate::private::Sealed + AsRef<libddwaf_sys::ddwaf_object> {
126 #[doc(hidden)]
141 unsafe fn as_raw_mut(&mut self) -> &mut libddwaf_sys::ddwaf_object;
142}
143
144pub trait TypedWafObject: AsRawMutObject {
147 const TYPE: WafObjectType;
150}
151
152#[derive(Default)]
156#[repr(transparent)]
157pub struct WafObject {
158 raw: libddwaf_sys::ddwaf_object,
159}
160impl WafObject {
161 pub fn from_json(json: impl AsRef<[u8]>) -> Option<WafOwnedOutputAllocator<Self>> {
171 let mut output = WafOwnedOutputAllocator::<Self>::default();
172 let data = json.as_ref();
173 let Ok(len) = u32::try_from(data.len()) else {
174 return None;
175 };
176 if !unsafe {
177 let alloc = WafOwnedOutputAllocator::<Self>::allocator();
178 libddwaf_sys::ddwaf_object_from_json(
179 output.as_raw_mut(),
180 data.as_ptr().cast(),
181 len,
182 alloc,
183 )
184 } {
185 return None;
186 }
187 Some(output)
188 }
189
190 #[must_use]
195 pub fn object_type(&self) -> WafObjectType {
196 self.as_ref()
197 .obj_type()
198 .try_into()
199 .unwrap_or(WafObjectType::Invalid)
200 }
201
202 #[must_use]
204 pub fn as_type<T: TypedWafObject>(&self) -> Option<&T> {
205 if self.object_type() == T::TYPE {
206 Some(unsafe { self.as_type_unchecked::<T>() })
207 } else {
208 None
209 }
210 }
211
212 pub(crate) unsafe fn as_type_unchecked<T: TypedWafObject>(&self) -> &T {
217 unsafe { self.as_ref().unchecked_as_ref::<T>() }
218 }
219
220 pub fn as_type_mut<T: TypedWafObject>(&mut self) -> Option<&mut T> {
222 if self.object_type() == T::TYPE {
223 Some(unsafe { self.as_raw_mut().unchecked_as_ref_mut::<T>() })
224 } else {
225 None
226 }
227 }
228
229 #[must_use]
232 pub fn is_valid(&self) -> bool {
233 self.object_type() != WafObjectType::Invalid
234 }
235
236 #[must_use]
238 pub fn to_u64(&self) -> Option<u64> {
239 self.as_type::<WafUnsigned>().map(WafUnsigned::value)
240 }
241
242 #[must_use]
245 pub fn to_i64(&self) -> Option<i64> {
246 match self.object_type() {
247 WafObjectType::Unsigned => {
248 let obj: &WafUnsigned = unsafe { self.as_type_unchecked() };
249 obj.value().try_into().ok()
250 }
251 WafObjectType::Signed => {
252 let obj: &WafSigned = unsafe { self.as_type_unchecked() };
253 Some(obj.value())
254 }
255 _ => None,
256 }
257 }
258
259 #[must_use]
261 pub fn to_f64(&self) -> Option<f64> {
262 self.as_type::<WafFloat>().map(WafFloat::value)
263 }
264
265 #[must_use]
267 pub fn to_bool(&self) -> Option<bool> {
268 self.as_type::<WafBool>().map(WafBool::value)
269 }
270
271 #[must_use]
274 pub fn to_str(&self) -> Option<&str> {
275 self.as_type::<WafString>().and_then(|x| x.as_str().ok())
276 }
277}
278impl AsRef<libddwaf_sys::ddwaf_object> for WafObject {
279 fn as_ref(&self) -> &libddwaf_sys::ddwaf_object {
280 &self.raw
281 }
282}
283impl AsRawMutObject for WafObject {
284 unsafe fn as_raw_mut(&mut self) -> &mut libddwaf_sys::ddwaf_object {
285 &mut self.raw
286 }
287}
288impl fmt::Debug for WafObject {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 match self.object_type() {
291 WafObjectType::Invalid => write!(f, "WafInvalid"),
292 WafObjectType::Unsigned => {
293 let obj: &WafUnsigned = self.as_type().unwrap();
294 obj.fmt(f)
295 }
296 WafObjectType::Signed => {
297 let obj: &WafSigned = self.as_type().unwrap();
298 obj.fmt(f)
299 }
300 WafObjectType::Float => {
301 let obj: &WafFloat = self.as_type().unwrap();
302 obj.fmt(f)
303 }
304 WafObjectType::Bool => {
305 let obj: &WafBool = self.as_type().unwrap();
306 obj.fmt(f)
307 }
308 WafObjectType::Null => {
309 let obj: &WafNull = self.as_type().unwrap();
310 obj.fmt(f)
311 }
312 WafObjectType::String => {
313 let obj: &WafString = self.as_type().unwrap();
314 obj.fmt(f)
315 }
316 WafObjectType::Array => {
317 let obj: &WafArray = self.as_type().unwrap();
318 obj.fmt(f)
319 }
320 WafObjectType::Map => {
321 let obj: &WafMap = self.as_type().unwrap();
322 obj.fmt(f)
323 }
324 }
325 }
326}
327impl Drop for WafObject {
328 fn drop(&mut self) {
329 unsafe { self.raw.drop_object() }
330 }
331}
332impl Clone for WafObject {
333 fn clone(&self) -> Self {
334 match self.object_type() {
335 WafObjectType::Invalid => {
336 let obj: &WafInvalid = unsafe { self.as_type_unchecked() };
337 (*obj).into()
338 }
339 WafObjectType::Signed => {
340 let obj: &WafSigned = unsafe { self.as_type_unchecked() };
341 (*obj).into()
342 }
343 WafObjectType::Unsigned => {
344 let obj: &WafUnsigned = unsafe { self.as_type_unchecked() };
345 (*obj).into()
346 }
347 WafObjectType::Bool => {
348 let obj: &WafBool = unsafe { self.as_type_unchecked() };
349 (*obj).into()
350 }
351 WafObjectType::Float => {
352 let obj: &WafFloat = unsafe { self.as_type_unchecked() };
353 (*obj).into()
354 }
355 WafObjectType::Null => {
356 let obj: &WafNull = unsafe { self.as_type_unchecked() };
357 (*obj).into()
358 }
359 WafObjectType::String => {
360 let obj: &WafString = unsafe { self.as_type_unchecked() };
361 obj.clone().into()
362 }
363 WafObjectType::Array => {
364 let obj: &WafArray = unsafe { self.as_type_unchecked() };
365 obj.clone().into()
366 }
367 WafObjectType::Map => {
368 let obj: &WafMap = unsafe { self.as_type_unchecked() };
369 obj.clone().into()
370 }
371 }
372 }
373}
374impl From<u64> for WafObject {
375 fn from(value: u64) -> Self {
376 WafUnsigned::new(value).into()
377 }
378}
379impl From<u32> for WafObject {
380 fn from(value: u32) -> Self {
381 WafUnsigned::new(value.into()).into()
382 }
383}
384impl From<i64> for WafObject {
385 fn from(value: i64) -> Self {
386 WafSigned::new(value).into()
387 }
388}
389impl From<i32> for WafObject {
390 fn from(value: i32) -> Self {
391 WafSigned::new(value.into()).into()
392 }
393}
394impl From<f64> for WafObject {
395 fn from(value: f64) -> Self {
396 WafFloat::new(value).into()
397 }
398}
399impl From<bool> for WafObject {
400 fn from(value: bool) -> Self {
401 WafBool::new(value).into()
402 }
403}
404impl From<&str> for WafObject {
405 fn from(value: &str) -> Self {
406 value.as_bytes().into()
407 }
408}
409impl From<&[u8]> for WafObject {
410 fn from(value: &[u8]) -> Self {
411 WafString::from(value).into()
412 }
413}
414impl From<()> for WafObject {
415 fn from((): ()) -> Self {
416 WafNull::new().into()
417 }
418}
419impl<T: TypedWafObject> From<T> for WafObject {
420 fn from(value: T) -> Self {
421 let res = Self {
422 raw: *value.as_ref(),
423 };
424 std::mem::forget(value);
425 res
426 }
427}
428impl<T: AsRef<libddwaf_sys::ddwaf_object>> cmp::PartialEq<T> for WafObject {
429 fn eq(&self, other: &T) -> bool {
430 self.raw == *other.as_ref()
431 }
432}
433impl crate::private::Sealed for WafObject {}
434
435pub trait AllocatorType: 'static {
437 fn allocator() -> libddwaf_sys::ddwaf_allocator;
439}
440
441pub struct LibddwafDefaultAllocator;
443impl AllocatorType for LibddwafDefaultAllocator {
444 fn allocator() -> libddwaf_sys::ddwaf_allocator {
445 unsafe { libddwaf_sys::ddwaf_get_default_allocator() }
446 }
447}
448
449pub struct RustAllocator;
451impl AllocatorType for RustAllocator {
452 fn allocator() -> libddwaf_sys::ddwaf_allocator {
453 get_default_allocator().into()
454 }
455}
456
457#[repr(transparent)]
462pub struct WafOwned<T: AsRawMutObject, A: AllocatorType = RustAllocator> {
463 inner: std::mem::ManuallyDrop<T>,
464 _phantom: std::marker::PhantomData<A>,
465}
466impl<T: AsRawMutObject, A: AllocatorType> WafOwned<T, A> {
467 pub(crate) fn allocator() -> libddwaf_sys::ddwaf_allocator {
468 A::allocator()
469 }
470}
471
472impl<T: AsRawMutObject + fmt::Debug, A: AllocatorType> fmt::Debug for WafOwned<T, A> {
473 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
474 self.inner.deref().fmt(f)
475 }
476}
477impl<T: AsRawMutObject + Default, A: AllocatorType> Default for WafOwned<T, A> {
478 fn default() -> Self {
479 Self {
480 inner: std::mem::ManuallyDrop::new(Default::default()),
481 _phantom: std::marker::PhantomData,
482 }
483 }
484}
485impl<T: AsRawMutObject, A: AllocatorType> Deref for WafOwned<T, A> {
486 type Target = T;
487 fn deref(&self) -> &Self::Target {
488 &self.inner
489 }
490}
491impl<T: AsRawMutObject, A: AllocatorType> DerefMut for WafOwned<T, A> {
492 fn deref_mut(&mut self) -> &mut Self::Target {
493 &mut self.inner
494 }
495}
496impl<T: AsRawMutObject, A: AllocatorType> Drop for WafOwned<T, A> {
497 fn drop(&mut self) {
498 unsafe {
499 libddwaf_sys::ddwaf_object_destroy(self.inner.as_raw_mut(), A::allocator());
500 }
501 }
502}
503impl<T: AsRawMutObject, A: AllocatorType> PartialEq<T> for WafOwned<T, A>
504where
505 T: PartialEq<T>,
506{
507 fn eq(&self, other: &T) -> bool {
508 *self.inner == *other
509 }
510}
511
512pub type WafOwnedDefaultAllocator<T> = WafOwned<T, LibddwafDefaultAllocator>;
514
515pub type WafOwnedOutputAllocator<T> = WafOwned<T, RustAllocator>;
517
518unsafe fn no_fail_alloc(layout: Layout) -> *mut u8 {
524 if layout.size() == 0 {
525 return null_mut();
526 }
527 let ptr = unsafe { std::alloc::alloc(layout) };
528 if ptr.is_null() {
529 std::alloc::handle_alloc_error(layout);
530 }
531 ptr
532}
533
534macro_rules! typed_object {
535 (@defaults $type:expr, $name:ident) => {
536 #[doc = concat!("Returns true if this [", stringify!($name), "] is indeed [", stringify!($type), "].")]
537 #[must_use]
538 pub fn is_valid(&self) -> bool {
539 self.raw.obj_type() == $type.as_raw()
540 }
541 };
542 (@defaults $type:expr, $name:ident, $($is_valid:tt)*) => {
543 #[doc = concat!("Returns true if this [", stringify!($name), "] is indeed [", stringify!($type), "].")]
544 #[must_use]
545 $($is_valid)*
546 };
547 ($type:expr => $name:ident $(derive($($derives:ident),* $(,)?))? $(is_valid { $($is_valid:tt)* })? $({ $($impl:tt)* })?) => {
548 #[doc = concat!("The WAF object representation of a value of type [", stringify!($type), "]")]
549 #[repr(transparent)]
550 $(#[derive($($derives),*)] )?
551 pub struct $name {
552 raw: libddwaf_sys::ddwaf_object,
553 }
554 impl $name {
555 typed_object!(@defaults $type, $name $(, $($is_valid)*)?);
556
557 #[must_use]
559 pub fn as_object(&self) -> &WafObject{
560 let obj: &libddwaf_sys::ddwaf_object = self.as_ref();
561 obj.as_object_ref()
562 }
563 $(
564 $($impl)*)?
565 }
566 impl AsRef<libddwaf_sys::ddwaf_object> for $name {
567 fn as_ref(&self) -> &libddwaf_sys::ddwaf_object {
568 &self.raw
569 }
570 }
571 impl AsRawMutObject for $name {
572 unsafe fn as_raw_mut(&mut self) -> &mut libddwaf_sys::ddwaf_object {
573 &mut self.raw
574 }
575 }
576 impl Default for $name {
577 #[allow(clippy::cast_possible_truncation)]
578 fn default() -> Self {
579 let mut raw: libddwaf_sys::ddwaf_object = unsafe { std::mem::zeroed() };
581 raw.type_ = $type.as_raw() as u8;
582 Self { raw }
583 }
584 }
585 impl TryFrom<WafObject> for $name {
586 type Error = ObjectTypeError;
587 fn try_from(obj: WafObject) -> Result<Self, Self::Error> {
588 if obj.object_type() != Self::TYPE {
589 return Err(ObjectTypeError {
590 expected: $type,
591 actual: obj.object_type(),
592 });
593 }
594 let res = Self { raw: obj.raw };
595 std::mem::forget(obj);
596 Ok(res)
597 }
598 }
599 impl<T: AsRef<libddwaf_sys::ddwaf_object>> cmp::PartialEq<T> for $name {
600 fn eq(&self, other: &T) -> bool {
601 self.raw == *other.as_ref()
602 }
603 }
604 impl crate::private::Sealed for $name {}
605 impl TypedWafObject for $name {
606 const TYPE: WafObjectType = $type;
607 }
608 };
609}
610
611typed_object!(WafObjectType::Invalid => WafInvalid derive(Copy, Clone));
612
613typed_object!(WafObjectType::Signed => WafSigned derive(Copy, Clone) {
614 #[must_use]
616 #[allow(clippy::cast_possible_truncation)]
617 pub const fn new(val: i64) -> Self {
618 Self {
619 raw: libddwaf_sys::ddwaf_object {
620 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
621 i64_: libddwaf_sys::_ddwaf_object_signed {
622 type_: libddwaf_sys::DDWAF_OBJ_SIGNED as u8,
623 val,
624 },
625 },
626 }
627 }
628 }
629
630 #[must_use]
632 pub const fn value(&self) -> i64 {
633 unsafe { self.raw.via.i64_.val }
634 }
635});
636
637typed_object!(WafObjectType::Unsigned => WafUnsigned derive(Copy, Clone) {
638 #[must_use]
640 #[allow(clippy::cast_possible_truncation)]
641 pub const fn new(val: u64) -> Self {
642 Self {
643 raw: libddwaf_sys::ddwaf_object {
644 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
645 u64_: libddwaf_sys::_ddwaf_object_unsigned {
646 type_: libddwaf_sys::DDWAF_OBJ_UNSIGNED as u8,
647 val,
648 },
649 },
650 }
651 }
652 }
653
654 #[must_use]
656 pub const fn value(&self) -> u64 {
657 unsafe { self.raw.via.u64_.val }
658 }
659});
660
661typed_object!(WafObjectType::String => WafString
662 is_valid {
663 pub fn is_valid(&self) -> bool {
664 self.raw.obj_type() & libddwaf_sys::DDWAF_OBJ_STRING != 0
665 }
666 }
667 {
668 #[allow(clippy::cast_possible_truncation, clippy::items_after_statements)]
674 pub fn new(val: impl AsRef<[u8]>) -> Option<Self> {
675 let val = val.as_ref();
676 if val.len() > (u32::MAX as usize) {
677 return None;
678 }
679
680 const SMALL_STRING_SIZE: usize = 14;
681
682 if val.len() <= SMALL_STRING_SIZE {
683 let mut ss = libddwaf_sys::_ddwaf_object_small_string {
684 type_: libddwaf_sys::DDWAF_OBJ_SMALL_STRING as u8,
685 size: val.len() as u8,
686 data: [0; 14],
687 };
688 let valcast = unsafe {
689 std::slice::from_raw_parts(val.as_ptr().cast(), val.len())
690 };
691 ss.data[..valcast.len()].copy_from_slice(valcast);
692
693 return Some(Self {
694 raw: libddwaf_sys::ddwaf_object {
695 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
696 sstr: ss,
697 },
698 },
699 })
700 }
701
702 let ptr: *mut ::std::os::raw::c_char = if val.is_empty() {
703 null_mut()
704 } else {
705 unsafe { no_fail_alloc(Layout::array::<::std::os::raw::c_char>(val.len()).unwrap()).cast() }
706 };
707 unsafe {
708 std::ptr::copy_nonoverlapping(val.as_ptr(), ptr.cast(), val.len());
709 }
710 Some(Self {
711 raw: libddwaf_sys::ddwaf_object {
712 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
713 str_: libddwaf_sys::_ddwaf_object_string {
714 type_: libddwaf_sys::DDWAF_OBJ_STRING as u8,
715 size: val.len() as u32,
716 ptr,
717 },
718 },
719 },
720 })
721 }
722
723 #[allow(clippy::cast_possible_truncation)]
728 pub fn new_literal(val: impl Into<&'static [u8]>) -> Self {
729 let val = val.into();
730 let len = u32::try_from(val.len()).expect("string is too large for this platform");
731
732 Self {
733 raw: libddwaf_sys::ddwaf_object {
734 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
735 str_: libddwaf_sys::_ddwaf_object_string {
736 type_: libddwaf_sys::DDWAF_OBJ_LITERAL_STRING as u8,
737 size: len,
738 ptr: val.as_ptr() as *mut _,
739 },
740 },
741 },
742 }
743
744 }
745
746 #[must_use]
748 pub fn len(&self) -> u32 {
749 if self.raw.obj_type() == libddwaf_sys::DDWAF_OBJ_SMALL_STRING {
750 u32::from(unsafe { self.raw.via.sstr.size })
751 } else {
752 unsafe { self.raw.via.str_.size }
753 }
754 }
755
756 #[must_use]
758 pub fn is_empty(&self) -> bool {
759 self.len() == 0u32
760 }
761
762 #[must_use]
764 #[allow(clippy::cast_possible_truncation)]
765 pub fn as_bytes(&self) -> &[u8] {
766 debug_assert!(self.is_valid());
767 let len = self.len();
768 if len == 0 {
769 return &[];
770 }
771
772 if self.raw.obj_type() == libddwaf_sys::DDWAF_OBJ_SMALL_STRING {
773 unsafe {
774 std::slice::from_raw_parts(
775 self.raw.via.sstr.data.as_ptr().cast(),
776 len as usize,
777 )
778 }
779 } else {
780 debug_assert!(!unsafe{ self.raw.via.str_.ptr }.is_null());
781 unsafe {
782 std::slice::from_raw_parts(
783 self.raw.via.str_.ptr.cast(),
784 len as usize,
785 )
786 }
787 }
788 }
789
790 pub fn as_str(&self) -> Result<&str, std::str::Utf8Error> {
796 std::str::from_utf8(self.as_bytes())
797 }
798});
799typed_object!(WafObjectType::Array => WafArray {
800 #[must_use]
806 pub fn new(nb_entries: u16) -> Self {
807 let size = usize::from(nb_entries);
808 let layout = Layout::array::<libddwaf_sys::ddwaf_object>(size).unwrap();
809 let ptr = unsafe { no_fail_alloc(layout).cast() };
810 unsafe { std::ptr::write_bytes(ptr, 0, size)};
811 Self {
812 raw: libddwaf_sys::ddwaf_object {
813 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
814 array: libddwaf_sys::_ddwaf_object_array {
815 #[allow(clippy::cast_possible_truncation)]
816 type_: libddwaf_sys::DDWAF_OBJ_ARRAY as u8,
817 size: nb_entries,
818 capacity: nb_entries,
819 ptr,
820 },
821 },
822 }
823 }
824 }
825
826 #[must_use]
828 pub const fn len(&self) -> u16 {
829 unsafe { self.raw.via.array.size }
830 }
831
832 #[must_use]
834 pub const fn is_empty(&self) -> bool {
835 self.len() == 0
836 }
837
838 #[must_use]
843 pub const fn capacity(&self) -> u16 {
844 unsafe { self.raw.via.array.capacity }
845 }
846
847 pub fn truncate(&mut self, new_size: u16) {
854 if new_size > self.len() {
855 return;
856 }
857 let arr: *mut WafObject = unsafe { self.raw.via.array.ptr.cast() };
858 for i in new_size..self.len() {
859 unsafe {
860 std::ptr::drop_in_place(arr.add(i as usize));
861 }
862 }
863 self.raw.via.array.size = new_size;
864 }
865
866 pub fn iter(&self) -> impl Iterator<Item = &WafObject> {
868 let slice : &[WafObject] = self.as_ref();
869 slice.iter()
870 }
871
872 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut WafObject> {
874 let slice : &mut [WafObject] = AsMut::as_mut(self);
875 slice.iter_mut()
876 }
877});
878typed_object!(WafObjectType::Map => WafMap {
879 #[must_use]
885 pub fn new(nb_entries: u16) -> Self {
886 let size = usize::from(nb_entries);
887 let layout = Layout::array::<libddwaf_sys::_ddwaf_object_kv>(size).unwrap();
888 let ptr = unsafe { no_fail_alloc(layout).cast() };
889 unsafe { std::ptr::write_bytes(ptr, 0, size)};
890 Self {
891 raw: libddwaf_sys::ddwaf_object {
892 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
893 map: libddwaf_sys::_ddwaf_object_map {
894 #[allow(clippy::cast_possible_truncation)]
895 type_: libddwaf_sys::DDWAF_OBJ_MAP as u8,
896 size: nb_entries,
897 capacity: nb_entries,
898 ptr,
899 },
900 },
901 }
902 }
903 }
904
905 #[must_use]
907 pub const fn len(&self) -> u16 {
908 unsafe { self.raw.via.map.size }
909 }
910
911 #[must_use]
913 pub const fn is_empty(&self) -> bool {
914 self.len() == 0
915 }
916
917 #[must_use]
922 pub const fn capacity(&self) -> u16 {
923 unsafe { self.raw.via.map.capacity }
924 }
925
926 pub fn truncate(&mut self, new_size: u16) {
933 if new_size > self.len() {
934 return;
935 }
936 let entries: *mut Keyed<WafObject> = unsafe { self.raw.via.map.ptr.cast() };
937 for i in new_size..self.len() {
938 unsafe {
939 std::ptr::drop_in_place(entries.add(i as usize));
940 }
941 }
942 self.raw.via.map.size = new_size;
943 }
944
945 pub fn iter(&self) -> impl Iterator<Item = &Keyed<WafObject>> {
947 let slice : &[Keyed<WafObject>] = self.as_ref();
948 slice.iter()
949 }
950
951 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Keyed<WafObject>> {
953 let slice : &mut [Keyed<WafObject>] = AsMut::as_mut(self);
954 slice.iter_mut()
955 }
956
957 #[must_use]
961 pub fn get(&self, key: impl AsRef<libddwaf_sys::ddwaf_object>) -> Option<&Keyed<WafObject>> {
962 let key = key.as_ref();
963 self.iter().find(|o| o.key().raw.eq(key))
964 }
965
966 #[must_use]
970 pub fn get_bstr(&self, key: &'_ [u8]) -> Option<&Keyed<WafObject>> {
971 self.iter().find(|o| {
972 match o.key().as_type::<WafString>() {
973 Some(s) => s.as_bytes() == key,
974 None => false,
975 }
976 })
977 }
978
979 pub fn get_mut(&mut self, key: &'_ [u8]) -> Option<&mut Keyed<WafObject>> {
983 self.iter_mut().find(|o| {
984 match o.key().as_type::<WafString>() {
985 Some(s) => s.as_bytes() == key,
986 None => false
987 }
988 })
989 }
990
991 #[must_use]
993 pub fn get_str(&self, key: &'_ str) -> Option<&Keyed<WafObject>> {
994 self.get_bstr(key.as_bytes())
995 }
996
997 pub fn get_str_mut(&mut self, key: &'_ str) -> Option<&mut Keyed<WafObject>> {
999 self.get_mut(key.as_bytes())
1000 }
1001});
1002typed_object!(WafObjectType::Bool => WafBool derive(Copy, Clone) {
1003 #[must_use]
1005 pub const fn new(val: bool) -> Self {
1006 Self {
1007 raw: libddwaf_sys::ddwaf_object {
1008 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
1009 b8: libddwaf_sys::_ddwaf_object_bool {
1010 #[allow(clippy::cast_possible_truncation)]
1011 type_: libddwaf_sys::DDWAF_OBJ_BOOL as u8,
1012 val,
1013 },
1014 },
1015 }
1016 }
1017 }
1018
1019 #[must_use]
1021 pub const fn value(&self) -> bool {
1022 unsafe { self.raw.via.b8.val }
1023 }
1024});
1025
1026typed_object!(WafObjectType::Float => WafFloat derive(Copy, Clone) {
1027 #[must_use]
1029 pub const fn new(val: f64) -> Self {
1030 Self {
1031 raw: libddwaf_sys::ddwaf_object {
1032 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
1033 f64_: libddwaf_sys::_ddwaf_object_float {
1034 #[allow(clippy::cast_possible_truncation)]
1035 type_: libddwaf_sys::DDWAF_OBJ_FLOAT as u8,
1036 val,
1037 },
1038 },
1039 }
1040 }
1041 }
1042
1043 #[must_use]
1045 pub const fn value(&self) -> f64 {
1046 unsafe { self.raw.via.f64_.val }
1047 }
1048});
1049
1050typed_object!(WafObjectType::Null => WafNull derive(Copy, Clone) {
1051 #[must_use]
1053 pub const fn new() -> Self {
1054 Self {
1055 raw: libddwaf_sys::ddwaf_object {
1056 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
1057 u64_: libddwaf_sys::_ddwaf_object_unsigned {
1058 #[allow(clippy::cast_possible_truncation)]
1059 type_: libddwaf_sys::DDWAF_OBJ_NULL as u8,
1060 val: 0,
1061 },
1062 },
1063 }
1064 }
1065 }
1066}
1067);
1068
1069impl fmt::Debug for WafSigned {
1070 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1071 write!(f, "{}({})", stringify!(WafSigned), self.value())
1072 }
1073}
1074impl From<i64> for WafSigned {
1075 fn from(value: i64) -> Self {
1076 Self::new(value)
1077 }
1078}
1079impl From<i32> for WafSigned {
1080 fn from(value: i32) -> Self {
1081 Self::new(value.into())
1082 }
1083}
1084
1085impl fmt::Debug for WafUnsigned {
1086 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1087 write!(f, "{}({})", stringify!(WafUnsigned), self.value())
1088 }
1089}
1090impl From<u64> for WafUnsigned {
1091 fn from(value: u64) -> Self {
1092 Self::new(value)
1093 }
1094}
1095impl From<u32> for WafUnsigned {
1096 fn from(value: u32) -> Self {
1097 Self::new(value.into())
1098 }
1099}
1100
1101impl<T: AsRef<[u8]>> From<T> for WafString {
1102 fn from(val: T) -> Self {
1103 let slice = val.as_ref();
1104 let slice = &slice[..slice.len().min(u32::MAX as usize)];
1105 Self::new(slice).unwrap()
1106 }
1107}
1108impl fmt::Debug for WafString {
1109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1110 write!(
1111 f,
1112 "{}(\"{:?}\")",
1113 stringify!(WafString),
1114 fmt_bin_str(self.as_bytes())
1115 )
1116 }
1117}
1118impl Drop for WafString {
1119 fn drop(&mut self) {
1120 if self.raw.obj_type() == libddwaf_sys::DDWAF_OBJ_STRING {
1123 unsafe { self.raw.drop_string() }
1124 }
1125 }
1126}
1127impl Clone for WafString {
1128 fn clone(&self) -> Self {
1129 if self.raw.obj_type() == libddwaf_sys::DDWAF_OBJ_STRING {
1130 let len = self.len();
1131 let layout = Layout::array::<std::os::raw::c_char>(len as usize).unwrap();
1132 let copied = unsafe { no_fail_alloc(layout).cast::<std::os::raw::c_char>() };
1133 unsafe {
1134 std::ptr::copy_nonoverlapping(
1135 self.as_bytes().as_ptr().cast(),
1136 copied,
1137 len as usize,
1138 );
1139 }
1140 return Self {
1141 raw: libddwaf_sys::ddwaf_object {
1142 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
1143 str_: libddwaf_sys::_ddwaf_object_string {
1144 #[allow(clippy::cast_possible_truncation)]
1145 type_: libddwaf_sys::DDWAF_OBJ_STRING as u8,
1146 size: len,
1147 ptr: copied,
1148 },
1149 },
1150 },
1151 };
1152 }
1153
1154 Self { raw: self.raw }
1156 }
1157}
1158
1159impl AsRef<[WafObject]> for WafArray {
1160 fn as_ref(&self) -> &[WafObject] {
1161 if self.is_empty() {
1162 return &[];
1163 }
1164 let array = unsafe { self.raw.via.array.ptr.cast() };
1165 unsafe { std::slice::from_raw_parts(array, self.len() as usize) }
1166 }
1167}
1168impl AsMut<[WafObject]> for WafArray {
1169 fn as_mut(&mut self) -> &mut [WafObject] {
1170 if self.is_empty() {
1171 return &mut [];
1172 }
1173 let array = unsafe { self.raw.via.array.ptr.cast() };
1174 unsafe { std::slice::from_raw_parts_mut(array, self.len() as usize) }
1175 }
1176}
1177impl fmt::Debug for WafArray {
1178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1179 write!(f, "{}[", stringify!(WafArray))?;
1180 let mut first = true;
1181 for obj in self.iter() {
1182 if first {
1183 first = false;
1184 } else {
1185 write!(f, ", ")?;
1186 }
1187 write!(f, "{obj:?}")?;
1188 }
1189 write!(f, "]")
1190 }
1191}
1192impl Drop for WafArray {
1193 fn drop(&mut self) {
1194 unsafe { self.raw.drop_array() }
1195 }
1196}
1197impl Clone for WafArray {
1198 fn clone(&self) -> Self {
1199 let size = self.len();
1200
1201 if size == 0 {
1202 return Self::new(0);
1203 }
1204
1205 let layout = Layout::array::<libddwaf_sys::ddwaf_object>(size as usize).unwrap();
1206 let new_arr: *mut libddwaf_sys::ddwaf_object = unsafe { no_fail_alloc(layout).cast() };
1207
1208 for i in 0..size {
1210 let src_elem: &WafObject = &self[i as usize];
1211 let cloned_elem = ManuallyDrop::new(src_elem.clone());
1212 unsafe { new_arr.add(i as usize).write(cloned_elem.raw) };
1213 }
1214
1215 Self {
1216 raw: libddwaf_sys::ddwaf_object {
1217 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
1218 array: libddwaf_sys::_ddwaf_object_array {
1219 #[allow(clippy::cast_possible_truncation)]
1220 type_: libddwaf_sys::DDWAF_OBJ_ARRAY as u8,
1221 size,
1222 capacity: size,
1223 ptr: new_arr,
1224 },
1225 },
1226 },
1227 }
1228 }
1229}
1230impl<T: Into<WafObject>, const N: usize> From<[T; N]> for WafArray {
1231 fn from(value: [T; N]) -> Self {
1232 let effective_length = N.min(u16::MAX as usize);
1233 #[allow(clippy::cast_possible_truncation)]
1234 let mut array = Self::new(effective_length as u16);
1235 for (i, obj) in value.into_iter().enumerate() {
1236 if i >= effective_length {
1237 break;
1238 }
1239 array[i] = obj.into();
1240 }
1241 array
1242 }
1243}
1244impl<T> From<&mut [T]> for WafArray
1245where
1246 T: Into<WafObject> + Default,
1247{
1248 fn from(value: &mut [T]) -> Self {
1249 let effective_length = value.len().min(u16::MAX as usize);
1250 #[allow(clippy::cast_possible_truncation)]
1251 let mut array = Self::new(effective_length as u16);
1252 for (i, obj) in value.iter_mut().enumerate() {
1253 if i >= effective_length {
1254 break;
1255 }
1256 let obj = std::mem::take(obj);
1257 array[i] = obj.into();
1258 }
1259 array
1260 }
1261}
1262impl Index<usize> for WafArray {
1263 type Output = WafObject;
1264 fn index(&self, index: usize) -> &Self::Output {
1265 let len = self.len() as usize;
1266 assert!(index < len, "index out of bounds ({index} >= {len})");
1267 let array = unsafe { self.raw.via.array.ptr };
1268 unsafe { &*(array.add(index) as *const _) }
1269 }
1270}
1271impl IndexMut<usize> for WafArray {
1272 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
1273 let len = self.len() as usize;
1274 assert!(index < len, "index out of bounds ({index} >= {len})");
1275 let array = unsafe { self.raw.via.array.ptr };
1276 unsafe { &mut *(array.add(index).cast()) }
1277 }
1278}
1279
1280impl AsRef<[Keyed<WafObject>]> for WafMap {
1281 fn as_ref(&self) -> &[Keyed<WafObject>] {
1282 if self.is_empty() {
1283 return &[];
1284 }
1285 let ptr = unsafe { self.raw.via.map.ptr as *const _ };
1286 unsafe { std::slice::from_raw_parts(ptr, self.len() as usize) }
1287 }
1288}
1289impl AsMut<[Keyed<WafObject>]> for WafMap {
1290 fn as_mut(&mut self) -> &mut [Keyed<WafObject>] {
1291 if self.is_empty() {
1292 return &mut [];
1293 }
1294 let ptr = unsafe { self.raw.via.map.ptr.cast() };
1295 unsafe { std::slice::from_raw_parts_mut(ptr, self.len() as usize) }
1296 }
1297}
1298impl fmt::Debug for WafMap {
1299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1300 write!(f, "{}{{", stringify!(WafMap))?;
1301 let mut first = true;
1302 for keyed_obj in self.iter() {
1303 if first {
1304 first = false;
1305 } else {
1306 write!(f, ", ")?;
1307 }
1308 write!(f, "{keyed_obj:?}")?;
1309 }
1310 write!(f, "}}")
1311 }
1312}
1313impl Drop for WafMap {
1314 fn drop(&mut self) {
1315 unsafe { self.raw.drop_map() }
1316 }
1317}
1318impl Clone for WafMap {
1319 fn clone(&self) -> Self {
1320 let size = self.len();
1321
1322 if size == 0 {
1323 return Self::new(0);
1324 }
1325
1326 let layout = Layout::array::<libddwaf_sys::_ddwaf_object_kv>(size as usize).unwrap();
1327 let new_ptr: *mut libddwaf_sys::_ddwaf_object_kv = unsafe { no_fail_alloc(layout).cast() };
1328 unsafe { std::ptr::write_bytes(new_ptr, 0, size as usize) };
1329
1330 for i in 0..size {
1332 let src_entry: &Keyed<WafObject> = &self[i as usize];
1333 let cloned_entry = ManuallyDrop::new(src_entry.clone());
1334 unsafe { new_ptr.add(i as usize).write(cloned_entry.raw) };
1335 }
1336
1337 Self {
1338 raw: libddwaf_sys::ddwaf_object {
1339 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
1340 map: libddwaf_sys::_ddwaf_object_map {
1341 #[allow(clippy::cast_possible_truncation)]
1342 type_: libddwaf_sys::DDWAF_OBJ_MAP as u8,
1343 size,
1344 capacity: size,
1345 ptr: new_ptr,
1346 },
1347 },
1348 },
1349 }
1350 }
1351}
1352impl Index<usize> for WafMap {
1353 type Output = Keyed<WafObject>;
1354 fn index(&self, index: usize) -> &Self::Output {
1355 let len = self.len() as usize;
1356 assert!(index < len, "index out of bounds ({index} >= {len})");
1357 let ptr = unsafe { self.raw.via.map.ptr };
1358 unsafe { &*ptr.add(index).cast() }
1359 }
1360}
1361impl IndexMut<usize> for WafMap {
1362 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
1363 let len = self.len() as usize;
1364 assert!(index < len, "index out of bounds ({index} >= {len})");
1365 let ptr = unsafe { self.raw.via.map.ptr };
1366 unsafe { &mut *ptr.add(index).cast() }
1367 }
1368}
1369impl<K: AsRef<[u8]>, V: Into<WafObject>, const N: usize> From<[(K, V); N]> for WafMap {
1370 fn from(vals: [(K, V); N]) -> Self {
1371 let effective_length = N.min(u16::MAX as usize);
1372 #[allow(clippy::cast_possible_truncation)]
1373 let mut map = WafMap::new(effective_length as u16);
1374 for (i, (k, v)) in vals.into_iter().enumerate() {
1375 if i >= effective_length {
1376 break;
1377 }
1378 map[i] = Keyed::from((k.as_ref(), v.into()));
1379 }
1380 map
1381 }
1382}
1383impl<V: Into<WafObject>, const N: usize> From<[(WafObject, V); N]> for WafMap {
1384 fn from(vals: [(WafObject, V); N]) -> Self {
1385 let effective_length = N.min(u16::MAX as usize);
1386 #[allow(clippy::cast_possible_truncation)]
1387 let mut map = WafMap::new(effective_length as u16);
1388 for (i, (k, v)) in vals.into_iter().enumerate() {
1389 if i >= effective_length {
1390 break;
1391 }
1392 map[i] = (k, v.into()).into();
1393 }
1394 map
1395 }
1396}
1397impl<K, V> From<&mut [(K, V)]> for WafMap
1398where
1399 K: Into<WafObject> + Default,
1400 V: Into<WafObject> + Default,
1401{
1402 fn from(value: &mut [(K, V)]) -> Self {
1403 let effective_length = value.len().min(u16::MAX as usize);
1404 #[allow(clippy::cast_possible_truncation)]
1405 let mut map = Self::new(effective_length as u16);
1406 for (i, (k, v)) in value.iter_mut().enumerate() {
1407 if i >= effective_length {
1408 break;
1409 }
1410 let k = std::mem::take(k);
1411 let v = std::mem::take(v);
1412 map[i] = (k.into(), v.into()).into();
1413 }
1414 map
1415 }
1416}
1417
1418impl fmt::Debug for WafBool {
1419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1420 write!(f, "{}({})", stringify!(WafBool), self.value())
1421 }
1422}
1423impl From<bool> for WafBool {
1424 fn from(value: bool) -> Self {
1425 Self::new(value)
1426 }
1427}
1428
1429impl fmt::Debug for WafFloat {
1430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1431 write!(f, "{}({})", stringify!(WafFloat), self.value())
1432 }
1433}
1434impl From<f64> for WafFloat {
1435 fn from(value: f64) -> Self {
1436 Self::new(value)
1437 }
1438}
1439
1440impl fmt::Debug for WafNull {
1441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1442 write!(f, "{}", stringify!(WafNull))
1443 }
1444}
1445impl From<()> for WafNull {
1446 fn from((): ()) -> Self {
1447 Self::new()
1448 }
1449}
1450
1451#[repr(transparent)]
1453pub struct Keyed<T: AsRawMutObject> {
1454 raw: libddwaf_sys::_ddwaf_object_kv,
1455 _marker: std::marker::PhantomData<T>,
1456}
1457impl<T: AsRawMutObject> Keyed<T> {
1458 pub fn new(key: impl Into<WafObject>, value: T) -> Self {
1460 let key = key.into();
1461 let val = *value.as_ref();
1462 let ret = Self {
1463 raw: libddwaf_sys::_ddwaf_object_kv { key: key.raw, val },
1464 _marker: std::marker::PhantomData,
1465 };
1466 std::mem::forget(key);
1467 std::mem::forget(value);
1468 ret
1469 }
1470
1471 #[must_use]
1473 pub fn key(&self) -> &WafObject {
1474 unsafe { self.raw.key.unchecked_as_ref() }
1475 }
1476
1477 #[must_use]
1479 pub fn key_mut(&mut self) -> &mut WafObject {
1480 unsafe { self.raw.key.unchecked_as_ref_mut() }
1481 }
1482
1483 #[must_use]
1485 pub fn value(&self) -> &T {
1486 unsafe { self.raw.val.unchecked_as_ref() }
1487 }
1488
1489 #[must_use]
1491 pub fn value_mut(&mut self) -> &mut T {
1492 unsafe { self.raw.val.unchecked_as_ref_mut() }
1493 }
1494
1495 #[allow(invalid_from_utf8)]
1501 pub fn key_str(&self) -> Result<&str, Box<dyn std::error::Error>> {
1502 std::str::from_utf8(self.key_bytes()?).map_err(std::convert::Into::into)
1503 }
1504
1505 pub fn key_bytes(&self) -> Result<&[u8], ObjectTypeError> {
1510 let key = self.key();
1511 match key.as_type::<WafString>() {
1512 Some(s) => Ok(s.as_bytes()),
1513 None => Err(ObjectTypeError {
1514 expected: WafObjectType::String,
1515 actual: key.object_type(),
1516 }),
1517 }
1518 }
1519}
1520impl Keyed<WafObject> {
1521 #[must_use]
1522 pub fn as_type<T: TypedWafObject>(&self) -> Option<&Keyed<T>> {
1523 if self.value().object_type() == T::TYPE {
1524 Some(unsafe { &*(std::ptr::from_ref(self).cast()) })
1525 } else {
1526 None
1527 }
1528 }
1529
1530 pub fn as_type_mut<T: TypedWafObject>(&mut self) -> Option<&mut Keyed<T>> {
1531 if self.value().object_type() == T::TYPE {
1532 Some(unsafe { &mut *(std::ptr::from_mut(self).cast()) })
1533 } else {
1534 None
1535 }
1536 }
1537}
1538impl Keyed<WafArray> {
1541 pub fn iter(&self) -> impl Iterator<Item = &WafObject> {
1542 self.value().iter()
1543 }
1544
1545 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut WafObject> {
1546 self.value_mut().iter_mut()
1547 }
1548}
1549impl Keyed<WafMap> {
1552 pub fn iter(&self) -> impl Iterator<Item = &Keyed<WafObject>> {
1553 self.value().iter()
1554 }
1555
1556 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Keyed<WafObject>> {
1557 self.value_mut().iter_mut()
1558 }
1559}
1560impl<T: AsRawMutObject> crate::private::Sealed for Keyed<T> {}
1566impl<T: AsRawMutObject> AsRef<libddwaf_sys::_ddwaf_object_kv> for Keyed<T> {
1567 fn as_ref(&self) -> &libddwaf_sys::_ddwaf_object_kv {
1568 &self.raw
1569 }
1570}
1571impl<T: Default + AsRawMutObject> std::default::Default for Keyed<T> {
1572 fn default() -> Self {
1573 let key = WafObject::default();
1574 let mut value = T::default();
1575 let ret = Self {
1576 raw: libddwaf_sys::_ddwaf_object_kv {
1577 key: key.raw,
1578 val: *unsafe { value.as_raw_mut() },
1579 },
1580 _marker: std::marker::PhantomData,
1581 };
1582 std::mem::forget(key);
1583 std::mem::forget(value);
1584 ret
1585 }
1586}
1587impl<T: AsRawMutObject> Deref for Keyed<T> {
1588 type Target = T;
1589 fn deref(&self) -> &Self::Target {
1590 self.value()
1591 }
1592}
1593impl<T: AsRawMutObject> std::ops::Drop for Keyed<T> {
1594 fn drop(&mut self) {
1595 unsafe { self.raw.key.drop_object() };
1596 unsafe { self.raw.val.drop_object() };
1597 }
1598}
1599impl<T: AsRawMutObject + fmt::Debug> fmt::Debug for Keyed<T> {
1600 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1601 let k = self.key();
1602 if k.object_type() == WafString::TYPE {
1603 write!(
1604 f,
1605 "\"{:?}\"={:?}",
1606 fmt_bin_str(unsafe { self.key().as_type_unchecked::<WafString>() }.as_bytes()),
1607 self.value()
1608 )
1609 } else {
1610 write!(f, "{:?}={:?}", k, self.value())
1611 }
1612 }
1613}
1614impl<T, U: AsRawMutObject> From<(&str, T)> for Keyed<U>
1615where
1616 T: Into<U>,
1617{
1618 fn from(value: (&str, T)) -> Self {
1619 (value.0.as_bytes(), value.1).into()
1620 }
1621}
1622impl<T, U: AsRawMutObject> From<(&[u8], T)> for Keyed<U>
1623where
1624 T: Into<U>,
1625{
1626 fn from(value: (&[u8], T)) -> Self {
1627 let key: WafObject = value.0.into();
1628 let value: U = value.1.into();
1629 Keyed::new(key, value)
1630 }
1631}
1632impl<T: TypedWafObject> From<Keyed<T>> for Keyed<WafObject> {
1633 fn from(value: Keyed<T>) -> Self {
1634 let res = Self {
1635 raw: value.raw,
1636 _marker: std::marker::PhantomData,
1637 };
1638 std::mem::forget(value);
1639 res
1640 }
1641}
1642impl From<(WafObject, WafObject)> for Keyed<WafObject> {
1643 fn from(value: (WafObject, WafObject)) -> Self {
1644 Keyed::new(value.0, value.1)
1645 }
1646}
1647impl<T: TypedWafObject> From<(WafObject, T)> for Keyed<T> {
1648 fn from(value: (WafObject, T)) -> Self {
1649 Keyed::new(value.0, value.1)
1650 }
1651}
1652impl<T: AsRawMutObject + Clone> Clone for Keyed<T> {
1653 fn clone(&self) -> Self {
1654 let cloned_key = self.key().clone();
1655 let cloned_value = self.value().clone();
1656
1657 let ret = Self {
1658 raw: libddwaf_sys::_ddwaf_object_kv {
1659 key: cloned_key.raw,
1660 val: *cloned_value.as_ref(),
1661 },
1662 _marker: std::marker::PhantomData,
1663 };
1664
1665 std::mem::forget(cloned_key);
1666 std::mem::forget(cloned_value);
1667 ret
1668 }
1669}
1670trait UncheckedAsRef: crate::private::Sealed {
1671 unsafe fn unchecked_as_ref<T: AsRef<libddwaf_sys::ddwaf_object> + crate::private::Sealed>(
1678 &self,
1679 ) -> &T;
1680
1681 unsafe fn unchecked_as_ref_mut<T: AsRef<libddwaf_sys::ddwaf_object> + crate::private::Sealed>(
1688 &mut self,
1689 ) -> &mut T;
1690}
1691impl crate::private::Sealed for libddwaf_sys::ddwaf_object {}
1692impl UncheckedAsRef for libddwaf_sys::ddwaf_object {
1693 unsafe fn unchecked_as_ref<T: AsRef<libddwaf_sys::ddwaf_object> + crate::private::Sealed>(
1694 &self,
1695 ) -> &T {
1696 unsafe { &*(std::ptr::from_ref(self).cast()) }
1697 }
1698
1699 unsafe fn unchecked_as_ref_mut<
1700 T: AsRef<libddwaf_sys::ddwaf_object> + crate::private::Sealed,
1701 >(
1702 &mut self,
1703 ) -> &mut T {
1704 unsafe { &mut *(std::ptr::from_mut(self).cast()) }
1705 }
1706}
1707trait UncheckedAsWafObject: crate::private::Sealed {
1708 fn as_object_ref(&self) -> &WafObject;
1710}
1711impl<T: UncheckedAsRef> UncheckedAsWafObject for T {
1712 fn as_object_ref(&self) -> &WafObject {
1714 unsafe { self.unchecked_as_ref::<WafObject>() }
1715 }
1716}
1717
1718fn fmt_bin_str(bytes: &[u8]) -> impl fmt::Debug + '_ {
1720 struct BinFormatter<'a>(&'a [u8]);
1721 impl fmt::Debug for BinFormatter<'_> {
1722 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1723 for &c in self.0 {
1724 if c == b'"' || c == b'\\' {
1725 write!(f, "\\{}", c as char)?;
1726 } else if c.is_ascii_graphic() || c == b' ' {
1727 write!(f, "{}", c as char)?;
1728 } else {
1729 write!(f, "\\x{c:02X}")?;
1730 }
1731 }
1732 Ok(())
1733 }
1734 }
1735 BinFormatter(bytes)
1736}
1737
1738pub(crate) struct RustDdwafAllocator {
1739 raw: libddwaf_sys::ddwaf_allocator,
1740}
1741impl RustDdwafAllocator {
1742 fn new() -> Option<Self> {
1743 let allocator = unsafe {
1744 libddwaf_sys::ddwaf_user_allocator_init(
1745 Some(Self::alloc_fn),
1746 Some(Self::free_fn),
1747 std::ptr::null_mut(),
1748 Option::None,
1749 )
1750 };
1751 if allocator.is_null() {
1752 None
1753 } else {
1754 Some(Self { raw: allocator })
1755 }
1756 }
1757 extern "C" fn alloc_fn(
1758 _udata: *mut ::std::os::raw::c_void,
1759 size: usize,
1760 alignment: usize,
1761 ) -> *mut ::std::os::raw::c_void {
1762 let layout = Layout::from_size_align(size, alignment);
1763 if let Ok(layout) = layout {
1764 unsafe { std::alloc::alloc(layout).cast() }
1765 } else {
1766 debug_assert!(false, "Invalid layout");
1767 std::ptr::null_mut()
1768 }
1769 }
1770
1771 extern "C" fn free_fn(
1772 _udata: *mut ::std::os::raw::c_void,
1773 ptr: *mut ::std::os::raw::c_void,
1774 size: usize,
1775 alignment: usize,
1776 ) {
1777 let layout = Layout::from_size_align(size, alignment);
1778 match layout {
1779 Ok(layout) => unsafe { std::alloc::dealloc(ptr.cast(), layout) },
1780 Err(_) => {
1781 debug_assert!(false, "Invalid layout");
1782 }
1783 }
1784 }
1785}
1786
1787impl Drop for RustDdwafAllocator {
1788 fn drop(&mut self) {
1789 unsafe { libddwaf_sys::ddwaf_allocator_destroy(self.raw) };
1790 }
1791}
1792
1793impl From<&RustDdwafAllocator> for libddwaf_sys::ddwaf_allocator {
1794 fn from(allocator: &RustDdwafAllocator) -> Self {
1795 allocator.raw
1796 }
1797}
1798
1799unsafe impl Sync for RustDdwafAllocator {}
1801unsafe impl Send for RustDdwafAllocator {}
1802
1803static DEFAULT_ALLOCATOR: OnceLock<RustDdwafAllocator> = OnceLock::new();
1804
1805pub(crate) fn get_default_allocator() -> &'static RustDdwafAllocator {
1806 DEFAULT_ALLOCATOR.get_or_init(|| RustDdwafAllocator::new().unwrap())
1807}
1808
1809#[macro_export]
1811macro_rules! waf_object {
1812 (null) => {
1813 $crate::object::WafObject::from(())
1814 };
1815 ($l:expr) => {
1816 $crate::object::WafObject::from($l)
1817 };
1818}
1819
1820#[macro_export]
1822macro_rules! waf_array {
1823 () => { $crate::object::WafArray::new(0) };
1824 ($($e:expr),* $(,)?) => {
1825 {
1826 let size = [$($crate::__repl_expr_with_unit!($e)),*].len();
1827 let mut res = $crate::object::WafArray::new(size as u16);
1828 let mut i = usize::MAX;
1829 $(
1830 i = i.wrapping_add(1);
1831 res[i] = $crate::waf_object!($e);
1832 )*
1833 res
1834 }
1835 };
1836}
1837
1838#[macro_export]
1840macro_rules! waf_map {
1841 () => { $crate::object::WafMap::new(0) };
1842 ($(($k:literal, $v:expr)),* $(,)?) => {
1843 {
1844 let size = [$($crate::__repl_expr_with_unit!($v)),*].len();
1845 let mut res = $crate::object::WafMap::new(u16::try_from(size).unwrap());
1846 let mut i = usize::MAX;
1847 $(
1848 i = i.wrapping_add(1);
1849 let k = $crate::object::WafString::new_literal($k.as_bytes());
1850 let val: $crate::object::WafObject = $v.into();
1851 res[i] = $crate::object::Keyed::new(k, val);
1852 )*
1853 res
1854 }
1855 };
1856}
1857
1858#[doc(hidden)]
1862#[macro_export]
1863macro_rules! __repl_expr_with_unit {
1864 ($e:expr) => {
1865 ()
1866 };
1867}
1868
1869#[cfg(test)]
1870#[cfg_attr(coverage_nightly, coverage(off))]
1871mod tests {
1872 use std::str::FromStr;
1873
1874 use super::*;
1875
1876 #[test]
1877 #[allow(clippy::float_cmp)] #[allow(clippy::cast_possible_truncation)]
1879 fn unsafe_changes_to_default_objects() {
1880 unsafe {
1881 let mut unsigned = WafUnsigned::default();
1882 unsigned.as_raw_mut().via.u64_.val += 1;
1883 assert_eq!(unsigned.value(), 1);
1884
1885 let mut signed = WafSigned::default();
1886 signed.as_raw_mut().via.i64_.val -= 1;
1887 assert_eq!(signed.value(), -1);
1888
1889 let mut float = WafFloat::default();
1890 float.as_raw_mut().via.f64_.val += 1.0;
1891 assert_eq!(float.value(), 1.0);
1892
1893 let mut boolean = WafBool::default();
1894 boolean.as_raw_mut().via.b8.val = true;
1895 assert!(boolean.value());
1896
1897 let null = WafNull::default();
1898 let s = String::from_str("foobar").unwrap();
1901 let keyed_null = Keyed::new(WafString::from(s.as_str()), null);
1902 std::mem::drop(keyed_null);
1903
1904 let mut string = WafString::default();
1905 let str_mut = string.as_raw_mut();
1906 let p: *mut u8 =
1907 no_fail_alloc(Layout::array::<::std::os::raw::c_char>(s.len()).unwrap()).cast();
1908 std::ptr::copy_nonoverlapping(s.as_ptr(), p.cast(), s.len());
1909 str_mut.drop_string();
1910 str_mut.via.str_.ptr = p.cast();
1911 str_mut.via.str_.size = s.len() as u32;
1912 assert_eq!(string.as_str().unwrap(), "foobar");
1913 assert_eq!(string.len(), s.len() as u32);
1914 assert!(!string.is_empty());
1915 }
1916 }
1917
1918 #[test]
1919 #[allow(clippy::cast_possible_truncation)]
1920 fn string_representations_are_equivalent() {
1921 const HELLO: &[u8] = b"hello";
1922
1923 let ss = WafString::new("hello").unwrap();
1924 assert_eq!(ss.raw.obj_type(), libddwaf_sys::DDWAF_OBJ_SMALL_STRING);
1925 assert!(ss.is_valid());
1926 assert!(ss.raw.is_string());
1927
1928 let ls = WafString::new_literal(HELLO);
1929 assert_eq!(ls.raw.obj_type(), libddwaf_sys::DDWAF_OBJ_LITERAL_STRING);
1930 assert!(ls.is_valid());
1931 assert!(ls.raw.is_string());
1932 assert_eq!(ss, ls);
1933
1934 let ns = libddwaf_sys::ddwaf_object {
1935 via: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
1936 str_: libddwaf_sys::_ddwaf_object_string {
1937 type_: libddwaf_sys::DDWAF_OBJ_STRING as u8,
1938 size: HELLO.len() as u32,
1939 ptr: HELLO.as_ptr() as *mut _,
1940 },
1941 },
1942 };
1943 let ns = unsafe { ns.unchecked_as_ref::<WafString>() };
1944 assert_eq!(ns.raw.obj_type(), libddwaf_sys::DDWAF_OBJ_STRING);
1945 assert!(ns.is_valid());
1946 assert!(ns.raw.is_string());
1947 assert_eq!(ns.as_bytes(), HELLO);
1948 assert_eq!(*ns, ss);
1949 assert_eq!(*ns, ls);
1950 }
1951}