//! The walks over a feature: its expressions (`params`), its references to the rest of the design //! (`feature_refs`) and its geometry (`feature_geometry`). `#[derive(Walk)]` //! (`solidcraft-derive`) generates them from `#[walk(...)]` roles on the fields of `FeatureKind` //! and the types inside it, so what a field is, is written once, where it is declared. The //! traits here carry the walks through the types the fields have: options, lists, arrays, planes //! and construction definitions. pub(crate) use solidcraft_geom::Vec3; pub(crate) use crate::ProfileSel; use crate::construct::{AxisDef, GeoRef, PointDef}; pub(crate) use crate::expr::Kind; pub(crate) use crate::feature_geometry::Geo; pub(crate) use crate::feature_refs::Ref; pub(crate) use crate::params::ExprRole; use crate::{PlaneRef, PointExpr}; /// An expression: its label, the expression, its kind and its role. pub(crate) type ExprItem<'a> = (&'static str, &'a String, Kind, ExprRole); pub(crate) type ExprItemMut<'a> = (&'static str, &'a mut String, Kind, ExprRole); pub(crate) type RefItem<'a> = Ref<&'a u64, &'a String>; pub(crate) type RefItemMut<'a> = Ref<&'a mut u64, &'a mut String>; pub(crate) type GeoItem<'a> = Geo<&'a Vec3, &'a PlaneRef, &'a GeoRef, &'a PointExpr, &'a ProfileSel>; pub(crate) type GeoItemMut<'a> = Geo<&'a mut Vec3, &'a mut PlaneRef, &'a mut GeoRef, &'a mut PointExpr, &'a mut ProfileSel>; /// A value's expressions, references and geometry, each walked in order. A type with none of /// them implements it empty. pub(crate) trait Walk { fn walk_exprs<'a>(&'a self, _: &mut dyn FnMut(ExprItem<'a>)) {} fn walk_exprs_mut<'a>(&'a mut self, _: &mut dyn FnMut(ExprItemMut<'a>)) {} fn walk_refs<'a>(&'a self, _: &mut dyn FnMut(RefItem<'a>)) {} fn walk_refs_mut<'a>(&'a mut self, _: &mut dyn FnMut(RefItemMut<'a>)) {} fn walk_geometry<'a>(&'a self, _: &mut dyn FnMut(GeoItem<'a>)) {} fn walk_geometry_mut<'a>(&'a mut self, _: &mut dyn FnMut(GeoItemMut<'a>)) {} } impl Walk for String {} impl Walk for std::sync::Arc {} impl Walk for bool {} impl Walk for u64 {} impl Walk for i8 {} impl Walk for f64 {} impl Walk for ProfileSel {} impl Walk for solidcraft_sketch::Sketch {} impl Walk for solidcraft_kernel::StepNode {} impl Walk for crate::document::Operation {} impl Walk for solidcraft_kernel::Continuity {} impl Walk for crate::document::Direction {} impl Walk for crate::document::FilletFit {} impl Walk for crate::document::MeshData {} impl Walk for crate::document::RevolveConvention {} impl Walk for crate::document::CoilSection {} impl Walk for crate::document::ThinSide {} impl Walk for crate::document::ExtendMode {} impl Walk for crate::document::RuledMode {} impl Walk for crate::document::RuledCorners {} impl Walk for crate::document::ExtrudeConvention {} /// Containers walk what they hold, in order. macro_rules! walk_each { ($([$($g:tt)*] $t:ty),*) => {$( impl<$($g)*> Walk for $t { fn walk_exprs<'a>(&'a self, f: &mut dyn FnMut(ExprItem<'a>)) { for t in self { t.walk_exprs(f) } } fn walk_exprs_mut<'a>(&'a mut self, f: &mut dyn FnMut(ExprItemMut<'a>)) { for t in self { t.walk_exprs_mut(f) } } fn walk_refs<'a>(&'a self, f: &mut dyn FnMut(RefItem<'a>)) { for t in self { t.walk_refs(f) } } fn walk_refs_mut<'a>(&'a mut self, f: &mut dyn FnMut(RefItemMut<'a>)) { for t in self { t.walk_refs_mut(f) } } fn walk_geometry<'a>(&'a self, f: &mut dyn FnMut(GeoItem<'a>)) { for t in self { t.walk_geometry(f) } } fn walk_geometry_mut<'a>(&'a mut self, f: &mut dyn FnMut(GeoItemMut<'a>)) { for t in self { t.walk_geometry_mut(f) } } } )*}; } walk_each!([T: Walk] Option, [T: Walk] Vec, [T: Walk, const N: usize] [T; N]); /// The values of a field with a role (`T`, an optional one or a list), in order. pub(crate) trait Each { fn each<'a>(&'a self, f: &mut dyn FnMut(&'a T)); fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(&'a mut T)); } impl Each for T { fn each<'a>(&'a self, f: &mut dyn FnMut(&'a T)) { f(self) } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(&'a mut T)) { f(self) } } impl Each for Option { fn each<'a>(&'a self, f: &mut dyn FnMut(&'a T)) { if let Some(t) = self { f(t) } } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(&'a mut T)) { if let Some(t) = self { f(t) } } } impl Each for Vec { fn each<'a>(&'a self, f: &mut dyn FnMut(&'a T)) { for t in self { f(t) } } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(&'a mut T)) { for t in self { f(t) } } } impl Each for [T; N] { fn each<'a>(&'a self, f: &mut dyn FnMut(&'a T)) { for t in self { f(t) } } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(&'a mut T)) { for t in self { f(t) } } } impl Each for Option<[T; N]> { fn each<'a>(&'a self, f: &mut dyn FnMut(&'a T)) { if let Some(a) = self { for t in a { f(t) } } } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(&'a mut T)) { if let Some(a) = self { for t in a { f(t) } } } } impl Each for Option> { fn each<'a>(&'a self, f: &mut dyn FnMut(&'a T)) { for t in self.iter().flatten() { f(t) } } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(&'a mut T)) { for t in self.iter_mut().flatten() { f(t) } } } /// The expressions of an expression field, each with its index and their count (for its label). pub(crate) trait ExprField { fn each<'a>(&'a self, f: &mut dyn FnMut(usize, usize, &'a String)); fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(usize, usize, &'a mut String)); } impl ExprField for String { fn each<'a>(&'a self, f: &mut dyn FnMut(usize, usize, &'a String)) { f(0, 1, self) } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(usize, usize, &'a mut String)) { f(0, 1, self) } } /// A position along an edge with its radius (a variable fillet's mid radii). impl ExprField for (f64, String) { fn each<'a>(&'a self, f: &mut dyn FnMut(usize, usize, &'a String)) { f(0, 1, &self.1) } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(usize, usize, &'a mut String)) { f(0, 1, &mut self.1) } } impl ExprField for Option { fn each<'a>(&'a self, f: &mut dyn FnMut(usize, usize, &'a String)) { if let Some(t) = self { t.each(f) } } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(usize, usize, &'a mut String)) { if let Some(t) = self { t.each_mut(f) } } } /// Lists and arrays number their elements. macro_rules! expr_list { ($([$($g:tt)*] $t:ty),*) => {$( impl<$($g)*> ExprField for $t { fn each<'a>(&'a self, f: &mut dyn FnMut(usize, usize, &'a String)) { let n = self.len(); for (i, t) in self.iter().enumerate() { t.each(&mut |_, _, e| f(i, n, e)); } } fn each_mut<'a>(&'a mut self, f: &mut dyn FnMut(usize, usize, &'a mut String)) { let n = self.len(); for (i, t) in self.iter_mut().enumerate() { t.each_mut(&mut |_, _, e| f(i, n, e)); } } } )*}; } expr_list!([T: ExprField] Vec, [T: ExprField, const N: usize] [T; N]); /// An expression's label: one for every element, one per element, or worked out from the /// element's index and the count. pub(crate) trait Label { fn at(&self, i: usize, n: usize) -> &'static str; } impl Label for &'static str { fn at(&self, _: usize, _: usize) -> &'static str { self } } impl Label for [&'static str; N] { fn at(&self, i: usize, _: usize) -> &'static str { self.get(i).copied().unwrap_or("") } } impl &'static str> Label for F { fn at(&self, i: usize, n: usize) -> &'static str { self(i, n) } } /// The offsets and angles of a plane, outermost first (nesting is capped like every walk over a /// plane), the construction plane it is built on, and the plane itself. impl Walk for PlaneRef { fn walk_exprs<'a>(&'a self, f: &mut dyn FnMut(ExprItem<'a>)) { let mut p = self; for _ in 0..64 { match p { PlaneRef::Offset { base, distance } => { f(("Offset", distance, Kind::Length, ExprRole::Input)); p = base; } PlaneRef::AtAngle { base, angle, .. } => { f(("Angle", angle, Kind::Angle, ExprRole::Input)); p = base; } PlaneRef::AlongPath { t, .. } => return f(("Distance (0 to 1)", t, Kind::Unitless, ExprRole::Input)), _ => return, } } } fn walk_exprs_mut<'a>(&'a mut self, f: &mut dyn FnMut(ExprItemMut<'a>)) { let mut p = self; for _ in 0..64 { match p { PlaneRef::Offset { base, distance } => { f(("Offset", distance, Kind::Length, ExprRole::Input)); p = base; } PlaneRef::AtAngle { base, angle, .. } => { f(("Angle", angle, Kind::Angle, ExprRole::Input)); p = base; } PlaneRef::AlongPath { t, .. } => return f(("Distance (0 to 1)", t, Kind::Unitless, ExprRole::Input)), _ => return, } } } fn walk_refs<'a>(&'a self, f: &mut dyn FnMut(RefItem<'a>)) { let mut p = self; for _ in 0..64 { match p { PlaneRef::Offset { base, .. } | PlaneRef::AtAngle { base, .. } => p = base, PlaneRef::Construction { name } => return f(Ref::Feature(name)), _ => return, } } } fn walk_refs_mut<'a>(&'a mut self, f: &mut dyn FnMut(RefItemMut<'a>)) { let mut p = self; for _ in 0..64 { match p { PlaneRef::Offset { base, .. } | PlaneRef::AtAngle { base, .. } => p = base, PlaneRef::Construction { name } => return f(Ref::Feature(name)), _ => return, } } } fn walk_geometry<'a>(&'a self, f: &mut dyn FnMut(GeoItem<'a>)) { f(Geo::Plane(self)) } fn walk_geometry_mut<'a>(&'a mut self, f: &mut dyn FnMut(GeoItemMut<'a>)) { f(Geo::Plane(self)) } } /// Construction axes and points: the expressions of the planes they are built from (and a point /// along a path's distance), and their references to the model. They name no sketches, features /// or bodies: copies remap their geometry references on their own (`Feature::remap_clone`). fn plane_exprs<'a>(refs: Vec<&'a GeoRef>, f: &mut dyn FnMut(ExprItem<'a>)) { for r in refs { if let GeoRef::Plane { plane } = r { plane.walk_exprs(f); } } } fn plane_exprs_mut<'a>(refs: Vec<&'a mut GeoRef>, f: &mut dyn FnMut(ExprItemMut<'a>)) { for r in refs { if let GeoRef::Plane { plane } = r { plane.walk_exprs_mut(f); } } } macro_rules! construct_geometry { () => { fn walk_geometry<'a>(&'a self, f: &mut dyn FnMut(GeoItem<'a>)) { for r in self.refs() { f(Geo::Construct(r)); } } fn walk_geometry_mut<'a>(&'a mut self, f: &mut dyn FnMut(GeoItemMut<'a>)) { for r in self.refs_mut() { f(Geo::Construct(r)); } } }; } impl Walk for AxisDef { fn walk_exprs<'a>(&'a self, f: &mut dyn FnMut(ExprItem<'a>)) { plane_exprs(self.refs(), f) } fn walk_exprs_mut<'a>(&'a mut self, f: &mut dyn FnMut(ExprItemMut<'a>)) { plane_exprs_mut(self.refs_mut(), f) } construct_geometry!(); } impl Walk for PointDef { fn walk_exprs<'a>(&'a self, f: &mut dyn FnMut(ExprItem<'a>)) { match self { PointDef::AlongPath { t, .. } => f(("Distance (0 to 1)", t, Kind::Unitless, ExprRole::Input)), other => plane_exprs(other.refs(), f), } } fn walk_exprs_mut<'a>(&'a mut self, f: &mut dyn FnMut(ExprItemMut<'a>)) { match self { PointDef::AlongPath { t, .. } => f(("Distance (0 to 1)", t, Kind::Unitless, ExprRole::Input)), other => plane_exprs_mut(other.refs_mut(), f), } } construct_geometry!(); }