This commit is contained in:
Tim 'Piepmatz' Hesse 2024-06-01 21:08:30 +02:00
parent a14ea9c2ca
commit 5f1eadb850

View File

@ -1,8 +1,8 @@
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
use proc_macro_error::{Diagnostic, Level}; use proc_macro_error::{Diagnostic, Level};
use quote::{format_ident, quote, ToTokens}; use quote::{quote, ToTokens};
use syn::{Data, DataEnum, DataStruct, DeriveInput, Fields, Generics, Ident, Index}; use syn::{Data, DataEnum, DataStruct, DeriveInput, Fields, Generics, Ident};
enum DeriveError { enum DeriveError {
Syn(syn::parse::Error), Syn(syn::parse::Error),
@ -31,7 +31,11 @@ pub fn derive_from_value(input: TokenStream2) -> Result<TokenStream2, impl Into<
data_struct, data_struct,
input.generics, input.generics,
)), )),
Data::Enum(data_enum) => Ok(derive_enum_from_value(input.ident, data_enum, input.generics)), Data::Enum(data_enum) => Ok(derive_enum_from_value(
input.ident,
data_enum,
input.generics,
)),
Data::Union(_) => Err(DeriveError::Unsupported), Data::Union(_) => Err(DeriveError::Unsupported),
} }
} }
@ -111,7 +115,7 @@ fn struct_expected_type(fields: &Fields) -> TokenStream2 {
fn derive_enum_from_value(ident: Ident, data: DataEnum, generics: Generics) -> TokenStream2 { fn derive_enum_from_value(ident: Ident, data: DataEnum, generics: Generics) -> TokenStream2 {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let from_value_impl = enum_from_value(&data); let from_value_impl = enum_from_value(&data);
// As variants are hard to type with the current type system, we use the // As variants are hard to type with the current type system, we use the
// default impl for `expected_type`. // default impl for `expected_type`.
quote! { quote! {
#[automatically_derived] #[automatically_derived]
@ -128,7 +132,7 @@ fn enum_from_value(data: &DataEnum) -> TokenStream2 {
let fields = fields_from_record(&variant.fields, quote!(Self::#ident)); let fields = fields_from_record(&variant.fields, quote!(Self::#ident));
quote!(#ident_s => {#fields}) quote!(#ident_s => {#fields})
}); });
quote! { quote! {
fn from_value( fn from_value(
v: nu_protocol::Value, v: nu_protocol::Value,
@ -144,7 +148,7 @@ fn enum_from_value(data: &DataEnum) -> TokenStream2 {
})?; })?;
let ty = ty.into_string()?; let ty = ty.into_string()?;
// This allows unit variants to resolve without the "content" field // This allows unit variants to resolve without the "content" field
// in the record. // in the record.
let v = record let v = record
.remove("content") .remove("content")
@ -165,10 +169,7 @@ fn enum_from_value(data: &DataEnum) -> TokenStream2 {
} }
} }
fn fields_from_record( fn fields_from_record(fields: &Fields, self_ident: impl ToTokens) -> TokenStream2 {
fields: &Fields,
self_ident: impl ToTokens
) -> TokenStream2 {
match fields { match fields {
Fields::Named(fields) => { Fields::Named(fields) => {
let fields = fields.named.iter().map(|field| { let fields = fields.named.iter().map(|field| {
@ -194,7 +195,7 @@ fn fields_from_record(
let mut record = v.into_record()?; let mut record = v.into_record()?;
std::result::Result::Ok(#self_ident {#(#fields),*}) std::result::Result::Ok(#self_ident {#(#fields),*})
} }
}, }
Fields::Unnamed(fields) => { Fields::Unnamed(fields) => {
let fields = fields.unnamed.iter().enumerate().map(|(i, field)| { let fields = fields.unnamed.iter().enumerate().map(|(i, field)| {
let ty = &field.ty; let ty = &field.ty;
@ -228,6 +229,6 @@ fn fields_from_record(
help: std::option::Option::None help: std::option::Option::None
}) })
} }
} },
} }
} }