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