1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Data, DeriveInput, Fields, Visibility, parse_macro_input};
4
5#[proc_macro_derive(Circuit)]
19pub fn circuit_derive(input: TokenStream) -> TokenStream {
20 let input = parse_macro_input!(input as DeriveInput);
21
22 match generate_circuit_impl(&input) {
23 Ok(tokens) => tokens,
24 Err(err) => err.to_compile_error().into(),
25 }
26}
27
28fn generate_circuit_impl(input: &DeriveInput) -> syn::Result<TokenStream> {
29 let name = &input.ident;
30 let name_str = name.to_string().to_lowercase();
31
32 let module_name = format_ident!("__rsnark_generated_{}", name_str);
34
35 let define_name = format_ident!("{}CircuitDefine", name);
37
38 let public_witness_name = format_ident!("{}PublicWitness", name);
40
41 let fields = match &input.data {
43 Data::Struct(data) => match &data.fields {
44 Fields::Named(fields) => &fields.named,
45 _ => {
46 return Err(syn::Error::new_spanned(
47 input,
48 "Only named fields are supported",
49 ));
50 }
51 },
52 _ => return Err(syn::Error::new_spanned(input, "Only structs are supported")),
53 };
54
55 let mut private_fields = Vec::new();
57 let mut public_fields = Vec::new();
58
59 for field in fields {
60 let field_name = field.ident.as_ref().unwrap();
61 let field_type = &field.ty;
62
63 match &field.vis {
64 Visibility::Public(_) => {
65 public_fields.push((field_name, field_type));
66 }
67 _ => {
68 private_fields.push((field_name, field_type));
69 }
70 }
71 }
72
73 let define_fields = fields.iter().map(|field| {
75 let field_name = field.ident.as_ref().unwrap();
76 let field_type = &field.ty;
77
78 match &field.vis {
79 Visibility::Public(_) => {
80 quote! {
81 pub #field_name: ::rsnark_core::PublicCircuitElement<#field_type>
82 }
83 }
84 _ => {
85 quote! {
86 pub #field_name: ::rsnark_core::PrivateCircuitElement<#field_type>
87 }
88 }
89 }
90 });
91
92 let new_field_inits = fields.iter().map(|field| {
94 let field_name = field.ident.as_ref().unwrap();
95 let field_type = &field.ty;
96
97 match &field.vis {
98 Visibility::Public(_) => {
99 quote! {
100 let #field_name = #field_type::create_public(initer, is_private);
101 }
102 }
103 _ => {
104 quote! {
105 let #field_name = #field_type::create_private(initer);
106 }
107 }
108 }
109 });
110
111 let field_names: Vec<_> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();
112
113 let append_public_impl_orig = public_fields.iter().map(|(field_name, _)| {
115 quote! {
116 self.#field_name.append_public_witness(witness, false);
117 }
118 });
119
120 let append_public_impl_witness = public_fields.iter().map(|(field_name, _)| {
122 quote! {
123 self.#field_name.append_public_witness(witness, false);
124 }
125 });
126
127 let append_witness_impl = fields.iter().map(|field| {
129 let field_name = field.ident.as_ref().unwrap();
130
131 match &field.vis {
132 Visibility::Public(_) => {
133 quote! {
135 self.#field_name.append_witness(public, private, false || _is_private);
136 }
137 }
138 _ => {
139 quote! {
141 self.#field_name.append_witness(public, private, true);
142 }
143 }
144 }
145 });
146
147 let public_witness_fields = public_fields.iter().map(|(field_name, _)| {
149 quote! {
150 #field_name: self.#field_name.into_public_witness()
151 }
152 });
153
154 let public_witness_struct_fields = public_fields.iter().map(|(field_name, field_type)| {
156 quote! {
157 pub #field_name: ::rsnark_core::PublicWitness<#field_type>
158 }
159 });
160
161 let expanded = quote! {
162 mod #module_name {
163 use super::*;
164
165 use ::rsnark_core::{
166 CircuitWitness, CircuitPublicWitness, U256, VariableIniter,
167 };
168
169 impl CircuitWitness for #name {
170 type PrivateElement = #define_name;
171 type PublicElement = #define_name;
172 type PublicWitness = #public_witness_name;
173
174 fn create_public(initer: &mut VariableIniter, is_private: bool) -> Self::PublicElement {
175 #define_name::new(initer, is_private)
176 }
177
178 fn create_private(initer: &mut VariableIniter) -> Self::PrivateElement {
179 #define_name::new(initer, true)
180 }
181
182 fn append_witness(&self, public: &mut Vec<U256>, private: &mut Vec<U256>, _is_private: bool) {
183 #(#append_witness_impl)*
184 }
185
186 fn into_public_witness(self) -> Self::PublicWitness {
187 #public_witness_name {
188 #(#public_witness_fields,)*
189 }
190 }
191 }
192
193 #[doc(hidden)]
194 pub struct #define_name {
195 #(#define_fields,)*
196 }
197
198 impl #define_name {
199 fn new(initer: &mut VariableIniter, is_private: bool) -> Self {
200 #(#new_field_inits)*
201
202 Self {
203 #(#field_names,)*
204 }
205 }
206 }
207
208 impl CircuitPublicWitness for #name {
209 fn append_public_witness(&self, witness: &mut Vec<U256>, _is_private: bool) {
210 #(#append_public_impl_orig)*
211 }
212 }
213
214 #[doc(hidden)]
215 pub struct #public_witness_name {
216 #(#public_witness_struct_fields,)*
217 }
218
219 impl CircuitPublicWitness for #public_witness_name {
220 fn append_public_witness(&self, witness: &mut Vec<U256>, _is_private: bool) {
221 #(#append_public_impl_witness)*
222 }
223 }
224 }
225 };
226
227 Ok(TokenStream::from(expanded))
228}