sp_runtime_interface_proc_macro/pass_by/
inner.rs1use crate::utils::{generate_crate_access, generate_runtime_interface_include};
24
25use syn::{parse_quote, Data, DeriveInput, Error, Fields, Generics, Ident, Result, Type};
26
27use quote::quote;
28
29use proc_macro2::{Span, TokenStream};
30
31pub fn derive_impl(mut input: DeriveInput) -> Result<TokenStream> {
33 add_trait_bounds(&mut input.generics);
34 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
35 let crate_include = generate_runtime_interface_include();
36 let crate_ = generate_crate_access();
37 let ident = input.ident;
38 let (inner_ty, inner_name) = extract_inner_ty_and_name(&input.data)?;
39
40 let access_inner = match inner_name {
41 Some(ref name) => quote!(self.#name),
42 None => quote!(self.0),
43 };
44
45 let from_inner = match inner_name {
46 Some(name) => quote!(Self { #name: inner }),
47 None => quote!(Self(inner)),
48 };
49
50 let res = quote! {
51 const _: () = {
52 #crate_include
53
54 impl #impl_generics #crate_::pass_by::PassBy for #ident #ty_generics #where_clause {
55 type PassBy = #crate_::pass_by::Inner<Self, #inner_ty>;
56 }
57
58 impl #impl_generics #crate_::pass_by::PassByInner for #ident #ty_generics #where_clause {
59 type Inner = #inner_ty;
60
61 fn into_inner(self) -> Self::Inner {
62 #access_inner
63 }
64
65 fn inner(&self) -> &Self::Inner {
66 &#access_inner
67 }
68
69 fn from_inner(inner: Self::Inner) -> Self {
70 #from_inner
71 }
72 }
73 };
74 };
75
76 Ok(res)
77}
78
79fn add_trait_bounds(generics: &mut Generics) {
81 let crate_ = generate_crate_access();
82
83 generics
84 .type_params_mut()
85 .for_each(|type_param| type_param.bounds.push(parse_quote!(#crate_::RIType)));
86}
87
88fn extract_inner_ty_and_name(data: &Data) -> Result<(Type, Option<Ident>)> {
92 if let Data::Struct(ref struct_data) = data {
93 match struct_data.fields {
94 Fields::Named(ref named) if named.named.len() == 1 => {
95 let field = &named.named[0];
96 return Ok((field.ty.clone(), field.ident.clone()))
97 },
98 Fields::Unnamed(ref unnamed) if unnamed.unnamed.len() == 1 => {
99 let field = &unnamed.unnamed[0];
100 return Ok((field.ty.clone(), field.ident.clone()))
101 },
102 _ => {},
103 }
104 }
105
106 Err(Error::new(
107 Span::call_site(),
108 "Only newtype/one field structs are supported by `PassByInner`!",
109 ))
110}