use crate::descriptor::FieldDescriptorProto; use crate::descriptor::FieldDescriptorProto_Label; use crate::json::json_name; use crate::message::Message; use crate::reflect::acc::Accessor; use crate::reflect::acc::FieldAccessor; use crate::reflect::map::ReflectMap; use crate::reflect::repeated::ReflectRepeated; use crate::reflect::EnumValueDescriptor; use crate::reflect::ReflectValueRef; /// Reference to a value stored in a field, optional, repeated or map. // TODO: implement Eq pub enum ReflectFieldRef<'a> { /// Singular field, optional or required in proto3 and just plain field in proto3 Optional(Option>), /// Repeated field Repeated(&'a dyn ReflectRepeated), /// Map field Map(&'a dyn ReflectMap), } /// Field descriptor. /// /// Can be used for runtime reflection. pub struct FieldDescriptor { proto: &'static FieldDescriptorProto, accessor: FieldAccessor, json_name: String, } impl FieldDescriptor { pub(crate) fn new( accessor: FieldAccessor, proto: &'static FieldDescriptorProto, ) -> FieldDescriptor { assert_eq!(proto.get_name(), accessor.name); let json_name = if !proto.get_json_name().is_empty() { proto.get_json_name().to_string() } else { json_name(proto.get_name()) }; FieldDescriptor { proto, accessor, // probably could be lazy-init json_name, } } /// Get `.proto` description of field pub fn proto(&self) -> &'static FieldDescriptorProto { self.proto } /// Field name as specified in `.proto` file pub fn name(&self) -> &'static str { self.proto.get_name() } /// JSON field name. /// /// Can be different from `.proto` field name. /// /// See [JSON mapping][json] for details. /// /// [json]: https://developers.google.com/protocol-buffers/docs/proto3#json pub fn json_name(&self) -> &str { &self.json_name } /// If this field repeated? pub fn is_repeated(&self) -> bool { self.proto.get_label() == FieldDescriptorProto_Label::LABEL_REPEATED } /// Check if field is set in given message. /// /// For repeated field or map field return `true` if /// collection is not empty. /// /// # Panics /// /// If this field belongs to a different message type. pub fn has_field(&self, m: &dyn Message) -> bool { match &self.accessor.accessor { Accessor::V1(a) => a.has_field_generic(m), } } /// Return length of repeated field. /// /// For singular field return `1` if field is set and `0` otherwise. /// /// # Panics /// /// If this field belongs to a different message type. pub fn len_field(&self, m: &dyn Message) -> usize { match &self.accessor.accessor { Accessor::V1(a) => a.len_field_generic(m), } } /// Get message field or default instance if field is unset. /// /// # Panics /// If this field belongs to a different message type or /// field type is not message. pub fn get_message<'a>(&self, m: &'a dyn Message) -> &'a dyn Message { match &self.accessor.accessor { Accessor::V1(a) => a.get_message_generic(m), } } /// Get `enum` field. /// /// # Panics /// /// If this field belongs to a different message type /// or field type is not singular `enum`. pub fn get_enum(&self, m: &dyn Message) -> &'static EnumValueDescriptor { match &self.accessor.accessor { Accessor::V1(a) => a.get_enum_generic(m), } } /// Get `string` field. /// /// # Panics /// /// If this field belongs to a different message type /// or field type is not singular `string`. pub fn get_str<'a>(&self, m: &'a dyn Message) -> &'a str { match &self.accessor.accessor { Accessor::V1(a) => a.get_str_generic(m), } } /// Get `bytes` field. /// /// # Panics /// /// If this field belongs to a different message type /// or field type is not singular `bytes`. pub fn get_bytes<'a>(&self, m: &'a dyn Message) -> &'a [u8] { match &self.accessor.accessor { Accessor::V1(a) => a.get_bytes_generic(m), } } /// Get `u32` field. /// /// # Panics /// /// If this field belongs to a different message type /// or field type is not singular `u32`. pub fn get_u32(&self, m: &dyn Message) -> u32 { match &self.accessor.accessor { Accessor::V1(a) => a.get_u32_generic(m), } } /// Get `u64` field. /// /// # Panics /// /// If this field belongs to a different message type /// or field type is not singular `u64`. pub fn get_u64(&self, m: &dyn Message) -> u64 { match &self.accessor.accessor { Accessor::V1(a) => a.get_u64_generic(m), } } /// Get `i32` field. /// /// # Panics /// /// If this field belongs to a different message type /// or field type is not singular `i32`. pub fn get_i32(&self, m: &dyn Message) -> i32 { match &self.accessor.accessor { Accessor::V1(a) => a.get_i32_generic(m), } } /// Get `i64` field. /// /// # Panics /// /// If this field belongs to a different message type /// or field type is not singular `i64`. pub fn get_i64(&self, m: &dyn Message) -> i64 { match &self.accessor.accessor { Accessor::V1(a) => a.get_i64_generic(m), } } /// Get `bool` field. /// /// # Panics /// /// If this field belongs to a different message type or /// field type is not singular `bool`. pub fn get_bool(&self, m: &dyn Message) -> bool { match &self.accessor.accessor { Accessor::V1(a) => a.get_bool_generic(m), } } /// Get `float` field. /// /// # Panics /// /// If this field belongs to a different message type or /// field type is not singular `float`. pub fn get_f32(&self, m: &dyn Message) -> f32 { match &self.accessor.accessor { Accessor::V1(a) => a.get_f32_generic(m), } } /// Get `double` field. /// /// # Panics /// /// If this field belongs to a different message type /// or field type is not singular `double`. pub fn get_f64(&self, m: &dyn Message) -> f64 { match &self.accessor.accessor { Accessor::V1(a) => a.get_f64_generic(m), } } /// Get field of any type. /// /// # Panics /// /// If this field belongs to a different message type. pub fn get_reflect<'a>(&self, m: &'a dyn Message) -> ReflectFieldRef<'a> { match &self.accessor.accessor { Accessor::V1(a) => a.get_reflect(m), } } }