enum-ordinalize-derive-4.3.2/.cargo_vcs_info.json0000644000000001640000000000100154210ustar { "git": { "sha1": "4ce3f4e082629cd859d9cedb7210ecbadbc7b511" }, "path_in_vcs": "enum-ordinalize-derive" }enum-ordinalize-derive-4.3.2/Cargo.lock0000644000000021500000000000100133710ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "enum-ordinalize-derive" version = "4.3.2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "proc-macro2" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] [[package]] name = "syn" version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" enum-ordinalize-derive-4.3.2/Cargo.toml0000644000000026510000000000100134220ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.68" name = "enum-ordinalize-derive" version = "4.3.2" build = false include = [ "src/**/*", "Cargo.toml", "README.md", "LICENSE", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "This crate provides a procedural macro that enables enums to not only obtain the ordinal values of their variants but also allows for the construction of enums from an ordinal value." homepage = "https://magiclen.org/enum-ordinalize" readme = "README.md" keywords = [ "enum", "ordinal", "ordinalize", "number", ] categories = [ "no-std", "rust-patterns", ] license = "MIT" repository = "https://github.com/magiclen/enum-ordinalize" [features] default = [] traits = [] [lib] name = "enum_ordinalize_derive" path = "src/lib.rs" proc-macro = true [dependencies.proc-macro2] version = "1" [dependencies.quote] version = "1" [dependencies.syn] version = "2" enum-ordinalize-derive-4.3.2/Cargo.toml.orig000064400000000000000000000012721046102023000171010ustar 00000000000000[package] name = "enum-ordinalize-derive" version = "4.3.2" edition = "2021" rust-version = "1.68" repository = "https://github.com/magiclen/enum-ordinalize" homepage = "https://magiclen.org/enum-ordinalize" keywords = ["enum", "ordinal", "ordinalize", "number"] categories = ["no-std", "rust-patterns"] description = "This crate provides a procedural macro that enables enums to not only obtain the ordinal values of their variants but also allows for the construction of enums from an ordinal value." license = "MIT" include = ["src/**/*", "Cargo.toml", "README.md", "LICENSE"] [lib] proc-macro = true [dependencies] syn = "2" quote = "1" proc-macro2 = "1" [features] default = [] traits = []enum-ordinalize-derive-4.3.2/LICENSE000064400000000000000000000020661046102023000152210ustar 00000000000000MIT License Copyright (c) 2023 magiclen.org (Ron Li) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. enum-ordinalize-derive-4.3.2/README.md000064400000000000000000000011271046102023000154700ustar 00000000000000Enum Ordinalize Derive ==================== [![CI](https://github.com/magiclen/enum-ordinalize/actions/workflows/ci.yml/badge.svg)](https://github.com/magiclen/enum-ordinalize/actions/workflows/ci.yml) This crate provides a procedural macro that enables enums to not only obtain the ordinal values of their variants but also allows for the construction of enums from an ordinal value. See the [`enum-ordinalize`](https://crates.io/crates/enum-ordinalize) crate. ## Crates.io https://crates.io/crates/enum-ordinalize ## Documentation https://docs.rs/enum-ordinalize ## License [MIT](LICENSE)enum-ordinalize-derive-4.3.2/src/int128.rs000064400000000000000000000077401046102023000164020ustar 00000000000000use core::{ cmp::Ordering, fmt::{self, Display, Formatter}, num::ParseIntError, ops::Neg, str::FromStr, }; #[derive(Debug, Copy, Eq, Clone)] pub(crate) enum Int128 { Signed(i128), Unsigned(u128), } impl PartialEq for Int128 { #[inline] fn eq(&self, other: &Int128) -> bool { match self { Self::Signed(i) => match other { Self::Signed(i2) => i.eq(i2), Self::Unsigned(u2) => { if i.is_negative() { false } else { (*i as u128).eq(u2) } }, }, Self::Unsigned(u) => match other { Self::Signed(i2) => { if i2.is_negative() { false } else { u.eq(&(*i2 as u128)) } }, Self::Unsigned(u2) => u.eq(u2), }, } } } impl PartialOrd for Int128 { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Int128 { #[inline] fn cmp(&self, other: &Self) -> Ordering { match self { Self::Signed(i) => match other { Self::Signed(i2) => i.cmp(i2), Self::Unsigned(u2) => { if i.is_negative() { Ordering::Less } else { (*i as u128).cmp(u2) } }, }, Self::Unsigned(u) => match other { Self::Signed(i2) => { if i2.is_negative() { Ordering::Greater } else { u.cmp(&(*i2 as u128)) } }, Self::Unsigned(u2) => u.cmp(u2), }, } } } impl Display for Int128 { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Signed(i) => Display::fmt(i, f), Self::Unsigned(u) => Display::fmt(u, f), } } } impl Default for Int128 { #[inline] fn default() -> Self { Self::ZERO } } impl Int128 { pub(crate) const ZERO: Self = Self::Unsigned(0); } macro_rules! impl_from_signed { (@inner $t: ty) => { impl From<$t> for Int128 { #[inline] fn from(value: $t) -> Self { Int128::Signed(value as i128) } } }; ($($t: ty),+ $(,)*) => { $( impl_from_signed!(@inner $t); )* }; } impl_from_signed!(i8, i16, i32, i64, i128, isize); impl FromStr for Int128 { type Err = ParseIntError; #[inline] fn from_str(s: &str) -> Result { if s.starts_with('-') { Ok(Self::Signed(s.parse()?)) } else { Ok(Self::Unsigned(s.parse()?)) } } } impl Neg for Int128 { type Output = Int128; fn neg(self) -> Self::Output { match self { Self::Signed(i) => { if i == i128::MIN { Self::Unsigned(1 << 127) } else { Self::Signed(-i) } }, Self::Unsigned(u) => match u.cmp(&(1 << 127)) { Ordering::Equal => Self::Signed(i128::MIN), Ordering::Less => Self::Signed(-(u as i128)), Ordering::Greater => panic!("-{} is experiencing an overflow", u), }, } } } impl Int128 { #[inline] pub(crate) fn inc(&mut self) { match self { Self::Signed(i) => { if *i == i128::MAX { *self = Self::Unsigned(1 << 127) } else { *i += 1; } }, Self::Unsigned(u) => { *u = u.saturating_add(1); }, } } } enum-ordinalize-derive-4.3.2/src/int_wrapper.rs000064400000000000000000000026031046102023000177000ustar 00000000000000use proc_macro2::{Literal, TokenStream}; use quote::{quote, ToTokens, TokenStreamExt}; use syn::Expr; use crate::int128::Int128; pub(crate) enum IntWrapper { Integer(Int128), Constant(Expr, usize), } impl From for IntWrapper { #[inline] fn from(v: Int128) -> IntWrapper { Self::Integer(v) } } impl From for IntWrapper { #[inline] fn from(v: i128) -> IntWrapper { Self::Integer(Int128::from(v)) } } impl From<(&Expr, usize)> for IntWrapper { #[inline] fn from((expr, counter): (&Expr, usize)) -> IntWrapper { Self::Constant(expr.clone(), counter) } } impl ToTokens for IntWrapper { #[inline] fn to_tokens(&self, tokens: &mut TokenStream) { match self { Self::Integer(v) => { let lit = match v { Int128::Signed(i) => Literal::i128_unsuffixed(*i), Int128::Unsigned(u) => Literal::u128_unsuffixed(*u), }; tokens.append(lit); }, Self::Constant(expr, counter) => { let counter = *counter; if counter > 0 { tokens.extend(quote!(#expr +)); tokens.append(Literal::usize_unsuffixed(counter)); } else { tokens.extend(quote!(#expr)); } }, } } } enum-ordinalize-derive-4.3.2/src/lib.rs000064400000000000000000001004771046102023000161240ustar 00000000000000/*! # Enum Ordinalize Derive This library enables enums to not only obtain the ordinal values of their variants but also allows for the construction of enums from an ordinal value. See the [`enum-ordinalize`](https://crates.io/crates/enum-ordinalize) crate. */ #![no_std] #[macro_use] extern crate alloc; mod int128; mod int_wrapper; mod panic; mod variant_type; use alloc::{string::ToString, vec::Vec}; use proc_macro::TokenStream; use quote::quote; use syn::{ parse::{Parse, ParseStream}, parse_macro_input, punctuated::Punctuated, spanned::Spanned, Data, DeriveInput, Expr, Fields, Ident, Lit, Meta, Token, UnOp, Visibility, }; use variant_type::VariantType; use crate::{int128::Int128, int_wrapper::IntWrapper}; #[proc_macro_derive(Ordinalize, attributes(ordinalize))] pub fn ordinalize_derive(input: TokenStream) -> TokenStream { struct ConstMember { vis: Option, ident: Ident, meta: Vec, function: bool, } impl Parse for ConstMember { #[inline] fn parse(input: ParseStream) -> syn::Result { let vis = input.parse::().ok(); let _ = input.parse::(); let function = input.parse::().is_ok(); let ident = input.parse::()?; let mut meta = Vec::new(); if !input.is_empty() { input.parse::()?; if !input.is_empty() { let result = Punctuated::::parse_terminated(input)?; let mut has_inline = false; for m in result { if m.path().is_ident("inline") { has_inline = true; } meta.push(m); } if !has_inline { meta.push(syn::parse_str("inline")?); } } } Ok(Self { vis, ident, meta, function, }) } } struct ConstFunctionMember { vis: Option, ident: Ident, meta: Vec, } impl Parse for ConstFunctionMember { #[inline] fn parse(input: ParseStream) -> syn::Result { let vis = input.parse::().ok(); let _ = input.parse::(); input.parse::()?; let ident = input.parse::()?; let mut meta = Vec::new(); if !input.is_empty() { input.parse::()?; if !input.is_empty() { let result = Punctuated::::parse_terminated(input)?; let mut has_inline = false; for m in result { if m.path().is_ident("inline") { has_inline = true; } meta.push(m); } if !has_inline { meta.push(syn::parse_str("inline")?); } } } Ok(Self { vis, ident, meta, }) } } struct MyDeriveInput { ast: DeriveInput, variant_type: VariantType, values: Vec, variant_idents: Vec, use_constant_counter: bool, enable_trait: bool, enable_variant_count: Option, enable_variants: Option, enable_values: Option, enable_from_ordinal_unsafe: Option, enable_from_ordinal: Option, enable_ordinal: Option, } impl Parse for MyDeriveInput { fn parse(input: ParseStream) -> syn::Result { let ast = input.parse::()?; let mut variant_type = VariantType::default(); let mut enable_trait = cfg!(feature = "traits"); let mut enable_variant_count = None; let mut enable_variants = None; let mut enable_values = None; let mut enable_from_ordinal_unsafe = None; let mut enable_from_ordinal = None; let mut enable_ordinal = None; for attr in ast.attrs.iter() { let path = attr.path(); if let Some(ident) = path.get_ident() { match ident.to_string().as_str() { "repr" => { // #[repr(u8)], #[repr(u16)], ..., etc. if let Meta::List(list) = &attr.meta { let result = list.parse_args_with( Punctuated::::parse_terminated, )?; if let Some(value) = result.into_iter().next() { variant_type = VariantType::from_str(value.to_string()); } } break; }, "ordinalize" => { if let Meta::List(list) = &attr.meta { let result = list.parse_args_with( Punctuated::::parse_terminated, )?; for meta in result { let path = meta.path(); if let Some(ident) = path.get_ident() { match ident.to_string().as_str() { "impl_trait" => { if let Meta::NameValue(meta) = &meta { if let Expr::Lit(lit) = &meta.value { if let Lit::Bool(value) = &lit.lit { if cfg!(feature = "traits") { enable_trait = value.value; } } else { return Err( panic::bool_attribute_usage( ident, ident.span(), ), ); } } else { return Err(panic::bool_attribute_usage( ident, ident.span(), )); } } else { return Err(panic::bool_attribute_usage( ident, ident.span(), )); } }, "variant_count" => { if let Meta::List(list) = &meta { enable_variant_count = Some(list.parse_args()?); } else { return Err(panic::list_attribute_usage( ident, ident.span(), )); } }, "variants" => { if let Meta::List(list) = &meta { enable_variants = Some(list.parse_args()?); } else { return Err(panic::list_attribute_usage( ident, ident.span(), )); } }, "values" => { if let Meta::List(list) = &meta { enable_values = Some(list.parse_args()?); } else { return Err(panic::list_attribute_usage( ident, ident.span(), )); } }, "from_ordinal_unsafe" => { if let Meta::List(list) = &meta { enable_from_ordinal_unsafe = Some(list.parse_args()?); } else { return Err(panic::list_attribute_usage( ident, ident.span(), )); } }, "from_ordinal" => { if let Meta::List(list) = &meta { enable_from_ordinal = Some(list.parse_args()?); } else { return Err(panic::list_attribute_usage( ident, ident.span(), )); } }, "ordinal" => { if let Meta::List(list) = &meta { enable_ordinal = Some(list.parse_args()?); } else { return Err(panic::list_attribute_usage( ident, ident.span(), )); } }, _ => { return Err(panic::sub_attributes_for_ordinalize( ident.span(), )); }, } } else { return Err(panic::list_attribute_usage( ident, ident.span(), )); } } } else { return Err(panic::list_attribute_usage(ident, ident.span())); } }, _ => (), } } } let name = &ast.ident; if let Data::Enum(data) = &ast.data { let variant_count = data.variants.len(); if variant_count == 0 { return Err(panic::no_variant(name.span())); } let mut values: Vec = Vec::with_capacity(variant_count); let mut variant_idents: Vec = Vec::with_capacity(variant_count); let mut use_constant_counter = false; if let VariantType::NonDetermined = variant_type { let mut min = i128::MAX; let mut max = i128::MIN; let mut counter = 0; for variant in data.variants.iter() { if let Fields::Unit = variant.fields { if let Some((_, exp)) = variant.discriminant.as_ref() { match exp { Expr::Lit(lit) => { if let Lit::Int(lit) = &lit.lit { counter = lit.base10_parse().map_err(|error| { syn::Error::new(lit.span(), error) })?; } else { return Err(panic::unsupported_discriminant( lit.span(), )); } }, Expr::Unary(unary) => { if let UnOp::Neg(_) = unary.op { match unary.expr.as_ref() { Expr::Lit(lit) => { if let Lit::Int(lit) = &lit.lit { match lit.base10_parse::() { Ok(i) => { counter = -i; }, Err(error) => { // overflow if lit.base10_digits() == "170141183460469231731687303715884105728" { counter = i128::MIN; } else { return Err(syn::Error::new(lit.span(), error)); } }, } } else { return Err(panic::unsupported_discriminant(lit.span())); } }, Expr::Path(_) | Expr::Cast(_) | Expr::Binary(_) | Expr::Call(_) => { return Err(panic::constant_variable_on_non_determined_size_enum(unary.expr.span())) }, _ => return Err(panic::unsupported_discriminant(unary.expr.span())), } } else { return Err(panic::unsupported_discriminant( unary.op.span(), )); } }, Expr::Path(_) | Expr::Cast(_) | Expr::Binary(_) | Expr::Call(_) => { return Err( panic::constant_variable_on_non_determined_size_enum( exp.span(), ), ) }, _ => return Err(panic::unsupported_discriminant(exp.span())), } }; if min > counter { min = counter; } if max < counter { max = counter; } variant_idents.push(variant.ident.clone()); values.push(IntWrapper::from(counter)); counter = counter.saturating_add(1); } else { return Err(panic::not_unit_variant(variant.span())); } } if min >= i8::MIN as i128 && max <= i8::MAX as i128 { variant_type = VariantType::I8; } else if min >= i16::MIN as i128 && max <= i16::MAX as i128 { variant_type = VariantType::I16; } else if min >= i32::MIN as i128 && max <= i32::MAX as i128 { variant_type = VariantType::I32; } else if min >= i64::MIN as i128 && max <= i64::MAX as i128 { variant_type = VariantType::I64; } else { variant_type = VariantType::I128; } } else { let mut counter = Int128::ZERO; let mut constant_counter = 0; let mut last_exp: Option<&Expr> = None; for variant in data.variants.iter() { if let Fields::Unit = variant.fields { if let Some((_, exp)) = variant.discriminant.as_ref() { match exp { Expr::Lit(lit) => { if let Lit::Int(lit) = &lit.lit { counter = lit.base10_parse().map_err(|error| { syn::Error::new(lit.span(), error) })?; values.push(IntWrapper::from(counter)); counter.inc(); last_exp = None; } else { return Err(panic::unsupported_discriminant( lit.span(), )); } }, Expr::Unary(unary) => { if let UnOp::Neg(_) = unary.op { match unary.expr.as_ref() { Expr::Lit(lit) => { if let Lit::Int(lit) = &lit.lit { counter = -lit.base10_parse().map_err( |error| { syn::Error::new(lit.span(), error) }, )?; values.push(IntWrapper::from(counter)); counter.inc(); last_exp = None; } else { return Err( panic::unsupported_discriminant( lit.span(), ), ); } }, Expr::Path(_) => { values.push(IntWrapper::from((exp, 0))); last_exp = Some(exp); constant_counter = 1; }, Expr::Cast(_) | Expr::Binary(_) | Expr::Call(_) => { values.push(IntWrapper::from((exp, 0))); last_exp = Some(exp); constant_counter = 1; use_constant_counter = true; }, _ => { return Err(panic::unsupported_discriminant( exp.span(), )); }, } } else { return Err(panic::unsupported_discriminant( unary.op.span(), )); } }, Expr::Path(_) => { values.push(IntWrapper::from((exp, 0))); last_exp = Some(exp); constant_counter = 1; }, Expr::Cast(_) | Expr::Binary(_) | Expr::Call(_) => { values.push(IntWrapper::from((exp, 0))); last_exp = Some(exp); constant_counter = 1; use_constant_counter = true; }, _ => return Err(panic::unsupported_discriminant(exp.span())), } } else if let Some(exp) = last_exp { values.push(IntWrapper::from((exp, constant_counter))); constant_counter += 1; use_constant_counter = true; } else { values.push(IntWrapper::from(counter)); counter.inc(); } variant_idents.push(variant.ident.clone()); } else { return Err(panic::not_unit_variant(variant.span())); } } } Ok(MyDeriveInput { ast, variant_type, values, variant_idents, use_constant_counter, enable_trait, enable_variant_count, enable_variants, enable_values, enable_from_ordinal_unsafe, enable_from_ordinal, enable_ordinal, }) } else { Err(panic::not_enum(ast.ident.span())) } } } // Parse the token stream let derive_input = parse_macro_input!(input as MyDeriveInput); let MyDeriveInput { ast, variant_type, values, variant_idents, use_constant_counter, enable_trait, enable_variant_count, enable_variants, enable_values, enable_ordinal, enable_from_ordinal_unsafe, enable_from_ordinal, } = derive_input; // Get the identifier of the type. let name = &ast.ident; let variant_count = values.len(); let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); // Build the code let mut expanded = proc_macro2::TokenStream::new(); if enable_trait { #[cfg(feature = "traits")] { let from_ordinal_unsafe = if variant_count == 1 { let variant_ident = &variant_idents[0]; quote! { #[inline] unsafe fn from_ordinal_unsafe(_number: #variant_type) -> Self { Self::#variant_ident } } } else { quote! { #[inline] unsafe fn from_ordinal_unsafe(number: #variant_type) -> Self { ::core::mem::transmute(number) } } }; let from_ordinal = if use_constant_counter { quote! { #[inline] fn from_ordinal(number: #variant_type) -> Option { if false { unreachable!() } #( else if number == #values { Some(Self::#variant_idents) } )* else { None } } } } else { quote! { #[inline] fn from_ordinal(number: #variant_type) -> Option { match number{ #( #values => Some(Self::#variant_idents), )* _ => None } } } }; expanded.extend(quote! { impl #impl_generics Ordinalize for #name #ty_generics #where_clause { type VariantType = #variant_type; const VARIANT_COUNT: usize = #variant_count; const VARIANTS: &'static [Self] = &[#( Self::#variant_idents, )*]; const VALUES: &'static [#variant_type] = &[#( #values, )*]; #[inline] fn ordinal(&self) -> #variant_type { match self { #( Self::#variant_idents => #values, )* } } #from_ordinal_unsafe #from_ordinal } }); } } let mut expanded_2 = proc_macro2::TokenStream::new(); if let Some(ConstMember { vis, ident, meta, function, }) = enable_variant_count { expanded_2.extend(if function { quote! { #(#[#meta])* #vis const fn #ident () -> usize { #variant_count } } } else { quote! { #(#[#meta])* #vis const #ident: usize = #variant_count; } }); } if let Some(ConstMember { vis, ident, meta, function, }) = enable_variants { expanded_2.extend(if function { quote! { #(#[#meta])* #vis const fn #ident () -> [Self; #variant_count] { [#( Self::#variant_idents, )*] } } } else { quote! { #(#[#meta])* #vis const #ident: [Self; #variant_count] = [#( Self::#variant_idents, )*]; } }); } if let Some(ConstMember { vis, ident, meta, function, }) = enable_values { expanded_2.extend(if function { quote! { #(#[#meta])* #vis const fn #ident () -> [#variant_type; #variant_count] { [#( #values, )*] } } } else { quote! { #(#[#meta])* #vis const #ident: [#variant_type; #variant_count] = [#( #values, )*]; } }); } if let Some(ConstFunctionMember { vis, ident, meta, }) = enable_from_ordinal_unsafe { let from_ordinal_unsafe = if variant_count == 1 { let variant_ident = &variant_idents[0]; quote! { #(#[#meta])* #vis const unsafe fn #ident (_number: #variant_type) -> Self { Self::#variant_ident } } } else { quote! { #(#[#meta])* #vis const unsafe fn #ident (number: #variant_type) -> Self { ::core::mem::transmute(number) } } }; expanded_2.extend(from_ordinal_unsafe); } if let Some(ConstFunctionMember { vis, ident, meta, }) = enable_from_ordinal { let from_ordinal = if use_constant_counter { quote! { #(#[#meta])* #vis const fn #ident (number: #variant_type) -> Option { if false { unreachable!() } #( else if number == #values { Some(Self::#variant_idents) } )* else { None } } } } else { quote! { #(#[#meta])* #vis const fn #ident (number: #variant_type) -> Option { match number{ #( #values => Some(Self::#variant_idents), )* _ => None } } } }; expanded_2.extend(from_ordinal); } if let Some(ConstFunctionMember { vis, ident, meta, }) = enable_ordinal { expanded_2.extend(quote! { #(#[#meta])* #vis const fn #ident (&self) -> #variant_type { match self { #( Self::#variant_idents => #values, )* } } }); } if !expanded_2.is_empty() { expanded.extend(quote! { impl #impl_generics #name #ty_generics #where_clause { #expanded_2 } }); } expanded.into() } enum-ordinalize-derive-4.3.2/src/panic.rs000064400000000000000000000043661046102023000164500ustar 00000000000000use core::fmt::{self, Display, Formatter}; use proc_macro2::Span; use syn::Ident; struct DisplayStringSlice<'a>(&'a [&'static str]); impl<'a> Display for DisplayStringSlice<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { for &s in self.0 { f.write_str("\n ")?; f.write_str(s)?; } Ok(()) } } #[inline] pub(crate) fn not_enum(span: Span) -> syn::Error { syn::Error::new(span, "only enums can be ordinalized") } #[inline] pub(crate) fn no_variant(span: Span) -> syn::Error { syn::Error::new(span, "an ordinalized enum needs to have at least one variant") } #[inline] pub(crate) fn not_unit_variant(span: Span) -> syn::Error { syn::Error::new(span, "an ordinalized enum can only have unit variants") } #[inline] pub(crate) fn unsupported_discriminant(span: Span) -> syn::Error { syn::Error::new( span, "the discriminant of a variant of an ordinalized enum needs to be a legal literal \ integer, a constant variable/function or a constant expression", ) } #[inline] pub(crate) fn constant_variable_on_non_determined_size_enum(span: Span) -> syn::Error { syn::Error::new( span, "the discriminant of a variant can be assigned not to a literal integer only when the \ ordinalized enum is using the `repr` attribute to determine it's size before compilation", ) } #[inline] pub fn list_attribute_usage(name: &Ident, span: Span) -> syn::Error { syn::Error::new(span, format!("the `{name}` attribute should be a list")) } #[inline] pub(crate) fn bool_attribute_usage(name: &Ident, span: Span) -> syn::Error { syn::Error::new( span, format!("the `{name}` attribute should be a name-value pair. The value type is boolean"), ) } #[inline] pub(crate) fn sub_attributes_for_ordinalize(span: Span) -> syn::Error { syn::Error::new( span, format!( "available sub-attributes for the `ordinalize` attribute:{}", DisplayStringSlice(&[ "impl_trait", "variant_count", "variants", "values", "ordinal", "from_ordinal_unsafe", "from_ordinal", ]) ), ) } enum-ordinalize-derive-4.3.2/src/variant_type.rs000064400000000000000000000034751046102023000200630ustar 00000000000000use proc_macro2::{Ident, Span, TokenStream}; use quote::{ToTokens, TokenStreamExt}; #[derive(Debug)] pub(crate) enum VariantType { ISize, I8, I16, I32, I64, I128, USize, U8, U16, U32, U64, U128, NonDetermined, } impl VariantType { #[inline] pub(crate) fn from_str>(s: S) -> VariantType { let s = s.as_ref(); match s { "i8" => VariantType::I8, "i16" => VariantType::I16, "i32" => VariantType::I32, "i64" => VariantType::I64, "i128" => VariantType::I128, "isize" => VariantType::ISize, "u8" => VariantType::U8, "u16" => VariantType::U16, "u32" => VariantType::U32, "u64" => VariantType::U64, "u128" => VariantType::U128, "usize" => VariantType::USize, _ => VariantType::NonDetermined, } } #[inline] pub(crate) fn as_str(&self) -> &'static str { match self { VariantType::ISize => "isize", VariantType::I8 => "i8", VariantType::I16 => "i16", VariantType::I32 => "i32", VariantType::I64 => "i64", VariantType::I128 => "i128", VariantType::USize => "usize", VariantType::U8 => "u8", VariantType::U16 => "u16", VariantType::U32 => "u32", VariantType::U64 => "u64", VariantType::U128 => "u128", _ => unreachable!(), } } } impl Default for VariantType { #[inline] fn default() -> Self { VariantType::NonDetermined } } impl ToTokens for VariantType { #[inline] fn to_tokens(&self, tokens: &mut TokenStream) { tokens.append(Ident::new(self.as_str(), Span::call_site())); } }