#![allow(clippy::manual_unwrap_or_default)]
use darling::{
FromDeriveInput, FromField, FromMeta, FromVariant,
ast::{Data, Fields},
util::{Flag, Override, SpannedValue},
};
use proc_macro_crate::{FoundCrate, crate_name};
use proc_macro_error2::{abort_call_site, emit_error};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::spanned::Spanned;
use crate::type_path_ext::TypePathWrapper;
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(mapper), supports(struct_named, struct_newtype, struct_tuple, enum_any))]
pub(super) struct MapperOpts {
pub(super) ident: syn::Ident,
pub(super) generics: syn::Generics,
pub(super) data: Data<VariantReceiver, FieldReceiver>,
#[darling(default, multiple, rename = "derive")]
items: Vec<ItemInput>,
#[darling(default, rename = "ty")]
path: Option<SpannedValue<TypePathWrapper>>,
#[darling(default)]
from: Option<SpannedValue<Override<DeriveInput>>>,
#[darling(default)]
into: Option<SpannedValue<Override<DeriveInput>>>,
#[darling(default)]
try_from: Option<SpannedValue<Override<DeriveInput>>>,
#[darling(default)]
try_into: Option<SpannedValue<Override<DeriveInput>>>,
#[darling(default, multiple)]
add: Vec<AddInput>,
#[darling(default)]
ignore_extra: SpannedValue<Flag>,
}
#[derive(Debug, FromMeta, Clone)]
pub(super) struct ItemInput {
#[darling(rename = "ty")]
pub(super) path: SpannedValue<TypePathWrapper>,
#[darling(default)]
pub(super) from: Option<SpannedValue<Override<DeriveInput>>>,
#[darling(default)]
pub(super) into: Option<SpannedValue<Override<DeriveInput>>>,
#[darling(default)]
pub(super) try_from: Option<SpannedValue<Override<DeriveInput>>>,
#[darling(default)]
pub(super) try_into: Option<SpannedValue<Override<DeriveInput>>>,
#[darling(default, multiple)]
pub(super) add: Vec<AddInput>,
#[darling(default)]
pub(super) ignore_extra: SpannedValue<Flag>,
}
#[derive(Debug, FromVariant, Clone)]
#[darling(attributes(mapper))]
pub(super) struct VariantReceiver {
pub(super) ident: syn::Ident,
pub(super) discriminant: Option<syn::Expr>,
pub(super) fields: Fields<FieldReceiver>,
#[darling(default, multiple, rename = "when")]
items: Vec<ItemVariantInput>,
#[darling(default, rename = "ty")]
path: Option<SpannedValue<TypePathWrapper>>,
#[darling(default)]
rename: Option<SpannedValue<syn::Ident>>,
#[darling(default, multiple)]
add: Vec<AddInput>,
#[darling(default)]
skip: Option<SpannedValue<Override<SkipInput>>>,
#[darling(default)]
ignore_extra: SpannedValue<Flag>,
}
macro_field_utils::variant_info!(VariantReceiver, FieldReceiver);
#[derive(Debug, FromMeta, Clone)]
struct ItemVariantInput {
#[darling(rename = "ty")]
path: SpannedValue<TypePathWrapper>,
#[darling(default)]
rename: Option<SpannedValue<syn::Ident>>,
#[darling(default, multiple)]
add: Vec<AddInput>,
#[darling(default)]
skip: Option<SpannedValue<Override<SkipInput>>>,
#[darling(default)]
ignore_extra: SpannedValue<Flag>,
}
#[derive(Debug, FromField, Clone)]
#[darling(attributes(mapper))]
pub(super) struct FieldReceiver {
pub(super) ident: Option<syn::Ident>,
pub(super) vis: syn::Visibility,
pub(super) ty: syn::Type,
#[darling(default, multiple, rename = "when")]
items: Vec<ItemFieldInput>,
#[darling(default, rename = "ty")]
path: Option<SpannedValue<TypePathWrapper>>,
#[darling(default)]
rename: Option<SpannedValue<syn::Ident>>,
#[darling(default)]
skip: Option<SpannedValue<Override<SkipInput>>>,
#[darling(default)]
other_ty: Option<SpannedValue<syn::Ident>>,
#[darling(flatten)]
hint: MapperHint,
}
macro_field_utils::field_info!(FieldReceiver);
#[derive(Debug, FromMeta, Clone)]
struct ItemFieldInput {
#[darling(rename = "ty")]
path: SpannedValue<TypePathWrapper>,
#[darling(default)]
rename: Option<SpannedValue<syn::Ident>>,
#[darling(default)]
skip: Option<SpannedValue<Override<SkipInput>>>,
#[darling(default)]
other_ty: Option<SpannedValue<syn::Ident>>,
#[darling(flatten)]
hint: MapperHint,
}
#[derive(Debug, FromMeta, Clone)]
pub(super) struct MapperHint {
#[darling(default)]
with: Option<SpannedValue<syn::Expr>>,
#[darling(default)]
into_with: Option<SpannedValue<syn::Expr>>,
#[darling(default)]
from_with: Option<SpannedValue<syn::Expr>>,
#[darling(default)]
opt: Option<SpannedValue<Override<Box<MapperHint>>>>,
#[darling(default)]
iter: Option<SpannedValue<Override<Box<MapperHint>>>>,
#[darling(default)]
map: Option<SpannedValue<Override<Box<MapperHint>>>>,
#[darling(default)]
boxed: Option<SpannedValue<Override<Box<MapperHint>>>>,
#[darling(default, rename = "box")]
r#box: Option<SpannedValue<Override<Box<MapperHint>>>>,
#[darling(default)]
unbox: Option<SpannedValue<Override<Box<MapperHint>>>>,
}
#[derive(Debug, FromMeta, Clone)]
pub(super) struct DeriveInput {
#[darling(default)]
pub(super) custom: Option<SpannedValue<Override<syn::Ident>>>,
}
#[derive(Debug, FromMeta, Clone)]
pub(super) struct AddInput {
pub(super) field: SpannedValue<syn::Ident>,
#[darling(default)]
pub(super) ty: Option<SpannedValue<TypePathWrapper>>,
#[darling(default)]
pub(super) default: Option<SpannedValue<Override<DefaultInput>>>,
}
#[derive(Debug, FromMeta, Clone)]
pub(super) struct DefaultInput {
pub(crate) value: syn::Expr,
}
#[derive(Debug, FromMeta, Clone)]
pub(super) struct SkipInput {
#[darling(default)]
pub(super) default: Option<SpannedValue<Override<DefaultInput>>>,
}
impl MapperOpts {
pub(super) fn items(&self) -> Vec<ItemInput> {
if !self.items.is_empty() {
if let Some(path) = self.path.as_ref() {
emit_error!(path.span(), "Illegal attribute when 'derive' is set")
}
if let Some(from) = self.from.as_ref() {
emit_error!(from.span(), "Illegal attribute when 'derive' is set")
}
if let Some(into) = self.into.as_ref() {
emit_error!(into.span(), "Illegal attribute when 'derive' is set")
}
if let Some(try_from) = self.try_from.as_ref() {
emit_error!(try_from.span(), "Illegal attribute when 'derive' is set")
}
if let Some(try_into) = self.try_into.as_ref() {
emit_error!(try_into.span(), "Illegal attribute when 'derive' is set")
}
if self.ignore_extra.is_present() {
emit_error!(self.ignore_extra.span(), "Illegal attribute when 'derive' is set")
}
if !self.add.is_empty() {
for i in &self.add {
emit_error!(i.field.span(), "Illegal attribute when 'derive' is set")
}
}
let paths = self.items.iter().map(|i| &i.path).collect::<Vec<_>>();
for i in 0..paths.len() {
for j in 0..paths.len() {
if i != j && paths[i].as_ref() == paths[j].as_ref() {
emit_error!(paths[j].span(), "This type is duplicated")
}
}
}
self.items.to_vec()
} else if let Some(path) = self.path.as_ref() {
vec![ItemInput {
path: path.clone(),
from: self.from.clone(),
into: self.into.clone(),
try_from: self.try_from.clone(),
try_into: self.try_into.clone(),
ignore_extra: self.ignore_extra,
add: self.add.clone(),
}]
} else {
abort_call_site!("One of 'ty' or 'derive' must be set")
}
}
}
impl ItemInput {
pub(super) fn validate(&self, is_enum: bool) {
if self.from.is_none() && self.into.is_none() && self.try_from.is_none() && self.try_into.is_none() {
emit_error!(
self.path.span(),
"One of 'from', 'into', 'try_from' or 'try_into' must be set"
);
}
let items = self.add.iter().filter(|a| a.default.is_none()).collect::<Vec<_>>();
if !items.is_empty() && !is_enum {
let mut has_into = false;
let mut missing_custom = false;
if let Some(into) = self.into.as_deref() {
has_into = true;
if into.as_ref().explicit().map(|e| e.custom.is_none()).unwrap_or(true) {
missing_custom = true;
}
}
if let Some(try_into) = self.try_into.as_deref() {
has_into = true;
if try_into.as_ref().explicit().map(|e| e.custom.is_none()).unwrap_or(true) {
missing_custom = true;
}
}
if missing_custom || has_into {
for e in items {
if missing_custom {
emit_error!(
e.field.span(),
"Enable `default` here or include `custom` on `into` and `try_into` derives"
);
}
if e.ty.is_none() && has_into {
emit_error!(
e.field.span(),
"Provide a field type with `ty` if the field is not `default` to derive `into` and \
`try_into`"
);
}
}
}
}
if is_enum {
for a in &self.add {
if let Some(ty) = &a.ty {
emit_error!(ty.span(), "Illegal attribute for enums")
}
if a.default.is_none() && (self.from.is_some() || self.try_from.is_some()) {
emit_error!(
a.field.span(),
"Missing mandatory `default` for enums when deriving `from` or `try_from`"
)
}
}
}
}
}
impl ItemVariantInput {
fn validate(&self, derives: &[ItemInput]) {
let derive = derives.iter().find(|d| d.path.as_ref() == self.path.as_ref());
if let Some(derive) = derive {
let items = self.add.iter().filter(|a| a.default.is_none()).collect::<Vec<_>>();
if !items.is_empty() {
let mut has_into = false;
let mut missing_custom = false;
if let Some(into) = derive.into.as_deref() {
has_into = true;
if into.as_ref().explicit().map(|e| e.custom.is_none()).unwrap_or(true) {
missing_custom = true;
}
}
if let Some(try_into) = derive.try_into.as_deref() {
has_into = true;
if try_into.as_ref().explicit().map(|e| e.custom.is_none()).unwrap_or(true) {
missing_custom = true;
}
}
if missing_custom || has_into {
for e in items {
if missing_custom {
emit_error!(
e.field.span(),
"Enable `default` here or include `custom` on `into` and `try_into` derives"
);
}
if e.ty.is_none() && has_into {
emit_error!(
e.field.span(),
"Provide a field type with `ty` if the field is not `default` to derive `into` and \
`try_into`"
);
}
}
}
}
if let Some(skip) = self.skip.as_ref()
&& Override::as_ref(skip)
.explicit()
.map(|e| e.default.is_none())
.unwrap_or(true)
{
if derive.into.is_some() || derive.try_into.is_some() {
emit_error!(
skip.span(),
"Enable `default` here required for `into` and `try_into` derives"
);
}
}
} else {
emit_error!(self.path.span(), "There is no derive defined for this type");
}
}
}
impl VariantReceiver {
pub(super) fn validate(&self, derives: &[ItemInput]) {
if !self.items.is_empty() {
if let Some(path) = self.path.as_ref() {
emit_error!(path.span(), "Illegal attribute if 'when' is set")
}
if let Some(rename) = self.rename.as_ref() {
emit_error!(rename.span(), "Illegal attribute if 'when' is set")
}
if !self.add.is_empty() {
for i in &self.add {
emit_error!(i.field.span(), "Illegal attribute if 'when' is set")
}
}
if let Some(skip) = self.skip.as_ref() {
emit_error!(skip.span(), "Illegal attribute if 'when' is set")
}
if self.ignore_extra.is_present() {
emit_error!(self.ignore_extra.span(), "Illegal attribute if 'when' is set")
}
let paths = self.items.iter().map(|i| &i.path).collect::<Vec<_>>();
for i in 0..paths.len() {
for j in 0..paths.len() {
if i != j && paths[i].as_ref() == paths[j].as_ref() {
emit_error!(paths[j].span(), "This type is duplicated")
}
}
}
}
if let Some(path) = &self.path {
ItemVariantInput {
path: path.clone(),
rename: self.rename.clone(),
add: self.add.to_vec(),
skip: self.skip.clone(),
ignore_extra: self.ignore_extra,
}
.validate(derives);
} else {
for d in derives {
ItemVariantInput {
path: d.path.clone(),
rename: self.rename.clone(),
add: self.add.to_vec(),
skip: self.skip.clone(),
ignore_extra: self.ignore_extra,
}
.validate(derives);
}
}
for item in self.items.iter() {
item.validate(derives);
}
self.fields.iter().for_each(|f| f.validate(derives));
}
pub(super) fn rename_for(&self, derive_path: &syn::TypePath) -> Option<&syn::Ident> {
for item in &self.items {
if item.path.as_ref() == derive_path {
return item.rename.as_deref();
}
}
if let Some(path) = &self.path {
if path.as_ref() == derive_path {
self.rename.as_deref()
} else {
None
}
} else {
self.rename.as_deref()
}
}
pub(super) fn additional_for(&self, derive_path: &syn::TypePath) -> Option<&Vec<AddInput>> {
for item in &self.items {
if item.path.as_ref() == derive_path {
if item.add.is_empty() {
return None;
} else {
return Some(item.add.as_ref());
}
}
}
if let Some(path) = &self.path {
if path.as_ref() == derive_path {
if self.add.is_empty() {
None
} else {
Some(self.add.as_ref())
}
} else {
None
}
} else if self.add.is_empty() {
None
} else {
Some(self.add.as_ref())
}
}
pub(super) fn skip_for(&self, derive_path: &syn::TypePath) -> Option<&Override<SkipInput>> {
for item in &self.items {
if item.path.as_ref() == derive_path {
return item.skip.as_deref();
}
}
if let Some(path) = &self.path {
if path.as_ref() == derive_path {
self.skip.as_deref()
} else {
None
}
} else {
self.skip.as_deref()
}
}
pub(super) fn ignore_extra_for(&self, derive_path: &syn::TypePath) -> bool {
for item in &self.items {
if item.path.as_ref() == derive_path {
return item.ignore_extra.is_present();
}
}
if let Some(path) = &self.path {
if path.as_ref() == derive_path {
self.ignore_extra.is_present()
} else {
false
}
} else {
self.ignore_extra.is_present()
}
}
}
impl ItemFieldInput {
fn validate(&self, span: Span, derives: &[ItemInput]) {
let derive = derives.iter().find(|d| d.path.as_ref() == self.path.as_ref());
if let Some(derive) = derive {
if let Some(skip) = self.skip.as_ref()
&& Override::as_ref(skip)
.explicit()
.map(|e| e.default.is_none())
.unwrap_or(true)
{
let mut missing_custom = false;
if let Some(from) = derive.from.as_deref()
&& from.as_ref().explicit().map(|e| e.custom.is_none()).unwrap_or(true)
{
missing_custom = true;
}
if let Some(try_from) = derive.try_from.as_deref()
&& try_from.as_ref().explicit().map(|e| e.custom.is_none()).unwrap_or(true)
{
missing_custom = true;
}
if missing_custom {
emit_error!(
skip.span(),
"Enable `default` here or include `custom` on `from` and `try_from` derives"
);
}
}
let mut hint_count = 0;
if self.hint.with.is_some() {
hint_count += 1;
}
if self.hint.from_with.is_some() || self.hint.into_with.is_some() {
hint_count += 1;
}
if self.hint.opt.is_some() {
hint_count += 1;
}
if self.hint.iter.is_some() {
hint_count += 1;
}
if self.hint.map.is_some() {
hint_count += 1;
}
if self.hint.boxed.is_some() {
hint_count += 1;
}
if self.hint.r#box.is_some() {
hint_count += 1;
}
if self.hint.unbox.is_some() {
hint_count += 1;
}
if hint_count > 1 {
emit_error!(
span,
"Only one of 'with', 'into_with'/'from_with', 'opt', 'iter', 'map', 'boxed', 'box' or 'unbox' can \
be set"
);
}
} else {
emit_error!(self.path.span(), "There is no derive defined for this type");
}
}
}
impl FieldReceiver {
pub(super) fn validate(&self, derives: &[ItemInput]) {
if !self.items.is_empty() {
if let Some(path) = self.path.as_ref() {
emit_error!(path.span(), "Illegal attribute if 'when' is set")
}
if let Some(rename) = self.rename.as_ref() {
emit_error!(rename.span(), "Illegal attribute if 'when' is set")
}
if let Some(skip) = self.skip.as_ref() {
emit_error!(skip.span(), "Illegal attribute if 'when' is set")
}
if let Some(with) = self.hint.with.as_ref() {
emit_error!(with.span(), "Illegal attribute if 'when' is set")
}
if let Some(into_with) = self.hint.into_with.as_ref() {
emit_error!(into_with.span(), "Illegal attribute if 'when' is set")
}
if let Some(from_with) = self.hint.from_with.as_ref() {
emit_error!(from_with.span(), "Illegal attribute if 'when' is set")
}
if let Some(opt) = self.hint.opt.as_ref() {
emit_error!(opt.span(), "Illegal attribute if 'when' is set")
}
if let Some(iter) = self.hint.iter.as_ref() {
emit_error!(iter.span(), "Illegal attribute if 'when' is set")
}
if let Some(map) = self.hint.map.as_ref() {
emit_error!(map.span(), "Illegal attribute if 'when' is set")
}
if let Some(boxed) = self.hint.boxed.as_ref() {
emit_error!(boxed.span(), "Illegal attribute if 'when' is set")
}
if let Some(r#box) = self.hint.r#box.as_ref() {
emit_error!(r#box.span(), "Illegal attribute if 'when' is set")
}
if let Some(unbox) = self.hint.unbox.as_ref() {
emit_error!(unbox.span(), "Illegal attribute if 'when' is set")
}
let paths = self.items.iter().map(|i| &i.path).collect::<Vec<_>>();
for i in 0..paths.len() {
for j in 0..paths.len() {
if i != j && paths[i].as_ref() == paths[j].as_ref() {
emit_error!(paths[j].span(), "This type is duplicated")
}
}
}
}
let span = self.ident.as_ref().map(|i| i.span()).unwrap_or_else(|| self.ty.span());
if let Some(path) = &self.path {
ItemFieldInput {
path: path.clone(),
rename: self.rename.clone(),
skip: self.skip.clone(),
other_ty: self.other_ty.clone(),
hint: self.hint.clone(),
}
.validate(span, derives);
} else {
for d in derives {
ItemFieldInput {
path: d.path.clone(),
rename: self.rename.clone(),
skip: self.skip.clone(),
other_ty: self.other_ty.clone(),
hint: self.hint.clone(),
}
.validate(span, derives);
}
}
for item in self.items.iter() {
item.validate(span, derives);
}
}
pub(super) fn rename_for(&self, derive_path: &syn::TypePath) -> Option<&syn::Ident> {
for item in &self.items {
if item.path.as_ref() == derive_path {
return item.rename.as_deref();
}
}
if let Some(path) = &self.path {
if path.as_ref() == derive_path {
self.rename.as_deref()
} else {
None
}
} else {
self.rename.as_deref()
}
}
pub(super) fn skip_for(&self, derive_path: &syn::TypePath) -> Option<&Override<SkipInput>> {
for item in &self.items {
if item.path.as_ref() == derive_path {
return item.skip.as_deref();
}
}
if let Some(path) = &self.path {
if path.as_ref() == derive_path {
self.skip.as_deref()
} else {
None
}
} else {
self.skip.as_deref()
}
}
pub(super) fn other_ty_for(&self, derive_path: &syn::TypePath) -> Option<&syn::Ident> {
for item in &self.items {
if item.path.as_ref() == derive_path {
return item.other_ty.as_deref();
}
}
if let Some(path) = &self.path {
if path.as_ref() == derive_path {
self.other_ty.as_deref()
} else {
None
}
} else {
self.other_ty.as_deref()
}
}
fn hint_for(&self, derive_path: &syn::TypePath) -> Option<&MapperHint> {
for item in &self.items {
if item.path.as_ref() == derive_path {
return Some(&item.hint);
}
}
if let Some(path) = &self.path {
if path.as_ref() == derive_path {
Some(&self.hint)
} else {
None
}
} else {
Some(&self.hint)
}
}
pub(super) fn build_into_for(
&self,
from: bool,
is_try: bool,
ident: &syn::Ident,
derive_path: &syn::TypePath,
) -> TokenStream {
let into = build_into_for_inner(from, is_try, ident, self.hint_for(derive_path));
if is_try { quote!(#into?) } else { into }
}
}
fn build_into_for_inner(from: bool, is_try: bool, ident: &syn::Ident, hint: Option<&MapperHint>) -> TokenStream {
if let Some(hint) = hint {
let check_with = |with: &Option<SpannedValue<syn::Expr>>| {
if let Some(with) = with {
let with = with.as_ref();
if let syn::Expr::Path(with_path) = with {
let crate_name = match crate_name("model-mapper") {
Ok(FoundCrate::Itself) => quote!(::model_mapper),
Ok(FoundCrate::Name(name)) => {
let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
quote!(::#ident)
}
Err(_) => quote!(::model_mapper),
};
Some(quote!({
use #crate_name::private::{RefMapper, ValueMapper};
(&(#with_path)).map_value(#ident)
}))
} else if is_try {
Some(quote!(Ok::<_, anyhow::Error>(#with)))
} else {
Some(quote!(#with))
}
} else {
None
}
};
if from {
if let Some(t) = check_with(&hint.from_with) {
return t;
}
} else if let Some(t) = check_with(&hint.into_with) {
return t;
}
if let Some(t) = check_with(&hint.with) {
return t;
} else if let Some(opt) = &hint.opt {
let inner;
if let Some(inner_hint) = opt.as_ref().as_ref().explicit() {
inner = build_into_for_inner(from, is_try, ident, Some(inner_hint));
} else {
inner = build_into_for_inner(from, is_try, ident, None);
}
if is_try {
return quote!(#ident.map(|#ident| #inner).transpose());
} else {
return quote!(#ident.map(|#ident| #inner));
}
} else if let Some(iter) = &hint.iter {
let inner;
if let Some(inner_hint) = iter.as_ref().as_ref().explicit() {
inner = build_into_for_inner(from, is_try, ident, Some(inner_hint));
} else {
inner = build_into_for_inner(from, is_try, ident, None);
}
if is_try {
return quote!(#ident.into_iter().map(|#ident| #inner).collect::<std::result::Result<_, _>>());
} else {
return quote!(#ident.into_iter().map(|#ident| #inner).collect());
}
} else if let Some(map) = &hint.map {
let inner;
if let Some(inner_hint) = map.as_ref().as_ref().explicit() {
inner = build_into_for_inner(from, is_try, ident, Some(inner_hint));
} else {
inner = build_into_for_inner(from, is_try, ident, None);
}
if is_try {
return quote!(
#ident.into_iter().map(|(k, #ident)| #inner.map(|v| (k, v))).collect::<std::result::Result<_, _>>()
);
} else {
return quote!(#ident.into_iter().map(|(k, #ident)| (k, #inner)).collect());
}
} else if hint.boxed.is_some() || hint.r#box.is_some() || hint.unbox.is_some() {
let (is_input_boxed, is_output_boxed) = if hint.boxed.is_some() {
(true, true)
} else if hint.r#box.is_some() {
if from { (true, false) } else { (false, true) }
} else {
if from { (false, true) } else { (true, false) }
};
let hint_opt = hint
.boxed
.as_ref()
.or(hint.r#box.as_ref())
.or(hint.unbox.as_ref())
.unwrap();
let inner;
if let Some(inner_hint) = hint_opt.as_ref().as_ref().explicit() {
inner = build_into_for_inner(from, is_try, ident, Some(inner_hint));
} else {
inner = build_into_for_inner(from, is_try, ident, None);
}
let input_expr = if is_input_boxed {
quote!(*#ident)
} else {
quote!(#ident)
};
if is_try {
if is_output_boxed {
return quote!({
let #ident = #input_expr;
#inner.map(|v| std::boxed::Box::new(v))
});
} else {
return quote!({
let #ident = #input_expr;
#inner
});
}
} else {
if is_output_boxed {
return quote!({
let #ident = #input_expr;
std::boxed::Box::new(#inner)
});
} else {
return quote!({
let #ident = #input_expr;
#inner
});
}
}
}
}
if is_try {
quote!(TryInto::try_into(#ident))
} else {
quote!(Into::into(#ident))
}
}