use proc_macro2::TokenStream;
use quote::quote;
use crate::context::{BaseModule, Context};
use crate::types::objects::AliasDefinition;
pub fn generate(ctx: &Context, def: &AliasDefinition) -> TokenStream {
let name = ctx.type_name(def.type_name().name());
let alias = ctx.rust_type(BaseModule::Objects, def.type_name(), def.alias());
let result = ctx.result_ident(def.type_name());
let docs = ctx.docs(def.docs());
let mut type_attrs = vec![quote!(#[serde(crate = "conjure_object::serde", transparent)])];
let mut field_attrs = vec![];
let mut derives = vec![
"Debug",
"Clone",
"conjure_object::serde::Deserialize",
"conjure_object::serde::Serialize",
];
if ctx.is_copy(def.alias()) {
derives.push("Copy");
}
if ctx.is_double(def.alias()) {
derives.push("conjure_object::private::DeriveWith");
type_attrs.push(quote!(#[derive_with(PartialEq, Eq, PartialOrd, Ord, Hash)]));
field_attrs.push(quote!(#[derive_with(with = conjure_object::private::DoubleWrapper)]));
} else {
derives.push("PartialEq");
derives.push("Eq");
derives.push("PartialOrd");
derives.push("Ord");
derives.push("Hash");
}
if ctx.is_default(def.alias()) {
derives.push("Default");
}
let derives = derives.iter().map(|s| s.parse::<TokenStream>().unwrap());
type_attrs.insert(0, quote!(#[derive(#(#derives),*)]));
let display = if ctx.is_display(def.alias()) {
quote! {
impl std::fmt::Display for #name {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, fmt)
}
}
}
} else {
quote!()
};
let plain = if ctx.is_plain(def.alias()) {
quote! {
impl conjure_object::Plain for #name {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
conjure_object::Plain::fmt(&self.0, fmt)
}
}
impl conjure_object::FromPlain for #name {
type Err = <#alias as conjure_object::FromPlain>::Err;
#[inline]
fn from_plain(s: &str) -> #result<#name, Self::Err> {
conjure_object::FromPlain::from_plain(s).map(#name)
}
}
}
} else {
quote!()
};
let from_iterator = match ctx.is_from_iter(BaseModule::Objects, def.type_name(), def.alias()) {
Some(item) => quote! {
impl std::iter::FromIterator<#item> for #name {
fn from_iter<T>(iter: T) -> Self
where
T: std::iter::IntoIterator<Item = #item>,
{
#name(std::iter::FromIterator::from_iter(iter))
}
}
},
None => quote!(),
};
let dealiased_type = ctx.rust_type(
BaseModule::Objects,
def.type_name(),
ctx.dealiased_type(def.alias()),
);
quote! {
#docs
#(#type_attrs)*
pub struct #name(#(#field_attrs)* pub #alias);
#display
#plain
#from_iterator
impl std::convert::From<#dealiased_type> for #name {
#[inline]
fn from(v: #dealiased_type) -> Self {
#name(std::convert::From::from(v))
}
}
impl std::ops::Deref for #name {
type Target = #alias;
#[inline]
fn deref(&self) -> &#alias {
&self.0
}
}
impl std::ops::DerefMut for #name {
#[inline]
fn deref_mut(&mut self) -> &mut #alias {
&mut self.0
}
}
impl std::convert::AsRef<#dealiased_type> for #name {
#[inline]
fn as_ref(&self) -> &#dealiased_type {
&self.0
}
}
}
}