protobuf/
enum_or_unknown.rs

1use std::fmt;
2use std::marker::PhantomData;
3use std::mem;
4
5use crate::reflect::runtime_types::RuntimeTypeEnumOrUnknown;
6use crate::reflect::EnumDescriptor;
7use crate::reflect::ProtobufValue;
8use crate::Enum;
9use crate::EnumFull;
10
11/// Protobuf enums with possibly unknown values are preserved in this struct.
12#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
13#[repr(transparent)]
14// This should be <E: ProtobufEnum> when it no longer prevents using const fns.
15pub struct EnumOrUnknown<E> {
16    value: i32,
17    _marker: PhantomData<E>,
18}
19
20// Move into <E: ProtobufEnum> when no longer:
21// > trait bounds other than `Sized` on const fn parameters are unstable.
22impl<E> EnumOrUnknown<E> {
23    /// Construct from any `i32` value.
24    ///
25    /// Note passed value is not required to be a valid enum value.
26    pub const fn from_i32(value: i32) -> EnumOrUnknown<E> {
27        EnumOrUnknown {
28            value,
29            _marker: PhantomData,
30        }
31    }
32}
33
34impl<E: Enum> EnumOrUnknown<E> {
35    /// Construct from typed enum
36    pub fn new(e: E) -> EnumOrUnknown<E> {
37        EnumOrUnknown::from_i32(e.value())
38    }
39
40    /// Get contained `i32` value of enum
41    pub fn value(&self) -> i32 {
42        self.value
43    }
44
45    /// Get `i32` value as typed enum. Return `None` is value is unknown.
46    pub fn enum_value(&self) -> Result<E, i32> {
47        E::from_i32(self.value).ok_or(self.value)
48    }
49
50    /// Get contained enum, panic if value is unknown.
51    pub fn unwrap(&self) -> E {
52        self.enum_value().unwrap()
53    }
54
55    /// Get `i32` value as typed enum.
56    /// Return default enum value (first value) if value is unknown.
57    pub fn enum_value_or_default(&self) -> E {
58        self.enum_value().unwrap_or_default()
59    }
60
61    /// Get `i32` value as typed enum.
62    /// Return given enum value if value is unknown.
63    pub fn enum_value_or(&self, map_unknown: E) -> E {
64        self.enum_value().unwrap_or(map_unknown)
65    }
66
67    pub(crate) fn cast_to_values(enums: &[EnumOrUnknown<E>]) -> &[i32] {
68        assert_eq!(mem::size_of::<EnumOrUnknown<E>>(), mem::size_of::<i32>());
69        // SAFETY: `EnumOrUnknown` is `repr(C)`.
70        unsafe { std::slice::from_raw_parts(enums.as_ptr() as *const i32, enums.len()) }
71    }
72}
73
74impl<E: EnumFull> EnumOrUnknown<E> {
75    /// Get enum descriptor by type.
76    pub fn enum_descriptor() -> EnumDescriptor {
77        E::enum_descriptor()
78    }
79}
80
81impl<E: Enum> From<E> for EnumOrUnknown<E> {
82    fn from(e: E) -> Self {
83        EnumOrUnknown::new(e)
84    }
85}
86
87impl<E: Enum> Default for EnumOrUnknown<E> {
88    fn default() -> EnumOrUnknown<E> {
89        EnumOrUnknown::new(E::default())
90    }
91}
92
93impl<E: Enum + fmt::Debug> fmt::Debug for EnumOrUnknown<E> {
94    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95        match self.enum_value() {
96            Ok(e) => fmt::Debug::fmt(&e, f),
97            Err(e) => fmt::Debug::fmt(&e, f),
98        }
99    }
100}
101
102impl<E: EnumFull> ProtobufValue for EnumOrUnknown<E> {
103    type RuntimeType = RuntimeTypeEnumOrUnknown<E>;
104}