use proc_macro2::TokenStream;
use quote::quote;
use crate::parse_type::{
CommonDerivedTypeInfo,
VariantData::{Named, Unit},
VariantInfo,
};
pub fn generate_derive_tagged_enum_impl(
info: CommonDerivedTypeInfo,
tag: String,
variants: Vec<VariantInfo>,
) -> TokenStream {
let variants_impls = variants
.into_iter()
.map(|v| generate_derive_tagged_enum_variant_impl(&info, &v))
.collect::<Vec<_>>();
let CommonDerivedTypeInfo {
impl_trait_tokens,
err_ty,
validate,
} = info;
quote! {
#impl_trait_tokens {
fn deserialize_from_value<V: ::deserr::IntoValue>(deserr_value__: ::deserr::Value<V>, deserr_location__: ::deserr::ValuePointerRef) -> ::std::result::Result<Self, #err_ty> {
let deserr_final__ = match deserr_value__ {
::deserr::Value::Map(mut deserr_map__) => {
let tag_value = ::deserr::Map::remove(&mut deserr_map__, #tag).ok_or_else(|| {
::deserr::take_result_content(<#err_ty as ::deserr::DeserializeError>::error::<V>(
None,
::deserr::ErrorKind::MissingField {
field: #tag,
},
deserr_location__
))
})?;
let tag_value_string = match tag_value.into_value() {
::deserr::Value::String(x) => x,
v => {
return ::std::result::Result::Err(
<#err_ty as ::deserr::DeserializeError>::error::<V>(
None,
::deserr::ErrorKind::IncorrectValueKind {
actual: v,
accepted: &[::deserr::ValueKind::String],
},
deserr_location__.push_key(#tag)
)?
);
}
};
match tag_value_string.as_str() {
#(#variants_impls)*
_ => {
::std::result::Result::Err(
<#err_ty as ::deserr::DeserializeError>::error::<V>(
None,
::deserr::ErrorKind::Unexpected {
msg: "Incorrect tag value".to_string(),
},
deserr_location__
)?
)
}
}
},
v => {
::std::result::Result::Err(
<#err_ty as ::deserr::DeserializeError>::error::<V>(
None,
::deserr::ErrorKind::IncorrectValueKind {
actual: v,
accepted: &[::deserr::ValueKind::Map],
},
deserr_location__
)?
)
}
}?;
#validate
}
}
}
}
fn generate_derive_tagged_enum_variant_impl(
info: &CommonDerivedTypeInfo,
variant: &VariantInfo,
) -> TokenStream {
let CommonDerivedTypeInfo { err_ty, .. } = info;
let VariantInfo {
ident: variant_ident,
data,
key_name: variant_key_name,
} = variant;
match data {
Unit => {
quote! {
#variant_key_name => {
::std::result::Result::Ok(Self::#variant_ident)
}
}
}
Named(fields) => {
let fields_impl = crate::generate_named_fields_impl(
fields,
err_ty,
quote! { Self :: #variant_ident },
);
quote! {
#variant_key_name => {
let mut deserr_error__ = None;
#fields_impl
}
}
}
}
}
pub fn generate_derive_untagged_enum_impl(
info: CommonDerivedTypeInfo,
variants: Vec<VariantInfo>,
) -> TokenStream {
let all_variants_as_str = variants
.iter()
.map(|v| &v.key_name)
.map(|v| quote!(#v, ))
.collect::<TokenStream>();
let all_variants_as_str = quote!(&[#all_variants_as_str]);
let variants_impls = variants
.into_iter()
.map(|v| generate_derive_tagged_enum_variant_impl(&info, &v))
.collect::<Vec<_>>();
let CommonDerivedTypeInfo {
impl_trait_tokens,
err_ty,
validate,
} = info;
quote! {
#impl_trait_tokens {
fn deserialize_from_value<V: ::deserr::IntoValue>(deserr_value__: ::deserr::Value<V>, deserr_location__: ::deserr::ValuePointerRef) -> ::std::result::Result<Self, #err_ty> {
let deserr_final__ = match deserr_value__ {
::deserr::Value::String(s) => {
match s.as_str() {
#(#variants_impls)*
s => {
::std::result::Result::Err(
<#err_ty as ::deserr::DeserializeError>::error::<V>(
None,
::deserr::ErrorKind::UnknownValue {
value: s,
accepted: #all_variants_as_str,
},
deserr_location__
)?
)
}
}
},
v => {
::std::result::Result::Err(
<#err_ty as ::deserr::DeserializeError>::error::<V>(
None,
::deserr::ErrorKind::IncorrectValueKind {
actual: v,
accepted: &[::deserr::ValueKind::String],
},
deserr_location__
)?
)
}
}?;
#validate
}
}
}
}