robot_description_builder/cluster_objects/
robot.rs

1use std::{
2	collections::HashMap,
3	sync::{Arc, PoisonError, RwLockWriteGuard},
4};
5
6#[cfg(feature = "urdf")]
7use crate::to_rdf::to_urdf::{ToURDF, URDFConfig};
8#[cfg(feature = "xml")]
9use quick_xml::{events::attributes::Attribute, name::QName};
10
11use super::{
12	kinematic_data_errors::AddTransmissionError, kinematic_data_tree::KinematicDataTree,
13	KinematicInterface,
14};
15use crate::{
16	identifiers::GroupID,
17	joint::Joint,
18	link::Link,
19	material::{data::MaterialData, Material},
20	transmission::{
21		transmission_builder_state::{WithActuator, WithJoints},
22		Transmission, TransmissionBuilder,
23	},
24	utils::{ArcLock, WeakLock},
25};
26
27#[derive(Debug)]
28pub struct Robot {
29	/// The name of the robot.
30	name: String,
31	data: Arc<KinematicDataTree>,
32}
33
34impl Robot {
35	pub(crate) fn new(name: impl Into<String>, data: Arc<KinematicDataTree>) -> Self {
36		Self {
37			name: name.into(),
38			data,
39		}
40	}
41
42	/// Gets a refence to the name of the `Robot`.
43	///
44	/// # Example
45	/// ```rust
46	/// # use robot_description_builder::{Robot, KinematicInterface, linkbuilding::LinkBuilder};
47	/// let robot: Robot = LinkBuilder::new("my-link")
48	///     .build_tree()
49	///     .to_robot("my-robot-called-rob");
50	///
51	/// assert_eq!(robot.name(), "my-robot-called-rob")
52	/// ```
53	pub fn name(&self) -> &String {
54		&self.name
55	}
56}
57
58impl KinematicInterface for Robot {
59	fn get_root_link(&self) -> ArcLock<Link> {
60		Arc::clone(&self.data.root_link)
61	}
62
63	fn get_newest_link(&self) -> ArcLock<Link> {
64		self.data.newest_link.read().unwrap().upgrade().unwrap()
65	}
66
67	fn get_links(&self) -> ArcLock<HashMap<String, WeakLock<Link>>> {
68		Arc::clone(&self.data.links)
69	}
70
71	fn get_joints(&self) -> ArcLock<HashMap<String, WeakLock<Joint>>> {
72		Arc::clone(&self.data.joints)
73	}
74
75	fn get_materials(&self) -> ArcLock<HashMap<String, ArcLock<MaterialData>>> {
76		Arc::clone(&self.data.material_index)
77	}
78
79	fn get_transmissions(&self) -> ArcLock<HashMap<String, ArcLock<Transmission>>> {
80		Arc::clone(&self.data.transmissions)
81	}
82
83	fn get_link(&self, name: &str) -> Option<ArcLock<Link>> {
84		self.data
85			.links
86			.read()
87			/* In the future the lock could be saved by overwriting with a newly generated index,
88			however waiting for "This is a nightly-only experimental API. (mutex_unpoison #96469)" */
89			.expect("The RwLock of the Link Index was poisoned. In the future this will be recoverable (mutex_unpoison).")
90			.get(name)
91			.and_then(|weak_link| weak_link.upgrade())
92	}
93
94	fn get_joint(&self, name: &str) -> Option<ArcLock<Joint>> {
95		self.data
96			.joints
97			.read()
98			/* In the future the lock could be saved by overwriting with a newly generated index,
99			however waiting for "This is a nightly-only experimental API. (mutex_unpoison #96469)" */
100			.expect("The RwLock of the Joint Index was poisoned. In the future this will be recoverable (mutex_unpoison).")
101			.get(name)
102			.and_then(|weak_joint| weak_joint.upgrade())
103	}
104
105	fn get_material(&self, name: &str) -> Option<Material> {
106		self.data
107			.material_index
108			.read()
109			.unwrap() // FIXME: Unwrapping might not be ok
110			.get(name)
111			.map(Arc::clone)
112			.map(|data| Material::new_named_inited(name, data))
113	}
114
115	fn get_transmission(&self, name: &str) -> Option<ArcLock<Transmission>> {
116		self.data
117			.transmissions
118			.read()
119			.unwrap() // FIXME: Unwrapping might not be ok
120			.get(name)
121			.map(Arc::clone)
122	}
123
124	fn try_add_transmission(
125		&self,
126		transmission: TransmissionBuilder<WithJoints, WithActuator>,
127	) -> Result<(), AddTransmissionError> {
128		self.data.try_add_transmission(transmission)
129	}
130
131	fn purge_links(&self) {
132		self.data.purge_links()
133	}
134
135	fn purge_joints(&self) {
136		self.data.purge_joints()
137	}
138
139	fn purge_materials(
140		&self,
141	) -> Result<(), PoisonError<RwLockWriteGuard<HashMap<String, ArcLock<MaterialData>>>>> {
142		self.data.purge_materials()
143	}
144
145	fn purge_transmissions(
146		&self,
147	) -> Result<(), PoisonError<RwLockWriteGuard<HashMap<String, ArcLock<Transmission>>>>> {
148		self.data.purge_transmissions()
149	}
150}
151
152#[cfg(feature = "urdf")]
153impl ToURDF for Robot {
154	fn to_urdf(
155		&self,
156		writer: &mut quick_xml::Writer<std::io::Cursor<Vec<u8>>>,
157		urdf_config: &URDFConfig,
158	) -> Result<(), quick_xml::Error> {
159		let element = writer.create_element("robot").with_attribute(Attribute {
160			key: QName(b"name"),
161			value: self.name.display().as_bytes().into(),
162		});
163		element.write_inner_content(|writer| self.data.to_urdf(writer, urdf_config))?;
164		Ok(())
165	}
166}