1use std::fmt;
39
40pub trait GenericRepr: Sized {
47 type Repr;
49
50 fn into_repr(self) -> Self::Repr;
52
53 fn from_repr(repr: Self::Repr) -> Self;
55}
56
57#[derive(Clone, Copy, PartialEq, Eq, Hash)]
64pub struct Product<H, T>(pub H, pub T);
65
66impl<H: fmt::Debug, T: fmt::Debug> fmt::Debug for Product<H, T> {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(f, "({:?} × {:?})", self.0, self.1)
69 }
70}
71
72#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
74pub struct Unit;
75
76#[derive(Clone, Copy, PartialEq, Eq, Hash)]
83pub enum Sum<L, R> {
84 Left(L),
86 Right(R),
88}
89
90impl<L: fmt::Debug, R: fmt::Debug> fmt::Debug for Sum<L, R> {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 match self {
93 Sum::Left(l) => write!(f, "Left({l:?})"),
94 Sum::Right(r) => write!(f, "Right({r:?})"),
95 }
96 }
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
103pub enum Void {}
104
105#[derive(Clone, Copy, PartialEq, Eq, Hash)]
112pub struct Field<T> {
113 pub name: &'static str,
115 pub value: T,
117}
118
119impl<T> Field<T> {
120 pub fn new(name: &'static str, value: T) -> Self {
122 Self { name, value }
123 }
124
125 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Field<U> {
127 Field {
128 name: self.name,
129 value: f(self.value),
130 }
131 }
132}
133
134impl<T: fmt::Debug> fmt::Debug for Field<T> {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 write!(f, "{}={:?}", self.name, self.value)
137 }
138}
139
140#[derive(Clone, Copy, PartialEq, Eq, Hash)]
142pub struct Variant<T> {
143 pub name: &'static str,
145 pub value: T,
147}
148
149impl<T> Variant<T> {
150 pub fn new(name: &'static str, value: T) -> Self {
151 Self { name, value }
152 }
153}
154
155impl<T: fmt::Debug> fmt::Debug for Variant<T> {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 write!(f, "{}({:?})", self.name, self.value)
158 }
159}
160
161impl GenericRepr for () {
164 type Repr = Unit;
165 fn into_repr(self) -> Unit {
166 Unit
167 }
168 fn from_repr(_: Unit) -> Self {}
169}
170
171impl GenericRepr for bool {
172 type Repr = Sum<Unit, Unit>;
173 fn into_repr(self) -> Self::Repr {
174 if self {
175 Sum::Left(Unit)
176 } else {
177 Sum::Right(Unit)
178 }
179 }
180 fn from_repr(repr: Self::Repr) -> Self {
181 matches!(repr, Sum::Left(_))
182 }
183}
184
185impl<T> GenericRepr for Option<T> {
186 type Repr = Sum<T, Unit>;
187 fn into_repr(self) -> Self::Repr {
188 match self {
189 Some(v) => Sum::Left(v),
190 None => Sum::Right(Unit),
191 }
192 }
193 fn from_repr(repr: Self::Repr) -> Self {
194 match repr {
195 Sum::Left(v) => Some(v),
196 Sum::Right(_) => None,
197 }
198 }
199}
200
201impl<T, E> GenericRepr for Result<T, E> {
202 type Repr = Sum<T, E>;
203 fn into_repr(self) -> Self::Repr {
204 match self {
205 Ok(v) => Sum::Left(v),
206 Err(e) => Sum::Right(e),
207 }
208 }
209 fn from_repr(repr: Self::Repr) -> Self {
210 match repr {
211 Sum::Left(v) => Ok(v),
212 Sum::Right(e) => Err(e),
213 }
214 }
215}
216
217impl<A, B> GenericRepr for (A, B) {
218 type Repr = Product<A, Product<B, Unit>>;
219 fn into_repr(self) -> Self::Repr {
220 Product(self.0, Product(self.1, Unit))
221 }
222 fn from_repr(repr: Self::Repr) -> Self {
223 (repr.0, repr.1.0)
224 }
225}
226
227impl<A, B, C> GenericRepr for (A, B, C) {
228 type Repr = Product<A, Product<B, Product<C, Unit>>>;
229 fn into_repr(self) -> Self::Repr {
230 Product(self.0, Product(self.1, Product(self.2, Unit)))
231 }
232 fn from_repr(repr: Self::Repr) -> Self {
233 (repr.0, repr.1.0, repr.1.1.0)
234 }
235}
236
237pub trait ProductLen {
241 fn product_len() -> usize;
242}
243
244impl ProductLen for Unit {
245 fn product_len() -> usize {
246 0
247 }
248}
249
250impl<H, T: ProductLen> ProductLen for Product<H, T> {
251 fn product_len() -> usize {
252 1 + T::product_len()
253 }
254}
255
256pub trait SumLen {
258 fn sum_len() -> usize;
259}
260
261impl SumLen for Void {
262 fn sum_len() -> usize {
263 0
264 }
265}
266
267impl<L, R: SumLen> SumLen for Sum<L, R> {
268 fn sum_len() -> usize {
269 1 + R::sum_len()
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[derive(Clone, Debug, PartialEq)]
278 struct Point {
279 x: f64,
280 y: f64,
281 }
282
283 impl GenericRepr for Point {
284 type Repr = Product<Field<f64>, Product<Field<f64>, Unit>>;
285
286 fn into_repr(self) -> Self::Repr {
287 Product(
288 Field::new("x", self.x),
289 Product(Field::new("y", self.y), Unit),
290 )
291 }
292
293 fn from_repr(repr: Self::Repr) -> Self {
294 Point {
295 x: repr.0.value,
296 y: repr.1.0.value,
297 }
298 }
299 }
300
301 #[derive(Clone, Debug, PartialEq)]
302 enum Color {
303 Red,
304 Green,
305 Blue,
306 Custom(u8, u8, u8),
307 }
308
309 impl GenericRepr for Color {
310 type Repr = Sum<
311 Variant<Unit>,
312 Sum<
313 Variant<Unit>,
314 Sum<Variant<Unit>, Sum<Variant<Product<u8, Product<u8, Product<u8, Unit>>>>, Void>>,
315 >,
316 >;
317
318 fn into_repr(self) -> Self::Repr {
319 match self {
320 Color::Red => Sum::Left(Variant::new("Red", Unit)),
321 Color::Green => Sum::Right(Sum::Left(Variant::new("Green", Unit))),
322 Color::Blue => Sum::Right(Sum::Right(Sum::Left(Variant::new("Blue", Unit)))),
323 Color::Custom(r, g, b) => Sum::Right(Sum::Right(Sum::Right(Sum::Left(
324 Variant::new("Custom", Product(r, Product(g, Product(b, Unit)))),
325 )))),
326 }
327 }
328
329 fn from_repr(repr: Self::Repr) -> Self {
330 match repr {
331 Sum::Left(_) => Color::Red,
332 Sum::Right(Sum::Left(_)) => Color::Green,
333 Sum::Right(Sum::Right(Sum::Left(_))) => Color::Blue,
334 Sum::Right(Sum::Right(Sum::Right(Sum::Left(v)))) => {
335 Color::Custom(v.value.0, v.value.1.0, v.value.1.1.0)
336 }
337 Sum::Right(Sum::Right(Sum::Right(Sum::Right(v)))) => match v {},
338 }
339 }
340 }
341
342 #[test]
345 fn point_roundtrip() {
346 let p = Point { x: 1.0, y: 2.0 };
347 let repr = p.clone().into_repr();
348 let back = Point::from_repr(repr);
349 assert_eq!(p, back);
350 }
351
352 #[test]
353 fn color_roundtrip_unit_variants() {
354 for c in [Color::Red, Color::Green, Color::Blue] {
355 let back = Color::from_repr(c.clone().into_repr());
356 assert_eq!(c, back);
357 }
358 }
359
360 #[test]
361 fn color_roundtrip_data_variant() {
362 let c = Color::Custom(255, 128, 0);
363 let back = Color::from_repr(c.clone().into_repr());
364 assert_eq!(c, back);
365 }
366
367 #[test]
370 fn unit_roundtrip() {
371 let repr = ().into_repr();
372 assert_eq!(repr, Unit);
373 assert_eq!(<()>::from_repr(repr), ());
374 }
375
376 #[test]
377 fn bool_roundtrip() {
378 assert!(bool::from_repr(true.into_repr()));
379 assert!(!bool::from_repr(false.into_repr()));
380 }
381
382 #[test]
383 fn option_roundtrip() {
384 let some = Some(42);
385 assert_eq!(Option::from_repr(some.into_repr()), Some(42));
386
387 let none: Option<i32> = None;
388 assert_eq!(Option::from_repr(none.into_repr()), None);
389 }
390
391 #[test]
392 fn result_roundtrip() {
393 let ok: Result<i32, String> = Ok(42);
394 assert_eq!(Result::from_repr(ok.into_repr()), Ok(42));
395
396 let err: Result<i32, String> = Err("fail".into());
397 assert_eq!(Result::from_repr(err.into_repr()), Err("fail".into()));
398 }
399
400 #[test]
401 fn tuple2_roundtrip() {
402 let t = (1u32, "hello");
403 let back = <(u32, &str)>::from_repr(t.into_repr());
404 assert_eq!(back, (1, "hello"));
405 }
406
407 #[test]
408 fn tuple3_roundtrip() {
409 let t = (1u32, 2.0f64, true);
410 let back = <(u32, f64, bool)>::from_repr(t.into_repr());
411 assert_eq!(back, (1, 2.0, true));
412 }
413
414 #[test]
417 fn product_len_unit() {
418 assert_eq!(Unit::product_len(), 0);
419 }
420
421 #[test]
422 fn product_len_two() {
423 assert_eq!(<Product<i32, Product<i32, Unit>>>::product_len(), 2);
424 }
425
426 #[test]
427 fn product_len_three() {
428 assert_eq!(
429 <Product<i32, Product<i32, Product<i32, Unit>>>>::product_len(),
430 3
431 );
432 }
433
434 #[test]
435 fn sum_len_void() {
436 assert_eq!(Void::sum_len(), 0);
437 }
438
439 #[test]
440 fn sum_len_two() {
441 assert_eq!(<Sum<i32, Sum<i32, Void>>>::sum_len(), 2);
442 }
443
444 #[test]
447 fn product_debug() {
448 let p = Product(1, Product(2, Unit));
449 let debug = format!("{p:?}");
450 assert!(debug.contains("1"));
451 assert!(debug.contains("2"));
452 }
453
454 #[test]
455 fn sum_debug() {
456 let s: Sum<i32, i32> = Sum::Left(42);
457 assert_eq!(format!("{s:?}"), "Left(42)");
458 }
459
460 #[test]
461 fn field_debug() {
462 let f = Field::new("x", 1.0);
463 assert_eq!(format!("{f:?}"), "x=1.0");
464 }
465
466 #[test]
467 fn variant_debug() {
468 let v = Variant::new("Red", Unit);
469 let debug = format!("{v:?}");
470 assert!(debug.contains("Red"));
471 }
472
473 #[test]
474 fn field_map() {
475 let f = Field::new("count", 5);
476 let doubled = f.map(|v| v * 2);
477 assert_eq!(doubled.name, "count");
478 assert_eq!(doubled.value, 10);
479 }
480
481 #[test]
484 fn point_repr_has_field_names() {
485 let p = Point { x: 3.0, y: 4.0 };
486 let repr = p.into_repr();
487 assert_eq!(repr.0.name, "x");
488 assert_eq!(repr.0.value, 3.0);
489 assert_eq!(repr.1.0.name, "y");
490 assert_eq!(repr.1.0.value, 4.0);
491 }
492
493 #[test]
494 fn color_repr_has_variant_names() {
495 let c = Color::Red;
496 let repr = c.into_repr();
497 match repr {
498 Sum::Left(v) => assert_eq!(v.name, "Red"),
499 _ => panic!("expected Left"),
500 }
501 }
502}