use std::fmt; use std::marker::PhantomData; use std::mem; use crate::reflect::runtime_types::RuntimeTypeEnumOrUnknown; use crate::reflect::EnumDescriptor; use crate::reflect::ProtobufValue; use crate::Enum; use crate::EnumFull; /// Protobuf enums with possibly unknown values are preserved in this struct. #[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)] #[repr(transparent)] // This should be when it no longer prevents using const fns. pub struct EnumOrUnknown { value: i32, _marker: PhantomData, } // Move into when no longer: // > trait bounds other than `Sized` on const fn parameters are unstable. impl EnumOrUnknown { /// Construct from any `i32` value. /// /// Note passed value is not required to be a valid enum value. pub const fn from_i32(value: i32) -> EnumOrUnknown { EnumOrUnknown { value, _marker: PhantomData, } } } impl EnumOrUnknown { /// Construct from typed enum pub fn new(e: E) -> EnumOrUnknown { EnumOrUnknown::from_i32(e.value()) } /// Get contained `i32` value of enum pub fn value(&self) -> i32 { self.value } /// Get `i32` value as typed enum. Return `None` is value is unknown. pub fn enum_value(&self) -> Result { E::from_i32(self.value).ok_or(self.value) } /// Get contained enum, panic if value is unknown. pub fn unwrap(&self) -> E { self.enum_value().unwrap() } /// Get `i32` value as typed enum. /// Return default enum value (first value) if value is unknown. pub fn enum_value_or_default(&self) -> E { self.enum_value().unwrap_or_default() } /// Get `i32` value as typed enum. /// Return given enum value if value is unknown. pub fn enum_value_or(&self, map_unknown: E) -> E { self.enum_value().unwrap_or(map_unknown) } pub(crate) fn cast_to_values(enums: &[EnumOrUnknown]) -> &[i32] { assert_eq!(mem::size_of::>(), mem::size_of::()); // SAFETY: `EnumOrUnknown` is `repr(C)`. unsafe { std::slice::from_raw_parts(enums.as_ptr() as *const i32, enums.len()) } } } impl EnumOrUnknown { /// Get enum descriptor by type. pub fn enum_descriptor() -> EnumDescriptor { E::enum_descriptor() } } impl From for EnumOrUnknown { fn from(e: E) -> Self { EnumOrUnknown::new(e) } } impl Default for EnumOrUnknown { fn default() -> EnumOrUnknown { EnumOrUnknown::new(E::default()) } } impl fmt::Debug for EnumOrUnknown { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.enum_value() { Ok(e) => fmt::Debug::fmt(&e, f), Err(e) => fmt::Debug::fmt(&e, f), } } } impl ProtobufValue for EnumOrUnknown { type RuntimeType = RuntimeTypeEnumOrUnknown; }