Last active
September 15, 2024 22:29
-
-
Save novafacing/aad21dcad051c6f2f616895844eceef7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #[macro_export] | |
| // https://stackoverflow.com/a/70222282 | |
| macro_rules! field_size { | |
| ($t:ident :: $field:ident) => {{ | |
| let m = core::mem::MaybeUninit::<$t>::uninit(); | |
| // According to https://doc.rust-lang.org/stable/std/ptr/macro.addr_of_mut.html#examples, | |
| // you can dereference an uninitialized MaybeUninit pointer in addr_of! | |
| // Raw pointer deref in const contexts is stabilized in 1.58: | |
| // https://github.com/rust-lang/rust/pull/89551 | |
| let p = unsafe { core::ptr::addr_of!((*(&m as *const _ as *const $t)).$field) }; | |
| const fn size_of_raw<T>(_: *const T) -> usize { | |
| core::mem::size_of::<T>() | |
| } | |
| size_of_raw(p) | |
| }}; | |
| } | |
| #[macro_export] | |
| macro_rules! from_primitive_patterns { | |
| { | |
| $match_ty:ty, | |
| $match_val:expr, | |
| @parse {$($eout:tt)*}, | |
| #[$variant_meta:meta] $($rest:tt)* | |
| } => { | |
| $crate::from_primitive_patterns! { | |
| $match_ty, | |
| $match_val, | |
| @parse { | |
| $($eout)* | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $match_ty:ty, | |
| $match_val:expr, | |
| @parse {$($eout:tt)*}, | |
| $variant:ident = $value:expr, | |
| $($rest:tt)* | |
| } => { | |
| $crate::from_primitive_patterns! { | |
| $match_ty, | |
| $match_val, | |
| @parse { | |
| $($eout)* | |
| if ($value as $match_ty) == $match_val { | |
| return Some(Self::$variant); | |
| } | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $match_ty:ty, | |
| $match_val:expr, | |
| @parse {$($eout:tt)*}, | |
| $variant:ident($param:ty), | |
| $($rest:tt)* | |
| } => { | |
| $crate::from_primitive_patterns! { | |
| $match_ty, | |
| $match_val, | |
| @parse { | |
| $($eout)* | |
| Some(Self::$variant($match_val as $param)) | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $match_ty:ty, | |
| $match_val:expr, | |
| @parse {$($eout:tt)*}, | |
| } => { | |
| $($eout)* | |
| }; | |
| } | |
| #[macro_export] | |
| macro_rules! to_primitive_patterns { | |
| { | |
| $self:ident, | |
| $match_ty:ty, | |
| @parse {$($eout:tt)*}, | |
| #[$variant_meta:meta] $($rest:tt)* | |
| } => { | |
| $crate::to_primitive_patterns! { | |
| $self, | |
| $match_ty, | |
| @parse { | |
| $($eout)* | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $self:ident, | |
| $match_ty:ty, | |
| @parse {$($eout:tt)*}, | |
| $variant:ident = $value:expr, | |
| $($rest:tt)* | |
| } => { | |
| $crate::to_primitive_patterns! { | |
| $self, | |
| $match_ty, | |
| @parse { | |
| $($eout)* | |
| Self::$variant => Some($value as $match_ty), | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $self:ident, | |
| $match_ty:ty, | |
| @parse {$($eout:tt)*}, | |
| $variant:ident($param:ty), | |
| $($rest:tt)* | |
| } => { | |
| $crate::to_primitive_patterns! { | |
| $self, | |
| $match_ty, | |
| @parse { | |
| $($eout)* | |
| Self::$variant(value) => Some(*value as $match_ty), | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $self:ident, | |
| $match_ty:ty, | |
| @parse {$($eout:tt)*}, | |
| } => { | |
| match $self { | |
| $($eout)* | |
| } | |
| }; | |
| } | |
| #[macro_export] | |
| macro_rules! parse_enum_variant { | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*}, | |
| #[$variant_meta:meta] $($rest:tt)* | |
| } => { | |
| $crate::parse_enum_variant! { | |
| $(#[$enum_meta])*, | |
| $vis, | |
| $name, | |
| $(<$($generic_param),*>)?, | |
| @where_clauses {$($where)*}, | |
| @parse { | |
| $($eout)* | |
| #[$variant_meta] | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*}, | |
| $variant:ident, | |
| $($rest:tt)* | |
| } => { | |
| $crate::parse_enum_variant! { | |
| $(#[$enum_meta])*, | |
| $vis, | |
| $name, | |
| $(<$($generic_param),*>)?, | |
| @where_clauses {$($where)*}, | |
| @parse { | |
| $($eout)* | |
| $variant, | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*}, | |
| $variant:ident = $value:expr, | |
| $($rest:tt)* | |
| } => { | |
| $crate::parse_enum_variant!{ | |
| $(#[$enum_meta])*, | |
| $vis, | |
| $name, | |
| $(<$($generic_param),*>)?, | |
| @where_clauses {$($where)*}, | |
| @parse { | |
| $($eout)* | |
| $variant = $value, | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*}, | |
| $variant:ident($param:ty), | |
| $($rest:tt)* | |
| } => { | |
| $crate::parse_enum_variant!{ | |
| $(#[$enum_meta])*, | |
| $vis, | |
| $name, | |
| $(<$($generic_param),*>)?, | |
| @where_clauses {$($where)*}, | |
| @parse { | |
| $($eout)* | |
| $variant($param), | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*}, | |
| $variant:ident { $($fields:tt)* }, | |
| $($rest:tt)* | |
| } => { | |
| $crate::parse_enum_variant!{ | |
| $(#[$enum_meta])*, | |
| $vis, | |
| $name, | |
| $(<$($generic_param),*>)?, | |
| @where_clauses {$($where)*}, | |
| @parse { | |
| $($eout)* | |
| $variant { $($fields)* }, | |
| }, | |
| $($rest)* | |
| } | |
| }; | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*} $(,)* | |
| } => { | |
| $(#[$enum_meta])* | |
| $vis enum $name | |
| $(<$($generic_param),*>)? | |
| $($where)* | |
| { | |
| $($eout)* | |
| } | |
| impl $(<$($generic_param),*>)? num_traits::FromPrimitive for $name $(<$($generic_param),*>)? $($where:tt)* { | |
| fn from_i64(n: i64) -> Option<Self> { | |
| $crate::from_primitive_patterns! { | |
| i64, | |
| n, | |
| @parse {}, | |
| $($eout)* | |
| } | |
| } | |
| fn from_u64(n: u64) -> Option<Self> { | |
| $crate::from_primitive_patterns! { | |
| u64, | |
| n, | |
| @parse {}, | |
| $($eout)* | |
| } | |
| } | |
| } | |
| impl $(<$($generic_param),*>)? num_traits::ToPrimitive for $name $(<$($generic_param),*>)? $($where:tt)* { | |
| fn to_i64(&self) -> Option<i64> { | |
| $crate::to_primitive_patterns! { | |
| self, | |
| i64, | |
| @parse {}, | |
| $($eout)* | |
| } | |
| } | |
| fn to_u64(&self) -> Option<u64> { | |
| $crate::to_primitive_patterns! { | |
| self, | |
| u64, | |
| @parse {}, | |
| $($eout)* | |
| } | |
| } | |
| } | |
| }; | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*} $(,)* | |
| } => { | |
| $(#[$enum_meta])* | |
| $vis enum $name | |
| $(<$($generic_param),*>)? | |
| $($where)* | |
| { | |
| $($eout)* | |
| } | |
| }; | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*} $(,)* | |
| } => { | |
| $(#[$enum_meta])* | |
| $vis enum $name | |
| $(<$($generic_param),*>)? | |
| $($where)* | |
| { | |
| $($eout)* | |
| } | |
| }; | |
| { | |
| $(#[$enum_meta:meta])*, | |
| $vis:vis, | |
| $name:ident, | |
| $(<$($generic_param:tt),*>)?, | |
| @where_clauses {$($where:tt)*}, | |
| @parse {$($eout:tt)*} $(,)* | |
| } => { | |
| $(#[$enum_meta])* | |
| $vis enum $name | |
| $(<$($generic_param),*>)? | |
| $($where)* | |
| { | |
| $($eout)* | |
| } | |
| }; | |
| } | |
| #[macro_export] | |
| /// Add the ability to convert a primitive to an enum with ToPrimitive/FromPrimitive. | |
| /// A trailing 1-element tuple variant is used as a fallback if one is found. | |
| macro_rules! convert_primitive { | |
| ( | |
| $(#[$enum_meta:meta])* | |
| $vis:vis enum $enum_name:ident | |
| $(<$($generic_param:tt),*>)? | |
| { | |
| $($variants:tt)* | |
| } | |
| ) => { | |
| $crate::parse_enum_variant! { | |
| $(#[$enum_meta])*, | |
| $vis, | |
| $enum_name, | |
| $(<$($generic_param),*>)?, | |
| @where_clauses {}, | |
| @parse {}, $($variants)* | |
| } | |
| }; | |
| ( | |
| $(#[$enum_meta:meta])* | |
| $vis:vis enum $enum_name:ident | |
| $(<$($generic_param:tt),*>)? | |
| where | |
| $where_clause:tt $(<$($where_generic_param:tt),*>)?: | |
| $where_clause_bound:tt $(<$($where_clause_bound_generic_param:tt),*>)? | |
| $(+ $where_clause_bound_plus:tt $(<$($where_clause_bound_generic_param_plus:tt),*>)?)* | |
| $(, $more_where_clause:tt $(<$($more_where_generic_param:tt),*>)?: | |
| $more_where_clause_bound:tt $(<$($more_where_clause_bound_generic_param:tt),*>)? | |
| $(+ $more_where_clause_bound_plus:tt $(<$($more_where_clause_bounds_generic_param_plus:tt),*>)?)* )* | |
| { | |
| $($variants:tt)* | |
| } | |
| ) => { | |
| $crate::parse_enum_variant! { | |
| $(#[$enum_meta])*, | |
| $vis, | |
| $enum_name, | |
| $(<$($generic_param),*>)?, | |
| @where_clauses { | |
| where | |
| $where_clause $(<$($where_generic_param),*>)?: | |
| $where_clause_bound $(<$($where_clause_bound_generic_param),*>)? | |
| $(+ $where_clause_bound_plus $(<$($where_clause_bound_generic_param_plus),*>)?)* | |
| $(, $more_where_clause $(<$($more_where_generic_param),*>)?: | |
| $more_where_clause_bound $(<$($more_where_clause_bound_generic_param),*>)? | |
| $(+ $more_where_clause_bound_plus $(<$($more_where_clause_bounds_generic_param_plus),*>)?)* )* | |
| }, | |
| @parse {}, $($variants)* | |
| } | |
| }; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated to not use match() in from_primitive_patterns because it wasn't working with externally-defined constants.