summaryrefslogtreecommitdiffstats
path: root/third_party/rust/enum-map-derive/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/enum-map-derive/src
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/enum-map-derive/src')
-rw-r--r--third_party/rust/enum-map-derive/src/derive_enum.rs216
-rw-r--r--third_party/rust/enum-map-derive/src/derive_struct.rs129
-rw-r--r--third_party/rust/enum-map-derive/src/lib.rs178
3 files changed, 523 insertions, 0 deletions
diff --git a/third_party/rust/enum-map-derive/src/derive_enum.rs b/third_party/rust/enum-map-derive/src/derive_enum.rs
new file mode 100644
index 0000000000..8dce3de984
--- /dev/null
+++ b/third_party/rust/enum-map-derive/src/derive_enum.rs
@@ -0,0 +1,216 @@
+// SPDX-FileCopyrightText: 2021 - 2023 Kamila Borowska <kamila@borowska.pw>
+// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann <brunoczim@gmail.com>
+//
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+use crate::type_length;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote, ToTokens};
+use syn::{DataEnum, Fields, FieldsNamed, FieldsUnnamed, Ident, Variant};
+
+pub fn generate(name: Ident, data_enum: DataEnum) -> TokenStream {
+ let mut generator = EnumGenerator::empty();
+ for variant in &data_enum.variants {
+ generator.handle_variant(variant);
+ }
+ generator.finish(&name)
+}
+
+#[derive(Debug)]
+struct Length {
+ units: usize,
+ opaque: TokenStream,
+}
+
+impl ToTokens for Length {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let Self { units, opaque } = self;
+ tokens.extend(quote! { (#units + #opaque) });
+ }
+}
+
+/// Total length is the sum of each variant's length. To represent a variant, its number is added to
+/// the sum of previous variant lengths.
+#[derive(Debug)]
+struct EnumGenerator {
+ length: Length,
+ from_usize_arms: TokenStream,
+ into_usize_arms: TokenStream,
+}
+
+impl EnumGenerator {
+ fn empty() -> Self {
+ Self {
+ length: Length {
+ units: 0,
+ opaque: quote! { 0 },
+ },
+ from_usize_arms: quote! {},
+ into_usize_arms: quote! {},
+ }
+ }
+
+ fn finish(&self, name: &Ident) -> TokenStream {
+ let Self {
+ length,
+ from_usize_arms,
+ into_usize_arms,
+ } = self;
+
+ quote! {
+ #[automatically_derived]
+ impl ::enum_map::Enum for #name {
+ const LENGTH: ::enum_map::usize = #length;
+
+ #[inline]
+ fn from_usize(value: ::enum_map::usize) -> Self {
+ #from_usize_arms {
+ ::enum_map::out_of_bounds()
+ }
+ }
+
+ #[inline]
+ fn into_usize(self) -> ::enum_map::usize {
+ match self {
+ #into_usize_arms
+ }
+ }
+ }
+
+ #[automatically_derived]
+ impl<V> ::enum_map::EnumArray<V> for #name {
+ type Array = [V; #length];
+ }
+ }
+ }
+
+ fn handle_variant(&mut self, variant: &Variant) {
+ match &variant.fields {
+ Fields::Unit => self.handle_unit_variant(&variant.ident),
+ Fields::Unnamed(fields) => self.handle_unnamed_variant(&variant.ident, fields),
+ Fields::Named(fields) => self.handle_named_variant(&variant.ident, fields),
+ }
+ }
+
+ /// Becomes simply `1` in counting, since this is the size of the unit.
+ fn handle_unit_variant(&mut self, variant: &Ident) {
+ let Self {
+ length,
+ from_usize_arms,
+ into_usize_arms,
+ } = self;
+ *into_usize_arms = quote! { #into_usize_arms Self::#variant => #length, };
+ *from_usize_arms = quote! {
+ #from_usize_arms if value == #length {
+ Self::#variant
+ } else
+ };
+ self.length.units += 1;
+ }
+
+ /// Its size is the product of the sizes of its members. To represent this variant, one can
+ /// think of this as representing a little-endian number. First member is simply added, but
+ /// next members are multiplied before being added.
+ fn handle_unnamed_variant(&mut self, variant: &Ident, fields: &FieldsUnnamed) {
+ let Self {
+ length,
+ from_usize_arms,
+ into_usize_arms,
+ } = self;
+ let mut expr_into = quote! { #length };
+ let mut fields_length = quote! { 1usize };
+ let mut params_from = quote! {};
+ for (i, field) in fields.unnamed.iter().enumerate() {
+ let ident = format_ident!("p{}", i);
+ let ty = &field.ty;
+ let field_length = type_length(ty);
+
+ expr_into = quote! {
+ (#expr_into + #fields_length * ::enum_map::Enum::into_usize(#ident))
+ };
+
+ params_from = quote! {
+ #params_from <#ty as ::enum_map::Enum>::from_usize(
+ (value - #length) / #fields_length % #field_length
+ ),
+ };
+
+ fields_length = quote! { (#fields_length * #field_length) };
+ }
+
+ *length = Length {
+ units: 0,
+ opaque: quote! { (#length + #fields_length) },
+ };
+
+ let from_arms = &from_usize_arms;
+ *from_usize_arms = quote! {
+ #from_arms if value < #length {
+ Self::#variant(#params_from)
+ } else
+ };
+
+ let mut params_into = quote! {};
+ for i in 0..fields.unnamed.len() {
+ let ident = format_ident!("p{}", i);
+ params_into = quote! { #params_into #ident, };
+ }
+
+ *into_usize_arms = quote! {
+ #into_usize_arms Self::#variant(#params_into) => #expr_into,
+ };
+ }
+
+ /// Its size is the product of the sizes of its members. To represent this variant, one can
+ /// think of this as representing a little-endian number. First member is simply added, but
+ /// next members are multiplied before being added.
+ fn handle_named_variant(&mut self, variant: &Ident, fields: &FieldsNamed) {
+ let Self {
+ length,
+ from_usize_arms,
+ into_usize_arms,
+ } = self;
+ let mut expr_into = quote! { #length };
+ let mut fields_length = quote! { 1usize };
+ let mut params_from = quote! {};
+
+ for field in fields.named.iter() {
+ let ident = field.ident.as_ref().unwrap();
+ let ty = &field.ty;
+ let field_length = type_length(ty);
+
+ expr_into = quote! {
+ (#expr_into + #fields_length * ::enum_map::Enum::into_usize(#ident))
+ };
+
+ params_from = quote! {
+ #params_from #ident: <#ty as ::enum_map::Enum>::from_usize(
+ (value - #length) / #fields_length % #field_length
+ ),
+ };
+
+ fields_length = quote! { (#fields_length * #field_length) };
+ }
+
+ *length = Length {
+ units: 0,
+ opaque: quote! { (#length + #fields_length) },
+ };
+
+ *from_usize_arms = quote! {
+ #from_usize_arms if value < #length {
+ Self::#variant { #params_from }
+ } else
+ };
+
+ let mut params_into = quote! {};
+ for field in fields.named.iter() {
+ let ident = field.ident.as_ref().unwrap();
+ params_into = quote! { #params_into #ident, };
+ }
+
+ *into_usize_arms = quote! {
+ #into_usize_arms Self::#variant { #params_into } => #expr_into,
+ };
+ }
+}
diff --git a/third_party/rust/enum-map-derive/src/derive_struct.rs b/third_party/rust/enum-map-derive/src/derive_struct.rs
new file mode 100644
index 0000000000..94f3f97250
--- /dev/null
+++ b/third_party/rust/enum-map-derive/src/derive_struct.rs
@@ -0,0 +1,129 @@
+// SPDX-FileCopyrightText: 2021 - 2022 Kamila Borowska <kamila@borowska.pw>
+// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann <brunoczim@gmail.com>
+//
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+use crate::type_length;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{DataStruct, Fields, FieldsNamed, FieldsUnnamed, Ident, Index};
+
+pub fn generate(name: Ident, data_struct: DataStruct) -> TokenStream {
+ StructGenerator::from_fields(&data_struct.fields).finish(&name)
+}
+
+/// Total length is the product of each member's length. To represent a struct, one can
+/// think of this as representing a little-endian number. First member is simply added, but
+/// next members are multiplied before being added.
+#[derive(Debug)]
+struct StructGenerator {
+ length: TokenStream,
+ from_usize: TokenStream,
+ into_usize: TokenStream,
+}
+
+impl StructGenerator {
+ fn from_fields(fields: &Fields) -> Self {
+ match fields {
+ Fields::Unit => Self::from_unit_fields(),
+ Fields::Unnamed(fields_data) => Self::from_unnamed_fields(fields_data),
+ Fields::Named(fields_data) => Self::from_named_fields(fields_data),
+ }
+ }
+
+ fn from_unit_fields() -> Self {
+ Self {
+ length: quote! { 1usize },
+ from_usize: quote! { Self },
+ into_usize: quote! { 0usize },
+ }
+ }
+
+ fn from_unnamed_fields(fields: &FieldsUnnamed) -> Self {
+ let mut params_from = quote! {};
+ let mut into_usize = quote! { 0usize };
+ let mut length = quote! { 1usize };
+ for (i, field) in fields.unnamed.iter().enumerate() {
+ let ty = &field.ty;
+ let index_ident = Index::from(i);
+ let field_length = type_length(ty);
+
+ into_usize = quote! {
+ (#into_usize + #length * ::enum_map::Enum::into_usize(self.#index_ident))
+ };
+
+ params_from = quote! {
+ #params_from <#ty as ::enum_map::Enum>::from_usize(
+ value / #length % #field_length
+ ),
+ };
+
+ length = quote! { (#length * #field_length) };
+ }
+
+ let from_usize = quote! { Self(#params_from) };
+ Self {
+ length,
+ from_usize,
+ into_usize,
+ }
+ }
+
+ fn from_named_fields(fields: &FieldsNamed) -> Self {
+ let mut params_from = quote! {};
+ let mut into_usize = quote! { 0usize };
+ let mut length = quote! { 1usize };
+ for field in fields.named.iter() {
+ let ty = &field.ty;
+ let ident = field.ident.as_ref().unwrap();
+ let field_length = type_length(ty);
+
+ into_usize = quote! {
+ (#into_usize + #length * ::enum_map::Enum::into_usize(self.#ident))
+ };
+
+ params_from = quote! {
+ #params_from #ident: <#ty as ::enum_map::Enum>::from_usize(
+ value / #length % #field_length
+ ),
+ };
+
+ length = quote! { (#field_length * #length) };
+ }
+
+ let from_usize = quote! { Self { #params_from } };
+ Self {
+ length,
+ from_usize,
+ into_usize,
+ }
+ }
+
+ fn finish(&self, name: &Ident) -> TokenStream {
+ let length = &self.length;
+ let from_usize = &self.from_usize;
+ let into_usize = &self.into_usize;
+
+ quote! {
+ #[automatically_derived]
+ impl ::enum_map::Enum for #name {
+ const LENGTH: ::enum_map::usize = #length;
+
+ #[inline]
+ fn from_usize(value: ::enum_map::usize) -> Self {
+ #from_usize
+ }
+
+ #[inline]
+ fn into_usize(self) -> ::enum_map::usize {
+ #into_usize
+ }
+ }
+
+ #[automatically_derived]
+ impl<V> ::enum_map::EnumArray<V> for #name {
+ type Array = [V; #length];
+ }
+ }
+ }
+}
diff --git a/third_party/rust/enum-map-derive/src/lib.rs b/third_party/rust/enum-map-derive/src/lib.rs
new file mode 100644
index 0000000000..0776559b28
--- /dev/null
+++ b/third_party/rust/enum-map-derive/src/lib.rs
@@ -0,0 +1,178 @@
+// SPDX-FileCopyrightText: 2017 - 2022 Kamila Borowska <kamila@borowska.pw>
+// SPDX-FileCopyrightText: 2018 hcpl <hcpl.prog@gmail.com>
+// SPDX-FileCopyrightText: 2019 mara <vmedea@protonmail.com>
+// SPDX-FileCopyrightText: 2021 Bruno Corrêa Zimmermann <brunoczim@gmail.com>
+// SPDX-FileCopyrightText: 2021 Dietrich <dietrich@teilgedanken.de>
+//
+// SPDX-License-Identifier: MIT OR Apache-2.0
+
+//! Procedural macro implementing `#[derive(Enum)]`
+//!
+//! This is supposed to used with `enum-map` crate, which provides the
+//! actual usage documentation.
+
+mod derive_enum;
+mod derive_struct;
+
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Data, DeriveInput, Type};
+
+/// Derive macro generating an implementation of trait `Enum`.
+///
+/// When using a derive, enum maps are maintained in the order in which
+/// enum variants are declared. This is reflected in the value returned
+/// by `Enum::into_usize`, iterators of enum map as well as
+/// `EnumMap::as_slice` method.
+///
+/// # Examples
+///
+/// ## Enums Without Payload
+/// ```
+/// use enum_map::Enum;
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// enum A {
+/// B,
+/// C,
+/// D,
+/// }
+///
+/// assert_eq!(A::B.into_usize(), 0);
+/// assert_eq!(A::C.into_usize(), 1);
+/// assert_eq!(A::D.into_usize(), 2);
+///
+/// assert_eq!(A::from_usize(0), A::B);
+/// assert_eq!(A::from_usize(1), A::C);
+/// assert_eq!(A::from_usize(2), A::D);
+/// ```
+///
+/// ## Enums With Payload
+///
+/// ```
+/// use enum_map::Enum;
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// enum A {
+/// B,
+/// C,
+/// D,
+/// }
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// enum X {
+/// Y,
+/// Z,
+/// }
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// enum Foo {
+/// Bar(bool, A),
+/// Empty,
+/// Baz { fa: A, fx: X },
+/// }
+///
+/// assert_eq!(Foo::Bar(false, A::B).into_usize(), 0);
+/// assert_eq!(Foo::Bar(false, A::D).into_usize(), 4);
+/// assert_eq!(Foo::Bar(true, A::B).into_usize(), 1);
+/// assert_eq!(Foo::Bar(true, A::C).into_usize(), 3);
+/// assert_eq!(Foo::Empty.into_usize(), 6);
+/// assert_eq!(Foo::Baz { fa: A::B, fx: X::Y }.into_usize(), 7);
+/// assert_eq!(Foo::Baz { fa: A::B, fx: X::Z }.into_usize(), 10);
+/// assert_eq!(Foo::Baz { fa: A::D, fx: X::Y }.into_usize(), 9);
+///
+/// assert_eq!(Foo::from_usize(0), Foo::Bar(false, A::B));
+/// assert_eq!(Foo::from_usize(4), Foo::Bar(false, A::D));
+/// assert_eq!(Foo::from_usize(1), Foo::Bar(true, A::B));
+/// assert_eq!(Foo::from_usize(3), Foo::Bar(true, A::C));
+/// assert_eq!(Foo::from_usize(6), Foo::Empty);
+/// assert_eq!(Foo::from_usize(7), Foo::Baz { fa: A::B, fx: X::Y });
+/// assert_eq!(Foo::from_usize(10), Foo::Baz { fa: A::B, fx: X::Z });
+/// assert_eq!(Foo::from_usize(9), Foo::Baz { fa: A::D, fx: X::Y });
+///
+/// ```
+///
+/// ## Structs
+///
+/// ```
+/// use enum_map::Enum;
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// enum A {
+/// B,
+/// C,
+/// D,
+/// }
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// enum X {
+/// Y,
+/// Z,
+/// }
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// struct Foo {
+/// bar: bool,
+/// baz: A,
+/// end: X,
+/// }
+///
+/// assert_eq!(Foo { bar: false, baz: A::B, end: X::Y }.into_usize(), 0);
+/// assert_eq!(Foo { bar: true, baz: A::B, end: X::Y }.into_usize(), 1);
+/// assert_eq!(Foo { bar: false, baz: A::D, end: X::Y }.into_usize(), 4);
+/// assert_eq!(Foo { bar: true, baz: A::C, end: X::Z }.into_usize(), 9);
+///
+/// assert_eq!(Foo::from_usize(0), Foo { bar: false, baz: A::B, end: X::Y });
+/// assert_eq!(Foo::from_usize(1), Foo { bar: true, baz: A::B, end: X::Y });
+/// assert_eq!(Foo::from_usize(4), Foo { bar: false, baz: A::D, end: X::Y });
+/// assert_eq!(Foo::from_usize(9), Foo { bar: true, baz: A::C, end: X::Z });
+/// ```
+///
+/// ## Tuple Structs
+///
+/// ```
+/// use enum_map::Enum;
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// enum A {
+/// B,
+/// C,
+/// D,
+/// }
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// enum X {
+/// Y,
+/// Z,
+/// }
+///
+/// #[derive(Enum, Debug, PartialEq, Eq)]
+/// struct Foo(bool, A, X);
+///
+/// assert_eq!(Foo(false, A::B, X::Y ).into_usize(), 0);
+/// assert_eq!(Foo(true, A::B, X::Y ).into_usize(), 1);
+/// assert_eq!(Foo(false, A::D, X::Y ).into_usize(), 4);
+/// assert_eq!(Foo(true, A::C, X::Z ).into_usize(), 9);
+///
+/// assert_eq!(Foo::from_usize(0), Foo(false, A::B, X::Y));
+/// assert_eq!(Foo::from_usize(1), Foo(true, A::B, X::Y));
+/// assert_eq!(Foo::from_usize(4), Foo(false, A::D, X::Y));
+/// assert_eq!(Foo::from_usize(9), Foo(true, A::C, X::Z));
+#[proc_macro_derive(Enum)]
+pub fn derive_enum_map(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let input: DeriveInput = syn::parse(input).unwrap();
+
+ let result = match input.data {
+ Data::Enum(data_enum) => derive_enum::generate(input.ident, data_enum),
+ Data::Struct(data_struct) => derive_struct::generate(input.ident, data_struct),
+ _ => quote! { compile_error! {"#[derive(Enum)] is only defined for enums and structs"} },
+ };
+
+ result.into()
+}
+
+fn type_length(ty: &Type) -> TokenStream {
+ quote! {
+ <#ty as ::enum_map::Enum>::LENGTH
+ }
+}