userspace/macros/enums/
opted.rs

1#[macro_export]
2macro_rules! enum_opted {
3    ($enum_vis:vis $enum_identifier:ident, $enum_discriminant_type:ty, [$([$variant_discriminant:expr,$variant_identifier:ident,$variant_type:ty]),* $(,)? ]) => {
4        #[derive(Debug, Clone, Copy)]
5        $enum_vis enum $enum_identifier {
6            $($variant_identifier($variant_type)),*
7        }
8
9        impl $enum_identifier {
10            pub fn discriminant(&self) -> $enum_discriminant_type {
11                match self {
12                    $($enum_identifier::$variant_identifier(_) => $variant_discriminant),*
13                }
14            }
15        }
16
17        impl traits::Bytes<crate::Origin,crate::Origin> for $enum_identifier {
18            const BYTES_SIZE : usize = <$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE + expressions_upperbound!($(<Option<$variant_type> as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE),*);
19            fn to_bytes(&self, endianness: bool) -> [u8;Self::BYTES_SIZE] {
20                let mut bytes = [0u8;Self::BYTES_SIZE];
21
22                match self {
23                    $(
24                        Self::$variant_identifier(payload) => {
25                            let discriminant = self.discriminant();
26
27                            let mut o = 0;
28                            bytes[o..(o+<$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE)].copy_from_slice(
29                                &if endianness {
30                                    <$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::to_le_bytes(&discriminant)
31                                } else {
32                                    <$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::to_be_bytes(&discriminant)
33                                }
34                            );
35                            o = o + <$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE;
36                            bytes[o..(o+<$variant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE)].copy_from_slice(
37                                &if endianness {
38                                    <$variant_type as traits::Bytes<crate::Origin,crate::Origin>>::to_le_bytes(payload)
39                                } else {
40                                    <$variant_type as traits::Bytes<crate::Origin,crate::Origin>>::to_be_bytes(payload)
41                                }
42                            );
43                            bytes
44                        }
45                    ),*
46                }
47            }
48
49            fn from_bytes(bytes: [u8;Self::BYTES_SIZE], endianness: bool) -> Self {
50                let mut o = 0;
51                let mut discriminant_bytes = [0u8; <$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE];
52                discriminant_bytes.copy_from_slice(&bytes[o..(o+<$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE)]);
53                let discriminant = if endianness {
54                    <$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::from_le_bytes(discriminant_bytes)
55                } else {
56                    <$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::from_be_bytes(discriminant_bytes)
57                };
58                o = o + <$enum_discriminant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE;
59                match discriminant {
60                    $(
61                        $variant_discriminant => {
62                            Self::$variant_identifier({
63                                let mut payload = [0u8; <$variant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE];
64                                payload.copy_from_slice(&bytes[o..(o+<$variant_type as traits::Bytes<crate::Origin,crate::Origin>>::BYTES_SIZE)]);
65                                if endianness {
66                                    <$variant_type as traits::Bytes<crate::Origin,crate::Origin>>::from_le_bytes(payload)
67                                } else {
68                                    <$variant_type as traits::Bytes<crate::Origin,crate::Origin>>::from_be_bytes(payload)
69                                }
70                            })
71                        },
72                    )*
73                    _ => unreachable!()
74                }
75
76            }
77        }
78    };
79}
80pub use enum_opted;