protobuf/reflect/field/
index.rs

1use protobuf_support::json_name::json_name;
2
3use crate::descriptor::field_descriptor_proto::Type;
4use crate::descriptor::FieldDescriptorProto;
5use crate::descriptor::FileDescriptorProto;
6use crate::owning_ref::OwningRef;
7use crate::reflect::error::ReflectError;
8use crate::reflect::field::protobuf_field_type::ProtobufFieldType;
9use crate::reflect::file::building::FileDescriptorBuilding;
10use crate::reflect::protobuf_type_box::ProtobufType;
11use crate::reflect::EnumDescriptor;
12use crate::reflect::EnumValueDescriptor;
13use crate::reflect::FieldDescriptor;
14use crate::reflect::FileDescriptor;
15use crate::reflect::MessageDescriptor;
16use crate::reflect::ReflectValueBox;
17use crate::reflect::ReflectValueRef;
18use crate::reflect::RuntimeType;
19
20#[derive(Debug)]
21pub(crate) enum ForwardProtobufTypeBox {
22    ProtobufTypeBox(ProtobufType),
23    CurrentFileEnum(usize),
24    CurrentFileMessage(usize),
25}
26
27impl ForwardProtobufTypeBox {
28    pub(crate) fn message(message: MessageDescriptor) -> ForwardProtobufTypeBox {
29        ForwardProtobufTypeBox::ProtobufTypeBox(ProtobufType::message(message))
30    }
31
32    pub(crate) fn enumeration(enumeration: EnumDescriptor) -> ForwardProtobufTypeBox {
33        ForwardProtobufTypeBox::ProtobufTypeBox(ProtobufType::enumeration(enumeration))
34    }
35
36    pub(crate) fn from_proto_type(t: Type) -> ForwardProtobufTypeBox {
37        ForwardProtobufTypeBox::ProtobufTypeBox(ProtobufType::from_proto_type(t))
38    }
39
40    pub(crate) fn resolve(&self, file: &FileDescriptor) -> ProtobufType {
41        match self {
42            ForwardProtobufTypeBox::ProtobufTypeBox(t) => t.clone(),
43            ForwardProtobufTypeBox::CurrentFileMessage(m) => {
44                ProtobufType::message(MessageDescriptor::new(file.clone(), *m))
45            }
46            ForwardProtobufTypeBox::CurrentFileEnum(m) => {
47                ProtobufType::enumeration(EnumDescriptor::new(file.clone(), *m))
48            }
49        }
50    }
51
52    pub(crate) fn resolve_message(&self, file: &FileDescriptor) -> MessageDescriptor {
53        match self.resolve(file).runtime() {
54            RuntimeType::Message(m) => m.clone(),
55            _ => panic!("not message"),
56        }
57    }
58}
59
60#[derive(Debug)]
61pub(crate) enum ForwardProtobufFieldType {
62    Singular(ForwardProtobufTypeBox),
63    Repeated(ForwardProtobufTypeBox),
64    Map(ForwardProtobufTypeBox, ForwardProtobufTypeBox),
65}
66
67impl ForwardProtobufFieldType {
68    pub(crate) fn resolve(&self, file: &FileDescriptor) -> ProtobufFieldType {
69        match self {
70            ForwardProtobufFieldType::Singular(t) => ProtobufFieldType::Singular(t.resolve(file)),
71            ForwardProtobufFieldType::Repeated(t) => ProtobufFieldType::Repeated(t.resolve(file)),
72            ForwardProtobufFieldType::Map(k, v) => {
73                ProtobufFieldType::Map(k.resolve(file), v.resolve(file))
74            }
75        }
76    }
77}
78
79#[derive(Debug)]
80pub(crate) enum FieldDefaultValue {
81    ReflectValueBox(ReflectValueBox),
82    Enum(usize),
83}
84
85#[derive(Debug)]
86pub(crate) enum FieldKind {
87    MessageField(
88        /// Message index.
89        usize,
90    ),
91    Extension(
92        /// Message index or `None` for file.
93        Option<usize>,
94        ForwardProtobufTypeBox,
95    ),
96}
97
98#[derive(Debug)]
99pub(crate) struct FieldIndex {
100    pub(crate) proto: OwningRef<FileDescriptorProto, FieldDescriptorProto>,
101    pub(crate) kind: FieldKind,
102    pub(crate) json_name: String,
103    pub(crate) field_type: ForwardProtobufFieldType,
104    pub(crate) default_value: Option<FieldDefaultValue>,
105}
106
107impl FieldIndex {
108    fn enum_default_value(
109        field: &FieldDescriptorProto,
110        building: &FileDescriptorBuilding,
111    ) -> crate::Result<FieldDefaultValue> {
112        let en = building.find_enum(field.type_name());
113        let (n, _) = match en
114            .value
115            .iter()
116            .enumerate()
117            .find(|(_n, v)| v.name() == field.default_value())
118        {
119            Some(v) => v,
120            None => Err(ReflectError::CouldNotParseDefaultValueForField(
121                field.name().to_owned(),
122            ))?,
123        };
124        Ok(FieldDefaultValue::Enum(n))
125    }
126
127    fn parse_default_value(
128        field: &FieldDescriptorProto,
129        building: &FileDescriptorBuilding,
130    ) -> crate::Result<FieldDefaultValue> {
131        Ok(FieldDefaultValue::ReflectValueBox(match field.type_() {
132            Type::TYPE_GROUP | Type::TYPE_MESSAGE => {
133                return Err(ReflectError::CouldNotParseDefaultValueForField(
134                    field.name().to_owned(),
135                )
136                .into());
137            }
138            Type::TYPE_ENUM => {
139                return Self::enum_default_value(field, building);
140            }
141            t => RuntimeType::from_proto_type(t)
142                .parse_proto_default_value(field.default_value())
143                .map_err(|()| {
144                    ReflectError::CouldNotParseDefaultValueForField(field.name().to_owned())
145                })?,
146        }))
147    }
148
149    pub(crate) fn index(
150        containing_message: Option<usize>,
151        field: OwningRef<FileDescriptorProto, FieldDescriptorProto>,
152        building: &FileDescriptorBuilding,
153    ) -> crate::Result<FieldIndex> {
154        let default_value = if field.has_default_value() {
155            Some(Self::parse_default_value(&field, building)?)
156        } else {
157            None
158        };
159
160        let json_name = if !field.json_name().is_empty() {
161            field.json_name().to_owned()
162        } else {
163            json_name(field.name())
164        };
165
166        let extendee = if field.has_extendee() {
167            Some(building.resolve_message(field.extendee())?)
168        } else {
169            None
170        };
171
172        let kind = match (containing_message, extendee) {
173            (Some(m), None) => FieldKind::MessageField(m),
174            (m, Some(extendee)) => FieldKind::Extension(m, extendee),
175            (None, None) => panic!("field must be in a message or an extension"),
176        };
177
178        let field_type = building.resolve_field_type(&field)?;
179        Ok(FieldIndex {
180            proto: field,
181            kind,
182            default_value,
183            json_name,
184            field_type,
185        })
186    }
187
188    pub(crate) fn default_value<'a>(&'a self, field: &FieldDescriptor) -> ReflectValueRef<'a> {
189        match &self.default_value {
190            Some(FieldDefaultValue::ReflectValueBox(v)) => v.as_value_ref(),
191            Some(FieldDefaultValue::Enum(v)) => match field.singular_runtime_type() {
192                RuntimeType::Enum(e) => {
193                    let ev = EnumValueDescriptor::new(e.clone(), *v);
194                    ReflectValueRef::from(ev)
195                }
196                t => panic!("wrong type {:?} for default value enum", t),
197            },
198            None => field.singular_runtime_type().default_value_ref(),
199        }
200    }
201}