robot_description_builder/chained/
mod.rs

1mod chained_jointbuilder;
2mod chained_linkbuilder;
3
4use std::{
5	fmt::Debug,
6	ops::{Deref, DerefMut},
7};
8
9use crate::identifiers::GroupIDChanger;
10
11/// A Wrapper to indicate if the current builder is a chain.
12///
13/// TODO: EXPAND
14#[derive(Debug, PartialEq, Clone)]
15#[repr(transparent)]
16pub struct Chained<Builder: ChainableBuilder>(pub(crate) Builder);
17
18// To allow for calling functions on the internal builders
19// TODO: Figure out if builderfunctions do not free the internal builder from it `Chained<Builder>` Identifier
20//
21// UPDATE: We do not escape however, the functions that consume can not be called either, see test chained::chained_joint_builder::test::chained escaping
22// TODO: Solution?: Add inplace methods???
23//
24// FIXME: but deref should theoretically only be implemented for smartpointers which do not add methods
25// https://rust-lang.github.io/api-guidelines/predictability.html?highlight=deref#only-smart-pointers-implement-deref-and-derefmut-c-deref
26// https://rust-lang.github.io/api-guidelines/predictability.html?highlight=deref#smart-pointers-do-not-add-inherent-methods-c-smart-ptr
27impl<Builder> Deref for Chained<Builder>
28where
29	Builder: ChainableBuilder,
30{
31	type Target = Builder;
32
33	fn deref(&self) -> &Self::Target {
34		&self.0
35	}
36}
37
38// To allow for calling functions on the internal builders
39// TODO: See above
40impl<Builder> DerefMut for Chained<Builder>
41where
42	Builder: ChainableBuilder,
43{
44	fn deref_mut(&mut self) -> &mut Self::Target {
45		&mut self.0
46	}
47}
48
49#[cfg(feature = "wrapper")]
50impl<Builder> Chained<Builder>
51where
52	Builder: ChainableBuilder,
53{
54	/// Create a Chained Builder, needs to be a chain.
55	pub unsafe fn new(builder: Builder) -> Self {
56		Chained(builder)
57	}
58}
59
60pub trait ChainableBuilder: Debug + PartialEq + Clone + GroupIDChanger {
61	/// Returns `true` if the builder has a chain/one or more childeren.
62	fn has_chain(&self) -> bool;
63}
64
65#[cfg(test)]
66mod tests {
67	use super::Chained;
68	use crate::{
69		joint::{JointBuilder, SmartJointBuilder},
70		link::{builder::LinkBuilder, Link},
71		prelude::*,
72	};
73	use test_log::test;
74
75	// For my own concept of `DerefMut`
76	#[test]
77	fn deref_mut_test() {
78		let leg_tree = Link::builder("leg_[[L01]]_l1").build_tree();
79		leg_tree
80			.get_root_link()
81			.try_write()
82			.unwrap()
83			.try_attach_child(
84				SmartJointBuilder::new_fixed("leg_[[L01]]_j1"),
85				Link::builder("leg_[[L01]]_l2"),
86			)
87			.unwrap();
88
89		let tree = Link::builder("root").build_tree();
90		tree.get_root_link()
91			.try_write()
92			.unwrap()
93			.try_attach_child(SmartJointBuilder::new_fixed("leg_[[L01]]_j0"), leg_tree)
94			.unwrap();
95
96		let builder_chain = tree.yank_joint("leg_[[L01]]_j0").unwrap();
97
98		assert_eq!(
99			builder_chain,
100			Chained(JointBuilder {
101				name: "leg_[[L01]]_j0".into(),
102				child: Some(LinkBuilder {
103					name: "leg_[[L01]]_l1".into(),
104					joints: vec![JointBuilder {
105						name: "leg_[[L01]]_j1".into(),
106						child: Some(LinkBuilder {
107							name: "leg_[[L01]]_l2".into(),
108							..Default::default()
109						}),
110						..Default::default()
111					}],
112					..Default::default()
113				}),
114				..Default::default()
115			})
116		);
117
118		let mut mirrored_chain = builder_chain
119			.clone()
120			.mirror(crate::transform::MirrorAxis::X);
121		// TODO: Add chainable version?
122		mirrored_chain.change_group_id("R01").unwrap();
123
124		let tree = Link::builder("root").build_tree();
125		tree.get_root_link()
126			.try_write()
127			.unwrap()
128			.attach_joint_chain(builder_chain)
129			.unwrap();
130		tree.get_root_link()
131			.try_write()
132			.unwrap()
133			.attach_joint_chain(mirrored_chain)
134			.unwrap();
135
136		assert_eq!(
137			tree.yank_link("root").unwrap(),
138			Chained(LinkBuilder {
139				name: "root".into(),
140				joints: vec![
141					JointBuilder {
142						name: "leg_[[L01]]_j0".into(),
143						child: Some(LinkBuilder {
144							name: "leg_[[L01]]_l1".into(),
145							joints: vec![JointBuilder {
146								name: "leg_[[L01]]_j1".into(),
147								child: Some(LinkBuilder {
148									name: "leg_[[L01]]_l2".into(),
149									..Default::default()
150								}),
151								..Default::default()
152							}],
153							..Default::default()
154						}),
155						..Default::default()
156					},
157					JointBuilder {
158						name: "leg_[[R01]]_j0".into(),
159						child: Some(LinkBuilder {
160							name: "leg_[[R01]]_l1".into(),
161							joints: vec![JointBuilder {
162								name: "leg_[[R01]]_j1".into(),
163								child: Some(LinkBuilder {
164									name: "leg_[[R01]]_l2".into(),
165									..Default::default()
166								}),
167								..Default::default()
168							}],
169							..Default::default()
170						}),
171						..Default::default()
172					}
173				],
174				..Default::default()
175			})
176		)
177	}
178}