refactor(entities): collapse trait wrapper boilerplate via macro

Every entity file ended with the same three-trait wrapper block:

    impl Grippable for T {
        fn grips(&self) -> Vec<GripDef> { grips(self) }
        fn apply_grip(&mut self, ...) { apply_grip(self, ...) }
    }
    impl PropertyEditable for T { ... }
    impl Transformable for T { ... }

— 23 lines of pure delegation around five same-named free functions.

Replace with `crate::impl_entity_basics!(T);` (a macro in
entities/traits.rs that expands to the three trait impls).

Applied where the file already follows the free-fn delegation
convention (Arc, Circle, Ellipse, Insert, Leader, Line, LwPolyline,
MultiLeader, Ole2Frame, Point, Spline, Viewport). Files that inlined
the trait method bodies directly (Ray, XLine, Shape, Solid, Tolerance,
MLine, Mesh, Solid3D/Region/Body, Table, RasterImage, Wipeout,
Underlay, Hatch, Polyline, Polyline2D, Polyline3D, Dimension) left
alone — they already skip the indirection. Text/MText/Attribute use
the with-text-style flavour and will move once that variant is needed
beyond the existing two manual impls.

A second macro `impl_entity_basics_with_text_styles!` is included for
the text-like flavour but no entity uses it yet.

Net: -204 lines.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.7 committed 2026-05-26 17:16:06 +03:00
1 parent 5e36e85e07
commit 9b5073752d
13 files changed
+101 -305

No files matched your search

