Skip to content

Commit

Permalink
Move to proc_macro instead of macro_rules
Browse files Browse the repository at this point in the history
Signed-off-by: Dimitris Zervas <[email protected]>
  • Loading branch information
dzervas committed May 28, 2024
1 parent e0c1fec commit a75667a
Show file tree
Hide file tree
Showing 8 changed files with 458 additions and 380 deletions.
487 changes: 254 additions & 233 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["packages/cadmium"]
members = [ "packages/cadmium", "packages/cadmium-macros"]
resolver = "2"

[patch.crates-io]
Expand Down
13 changes: 13 additions & 0 deletions packages/cadmium-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "cadmium-macros"
version = "0.1.0"
edition = "2021"

[dependencies]
syn = { version = "1.0", features = ["parsing", "derive"] }
quote = "1.0"
proc-macro2 = "1.0"
convert_case = "0.6.0"

[lib]
proc-macro = true
143 changes: 143 additions & 0 deletions packages/cadmium-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use convert_case::{Case, Casing};
use proc_macro::TokenStream;
use quote::quote;
use syn::punctuated::Punctuated;
use syn::{parse_macro_input, DeriveInput, Ident, MetaNameValue, Token};
use syn::spanned::Spanned;

#[proc_macro_derive(StepDataActions, attributes(step_data))]
pub fn derive_step_data(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);

let name = &input.ident;
let data = match input.data {
syn::Data::Enum(data) => data,
_ => panic!("StepData can only be derived for enums"),
};

