use crate::{function_args::*, prelude::*, with_tokens::*};
use proc_macro2::TokenStream;
use quote::quote_spanned;
use syn::{parse_quote as pq, Ident, Path, ReturnType, Type};
pub(crate) type GenIn<'a> =
FunctionArgs<'a, Box<[WithTokens<'a, Type>]>, WithTokens<'a, ReturnType>>;
pub(crate) type GenOut = Result<TokenStream>;
pub(crate) type GenFn = fn(GenIn) -> GenOut;
pub(crate) fn get_trait_fn(ident: &Ident) -> Result<GenFn> {
let key = ident.to_string();
let has_alloc = || -> Result<bool> {
if cfg!(feature = "alloc") {
Ok(true)
} else {
Err(diagnostic_error! {
ident, "this trait requires an allocator"
; help = "enable zoet's `alloc` feature"
})
}
};
let is_marker = || {
Err(diagnostic_error! {
ident, "this is a marker trait"
; help = "`#[derive({})]` on the struct/enum/union definition instead", key
})
};
let func: GenFn = match &*key {
"Borrow" => |f| borrow_shaped(f, &pq!(::core::borrow::Borrow), &pq!(borrow)),
"BorrowMut" => |f| borrow_mut_shaped(f, &pq!(::core::borrow::BorrowMut), &pq!(borrow_mut)),
"ToOwned" if has_alloc()? => to_owned,
"Clone" => clone,
"Eq" => return is_marker(),
"Ord" => ord,
"PartialEq" => partial_eq,
"PartialOrd" => partial_ord,
"AsMut" => |f| borrow_mut_shaped(f, &pq!(::core::convert::AsMut), &pq!(as_mut)),
"AsRef" => |f| borrow_shaped(f, &pq!(::core::convert::AsRef), &pq!(as_ref)),
"From" => from,
"Into" => into,
"TryFrom" => try_from,
"TryInto" => try_into,
"Default" => default,
"Binary" => |f| debug_shaped(f, &pq!(::core::fmt::Binary)),
"Debug" => |f| debug_shaped(f, &pq!(::core::fmt::Debug)),
"Display" => |f| debug_shaped(f, &pq!(::core::fmt::Display)),
"LowerExp" => |f| debug_shaped(f, &pq!(::core::fmt::LowerExp)),
"LowerHex" => |f| debug_shaped(f, &pq!(::core::fmt::LowerHex)),
"Octal" => |f| debug_shaped(f, &pq!(::core::fmt::Octal)),
"Pointer" => |f| debug_shaped(f, &pq!(::core::fmt::Pointer)),
"UpperExp" => |f| debug_shaped(f, &pq!(::core::fmt::UpperExp)),
"UpperHex" => |f| debug_shaped(f, &pq!(::core::fmt::UpperHex)),
"Write" => write,
"Future" => future,
"IntoFuture" => into_future,
"Hash" => hash,
"IntoIterator" => into_iterator,
"Iterator" => iterator,
"Add" => |f| add_shaped(f, &pq!(::core::ops::Add), &pq!(add)),
"AddAssign" => |f| add_assign_shaped(f, &pq!(::core::ops::AddAssign), &pq!(add_assign)),
"BitAnd" => |f| add_shaped(f, &pq!(::core::ops::BitAnd), &pq!(bitand)),
"BitAndAssign" =>
|f| add_assign_shaped(f, &pq!(::core::ops::BitAndAssign), &pq!(bitand_assign)),
"BitOr" => |f| add_shaped(f, &pq!(::core::ops::BitOr), &pq!(bitor)),
"BitOrAssign" =>
|f| add_assign_shaped(f, &pq!(::core::ops::BitOrAssign), &pq!(bitor_assign)),
"BitXor" => |f| add_shaped(f, &pq!(::core::ops::BitXor), &pq!(bitxor)),
"BitXorAssign" =>
|f| add_assign_shaped(f, &pq!(::core::ops::BitXorAssign), &pq!(bitxor_assign)),
"Deref" => deref,
"DerefMut" => deref_mut,
"Div" => |f| add_shaped(f, &pq!(::core::ops::Div), &pq!(div)),
"DivAssign" => |f| add_assign_shaped(f, &pq!(::core::ops::DivAssign), &pq!(div_assign)),
"Drop" => drop,
"Index" => index,
"IndexMut" => index_mut,
"Mul" => |f| add_shaped(f, &pq!(::core::ops::Mul), &pq!(mul)),
"MulAssign" => |f| add_assign_shaped(f, &pq!(::core::ops::MulAssign), &pq!(mul_assign)),
"Neg" => |f| neg_shaped(f, &pq!(::core::ops::Neg), &pq!(neg)),
"Not" => |f| neg_shaped(f, &pq!(::core::ops::Not), &pq!(not)),
"Rem" => |f| add_shaped(f, &pq!(::core::ops::Rem), &pq!(rem)),
"RemAssign" => |f| add_assign_shaped(f, &pq!(::core::ops::RemAssign), &pq!(rem_assign)),
"Shl" => |f| add_shaped(f, &pq!(::core::ops::Shl), &pq!(shl)),
"ShlAssign" => |f| add_assign_shaped(f, &pq!(::core::ops::ShlAssign), &pq!(shl_assign)),
"Shr" => |f| add_shaped(f, &pq!(::core::ops::Shr), &pq!(shr)),
"ShrAssign" => |f| add_assign_shaped(f, &pq!(::core::ops::ShrAssign), &pq!(shr_assign)),
"Sub" => |f| add_shaped(f, &pq!(::core::ops::Sub), &pq!(sub)),
"SubAssign" => |f| add_assign_shaped(f, &pq!(::core::ops::SubAssign), &pq!(sub_assign)),
"FromStr" => from_str,
"ToString" if has_alloc()? => to_string,
_ =>
return Err(diagnostic_error!(
ident,
"this trait name is not recognised"
)),
};
Ok(func)
}
fn borrow_shaped(func: GenIn, trait_name: &Path, method_name: &Ident) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_ref_param(0)?.unary()?.unwrap_ref_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics #trait_name <#output> for #input #where_clause {
#[inline]
fn #method_name (&self) -> &#output {
#to_call(self)
}
}
})
}
fn borrow_mut_shaped(func: GenIn, trait_name: &Path, method_name: &Ident) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_mut_param(0)?.unary()?.unwrap_mut_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics #trait_name <#output> for #input #where_clause {
#[inline]
fn #method_name (&mut self) -> &mut #output {
#to_call(self)
}
}
})
}
fn to_owned(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_ref_param(0)?.unary()?.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::zoet::__alloc::borrow::ToOwned for #input #where_clause {
type Owned = #output;
#[inline]
fn to_owned(&self) -> Self::Owned {
#to_call(self)
}
}
})
}
fn clone(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_ref_param(0)?.unary()?.has_return()?; let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::clone::Clone for #input #where_clause {
#[inline]
fn clone(&self) -> #output {
#to_call(self)
}
}
})
}
enum CompareShape {
PartialOrd,
PartialEq,
Ord,
}
#[allow(clippy::type_complexity)] fn compare_shape(func: GenIn) -> Result<(CompareShape, FunctionArgs<(Type, Type), Type>)> {
let filtered = func.unwrap_ref_param(0)?.unwrap_ref_param(1)?.binary()?;
let ok = if let Ok(args) = filtered.clone().unwrap_return("Option") {
(CompareShape::PartialOrd, args)
} else {
let args = filtered.has_return()?;
match args.output {
Type::Path(ref type_path) if type_path.path.is_ident("bool") =>
(CompareShape::PartialEq, args),
_ => (CompareShape::Ord, args),
}
};
Ok(ok)
}
fn ord(func: GenIn) -> Result<TokenStream> {
let (
shape,
FunctionArgs {
input: (lhs, rhs),
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
},
) = compare_shape(func)?;
let fn_body = match shape {
CompareShape::Ord => quote_spanned! {
derive_span => #to_call(self, other)
},
_ =>
return Err(diagnostic_error! {
output, "`Ord` requires a function returning `Ordering`"
}),
};
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::cmp::Ord for #lhs #where_clause {
fn cmp(&self, other: &#rhs) -> ::core::cmp::Ordering {
#fn_body
}
}
})
}
fn partial_eq(func: GenIn) -> Result<TokenStream> {
let (
shape,
FunctionArgs {
input: (lhs, rhs),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
..
},
) = compare_shape(func)?;
let fn_body = match shape {
CompareShape::PartialOrd => quote_spanned! {
derive_span =>
#to_call(self, other) == ::core::option::Option::Some(::core::cmp::Ordering::Equals)
},
CompareShape::PartialEq => quote_spanned! {
derive_span => #to_call(self, other)
},
CompareShape::Ord => quote_spanned! {
derive_span => #to_call(self, other) == ::core::cmp::Ordering::Equal
},
};
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::cmp::PartialEq<#rhs> for #lhs #where_clause {
#[inline]
fn eq(&self, other: &#rhs) -> ::core::primitive::bool {
#fn_body
}
}
})
}
fn partial_ord(func: GenIn) -> Result<TokenStream> {
let (
shape,
FunctionArgs {
input: (lhs, rhs),
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
},
) = compare_shape(func)?;
let fn_body = match shape {
CompareShape::PartialOrd => quote_spanned! {
derive_span => #to_call(self, other)
},
CompareShape::Ord => quote_spanned! {
derive_span => ::core::option::Option::Some(#to_call(self, other))
},
CompareShape::PartialEq =>
return Err(diagnostic_error! {
output, "`Partial` requires a function returning `Ordering` or `Option<Ordering>`"
}),
};
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::cmp::PartialOrd<#rhs> for #lhs #where_clause {
#[inline]
fn partial_cmp(&self, other: &#rhs) -> ::core::option::Option<::core::cmp::Ordering> {
#fn_body
}
}
})
}
fn from(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unary()?.has_return()?; let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::convert::From<#input> for #output #where_clause {
#[inline]
fn from(value: #input) -> Self {
#to_call(value)
}
}
})
}
fn into(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unary()?.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::convert::Into<#output> for #input #where_clause {
#[inline]
fn into(self) -> #output {
#to_call(self)
}
}
})
}
fn try_from(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output: (output, err),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unary()?.unwrap_result_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::convert::TryFrom<#input> for #output #where_clause {
type Error = #err;
#[inline]
fn try_from(value: #input) -> ::core::result::Result<Self, Self::Error> {
#to_call(value)
}
}
})
}
fn try_into(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output: (output, err),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unary()?.unwrap_result_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::convert::TryInto<#output> for #input #where_clause {
type Error = #err;
#[inline]
fn try_into(self) -> ::core::result::Result<#output, Self::Error> {
#to_call(self)
}
}
})
}
fn default(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input: (),
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.nullary()?.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::default::Default for #output #where_clause {
#[inline]
fn default() -> Self {
#to_call()
}
}
})
}
fn debug_shaped(func: GenIn, trait_name: &Path) -> Result<TokenStream> {
let FunctionArgs {
input: (obj, formatter),
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func
.unwrap_ref_param(0)?
.unwrap_mut_param(1)?
.binary()?
.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics #trait_name for #obj #where_clause {
#[inline]
fn fmt(&self, f: &mut #formatter) -> #output {
#to_call(self, f)
}
}
})
}
fn write(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input: (obj, str),
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func
.unwrap_mut_param(0)?
.unwrap_ref_param(1)?
.binary()?
.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::fmt::Write for #obj #where_clause {
#[inline]
fn write_str(&mut self, s: &#str) -> #output {
#to_call(self, s)
}
}
})
}
fn future(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input: (obj, _),
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func
.unwrap_param(0, "Pin")?
.unwrap_mut_param(0)?
.binary()?
.unwrap_return("Poll")?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::future::Future for #obj #where_clause {
type Output = #output;
#[inline]
fn poll(
self: ::core::pin::Pin<&mut Self>,
cx: &mut ::core::task::Context
) -> ::core::task::Poll<Self::Output> {
#to_call(self, cx)
}
}
})
}
fn into_future(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unary()?.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::future::IntoFuture for #input #where_clause {
type IntoFuture = #output;
type Output = <Self::IntoFuture as ::core::future::Future>::Output;
#[inline]
fn into_future(self) -> Self::IntoFuture {
#to_call(self)
}
}
})
}
fn hash(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input: (obj, _hasher),
output: (),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func
.unwrap_ref_param(0)?
.unwrap_mut_param(1)?
.binary()?
.default_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::hash::Hash for #obj #where_clause {
#[inline]
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
#to_call(self, state);
}
}
})
}
fn into_iterator(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unary()?.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::iter::IntoIterator for #input #where_clause {
type IntoIter = #output;
type Item = <Self::IntoIter as ::core::iter::Iterator>::Item;
#[inline]
fn into_iter(self) -> Self::IntoIter {
#to_call(self)
}
}
})
}
fn iterator(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_mut_param(0)?.unary()?.unwrap_return("Option")?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::iter::Iterator for #input #where_clause {
type Item = #output;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
#to_call(self)
}
}
})
}
fn add_shaped(func: GenIn, trait_name: &Path, method_name: &Ident) -> Result<TokenStream> {
if let Ok(ts) = add_from_add_assign_shaped(func.clone(), trait_name, method_name) {
return Ok(ts);
}
let FunctionArgs {
input: (lhs, rhs),
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.binary()?.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics #trait_name<#rhs> for #lhs #where_clause {
type Output = #output;
#[inline]
fn #method_name(self, rhs: #rhs) -> Self::Output {
#to_call(self, rhs)
}
}
})
}
fn add_from_add_assign_shaped(
func: GenIn, trait_name: &Path, method_name: &Ident,
) -> Result<TokenStream> {
let FunctionArgs {
input: (lhs, rhs),
output: (),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_mut_param(0)?.binary()?.default_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics #trait_name<#rhs> for #lhs #where_clause {
type Output = #lhs;
#[inline]
fn #method_name(mut self, rhs: #rhs) -> #lhs {
#to_call(&mut self, rhs) ; self
}
}
})
}
fn add_assign_shaped(func: GenIn, trait_name: &Path, method_name: &Ident) -> Result<TokenStream> {
let FunctionArgs {
input: (lhs, rhs),
output: (),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_mut_param(0)?.binary()?.default_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics #trait_name<#rhs> for #lhs #where_clause {
#[inline]
fn #method_name(&mut self, rhs: #rhs) {
#to_call(self, rhs);
}
}
})
}
fn drop(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output: (),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_mut_param(0)?.unary()?.default_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::ops::Drop for #input #where_clause {
#[inline]
fn drop(&mut self) {
#to_call(self);
}
}
})
}
fn index(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input: (coll, idx),
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_ref_param(0)?.binary()?.unwrap_ref_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::ops::Index<#idx> for #coll #where_clause {
type Output = #output;
#[inline]
fn index(&self, index: #idx) -> &Self::Output {
#to_call(self, index)
}
}
})
}
fn index_mut(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input: (coll, idx),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
..
} = func.unwrap_mut_param(0)?.binary()?.unwrap_mut_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::ops::IndexMut<#idx> for #coll #where_clause {
#[inline]
fn index_mut(&mut self, index: #idx) -> &mut Self::Output {
#to_call(self, index)
}
}
})
}
fn neg_shaped(func: GenIn, trait_name: &Path, method_name: &Ident) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unary()?.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics #trait_name for #input #where_clause {
type Output = #output;
#[inline]
fn #method_name(self) -> Self::Output {
#to_call(self)
}
}
})
}
fn deref(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_ref_param(0)?.unary()?.unwrap_ref_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::ops::Deref for #input #where_clause {
type Target = #output;
#[inline]
fn deref(&self) -> &Self::Target {
#to_call(self)
}
}
})
}
fn deref_mut(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_mut_param(0)?.unary()?.unwrap_mut_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::ops::DerefMut for #input #where_clause {
#[inline]
fn deref_mut(&mut self) -> &mut #output {
#to_call(self)
}
}
})
}
fn from_str(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output: (output, err),
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.check_ref_param(0)?.unary()?.unwrap_result_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::core::str::FromStr for #output #where_clause {
type Err = #err;
#[inline]
fn from_str(s: #input) -> ::core::result::Result<Self, Self::Err> {
#to_call(s)
}
}
})
}
fn to_string(func: GenIn) -> Result<TokenStream> {
let FunctionArgs {
input,
output,
meta:
FunctionMeta {
derive_span,
generics,
to_call,
extra_attrs,
..
},
} = func.unwrap_ref_param(0)?.unary()?.has_return()?;
let where_clause = &generics.where_clause;
Ok(quote_spanned! {
derive_span =>
#extra_attrs
impl #generics ::zoet::__alloc::string::ToString for #input #where_clause {
#[inline]
fn to_string(&self) -> #output {
#to_call(self)
}
}
})
}