// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright by contributors to this project. // SPDX-License-Identifier: (Apache-2.0 OR MIT)
use std::str::FromStr;
use darling::{
ast::{self, Fields},
FromDeriveInput, FromField, FromVariant,
}; use proc_macro2::{Literal, TokenStream}; use quote::quote; use syn::{
parse_macro_input, parse_quote, Attribute, DeriveInput, Expr, Generics, Ident, Index, Lit, Path,
};
/// Provides the discriminant for a given variant. If the variant does not specify a suffix /// and a `repr_ident` is provided, it will be appended to number. fn discriminant_for_variant(
variant: &MlsVariantReceiver,
repr_ident: &Option<Ident>,
) -> TokenStream { let discriminant = variant
.discriminant
.clone()
.expect("Enum discriminants must be explicitly defined");
let Expr::Lit(lit_expr) = &discriminant else { return quote! {#discriminant};
};
let Lit::Int(lit_int) = &lit_expr.lit else { return quote! {#discriminant};
};
if lit_int.suffix().is_empty() { // This is dirty and there is probably a better way of doing this but I'm way too much of a noob at // proc macros to pull it off... // TODO: Add proper support for correctly ignoring transparent, packed and modifiers let str = format!( "{}{}",
lit_int.base10_digits(),
&repr_ident.clone().expect("Expected a repr(u*) to be provided or for the variant's discriminant to be defined with suffixed literals.")
);
Literal::from_str(&str)
.map(|l| quote! {#l})
.ok()
.unwrap_or_else(|| quote! {#discriminant})
} else {
quote! {#discriminant}
}
}
fn enum_impl(
ident: &Ident,
attrs: &[Attribute],
variants: &[MlsVariantReceiver],
operation: Operation,
) -> TokenStream { let handle_error = operation.is_result().then_some(quote! { ? }); let path = operation.path(); let call = operation.call(); let extras = operation.extras(); let enum_name = &ident; let repr_ident = repr_ident(attrs); if matches!(operation, Operation::Decode) { let cases = variants.iter().map(|variant| { let variant_name = &variant.ident;
let discriminant = discriminant_for_variant(variant, &repr_ident);
// TODO: Support more than 1 field match variant.fields.len() { 0 => quote! { #discriminant => Ok(#enum_name::#variant_name), }, 1 =>{ let path = variant.fields.fields[0].with.as_ref().unwrap_or(&path);
quote! { #discriminant => Ok(#enum_name::#variant_name(#path::#call(#extras) #handle_error)), }
},
_ => panic!("Enum discriminants with more than 1 field are not currently supported")
}
});
return quote! { let discriminant = #path::#call(#extras)#handle_error;
match discriminant { #(#cases)*
_ => Err(mls_rs_codec::Error::UnsupportedEnumDiscriminant),
}
};
}
let cases = variants.iter().map(|variant| { let variant_name = &variant.ident;
let discriminant = discriminant_for_variant(variant, &repr_ident);
let (parameter, field) = if variant.fields.is_empty() {
(None, None)
} else { let path = variant.fields.fields[0].with.as_ref().unwrap_or(&path);
let start = match operation {
Operation::Size => Some(quote! { + }),
Operation::Encode => Some(quote! {;}),
Operation::Decode => None,
};
let handle_error = operation.is_result().then_some(quote! { ? }); let path = field.with.clone().unwrap_or(operation.path()); let call = operation.call(); let extras = operation.extras();
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.11Bemerkung:
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.