1use super::units::Rad;
35use std::fmt;
36use std::ops::{Index, IndexMut};
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub enum Joint {
44 J1 = 0,
46 J2 = 1,
48 J3 = 2,
50 J4 = 3,
52 J5 = 4,
54 J6 = 5,
56}
57
58impl Joint {
59 pub const ALL: [Joint; 6] = [
61 Joint::J1,
62 Joint::J2,
63 Joint::J3,
64 Joint::J4,
65 Joint::J5,
66 Joint::J6,
67 ];
68
69 #[inline]
71 pub const fn index(self) -> usize {
72 self as usize
73 }
74
75 pub fn from_index(index: usize) -> Option<Self> {
77 match index {
78 0 => Some(Joint::J1),
79 1 => Some(Joint::J2),
80 2 => Some(Joint::J3),
81 3 => Some(Joint::J4),
82 4 => Some(Joint::J5),
83 5 => Some(Joint::J6),
84 _ => None,
85 }
86 }
87
88 pub const fn name(self) -> &'static str {
90 match self {
91 Joint::J1 => "J1",
92 Joint::J2 => "J2",
93 Joint::J3 => "J3",
94 Joint::J4 => "J4",
95 Joint::J5 => "J5",
96 Joint::J6 => "J6",
97 }
98 }
99}
100
101impl fmt::Display for Joint {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(f, "{}", self.name())
104 }
105}
106
107#[derive(Debug, Clone, PartialEq)]
111#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
112pub struct JointArray<T> {
113 data: [T; 6],
114}
115
116impl<T: Copy> Copy for JointArray<T> {}
118
119impl<T> JointArray<T> {
120 #[inline]
122 pub const fn new(data: [T; 6]) -> Self {
123 JointArray { data }
124 }
125
126 #[inline]
128 pub fn as_array(&self) -> &[T; 6] {
129 &self.data
130 }
131
132 #[inline]
134 pub fn as_array_mut(&mut self) -> &mut [T; 6] {
135 &mut self.data
136 }
137
138 #[inline]
140 pub fn into_array(self) -> [T; 6] {
141 self.data
142 }
143
144 pub fn iter(&self) -> std::slice::Iter<'_, T> {
146 self.data.iter()
147 }
148
149 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
151 self.data.iter_mut()
152 }
153
154 pub fn map<U, F>(self, mut f: F) -> JointArray<U>
156 where
157 F: FnMut(T) -> U,
158 {
159 let [a, b, c, d, e, g] = self.data;
160 JointArray::new([f(a), f(b), f(c), f(d), f(e), f(g)])
161 }
162
163 pub fn map_with_joint<U, F>(self, mut f: F) -> JointArray<U>
165 where
166 F: FnMut(Joint, T) -> U,
167 {
168 let [a, b, c, d, e, g] = self.data;
169 JointArray::new([
170 f(Joint::J1, a),
171 f(Joint::J2, b),
172 f(Joint::J3, c),
173 f(Joint::J4, d),
174 f(Joint::J5, e),
175 f(Joint::J6, g),
176 ])
177 }
178
179 pub fn map_with<U, V, F>(self, other: JointArray<U>, mut f: F) -> JointArray<V>
181 where
182 F: FnMut(T, U) -> V,
183 {
184 let [a1, b1, c1, d1, e1, f1] = self.data;
185 let [a2, b2, c2, d2, e2, f2] = other.data;
186 JointArray::new([
187 f(a1, a2),
188 f(b1, b2),
189 f(c1, c2),
190 f(d1, d2),
191 f(e1, e2),
192 f(f1, f2),
193 ])
194 }
195}
196
197impl<T: Copy> JointArray<T> {
198 #[inline]
200 pub const fn splat(value: T) -> Self {
201 JointArray::new([value, value, value, value, value, value])
202 }
203}
204
205impl<T: Default> Default for JointArray<T> {
206 fn default() -> Self {
207 JointArray::new([
208 T::default(),
209 T::default(),
210 T::default(),
211 T::default(),
212 T::default(),
213 T::default(),
214 ])
215 }
216}
217
218impl<T> Index<Joint> for JointArray<T> {
220 type Output = T;
221
222 #[inline]
223 fn index(&self, joint: Joint) -> &T {
224 &self.data[joint.index()]
225 }
226}
227
228impl<T> IndexMut<Joint> for JointArray<T> {
229 #[inline]
230 fn index_mut(&mut self, joint: Joint) -> &mut T {
231 &mut self.data[joint.index()]
232 }
233}
234
235impl<T> Index<usize> for JointArray<T> {
236 type Output = T;
237
238 #[inline]
239 fn index(&self, index: usize) -> &T {
240 &self.data[index]
241 }
242}
243
244impl<T> IndexMut<usize> for JointArray<T> {
245 #[inline]
246 fn index_mut(&mut self, index: usize) -> &mut T {
247 &mut self.data[index]
248 }
249}
250
251impl<T> From<[T; 6]> for JointArray<T> {
253 #[inline]
254 fn from(data: [T; 6]) -> Self {
255 JointArray::new(data)
256 }
257}
258
259impl<T> From<JointArray<T>> for [T; 6] {
260 #[inline]
261 fn from(arr: JointArray<T>) -> Self {
262 arr.data
263 }
264}
265
266impl<T> IntoIterator for JointArray<T> {
268 type Item = T;
269 type IntoIter = std::array::IntoIter<T, 6>;
270
271 fn into_iter(self) -> Self::IntoIter {
272 self.data.into_iter()
273 }
274}
275
276impl<'a, T> IntoIterator for &'a JointArray<T> {
277 type Item = &'a T;
278 type IntoIter = std::slice::Iter<'a, T>;
279
280 fn into_iter(self) -> Self::IntoIter {
281 self.data.iter()
282 }
283}
284
285impl<'a, T> IntoIterator for &'a mut JointArray<T> {
286 type Item = &'a mut T;
287 type IntoIter = std::slice::IterMut<'a, T>;
288
289 fn into_iter(self) -> Self::IntoIter {
290 self.data.iter_mut()
291 }
292}
293
294pub type JointPositions = JointArray<Rad>;
296
297pub type JointVelocities = JointArray<Rad>;
299
300pub type JointAccelerations = JointArray<Rad>;
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306
307 #[test]
308 fn test_joint_index() {
309 assert_eq!(Joint::J1.index(), 0);
310 assert_eq!(Joint::J6.index(), 5);
311 }
312
313 #[test]
314 fn test_joint_from_index() {
315 assert_eq!(Joint::from_index(0), Some(Joint::J1));
316 assert_eq!(Joint::from_index(5), Some(Joint::J6));
317 assert_eq!(Joint::from_index(6), None);
318 }
319
320 #[test]
321 fn test_joint_name() {
322 assert_eq!(Joint::J1.name(), "J1");
323 assert_eq!(format!("{}", Joint::J3), "J3");
324 }
325
326 #[test]
327 fn test_joint_all() {
328 assert_eq!(Joint::ALL.len(), 6);
329 assert_eq!(Joint::ALL[0], Joint::J1);
330 assert_eq!(Joint::ALL[5], Joint::J6);
331 }
332
333 #[test]
334 fn test_joint_array_creation() {
335 let arr = JointArray::new([1, 2, 3, 4, 5, 6]);
336 assert_eq!(arr[Joint::J1], 1);
337 assert_eq!(arr[Joint::J6], 6);
338 }
339
340 #[test]
341 fn test_joint_array_indexing() {
342 let positions =
343 JointArray::new([Rad(0.0), Rad(0.1), Rad(0.2), Rad(0.3), Rad(0.4), Rad(0.5)]);
344
345 assert_eq!(positions[Joint::J1], Rad(0.0));
346 assert_eq!(positions[Joint::J6], Rad(0.5));
347
348 assert_eq!(positions[0], Rad(0.0));
350 assert_eq!(positions[5], Rad(0.5));
351 }
352
353 #[test]
354 fn test_joint_array_iteration() {
355 let positions = JointArray::new([Rad(1.0); 6]);
356 let sum: f64 = positions.iter().map(|r| r.0).sum();
357 assert!((sum - 6.0).abs() < 1e-10);
358 }
359
360 #[test]
361 fn test_joint_array_map() {
362 let rad = JointArray::new([Rad(std::f64::consts::PI); 6]);
363 let deg = rad.map(|r| r.to_deg());
364 assert!((deg[Joint::J1].0 - 180.0).abs() < 1e-6);
365 }
366
367 #[test]
368 fn test_joint_array_map_with_joint() {
369 let positions = JointArray::new([Rad(1.0); 6]);
370 let scaled = positions.map_with_joint(|joint, rad| Rad(rad.0 * (joint.index() + 1) as f64));
371
372 assert_eq!(scaled[Joint::J1], Rad(1.0));
373 assert_eq!(scaled[Joint::J2], Rad(2.0));
374 assert_eq!(scaled[Joint::J6], Rad(6.0));
375 }
376
377 #[test]
378 fn test_joint_array_map_with() {
379 let a = JointArray::new([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
380 let b = JointArray::new([0.5, 0.5, 0.5, 0.5, 0.5, 0.5]);
381 let c = a.map_with(b, |x, y| x * y);
382
383 assert_eq!(c[Joint::J1], 0.5);
384 assert_eq!(c[Joint::J2], 1.0);
385 }
386
387 #[test]
388 fn test_joint_array_splat() {
389 let arr = JointArray::splat(Rad(0.5));
390 for joint in Joint::ALL {
391 assert_eq!(arr[joint], Rad(0.5));
392 }
393 }
394
395 #[test]
396 fn test_joint_array_mut() {
397 let mut positions = JointArray::new([Rad(0.0); 6]);
398 positions[Joint::J3] = Rad(1.5);
399 assert_eq!(positions[Joint::J3], Rad(1.5));
400 }
401
402 #[test]
403 fn test_joint_array_into_iter() {
404 let arr = JointArray::new([1, 2, 3, 4, 5, 6]);
405 let vec: Vec<_> = arr.into_iter().collect();
406 assert_eq!(vec, vec![1, 2, 3, 4, 5, 6]);
407 }
408
409 #[test]
410 fn test_joint_array_default() {
411 let arr: JointArray<i32> = JointArray::default();
412 for i in 0..6 {
413 assert_eq!(arr[i], 0);
414 }
415 }
416
417 #[test]
418 fn test_joint_positions_type() {
419 let positions: JointPositions = JointArray::new([Rad(0.0); 6]);
420 assert_eq!(positions[Joint::J1], Rad(0.0));
421 }
422
423 #[test]
424 fn test_from_into_array() {
425 let data = [1, 2, 3, 4, 5, 6];
426 let joint_array = JointArray::from(data);
427 let back: [i32; 6] = joint_array.into();
428 assert_eq!(data, back);
429 }
430}