let variants = data.variants.iter().map(|variant| {
let variant_name = &variant.ident;

let mut skip_workbench = false;
let mut workbench_field = None;
let mut parent_type = None;

for attr in &variant.attrs {
if !attr.path.is_ident("step_data") {
continue;
}

let name_values: Punctuated<MetaNameValue, Token![,]> = attr.parse_args_with(Punctuated::parse_terminated).unwrap(); // handle error instead of unwrap
for nv in name_values {
let ident = nv.path.get_ident().unwrap();

match ident.to_string().as_str() {
"skip_workbench" => {
skip_workbench = true;
},
"workbench_field" => {
if let syn::Lit::Str(value) = nv.lit {
workbench_field = Some(value.value());
} else {
panic!("workbench_field must be a string literal");
}
},
"type" => {
if let syn::Lit::Str(value) = nv.lit {
parent_type = Some(value.value());
} else {
panic!("type must be a string literal");
}
},
&_ => {}
}
}
}

// Process not skipped workbench
let mut wb_var = quote! {};
let mut wb_id_def = quote! {};
let mut wb_id_arg = quote! {};
if !skip_workbench {
wb_var = quote! {
let wb_ = self.native.workbenches
.get_mut(workbench_id as usize)
.ok_or(anyhow::anyhow!("Could not find workbench"))?;
};
wb_id_def = quote! { workbench_id: crate::IDType, };
wb_id_arg = quote! { workbench_id, };
}

// Process type and workbench_field
let mut field_var = quote! {};
let mut field_id_def = quote! {};
let mut field_id_arg = quote! {};
let id_arg_name = if let Some(f) = parent_type.clone() {
Ident::new(format!("{}_id", f.to_string().to_case(Case::Snake)).as_str(), f.span())
} else {
Ident::new("id", variant_name.span())
};
if let Some(field_ident) = workbench_field.clone() {
let field_name = Ident::new(field_ident.as_str(), field_ident.span());
field_var = quote! {
let parent_ref_ = wb_.#field_name
.get(& #id_arg_name)
.ok_or(anyhow::anyhow!("Could not find parent"))?;
let parent_ = parent_ref_.borrow_mut();
};
field_id_def = quote! { #id_arg_name: crate::IDType, };
field_id_arg = quote! { #id_arg_name, };
} else if !skip_workbench {
field_var = quote! { let parent_ = wb_; };
} else {
field_var = quote! { let parent_ = self; };
}

// Function declaration
let add_func_name = Ident::new(format!("add_{}", variant_name.to_string().to_case(Case::Snake)).as_str(), variant_name.span());
let function_defs = variant.fields.iter().map(|field| {
let field_name = &field.ident;
let field_type = &field.ty;

quote! { #field_name: #field_type }
}).into_iter();
let function_args = variant.fields.iter().map(|field| {
let field_name = &field.ident;

quote! { #field_name }
}).into_iter();
let function_args2 = function_args.clone();

quote! {
pub fn #add_func_name(&mut self, #wb_id_def #field_id_def name: String, #( #function_defs ),*) -> Result<crate::IDType, anyhow::Error> {
#wb_var
#field_var
let result_id_ = parent_.#add_func_name(#( #function_args ),*)?;

let step_ = Step {
name,
operation: StepOperation::Add,
unique_id: format!(concat!("Add:", stringify!(#name), "-{}"), result_id_),
suppressed: false,
data: #name::#variant_name {
// #wb_id_arg
// #field_id_arg
#( #function_args2 ),*
},
};

wb_.history.push(step_);

Ok(result_id_)
}
}
});

let expanded = quote! {
impl crate::Project {
#( #variants )*
}
};

TokenStream::from(expanded)
}
1 change: 1 addition & 0 deletions packages/cadmium/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ strum = { version = "0.26.2", features = ["derive"] }
# isotope = { git = "https://github.com/CADmium-Co/ISOtope.git", version = "*", features = ["tsify"] }
isotope = { path = "../../../isotope", version = "*", features = ["tsify"]}
paste = "1.0.15"
cadmium-macros = { path = "../cadmium-macros", version = "*" }

[lib]
crate-type = ["cdylib", "rlib"]
8 changes: 4 additions & 4 deletions packages/cadmium/src/isketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl ISketch {
}

impl ISketch {
pub(super) fn add_point(&mut self, point: Point2) -> Result<IDType, anyhow::Error> {
pub(super) fn add_sketch_point(&mut self, point: Point2) -> Result<IDType, anyhow::Error> {
let iso_point = PrimitiveCell::Point2(Rc::new(RefCell::new(point.into())));

let mut sketch = self.sketch.borrow_mut();
Expand All @@ -103,7 +103,7 @@ impl ISketch {
Ok(point_id)
}

pub(super) fn add_arc(&mut self, center: IDType, radius: f64, clockwise: bool, start_angle: f64, end_angle: f64) -> Result<IDType, anyhow::Error> {
pub(super) fn add_sketch_arc(&mut self, center: IDType, radius: f64, clockwise: bool, start_angle: f64, end_angle: f64) -> Result<IDType, anyhow::Error> {
let mut sketch = self.sketch.borrow_mut();

let center_point = if let PrimitiveCell::Point2(point) = sketch.get_primitive_by_id(center).unwrap() {
Expand All @@ -118,7 +118,7 @@ impl ISketch {
Ok(point_id)
}

pub(super) fn add_circle(&mut self, center: IDType, radius: f64) -> Result<IDType, anyhow::Error> {
pub(super) fn add_sketch_circle(&mut self, center: IDType, radius: f64) -> Result<IDType, anyhow::Error> {
let mut sketch = self.sketch.borrow_mut();

let center_point = if let PrimitiveCell::Point2(point) = sketch.get_primitive_by_id(center).unwrap() {
Expand All @@ -133,7 +133,7 @@ impl ISketch {
Ok(point_id)
}

pub(super) fn add_line(&mut self, start: IDType, end: IDType) -> Result<IDType, anyhow::Error> {
pub(super) fn add_sketch_line(&mut self, start: IDType, end: IDType) -> Result<IDType, anyhow::Error> {
let mut sketch = self.sketch.borrow_mut();

let start_point = if let PrimitiveCell::Point2(point) = sketch.get_primitive_by_id(start).unwrap() {
Expand Down
Loading

0 comments on commit a75667a

Please sign in to comment.