1extern crate alloc;
2extern crate proc_macro;
3
4use itertools::{multiunzip, Itertools};
5use proc_macro::{Span, TokenStream};
6use quote::{quote, ToTokens};
7use syn::{
8 parse_quote, punctuated::Punctuated, spanned::Spanned, Data, DataStruct, Field, Fields,
9 GenericParam, Ident, Meta, Token,
10};
11
12#[cfg(feature = "tco")]
13mod tco;
14
15#[proc_macro_derive(PreflightExecutor)]
16pub fn preflight_executor_derive(input: TokenStream) -> TokenStream {
17 let ast: syn::DeriveInput = syn::parse(input).unwrap();
18
19 let name = &ast.ident;
20 let generics = &ast.generics;
21 let (_, ty_generics, _) = generics.split_for_impl();
22
23 let default_ty_generic = Ident::new("F", proc_macro2::Span::call_site());
24 let mut new_generics = generics.clone();
25 new_generics.params.push(syn::parse_quote! { RA });
26 let field_ty_generic = generics
27 .params
28 .first()
29 .and_then(|param| match param {
30 GenericParam::Type(type_param) => Some(&type_param.ident),
31 _ => None,
32 })
33 .unwrap_or_else(|| {
34 new_generics.params.push(syn::parse_quote! { F });
35 &default_ty_generic
36 });
37
38 match &ast.data {
39 Data::Struct(inner) => {
40 let inner_ty = match &inner.fields {
42 Fields::Unnamed(fields) => {
43 if fields.unnamed.len() != 1 {
44 panic!("Only one unnamed field is supported");
45 }
46 fields.unnamed.first().unwrap().ty.clone()
47 }
48 _ => panic!("Only unnamed fields are supported"),
49 };
50 let where_clause = new_generics.make_where_clause();
53 where_clause.predicates.push(
54 syn::parse_quote! { #inner_ty: ::openvm_circuit::arch::PreflightExecutor<#field_ty_generic, RA> },
55 );
56 let (impl_generics, _, where_clause) = new_generics.split_for_impl();
57 quote! {
58 impl #impl_generics ::openvm_circuit::arch::PreflightExecutor<#field_ty_generic, RA> for #name #ty_generics #where_clause {
59 fn execute(
60 &self,
61 state: ::openvm_circuit::arch::VmStateMut<#field_ty_generic, ::openvm_circuit::system::memory::online::TracingMemory, RA>,
62 instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<#field_ty_generic>,
63 ) -> Result<(), ::openvm_circuit::arch::ExecutionError> {
64 self.0.execute(state, instruction)
65 }
66
67 fn get_opcode_name(&self, opcode: usize) -> String {
68 self.0.get_opcode_name(opcode)
69 }
70 }
71 }
72 .into()
73 }
74 Data::Enum(e) => {
75 let variants = e
76 .variants
77 .iter()
78 .map(|variant| {
79 let variant_name = &variant.ident;
80
81 let mut fields = variant.fields.iter();
82 let field = fields.next().unwrap();
83 assert!(fields.next().is_none(), "Only one field is supported");
84 (variant_name, field)
85 })
86 .collect::<Vec<_>>();
87 let (execute_arms, get_opcode_name_arms, where_predicates): (Vec<_>, Vec<_>, Vec<_>) =
90 multiunzip(variants.iter().map(|(variant_name, field)| {
91 let field_ty = &field.ty;
92 let execute_arm = quote! {
93 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::PreflightExecutor<#field_ty_generic, RA>>::execute(x, state, instruction)
94 };
95 let get_opcode_name_arm = quote! {
96 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::PreflightExecutor<#field_ty_generic, RA>>::get_opcode_name(x, opcode)
97 };
98 let where_predicate = syn::parse_quote! {
99 #field_ty: ::openvm_circuit::arch::PreflightExecutor<#field_ty_generic, RA>
100 };
101 (execute_arm, get_opcode_name_arm, where_predicate)
102 }));
103 let where_clause = new_generics.make_where_clause();
104 for predicate in where_predicates {
105 where_clause.predicates.push(predicate);
106 }
107 let (impl_generics, _, where_clause) = new_generics.split_for_impl();
109 quote! {
110 impl #impl_generics ::openvm_circuit::arch::PreflightExecutor<#field_ty_generic, RA> for #name #ty_generics #where_clause {
111 fn execute(
112 &self,
113 state: ::openvm_circuit::arch::VmStateMut<#field_ty_generic, ::openvm_circuit::system::memory::online::TracingMemory, RA>,
114 instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<#field_ty_generic>,
115 ) -> Result<(), ::openvm_circuit::arch::ExecutionError> {
116 match self {
117 #(#execute_arms,)*
118 }
119 }
120
121 fn get_opcode_name(&self, opcode: usize) -> String {
122 match self {
123 #(#get_opcode_name_arms,)*
124 }
125 }
126 }
127 }
128 .into()
129 }
130 Data::Union(_) => unimplemented!("Unions are not supported"),
131 }
132}
133
134#[proc_macro_derive(Executor)]
135pub fn executor_derive(input: TokenStream) -> TokenStream {
136 let ast: syn::DeriveInput = syn::parse(input).unwrap();
137
138 let name = &ast.ident;
139 let generics = &ast.generics;
140 let (impl_generics, ty_generics, _) = generics.split_for_impl();
141
142 match &ast.data {
143 Data::Struct(inner) => {
144 let inner_ty = match &inner.fields {
146 Fields::Unnamed(fields) => {
147 if fields.unnamed.len() != 1 {
148 panic!("Only one unnamed field is supported");
149 }
150 fields.unnamed.first().unwrap().ty.clone()
151 }
152 _ => panic!("Only unnamed fields are supported"),
153 };
154 let mut new_generics = generics.clone();
157 let where_clause = new_generics.make_where_clause();
158 where_clause
159 .predicates
160 .push(syn::parse_quote! { #inner_ty: ::openvm_circuit::arch::Executor<F> });
161
162 #[cfg(feature = "tco")]
165 let handler = quote! {
166 fn handler<Ctx>(
167 &self,
168 pc: u32,
169 inst: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
170 data: &mut [u8],
171 ) -> Result<::openvm_circuit::arch::Handler<F, Ctx>, ::openvm_circuit::arch::StaticProgramError>
172 where
173 Ctx: ::openvm_circuit::arch::execution_mode::ExecutionCtxTrait, {
174 self.0.handler(pc, inst, data)
175 }
176 };
177 #[cfg(not(feature = "tco"))]
178 let handler = quote! {};
179
180 quote! {
181 impl #impl_generics ::openvm_circuit::arch::Executor<F> for #name #ty_generics #where_clause {
182 #[inline(always)]
183 fn pre_compute_size(&self) -> usize {
184 self.0.pre_compute_size()
185 }
186 #[inline(always)]
187 fn pre_compute<Ctx>(
188 &self,
189 pc: u32,
190 inst: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
191 data: &mut [u8],
192 ) -> Result<::openvm_circuit::arch::ExecuteFunc<F, Ctx>, ::openvm_circuit::arch::StaticProgramError>
193 where
194 Ctx: ::openvm_circuit::arch::execution_mode::ExecutionCtxTrait, {
195 self.0.pre_compute(pc, inst, data)
196 }
197
198 #handler
199 }
200 }
201 .into()
202 }
203 Data::Enum(e) => {
204 let variants = e
205 .variants
206 .iter()
207 .map(|variant| {
208 let variant_name = &variant.ident;
209
210 let mut fields = variant.fields.iter();
211 let field = fields.next().unwrap();
212 assert!(fields.next().is_none(), "Only one field is supported");
213 (variant_name, field)
214 })
215 .collect::<Vec<_>>();
216 let default_ty_generic = Ident::new("F", proc_macro2::Span::call_site());
217 let mut new_generics = generics.clone();
218 let first_ty_generic = ast
219 .generics
220 .params
221 .first()
222 .and_then(|param| match param {
223 GenericParam::Type(type_param) => Some(&type_param.ident),
224 _ => None,
225 })
226 .unwrap_or_else(|| {
227 new_generics.params.push(syn::parse_quote! { F });
228 &default_ty_generic
229 });
230 let (pre_compute_size_arms, pre_compute_arms, _handler_arms, where_predicates): (Vec<_>, Vec<_>, Vec<_>, Vec<_>) = multiunzip(variants.iter().map(|(variant_name, field)| {
233 let field_ty = &field.ty;
234 let pre_compute_size_arm = quote! {
235 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::Executor<#first_ty_generic>>::pre_compute_size(x)
236 };
237 let pre_compute_arm = quote! {
238 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::Executor<#first_ty_generic>>::pre_compute(x, pc, instruction, data)
239 };
240 let handler_arm = quote! {
241 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::Executor<#first_ty_generic>>::handler(x, pc, instruction, data)
242 };
243 let where_predicate = syn::parse_quote! {
244 #field_ty: ::openvm_circuit::arch::Executor<#first_ty_generic>
245 };
246 (pre_compute_size_arm, pre_compute_arm, handler_arm, where_predicate)
247 }));
248 let where_clause = new_generics.make_where_clause();
249 for predicate in where_predicates {
250 where_clause.predicates.push(predicate);
251 }
252 #[cfg(feature = "tco")]
255 let handler = quote! {
256 fn handler<Ctx>(
257 &self,
258 pc: u32,
259 instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
260 data: &mut [u8],
261 ) -> Result<::openvm_circuit::arch::Handler<F, Ctx>, ::openvm_circuit::arch::StaticProgramError>
262 where
263 Ctx: ::openvm_circuit::arch::execution_mode::ExecutionCtxTrait, {
264 match self {
265 #(#_handler_arms,)*
266 }
267 }
268 };
269 #[cfg(not(feature = "tco"))]
270 let handler = quote! {};
271
272 let (impl_generics, _, where_clause) = new_generics.split_for_impl();
274
275 quote! {
276 impl #impl_generics ::openvm_circuit::arch::Executor<#first_ty_generic> for #name #ty_generics #where_clause {
277 #[inline(always)]
278 fn pre_compute_size(&self) -> usize {
279 match self {
280 #(#pre_compute_size_arms,)*
281 }
282 }
283
284 #[inline(always)]
285 fn pre_compute<Ctx>(
286 &self,
287 pc: u32,
288 instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
289 data: &mut [u8],
290 ) -> Result<::openvm_circuit::arch::ExecuteFunc<F, Ctx>, ::openvm_circuit::arch::StaticProgramError>
291 where
292 Ctx: ::openvm_circuit::arch::execution_mode::ExecutionCtxTrait, {
293 match self {
294 #(#pre_compute_arms,)*
295 }
296 }
297
298 #handler
299 }
300 }
301 .into()
302 }
303 Data::Union(_) => unimplemented!("Unions are not supported"),
304 }
305}
306
307#[proc_macro_derive(MeteredExecutor)]
308pub fn metered_executor_derive(input: TokenStream) -> TokenStream {
309 let ast: syn::DeriveInput = syn::parse(input).unwrap();
310
311 let name = &ast.ident;
312 let generics = &ast.generics;
313 let (impl_generics, ty_generics, _) = generics.split_for_impl();
314
315 match &ast.data {
316 Data::Struct(inner) => {
317 let inner_ty = match &inner.fields {
319 Fields::Unnamed(fields) => {
320 if fields.unnamed.len() != 1 {
321 panic!("Only one unnamed field is supported");
322 }
323 fields.unnamed.first().unwrap().ty.clone()
324 }
325 _ => panic!("Only unnamed fields are supported"),
326 };
327 let mut new_generics = generics.clone();
330 let where_clause = new_generics.make_where_clause();
331 where_clause
332 .predicates
333 .push(syn::parse_quote! { #inner_ty: ::openvm_circuit::arch::MeteredExecutor<F> });
334
335 #[cfg(feature = "tco")]
338 let metered_handler = quote! {
339 fn metered_handler<Ctx>(
340 &self,
341 chip_idx: usize,
342 pc: u32,
343 inst: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
344 data: &mut [u8],
345 ) -> Result<::openvm_circuit::arch::Handler<F, Ctx>, ::openvm_circuit::arch::StaticProgramError>
346 where
347 Ctx: ::openvm_circuit::arch::execution_mode::MeteredExecutionCtxTrait, {
348 self.0.metered_handler(chip_idx, pc, inst, data)
349 }
350 };
351 #[cfg(not(feature = "tco"))]
352 let metered_handler = quote! {};
353
354 quote! {
355 impl #impl_generics ::openvm_circuit::arch::MeteredExecutor<F> for #name #ty_generics #where_clause {
356 #[inline(always)]
357 fn metered_pre_compute_size(&self) -> usize {
358 self.0.metered_pre_compute_size()
359 }
360 #[inline(always)]
361 fn metered_pre_compute<Ctx>(
362 &self,
363 chip_idx: usize,
364 pc: u32,
365 inst: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
366 data: &mut [u8],
367 ) -> Result<::openvm_circuit::arch::ExecuteFunc<F, Ctx>, ::openvm_circuit::arch::StaticProgramError>
368 where
369 Ctx: ::openvm_circuit::arch::execution_mode::MeteredExecutionCtxTrait, {
370 self.0.metered_pre_compute(chip_idx, pc, inst, data)
371 }
372 #metered_handler
373 }
374 }
375 .into()
376 }
377 Data::Enum(e) => {
378 let variants = e
379 .variants
380 .iter()
381 .map(|variant| {
382 let variant_name = &variant.ident;
383
384 let mut fields = variant.fields.iter();
385 let field = fields.next().unwrap();
386 assert!(fields.next().is_none(), "Only one field is supported");
387 (variant_name, field)
388 })
389 .collect::<Vec<_>>();
390 let default_ty_generic = Ident::new("F", proc_macro2::Span::call_site());
391 let mut new_generics = generics.clone();
392 let first_ty_generic = ast
393 .generics
394 .params
395 .first()
396 .and_then(|param| match param {
397 GenericParam::Type(type_param) => Some(&type_param.ident),
398 _ => None,
399 })
400 .unwrap_or_else(|| {
401 new_generics.params.push(syn::parse_quote! { F });
402 &default_ty_generic
403 });
404 let (pre_compute_size_arms, metered_pre_compute_arms, _metered_handler_arms, where_predicates): (Vec<_>, Vec<_>, Vec<_>, Vec<_>) = multiunzip(variants.iter().map(|(variant_name, field)| {
407 let field_ty = &field.ty;
408 let pre_compute_size_arm = quote! {
409 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::MeteredExecutor<#first_ty_generic>>::metered_pre_compute_size(x)
410 };
411 let metered_pre_compute_arm = quote! {
412 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::MeteredExecutor<#first_ty_generic>>::metered_pre_compute(x, chip_idx, pc, instruction, data)
413 };
414 let metered_handler_arm = quote! {
415 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::MeteredExecutor<#first_ty_generic>>::metered_handler(x, chip_idx, pc, instruction, data)
416 };
417 let where_predicate = syn::parse_quote! {
418 #field_ty: ::openvm_circuit::arch::MeteredExecutor<#first_ty_generic>
419 };
420 (pre_compute_size_arm, metered_pre_compute_arm, metered_handler_arm, where_predicate)
421 }));
422 let where_clause = new_generics.make_where_clause();
423 for predicate in where_predicates {
424 where_clause.predicates.push(predicate);
425 }
426 let (impl_generics, _, where_clause) = new_generics.split_for_impl();
428
429 #[cfg(feature = "tco")]
432 let metered_handler = quote! {
433 fn metered_handler<Ctx>(
434 &self,
435 chip_idx: usize,
436 pc: u32,
437 instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
438 data: &mut [u8],
439 ) -> Result<::openvm_circuit::arch::Handler<F, Ctx>, ::openvm_circuit::arch::StaticProgramError>
440 where
441 Ctx: ::openvm_circuit::arch::execution_mode::MeteredExecutionCtxTrait,
442 {
443 match self {
444 #(#_metered_handler_arms,)*
445 }
446 }
447 };
448 #[cfg(not(feature = "tco"))]
449 let metered_handler = quote! {};
450
451 quote! {
452 impl #impl_generics ::openvm_circuit::arch::MeteredExecutor<#first_ty_generic> for #name #ty_generics #where_clause {
453 #[inline(always)]
454 fn metered_pre_compute_size(&self) -> usize {
455 match self {
456 #(#pre_compute_size_arms,)*
457 }
458 }
459
460 #[inline(always)]
461 fn metered_pre_compute<Ctx>(
462 &self,
463 chip_idx: usize,
464 pc: u32,
465 instruction: &::openvm_circuit::arch::instructions::instruction::Instruction<F>,
466 data: &mut [u8],
467 ) -> Result<::openvm_circuit::arch::ExecuteFunc<F, Ctx>, ::openvm_circuit::arch::StaticProgramError>
468 where
469 Ctx: ::openvm_circuit::arch::execution_mode::MeteredExecutionCtxTrait, {
470 match self {
471 #(#metered_pre_compute_arms,)*
472 }
473 }
474
475 #metered_handler
476 }
477 }
478 .into()
479 }
480 Data::Union(_) => unimplemented!("Unions are not supported"),
481 }
482}
483
484#[proc_macro_derive(AnyEnum, attributes(any_enum))]
490pub fn any_enum_derive(input: TokenStream) -> TokenStream {
491 let ast: syn::DeriveInput = syn::parse(input).unwrap();
492
493 let name = &ast.ident;
494 let generics = &ast.generics;
495 let (impl_generics, ty_generics, _) = generics.split_for_impl();
496
497 match &ast.data {
498 Data::Enum(e) => {
499 let variants = e
500 .variants
501 .iter()
502 .map(|variant| {
503 let variant_name = &variant.ident;
504
505 let is_enum = variant
507 .attrs
508 .iter()
509 .any(|attr| attr.path().is_ident("any_enum"));
510 let mut fields = variant.fields.iter();
511 let field = fields.next().unwrap();
512 assert!(fields.next().is_none(), "Only one field is supported");
513 (variant_name, field, is_enum)
514 })
515 .collect::<Vec<_>>();
516 let (arms, arms_mut): (Vec<_>, Vec<_>) =
517 variants.iter().map(|(variant_name, field, is_enum)| {
518 let field_ty = &field.ty;
519
520 if *is_enum {
521 (quote! {
523 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::AnyEnum>::as_any_kind(x)
524 },
525 quote! {
526 #name::#variant_name(x) => <#field_ty as ::openvm_circuit::arch::AnyEnum>::as_any_kind_mut(x)
527 })
528 } else {
529 (quote! {
530 #name::#variant_name(x) => x
531 },
532 quote! {
533 #name::#variant_name(x) => x
534 })
535 }
536 }).unzip();
537 quote! {
538 impl #impl_generics ::openvm_circuit::arch::AnyEnum for #name #ty_generics {
539 fn as_any_kind(&self) -> &dyn std::any::Any {
540 match self {
541 #(#arms,)*
542 }
543 }
544
545 fn as_any_kind_mut(&mut self) -> &mut dyn std::any::Any {
546 match self {
547 #(#arms_mut,)*
548 }
549 }
550 }
551 }
552 .into()
553 }
554 _ => syn::Error::new(name.span(), "Only enums are supported")
555 .to_compile_error()
556 .into(),
557 }
558}
559
560#[proc_macro_derive(VmConfig, attributes(config, extension))]
561pub fn vm_generic_config_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
562 let ast = syn::parse_macro_input!(input as syn::DeriveInput);
563 let name = &ast.ident;
564
565 match &ast.data {
566 syn::Data::Struct(inner) => match generate_config_traits_impl(name, inner) {
567 Ok(tokens) => tokens,
568 Err(err) => err.to_compile_error().into(),
569 },
570 _ => syn::Error::new(name.span(), "Only structs are supported")
571 .to_compile_error()
572 .into(),
573 }
574}
575
576fn generate_config_traits_impl(name: &Ident, inner: &DataStruct) -> syn::Result<TokenStream> {
577 let gen_name_with_uppercase_idents = |ident: &Ident| {
578 let mut name = ident.to_string().chars().collect::<Vec<_>>();
579 assert!(name[0].is_lowercase(), "Field name must not be capitalized");
580 let res_lower = Ident::new(&name.iter().collect::<String>(), Span::call_site().into());
581 name[0] = name[0].to_ascii_uppercase();
582 let res_upper = Ident::new(&name.iter().collect::<String>(), Span::call_site().into());
583 (res_lower, res_upper)
584 };
585
586 let fields = match &inner.fields {
587 Fields::Named(named) => named.named.iter().collect(),
588 Fields::Unnamed(_) => {
589 return Err(syn::Error::new(
590 name.span(),
591 "Only named fields are supported",
592 ))
593 }
594 Fields::Unit => vec![],
595 };
596
597 let source_field = fields
598 .iter()
599 .filter(|f| f.attrs.iter().any(|attr| attr.path().is_ident("config")))
600 .exactly_one()
601 .map_err(|_| {
602 syn::Error::new(
603 name.span(),
604 "Exactly one field must have the #[config] attribute",
605 )
606 })?;
607 let (source_name, source_name_upper) =
608 gen_name_with_uppercase_idents(source_field.ident.as_ref().unwrap());
609
610 let extensions = fields
611 .iter()
612 .filter(|f| f.attrs.iter().any(|attr| attr.path().is_ident("extension")))
613 .cloned()
614 .collect::<Vec<_>>();
615
616 let mut executor_enum_fields = Vec::new();
617 let mut create_executors = Vec::new();
618 let mut create_airs = Vec::new();
619 let mut execution_where_predicates: Vec<syn::WherePredicate> = Vec::new();
620 let mut circuit_where_predicates: Vec<syn::WherePredicate> = Vec::new();
621
622 let source_field_ty = source_field.ty.clone();
623
624 for e in extensions.iter() {
625 let (ext_field_name, ext_name_upper) =
626 gen_name_with_uppercase_idents(e.ident.as_ref().expect("field must be named"));
627 let executor_type = parse_executor_type(e, false)?;
628 executor_enum_fields.push(quote! {
629 #[any_enum]
630 #ext_name_upper(#executor_type),
631 });
632 create_executors.push(quote! {
633 let inventory: ::openvm_circuit::arch::ExecutorInventory<Self::Executor> = inventory.extend::<F, _, _>(&self.#ext_field_name)?;
634 });
635 let extension_ty = e.ty.clone();
636 execution_where_predicates.push(parse_quote! {
637 #extension_ty: ::openvm_circuit::arch::VmExecutionExtension<F, Executor = #executor_type>
638 });
639 create_airs.push(quote! {
640 inventory.start_new_extension();
641 ::openvm_circuit::arch::VmCircuitExtension::extend_circuit(&self.#ext_field_name, &mut inventory)?;
642 });
643 circuit_where_predicates.push(parse_quote! {
644 #extension_ty: ::openvm_circuit::arch::VmCircuitExtension<SC>
645 });
646 }
647
648 let source_executor_type = parse_executor_type(source_field, true)?;
650 execution_where_predicates.push(parse_quote! {
651 #source_field_ty: ::openvm_circuit::arch::VmExecutionConfig<F, Executor = #source_executor_type>
652 });
653 circuit_where_predicates.push(parse_quote! {
654 #source_field_ty: ::openvm_circuit::arch::VmCircuitConfig<SC>
655 });
656 let execution_where_clause = quote! { where #(#execution_where_predicates),* };
657 let circuit_where_clause = quote! { where #(#circuit_where_predicates),* };
658
659 let executor_type = Ident::new(&format!("{}Executor", name), name.span());
660
661 let token_stream = TokenStream::from(quote! {
662 #[derive(
663 Clone,
664 ::derive_more::derive::From,
665 ::openvm_circuit::derive::AnyEnum,
666 ::openvm_circuit::derive::Executor,
667 ::openvm_circuit::derive::MeteredExecutor,
668 ::openvm_circuit::derive::PreflightExecutor,
669 )]
670 pub enum #executor_type<F: openvm_stark_backend::p3_field::Field> {
671 #[any_enum]
672 #source_name_upper(#source_executor_type),
673 #(#executor_enum_fields)*
674 }
675
676 impl<F: openvm_stark_backend::p3_field::Field> ::openvm_circuit::arch::VmExecutionConfig<F> for #name #execution_where_clause {
677 type Executor = #executor_type<F>;
678
679 fn create_executors(
680 &self,
681 ) -> Result<::openvm_circuit::arch::ExecutorInventory<Self::Executor>, ::openvm_circuit::arch::ExecutorInventoryError> {
682 let inventory = self.#source_name.create_executors()?.transmute::<Self::Executor>();
683 #(#create_executors)*
684 Ok(inventory)
685 }
686 }
687
688 impl<SC: openvm_stark_backend::config::StarkGenericConfig> ::openvm_circuit::arch::VmCircuitConfig<SC> for #name #circuit_where_clause {
689 fn create_airs(
690 &self,
691 ) -> Result<::openvm_circuit::arch::AirInventory<SC>, ::openvm_circuit::arch::AirInventoryError> {
692 let mut inventory = self.#source_name.create_airs()?;
693 #(#create_airs)*
694 Ok(inventory)
695 }
696 }
697
698 impl AsRef<SystemConfig> for #name {
699 fn as_ref(&self) -> &SystemConfig {
700 self.#source_name.as_ref()
701 }
702 }
703
704 impl AsMut<SystemConfig> for #name {
705 fn as_mut(&mut self) -> &mut SystemConfig {
706 self.#source_name.as_mut()
707 }
708 }
709 });
710 Ok(token_stream)
711}
712
713fn parse_executor_type(
717 f: &Field,
718 default_needs_generics: bool,
719) -> syn::Result<proc_macro2::TokenStream> {
720 let mut executor_type = None;
723 let executor_name = syn::parse_str::<Ident>(&format!("{}Executor", f.ty.to_token_stream()));
725
726 if let Some(attr) = f
727 .attrs
728 .iter()
729 .find(|attr| attr.path().is_ident("extension") || attr.path().is_ident("config"))
730 {
731 match attr.meta {
732 Meta::Path(_) => {}
733 Meta::NameValue(_) => {
734 return Err(syn::Error::new(
735 f.ty.span(),
736 "Only `#[config]`, `#[extension]`, `#[config(...)]` or `#[extension(...)]` formats are supported",
737 ))
738 }
739 _ => {
740 let nested = attr
741 .parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
742 for meta in nested {
743 match meta {
744 Meta::NameValue(nv) => {
745 if nv.path.is_ident("executor") {
746 executor_type = match nv.value {
747 syn::Expr::Lit(syn::ExprLit {
748 lit: syn::Lit::Str(lit_str), ..
749 }) => {
750 let executor_type: syn::Type = syn::parse_str(&lit_str.value())?;
751 Some(quote! { #executor_type })
752 },
753 syn::Expr::Path(path) => {
754 Some(path.to_token_stream())
756 },
757 _ => {
758 return Err(syn::Error::new(
759 nv.value.span(),
760 "executor value must be a string literal or identifier"
761 ));
762 }
763 };
764 } else if nv.path.is_ident("generics") {
765 let value_str = nv.value.to_token_stream().to_string();
767 let needs_generics = match value_str.as_str() {
768 "true" => true,
769 "false" => false,
770 _ => return Err(syn::Error::new(
771 nv.value.span(),
772 "generics attribute must be either true or false"
773 ))
774 };
775 let executor_name = executor_name.clone()?;
776 executor_type = Some(if needs_generics {
777 quote! { #executor_name<F> }
778 } else {
779 quote! { #executor_name }
780 });
781 } else {
782 return Err(syn::Error::new(nv.span(), "only executor and generics keys are supported"));
783 }
784 }
785 _ => {
786 return Err(syn::Error::new(meta.span(), "only name = value format is supported"));
787 }
788 }
789 }
790 }
791 }
792 }
793 if let Some(executor_type) = executor_type {
794 Ok(executor_type)
795 } else {
796 let executor_name = executor_name?;
797 Ok(if default_needs_generics {
798 quote! { #executor_name<F> }
799 } else {
800 quote! { #executor_name }
801 })
802 }
803}
804
805#[proc_macro_attribute]
835pub fn create_tco_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
836 #[cfg(feature = "tco")]
837 {
838 tco::tco_impl(item)
839 }
840 #[cfg(not(feature = "tco"))]
841 {
842 item
843 }
844}