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::{cmp, fmt};
7
8mod iter;
9#[doc(inline)]
10pub use iter::*;
11
12#[non_exhaustive]
14#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub enum WafObjectType {
16 Invalid,
19 Signed,
21 Unsigned,
23 String,
25 Array,
27 Map,
29 Bool,
31 Float,
33 Null,
35}
36impl WafObjectType {
37 const fn as_raw(self) -> libddwaf_sys::DDWAF_OBJ_TYPE {
39 match self {
40 WafObjectType::Invalid => libddwaf_sys::DDWAF_OBJ_INVALID,
41 WafObjectType::Signed => libddwaf_sys::DDWAF_OBJ_SIGNED,
42 WafObjectType::Unsigned => libddwaf_sys::DDWAF_OBJ_UNSIGNED,
43 WafObjectType::String => libddwaf_sys::DDWAF_OBJ_STRING,
44 WafObjectType::Array => libddwaf_sys::DDWAF_OBJ_ARRAY,
45 WafObjectType::Map => libddwaf_sys::DDWAF_OBJ_MAP,
46 WafObjectType::Bool => libddwaf_sys::DDWAF_OBJ_BOOL,
47 WafObjectType::Float => libddwaf_sys::DDWAF_OBJ_FLOAT,
48 WafObjectType::Null => libddwaf_sys::DDWAF_OBJ_NULL,
49 }
50 }
51}
52impl TryFrom<libddwaf_sys::DDWAF_OBJ_TYPE> for WafObjectType {
53 type Error = UnknownObjectTypeError;
54 fn try_from(value: libddwaf_sys::DDWAF_OBJ_TYPE) -> Result<Self, UnknownObjectTypeError> {
55 match value {
56 libddwaf_sys::DDWAF_OBJ_INVALID => Ok(WafObjectType::Invalid),
57 libddwaf_sys::DDWAF_OBJ_SIGNED => Ok(WafObjectType::Signed),
58 libddwaf_sys::DDWAF_OBJ_UNSIGNED => Ok(WafObjectType::Unsigned),
59 libddwaf_sys::DDWAF_OBJ_STRING => Ok(WafObjectType::String),
60 libddwaf_sys::DDWAF_OBJ_ARRAY => Ok(WafObjectType::Array),
61 libddwaf_sys::DDWAF_OBJ_MAP => Ok(WafObjectType::Map),
62 libddwaf_sys::DDWAF_OBJ_BOOL => Ok(WafObjectType::Bool),
63 libddwaf_sys::DDWAF_OBJ_FLOAT => Ok(WafObjectType::Float),
64 libddwaf_sys::DDWAF_OBJ_NULL => Ok(WafObjectType::Null),
65 unknown => Err(UnknownObjectTypeError(unknown)),
66 }
67 }
68}
69
70#[derive(Copy, Clone, Debug)]
72pub struct UnknownObjectTypeError(libddwaf_sys::DDWAF_OBJ_TYPE);
73impl std::error::Error for UnknownObjectTypeError {}
74impl std::fmt::Display for UnknownObjectTypeError {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 write!(f, "Unknown object type: {:?}", self.0)
77 }
78}
79
80#[derive(Copy, Clone, Debug)]
82pub struct ObjectTypeError {
83 pub expected: WafObjectType,
84 pub actual: WafObjectType,
85}
86impl std::error::Error for ObjectTypeError {}
87impl std::fmt::Display for ObjectTypeError {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 write!(
90 f,
91 "Invalid object type (expected {:?}, got {:?})",
92 self.expected, self.actual
93 )
94 }
95}
96
97#[doc(hidden)]
100pub trait AsRawMutObject: crate::private::Sealed + AsRef<libddwaf_sys::ddwaf_object> {
101 #[doc(hidden)]
116 unsafe fn as_raw_mut(&mut self) -> &mut libddwaf_sys::ddwaf_object;
117}
118
119pub trait TypedWafObject: AsRawMutObject {
122 const TYPE: WafObjectType;
125}
126
127#[derive(Default)]
131#[repr(transparent)]
132pub struct WafObject {
133 raw: libddwaf_sys::ddwaf_object,
134}
135impl WafObject {
136 pub fn from_json(json: impl AsRef<[u8]>) -> Option<WafOwned<Self>> {
146 let mut obj = WafOwned::<Self>::default();
147 let data = json.as_ref();
148 let Ok(len) = u32::try_from(data.len()) else {
149 return None;
150 };
151 if !unsafe {
152 libddwaf_sys::ddwaf_object_from_json(obj.as_raw_mut(), data.as_ptr().cast(), len)
153 } {
154 return None;
155 }
156 Some(obj)
157 }
158
159 #[must_use]
164 pub fn get_type(&self) -> WafObjectType {
165 self.as_ref()
166 .type_
167 .try_into()
168 .unwrap_or(WafObjectType::Invalid)
169 }
170
171 #[must_use]
173 pub fn as_type<T: TypedWafObject>(&self) -> Option<&T> {
174 if self.get_type() == T::TYPE {
175 Some(unsafe { self.as_type_unchecked::<T>() })
176 } else {
177 None
178 }
179 }
180
181 pub(crate) unsafe fn as_type_unchecked<T: TypedWafObject>(&self) -> &T {
186 unsafe { self.as_ref().unchecked_as_ref::<T>() }
187 }
188
189 pub fn as_type_mut<T: TypedWafObject>(&mut self) -> Option<&mut T> {
191 if self.get_type() == T::TYPE {
192 Some(unsafe { self.as_raw_mut().unchecked_as_ref_mut::<T>() })
193 } else {
194 None
195 }
196 }
197
198 #[must_use]
201 pub fn is_valid(&self) -> bool {
202 self.get_type() != WafObjectType::Invalid
203 }
204
205 #[must_use]
207 pub fn to_u64(&self) -> Option<u64> {
208 self.as_type::<WafUnsigned>().map(WafUnsigned::value)
209 }
210
211 #[must_use]
214 pub fn to_i64(&self) -> Option<i64> {
215 match self.get_type() {
216 WafObjectType::Unsigned => {
217 let obj: &WafUnsigned = unsafe { self.as_type_unchecked() };
218 obj.value().try_into().ok()
219 }
220 WafObjectType::Signed => {
221 let obj: &WafSigned = unsafe { self.as_type_unchecked() };
222 Some(obj.value())
223 }
224 _ => None,
225 }
226 }
227
228 #[must_use]
230 pub fn to_f64(&self) -> Option<f64> {
231 self.as_type::<WafFloat>().map(WafFloat::value)
232 }
233
234 #[must_use]
236 pub fn to_bool(&self) -> Option<bool> {
237 self.as_type::<WafBool>().map(WafBool::value)
238 }
239
240 #[must_use]
243 pub fn to_str(&self) -> Option<&str> {
244 self.as_type::<WafString>().and_then(|x| x.as_str().ok())
245 }
246}
247impl AsRef<libddwaf_sys::ddwaf_object> for WafObject {
248 fn as_ref(&self) -> &libddwaf_sys::ddwaf_object {
249 &self.raw
250 }
251}
252impl AsRawMutObject for WafObject {
253 unsafe fn as_raw_mut(&mut self) -> &mut libddwaf_sys::ddwaf_object {
254 &mut self.raw
255 }
256}
257impl fmt::Debug for WafObject {
258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259 match self.get_type() {
260 WafObjectType::Invalid => write!(f, "WafInvalid"),
261 WafObjectType::Unsigned => {
262 let obj: &WafUnsigned = self.as_type().unwrap();
263 obj.fmt(f)
264 }
265 WafObjectType::Signed => {
266 let obj: &WafSigned = self.as_type().unwrap();
267 obj.fmt(f)
268 }
269 WafObjectType::Float => {
270 let obj: &WafFloat = self.as_type().unwrap();
271 obj.fmt(f)
272 }
273 WafObjectType::Bool => {
274 let obj: &WafBool = self.as_type().unwrap();
275 obj.fmt(f)
276 }
277 WafObjectType::Null => {
278 let obj: &WafNull = self.as_type().unwrap();
279 obj.fmt(f)
280 }
281 WafObjectType::String => {
282 let obj: &WafString = self.as_type().unwrap();
283 obj.fmt(f)
284 }
285 WafObjectType::Array => {
286 let obj: &WafArray = self.as_type().unwrap();
287 obj.fmt(f)
288 }
289 WafObjectType::Map => {
290 let obj: &WafMap = self.as_type().unwrap();
291 obj.fmt(f)
292 }
293 }
294 }
295}
296impl Drop for WafObject {
297 fn drop(&mut self) {
298 unsafe { self.raw.drop_object() }
299 }
300}
301impl From<u64> for WafObject {
302 fn from(value: u64) -> Self {
303 WafUnsigned::new(value).into()
304 }
305}
306impl From<u32> for WafObject {
307 fn from(value: u32) -> Self {
308 WafUnsigned::new(value.into()).into()
309 }
310}
311impl From<i64> for WafObject {
312 fn from(value: i64) -> Self {
313 WafSigned::new(value).into()
314 }
315}
316impl From<i32> for WafObject {
317 fn from(value: i32) -> Self {
318 WafSigned::new(value.into()).into()
319 }
320}
321impl From<f64> for WafObject {
322 fn from(value: f64) -> Self {
323 WafFloat::new(value).into()
324 }
325}
326impl From<bool> for WafObject {
327 fn from(value: bool) -> Self {
328 WafBool::new(value).into()
329 }
330}
331impl From<&str> for WafObject {
332 fn from(value: &str) -> Self {
333 WafString::new(value).into()
334 }
335}
336impl From<&[u8]> for WafObject {
337 fn from(value: &[u8]) -> Self {
338 WafString::new(value).into()
339 }
340}
341impl From<()> for WafObject {
342 fn from((): ()) -> Self {
343 WafNull::new().into()
344 }
345}
346impl<T: TypedWafObject> From<T> for WafObject {
347 fn from(value: T) -> Self {
348 let res = Self {
349 raw: *value.as_ref(),
350 };
351 std::mem::forget(value);
352 res
353 }
354}
355impl<T: AsRef<libddwaf_sys::ddwaf_object>> cmp::PartialEq<T> for WafObject {
356 fn eq(&self, other: &T) -> bool {
357 self.raw == *other.as_ref()
358 }
359}
360impl crate::private::Sealed for WafObject {}
361
362pub struct WafOwned<T: AsRawMutObject> {
366 inner: std::mem::ManuallyDrop<T>,
367}
368impl<T: AsRawMutObject + fmt::Debug> fmt::Debug for WafOwned<T> {
369 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 self.inner.deref().fmt(f)
371 }
372}
373impl<T: AsRawMutObject + Default> Default for WafOwned<T> {
374 fn default() -> Self {
375 Self {
376 inner: std::mem::ManuallyDrop::new(Default::default()),
377 }
378 }
379}
380impl<T: AsRawMutObject> Deref for WafOwned<T> {
381 type Target = T;
382 fn deref(&self) -> &Self::Target {
383 &self.inner
384 }
385}
386impl<T: AsRawMutObject> DerefMut for WafOwned<T> {
387 fn deref_mut(&mut self) -> &mut Self::Target {
388 &mut self.inner
389 }
390}
391impl<T: AsRawMutObject> Drop for WafOwned<T> {
392 fn drop(&mut self) {
393 unsafe { libddwaf_sys::ddwaf_object_free(self.inner.as_raw_mut()) };
394 }
395}
396impl<T: AsRawMutObject> PartialEq<T> for WafOwned<T>
397where
398 T: PartialEq<T>,
399{
400 fn eq(&self, other: &T) -> bool {
401 *self.inner == *other
402 }
403}
404
405unsafe fn no_fail_alloc(layout: Layout) -> *mut u8 {
411 if layout.size() == 0 {
412 return null_mut();
413 }
414 let ptr = unsafe { std::alloc::alloc(layout) };
415 if ptr.is_null() {
416 std::alloc::handle_alloc_error(layout);
417 }
418 ptr
419}
420
421macro_rules! typed_object {
422 ($type:expr => $name:ident $({ $($impl:tt)* })?) => {
423 #[doc = concat!("The WAF object representation of a value of type [", stringify!($type), "]")]
424 #[repr(transparent)]
425 pub struct $name {
426 raw: libddwaf_sys::ddwaf_object,
427 }
428 impl $name {
429 #[doc = concat!("Returns true if this [", stringify!($name), "] is indeed [", stringify!($type), "].")]
430 #[must_use]
431 pub const fn is_valid(&self) -> bool {
432 self.raw.type_ == $type.as_raw()
433 }
434
435 #[must_use]
437 pub fn as_object(&self) -> &WafObject{
438 let obj: &libddwaf_sys::ddwaf_object = self.as_ref();
439 obj.as_object_ref()
440 }
441 $(
442 $($impl)*)?
443 }
444 impl AsRef<libddwaf_sys::ddwaf_object> for $name {
445 fn as_ref(&self) -> &libddwaf_sys::ddwaf_object {
446 &self.raw
447 }
448 }
449 impl AsRawMutObject for $name {
450 unsafe fn as_raw_mut(&mut self) -> &mut libddwaf_sys::ddwaf_object {
451 &mut self.raw
452 }
453 }
454 impl Default for $name {
455 fn default() -> Self {
456 Self {
457 raw: libddwaf_sys::ddwaf_object {
458 type_: $type.as_raw(),
459 ..Default::default()
460 },
461 }
462 }
463 }
464 impl TryFrom<WafObject> for $name {
465 type Error = ObjectTypeError;
466 fn try_from(obj: WafObject) -> Result<Self, Self::Error> {
467 if obj.get_type() != Self::TYPE {
468 return Err(ObjectTypeError {
469 expected: $type,
470 actual: obj.get_type(),
471 });
472 }
473 let res = Self { raw: obj.raw };
474 std::mem::forget(obj);
475 Ok(res)
476 }
477 }
478 impl<T: AsRef<libddwaf_sys::ddwaf_object>> cmp::PartialEq<T> for $name {
479 fn eq(&self, other: &T) -> bool {
480 self.raw == *other.as_ref()
481 }
482 }
483 impl crate::private::Sealed for $name {}
484 impl TypedWafObject for $name {
485 const TYPE: WafObjectType = $type;
486 }
487 };
488}
489
490typed_object!(WafObjectType::Invalid => WafInvalid);
491typed_object!(WafObjectType::Signed => WafSigned {
492 #[must_use]
494 pub const fn new(val: i64) -> Self {
495 Self {
496 raw: libddwaf_sys::ddwaf_object {
497 type_: libddwaf_sys::DDWAF_OBJ_SIGNED,
498 #[allow(clippy::used_underscore_items)]
499 __bindgen_anon_1: libddwaf_sys::_ddwaf_object__bindgen_ty_1 { intValue: val },
500 nbEntries: 0,
501 parameterName: null_mut(),
502 parameterNameLength: 0,
503 }
504 }
505 }
506
507 #[must_use]
509 pub const fn value(&self) -> i64 {
510 unsafe { self.raw.__bindgen_anon_1.intValue }
511 }
512});
513typed_object!(WafObjectType::Unsigned => WafUnsigned {
514 #[must_use]
516 pub const fn new (val: u64) -> Self {
517 Self {
518 raw: libddwaf_sys::ddwaf_object {
519 type_: libddwaf_sys::DDWAF_OBJ_UNSIGNED,
520 #[allow(clippy::used_underscore_items)]
521 __bindgen_anon_1: libddwaf_sys::_ddwaf_object__bindgen_ty_1 { uintValue: val },
522 nbEntries: 0,
523 parameterName: null_mut(),
524 parameterNameLength: 0,
525 }
526 }
527 }
528
529 #[must_use]
531 pub const fn value(&self) -> u64 {
532 unsafe { self.raw.__bindgen_anon_1.uintValue }
533 }
534});
535typed_object!(WafObjectType::String => WafString {
536 pub fn new(val: impl AsRef<[u8]>) -> Self {
538 let val = val.as_ref();
539 let ptr = if val.is_empty() {
540 null_mut()
541 } else {
542 let b: Box<[u8]> = val.into();
543 Box::into_raw(b).cast()
544 };
545 Self {
546 raw: libddwaf_sys::ddwaf_object {
547 type_: libddwaf_sys::DDWAF_OBJ_STRING,
548 #[allow(clippy::used_underscore_items)]
549 __bindgen_anon_1: libddwaf_sys::_ddwaf_object__bindgen_ty_1 {
550 stringValue: ptr,
551 },
552 nbEntries: val.len() as u64,
553 ..Default::default()
554 },
555 }
556 }
557
558 #[must_use]
564 pub fn len(&self) -> usize {
565 usize::try_from(self.raw.nbEntries).expect("string is too large for this platform")
566 }
567
568 #[must_use]
570 pub fn is_empty(&self) -> bool {
571 self.len() == 0
572 }
573
574 #[must_use]
576 pub fn bytes(&self) -> &[u8] {
577 debug_assert_eq!(self.raw.type_, libddwaf_sys::DDWAF_OBJ_STRING);
578 let len = self.len();
579 if len == 0 {
580 return &[];
581 }
582 debug_assert!(!unsafe{ self.raw.__bindgen_anon_1.stringValue }.is_null());
583 unsafe {
584 std::slice::from_raw_parts(
585 self.raw.__bindgen_anon_1.stringValue.cast(),
586 len,
587 )
588 }
589 }
590
591 pub fn as_str(&self) -> Result<&str, std::str::Utf8Error> {
597 std::str::from_utf8(self.bytes())
598 }
599});
600typed_object!(WafObjectType::Array => WafArray {
601 #[must_use]
608 pub fn new(nb_entries: u64) -> Self {
609 let size = usize::try_from(nb_entries).expect("size is too large for this platform");
610 let layout = Layout::array::<libddwaf_sys::ddwaf_object>(size).unwrap();
611 let array = unsafe { no_fail_alloc(layout).cast() };
612 unsafe { std::ptr::write_bytes(array, 0, size)};
613 Self {
614 raw: libddwaf_sys::ddwaf_object {
615 type_: libddwaf_sys::DDWAF_OBJ_ARRAY,
616 #[allow(clippy::used_underscore_items)]
617 __bindgen_anon_1: libddwaf_sys::_ddwaf_object__bindgen_ty_1 { array },
618 nbEntries: nb_entries,
619 ..Default::default()
620 }
621 }
622 }
623
624 #[must_use]
630 pub fn len(&self) -> usize {
631 usize::try_from(self.raw.nbEntries).expect("array is too large for this platform")
632 }
633
634 #[must_use]
636 pub fn is_empty(&self) -> bool {
637 self.len() == 0
638 }
639
640 pub fn iter(&self) -> impl Iterator<Item = &WafObject> {
642 let slice : &[WafObject] = self.as_ref();
643 slice.iter()
644 }
645
646 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut WafObject> {
648 let slice : &mut [WafObject] = AsMut::as_mut(self);
649 slice.iter_mut()
650 }
651});
652typed_object!(WafObjectType::Map => WafMap {
653 #[must_use]
660 pub fn new(nb_entries: u64) -> Self {
661 let size = usize::try_from(nb_entries).expect("size is too large for this platform");
662 let layout = Layout::array::<libddwaf_sys::ddwaf_object>(size).unwrap();
663 let array = unsafe { no_fail_alloc(layout).cast() };
664 unsafe { std::ptr::write_bytes(array, 0, size)};
665 Self {
666 raw: libddwaf_sys::ddwaf_object {
667 type_: libddwaf_sys::DDWAF_OBJ_MAP,
668 #[allow(clippy::used_underscore_items)]
669 __bindgen_anon_1: libddwaf_sys::_ddwaf_object__bindgen_ty_1 { array },
670 nbEntries: nb_entries,
671 ..Default::default()
672 }
673 }
674 }
675
676 #[must_use]
682 pub fn len(&self) -> usize {
683 usize::try_from(self.raw.nbEntries).expect("map is too large for this platform")
684 }
685
686 #[must_use]
688 pub fn is_empty(&self) -> bool {
689 self.len() == 0
690 }
691
692 pub fn iter(&self) -> impl Iterator<Item = &Keyed<WafObject>> {
694 let slice : &[Keyed<WafObject>] = self.as_ref();
695 slice.iter()
696 }
697
698 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Keyed<WafObject>> {
700 let slice : &mut [Keyed<WafObject>] = AsMut::as_mut(self);
701 slice.iter_mut()
702 }
703
704 #[must_use]
708 pub fn get(&self, key: &'_ [u8]) -> Option<&Keyed<WafObject>> {
709 for o in self.iter() {
710 if o.key() == key {
711 return Some(o)
712 }
713 }
714 None
715 }
716
717 pub fn get_mut(&mut self, key: &'_ [u8]) -> Option<&mut Keyed<WafObject>> {
721 for o in self.iter_mut() {
722 if o.key() == key {
723 return Some(o)
724 }
725 }
726 None
727 }
728
729 #[must_use]
731 pub fn get_str(&self, key: &'_ str) -> Option<&Keyed<WafObject>> {
732 self.get(key.as_bytes())
733 }
734
735 pub fn get_str_mut(&mut self, key: &'_ str) -> Option<&mut Keyed<WafObject>> {
737 self.get_mut(key.as_bytes())
738 }
739});
740typed_object!(WafObjectType::Bool => WafBool {
741 #[must_use]
743 pub const fn new(val: bool) -> Self {
744 Self {
745 raw: libddwaf_sys::ddwaf_object {
746 type_: libddwaf_sys::DDWAF_OBJ_BOOL,
747 #[allow(clippy::used_underscore_items)]
748 __bindgen_anon_1: libddwaf_sys::_ddwaf_object__bindgen_ty_1 { boolean: val },
749 nbEntries: 0,
750 parameterName: null_mut(),
751 parameterNameLength: 0,
752 }
753 }
754 }
755
756 #[must_use]
758 pub const fn value(&self) -> bool {
759 unsafe { self.raw.__bindgen_anon_1.boolean }
760 }
761});
762typed_object!(WafObjectType::Float => WafFloat {
763 #[must_use]
765 pub const fn new(val: f64) -> Self {
766 Self {
767 raw: libddwaf_sys::ddwaf_object {
768 type_: libddwaf_sys::DDWAF_OBJ_FLOAT,
769 #[allow(clippy::used_underscore_items)]
770 __bindgen_anon_1: libddwaf_sys::_ddwaf_object__bindgen_ty_1 { f64_: val },
771 nbEntries: 0,
772 parameterName: null_mut(),
773 parameterNameLength: 0,
774 }
775 }
776 }
777
778 #[must_use]
780 pub const fn value(&self) -> f64 {
781 unsafe { self.raw.__bindgen_anon_1.f64_ }
782 }
783});
784typed_object!(WafObjectType::Null => WafNull {
785 #[must_use]
787 pub const fn new() -> Self {
788 Self { raw: libddwaf_sys::ddwaf_object {
789 type_: libddwaf_sys::DDWAF_OBJ_NULL,
790 #[allow(clippy::used_underscore_items)]
791 __bindgen_anon_1: libddwaf_sys::_ddwaf_object__bindgen_ty_1 { uintValue: 0},
792 nbEntries: 0,
793 parameterName: null_mut(),
794 parameterNameLength: 0,
795 } }
796 }
797});
798
799impl fmt::Debug for WafSigned {
800 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
801 write!(f, "{}({})", stringify!(WafSigned), self.value())
802 }
803}
804impl From<i64> for WafSigned {
805 fn from(value: i64) -> Self {
806 Self::new(value)
807 }
808}
809impl From<i32> for WafSigned {
810 fn from(value: i32) -> Self {
811 Self::new(value.into())
812 }
813}
814
815impl fmt::Debug for WafUnsigned {
816 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
817 write!(f, "{}({})", stringify!(WafUnsigned), self.value())
818 }
819}
820impl From<u64> for WafUnsigned {
821 fn from(value: u64) -> Self {
822 Self::new(value)
823 }
824}
825impl From<u32> for WafUnsigned {
826 fn from(value: u32) -> Self {
827 Self::new(value.into())
828 }
829}
830
831impl<T: AsRef<[u8]>> From<T> for WafString {
832 fn from(val: T) -> Self {
833 Self::new(val)
834 }
835}
836impl fmt::Debug for WafString {
837 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
838 write!(
839 f,
840 "{}(\"{:?}\")",
841 stringify!(WafString),
842 fmt_bin_str(self.bytes())
843 )
844 }
845}
846impl Drop for WafString {
847 fn drop(&mut self) {
848 unsafe { self.raw.drop_string() }
849 }
850}
851
852impl AsRef<[WafObject]> for WafArray {
853 fn as_ref(&self) -> &[WafObject] {
854 if self.is_empty() {
855 return &[];
856 }
857 let array = unsafe { self.raw.__bindgen_anon_1.array.cast() };
858 unsafe { std::slice::from_raw_parts(array, self.len()) }
859 }
860}
861impl AsMut<[WafObject]> for WafArray {
862 fn as_mut(&mut self) -> &mut [WafObject] {
863 if self.is_empty() {
864 return &mut [];
865 }
866 let array = unsafe { self.raw.__bindgen_anon_1.array.cast() };
867 unsafe { std::slice::from_raw_parts_mut(array, self.len()) }
868 }
869}
870impl fmt::Debug for WafArray {
871 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
872 write!(f, "{}[", stringify!(WafArray))?;
873 let mut first = true;
874 for obj in self.iter() {
875 if first {
876 first = false;
877 } else {
878 write!(f, ", ")?;
879 }
880 write!(f, "{obj:?}")?;
881 }
882 write!(f, "]")
883 }
884}
885impl Drop for WafArray {
886 fn drop(&mut self) {
887 unsafe { self.raw.drop_array() }
888 }
889}
890impl<T: Into<WafObject>, const N: usize> From<[T; N]> for WafArray {
891 fn from(value: [T; N]) -> Self {
892 let mut array = Self::new(value.len() as u64);
893 for (i, obj) in value.into_iter().enumerate() {
894 array[i] = obj.into();
895 }
896 array
897 }
898}
899impl Index<usize> for WafArray {
900 type Output = WafObject;
901 fn index(&self, index: usize) -> &Self::Output {
902 let obj: &libddwaf_sys::ddwaf_object = self.as_ref();
903 assert!(
904 index < usize::try_from(obj.nbEntries).unwrap_or(usize::MAX),
906 "index out of bounds ({} >= {})",
907 index,
908 obj.nbEntries
909 );
910 let array = unsafe { obj.__bindgen_anon_1.array };
911 unsafe { &*(array.add(index) as *const _) }
912 }
913}
914impl IndexMut<usize> for WafArray {
915 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
916 let obj: &libddwaf_sys::ddwaf_object = self.as_ref();
917 assert!(
918 index < usize::try_from(obj.nbEntries).unwrap_or(usize::MAX),
920 "index out of bounds ({} >= {})",
921 index,
922 obj.nbEntries
923 );
924 let array = unsafe { obj.__bindgen_anon_1.array };
925 unsafe { &mut *(array.add(index).cast()) }
926 }
927}
928
929impl AsRef<[Keyed<WafObject>]> for WafMap {
930 fn as_ref(&self) -> &[Keyed<WafObject>] {
931 if self.is_empty() {
932 return &[];
933 }
934 let array = unsafe { self.raw.__bindgen_anon_1.array as *const _ };
935 unsafe { std::slice::from_raw_parts(array, self.len()) }
936 }
937}
938impl AsMut<[Keyed<WafObject>]> for WafMap {
939 fn as_mut(&mut self) -> &mut [Keyed<WafObject>] {
940 if self.is_empty() {
941 return &mut [];
942 }
943 let array = unsafe { self.raw.__bindgen_anon_1.array.cast() };
944 unsafe { std::slice::from_raw_parts_mut(array, self.len()) }
945 }
946}
947impl fmt::Debug for WafMap {
948 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
949 write!(f, "{}{{", stringify!(WafMap))?;
950 let mut first = true;
951 for keyed_obj in self.iter() {
952 if first {
953 first = false;
954 } else {
955 write!(f, ", ")?;
956 }
957 write!(f, "{keyed_obj:?}")?;
958 }
959 write!(f, "}}")
960 }
961}
962impl Drop for WafMap {
963 fn drop(&mut self) {
964 unsafe { self.raw.drop_map() }
965 }
966}
967impl Index<usize> for WafMap {
968 type Output = Keyed<WafObject>;
969 fn index(&self, index: usize) -> &Self::Output {
970 let obj: &libddwaf_sys::ddwaf_object = self.as_ref();
971 assert!(
972 index < usize::try_from(obj.nbEntries).unwrap_or(usize::MAX),
974 "index out of bounds ({} >= {})",
975 index,
976 obj.nbEntries
977 );
978 let array = unsafe { obj.__bindgen_anon_1.array };
979 unsafe { &*array.add(index) }.as_keyed_object_ref()
980 }
981}
982impl IndexMut<usize> for WafMap {
983 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
984 let obj: &libddwaf_sys::ddwaf_object = self.as_ref();
985 assert!(
986 index < usize::try_from(obj.nbEntries).unwrap_or(usize::MAX),
988 "index out of bounds ({} >= {})",
989 index,
990 obj.nbEntries
991 );
992 let array = unsafe { obj.__bindgen_anon_1.array };
993 unsafe { (*array.add(index)).as_keyed_object_mut() }
994 }
995}
996impl<K: AsRef<[u8]>, V: Into<WafObject>, const N: usize> From<[(K, V); N]> for WafMap {
997 fn from(vals: [(K, V); N]) -> Self {
998 let mut map = WafMap::new(N as u64);
999 for (i, (k, v)) in vals.into_iter().enumerate() {
1000 map[i] = Keyed::from((k.as_ref(), v));
1001 }
1002 map
1003 }
1004}
1005
1006impl fmt::Debug for WafBool {
1007 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1008 write!(f, "{}({})", stringify!(WafBool), self.value())
1009 }
1010}
1011impl From<bool> for WafBool {
1012 fn from(value: bool) -> Self {
1013 Self::new(value)
1014 }
1015}
1016
1017impl fmt::Debug for WafFloat {
1018 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1019 write!(f, "{}({})", stringify!(WafFloat), self.value())
1020 }
1021}
1022impl From<f64> for WafFloat {
1023 fn from(value: f64) -> Self {
1024 Self::new(value)
1025 }
1026}
1027
1028impl fmt::Debug for WafNull {
1029 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1030 write!(f, "{}", stringify!(WafNull))
1031 }
1032}
1033impl From<()> for WafNull {
1034 fn from((): ()) -> Self {
1035 Self::new()
1036 }
1037}
1038
1039#[repr(transparent)]
1041pub struct Keyed<T: AsRawMutObject> {
1042 value: T,
1043}
1044impl<T: AsRawMutObject> Keyed<T> {
1045 pub(crate) fn new(value: T) -> Self {
1047 Self { value }
1048 }
1049
1050 pub fn inner(&self) -> &T {
1052 &self.value
1053 }
1054
1055 pub fn key(&self) -> &[u8] {
1061 let obj = self.as_ref();
1062 if obj.parameterNameLength == 0 {
1063 return &[];
1064 }
1065 let len =
1066 usize::try_from(obj.parameterNameLength).expect("key is too long for this platform");
1067 unsafe { std::slice::from_raw_parts(obj.parameterName.cast(), len) }
1068 }
1069
1070 pub fn key_str(&self) -> Result<&str, std::str::Utf8Error> {
1076 std::str::from_utf8(self.key())
1077 }
1078
1079 pub fn set_key(&mut self, key: &[u8]) -> &mut Self {
1081 let obj = unsafe { self.as_raw_mut() };
1082 unsafe { obj.drop_key() };
1083 if key.is_empty() {
1084 obj.parameterName = null_mut();
1085 obj.parameterNameLength = 0;
1086 return self;
1087 }
1088
1089 let b: Box<[u8]> = key.into();
1090 let ptr = Box::into_raw(b);
1091 obj.parameterName = ptr.cast();
1092 obj.parameterNameLength = key.len() as u64;
1093 self
1094 }
1095
1096 pub fn set_key_str(&mut self, key: &str) -> &mut Self {
1098 self.set_key(key.as_bytes())
1099 }
1100}
1101impl Keyed<WafObject> {
1102 #[must_use]
1103 pub fn as_type<T: TypedWafObject>(&self) -> Option<&Keyed<T>> {
1104 if self.value.get_type() == T::TYPE {
1105 Some(unsafe { &*(std::ptr::from_ref(self).cast()) })
1106 } else {
1107 None
1108 }
1109 }
1110
1111 pub fn as_type_mut<T: TypedWafObject>(&mut self) -> Option<&mut Keyed<T>> {
1112 if self.value.get_type() == T::TYPE {
1113 Some(unsafe { &mut *(std::ptr::from_mut(self).cast()) })
1114 } else {
1115 None
1116 }
1117 }
1118}
1119impl Keyed<WafArray> {
1122 pub fn iter(&self) -> impl Iterator<Item = &WafObject> {
1123 self.value.iter()
1124 }
1125
1126 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut WafObject> {
1127 self.value.iter_mut()
1128 }
1129}
1130impl Keyed<WafMap> {
1133 pub fn iter(&self) -> impl Iterator<Item = &Keyed<WafObject>> {
1134 self.value.iter()
1135 }
1136
1137 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Keyed<WafObject>> {
1138 self.value.iter_mut()
1139 }
1140}
1141impl<T: AsRawMutObject> AsRawMutObject for Keyed<T> {
1142 unsafe fn as_raw_mut(&mut self) -> &mut libddwaf_sys::ddwaf_object {
1143 unsafe { self.value.as_raw_mut() }
1144 }
1145}
1146impl<T: AsRawMutObject> crate::private::Sealed for Keyed<T> {}
1147impl<T: AsRawMutObject> AsRef<libddwaf_sys::ddwaf_object> for Keyed<T> {
1148 fn as_ref(&self) -> &libddwaf_sys::ddwaf_object {
1149 self.value.as_ref()
1150 }
1151}
1152impl<T: Default + AsRawMutObject> std::default::Default for Keyed<T> {
1153 fn default() -> Self {
1154 Self {
1155 value: T::default(),
1156 }
1157 }
1158}
1159impl<T: AsRawMutObject> Deref for Keyed<T> {
1160 type Target = T;
1161 fn deref(&self) -> &Self::Target {
1162 &self.value
1163 }
1164}
1165impl<T: AsRawMutObject> std::ops::Drop for Keyed<T> {
1166 fn drop(&mut self) {
1167 unsafe { self.as_raw_mut().drop_key() };
1168 }
1170}
1171impl<T: AsRawMutObject + fmt::Debug> fmt::Debug for Keyed<T> {
1172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1173 write!(f, "\"{:?}\"={:?}", fmt_bin_str(self.key()), self.value)
1174 }
1175}
1176impl<T, U: AsRawMutObject> From<(&str, T)> for Keyed<U>
1177where
1178 T: Into<U>,
1179{
1180 fn from((key, value): (&str, T)) -> Self {
1181 let unkeyed = value.into();
1182 let mut keyed = Keyed::new(unkeyed);
1183 keyed.set_key_str(key);
1184 keyed
1185 }
1186}
1187impl<T, U: AsRawMutObject> From<(&[u8], T)> for Keyed<U>
1188where
1189 T: Into<U>,
1190{
1191 fn from((key, value): (&[u8], T)) -> Self {
1192 let unkeyed = value.into();
1193 let mut keyed = Keyed::new(unkeyed);
1194 keyed.set_key(key);
1195 keyed
1196 }
1197}
1198impl<T: TypedWafObject> From<Keyed<T>> for Keyed<WafObject> {
1199 fn from(value: Keyed<T>) -> Self {
1200 let res = Self {
1201 value: WafObject {
1202 raw: *value.as_ref(),
1203 },
1204 };
1205 std::mem::forget(value);
1206 res
1207 }
1208}
1209
1210trait UncheckedAsRef: crate::private::Sealed {
1211 unsafe fn unchecked_as_ref<T: AsRef<libddwaf_sys::ddwaf_object> + crate::private::Sealed>(
1218 &self,
1219 ) -> &T;
1220
1221 unsafe fn unchecked_as_ref_mut<T: AsRef<libddwaf_sys::ddwaf_object> + crate::private::Sealed>(
1228 &mut self,
1229 ) -> &mut T;
1230}
1231impl crate::private::Sealed for libddwaf_sys::ddwaf_object {}
1232impl UncheckedAsRef for libddwaf_sys::ddwaf_object {
1233 unsafe fn unchecked_as_ref<T: AsRef<libddwaf_sys::ddwaf_object> + crate::private::Sealed>(
1234 &self,
1235 ) -> &T {
1236 unsafe { &*(std::ptr::from_ref(self).cast()) }
1237 }
1238
1239 unsafe fn unchecked_as_ref_mut<
1240 T: AsRef<libddwaf_sys::ddwaf_object> + crate::private::Sealed,
1241 >(
1242 &mut self,
1243 ) -> &mut T {
1244 unsafe { &mut *(std::ptr::from_mut(self).cast()) }
1245 }
1246}
1247trait UncheckedAsWafObject: crate::private::Sealed {
1248 fn as_object_ref(&self) -> &WafObject;
1250
1251 fn as_keyed_object_ref(&self) -> &Keyed<WafObject>;
1254
1255 unsafe fn as_keyed_object_mut(&mut self) -> &mut Keyed<WafObject>;
1263}
1264impl<T: UncheckedAsRef> UncheckedAsWafObject for T {
1265 fn as_object_ref(&self) -> &WafObject {
1267 unsafe { self.unchecked_as_ref::<WafObject>() }
1268 }
1269
1270 fn as_keyed_object_ref(&self) -> &Keyed<WafObject> {
1273 unsafe { self.unchecked_as_ref::<Keyed<WafObject>>() }
1276 }
1277
1278 unsafe fn as_keyed_object_mut(&mut self) -> &mut Keyed<WafObject> {
1286 unsafe { self.unchecked_as_ref_mut::<Keyed<WafObject>>() }
1287 }
1288}
1289
1290fn fmt_bin_str(bytes: &[u8]) -> impl fmt::Debug + '_ {
1292 struct BinFormatter<'a>(&'a [u8]);
1293 impl fmt::Debug for BinFormatter<'_> {
1294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1295 for &c in self.0 {
1296 if c == b'"' || c == b'\\' {
1297 write!(f, "\\{}", c as char)?;
1298 } else if c.is_ascii_graphic() || c == b' ' {
1299 write!(f, "{}", c as char)?;
1300 } else {
1301 write!(f, "\\x{c:02X}")?;
1302 }
1303 }
1304 Ok(())
1305 }
1306 }
1307 BinFormatter(bytes)
1308}
1309
1310#[macro_export]
1312macro_rules! waf_object {
1313 (null) => {
1314 $crate::object::WafObject::from(())
1315 };
1316 ($l:expr) => {
1317 $crate::object::WafObject::from($l)
1318 };
1319}
1320
1321#[macro_export]
1323macro_rules! waf_array {
1324 () => { $crate::object::WafArray::new(0) };
1325 ($($e:expr),* $(,)?) => {
1326 {
1327 let size = [$($crate::__repl_expr_with_unit!($e)),*].len();
1328 let mut res = $crate::object::WafArray::new(size as u64);
1329 let mut i = usize::MAX;
1330 $(
1331 i = i.wrapping_add(1);
1332 res[i] = $crate::waf_object!($e);
1333 )*
1334 res
1335 }
1336 };
1337}
1338
1339#[macro_export]
1341macro_rules! waf_map {
1342 () => { $crate::object::WafMap::new(0) };
1343 ($(($k:literal, $v:expr)),* $(,)?) => {
1344 {
1345 let size = [$($crate::__repl_expr_with_unit!($v)),*].len();
1346 let mut res = $crate::object::WafMap::new(size as u64);
1347 let mut i = usize::MAX;
1348 $(
1349 i = i.wrapping_add(1);
1350 let k: &str = $k.into();
1351 let obj = $crate::object::Keyed::<$crate::object::WafObject>::from((k, $v));
1352 res[i] = obj.into();
1353 )*
1354 res
1355 }
1356 };
1357}
1358
1359#[doc(hidden)]
1363#[macro_export]
1364macro_rules! __repl_expr_with_unit {
1365 ($e:expr) => {
1366 ()
1367 };
1368}
1369
1370#[cfg(test)]
1371#[cfg_attr(coverage_nightly, coverage(off))]
1372mod tests {
1373 use std::str::FromStr;
1374
1375 use super::*;
1376
1377 #[test]
1378 #[allow(clippy::float_cmp)] fn unsafe_changes_to_default_objects() {
1380 unsafe {
1381 let mut unsigned = WafUnsigned::default();
1382 unsigned.as_raw_mut().__bindgen_anon_1.uintValue += 1;
1383 assert_eq!(unsigned.value(), 1);
1384
1385 let mut signed = WafSigned::default();
1386 signed.as_raw_mut().__bindgen_anon_1.intValue -= 1;
1387 assert_eq!(signed.value(), -1);
1388
1389 let mut float = WafFloat::default();
1390 float.as_raw_mut().__bindgen_anon_1.f64_ += 1.0;
1391 assert_eq!(float.value(), 1.0);
1392
1393 let mut boolean = WafBool::default();
1394 boolean.as_raw_mut().__bindgen_anon_1.boolean = true;
1395 assert!(boolean.value());
1396
1397 let mut null = WafNull::default();
1398 let s = String::from_str("foobar").unwrap();
1401 let b: Box<[u8]> = s.as_bytes().into();
1402 let p = Box::<[u8]>::into_raw(b);
1403 let null_mut = null.as_raw_mut();
1404 null_mut.parameterName = p.cast();
1405 null_mut.parameterNameLength = s.len() as u64;
1406 drop(std::mem::take(null_mut.as_keyed_object_mut()));
1407
1408 let mut string = WafString::default();
1409 let str_mut = string.as_raw_mut();
1410 let b: Box<[u8]> = s.as_bytes().into();
1411 let p = Box::<[u8]>::into_raw(b);
1412 str_mut.drop_string();
1413 str_mut.__bindgen_anon_1.stringValue = p as *const _;
1414 str_mut.nbEntries = s.len() as u64;
1415 assert_eq!(string.as_str().unwrap(), "foobar");
1416 assert_eq!(string.len(), s.len());
1417 assert!(!string.is_empty());
1418 }
1419 }
1420}