1use std::fmt;
2
3use crate::lister::Lister;
4
5bitflags::bitflags! {
6 struct AxisFlags: u8 {
7 const X = 1;
8 const Y = 2;
9 const Z = 4;
10 }
11}
12
13#[derive(Clone, Copy, PartialEq, Eq)]
18pub struct Axes {
19 flags: AxisFlags,
20}
21
22impl Axes {
23 pub const X: Self = Self {
24 flags: AxisFlags::X,
25 };
26
27 pub const Y: Self = Self {
28 flags: AxisFlags::Y,
29 };
30
31 pub const Z: Self = Self {
32 flags: AxisFlags::Z,
33 };
34}
35
36impl Axes {
37 pub const fn empty() -> Self {
38 Self {
39 flags: AxisFlags::empty(),
40 }
41 }
42
43 pub const fn all() -> Self {
44 Self {
45 flags: AxisFlags::all(),
46 }
47 }
48
49 pub const fn contains(self, other: Self) -> bool {
50 self.flags.contains(other.flags)
51 }
52
53 pub const fn bits(self) -> u8 {
54 self.flags.bits()
55 }
56
57 pub const fn from_bits(bits: u8) -> Option<Self> {
58 match AxisFlags::from_bits(bits) {
59 Some(flags) => Some(Self { flags }),
60 None => None,
61 }
62 }
63
64 #[cfg(feature = "serde")]
65 fn len(self) -> usize {
66 self.bits().count_ones() as usize
67 }
68}
69
70impl fmt::Debug for Axes {
71 fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
72 let mut list = Lister::new();
73
74 write!(out, "Axes(")?;
75
76 if self.contains(Self::X) {
77 list.write(out, "X")?;
78 }
79
80 if self.contains(Self::Y) {
81 list.write(out, "Y")?;
82 }
83
84 if self.contains(Self::Z) {
85 list.write(out, "Z")?;
86 }
87
88 write!(out, ")")
89 }
90}
91
92#[cfg(feature = "serde")]
93mod serde_impl {
94 use super::*;
95
96 use std::fmt;
97
98 use serde::{
99 de::{Error as _, SeqAccess, Visitor},
100 ser::SerializeSeq,
101 Deserialize, Deserializer, Serialize, Serializer,
102 };
103
104 impl Serialize for Axes {
105 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
106 if serializer.is_human_readable() {
107 let mut seq = serializer.serialize_seq(Some(self.len()))?;
108
109 if self.contains(Self::X) {
110 seq.serialize_element("X")?;
111 }
112
113 if self.contains(Self::Y) {
114 seq.serialize_element("Y")?;
115 }
116
117 if self.contains(Self::Z) {
118 seq.serialize_element("Z")?;
119 }
120
121 seq.end()
122 } else {
123 serializer.serialize_u8(self.bits())
124 }
125 }
126 }
127
128 struct HumanVisitor;
129
130 impl<'de> Visitor<'de> for HumanVisitor {
131 type Value = Axes;
132
133 fn expecting(&self, out: &mut fmt::Formatter) -> fmt::Result {
134 write!(out, "a list of strings representing axes")
135 }
136
137 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
138 let mut flags = AxisFlags::empty();
139
140 while let Some(axis_str) = seq.next_element::<String>()? {
141 match axis_str.as_str() {
142 "X" => flags |= AxisFlags::X,
143 "Y" => flags |= AxisFlags::Y,
144 "Z" => flags |= AxisFlags::Z,
145 _ => {
146 return Err(A::Error::custom(format!("invalid axis '{axis_str}'")));
147 }
148 }
149 }
150
151 Ok(Axes { flags })
152 }
153 }
154
155 impl<'de> Deserialize<'de> for Axes {
156 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
157 if deserializer.is_human_readable() {
158 deserializer.deserialize_seq(HumanVisitor)
159 } else {
160 let value = u8::deserialize(deserializer)?;
161
162 Axes::from_bits(value)
163 .ok_or_else(|| D::Error::custom("value must a u8 bitmask of axes"))
164 }
165 }
166 }
167}
168
169#[cfg(all(test, feature = "serde"))]
170mod serde_test {
171 use super::*;
172
173 #[test]
174 fn human_de() {
175 let empty: Axes = serde_json::from_str("[]").unwrap();
176 assert_eq!(empty, Axes::empty());
177
178 let x: Axes = serde_json::from_str(r#"["X"]"#).unwrap();
179 assert_eq!(x, Axes::X);
180
181 let all: Axes = serde_json::from_str(r#"["X", "Y", "Z"]"#).unwrap();
182 assert_eq!(all, Axes::all());
183 }
184
185 #[test]
186 fn human_ser() {
187 let empty = serde_json::to_string(&Axes::empty()).unwrap();
188 assert_eq!(empty, "[]");
189
190 let x = serde_json::to_string(&Axes::X).unwrap();
191 assert_eq!(x, r#"["X"]"#);
192
193 let all = serde_json::to_string(&Axes::all()).unwrap();
194 assert_eq!(all, r#"["X","Y","Z"]"#);
195 }
196
197 #[test]
198 fn human_duplicate() {
199 let x: Axes = serde_json::from_str(r#"["X", "X", "X", "X"]"#).unwrap();
200 assert_eq!(x, Axes::X);
201 }
202
203 #[test]
204 fn human_invalid() {
205 let invalid = serde_json::from_str::<Axes>(r#"["pizza"]"#);
207 assert!(invalid.is_err());
208 }
209
210 #[test]
211 fn non_human() {
212 let empty = Axes::empty();
213 let ser_empty = bincode::serialize(&empty).unwrap();
214 let de_empty = bincode::deserialize(&ser_empty).unwrap();
215 assert_eq!(empty, de_empty);
216
217 let x = Axes::X;
218 let ser_x = bincode::serialize(&x).unwrap();
219 let de_x = bincode::deserialize(&ser_x).unwrap();
220 assert_eq!(x, de_x);
221
222 let all = Axes::all();
223 let ser_all = bincode::serialize(&all).unwrap();
224 let de_all = bincode::deserialize(&ser_all).unwrap();
225 assert_eq!(all, de_all);
226 }
227}