resource_bound_derive/
lib.rs1
2mod outer_attr;
3
4use proc_macro::{TokenStream};
5use quote::quote;
6use syn::{DeriveInput, Fields, spanned::Spanned};
7
8use outer_attr::OuterAttributes;
9
10
11#[proc_macro_derive(ResourceBound, attributes(size_limit, allow_heap))]
16pub fn resource_derive(input: TokenStream) -> TokenStream {
17 let input = syn::parse_macro_input!(input as DeriveInput);
18
19 match expand_resource(&input) {
20 Ok(ts) => ts,
21 Err(e) => e.to_compile_error().into(),
22 }
23}
24
25fn expand_resource(input: &DeriveInput) -> syn::Result<TokenStream> {
26 let name = &input.ident;
27 let fields;
28 match &input.data {
30 syn::Data::Struct(ds) => {fields=&ds.fields}
31 syn::Data::Enum(_) => {
32 return Err(syn::Error::new_spanned(
33 input,
34 "ResourceBound cannot be derived for enums",
35 ));
36 }
37 syn::Data::Union(_) => {
38 return Err(syn::Error::new_spanned(
39 input,
40 "ResourceBound cannot be derived for unions",
41 ));
42 }
43 }
44
45 let lifetimes=input.generics.lifetimes();
47 let liftimes_use=input.generics.lifetimes();
48
49 let mut outer_attrs = OuterAttributes::new();
51 for attr in &input.attrs {
52 outer_attr::parse_struct_attrs(&mut outer_attrs, attr)?;
53 }
54
55
56 let size_limit=match outer_attrs.get_max_size() {
58 Some(s)=>s,
59 None=>0
60 };
61 let heap_permission=outer_attrs.get_heap_allo();if !heap_permission{
63 map_fields(&fields,&mut outer_attrs)?;
64 }
65 let mut field_ctr=0;
66 let field_types=outer_attrs.get_types();
67 let field_assert=field_types.iter().map(move |ty|{
68 field_ctr+=1;
69 let ctr_name=String::from("FIELD")+&field_ctr.to_string();
70 let ctr_name=syn::Ident::new(&ctr_name,ty.span());
71 let assert_fn_name=String::from("assert_fn")+&field_ctr.to_string()[..];
72 let assert_fn_name=syn::Ident::new(&assert_fn_name[..], ty.span());
73 quote! {
74
75 const #ctr_name : () ={
76 const fn #assert_fn_name<T:StackOnly>(){};
77 #assert_fn_name::<#ty>();
78 ()
79 };
80 }
81 });
82
83 let allowed_heap_types_code=quote! {
84 use resource_bound_core::StackOnly;
85
86
87
88 };
89 let heap_assert_code=if !heap_permission {
90 quote! {
91 #allowed_heap_types_code
92 #(#field_assert)*
93 }
94 }else{
95 quote! {
96
97 }
98 };
99 let expanded_limit=quote! {
100
101 #heap_assert_code
102 impl<#(#lifetimes)*> #name <#(#liftimes_use)*> {
103 #[doc(hidden)]
104 const __RESOURCE_BOUND_ASSERTION_FAILED_BECAUSE_THE_STRUCT_SIZE_IS_MORE_THAN_THE_EXPLICITLY_DEFINED_VALUE: [(); 0] =
105 [(); (core::mem::size_of::<Self>() <= #size_limit) as usize - 1];
106 }
107
108 };
109 Ok(expanded_limit
111 .into())
112}
113
114
115fn map_fields(fields:&Fields,mutable:&mut OuterAttributes)->syn::Result<()>{
116
117 for field in fields{
118 let ty=&field.ty;
119 mutable.push_type(ty.clone());
120 }
121
122
123 Ok(())
124}