Import protobuf-2.14.0
* Add OWNERS and Android.bp
* add generated version.rs into out
Bug: 143953733
Test: make
Change-Id: Ib53a973b74679c4dd78e2de2fa54141e55048c17
diff --git a/src/reflect/accessor.rs b/src/reflect/accessor.rs
new file mode 100644
index 0000000..8a586b2
--- /dev/null
+++ b/src/reflect/accessor.rs
@@ -0,0 +1,789 @@
+#![doc(hidden)]
+
+use std::collections::HashMap;
+use std::fmt;
+use std::hash::Hash;
+
+use core::message_down_cast;
+use core::Message;
+use enums::ProtobufEnum;
+use reflect::EnumValueDescriptor;
+use types::*;
+
+use repeated::RepeatedField;
+use singular::SingularField;
+use singular::SingularPtrField;
+
+use super::map::ReflectMap;
+use super::optional::ReflectOptional;
+use super::repeated::ReflectRepeated;
+use super::repeated::ReflectRepeatedEnum;
+use super::repeated::ReflectRepeatedMessage;
+use super::value::ProtobufValue;
+use super::value::ReflectValueRef;
+use super::ReflectFieldRef;
+
+/// this trait should not be used directly, use `FieldDescriptor` instead
+pub trait FieldAccessor {
+ fn name_generic(&self) -> &'static str;
+ fn has_field_generic(&self, m: &Message) -> bool;
+ fn len_field_generic(&self, m: &Message) -> usize;
+ // TODO: should it return default value or panic on unset field?
+ fn get_message_generic<'a>(&self, m: &'a Message) -> &'a Message;
+ fn get_enum_generic(&self, m: &Message) -> &'static EnumValueDescriptor;
+ fn get_str_generic<'a>(&self, m: &'a Message) -> &'a str;
+ fn get_bytes_generic<'a>(&self, m: &'a Message) -> &'a [u8];
+ fn get_u32_generic(&self, m: &Message) -> u32;
+ fn get_u64_generic(&self, m: &Message) -> u64;
+ fn get_i32_generic(&self, m: &Message) -> i32;
+ fn get_i64_generic(&self, m: &Message) -> i64;
+ fn get_bool_generic(&self, m: &Message) -> bool;
+ fn get_f32_generic(&self, m: &Message) -> f32;
+ fn get_f64_generic(&self, m: &Message) -> f64;
+
+ fn get_reflect<'a>(&self, m: &'a Message) -> ReflectFieldRef<'a>;
+}
+
+trait GetSingularMessage<M> {
+ fn get_message<'a>(&self, m: &'a M) -> &'a Message;
+}
+
+struct GetSingularMessageImpl<M, N> {
+ get: for<'a> fn(&'a M) -> &'a N,
+}
+
+impl<M: Message, N: Message + 'static> GetSingularMessage<M> for GetSingularMessageImpl<M, N> {
+ fn get_message<'a>(&self, m: &'a M) -> &'a Message {
+ (self.get)(m)
+ }
+}
+
+trait GetSingularEnum<M> {
+ fn get_enum(&self, m: &M) -> &'static EnumValueDescriptor;
+}
+
+struct GetSingularEnumImpl<M, E> {
+ get: fn(&M) -> E,
+}
+
+impl<M: Message, E: ProtobufEnum> GetSingularEnum<M> for GetSingularEnumImpl<M, E> {
+ fn get_enum(&self, m: &M) -> &'static EnumValueDescriptor {
+ (self.get)(m).descriptor()
+ }
+}
+
+trait GetRepeatedMessage<M> {
+ fn len_field(&self, m: &M) -> usize;
+ fn get_message_item<'a>(&self, m: &'a M, index: usize) -> &'a Message;
+ fn reflect_repeated_message<'a>(&self, m: &'a M) -> Box<ReflectRepeatedMessage<'a> + 'a>;
+}
+
+trait GetRepeatedEnum<M: Message + 'static> {
+ fn len_field(&self, m: &M) -> usize;
+ fn get_enum_item(&self, m: &M, index: usize) -> &'static EnumValueDescriptor;
+ fn reflect_repeated_enum<'a>(&self, m: &'a M) -> Box<ReflectRepeatedEnum<'a> + 'a>;
+}
+
+trait GetSetCopyFns<M> {
+ fn get_field<'a>(&self, m: &'a M) -> ReflectValueRef<'a>;
+}
+
+struct GetSetCopyFnsImpl<M, V: ProtobufValue + Copy> {
+ get: fn(&M) -> V,
+ _set: fn(&mut M, V),
+}
+
+impl<M, V: ProtobufValue + Copy> GetSetCopyFns<M> for GetSetCopyFnsImpl<M, V> {
+ fn get_field<'a>(&self, m: &'a M) -> ReflectValueRef<'a> {
+ (&(self.get)(m) as &ProtobufValue).as_ref_copy()
+ }
+}
+
+enum SingularGetSet<M> {
+ Copy(Box<GetSetCopyFns<M>>),
+ String(for<'a> fn(&'a M) -> &'a str, fn(&mut M, String)),
+ Bytes(for<'a> fn(&'a M) -> &'a [u8], fn(&mut M, Vec<u8>)),
+ Enum(Box<GetSingularEnum<M> + 'static>),
+ Message(Box<GetSingularMessage<M> + 'static>),
+}
+
+impl<M: Message + 'static> SingularGetSet<M> {
+ fn get_ref<'a>(&self, m: &'a M) -> ReflectValueRef<'a> {
+ match self {
+ &SingularGetSet::Copy(ref copy) => copy.get_field(m),
+ &SingularGetSet::String(get, _) => ReflectValueRef::String(get(m)),
+ &SingularGetSet::Bytes(get, _) => ReflectValueRef::Bytes(get(m)),
+ &SingularGetSet::Enum(ref get) => ReflectValueRef::Enum(get.get_enum(m)),
+ &SingularGetSet::Message(ref get) => ReflectValueRef::Message(get.get_message(m)),
+ }
+ }
+}
+
+trait FieldAccessor2<M, R: ?Sized>
+where
+ M: Message + 'static,
+{
+ fn get_field<'a>(&self, &'a M) -> &'a R;
+ fn mut_field<'a>(&self, &'a mut M) -> &'a mut R;
+}
+
+struct MessageGetMut<M, L>
+where
+ M: Message + 'static,
+{
+ get_field: for<'a> fn(&'a M) -> &'a L,
+ mut_field: for<'a> fn(&'a mut M) -> &'a mut L,
+}
+
+enum FieldAccessorFunctions<M> {
+ // up to 1.0.24 optional or required
+ SingularHasGetSet {
+ has: fn(&M) -> bool,
+ get_set: SingularGetSet<M>,
+ },
+ // protobuf 3 simple field
+ Simple(Box<FieldAccessor2<M, ProtobufValue>>),
+ // optional, required or message
+ Optional(Box<FieldAccessor2<M, ReflectOptional>>),
+ // repeated
+ Repeated(Box<FieldAccessor2<M, ReflectRepeated>>),
+ // protobuf 3 map
+ Map(Box<FieldAccessor2<M, ReflectMap>>),
+}
+
+impl<M> fmt::Debug for FieldAccessorFunctions<M> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &FieldAccessorFunctions::SingularHasGetSet { .. } => {
+ write!(f, "SingularHasGetSet {{ .. }}")
+ }
+ &FieldAccessorFunctions::Simple(..) => write!(f, "Simple(..)"),
+ &FieldAccessorFunctions::Optional(..) => write!(f, "Optional(..)"),
+ &FieldAccessorFunctions::Repeated(..) => write!(f, "Repeated(..)"),
+ &FieldAccessorFunctions::Map(..) => write!(f, "Map(..)"),
+ }
+ }
+}
+
+struct FieldAccessorImpl<M> {
+ name: &'static str,
+ fns: FieldAccessorFunctions<M>,
+}
+
+impl<M: Message> FieldAccessorImpl<M> {
+ fn get_value_option<'a>(&self, m: &'a M) -> Option<ReflectValueRef<'a>> {
+ match self.fns {
+ FieldAccessorFunctions::Repeated(..) | FieldAccessorFunctions::Map(..) => {
+ panic!("repeated")
+ }
+ FieldAccessorFunctions::Simple(ref a) => Some(a.get_field(m).as_ref()),
+ FieldAccessorFunctions::Optional(ref a) => {
+ a.get_field(m).to_option().map(|v| v.as_ref())
+ }
+ FieldAccessorFunctions::SingularHasGetSet {
+ ref has,
+ ref get_set,
+ } => {
+ if !has(m) {
+ None
+ } else {
+ Some(get_set.get_ref(m))
+ }
+ }
+ }
+ }
+}
+
+impl<M: Message + 'static> FieldAccessor for FieldAccessorImpl<M> {
+ fn name_generic(&self) -> &'static str {
+ self.name
+ }
+
+ fn has_field_generic(&self, m: &Message) -> bool {
+ match self.fns {
+ FieldAccessorFunctions::SingularHasGetSet { has, .. } => has(message_down_cast(m)),
+ FieldAccessorFunctions::Optional(ref a) => {
+ a.get_field(message_down_cast(m)).to_option().is_some()
+ }
+ FieldAccessorFunctions::Simple(ref a) => {
+ a.get_field(message_down_cast(m)).is_non_zero()
+ }
+ FieldAccessorFunctions::Map(..) | FieldAccessorFunctions::Repeated(..) => {
+ panic!("has_xxx is not implemented for repeated");
+ }
+ }
+ }
+
+ fn len_field_generic(&self, m: &Message) -> usize {
+ match self.fns {
+ FieldAccessorFunctions::Repeated(ref a) => a.get_field(message_down_cast(m)).len(),
+ FieldAccessorFunctions::Map(ref a) => a.get_field(message_down_cast(m)).len(),
+ FieldAccessorFunctions::Simple(..)
+ | FieldAccessorFunctions::SingularHasGetSet { .. }
+ | FieldAccessorFunctions::Optional(..) => {
+ panic!("not a repeated field");
+ }
+ }
+ }
+
+ fn get_message_generic<'a>(&self, m: &'a Message) -> &'a Message {
+ match self.fns {
+ FieldAccessorFunctions::SingularHasGetSet {
+ get_set: SingularGetSet::Message(ref get),
+ ..
+ } => get.get_message(message_down_cast(m)),
+ FieldAccessorFunctions::Optional(ref t) => {
+ match t
+ .get_field(message_down_cast(m))
+ .to_option()
+ .expect("field unset")
+ .as_ref()
+ {
+ ReflectValueRef::Message(m) => m,
+ _ => panic!("not a message"),
+ }
+ }
+ ref fns => panic!("unknown accessor type: {:?}", fns),
+ }
+ }
+
+ fn get_enum_generic(&self, m: &Message) -> &'static EnumValueDescriptor {
+ match self.fns {
+ FieldAccessorFunctions::SingularHasGetSet {
+ get_set: SingularGetSet::Enum(ref get),
+ ..
+ } => get.get_enum(message_down_cast(m)),
+ _ => panic!(),
+ }
+ }
+
+ fn get_str_generic<'a>(&self, m: &'a Message) -> &'a str {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::String(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => "", // TODO: check type
+ }
+ }
+
+ fn get_bytes_generic<'a>(&self, m: &'a Message) -> &'a [u8] {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::Bytes(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => b"", // TODO: check type
+ }
+ }
+
+ fn get_u32_generic(&self, m: &Message) -> u32 {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::U32(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => 0, // TODO: check type
+ }
+ }
+
+ fn get_u64_generic(&self, m: &Message) -> u64 {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::U64(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => 0, // TODO: check type
+ }
+ }
+
+ fn get_i32_generic(&self, m: &Message) -> i32 {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::I32(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => 0, // TODO: check type
+ }
+ }
+
+ fn get_i64_generic(&self, m: &Message) -> i64 {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::I64(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => 0, // TODO: check type
+ }
+ }
+
+ fn get_f32_generic(&self, m: &Message) -> f32 {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::F32(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => 0.0, // TODO: check type
+ }
+ }
+
+ fn get_f64_generic(&self, m: &Message) -> f64 {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::F64(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => 0.0, // TODO: check type
+ }
+ }
+
+ fn get_bool_generic(&self, m: &Message) -> bool {
+ match self.get_value_option(message_down_cast(m)) {
+ Some(ReflectValueRef::Bool(v)) => v,
+ Some(_) => panic!("wrong type"),
+ None => false, // TODO: check type
+ }
+ }
+
+ fn get_reflect<'a>(&self, m: &'a Message) -> ReflectFieldRef<'a> {
+ match self.fns {
+ FieldAccessorFunctions::Repeated(ref accessor2) => {
+ ReflectFieldRef::Repeated(accessor2.get_field(message_down_cast(m)))
+ }
+ FieldAccessorFunctions::Map(ref accessor2) => {
+ ReflectFieldRef::Map(accessor2.get_field(message_down_cast(m)))
+ }
+ FieldAccessorFunctions::Optional(ref accessor2) => ReflectFieldRef::Optional(
+ accessor2
+ .get_field(message_down_cast(m))
+ .to_option()
+ .map(|v| v.as_ref()),
+ ),
+ FieldAccessorFunctions::Simple(ref accessor2) => ReflectFieldRef::Optional({
+ let v = accessor2.get_field(message_down_cast(m));
+ if v.is_non_zero() {
+ Some(v.as_ref())
+ } else {
+ None
+ }
+ }),
+ FieldAccessorFunctions::SingularHasGetSet {
+ ref has,
+ ref get_set,
+ } => ReflectFieldRef::Optional(if has(message_down_cast(m)) {
+ Some(get_set.get_ref(message_down_cast(m)))
+ } else {
+ None
+ }),
+ }
+ }
+}
+
+// singular
+
+fn set_panic<A, B>(_: &mut A, _: B) {
+ panic!()
+}
+
+// TODO: make_singular_xxx_accessor are used only for oneof fields
+// oneof codegen should be changed
+
+pub fn make_singular_u32_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: fn(&M) -> u32,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Copy(Box::new(GetSetCopyFnsImpl {
+ get: get,
+ _set: set_panic,
+ })),
+ },
+ })
+}
+
+pub fn make_singular_i32_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: fn(&M) -> i32,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Copy(Box::new(GetSetCopyFnsImpl {
+ get: get,
+ _set: set_panic,
+ })),
+ },
+ })
+}
+
+pub fn make_singular_u64_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: fn(&M) -> u64,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Copy(Box::new(GetSetCopyFnsImpl {
+ get: get,
+ _set: set_panic,
+ })),
+ },
+ })
+}
+
+pub fn make_singular_i64_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: fn(&M) -> i64,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Copy(Box::new(GetSetCopyFnsImpl {
+ get: get,
+ _set: set_panic,
+ })),
+ },
+ })
+}
+
+pub fn make_singular_f32_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: fn(&M) -> f32,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Copy(Box::new(GetSetCopyFnsImpl {
+ get: get,
+ _set: set_panic,
+ })),
+ },
+ })
+}
+
+pub fn make_singular_f64_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: fn(&M) -> f64,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Copy(Box::new(GetSetCopyFnsImpl {
+ get: get,
+ _set: set_panic,
+ })),
+ },
+ })
+}
+
+pub fn make_singular_bool_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: fn(&M) -> bool,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Copy(Box::new(GetSetCopyFnsImpl {
+ get: get,
+ _set: set_panic,
+ })),
+ },
+ })
+}
+
+pub fn make_singular_enum_accessor<M: Message + 'static, E: ProtobufEnum + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: fn(&M) -> E,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Enum(Box::new(GetSingularEnumImpl { get: get })),
+ },
+ })
+}
+
+pub fn make_singular_string_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: for<'a> fn(&'a M) -> &'a str,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::String(get, set_panic),
+ },
+ })
+}
+
+pub fn make_singular_bytes_accessor<M: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: for<'a> fn(&'a M) -> &'a [u8],
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Bytes(get, set_panic),
+ },
+ })
+}
+
+pub fn make_singular_message_accessor<M: Message + 'static, F: Message + 'static>(
+ name: &'static str,
+ has: fn(&M) -> bool,
+ get: for<'a> fn(&'a M) -> &'a F,
+) -> Box<FieldAccessor + 'static> {
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::SingularHasGetSet {
+ has: has,
+ get_set: SingularGetSet::Message(Box::new(GetSingularMessageImpl { get: get })),
+ },
+ })
+}
+
+// repeated
+
+impl<M, V> FieldAccessor2<M, ReflectRepeated> for MessageGetMut<M, Vec<V>>
+where
+ M: Message + 'static,
+ V: ProtobufValue + 'static,
+{
+ fn get_field<'a>(&self, m: &'a M) -> &'a ReflectRepeated {
+ (self.get_field)(m) as &ReflectRepeated
+ }
+
+ fn mut_field<'a>(&self, m: &'a mut M) -> &'a mut ReflectRepeated {
+ (self.mut_field)(m) as &mut ReflectRepeated
+ }
+}
+
+pub fn make_vec_accessor<M, V>(
+ name: &'static str,
+ get_vec: for<'a> fn(&'a M) -> &'a Vec<V::Value>,
+ mut_vec: for<'a> fn(&'a mut M) -> &'a mut Vec<V::Value>,
+) -> Box<FieldAccessor + 'static>
+where
+ M: Message + 'static,
+ V: ProtobufType + 'static,
+{
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::Repeated(Box::new(MessageGetMut::<M, Vec<V::Value>> {
+ get_field: get_vec,
+ mut_field: mut_vec,
+ })),
+ })
+}
+
+impl<M, V> FieldAccessor2<M, ReflectRepeated> for MessageGetMut<M, RepeatedField<V>>
+where
+ M: Message + 'static,
+ V: ProtobufValue + 'static,
+{
+ fn get_field<'a>(&self, m: &'a M) -> &'a ReflectRepeated {
+ (self.get_field)(m) as &ReflectRepeated
+ }
+
+ fn mut_field<'a>(&self, m: &'a mut M) -> &'a mut ReflectRepeated {
+ (self.mut_field)(m) as &mut ReflectRepeated
+ }
+}
+
+pub fn make_repeated_field_accessor<M, V>(
+ name: &'static str,
+ get_vec: for<'a> fn(&'a M) -> &'a RepeatedField<V::Value>,
+ mut_vec: for<'a> fn(&'a mut M) -> &'a mut RepeatedField<V::Value>,
+) -> Box<FieldAccessor + 'static>
+where
+ M: Message + 'static,
+ V: ProtobufType + 'static,
+{
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::Repeated(Box::new(MessageGetMut::<
+ M,
+ RepeatedField<V::Value>,
+ > {
+ get_field: get_vec,
+ mut_field: mut_vec,
+ })),
+ })
+}
+
+impl<M, V> FieldAccessor2<M, ReflectOptional> for MessageGetMut<M, Option<V>>
+where
+ M: Message + 'static,
+ V: ProtobufValue + Clone + 'static,
+{
+ fn get_field<'a>(&self, m: &'a M) -> &'a ReflectOptional {
+ (self.get_field)(m) as &ReflectOptional
+ }
+
+ fn mut_field<'a>(&self, m: &'a mut M) -> &'a mut ReflectOptional {
+ (self.mut_field)(m) as &mut ReflectOptional
+ }
+}
+
+pub fn make_option_accessor<M, V>(
+ name: &'static str,
+ get_field: for<'a> fn(&'a M) -> &'a Option<V::Value>,
+ mut_field: for<'a> fn(&'a mut M) -> &'a mut Option<V::Value>,
+) -> Box<FieldAccessor + 'static>
+where
+ M: Message + 'static,
+ V: ProtobufType + 'static,
+{
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::Optional(Box::new(MessageGetMut::<M, Option<V::Value>> {
+ get_field: get_field,
+ mut_field: mut_field,
+ })),
+ })
+}
+
+impl<M, V> FieldAccessor2<M, ReflectOptional> for MessageGetMut<M, SingularField<V>>
+where
+ M: Message + 'static,
+ V: ProtobufValue + Clone + 'static,
+{
+ fn get_field<'a>(&self, m: &'a M) -> &'a ReflectOptional {
+ (self.get_field)(m) as &ReflectOptional
+ }
+
+ fn mut_field<'a>(&self, m: &'a mut M) -> &'a mut ReflectOptional {
+ (self.mut_field)(m) as &mut ReflectOptional
+ }
+}
+
+pub fn make_singular_field_accessor<M, V>(
+ name: &'static str,
+ get_field: for<'a> fn(&'a M) -> &'a SingularField<V::Value>,
+ mut_field: for<'a> fn(&'a mut M) -> &'a mut SingularField<V::Value>,
+) -> Box<FieldAccessor + 'static>
+where
+ M: Message + 'static,
+ V: ProtobufType + 'static,
+{
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::Optional(Box::new(MessageGetMut::<
+ M,
+ SingularField<V::Value>,
+ > {
+ get_field: get_field,
+ mut_field: mut_field,
+ })),
+ })
+}
+
+impl<M, V> FieldAccessor2<M, ReflectOptional> for MessageGetMut<M, SingularPtrField<V>>
+where
+ M: Message + 'static,
+ V: ProtobufValue + Clone + 'static,
+{
+ fn get_field<'a>(&self, m: &'a M) -> &'a ReflectOptional {
+ (self.get_field)(m) as &ReflectOptional
+ }
+
+ fn mut_field<'a>(&self, m: &'a mut M) -> &'a mut ReflectOptional {
+ (self.mut_field)(m) as &mut ReflectOptional
+ }
+}
+
+pub fn make_singular_ptr_field_accessor<M, V>(
+ name: &'static str,
+ get_field: for<'a> fn(&'a M) -> &'a SingularPtrField<V::Value>,
+ mut_field: for<'a> fn(&'a mut M) -> &'a mut SingularPtrField<V::Value>,
+) -> Box<FieldAccessor + 'static>
+where
+ M: Message + 'static,
+ V: ProtobufType + 'static,
+{
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::Optional(Box::new(MessageGetMut::<
+ M,
+ SingularPtrField<V::Value>,
+ > {
+ get_field: get_field,
+ mut_field: mut_field,
+ })),
+ })
+}
+
+impl<M, V> FieldAccessor2<M, ProtobufValue> for MessageGetMut<M, V>
+where
+ M: Message + 'static,
+ V: ProtobufValue + Clone + 'static,
+{
+ fn get_field<'a>(&self, m: &'a M) -> &'a ProtobufValue {
+ (self.get_field)(m) as &ProtobufValue
+ }
+
+ fn mut_field<'a>(&self, m: &'a mut M) -> &'a mut ProtobufValue {
+ (self.mut_field)(m) as &mut ProtobufValue
+ }
+}
+
+pub fn make_simple_field_accessor<M, V>(
+ name: &'static str,
+ get_field: for<'a> fn(&'a M) -> &'a V::Value,
+ mut_field: for<'a> fn(&'a mut M) -> &'a mut V::Value,
+) -> Box<FieldAccessor + 'static>
+where
+ M: Message + 'static,
+ V: ProtobufType + 'static,
+{
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::Simple(Box::new(MessageGetMut::<M, V::Value> {
+ get_field: get_field,
+ mut_field: mut_field,
+ })),
+ })
+}
+
+impl<M, K, V> FieldAccessor2<M, ReflectMap> for MessageGetMut<M, HashMap<K, V>>
+where
+ M: Message + 'static,
+ K: ProtobufValue + 'static,
+ V: ProtobufValue + 'static,
+ K: Hash + Eq,
+{
+ fn get_field<'a>(&self, m: &'a M) -> &'a ReflectMap {
+ (self.get_field)(m) as &ReflectMap
+ }
+
+ fn mut_field<'a>(&self, m: &'a mut M) -> &'a mut ReflectMap {
+ (self.mut_field)(m) as &mut ReflectMap
+ }
+}
+
+pub fn make_map_accessor<M, K, V>(
+ name: &'static str,
+ get_field: for<'a> fn(&'a M) -> &'a HashMap<K::Value, V::Value>,
+ mut_field: for<'a> fn(&'a mut M) -> &'a mut HashMap<K::Value, V::Value>,
+) -> Box<FieldAccessor + 'static>
+where
+ M: Message + 'static,
+ K: ProtobufType + 'static,
+ V: ProtobufType + 'static,
+ <K as ProtobufType>::Value: Hash + Eq,
+{
+ Box::new(FieldAccessorImpl {
+ name: name,
+ fns: FieldAccessorFunctions::Map(Box::new(
+ MessageGetMut::<M, HashMap<K::Value, V::Value>> {
+ get_field: get_field,
+ mut_field: mut_field,
+ },
+ )),
+ })
+}
diff --git a/src/reflect/enums.rs b/src/reflect/enums.rs
new file mode 100644
index 0000000..e4ba4f6
--- /dev/null
+++ b/src/reflect/enums.rs
@@ -0,0 +1,127 @@
+use descriptor::EnumDescriptorProto;
+use descriptor::EnumValueDescriptorProto;
+use descriptor::FileDescriptorProto;
+use descriptorx::find_enum_by_rust_name;
+use reflect::find_message_or_enum::find_message_or_enum;
+use reflect::find_message_or_enum::MessageOrEnum;
+use std::collections::HashMap;
+use ProtobufEnum;
+
+/// Description for enum variant.
+///
+/// Used in reflection.
+#[derive(Clone, Debug)]
+pub struct EnumValueDescriptor {
+ proto: &'static EnumValueDescriptorProto,
+}
+
+impl Copy for EnumValueDescriptor {}
+
+impl EnumValueDescriptor {
+ /// Name of enum variant as specified in proto file
+ pub fn name(&self) -> &'static str {
+ self.proto.get_name()
+ }
+
+ /// `i32` value of the enum variant
+ pub fn value(&self) -> i32 {
+ self.proto.get_number()
+ }
+}
+
+/// Dynamic representation of enum type.
+///
+/// Can be used in reflective operations.
+pub struct EnumDescriptor {
+ proto: &'static EnumDescriptorProto,
+ values: Vec<EnumValueDescriptor>,
+
+ index_by_name: HashMap<String, usize>,
+ index_by_number: HashMap<i32, usize>,
+}
+
+impl EnumDescriptor {
+ /// Enum name as given in `.proto` file
+ pub fn name(&self) -> &'static str {
+ self.proto.get_name()
+ }
+
+ /// `EnumDescriptor` for enum type
+ pub fn for_type<E: ProtobufEnum>() -> &'static EnumDescriptor {
+ E::enum_descriptor_static()
+ }
+
+ /// Create new enum descriptor.
+ ///
+ /// This function is called by generated code, and should not be called manually.
+ #[deprecated(
+ since = "2.12",
+ note = "Please regenerate .rs files from .proto files to use newer APIs"
+ )]
+ pub fn new(rust_name: &'static str, file: &'static FileDescriptorProto) -> EnumDescriptor {
+ let proto = find_enum_by_rust_name(file, rust_name);
+ let mut index_by_name = HashMap::new();
+ let mut index_by_number = HashMap::new();
+ for (i, v) in proto.en.get_value().iter().enumerate() {
+ index_by_number.insert(v.get_number(), i);
+ index_by_name.insert(v.get_name().to_string(), i);
+ }
+ EnumDescriptor {
+ proto: proto.en,
+ values: proto
+ .en
+ .get_value()
+ .iter()
+ .map(|v| EnumValueDescriptor { proto: v })
+ .collect(),
+ index_by_name: index_by_name,
+ index_by_number: index_by_number,
+ }
+ }
+
+ /// Create new enum descriptor.
+ ///
+ /// This function is called by generated code, and should not be called manually.
+ pub fn new_pb_name<E>(
+ name_in_file: &'static str,
+ file: &'static FileDescriptorProto,
+ ) -> EnumDescriptor
+ where
+ E: ProtobufEnum,
+ {
+ let (_path_to_package, proto) = match find_message_or_enum(file, name_in_file) {
+ (path_to_package, MessageOrEnum::Enum(e)) => (path_to_package, e),
+ (_, MessageOrEnum::Message(_)) => panic!("not an enum"),
+ };
+
+ let mut index_by_name = HashMap::new();
+ let mut index_by_number = HashMap::new();
+ for (i, v) in proto.get_value().iter().enumerate() {
+ index_by_number.insert(v.get_number(), i);
+ index_by_name.insert(v.get_name().to_string(), i);
+ }
+ EnumDescriptor {
+ proto,
+ values: proto
+ .get_value()
+ .iter()
+ .map(|v| EnumValueDescriptor { proto: v })
+ .collect(),
+ index_by_name: index_by_name,
+ index_by_number: index_by_number,
+ }
+ }
+
+ /// Find enum value by name
+ pub fn value_by_name<'a>(&'a self, name: &str) -> &'a EnumValueDescriptor {
+ // TODO: clone is weird
+ let &index = self.index_by_name.get(&name.to_string()).unwrap();
+ &self.values[index]
+ }
+
+ /// Find enum value by number
+ pub fn value_by_number<'a>(&'a self, number: i32) -> &'a EnumValueDescriptor {
+ let &index = self.index_by_number.get(&number).unwrap();
+ &self.values[index]
+ }
+}
diff --git a/src/reflect/field.rs b/src/reflect/field.rs
new file mode 100644
index 0000000..ecac510
--- /dev/null
+++ b/src/reflect/field.rs
@@ -0,0 +1,191 @@
+use descriptor::{FieldDescriptorProto, FieldDescriptorProto_Label};
+use reflect::accessor::FieldAccessor;
+use reflect::map::ReflectMap;
+use reflect::repeated::ReflectRepeated;
+use reflect::{EnumValueDescriptor, ReflectValueRef};
+use Message;
+
+/// 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<ReflectValueRef<'a>>),
+ /// Repeated field
+ Repeated(&'a ReflectRepeated),
+ /// Map field
+ Map(&'a ReflectMap),
+}
+
+/// Field descriptor.
+///
+/// Can be used for runtime reflection.
+pub struct FieldDescriptor {
+ proto: &'static FieldDescriptorProto,
+ accessor: Box<FieldAccessor + 'static>,
+}
+
+impl FieldDescriptor {
+ pub(crate) fn new(
+ accessor: Box<FieldAccessor + 'static>,
+ proto: &'static FieldDescriptorProto,
+ ) -> FieldDescriptor {
+ assert_eq!(proto.get_name(), accessor.name_generic());
+ FieldDescriptor { proto, accessor }
+ }
+
+ /// 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()
+ }
+
+ /// 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: &Message) -> bool {
+ self.accessor.has_field_generic(m)
+ }
+
+ /// Return length of repeated field.
+ ///
+ /// For singualar 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 {
+ self.accessor.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 {
+ self.accessor.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 {
+ self.accessor.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 {
+ self.accessor.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] {
+ self.accessor.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 {
+ self.accessor.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 {
+ self.accessor.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 {
+ self.accessor.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 {
+ self.accessor.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 {
+ self.accessor.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 {
+ self.accessor.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 {
+ self.accessor.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> {
+ self.accessor.get_reflect(m)
+ }
+}
diff --git a/src/reflect/find_message_or_enum.rs b/src/reflect/find_message_or_enum.rs
new file mode 100644
index 0000000..7ee3915
--- /dev/null
+++ b/src/reflect/find_message_or_enum.rs
@@ -0,0 +1,62 @@
+use crate::descriptor::DescriptorProto;
+use crate::descriptor::EnumDescriptorProto;
+use crate::descriptor::FileDescriptorProto;
+
+pub(crate) enum MessageOrEnum<'a> {
+ Message(&'a DescriptorProto),
+ Enum(&'a EnumDescriptorProto),
+}
+
+impl<'a> MessageOrEnum<'a> {
+ fn from_two_options(
+ m: Option<&'a DescriptorProto>,
+ e: Option<&'a EnumDescriptorProto>,
+ ) -> MessageOrEnum<'a> {
+ match (m, e) {
+ (Some(_), Some(_)) => panic!("enum and message with the same name"),
+ (Some(m), None) => MessageOrEnum::Message(m),
+ (None, Some(e)) => MessageOrEnum::Enum(e),
+ (None, None) => panic!("not found"),
+ }
+ }
+}
+
+pub(crate) fn find_message_or_enum<'a>(
+ file: &'a FileDescriptorProto,
+ name_to_package: &str,
+) -> (String, MessageOrEnum<'a>) {
+ let mut path = name_to_package.split('.');
+ let first = path.next().unwrap();
+ let child_message = file
+ .get_message_type()
+ .iter()
+ .find(|m| m.get_name() == first);
+ let child_enum = file.get_enum_type().iter().find(|e| e.get_name() == first);
+
+ let mut package_to_name = String::new();
+ let mut me = MessageOrEnum::from_two_options(child_message, child_enum);
+
+ for name in path {
+ let message = match me {
+ MessageOrEnum::Message(m) => m,
+ MessageOrEnum::Enum(_) => panic!("enum has no children"),
+ };
+
+ if !package_to_name.is_empty() {
+ package_to_name.push_str(".");
+ }
+ package_to_name.push_str(message.get_name());
+
+ let child_message = message
+ .get_nested_type()
+ .iter()
+ .find(|m| m.get_name() == name);
+ let child_enum = message
+ .get_enum_type()
+ .iter()
+ .find(|e| e.get_name() == name);
+ me = MessageOrEnum::from_two_options(child_message, child_enum)
+ }
+
+ (package_to_name, me)
+}
diff --git a/src/reflect/map.rs b/src/reflect/map.rs
new file mode 100644
index 0000000..9f03123
--- /dev/null
+++ b/src/reflect/map.rs
@@ -0,0 +1,66 @@
+use std::collections::hash_map;
+use std::collections::HashMap;
+use std::hash::Hash;
+
+use super::value::ProtobufValue;
+
+/// Implemented for `HashMap` with appropriate keys and values
+pub trait ReflectMap: 'static {
+ fn reflect_iter(&self) -> ReflectMapIter;
+
+ fn len(&self) -> usize;
+}
+
+impl<K: ProtobufValue + Eq + Hash + 'static, V: ProtobufValue + 'static> ReflectMap
+ for HashMap<K, V>
+{
+ fn reflect_iter<'a>(&'a self) -> ReflectMapIter<'a> {
+ ReflectMapIter {
+ imp: Box::new(ReflectMapIterImpl::<'a, K, V> { iter: self.iter() }),
+ }
+ }
+
+ fn len(&self) -> usize {
+ HashMap::len(self)
+ }
+}
+
+trait ReflectMapIterTrait<'a> {
+ fn next(&mut self) -> Option<(&'a ProtobufValue, &'a ProtobufValue)>;
+}
+
+struct ReflectMapIterImpl<'a, K: Eq + Hash + 'static, V: 'static> {
+ iter: hash_map::Iter<'a, K, V>,
+}
+
+impl<'a, K: ProtobufValue + Eq + Hash + 'static, V: ProtobufValue + 'static> ReflectMapIterTrait<'a>
+ for ReflectMapIterImpl<'a, K, V>
+{
+ fn next(&mut self) -> Option<(&'a ProtobufValue, &'a ProtobufValue)> {
+ match self.iter.next() {
+ Some((k, v)) => Some((k as &ProtobufValue, v as &ProtobufValue)),
+ None => None,
+ }
+ }
+}
+
+pub struct ReflectMapIter<'a> {
+ imp: Box<ReflectMapIterTrait<'a> + 'a>,
+}
+
+impl<'a> Iterator for ReflectMapIter<'a> {
+ type Item = (&'a ProtobufValue, &'a ProtobufValue);
+
+ fn next(&mut self) -> Option<(&'a ProtobufValue, &'a ProtobufValue)> {
+ self.imp.next()
+ }
+}
+
+impl<'a> IntoIterator for &'a ReflectMap {
+ type IntoIter = ReflectMapIter<'a>;
+ type Item = (&'a ProtobufValue, &'a ProtobufValue);
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.reflect_iter()
+ }
+}
diff --git a/src/reflect/message.rs b/src/reflect/message.rs
new file mode 100644
index 0000000..c35a854
--- /dev/null
+++ b/src/reflect/message.rs
@@ -0,0 +1,223 @@
+use descriptor::{DescriptorProto, FileDescriptorProto};
+use descriptorx::find_message_by_rust_name;
+use reflect::accessor::FieldAccessor;
+use reflect::find_message_or_enum::find_message_or_enum;
+use reflect::find_message_or_enum::MessageOrEnum;
+use reflect::FieldDescriptor;
+use std::collections::HashMap;
+use std::marker;
+use Message;
+
+trait MessageFactory: Send + Sync + 'static {
+ fn new_instance(&self) -> Box<dyn Message>;
+}
+
+struct MessageFactoryImpl<M>(marker::PhantomData<M>);
+
+impl<M> MessageFactory for MessageFactoryImpl<M>
+where
+ M: 'static + Message + Default + Clone + PartialEq,
+{
+ fn new_instance(&self) -> Box<dyn Message> {
+ let m: M = Default::default();
+ Box::new(m)
+ }
+}
+
+/// Dynamic message type
+pub struct MessageDescriptor {
+ full_name: String,
+ proto: &'static DescriptorProto,
+ factory: &'static dyn MessageFactory,
+ fields: Vec<FieldDescriptor>,
+
+ index_by_name: HashMap<String, usize>,
+ index_by_number: HashMap<u32, usize>,
+}
+
+impl MessageDescriptor {
+ /// Get underlying `DescriptorProto` object.
+ pub fn get_proto(&self) -> &DescriptorProto {
+ self.proto
+ }
+
+ /// Get a message descriptor for given message type
+ pub fn for_type<M: Message>() -> &'static MessageDescriptor {
+ M::descriptor_static()
+ }
+
+ fn compute_full_name(package: &str, path_to_package: &str, proto: &DescriptorProto) -> String {
+ let mut full_name = package.to_owned();
+ if path_to_package.len() != 0 {
+ if full_name.len() != 0 {
+ full_name.push('.');
+ }
+ full_name.push_str(path_to_package);
+ }
+ if full_name.len() != 0 {
+ full_name.push('.');
+ }
+ full_name.push_str(proto.get_name());
+ full_name
+ }
+
+ // Non-generic part of `new` is a separate function
+ // to reduce code bloat from multiple instantiations.
+ fn new_non_generic_by_rust_name(
+ rust_name: &'static str,
+ fields: Vec<Box<FieldAccessor + 'static>>,
+ file: &'static FileDescriptorProto,
+ factory: &'static dyn MessageFactory,
+ ) -> MessageDescriptor {
+ let proto = find_message_by_rust_name(file, rust_name);
+
+ let mut field_proto_by_name = HashMap::new();
+ for field_proto in proto.message.get_field() {
+ field_proto_by_name.insert(field_proto.get_name(), field_proto);
+ }
+
+ let mut index_by_name = HashMap::new();
+ let mut index_by_number = HashMap::new();
+ for (i, f) in proto.message.get_field().iter().enumerate() {
+ index_by_number.insert(f.get_number() as u32, i);
+ index_by_name.insert(f.get_name().to_string(), i);
+ }
+
+ let mut full_name = file.get_package().to_string();
+ if full_name.len() > 0 {
+ full_name.push('.');
+ }
+ full_name.push_str(proto.message.get_name());
+
+ MessageDescriptor {
+ full_name: full_name,
+ proto: proto.message,
+ factory,
+ fields: fields
+ .into_iter()
+ .map(|f| {
+ let proto = *field_proto_by_name.get(&f.name_generic()).unwrap();
+ FieldDescriptor::new(f, proto)
+ })
+ .collect(),
+ index_by_name,
+ index_by_number,
+ }
+ }
+
+ // Non-generic part of `new` is a separate function
+ // to reduce code bloat from multiple instantiations.
+ fn new_non_generic_by_pb_name(
+ protobuf_name_to_package: &'static str,
+ fields: Vec<Box<FieldAccessor + 'static>>,
+ file_descriptor_proto: &'static FileDescriptorProto,
+ factory: &'static dyn MessageFactory,
+ ) -> MessageDescriptor {
+ let (path_to_package, proto) =
+ match find_message_or_enum(file_descriptor_proto, protobuf_name_to_package) {
+ (path_to_package, MessageOrEnum::Message(m)) => (path_to_package, m),
+ (_, MessageOrEnum::Enum(_)) => panic!("not a message"),
+ };
+
+ let mut field_proto_by_name = HashMap::new();
+ for field_proto in proto.get_field() {
+ field_proto_by_name.insert(field_proto.get_name(), field_proto);
+ }
+
+ let mut index_by_name = HashMap::new();
+ let mut index_by_number = HashMap::new();
+ for (i, f) in proto.get_field().iter().enumerate() {
+ index_by_number.insert(f.get_number() as u32, i);
+ index_by_name.insert(f.get_name().to_string(), i);
+ }
+
+ MessageDescriptor {
+ full_name: MessageDescriptor::compute_full_name(
+ file_descriptor_proto.get_package(),
+ &path_to_package,
+ &proto,
+ ),
+ proto,
+ factory,
+ fields: fields
+ .into_iter()
+ .map(|f| {
+ let proto = *field_proto_by_name.get(&f.name_generic()).unwrap();
+ FieldDescriptor::new(f, proto)
+ })
+ .collect(),
+ index_by_name,
+ index_by_number,
+ }
+ }
+
+ /// Construct a new message descriptor.
+ ///
+ /// This operation is called from generated code and rarely
+ /// need to be called directly.
+ #[doc(hidden)]
+ #[deprecated(
+ since = "2.12",
+ note = "Please regenerate .rs files from .proto files to use newer APIs"
+ )]
+ pub fn new<M: 'static + Message + Default + Clone + PartialEq>(
+ rust_name: &'static str,
+ fields: Vec<Box<FieldAccessor + 'static>>,
+ file: &'static FileDescriptorProto,
+ ) -> MessageDescriptor {
+ let factory = &MessageFactoryImpl(marker::PhantomData::<M>);
+ MessageDescriptor::new_non_generic_by_rust_name(rust_name, fields, file, factory)
+ }
+
+ /// Construct a new message descriptor.
+ ///
+ /// This operation is called from generated code and rarely
+ /// need to be called directly.
+ #[doc(hidden)]
+ pub fn new_pb_name<M: 'static + Message + Default + Clone + PartialEq>(
+ protobuf_name_to_package: &'static str,
+ fields: Vec<Box<FieldAccessor + 'static>>,
+ file_descriptor_proto: &'static FileDescriptorProto,
+ ) -> MessageDescriptor {
+ let factory = &MessageFactoryImpl(marker::PhantomData::<M>);
+ MessageDescriptor::new_non_generic_by_pb_name(
+ protobuf_name_to_package,
+ fields,
+ file_descriptor_proto,
+ factory,
+ )
+ }
+
+ /// New empty message
+ pub fn new_instance(&self) -> Box<dyn Message> {
+ self.factory.new_instance()
+ }
+
+ /// Protobuf message name
+ pub fn name(&self) -> &'static str {
+ self.proto.get_name()
+ }
+
+ /// Fully qualified protobuf message name
+ pub fn full_name(&self) -> &str {
+ &self.full_name[..]
+ }
+
+ /// Message field descriptors.
+ pub fn fields(&self) -> &[FieldDescriptor] {
+ &self.fields
+ }
+
+ /// Find field by name
+ pub fn field_by_name<'a>(&'a self, name: &str) -> &'a FieldDescriptor {
+ // TODO: clone is weird
+ let &index = self.index_by_name.get(&name.to_string()).unwrap();
+ &self.fields[index]
+ }
+
+ /// Find field by number
+ pub fn field_by_number<'a>(&'a self, number: u32) -> &'a FieldDescriptor {
+ let &index = self.index_by_number.get(&number).unwrap();
+ &self.fields[index]
+ }
+}
diff --git a/src/reflect/mod.rs b/src/reflect/mod.rs
new file mode 100644
index 0000000..ede3743
--- /dev/null
+++ b/src/reflect/mod.rs
@@ -0,0 +1,27 @@
+//! Reflection implementation for protobuf types.
+
+use core::Message;
+
+pub mod accessor;
+mod enums;
+mod field;
+mod find_message_or_enum;
+mod map;
+mod message;
+mod optional;
+mod repeated;
+mod value;
+
+pub use self::value::ProtobufValue;
+pub use self::value::ReflectValueRef;
+#[doc(hidden)]
+#[deprecated(since = "2.11", note = "Use ReflectValueRef instead")]
+pub use self::value::ReflectValueRef as ProtobufValueRef;
+
+pub use self::enums::EnumDescriptor;
+pub use self::enums::EnumValueDescriptor;
+
+pub use self::message::MessageDescriptor;
+
+pub use self::field::FieldDescriptor;
+pub use self::field::ReflectFieldRef;
diff --git a/src/reflect/optional.rs b/src/reflect/optional.rs
new file mode 100644
index 0000000..4d33752
--- /dev/null
+++ b/src/reflect/optional.rs
@@ -0,0 +1,50 @@
+use std::mem;
+
+use super::value::ProtobufValue;
+
+use singular::*;
+
+pub trait ReflectOptional: 'static {
+ fn to_option(&self) -> Option<&ProtobufValue>;
+
+ fn set_value(&mut self, value: &ProtobufValue);
+}
+
+impl<V: ProtobufValue + Clone + 'static> ReflectOptional for Option<V> {
+ fn to_option(&self) -> Option<&ProtobufValue> {
+ self.as_ref().map(|v| v as &ProtobufValue)
+ }
+
+ fn set_value(&mut self, value: &ProtobufValue) {
+ match value.as_any().downcast_ref::<V>() {
+ Some(v) => mem::replace(self, Some(v.clone())),
+ None => panic!(),
+ };
+ }
+}
+
+impl<V: ProtobufValue + Clone + 'static> ReflectOptional for SingularField<V> {
+ fn to_option(&self) -> Option<&ProtobufValue> {
+ self.as_ref().map(|v| v as &ProtobufValue)
+ }
+
+ fn set_value(&mut self, value: &ProtobufValue) {
+ match value.as_any().downcast_ref::<V>() {
+ Some(v) => mem::replace(self, SingularField::some(v.clone())),
+ None => panic!(),
+ };
+ }
+}
+
+impl<V: ProtobufValue + Clone + 'static> ReflectOptional for SingularPtrField<V> {
+ fn to_option(&self) -> Option<&ProtobufValue> {
+ self.as_ref().map(|v| v as &ProtobufValue)
+ }
+
+ fn set_value(&mut self, value: &ProtobufValue) {
+ match value.as_any().downcast_ref::<V>() {
+ Some(v) => mem::replace(self, SingularPtrField::some(v.clone())),
+ None => panic!(),
+ };
+ }
+}
diff --git a/src/reflect/repeated.rs b/src/reflect/repeated.rs
new file mode 100644
index 0000000..7ffc979
--- /dev/null
+++ b/src/reflect/repeated.rs
@@ -0,0 +1,192 @@
+use std::slice;
+
+use super::value::ProtobufValue;
+use super::value::ReflectValueRef;
+
+use repeated::RepeatedField;
+
+pub trait ReflectRepeated: 'static {
+ fn reflect_iter(&self) -> ReflectRepeatedIter;
+ fn len(&self) -> usize;
+ fn get(&self, index: usize) -> &ProtobufValue;
+}
+
+impl<V: ProtobufValue + 'static> ReflectRepeated for Vec<V> {
+ fn reflect_iter<'a>(&'a self) -> ReflectRepeatedIter<'a> {
+ ReflectRepeatedIter {
+ imp: Box::new(ReflectRepeatedIterImplSlice::<'a, V> { iter: self.iter() }),
+ }
+ }
+
+ fn len(&self) -> usize {
+ Vec::len(self)
+ }
+
+ fn get(&self, index: usize) -> &ProtobufValue {
+ &self[index]
+ }
+}
+
+// useless
+impl<V: ProtobufValue + 'static> ReflectRepeated for [V] {
+ fn reflect_iter<'a>(&'a self) -> ReflectRepeatedIter<'a> {
+ ReflectRepeatedIter {
+ imp: Box::new(ReflectRepeatedIterImplSlice::<'a, V> { iter: self.iter() }),
+ }
+ }
+
+ fn len(&self) -> usize {
+ <[_]>::len(self)
+ }
+
+ fn get(&self, index: usize) -> &ProtobufValue {
+ &self[index]
+ }
+}
+
+impl<V: ProtobufValue + 'static> ReflectRepeated for RepeatedField<V> {
+ fn reflect_iter<'a>(&'a self) -> ReflectRepeatedIter<'a> {
+ ReflectRepeatedIter {
+ imp: Box::new(ReflectRepeatedIterImplSlice::<'a, V> { iter: self.iter() }),
+ }
+ }
+
+ fn len(&self) -> usize {
+ RepeatedField::len(self)
+ }
+
+ fn get(&self, index: usize) -> &ProtobufValue {
+ &self[index]
+ }
+}
+
+trait ReflectRepeatedIterTrait<'a> {
+ fn next(&mut self) -> Option<&'a ProtobufValue>;
+}
+
+struct ReflectRepeatedIterImplSlice<'a, V: ProtobufValue + 'static> {
+ iter: slice::Iter<'a, V>,
+}
+
+impl<'a, V: ProtobufValue + 'static> ReflectRepeatedIterTrait<'a>
+ for ReflectRepeatedIterImplSlice<'a, V>
+{
+ fn next(&mut self) -> Option<&'a ProtobufValue> {
+ self.iter.next().map(|v| v as &ProtobufValue)
+ }
+}
+
+pub struct ReflectRepeatedIter<'a> {
+ imp: Box<ReflectRepeatedIterTrait<'a> + 'a>,
+}
+
+impl<'a> Iterator for ReflectRepeatedIter<'a> {
+ type Item = &'a ProtobufValue;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.imp.next()
+ }
+}
+
+impl<'a> IntoIterator for &'a ReflectRepeated {
+ type IntoIter = ReflectRepeatedIter<'a>;
+ type Item = &'a ProtobufValue;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.reflect_iter()
+ }
+}
+
+pub trait ReflectRepeatedEnum<'a> {
+ fn len(&self) -> usize;
+
+ fn get(&self, index: usize) -> ReflectValueRef<'a>;
+}
+
+pub trait ReflectRepeatedMessage<'a> {
+ fn len(&self) -> usize;
+
+ fn get(&self, index: usize) -> ReflectValueRef<'a>;
+}
+
+pub enum ReflectRepeatedRef<'a> {
+ Generic(&'a ReflectRepeated),
+ U32(&'a [u32]),
+ U64(&'a [u64]),
+ I32(&'a [i32]),
+ I64(&'a [i64]),
+ F32(&'a [f32]),
+ F64(&'a [f64]),
+ Bool(&'a [bool]),
+ String(&'a [String]),
+ Bytes(&'a [Vec<u8>]),
+ Enum(Box<ReflectRepeatedEnum<'a> + 'a>),
+ Message(Box<ReflectRepeatedMessage<'a> + 'a>),
+}
+
+impl<'a> ReflectRepeatedRef<'a> {
+ fn len(&self) -> usize {
+ match *self {
+ ReflectRepeatedRef::Generic(ref r) => r.len(),
+ ReflectRepeatedRef::U32(ref r) => r.len(),
+ ReflectRepeatedRef::U64(ref r) => r.len(),
+ ReflectRepeatedRef::I32(ref r) => r.len(),
+ ReflectRepeatedRef::I64(ref r) => r.len(),
+ ReflectRepeatedRef::F32(ref r) => r.len(),
+ ReflectRepeatedRef::F64(ref r) => r.len(),
+ ReflectRepeatedRef::Bool(ref r) => r.len(),
+ ReflectRepeatedRef::String(ref r) => r.len(),
+ ReflectRepeatedRef::Bytes(ref r) => r.len(),
+ ReflectRepeatedRef::Enum(ref r) => r.len(),
+ ReflectRepeatedRef::Message(ref r) => r.len(),
+ }
+ }
+
+ fn get(&self, index: usize) -> ReflectValueRef<'a> {
+ match *self {
+ ReflectRepeatedRef::Generic(ref r) => r.get(index).as_ref(),
+ ReflectRepeatedRef::U32(ref r) => ReflectValueRef::U32(r[index]),
+ ReflectRepeatedRef::U64(ref r) => ReflectValueRef::U64(r[index]),
+ ReflectRepeatedRef::I32(ref r) => ReflectValueRef::I32(r[index]),
+ ReflectRepeatedRef::I64(ref r) => ReflectValueRef::I64(r[index]),
+ ReflectRepeatedRef::F32(ref r) => ReflectValueRef::F32(r[index]),
+ ReflectRepeatedRef::F64(ref r) => ReflectValueRef::F64(r[index]),
+ ReflectRepeatedRef::Bool(ref r) => ReflectValueRef::Bool(r[index]),
+ ReflectRepeatedRef::String(ref r) => ReflectValueRef::String(&r[index]),
+ ReflectRepeatedRef::Bytes(ref r) => ReflectValueRef::Bytes(&r[index]),
+ ReflectRepeatedRef::Enum(ref r) => r.get(index),
+ ReflectRepeatedRef::Message(ref r) => r.get(index),
+ }
+ }
+}
+
+pub struct ReflectRepeatedRefIter<'a> {
+ repeated: &'a ReflectRepeatedRef<'a>,
+ pos: usize,
+}
+
+impl<'a> Iterator for ReflectRepeatedRefIter<'a> {
+ type Item = ReflectValueRef<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.pos < self.repeated.len() {
+ let pos = self.pos;
+ self.pos += 1;
+ Some(self.repeated.get(pos))
+ } else {
+ None
+ }
+ }
+}
+
+impl<'a> IntoIterator for &'a ReflectRepeatedRef<'a> {
+ type IntoIter = ReflectRepeatedRefIter<'a>;
+ type Item = ReflectValueRef<'a>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ ReflectRepeatedRefIter {
+ repeated: self,
+ pos: 0,
+ }
+ }
+}
diff --git a/src/reflect/value.rs b/src/reflect/value.rs
new file mode 100644
index 0000000..22f76af
--- /dev/null
+++ b/src/reflect/value.rs
@@ -0,0 +1,185 @@
+use std::any::Any;
+
+#[cfg(feature = "bytes")]
+use bytes::Bytes;
+#[cfg(feature = "bytes")]
+use chars::Chars;
+
+use super::*;
+
+/// Type implemented by all protobuf elementary types
+/// (ints, floats, bool, string, bytes, enums, messages).
+pub trait ProtobufValue: Any + 'static {
+ /// As ref
+ fn as_ref(&self) -> ReflectValueRef;
+
+ /// Convert to `Any`
+ fn as_any(&self) -> &Any {
+ unimplemented!()
+ }
+
+ /// Is value non-zero?
+ fn is_non_zero(&self) -> bool {
+ self.as_ref().is_non_zero()
+ }
+
+ /// Return `ProtobufValueRef` if self is `Copy`.
+ ///
+ /// # Panics
+ ///
+ /// if `Self` is not `Copy`.
+ fn as_ref_copy(&self) -> ReflectValueRef<'static>
+//where Self : Copy // TODO
+ {
+ match self.as_ref() {
+ ReflectValueRef::Bool(v) => ReflectValueRef::Bool(v),
+ ReflectValueRef::U32(v) => ReflectValueRef::U32(v),
+ ReflectValueRef::U64(v) => ReflectValueRef::U64(v),
+ ReflectValueRef::I32(v) => ReflectValueRef::I32(v),
+ ReflectValueRef::I64(v) => ReflectValueRef::I64(v),
+ ReflectValueRef::F32(v) => ReflectValueRef::F32(v),
+ ReflectValueRef::F64(v) => ReflectValueRef::F64(v),
+ ReflectValueRef::Enum(v) => ReflectValueRef::Enum(v),
+ ReflectValueRef::String(..)
+ | ReflectValueRef::Bytes(..)
+ | ReflectValueRef::Message(..) => unreachable!(),
+ }
+ }
+}
+
+impl ProtobufValue for u32 {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::U32(*self)
+ }
+}
+
+impl ProtobufValue for u64 {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::U64(*self)
+ }
+}
+
+impl ProtobufValue for i32 {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::I32(*self)
+ }
+}
+
+impl ProtobufValue for i64 {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::I64(*self)
+ }
+}
+
+impl ProtobufValue for f32 {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::F32(*self)
+ }
+}
+
+impl ProtobufValue for f64 {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::F64(*self)
+ }
+}
+
+impl ProtobufValue for bool {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::Bool(*self)
+ }
+}
+
+impl ProtobufValue for String {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::String(*&self)
+ }
+}
+
+impl ProtobufValue for str {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::String(self)
+ }
+}
+
+impl ProtobufValue for Vec<u8> {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::Bytes(*&self)
+ }
+}
+
+#[cfg(feature = "bytes")]
+impl ProtobufValue for Bytes {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::Bytes(&*self)
+ }
+}
+
+#[cfg(feature = "bytes")]
+impl ProtobufValue for Chars {
+ fn as_ref(&self) -> ReflectValueRef {
+ ReflectValueRef::String(&*self)
+ }
+}
+
+// conflicting implementations, so generated code is used instead
+/*
+impl<E : ProtobufEnum> ProtobufValue for E {
+ fn as_ref(&self) -> ProtobufValueRef {
+ ProtobufValueRef::Enum(self.descriptor())
+ }
+}
+
+impl<M : Message> ProtobufValue for M {
+ fn as_ref(&self) -> ProtobufValueRef {
+ ProtobufValueRef::Message(self)
+ }
+}
+*/
+
+/// A reference to a value
+#[derive(Debug)]
+pub enum ReflectValueRef<'a> {
+ /// `u32`
+ U32(u32),
+ /// `u64`
+ U64(u64),
+ /// `i32`
+ I32(i32),
+ /// `i64`
+ I64(i64),
+ /// `f32`
+ F32(f32),
+ /// `f64`
+ F64(f64),
+ /// `bool`
+ Bool(bool),
+ /// `string`
+ String(&'a str),
+ /// `bytes`
+ Bytes(&'a [u8]),
+ /// `enum`
+ // TODO: change to (i32, EnumDescriptor)
+ Enum(&'static EnumValueDescriptor),
+ /// `message`
+ Message(&'a dyn Message),
+}
+
+impl<'a> ReflectValueRef<'a> {
+ /// Value is "non-zero"?
+ #[doc(hidden)]
+ pub fn is_non_zero(&self) -> bool {
+ match *self {
+ ReflectValueRef::U32(v) => v != 0,
+ ReflectValueRef::U64(v) => v != 0,
+ ReflectValueRef::I32(v) => v != 0,
+ ReflectValueRef::I64(v) => v != 0,
+ ReflectValueRef::F32(v) => v != 0.,
+ ReflectValueRef::F64(v) => v != 0.,
+ ReflectValueRef::Bool(v) => v,
+ ReflectValueRef::String(v) => !v.is_empty(),
+ ReflectValueRef::Bytes(v) => !v.is_empty(),
+ ReflectValueRef::Enum(v) => v.value() != 0,
+ ReflectValueRef::Message(_) => true,
+ }
+ }
+}