From 4d6a6cb478e3ccc2d42dc8e6681d393398b897c5 Mon Sep 17 00:00:00 2001 From: gabsi26 Date: Wed, 1 Jun 2022 17:42:18 +0200 Subject: [PATCH 1/2] Improve `model` macro If an argument has no annotations it now does not require an attribute Signed-off-by: gabsi26 --- crates/fj-proc/src/attributed_arguments.rs | 50 +++++++++++++--------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/crates/fj-proc/src/attributed_arguments.rs b/crates/fj-proc/src/attributed_arguments.rs index f277dc6d73..b331a5520f 100644 --- a/crates/fj-proc/src/attributed_arguments.rs +++ b/crates/fj-proc/src/attributed_arguments.rs @@ -18,37 +18,44 @@ pub fn attributed_arguments(_: TokenStream, input: TokenStream) -> TokenStream { for arg in args { let ident = arg.ident; let ty = arg.ty; - - if let Some(default) = arg.attr.get_default() { - let def = default.val; - parameter_extraction.push(quote! { - let #ident: #ty = args.get(stringify!(#ident)) - .map(|arg| arg.parse().unwrap()) - .unwrap_or(#def); - }); - } else { - parameter_extraction.push(quote! { + if let Some(attr) = arg.attr { + if let Some(default) = attr.get_default() { + let def = default.val; + parameter_extraction.push(quote! { + let #ident: #ty = args.get(stringify!(#ident)) + .map(|arg| arg.parse().unwrap()) + .unwrap_or(#def); + }); + } else { + parameter_extraction.push(quote! { let #ident: #ty = args.get(stringify!(#ident)) .map(|arg| arg.parse().unwrap()) .expect(format!("A value for `{}` has to be provided since no default is specified",stringify!(#ident)).as_str()); }); - } + } - if let Some(minimum) = arg.attr.get_minimum() { - let min = minimum.val; - min_checks.push(quote! { + if let Some(minimum) = attr.get_minimum() { + let min = minimum.val; + min_checks.push(quote! { if #ident < #min { panic!("Value of `{}` must not be smaller than: {}",stringify!(#ident), #min); } }); - } - if let Some(maximum) = arg.attr.get_maximum() { - let max = maximum.val; - max_checks.push(quote! { + } + if let Some(maximum) = attr.get_maximum() { + let max = maximum.val; + max_checks.push(quote! { if #ident > #max { panic!("Value of `{}` must not be larger than: {}", stringify!(#ident), #max); } }) + } + } else { + parameter_extraction.push(quote! { + let #ident: #ty = args.get(stringify!(#ident)) + .map(|arg| arg.parse().unwrap()) + .expect(format!("A value for `{}` has to be provided since no default is specified",stringify!(#ident)).as_str()); + }); } } let block = item.block; @@ -82,14 +89,17 @@ pub fn attributed_arguments(_: TokenStream, input: TokenStream) -> TokenStream { /// ` attr ident` #[derive(Debug, Clone)] struct Argument { - pub attr: HelperAttribute, + pub attr: Option, pub ident: proc_macro2::Ident, pub ty: proc_macro2::Ident, } impl Parse for Argument { fn parse(input: syn::parse::ParseStream) -> syn::Result { - let attr: HelperAttribute = input.parse()?; + let mut attr = None; + if input.peek(syn::token::Pound) { + attr = Some(input.parse()?); + } let ident: proc_macro2::Ident = input.parse()?; let _: syn::token::Colon = input.parse()?; From 1ffc0866a1192d1ce1ca84bd9afe334282ef4440 Mon Sep 17 00:00:00 2001 From: gabsi26 Date: Wed, 1 Jun 2022 18:31:15 +0200 Subject: [PATCH 2/2] Use `model` proc-macro in all example models Signed-off-by: gabsi26 --- models/cuboid/src/lib.rs | 24 ++++++------------------ models/spacer/src/lib.rs | 24 ++++++------------------ models/test/src/lib.rs | 4 ++-- 3 files changed, 14 insertions(+), 38 deletions(-) diff --git a/models/cuboid/src/lib.rs b/models/cuboid/src/lib.rs index fa1459ab0c..59a09995fe 100644 --- a/models/cuboid/src/lib.rs +++ b/models/cuboid/src/lib.rs @@ -1,23 +1,11 @@ use std::collections::HashMap; -#[no_mangle] -pub extern "C" fn model(args: &HashMap) -> fj::Shape { - let x: f64 = args - .get("x") - .unwrap_or(&"3.0".to_owned()) - .parse() - .expect("Could not parse parameter `x`"); - let y: f64 = args - .get("y") - .unwrap_or(&"2.0".to_owned()) - .parse() - .expect("Could not parse parameter `y`"); - let z: f64 = args - .get("z") - .unwrap_or(&"1.0".to_owned()) - .parse() - .expect("Could not parse parameter `z`"); - +#[fj::model] +pub fn model( + #[value(default = 3.0)] x: f64, + #[value(default = 2.0)] y: f64, + #[value(default = 1.0)] z: f64, +) -> fj::Shape { #[rustfmt::skip] let rectangle = fj::Sketch::from_points(vec![ [-x / 2., -y / 2.], diff --git a/models/spacer/src/lib.rs b/models/spacer/src/lib.rs index 86a11450e3..7cb687eb80 100644 --- a/models/spacer/src/lib.rs +++ b/models/spacer/src/lib.rs @@ -2,24 +2,12 @@ use std::collections::HashMap; use fj::syntax::*; -#[no_mangle] -pub extern "C" fn model(args: &HashMap) -> fj::Shape { - let outer = args - .get("outer") - .unwrap_or(&"1.0".to_owned()) - .parse() - .expect("Could not parse parameter `outer`"); - let inner = args - .get("inner") - .unwrap_or(&"0.5".to_owned()) - .parse() - .expect("Could not parse parameter `inner`"); - let height: f64 = args - .get("height") - .unwrap_or(&"1.0".to_owned()) - .parse() - .expect("Could not parse parameter `height`"); - +#[fj::model] +pub fn model( + #[value(default = 1.0, min = inner * 1.01)] outer: f64, + #[value(default = 0.5, max = outer * 0.99)] inner: f64, + #[value(default = 1.0)] height: f64, +) -> fj::Shape { let outer_edge = fj::Circle::from_radius(outer); let inner_edge = fj::Circle::from_radius(inner); diff --git a/models/test/src/lib.rs b/models/test/src/lib.rs index 81e043f3ec..cf4ce09c26 100644 --- a/models/test/src/lib.rs +++ b/models/test/src/lib.rs @@ -2,8 +2,8 @@ use std::{collections::HashMap, f64::consts::PI}; use fj::{syntax::*, Angle}; -#[no_mangle] -pub extern "C" fn model(_: &HashMap) -> fj::Shape { +#[fj::model] +pub fn model() -> fj::Shape { let a = star(4, [0, 255, 0, 200]); let b = star(5, [255, 0, 0, 255]) .rotate([1., 1., 1.], Angle::from_deg(45.))