Skip to main content

steel_utils/codec/
or.rs

1use std::io::{Cursor, Error, Write};
2
3use crate::serial::{ReadFrom, WriteTo};
4
5/// An enum that represents one of two possible types (Left or Right).
6/// When serialized, it writes only the inner value without any discriminant.
7/// The discriminant must be managed externally (e.g., via a separate boolean field).
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub enum Or<L, R> {
10    /// The left variant.
11    Left(L),
12    /// The right variant.
13    Right(R),
14}
15
16impl<L, R> Or<L, R> {
17    /// Creates a new `Or` with the left variant.
18    pub const fn left(value: L) -> Self {
19        Self::Left(value)
20    }
21
22    /// Creates a new `Or` with the right variant.
23    pub const fn right(value: R) -> Self {
24        Self::Right(value)
25    }
26
27    /// Returns `true` if this is a `Left` variant.
28    pub const fn is_left(&self) -> bool {
29        matches!(self, Self::Left(_))
30    }
31
32    /// Returns `true` if this is a `Right` variant.
33    pub const fn is_right(&self) -> bool {
34        matches!(self, Self::Right(_))
35    }
36}
37
38impl<L: WriteTo, R: WriteTo> WriteTo for Or<L, R> {
39    fn write(&self, writer: &mut impl Write) -> Result<(), Error> {
40        match self {
41            Self::Left(value) => value.write(writer),
42            Self::Right(value) => value.write(writer),
43        }
44    }
45}
46
47// Note: ReadFrom cannot be implemented without external context about which variant to read.
48// The discriminant must be read separately before calling this.
49
50impl<L, R> From<L> for Or<L, R> {
51    fn from(value: L) -> Self {
52        Self::Left(value)
53    }
54}
55
56// Implement WriteTo for unit type so it can be used as a placeholder in Or<T, ()>
57impl WriteTo for () {
58    fn write(&self, _writer: &mut impl Write) -> Result<(), Error> {
59        Ok(())
60    }
61}
62
63impl ReadFrom for () {
64    fn read(_data: &mut Cursor<&[u8]>) -> Result<Self, Error> {
65        Ok(())
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_or_write_left() {
75        let or_val = Or::<i32, i64>::Left(42);
76        let mut buf = Vec::new();
77        or_val.write(&mut buf).expect("write failed");
78
79        // Should write as a 32-bit integer
80        assert_eq!(buf.len(), 4);
81    }
82
83    #[test]
84    fn test_or_write_right() {
85        let or_val = Or::<i32, i64>::Right(12345i64);
86        let mut buf = Vec::new();
87        or_val.write(&mut buf).expect("write failed");
88
89        // Should write as a 64-bit integer
90        assert_eq!(buf.len(), 8);
91    }
92
93    #[test]
94    fn test_or_helpers() {
95        let left = Or::<i32, i64>::left(10);
96        assert!(left.is_left());
97        assert!(!left.is_right());
98
99        let right = Or::<i32, i64>::right(20);
100        assert!(!right.is_left());
101        assert!(right.is_right());
102    }
103}