+2 -26
View File
@@ -4,7 +4,7 @@ use truck_modeling::{builder, Point3};
use crate::command::EntityTransform;
use crate::entities::common::{diamond_grip, edit_prop as edit, parse_f64, square_grip};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::TruckConvertible;
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection};
use crate::scene::wire_model::{SnapHint, TangentGeom};
@@ -219,31 +219,7 @@ impl TruckConvertible for Arc {
}
}
impl Grippable for Arc {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Arc {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Arc {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(Arc);
impl crate::entities::traits::MassPropsCalc for acadrust::entities::Arc {
fn mass_props(&self) -> crate::entities::traits::MassProps {
+2 -26
View File
@@ -6,7 +6,7 @@ use crate::command::EntityTransform;
use crate::entities::common::{
diamond_grip, edit_prop as edit, parse_f64, ro_prop as ro, square_grip,
};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::TruckConvertible;
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection};
use crate::scene::wire_model::{SnapHint, TangentGeom};
@@ -202,31 +202,7 @@ impl TruckConvertible for Circle {
}
}
impl Grippable for Circle {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Circle {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Circle {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(Circle);
impl crate::entities::traits::MassPropsCalc for Circle {
fn mass_props(&self) -> crate::entities::traits::MassProps {
+2 -26
View File
@@ -4,7 +4,7 @@ use truck_modeling::{builder, BSplineCurve, Curve, Edge, KnotVec, Point3, Wire};
use crate::command::EntityTransform;
use crate::entities::common::{diamond_grip, edit_prop as edit, ro_prop as ro, square_grip};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::TruckConvertible;
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection};
use crate::scene::wire_model::SnapHint;
@@ -251,31 +251,7 @@ impl TruckConvertible for Ellipse {
}
}
impl Grippable for Ellipse {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Ellipse {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Ellipse {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(Ellipse);
impl crate::entities::traits::MassPropsCalc for acadrust::entities::Ellipse {
fn mass_props(&self) -> crate::entities::traits::MassProps {
+2 -26
View File
@@ -5,7 +5,7 @@ use glam::Vec3;
use crate::command::EntityTransform;
use crate::entities::common::{edit_prop as edit, parse_f64, ro_prop as ro, square_grip};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable};
use crate::scene::object::{GripApply, GripDef, PropSection};
use crate::scene::{block_cache, render, tessellate};
use crate::scene::wire_model::WireModel;
@@ -96,31 +96,7 @@ fn apply_transform(ins: &mut Insert, t: &EntityTransform) {
});
}
impl Grippable for Insert {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Insert {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Insert {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(Insert);
impl crate::entities::traits::FallbackTess for Insert {
fn fallback_geometry(&self, world_offset: [f64; 3]) -> crate::scene::tess_util::FallbackGeometry {
+2 -26
View File
@@ -4,7 +4,7 @@ use glam::Vec3;
use crate::command::EntityTransform;
use crate::entities::common::{diamond_grip, edit_prop as edit, ro_prop as ro, square_grip};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::{TruckConvertible};
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection, PropValue, Property};
use crate::scene::wire_model::TangentGeom;
@@ -455,31 +455,7 @@ impl TruckConvertible for Leader {
}
}
impl Grippable for Leader {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Leader {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Leader {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(Leader);
/// Per-entity tessellation entry for `Leader`. Lives here so all leader
/// tess code stays alongside the entity definition. Cross-entity dim
+2 -26
View File
@@ -6,7 +6,7 @@ use crate::command::EntityTransform;
use crate::entities::common::{
diamond_grip, edit_prop as edit, parse_f64, ro_prop as ro, square_grip,
};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::TruckConvertible;
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection};
use crate::scene::wire_model::TangentGeom;
@@ -156,31 +156,7 @@ impl TruckConvertible for Line {
}
}
impl Grippable for Line {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Line {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Line {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(Line);
impl crate::entities::traits::MassPropsCalc for acadrust::entities::Line {
fn mass_props(&self) -> crate::entities::traits::MassProps {
+2 -25
View File
@@ -6,7 +6,7 @@ use crate::command::EntityTransform;
use crate::entities::common::{
diamond_grip, edit_prop as edit, parse_f64, ro_prop as ro, square_grip,
};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::{TruckConvertible};
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection};
use crate::scene::wire_model::TangentGeom;
@@ -406,31 +406,8 @@ impl TruckConvertible for LwPolyline {
}
}
impl Grippable for LwPolyline {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
crate::impl_entity_basics!(LwPolyline);
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for LwPolyline {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for LwPolyline {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
pub(crate) fn wide_fills(pl: &acadrust::entities::LwPolyline) -> Vec<Vec<[f32; 2]>> {
let hw_const = (pl.constant_width / 2.0) as f32;
let verts = &pl.vertices;
+2 -24
View File
@@ -30,7 +30,7 @@ use glam::Vec3;
use crate::command::EntityTransform;
use crate::entities::common::{diamond_grip, edit_prop as edit, ro_prop as ro, square_grip};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::{TruckConvertible};
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection, PropValue, Property};
use crate::scene::wire_model::{SnapHint, TangentGeom};
@@ -827,29 +827,7 @@ impl TruckConvertible for MultiLeader {
}
}
impl Grippable for MultiLeader {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for MultiLeader {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for MultiLeader {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(MultiLeader);
/// Per-entity tessellation entry for `MultiLeader`. Returns multiple
/// `WireModel`s (leader/dogleg + arrow fill, optional block content,
+2 -24
View File
@@ -3,7 +3,7 @@ use glam::Vec3;
use crate::command::EntityTransform;
use crate::entities::common::{diamond_grip, edit_prop as edit, ro_prop as ro, square_grip};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::{TruckConvertible};
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection};
use crate::scene::wire_model::SnapHint;
@@ -178,29 +178,7 @@ impl TruckConvertible for Ole2Frame {
}
}
impl Grippable for Ole2Frame {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Ole2Frame {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Ole2Frame {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(Ole2Frame);
impl crate::entities::traits::FallbackTess for Ole2Frame {
fn fallback_geometry(&self, world_offset: [f64; 3]) -> crate::scene::tess_util::FallbackGeometry {
+2 -25
View File
@@ -4,7 +4,7 @@ use truck_modeling::{builder, Point3};
use crate::command::EntityTransform;
use crate::entities::common::{edit_prop as edit, parse_f64, square_grip};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::TruckConvertible;
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection};
use crate::scene::wire_model::SnapHint;
@@ -195,28 +195,5 @@ impl TruckConvertible for Point {
}
}
impl Grippable for Point {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
crate::impl_entity_basics!(Point);
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Point {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Point {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
+2 -25
View File
@@ -7,7 +7,7 @@ use truck_modeling::{
use crate::command::EntityTransform;
use crate::entities::common::{ro_prop as ro, square_grip};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable, TruckConvertible};
use crate::entities::traits::TruckConvertible;
use crate::scene::acad_to_truck::{TruckEntity, TruckObject};
use crate::scene::object::{GripApply, GripDef, PropSection};
@@ -161,28 +161,5 @@ impl TruckConvertible for Spline {
}
}
impl Grippable for Spline {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
crate::impl_entity_basics!(Spline);
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Spline {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Spline {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
+77
View File
@@ -81,6 +81,83 @@ macro_rules! dispatch {
};
}
/// Generates `Grippable`, `PropertyEditable`, `Transformable` trait impls
/// that delegate to identically-named free functions in the entity's own
/// module (`grips`, `apply_grip`, `properties`, `apply_geom_prop`,
/// `apply_transform`). `properties()` is called with `self` only — for
/// text-like entities that need the document's text-style list use
/// [`impl_entity_basics_with_text_styles!`] instead.
#[macro_export]
macro_rules! impl_entity_basics {
($T:ty) => {
impl $crate::entities::traits::Grippable for $T {
fn grips(&self) -> Vec<$crate::scene::object::GripDef> {
grips(self)
}
fn apply_grip(
&mut self,
grip_id: usize,
apply: $crate::scene::object::GripApply,
) {
apply_grip(self, grip_id, apply);
}
}
impl $crate::entities::traits::PropertyEditable for $T {
fn geometry_properties(
&self,
_text_style_names: &[String],
) -> $crate::scene::object::PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl $crate::entities::traits::Transformable for $T {
fn apply_transform(&mut self, t: &$crate::command::EntityTransform) {
apply_transform(self, t);
}
}
};
}
/// Same as [`impl_entity_basics!`] but the entity's `properties(...)` free
/// function takes the document's text-style name list as a second
/// argument (Text, MText, …).
#[macro_export]
macro_rules! impl_entity_basics_with_text_styles {
($T:ty) => {
impl $crate::entities::traits::Grippable for $T {
fn grips(&self) -> Vec<$crate::scene::object::GripDef> {
grips(self)
}
fn apply_grip(
&mut self,
grip_id: usize,
apply: $crate::scene::object::GripApply,
) {
apply_grip(self, grip_id, apply);
}
}
impl $crate::entities::traits::PropertyEditable for $T {
fn geometry_properties(
&self,
text_style_names: &[String],
) -> $crate::scene::object::PropSection {
properties(self, text_style_names)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl $crate::entities::traits::Transformable for $T {
fn apply_transform(&mut self, t: &$crate::command::EntityTransform) {
apply_transform(self, t);
}
}
};
}
impl EntityTypeOps for EntityType {
fn to_truck_entity(&self, document: &CadDocument) -> Option<TruckEntity> {
dispatch!(self,
+2 -26
View File
@@ -5,7 +5,7 @@ use crate::command::EntityTransform;
use crate::entities::common::{
diamond_grip, edit_prop as edit, parse_f64, ro_prop as ro, square_grip,
};
use crate::entities::traits::{Grippable, PropertyEditable, Transformable};
use crate::scene::object::{GripApply, GripDef, PropSection, PropValue, Property};
// ── Standard scale options ────────────────────────────────────────────────
@@ -541,31 +541,7 @@ fn apply_transform(vp: &mut Viewport, t: &EntityTransform) {
});
}
impl Grippable for Viewport {
fn grips(&self) -> Vec<GripDef> {
grips(self)
}
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
apply_grip(self, grip_id, apply);
}
}
impl PropertyEditable for Viewport {
fn geometry_properties(&self, _text_style_names: &[String]) -> PropSection {
properties(self)
}
fn apply_geom_prop(&mut self, field: &str, value: &str) {
apply_geom_prop(self, field, value);
}
}
impl Transformable for Viewport {
fn apply_transform(&mut self, t: &EntityTransform) {
apply_transform(self, t);
}
}
crate::impl_entity_basics!(Viewport);
impl crate::entities::traits::FallbackTess for Viewport {
fn fallback_geometry(&self, world_offset: [f64; 3]) -> crate::scene::tess_util::FallbackGeometry {