bnr_xfs/
macros.rs

1/// Provides convenience functions to destructure an enum with new-type variants.
2#[macro_export]
3macro_rules! inner_enum {
4    // macro variant for when the enum variant and its type are the same ident
5    ($ty:ident, $var:ident) => {
6        inner_enum!($ty, $var, $var);
7    };
8
9    // macro variant for when the enum variant and its type are potentially different
10    ($ty:ident, $var:ident, $var_ty:ident) => {
11        impl $ty {
12            ::paste::paste! {
13                #[doc = "Gets whether `" $ty "` is the variant `" $var "`."]
14                pub fn [<is_ $var:snake>](&self) -> bool {
15                    matches!(self, $ty::$var(_))
16                }
17
18                #[doc = "Gets a reference to `" $ty "` as the variant `" $var "`'s inner type `" $var_ty "`."]
19                #[allow(unreachable_patterns)]
20                pub fn [<as_ $var:snake>](&self) -> $crate::Result<&$var_ty> {
21                    use $crate::Error;
22
23                    match self {
24                        $ty::$var(ty) => Ok(ty),
25                        _ => Err(Error::Enum(format!("have variant: {self}, expected: {}", ::std::any::type_name::<$var_ty>()))),
26                    }
27                }
28
29                #[doc = "Converts `" $ty "` into the variant `" $var "`'s inner type `" $var_ty "`."]
30                #[allow(unreachable_patterns)]
31                pub fn [<into_ $var:snake>](self) -> $crate::Result<$var_ty> {
32                    use $crate::Error;
33
34                    match self {
35                        $ty::$var(ty) => Ok(ty),
36                        _ => Err(Error::Enum(format!("have variant: {self}, expected: {}", ::std::any::type_name::<$var_ty>()))),
37                    }
38                }
39            }
40        }
41    };
42}
43
44/// Implements the `Default` trait for types that have a `new` function.
45#[macro_export]
46macro_rules! impl_default {
47    ($ty:ident) => {
48        impl Default for $ty {
49            fn default() -> Self {
50                $ty::new()
51            }
52        }
53    };
54}
55
56/// Implements traits common to XFS enum types.
57#[macro_export]
58macro_rules! impl_xfs_enum {
59    ($ty:ident, $name:expr) => {
60        impl $ty {
61            /// Gets the inner representation.
62            pub const fn inner(&self) -> u32 {
63                *self as u32
64            }
65
66            /// Converts into the inner representation.
67            pub fn into_inner(self) -> u32 {
68                self as u32
69            }
70        }
71
72        $crate::impl_xfs_i4!($ty, $name);
73    };
74}
75
76/// Creates a new XFS `i4` type.
77#[macro_export]
78macro_rules! create_xfs_i4 {
79    ($ty:ident, $name:expr, $doc:expr) => {
80        ::paste::paste! {
81            #[doc = $doc]
82            #[repr(C)]
83            #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, ::serde::Deserialize, ::serde::Serialize)]
84            pub struct $ty(u32);
85
86            impl $ty {
87                #[doc = "Creates a new `" $ty "`."]
88                pub const fn new() -> Self {
89                    Self(0)
90                }
91
92                #[doc = "Creates a new `" $ty "` from the provided parameter."]
93                pub const fn create(val: u32) -> Self {
94                    Self(val)
95                }
96
97                #[doc = "Gets the inner representation of `" $ty "`."]
98                pub const fn inner(&self) -> u32 {
99                    self.0
100                }
101
102                #[doc = "Sets the inner representation of `" $ty "`."]
103                pub fn set_inner(&mut self, val: u32) {
104                    self.0 = val;
105                }
106
107                #[doc = "Converts into the inner representation of `" $ty "`."]
108                pub fn into_inner(self) -> u32 {
109                    self.0
110                }
111            }
112
113            $crate::impl_xfs_i4!($ty, $name);
114
115            impl ::std::fmt::Display for $ty {
116                fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
117                    write!(f, "{}", self.inner())
118                }
119            }
120        }
121    }
122}
123
124/// Common functionality for XFS `i4` types.
125#[macro_export]
126macro_rules! impl_xfs_i4 {
127    ($ty:ident, $name:expr) => {
128        impl $ty {
129            /// Gets the [XfsMember](crate::xfs::xfs_struct::XfsMember) name.
130            pub const fn xfs_name() -> &'static str {
131                $name
132            }
133        }
134
135        impl From<u32> for $ty {
136            fn from(val: u32) -> Self {
137                Self::create(val)
138            }
139        }
140
141        impl From<&u32> for $ty {
142            fn from(val: &u32) -> Self {
143                (*val).into()
144            }
145        }
146
147        impl From<$ty> for u32 {
148            fn from(val: $ty) -> Self {
149                val.inner()
150            }
151        }
152
153        impl From<&$ty> for u32 {
154            fn from(val: &$ty) -> Self {
155                (*val).into()
156            }
157        }
158
159        impl From<i32> for $ty {
160            fn from(val: i32) -> Self {
161                (val as u32).into()
162            }
163        }
164
165        impl From<&i32> for $ty {
166            fn from(val: &i32) -> Self {
167                (*val).into()
168            }
169        }
170
171        impl From<$ty> for i32 {
172            fn from(val: $ty) -> Self {
173                val.inner() as i32
174            }
175        }
176
177        impl From<&$ty> for i32 {
178            fn from(val: &$ty) -> Self {
179                (*val).into()
180            }
181        }
182
183        impl From<&$ty> for $crate::xfs::value::XfsValue {
184            fn from(val: &$ty) -> Self {
185                Self::new().with_i4(val.into())
186            }
187        }
188
189        impl From<$ty> for $crate::xfs::value::XfsValue {
190            fn from(val: $ty) -> Self {
191                (&val).into()
192            }
193        }
194
195        impl TryFrom<&$crate::xfs::value::XfsValue> for $ty {
196            type Error = $crate::Error;
197
198            fn try_from(val: &$crate::xfs::value::XfsValue) -> $crate::Result<Self> {
199                let name = $ty::xfs_name();
200                Ok(val
201                    .i4()
202                    .ok_or($crate::Error::Xfs(format!(
203                        "Expected {name} XfsValue, have: {val}"
204                    )))?
205                    .into())
206            }
207        }
208
209        impl TryFrom<$crate::xfs::value::XfsValue> for $ty {
210            type Error = $crate::Error;
211
212            fn try_from(val: $crate::xfs::value::XfsValue) -> $crate::Result<Self> {
213                (&val).try_into()
214            }
215        }
216
217        impl From<&$ty> for $crate::xfs::xfs_struct::XfsMember {
218            fn from(val: &$ty) -> Self {
219                $crate::xfs::xfs_struct::XfsMember::create($ty::xfs_name(), val.into())
220            }
221        }
222
223        impl From<$ty> for $crate::xfs::xfs_struct::XfsMember {
224            fn from(val: $ty) -> Self {
225                (&val).into()
226            }
227        }
228
229        impl TryFrom<&$crate::xfs::xfs_struct::XfsMember> for $ty {
230            type Error = $crate::Error;
231
232            fn try_from(val: &$crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
233                let name = $ty::xfs_name();
234                match (val.name(), val.value().i4()) {
235                    (n, Some(v)) if n == name => Ok(v.into()),
236                    _ => Err($crate::Error::Xfs(format!(
237                        "Expected {name} XfsMember, have: {val}"
238                    ))),
239                }
240            }
241        }
242
243        impl TryFrom<$crate::xfs::xfs_struct::XfsMember> for $ty {
244            type Error = $crate::Error;
245
246            fn try_from(val: $crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
247                (&val).try_into()
248            }
249        }
250    };
251}
252
253/// Common functionality for XFS `int` types.
254#[macro_export]
255macro_rules! impl_xfs_int {
256    ($ty:ident, $name:expr) => {
257        impl $ty {
258            /// Gets the [XfsMember](crate::xfs::xfs_struct::XfsMember) name.
259            pub const fn xfs_name() -> &'static str {
260                $name
261            }
262        }
263
264        impl From<u64> for $ty {
265            fn from(val: u64) -> Self {
266                Self::create(val)
267            }
268        }
269
270        impl From<&u64> for $ty {
271            fn from(val: &u64) -> Self {
272                (*val).into()
273            }
274        }
275
276        impl From<&$ty> for u64 {
277            fn from(val: &$ty) -> Self {
278                val.inner()
279            }
280        }
281
282        impl From<$ty> for u64 {
283            fn from(val: $ty) -> Self {
284                val.into_inner()
285            }
286        }
287
288        impl From<i64> for $ty {
289            fn from(val: i64) -> Self {
290                (val as u64).into()
291            }
292        }
293
294        impl From<&i64> for $ty {
295            fn from(val: &i64) -> Self {
296                (*val).into()
297            }
298        }
299
300        impl From<$ty> for i64 {
301            fn from(val: $ty) -> Self {
302                val.into_inner() as i64
303            }
304        }
305
306        impl From<&$ty> for i64 {
307            fn from(val: &$ty) -> Self {
308                val.inner() as i64
309            }
310        }
311
312        impl From<&$ty> for $crate::xfs::value::XfsValue {
313            fn from(val: &$ty) -> Self {
314                Self::new().with_int(val.into())
315            }
316        }
317
318        impl From<$ty> for $crate::xfs::value::XfsValue {
319            fn from(val: $ty) -> Self {
320                Self::new().with_int(val.into())
321            }
322        }
323
324        impl TryFrom<&$crate::xfs::value::XfsValue> for $ty {
325            type Error = $crate::Error;
326
327            fn try_from(val: &$crate::xfs::value::XfsValue) -> $crate::Result<Self> {
328                let name = $ty::xfs_name();
329                Ok(val
330                    .int()
331                    .ok_or($crate::Error::Xfs(format!(
332                        "Expected {name} XfsValue, have: {val}"
333                    )))?
334                    .into())
335            }
336        }
337
338        impl TryFrom<$crate::xfs::value::XfsValue> for $ty {
339            type Error = $crate::Error;
340
341            fn try_from(val: $crate::xfs::value::XfsValue) -> $crate::Result<Self> {
342                (&val).try_into()
343            }
344        }
345
346        impl From<&$ty> for $crate::xfs::xfs_struct::XfsMember {
347            fn from(val: &$ty) -> Self {
348                $crate::xfs::xfs_struct::XfsMember::create($ty::xfs_name(), val.into())
349            }
350        }
351
352        impl From<$ty> for $crate::xfs::xfs_struct::XfsMember {
353            fn from(val: $ty) -> Self {
354                (&val).into()
355            }
356        }
357
358        impl TryFrom<&$crate::xfs::xfs_struct::XfsMember> for $ty {
359            type Error = $crate::Error;
360
361            fn try_from(val: &$crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
362                let name = $ty::xfs_name();
363                match (val.name(), val.value().int()) {
364                    (n, Some(v)) if n == name => Ok(v.into()),
365                    _ => Err($crate::Error::Xfs(format!(
366                        "Expected {name} XfsMember, have: {val}"
367                    ))),
368                }
369            }
370        }
371
372        impl TryFrom<$crate::xfs::xfs_struct::XfsMember> for $ty {
373            type Error = $crate::Error;
374
375            fn try_from(val: $crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
376                (&val).try_into()
377            }
378        }
379    };
380}
381
382/// Creates a new XFS boolean type.
383#[macro_export]
384macro_rules! create_xfs_bool {
385    ($ty:ident, $name:expr, $doc:expr) => {
386        ::paste::paste! {
387            #[doc = $doc]
388            #[repr(C)]
389            #[derive(Clone, Copy, Debug, Default, PartialEq, ::serde::Deserialize, ::serde::Serialize)]
390            pub struct $ty(bool);
391
392            impl $ty {
393                #[doc = "Creates a new `" $ty "`."]
394                pub const fn new() -> Self {
395                    Self(false)
396                }
397
398                #[doc = "Creates a new `" $ty "` from the provided parameter."]
399                pub const fn create(val: bool) -> Self {
400                    Self(val)
401                }
402
403                #[doc = "Gets the inner representation of `" $ty "`."]
404                pub const fn inner(&self) -> bool {
405                    self.0
406                }
407
408                #[doc = "Sets the inner representation of `" $ty "`."]
409                pub fn set_inner(&mut self, val: bool) {
410                    self.0 = val;
411                }
412
413                #[doc = "Converts into the inner representation of `" $ty "`."]
414                pub fn into_inner(self) -> bool {
415                    self.0
416                }
417            }
418
419            $crate::impl_xfs_bool!($ty, $name);
420
421            impl ::std::fmt::Display for $ty {
422                fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
423                    write!(f, "{}", self.inner())
424                }
425            }
426        }
427    }
428}
429
430/// Common functionality for XFS `boolean` types.
431#[macro_export]
432macro_rules! impl_xfs_bool {
433    ($ty:ident, $name:expr) => {
434        impl $ty {
435            /// Gets the [XfsMember](crate::xfs::xfs_struct::XfsMember) name.
436            pub const fn xfs_name() -> &'static str {
437                $name
438            }
439        }
440
441        impl From<bool> for $ty {
442            fn from(val: bool) -> Self {
443                Self::create(val)
444            }
445        }
446
447        impl From<&bool> for $ty {
448            fn from(val: &bool) -> Self {
449                (*val).into()
450            }
451        }
452
453        impl From<u8> for $ty {
454            fn from(val: u8) -> Self {
455                Self::create(val != 0)
456            }
457        }
458
459        impl From<&u8> for $ty {
460            fn from(val: &u8) -> Self {
461                (*val).into()
462            }
463        }
464
465        impl From<&$ty> for bool {
466            fn from(val: &$ty) -> Self {
467                val.inner()
468            }
469        }
470
471        impl From<$ty> for bool {
472            fn from(val: $ty) -> Self {
473                (&val).into()
474            }
475        }
476
477        impl From<&$ty> for u8 {
478            fn from(val: &$ty) -> Self {
479                val.inner() as u8
480            }
481        }
482
483        impl From<$ty> for u8 {
484            fn from(val: $ty) -> Self {
485                (&val).into()
486            }
487        }
488
489        impl From<&$ty> for $crate::xfs::value::XfsValue {
490            fn from(val: &$ty) -> Self {
491                Self::new().with_boolean(val.into())
492            }
493        }
494
495        impl From<$ty> for $crate::xfs::value::XfsValue {
496            fn from(val: $ty) -> Self {
497                (&val).into()
498            }
499        }
500
501        impl TryFrom<&$crate::xfs::value::XfsValue> for $ty {
502            type Error = $crate::Error;
503
504            fn try_from(val: &$crate::xfs::value::XfsValue) -> $crate::Result<Self> {
505                let name = $ty::xfs_name();
506                Ok(val
507                    .boolean()
508                    .ok_or($crate::Error::Xfs(format!(
509                        "Expected {name} XfsValue, have: {val}"
510                    )))?
511                    .into())
512            }
513        }
514
515        impl TryFrom<$crate::xfs::value::XfsValue> for $ty {
516            type Error = $crate::Error;
517
518            fn try_from(val: $crate::xfs::value::XfsValue) -> $crate::Result<Self> {
519                (&val).try_into()
520            }
521        }
522
523        impl From<&$ty> for $crate::xfs::xfs_struct::XfsMember {
524            fn from(val: &$ty) -> Self {
525                $crate::xfs::xfs_struct::XfsMember::create($ty::xfs_name(), val.into())
526            }
527        }
528
529        impl From<$ty> for $crate::xfs::xfs_struct::XfsMember {
530            fn from(val: $ty) -> Self {
531                (&val).into()
532            }
533        }
534
535        impl TryFrom<&$crate::xfs::xfs_struct::XfsMember> for $ty {
536            type Error = $crate::Error;
537
538            fn try_from(val: &$crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
539                let name = $ty::xfs_name();
540                match (val.name(), val.value().boolean()) {
541                    (n, Some(v)) if n == name => Ok(v.into()),
542                    _ => Err($crate::Error::Xfs(format!(
543                        "Expected {name} XfsMember, have: {val}"
544                    ))),
545                }
546            }
547        }
548
549        impl TryFrom<$crate::xfs::xfs_struct::XfsMember> for $ty {
550            type Error = $crate::Error;
551
552            fn try_from(val: $crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
553                (&val).try_into()
554            }
555        }
556    };
557}
558
559/// Creates an XFS `struct` type.
560///
561/// ## Parameters:
562///
563/// - `$ty`: the type name of the Rust struct.
564/// - `$name`: the XFS name of the Rust struct.
565/// - `[$field_name: $field_ty]`: list of the Rust struct's field names and types.
566///
567/// **NOTE** all fields must implement `xfs_name`, and convert to/from
568/// [XfsMember](crate::xfs::xfs_struct::XfsMember).
569#[macro_export]
570macro_rules! create_xfs_struct {
571    ($ty:ident, $name:expr, [$($field_name:ident: $field_ty:ident),*], $doc:expr) => {
572        ::paste::paste! {
573            #[doc = $doc]
574            #[repr(C)]
575            #[derive(Clone, Debug, PartialEq)]
576            pub struct $ty {
577                $($field_name: $field_ty),*
578            }
579
580            impl $ty {
581                #[doc = "Creates a new [" $ty "]."]
582                pub const fn new() -> Self {
583                    Self {
584                        $($field_name: $field_ty::new()),*
585                    }
586                }
587
588                $(
589                #[doc = "Gets the [" $field_ty "] for [" $ty "]."]
590                pub const fn $field_name(&self) -> &$field_ty {
591                    &self.$field_name
592                }
593
594                #[doc = "Sets the [" $field_ty "] for [" $ty "]."]
595                pub fn [<set_ $field_name>](&mut self, val: $field_ty) {
596                    self.$field_name = val;
597                }
598
599                #[doc = "Builder function that sets the [" $field_ty "] for [" $ty "]."]
600                pub fn [<with_ $field_name>](mut self, val: $field_ty) -> Self {
601                    self.[<set_ $field_name>](val);
602                    self
603                }
604                )*
605            }
606
607            impl ::std::fmt::Display for $ty {
608                fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
609                    write!(f, "{{")?;
610                    write!(f, r#""name": "{}""#, $name)?;
611                    $(
612                    write!(f, r#","{}": {}"#, stringify!($field_name), self.$field_name)?;
613                    )*
614                    write!(f, "}}")
615                }
616            }
617
618            impl Default for $ty {
619                fn default() -> Self {
620                    $ty::new()
621                }
622            }
623
624            $crate::impl_xfs_struct!($ty, $name, [$($field_name: $field_ty),*]);
625        }
626    }
627}
628
629/// Common functionality for XFS `struct` types.
630///
631/// ## Parameters:
632///
633/// - `$ty`: the type name of the Rust struct.
634/// - `$name`: the XFS name of the Rust struct.
635/// - `[$field_name: $field_ty]`: list of the Rust struct's field names and types.
636///
637/// **NOTE** all fields must implement `xfs_name`, and convert to/from
638/// [XfsMember](crate::xfs::xfs_struct::XfsMember).
639#[macro_export]
640macro_rules! impl_xfs_struct {
641    ($ty:ident, $name:expr, [$($field_name:ident: $field_ty:ident),*]) => {
642        impl $ty {
643            /// Gets the [XfsMember](crate::xfs::xfs_struct::XfsMember) name.
644            pub const fn xfs_name() -> &'static str {
645                $name
646            }
647        }
648
649        impl From<&$ty> for $crate::xfs::xfs_struct::XfsStruct {
650            fn from(val: &$ty) -> Self {
651                Self::create([
652                    $(val.$field_name.clone().into(),)*
653                ])
654            }
655        }
656
657        impl From<$ty> for $crate::xfs::xfs_struct::XfsStruct {
658            fn from(val: $ty) -> Self {
659                (&val).into()
660            }
661        }
662
663        impl TryFrom<&$crate::xfs::xfs_struct::XfsStruct> for $ty {
664            type Error = $crate::Error;
665
666            #[allow(clippy::needless_update)]
667            fn try_from(val: &$crate::xfs::xfs_struct::XfsStruct) -> $crate::Result<Self> {
668                Ok(Self {
669                    $(
670                        $field_name: match val.find_member($field_ty::xfs_name()) {
671                            Ok(m) => m.try_into()?,
672                            Err(_err) => {
673                                ::log::warn!("Missing member {} from {}", stringify!($field_name), stringify!($ty));
674                                $field_ty::new()
675                            }
676                        },
677                    )*
678                    ..Default::default()
679                })
680            }
681        }
682
683        impl TryFrom<$crate::xfs::xfs_struct::XfsStruct> for $ty {
684            type Error = $crate::Error;
685
686            fn try_from(val: $crate::xfs::xfs_struct::XfsStruct) -> $crate::Result<Self> {
687                (&val).try_into()
688            }
689        }
690
691        impl From<&$ty> for $crate::xfs::value::XfsValue {
692            fn from(val: &$ty) -> Self {
693                Self::new().with_xfs_struct(val.into())
694            }
695        }
696
697        impl From<$ty> for $crate::xfs::value::XfsValue {
698            fn from(val: $ty) -> Self {
699                (&val).into()
700            }
701        }
702
703        impl TryFrom<&$crate::xfs::value::XfsValue> for $ty {
704            type Error = $crate::Error;
705
706            fn try_from(val: &$crate::xfs::value::XfsValue) -> $crate::Result<Self> {
707                let name = $ty::xfs_name();
708                val
709                    .xfs_struct()
710                    .ok_or($crate::Error::Xfs(format!(
711                        "Expected {name} XfsValue, have: {val}"
712                    )))?
713                    .try_into()
714            }
715        }
716
717        impl TryFrom<$crate::xfs::value::XfsValue> for $ty {
718            type Error = $crate::Error;
719
720            fn try_from(val: $crate::xfs::value::XfsValue) -> $crate::Result<Self> {
721                (&val).try_into()
722            }
723        }
724
725        impl From<&$ty> for $crate::xfs::xfs_struct::XfsMember {
726            fn from(val: &$ty) -> Self {
727                $crate::xfs::xfs_struct::XfsMember::create($ty::xfs_name(), val.into())
728            }
729        }
730
731        impl From<$ty> for $crate::xfs::xfs_struct::XfsMember {
732            fn from(val: $ty) -> Self {
733                (&val).into()
734            }
735        }
736
737        impl TryFrom<&$crate::xfs::xfs_struct::XfsMember> for $ty {
738            type Error = $crate::Error;
739
740            fn try_from(val: &$crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
741                let name = $ty::xfs_name();
742                match (val.name(), val.value().xfs_struct()) {
743                    (n, Some(v)) if n == name => v.try_into(),
744                    _ => Err($crate::Error::Xfs(format!(
745                        "Expected {name} XfsMember, have: {val}"
746                    ))),
747                }
748            }
749        }
750
751        impl TryFrom<$crate::xfs::xfs_struct::XfsMember> for $ty {
752            type Error = $crate::Error;
753
754            fn try_from(val: $crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
755                (&val).try_into()
756            }
757        }
758    };
759}
760
761#[macro_export]
762macro_rules! create_xfs_array {
763    ($ty:ident, $name:expr, $item:ident, $len:expr, $default:expr, $doc:expr) => {
764        ::paste::paste! {
765            #[doc = $doc]
766            #[repr(C)]
767            #[derive(Clone, Debug, PartialEq)]
768            pub struct $ty{
769                size: usize,
770                items: [$item; $len],
771            }
772
773            impl $ty {
774                #[doc = "Creates a new [" $ty "]."]
775                pub const fn new() -> Self {
776                    Self {
777                        size: 0,
778                        items: [$default; $len],
779                    }
780                }
781
782                #[doc = "Gets the maximum number of [" $ty "] items."]
783                pub const fn max_size() -> usize {
784                    $len
785                }
786
787                #[doc = "Gets the size of the [" $ty "]."]
788                pub const fn size(&self) -> usize {
789                    self.size
790                }
791
792                #[doc = "Sets the size of the [" $ty "]."]
793                #[doc = ""]
794                #[doc = "No-op if `val` is larger than [" $ty "]."]
795                pub fn set_size(&mut self, val: u32) {
796                    let size = val as usize;
797                    if size <= $len {
798                        self.size = size;
799                    }
800                }
801
802                #[doc = "Builder function that sets the size of the [" $ty "]."]
803                #[doc = ""]
804                #[doc = "No-op if `val` is larger than [" $ty "]."]
805                pub fn with_size(mut self, val: u32) -> Self {
806                    self.set_size(val);
807                    self
808                }
809
810                #[doc = "Gets a reference to the list of set [" $ty "] items."]
811                pub fn items(&self) -> &[$item] {
812                    let len = ::std::cmp::min(self.size, $len);
813                    self.items[..len].as_ref()
814                }
815
816                #[doc = "Sets the list of [" $ty "] items."]
817                pub fn set_items(&mut self, val: &[$item]) {
818                    let len = ::std::cmp::min(val.len(), $len);
819                    self.items[..len]
820                        .iter_mut()
821                        .zip(val[..len].iter())
822                        .for_each(|(dst, src)| *dst = src.clone());
823                    self.items[len..]
824                        .iter_mut()
825                        .for_each(|item| *item = $item::new());
826                    self.size = len;
827                }
828
829                #[doc = "Builder function that sets the list of [" $ty "] items."]
830                pub fn with_items(mut self, val: &[$item]) -> Self {
831                    self.set_items(val);
832                    self
833                }
834
835                #[doc = "Pushes a [" $ty "] onto the end of the list."]
836                #[doc = ""]
837                #[doc = "No-op if the list is at capacity."]
838                pub fn push_item(&mut self, val: $item) {
839                    if self.size < $len {
840                        self.items[self.size] = val;
841                        self.size += 1;
842                    }
843                }
844            }
845
846            impl Default for $ty {
847                fn default() -> Self {
848                    Self::new()
849                }
850            }
851
852            impl ::std::fmt::Display for $ty {
853                fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
854                    write!(f, r#"{{"items":["#)?;
855                    for (i, item) in self.items().iter().enumerate() {
856                        if i != 0 {
857                            write!(f, ",")?;
858                        }
859                        write!(f, "{item}")?;
860                    }
861                    write!(f, "]}}")
862                }
863            }
864
865            $crate::impl_xfs_array!($ty, $name);
866        }
867    };
868}
869
870/// Common functionality for XFS `struct` types.
871///
872/// ## Parameters:
873///
874/// - `$ty`: the type name of the Rust struct.
875/// - `$name`: the XFS name of the Rust struct.
876///
877/// **NOTE** inner items must convert to/from [XfsValue](crate::xfs::value::XfsValue).
878#[macro_export]
879macro_rules! impl_xfs_array {
880    ($ty:ident, $name:expr) => {
881        impl $ty {
882            /// Gets the [XfsMember](crate::xfs::xfs_struct::XfsMember) name.
883            pub const fn xfs_name() -> &'static str {
884                $name
885            }
886        }
887
888        impl From<&$ty> for $crate::xfs::array::XfsArray {
889            fn from(val: &$ty) -> Self {
890                Self::create(val.items().iter().map($crate::xfs::value::XfsValue::from))
891            }
892        }
893
894        impl From<$ty> for $crate::xfs::array::XfsArray {
895            fn from(val: $ty) -> Self {
896                (&val).into()
897            }
898        }
899
900        impl TryFrom<&$crate::xfs::array::XfsArray> for $ty {
901            type Error = $crate::Error;
902
903            fn try_from(val: &$crate::xfs::array::XfsArray) -> $crate::Result<Self> {
904                let data = val.data();
905                let mut res = $ty::new();
906
907                // FIXME: this could be an issue for dynamic-length collection types (Vec, etc.).
908                // Dynamic-length types initialize to zero length, and would require pushing items from `data`.
909                // Currently, all types converting to/from XfsArray are fixed-length.
910                let len = ::std::cmp::min($ty::max_size(), data.len());
911                for (i, (dst, src)) in res.items[..len]
912                    .iter_mut()
913                    .zip(data[..len].iter().map(|m| m.inner()))
914                    .enumerate()
915                {
916                    match src.try_into() {
917                        Ok(d) => *dst = d,
918                        Err(err) => log::warn!("Failed to convert item[{i}]: {err}"),
919                    }
920                }
921
922                res.set_size(len as u32);
923
924                Ok(res)
925            }
926        }
927
928        impl TryFrom<$crate::xfs::array::XfsArray> for $ty {
929            type Error = $crate::Error;
930
931            fn try_from(val: $crate::xfs::array::XfsArray) -> $crate::Result<Self> {
932                (&val).try_into()
933            }
934        }
935
936        impl From<&$ty> for $crate::xfs::value::XfsValue {
937            fn from(val: &$ty) -> Self {
938                Self::new().with_array(val.into())
939            }
940        }
941
942        impl From<$ty> for $crate::xfs::value::XfsValue {
943            fn from(val: $ty) -> Self {
944                (&val).into()
945            }
946        }
947
948        impl TryFrom<&$crate::xfs::value::XfsValue> for $ty {
949            type Error = $crate::Error;
950
951            fn try_from(val: &$crate::xfs::value::XfsValue) -> $crate::Result<Self> {
952                let name = $ty::xfs_name();
953                val.array()
954                    .ok_or($crate::Error::Xfs(format!(
955                        "Expected {name} XfsValue, have: {val}"
956                    )))?
957                    .try_into()
958            }
959        }
960
961        impl TryFrom<$crate::xfs::value::XfsValue> for $ty {
962            type Error = $crate::Error;
963
964            fn try_from(val: $crate::xfs::value::XfsValue) -> $crate::Result<Self> {
965                (&val).try_into()
966            }
967        }
968
969        impl From<&$ty> for $crate::xfs::xfs_struct::XfsMember {
970            fn from(val: &$ty) -> Self {
971                $crate::xfs::xfs_struct::XfsMember::create($ty::xfs_name(), val.into())
972            }
973        }
974
975        impl From<$ty> for $crate::xfs::xfs_struct::XfsMember {
976            fn from(val: $ty) -> Self {
977                (&val).into()
978            }
979        }
980
981        impl TryFrom<&$crate::xfs::xfs_struct::XfsMember> for $ty {
982            type Error = $crate::Error;
983
984            fn try_from(val: &$crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
985                let name = $ty::xfs_name();
986                match (val.name(), val.value().array()) {
987                    (n, Some(v)) if n == name => v.try_into(),
988                    _ => Err($crate::Error::Xfs(format!(
989                        "Expected {name} XfsMember, have: {val}"
990                    ))),
991                }
992            }
993        }
994
995        impl TryFrom<$crate::xfs::xfs_struct::XfsMember> for $ty {
996            type Error = $crate::Error;
997
998            fn try_from(val: $crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
999                (&val).try_into()
1000            }
1001        }
1002    };
1003}
1004
1005#[macro_export]
1006macro_rules! create_xfs_string {
1007    ($ty:ident, $name:expr, $doc:expr) => {
1008        ::paste::paste! {
1009            #[doc = $doc]
1010            #[derive(Clone, Debug, Eq, PartialEq)]
1011            pub struct $ty(String);
1012
1013            impl $ty {
1014                #[doc = "Creates a new [" $ty "]."]
1015                pub const fn new() -> Self {
1016                    Self(String::new())
1017                }
1018
1019                #[doc = "Gets a reference to the [" $ty "] inner representation."]
1020                pub fn inner(&self) -> &str {
1021                    self.0.as_str()
1022                }
1023
1024                #[doc = "Sets the [" $ty "] inner representation value."]
1025                pub fn set_inner(&mut self, val: &str) {
1026                    self.0 = val.into();
1027                }
1028
1029                #[doc = "Builder function that sets the [" $ty "] inner representation value."]
1030                pub fn with_inner(mut self, val: &str) -> Self {
1031                    self.set_inner(val);
1032                    self
1033                }
1034
1035                #[doc = "Converts the [" $ty "] into the inner representation."]
1036                pub fn into_inner(self) -> String {
1037                    self.0
1038                }
1039            }
1040        }
1041
1042        impl Default for $ty {
1043            fn default() -> Self {
1044                Self::new()
1045            }
1046        }
1047
1048        impl ::std::fmt::Display for $ty {
1049            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
1050                write!(f, r#""{}""#, self.0)
1051            }
1052        }
1053
1054        $crate::impl_xfs_string!($ty, $name);
1055    };
1056}
1057
1058/// Common functionality for XFS `string` types.
1059#[macro_export]
1060macro_rules! impl_xfs_string {
1061    ($ty:ident, $name:expr) => {
1062        impl $ty {
1063            /// Gets the [XfsMember](crate::xfs::xfs_struct::XfsMember) name.
1064            pub const fn xfs_name() -> &'static str {
1065                $name
1066            }
1067        }
1068
1069        impl From<&str> for $ty {
1070            fn from(val: &str) -> Self {
1071                Self(val.into())
1072            }
1073        }
1074
1075        impl From<String> for $ty {
1076            fn from(val: String) -> Self {
1077                Self(val)
1078            }
1079        }
1080
1081        impl From<&$ty> for String {
1082            fn from(val: &$ty) -> Self {
1083                val.inner().into()
1084            }
1085        }
1086
1087        impl From<$ty> for String {
1088            fn from(val: $ty) -> Self {
1089                val.into_inner()
1090            }
1091        }
1092
1093        impl From<&$ty> for $crate::xfs::value::XfsValue {
1094            fn from(val: &$ty) -> Self {
1095                Self::new().with_string(val.inner())
1096            }
1097        }
1098
1099        impl From<$ty> for $crate::xfs::value::XfsValue {
1100            fn from(val: $ty) -> Self {
1101                Self::new().with_string(val.into_inner())
1102            }
1103        }
1104
1105        impl TryFrom<&$crate::xfs::value::XfsValue> for $ty {
1106            type Error = $crate::Error;
1107
1108            fn try_from(val: &$crate::xfs::value::XfsValue) -> $crate::Result<Self> {
1109                Ok(val.string().unwrap_or("").into())
1110            }
1111        }
1112
1113        impl TryFrom<$crate::xfs::value::XfsValue> for $ty {
1114            type Error = $crate::Error;
1115
1116            fn try_from(val: $crate::xfs::value::XfsValue) -> $crate::Result<Self> {
1117                (&val).try_into()
1118            }
1119        }
1120
1121        impl From<&$ty> for $crate::xfs::xfs_struct::XfsMember {
1122            fn from(val: &$ty) -> Self {
1123                $crate::xfs::xfs_struct::XfsMember::create($ty::xfs_name(), val.into())
1124            }
1125        }
1126
1127        impl From<$ty> for $crate::xfs::xfs_struct::XfsMember {
1128            fn from(val: $ty) -> Self {
1129                (&val).into()
1130            }
1131        }
1132
1133        impl TryFrom<&$crate::xfs::xfs_struct::XfsMember> for $ty {
1134            type Error = $crate::Error;
1135
1136            fn try_from(val: &$crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
1137                let name = $ty::xfs_name();
1138                match (val.name(), val.value().string()) {
1139                    (n, Some(v)) if n == name => Ok(v.into()),
1140                    (n, None) if n == name => Ok("".into()),
1141                    _ => Err($crate::Error::Xfs(format!(
1142                        "Expected {name} XfsMember, have: {val}"
1143                    ))),
1144                }
1145            }
1146        }
1147
1148        impl TryFrom<$crate::xfs::xfs_struct::XfsMember> for $ty {
1149            type Error = $crate::Error;
1150
1151            fn try_from(val: $crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
1152                (&val).try_into()
1153            }
1154        }
1155    };
1156}
1157
1158#[macro_export]
1159macro_rules! create_xfs_date_time {
1160    ($ty:ident, $name:expr, $doc:expr) => {
1161        ::paste::paste! {
1162            #[doc = $doc]
1163            #[derive(Clone, Debug, Eq, PartialEq)]
1164            pub struct $ty(String);
1165
1166            impl $ty {
1167                #[doc = "Creates a new [" $ty "]."]
1168                pub const fn new() -> Self {
1169                    Self(String::new())
1170                }
1171
1172                #[doc = "Gets a reference to the [" $ty "] inner representation."]
1173                pub fn inner(&self) -> &str {
1174                    self.0.as_str()
1175                }
1176
1177                #[doc = "Sets the [" $ty "] inner representation value."]
1178                pub fn set_inner(&mut self, val: &str) {
1179                    self.0 = val.into();
1180                }
1181
1182                #[doc = "Builder function that sets the [" $ty "] inner representation value."]
1183                pub fn with_inner(mut self, val: &str) -> Self {
1184                    self.set_inner(val);
1185                    self
1186                }
1187
1188                #[doc = "Converts the [" $ty "] into the inner representation."]
1189                pub fn into_inner(self) -> String {
1190                    self.0
1191                }
1192            }
1193        }
1194
1195        impl Default for $ty {
1196            fn default() -> Self {
1197                Self::new()
1198            }
1199        }
1200
1201        impl TryFrom<&$ty> for ::time::OffsetDateTime {
1202            type Error = $crate::Error;
1203
1204            fn try_from(val: &$ty) -> $crate::Result<Self> {
1205                let date_str = val.inner();
1206                if date_str.len() < 17 {
1207                    Err($crate::Error::DateTime(format!(
1208                        "invalid ISO-8601 DateTime, too short: {date_str}"
1209                    )))
1210                } else {
1211                    let mut date_string = date_str.to_string();
1212
1213                    date_string.insert(6, '-');
1214                    date_string.insert(4, '-');
1215
1216                    date_string += "+00:00";
1217
1218                    ::log::debug!("Formatted DateTime: {date_string}");
1219
1220                    Ok(Self::parse(
1221                        date_string.as_str(),
1222                        &::time::format_description::well_known::Iso8601::DATE_TIME,
1223                    )?)
1224                }
1225            }
1226        }
1227
1228        impl ::std::fmt::Display for $ty {
1229            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
1230                write!(f, r#""{}""#, self.0)
1231            }
1232        }
1233
1234        $crate::impl_xfs_date_time!($ty, $name);
1235    };
1236}
1237
1238/// Common functionality for XFS `dateTime` types.
1239#[macro_export]
1240macro_rules! impl_xfs_date_time {
1241    ($ty:ident, $name:expr) => {
1242        impl $ty {
1243            /// Gets the [XfsMember](crate::xfs::xfs_struct::XfsMember) name.
1244            pub const fn xfs_name() -> &'static str {
1245                $name
1246            }
1247        }
1248
1249        impl From<&str> for $ty {
1250            fn from(val: &str) -> Self {
1251                Self(val.into())
1252            }
1253        }
1254
1255        impl From<String> for $ty {
1256            fn from(val: String) -> Self {
1257                Self(val)
1258            }
1259        }
1260
1261        impl From<&$ty> for String {
1262            fn from(val: &$ty) -> Self {
1263                val.inner().into()
1264            }
1265        }
1266
1267        impl From<$ty> for String {
1268            fn from(val: $ty) -> Self {
1269                val.into_inner()
1270            }
1271        }
1272
1273        impl From<&$ty> for $crate::xfs::value::XfsValue {
1274            fn from(val: &$ty) -> Self {
1275                Self::new().with_date_time(val.inner())
1276            }
1277        }
1278
1279        impl From<$ty> for $crate::xfs::value::XfsValue {
1280            fn from(val: $ty) -> Self {
1281                Self::new().with_date_time(val.into_inner())
1282            }
1283        }
1284
1285        impl TryFrom<&$crate::xfs::value::XfsValue> for $ty {
1286            type Error = $crate::Error;
1287
1288            fn try_from(val: &$crate::xfs::value::XfsValue) -> $crate::Result<Self> {
1289                Ok(val.date_time().unwrap_or("").into())
1290            }
1291        }
1292
1293        impl TryFrom<$crate::xfs::value::XfsValue> for $ty {
1294            type Error = $crate::Error;
1295
1296            fn try_from(val: $crate::xfs::value::XfsValue) -> $crate::Result<Self> {
1297                (&val).try_into()
1298            }
1299        }
1300
1301        impl From<&$ty> for $crate::xfs::xfs_struct::XfsMember {
1302            fn from(val: &$ty) -> Self {
1303                $crate::xfs::xfs_struct::XfsMember::create($ty::xfs_name(), val.into())
1304            }
1305        }
1306
1307        impl From<$ty> for $crate::xfs::xfs_struct::XfsMember {
1308            fn from(val: $ty) -> Self {
1309                (&val).into()
1310            }
1311        }
1312
1313        impl TryFrom<&$crate::xfs::xfs_struct::XfsMember> for $ty {
1314            type Error = $crate::Error;
1315
1316            fn try_from(val: &$crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
1317                let name = $ty::xfs_name();
1318                match (val.name(), val.value().date_time()) {
1319                    (n, Some(v)) if n == name => Ok(v.into()),
1320                    (n, None) if n == name => Ok("".into()),
1321                    _ => Err($crate::Error::Xfs(format!(
1322                        "Expected {name} XfsMember, have: {val}"
1323                    ))),
1324                }
1325            }
1326        }
1327
1328        impl TryFrom<$crate::xfs::xfs_struct::XfsMember> for $ty {
1329            type Error = $crate::Error;
1330
1331            fn try_from(val: $crate::xfs::xfs_struct::XfsMember) -> $crate::Result<Self> {
1332                (&val).try_into()
1333            }
1334        }
1335    };
1336}