1 use std::fmt;
2 use std::marker::PhantomData;
3 use std::mem;
4 
5 use crate::reflect::runtime_types::RuntimeTypeEnumOrUnknown;
6 use crate::reflect::EnumDescriptor;
7 use crate::reflect::ProtobufValue;
8 use crate::Enum;
9 use 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.
15 pub 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.
22 impl<E> EnumOrUnknown<E> {
23     /// Construct from any `i32` value.
24     ///
25     /// Note passed value is not required to be a valid enum value.
from_i32(value: i32) -> EnumOrUnknown<E>26     pub const fn from_i32(value: i32) -> EnumOrUnknown<E> {
27         EnumOrUnknown {
28             value,
29             _marker: PhantomData,
30         }
31     }
32 }
33 
34 impl<E: Enum> EnumOrUnknown<E> {
35     /// Construct from typed enum
new(e: E) -> EnumOrUnknown<E>36     pub fn new(e: E) -> EnumOrUnknown<E> {
37         EnumOrUnknown::from_i32(e.value())
38     }
39 
40     /// Get contained `i32` value of enum
value(&self) -> i3241     pub fn value(&self) -> i32 {
42         self.value
43     }
44 
45     /// Get `i32` value as typed enum. Return `None` is value is unknown.
enum_value(&self) -> Result<E, i32>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.
unwrap(&self) -> E51     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.
enum_value_or_default(&self) -> E57     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.
enum_value_or(&self, map_unknown: E) -> E63     pub fn enum_value_or(&self, map_unknown: E) -> E {
64         self.enum_value().unwrap_or(map_unknown)
65     }
66 
cast_to_values(enums: &[EnumOrUnknown<E>]) -> &[i32]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 
74 impl<E: EnumFull> EnumOrUnknown<E> {
75     /// Get enum descriptor by type.
enum_descriptor() -> EnumDescriptor76     pub fn enum_descriptor() -> EnumDescriptor {
77         E::enum_descriptor()
78     }
79 }
80 
81 impl<E: Enum> From<E> for EnumOrUnknown<E> {
from(e: E) -> Self82     fn from(e: E) -> Self {
83         EnumOrUnknown::new(e)
84     }
85 }
86 
87 impl<E: Enum> Default for EnumOrUnknown<E> {
default() -> EnumOrUnknown<E>88     fn default() -> EnumOrUnknown<E> {
89         EnumOrUnknown::new(E::default())
90     }
91 }
92 
93 impl<E: Enum + fmt::Debug> fmt::Debug for EnumOrUnknown<E> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result94     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 
102 impl<E: EnumFull> ProtobufValue for EnumOrUnknown<E> {
103     type RuntimeType = RuntimeTypeEnumOrUnknown<E>;
104 }
105