1#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum FieldKind {
6 Bool,
8
9 UInt {
11 bits: u8,
13 },
14
15 SInt {
17 bits: u8,
19 },
20
21 VarUInt,
23
24 VarSInt,
26
27 FixedPoint {
29 min: f32,
31 max: f32,
33 bits: u8,
35 },
36}
37
38#[derive(Debug, Clone, PartialEq)]
40pub struct FieldCodec {
41 pub kind: FieldKind,
43
44 pub threshold: Option<f32>,
47}
48
49impl FieldCodec {
50 #[must_use]
52 pub const fn bool() -> Self {
53 Self {
54 kind: FieldKind::Bool,
55 threshold: None,
56 }
57 }
58
59 #[must_use]
61 pub const fn uint(bits: u8) -> Self {
62 Self {
63 kind: FieldKind::UInt { bits },
64 threshold: None,
65 }
66 }
67
68 #[must_use]
70 pub const fn sint(bits: u8) -> Self {
71 Self {
72 kind: FieldKind::SInt { bits },
73 threshold: None,
74 }
75 }
76
77 #[must_use]
79 pub const fn var_uint() -> Self {
80 Self {
81 kind: FieldKind::VarUInt,
82 threshold: None,
83 }
84 }
85
86 #[must_use]
88 pub const fn var_sint() -> Self {
89 Self {
90 kind: FieldKind::VarSInt,
91 threshold: None,
92 }
93 }
94
95 #[must_use]
97 pub const fn fixed_point(min: f32, max: f32, bits: u8) -> Self {
98 Self {
99 kind: FieldKind::FixedPoint { min, max, bits },
100 threshold: None,
101 }
102 }
103
104 #[must_use]
106 pub const fn with_threshold(mut self, threshold: f32) -> Self {
107 self.threshold = Some(threshold);
108 self
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
118 fn field_kind_bool() {
119 let kind = FieldKind::Bool;
120 assert!(matches!(kind, FieldKind::Bool));
121 }
122
123 #[test]
124 fn field_kind_uint() {
125 let kind = FieldKind::UInt { bits: 16 };
126 assert!(matches!(kind, FieldKind::UInt { bits: 16 }));
127 }
128
129 #[test]
130 fn field_kind_sint() {
131 let kind = FieldKind::SInt { bits: 32 };
132 assert!(matches!(kind, FieldKind::SInt { bits: 32 }));
133 }
134
135 #[test]
136 fn field_kind_var_uint() {
137 let kind = FieldKind::VarUInt;
138 assert!(matches!(kind, FieldKind::VarUInt));
139 }
140
141 #[test]
142 fn field_kind_var_sint() {
143 let kind = FieldKind::VarSInt;
144 assert!(matches!(kind, FieldKind::VarSInt));
145 }
146
147 #[test]
148 fn field_kind_fixed_point() {
149 let kind = FieldKind::FixedPoint {
150 min: -100.0,
151 max: 100.0,
152 bits: 16,
153 };
154 match kind {
155 FieldKind::FixedPoint { min, max, bits } => {
156 assert!((min - (-100.0)).abs() < f32::EPSILON);
157 assert!((max - 100.0).abs() < f32::EPSILON);
158 assert_eq!(bits, 16);
159 }
160 _ => panic!("wrong kind"),
161 }
162 }
163
164 #[test]
165 fn field_kind_equality() {
166 let k1 = FieldKind::UInt { bits: 8 };
167 let k2 = FieldKind::UInt { bits: 8 };
168 let k3 = FieldKind::UInt { bits: 16 };
169
170 assert_eq!(k1, k2);
171 assert_ne!(k1, k3);
172 }
173
174 #[test]
175 fn field_kind_clone_copy() {
176 let kind = FieldKind::Bool;
177 let copied = kind; assert_eq!(kind, copied);
179 }
180
181 #[test]
183 fn field_codec_bool() {
184 let codec = FieldCodec::bool();
185 assert!(matches!(codec.kind, FieldKind::Bool));
186 assert!(codec.threshold.is_none());
187 }
188
189 #[test]
190 fn field_codec_uint() {
191 let codec = FieldCodec::uint(16);
192 assert!(matches!(codec.kind, FieldKind::UInt { bits: 16 }));
193 assert!(codec.threshold.is_none());
194 }
195
196 #[test]
197 fn field_codec_sint() {
198 let codec = FieldCodec::sint(32);
199 assert!(matches!(codec.kind, FieldKind::SInt { bits: 32 }));
200 }
201
202 #[test]
203 fn field_codec_var_uint() {
204 let codec = FieldCodec::var_uint();
205 assert!(matches!(codec.kind, FieldKind::VarUInt));
206 }
207
208 #[test]
209 fn field_codec_var_sint() {
210 let codec = FieldCodec::var_sint();
211 assert!(matches!(codec.kind, FieldKind::VarSInt));
212 }
213
214 #[test]
215 fn field_codec_fixed_point() {
216 let codec = FieldCodec::fixed_point(-100.0, 100.0, 12);
217 match codec.kind {
218 FieldKind::FixedPoint { min, max, bits } => {
219 assert!((min - (-100.0)).abs() < f32::EPSILON);
220 assert!((max - 100.0).abs() < f32::EPSILON);
221 assert_eq!(bits, 12);
222 }
223 _ => panic!("wrong kind"),
224 }
225 }
226
227 #[test]
228 fn field_codec_with_threshold() {
229 let codec = FieldCodec::uint(8).with_threshold(0.5);
230 assert_eq!(codec.threshold, Some(0.5));
231 }
232
233 #[test]
234 fn field_codec_chained_threshold() {
235 let codec = FieldCodec::fixed_point(-100.0, 100.0, 12).with_threshold(0.1);
236 assert!(matches!(codec.kind, FieldKind::FixedPoint { bits: 12, .. }));
237 assert_eq!(codec.threshold, Some(0.1));
238 }
239
240 #[test]
241 fn field_codec_equality() {
242 let c1 = FieldCodec::uint(8);
243 let c2 = FieldCodec::uint(8);
244 let c3 = FieldCodec::uint(16);
245
246 assert_eq!(c1, c2);
247 assert_ne!(c1, c3);
248 }
249
250 #[test]
251 fn field_codec_threshold_equality() {
252 let c1 = FieldCodec::uint(8).with_threshold(0.5);
253 let c2 = FieldCodec::uint(8).with_threshold(0.5);
254 let c3 = FieldCodec::uint(8).with_threshold(1.0);
255 let c4 = FieldCodec::uint(8);
256
257 assert_eq!(c1, c2);
258 assert_ne!(c1, c3);
259 assert_ne!(c1, c4);
260 }
261
262 #[test]
263 fn field_codec_clone() {
264 let codec = FieldCodec::uint(8).with_threshold(0.5);
265 let cloned = codec.clone();
266 assert_eq!(codec, cloned);
267 }
268
269 #[test]
270 fn field_codec_const() {
271 const CODEC: FieldCodec = FieldCodec::bool();
272 assert!(matches!(CODEC.kind, FieldKind::Bool));
273 }
274}