use quote::{quote, ToTokens};
use super::{check_mode::CheckMode, OwnedCodeGen, RefCodeGen};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ImplOption {
Implement,
Omit,
}
impl ImplOption {
fn map<F>(self, f: F) -> Option<proc_macro2::TokenStream>
where
F: FnOnce() -> proc_macro2::TokenStream,
{
match self {
Self::Implement => Some(f()),
Self::Omit => None,
}
}
}
impl std::str::FromStr for ImplOption {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"impl" => Ok(Self::Implement),
"omit" => Ok(Self::Omit),
_ => Err("valid values are: `impl` or `omit`"),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DelegatingImplOption {
Implement,
OwnedOnly,
Omit,
}
impl DelegatingImplOption {
fn map_owned<F>(self, f: F) -> Option<proc_macro2::TokenStream>
where
F: FnOnce() -> proc_macro2::TokenStream,
{
match self {
Self::Implement | Self::OwnedOnly => Some(f()),
Self::Omit => None,
}
}
fn map_ref<F>(self, f: F) -> Option<proc_macro2::TokenStream>
where
F: FnOnce() -> proc_macro2::TokenStream,
{
match self {
Self::Implement => Some(f()),
Self::Omit | Self::OwnedOnly => None,
}
}
}
impl std::str::FromStr for DelegatingImplOption {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"impl" => Ok(Self::Implement),
"owned" => Ok(Self::OwnedOnly),
"omit" => Ok(Self::Omit),
_ => Err("valid values are: `impl`, `owned`, or `omit`"),
}
}
}
impl From<ImplOption> for DelegatingImplOption {
fn from(opt: ImplOption) -> Self {
match opt {
ImplOption::Implement => Self::Implement,
ImplOption::Omit => Self::Omit,
}
}
}
#[derive(Debug, Default)]
pub struct Impls {
pub clone: ImplClone,
pub debug: ImplDebug,
pub display: ImplDisplay,
pub ord: ImplOrd,
pub serde: ImplSerde,
}
pub(crate) trait ToImpl {
fn to_owned_impl(&self, _gen: &OwnedCodeGen) -> Option<proc_macro2::TokenStream> {
None
}
fn to_borrowed_impl(&self, _gen: &RefCodeGen) -> Option<proc_macro2::TokenStream> {
None
}
}
#[derive(Debug)]
pub struct ImplClone(ImplOption);
impl Default for ImplClone {
fn default() -> Self {
Self(ImplOption::Implement)
}
}
impl From<ImplOption> for ImplClone {
fn from(opt: ImplOption) -> Self {
Self(opt)
}
}
impl ToImpl for ImplClone {
fn to_owned_impl(&self, _gen: &OwnedCodeGen) -> Option<proc_macro2::TokenStream> {
self.0.map(|| quote! { #[derive(Clone)] })
}
}
#[derive(Debug)]
pub struct ImplDisplay(DelegatingImplOption);
impl Default for ImplDisplay {
fn default() -> Self {
Self(DelegatingImplOption::Implement)
}
}
impl From<DelegatingImplOption> for ImplDisplay {
fn from(opt: DelegatingImplOption) -> Self {
Self(opt)
}
}
impl ToImpl for ImplDisplay {
fn to_owned_impl(&self, gen: &OwnedCodeGen) -> Option<proc_macro2::TokenStream> {
let ty = gen.ty;
let ref_ty = gen.ref_ty;
let core = gen.std_lib.core();
self.0.map_owned(|| {
quote! {
#[automatically_derived]
impl ::#core::fmt::Display for #ty {
#[inline]
fn fmt(&self, f: &mut ::#core::fmt::Formatter) -> ::#core::fmt::Result {
<#ref_ty as ::#core::fmt::Display>::fmt(::#core::ops::Deref::deref(self), f)
}
}
}
})
}
fn to_borrowed_impl(&self, gen: &RefCodeGen) -> Option<proc_macro2::TokenStream> {
let ty = &gen.ty;
let field_name = &gen.field.name;
let core = gen.std_lib.core();
self.0.map_ref(|| {
quote! {
#[automatically_derived]
impl ::#core::fmt::Display for #ty {
#[inline]
fn fmt(&self, f: &mut ::#core::fmt::Formatter) -> ::#core::fmt::Result {
<str as ::#core::fmt::Display>::fmt(&self.#field_name, f)
}
}
}
})
}
}
#[derive(Debug)]
pub struct ImplDebug(DelegatingImplOption);
impl Default for ImplDebug {
fn default() -> Self {
Self(DelegatingImplOption::Implement)
}
}
impl From<DelegatingImplOption> for ImplDebug {
fn from(opt: DelegatingImplOption) -> Self {
Self(opt)
}
}
impl ToImpl for ImplDebug {
fn to_owned_impl(&self, gen: &OwnedCodeGen) -> Option<proc_macro2::TokenStream> {
let ty = gen.ty;
let ref_ty = gen.ref_ty;
let core = gen.std_lib.core();
self.0.map_owned(|| {
quote! {
#[automatically_derived]
impl ::#core::fmt::Debug for #ty {
#[inline]
fn fmt(&self, f: &mut ::#core::fmt::Formatter) -> ::#core::fmt::Result {
<#ref_ty as ::#core::fmt::Debug>::fmt(::#core::ops::Deref::deref(self), f)
}
}
}
})
}
fn to_borrowed_impl(&self, gen: &RefCodeGen) -> Option<proc_macro2::TokenStream> {
let ty = &gen.ty;
let field_name = &gen.field.name;
let core = gen.std_lib.core();
self.0.map_ref(|| {
quote! {
#[automatically_derived]
impl ::#core::fmt::Debug for #ty {
#[inline]
fn fmt(&self, f: &mut ::#core::fmt::Formatter) -> ::#core::fmt::Result {
<str as ::#core::fmt::Debug>::fmt(&self.#field_name, f)
}
}
}
})
}
}
#[derive(Debug)]
pub struct ImplOrd(DelegatingImplOption);
impl Default for ImplOrd {
fn default() -> Self {
Self(DelegatingImplOption::Implement)
}
}
impl From<DelegatingImplOption> for ImplOrd {
fn from(opt: DelegatingImplOption) -> Self {
Self(opt)
}
}
impl ToImpl for ImplOrd {
fn to_owned_impl(&self, gen: &OwnedCodeGen) -> Option<proc_macro2::TokenStream> {
let ty = &gen.ty;
let field_name = &gen.field.name;
let core = gen.std_lib.core();
self.0.map_owned(|| quote! {
#[automatically_derived]
impl ::#core::cmp::Ord for #ty {
#[inline]
fn cmp(&self, other: &Self) -> ::#core::cmp::Ordering {
::#core::cmp::Ord::cmp(&self.#field_name, &other.#field_name)
}
}
#[automatically_derived]
impl ::#core::cmp::PartialOrd for #ty {
#[inline]
fn partial_cmp(&self, other: &Self) -> ::#core::option::Option<::#core::cmp::Ordering> {
::#core::cmp::PartialOrd::partial_cmp(&self.#field_name, &other.#field_name)
}
}
})
}
fn to_borrowed_impl(&self, _gen: &RefCodeGen) -> Option<proc_macro2::TokenStream> {
self.0.map_ref(|| quote! { #[derive(PartialOrd, Ord)] })
}
}
#[derive(Debug)]
pub struct ImplSerde(ImplOption);
impl Default for ImplSerde {
fn default() -> Self {
Self(ImplOption::Omit)
}
}
impl From<ImplOption> for ImplSerde {
fn from(opt: ImplOption) -> Self {
Self(opt)
}
}
impl ToImpl for ImplSerde {
fn to_owned_impl(&self, gen: &OwnedCodeGen) -> Option<proc_macro2::TokenStream> {
self.0.map(|| {
let handle_failure = gen.check_mode.serde_err_handler();
let name = gen.ty;
let field_name = &gen.field.name;
let wrapped_type = &gen.field.ty;
quote! {
#[automatically_derived]
impl ::serde::Serialize for #name {
fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
<#wrapped_type as ::serde::Serialize>::serialize(&self.#field_name, serializer)
}
}
#[allow(clippy::needless_question_mark, clippy::unsafe_derive_deserialize)]
#[automatically_derived]
impl<'de> ::serde::Deserialize<'de> for #name {
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let raw = <#wrapped_type as ::serde::Deserialize<'de>>::deserialize(deserializer)?;
Ok(Self::new(raw)#handle_failure)
}
}
}
})
}
fn to_borrowed_impl(&self, gen: &RefCodeGen) -> Option<proc_macro2::TokenStream> {
self.0.map(|| {
let ty = &gen.ty;
let check_mode = gen.check_mode;
let core = gen.std_lib.core();
let alloc = gen.std_lib.alloc();
let handle_failure = check_mode.serde_err_handler();
let deserialize_boxed = gen.owned_ty.map(|owned_ty| {
quote! {
#[automatically_derived]
impl<'de> ::serde::Deserialize<'de> for ::#alloc::boxed::Box<#ty> {
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> ::#core::result::Result<Self, D::Error> {
let owned = <#owned_ty as ::serde::Deserialize<'de>>::deserialize(deserializer)?;
::#core::result::Result::Ok(owned.into_boxed_ref())
}
}
}
});
let deserialize = if matches!(check_mode, CheckMode::Normalize(_)) {
let deserialize_doc = format!(
"Deserializes a `{ty}` in normalized form\n\
\n\
This deserializer _requires_ that the value already be in normalized form. \
If values may require normalization, then deserialized as [`{owned}`] or \
[`Cow<{ty}>`][{alloc}::borrow::Cow] instead.",
ty = ty.to_token_stream(),
owned = gen.owned_ty.expect("normalize not available if no owned").to_token_stream(),
);
quote! {
#[doc = #deserialize_doc]
#[allow(clippy::needless_question_mark, clippy::unsafe_derive_deserialize)]
#[automatically_derived]
impl<'de: 'a, 'a> ::serde::Deserialize<'de> for &'a #ty {
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> ::#core::result::Result<Self, D::Error> {
let raw = <&str as ::serde::Deserialize<'de>>::deserialize(deserializer)?;
::#core::result::Result::Ok(#ty::from_normalized_str(raw)#handle_failure)
}
}
}
} else {
quote! {
#[allow(clippy::needless_question_mark, clippy::unsafe_derive_deserialize)]
#[automatically_derived]
impl<'de: 'a, 'a> ::serde::Deserialize<'de> for &'a #ty {
fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> ::#core::result::Result<Self, D::Error> {
let raw = <&str as ::serde::Deserialize<'de>>::deserialize(deserializer)?;
::#core::result::Result::Ok(#ty::from_str(raw)#handle_failure)
}
}
}
};
quote! {
#[automatically_derived]
impl ::serde::Serialize for #ty {
fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> ::#core::result::Result<S::Ok, S::Error> {
<str as ::serde::Serialize>::serialize(self.as_str(), serializer)
}
}
#deserialize
#deserialize_boxed
}
})
}
}