prost_reflect/descriptor/build/
options.rs

1use std::sync::Arc;
2
3use prost::{bytes::Bytes, Message};
4
5use crate::{
6    descriptor::{
7        build::{
8            join_path, resolve_name,
9            visit::{visit, Visitor},
10            DescriptorPoolOffsets, ResolveNameFilter,
11        },
12        error::{DescriptorErrorKind, Label},
13        tag,
14        types::{
15            uninterpreted_option, DescriptorProto, EnumDescriptorProto, EnumValueDescriptorProto,
16            FieldDescriptorProto, FileDescriptorProto, MethodDescriptorProto, OneofDescriptorProto,
17            Options, ServiceDescriptorProto, UninterpretedOption,
18        },
19        Definition, DefinitionKind, EnumIndex, EnumValueIndex, ExtensionIndex, FieldIndex,
20        FileIndex, MessageIndex, MethodIndex, OneofIndex, ServiceIndex, MAP_ENTRY_KEY_NUMBER,
21        MAP_ENTRY_VALUE_NUMBER,
22    },
23    dynamic::{fmt_string, FieldDescriptorLike},
24    Cardinality, DescriptorError, DescriptorPool, DynamicMessage, EnumDescriptor,
25    ExtensionDescriptor, MapKey, MessageDescriptor, ReflectMessage, Value,
26};
27
28impl DescriptorPool {
29    pub(super) fn resolve_options(
30        &mut self,
31        offsets: DescriptorPoolOffsets,
32        files: &[FileDescriptorProto],
33    ) -> Result<(), DescriptorError> {
34        debug_assert_eq!(Arc::strong_count(&self.inner), 1);
35        let mut visitor = OptionsVisitor {
36            pool: self,
37            errors: Vec::new(),
38            options: Vec::new(),
39            locations: Vec::new(),
40        };
41        visit(offsets, files, &mut visitor);
42
43        if !visitor.errors.is_empty() {
44            return Err(DescriptorError::new(visitor.errors));
45        }
46
47        debug_assert_eq!(Arc::strong_count(&visitor.pool.inner), 1);
48        let inner = Arc::get_mut(&mut visitor.pool.inner).unwrap();
49        for (file, path, encoded) in visitor.options {
50            let file = &mut inner.files[file as usize].raw;
51            set_file_option(file, &path, &encoded);
52        }
53
54        for (file, from, to) in visitor.locations {
55            let file = &mut inner.files[file as usize].raw;
56            if let Some(source_code_info) = &mut file.source_code_info {
57                for location in &mut source_code_info.location {
58                    if location.path.starts_with(&from) {
59                        location.path.splice(..from.len(), to.iter().copied());
60                    }
61                }
62            }
63        }
64
65        Ok(())
66    }
67}
68
69struct OptionsVisitor<'a> {
70    pool: &'a mut DescriptorPool,
71    errors: Vec<DescriptorErrorKind>,
72    options: Vec<(FileIndex, Box<[i32]>, Vec<u8>)>,
73    #[allow(clippy::type_complexity)]
74    locations: Vec<(FileIndex, Box<[i32]>, Box<[i32]>)>,
75}
76
77impl Visitor for OptionsVisitor<'_> {
78    fn visit_file(&mut self, path: &[i32], index: FileIndex, file: &FileDescriptorProto) {
79        if let Some(options) = &file.options {
80            let path = join_path(path, &[tag::file::OPTIONS]);
81            let encoded = self.resolve_options(
82                "google.protobuf.FileOptions",
83                options,
84                &options.value.uninterpreted_option,
85                file.package(),
86                index,
87                &path,
88            );
89            self.options.push((index, path, encoded));
90        }
91    }
92
93    fn visit_message(
94        &mut self,
95        path: &[i32],
96        full_name: &str,
97        file: FileIndex,
98        _: Option<MessageIndex>,
99        _: MessageIndex,
100        message: &DescriptorProto,
101    ) {
102        if let Some(options) = &message.options {
103            let path = join_path(path, &[tag::message::OPTIONS]);
104            let encoded = self.resolve_options(
105                "google.protobuf.MessageOptions",
106                options,
107                &options.value.uninterpreted_option,
108                full_name,
109                file,
110                &path,
111            );
112            self.options.push((file, path, encoded));
113        }
114
115        for (i, extension_range) in message.extension_range.iter().enumerate() {
116            let path = join_path(
117                path,
118                &[
119                    tag::message::EXTENSION_RANGE,
120                    i as i32,
121                    tag::message::extension_range::OPTIONS,
122                ],
123            );
124            if let Some(options) = &extension_range.options {
125                let encoded = self.resolve_options(
126                    "google.protobuf.ExtensionRangeOptions",
127                    options,
128                    &options.value.uninterpreted_option,
129                    full_name,
130                    file,
131                    &path,
132                );
133                self.options.push((file, path, encoded));
134            }
135        }
136    }
137
138    fn visit_field(
139        &mut self,
140        path: &[i32],
141        full_name: &str,
142        file: FileIndex,
143        _: MessageIndex,
144        _: FieldIndex,
145        field: &FieldDescriptorProto,
146    ) {
147        if let Some(options) = &field.options {
148            let path = join_path(path, &[tag::field::OPTIONS]);
149            let encoded = self.resolve_options(
150                "google.protobuf.FieldOptions",
151                options,
152                &options.value.uninterpreted_option,
153                full_name,
154                file,
155                &path,
156            );
157            self.options.push((file, path, encoded));
158        }
159    }
160
161    fn visit_oneof(
162        &mut self,
163        path: &[i32],
164        full_name: &str,
165        file: FileIndex,
166        _: MessageIndex,
167        _: OneofIndex,
168        oneof: &OneofDescriptorProto,
169    ) {
170        if let Some(options) = &oneof.options {
171            let path = join_path(path, &[tag::oneof::OPTIONS]);
172            let encoded = self.resolve_options(
173                "google.protobuf.OneofOptions",
174                options,
175                &options.value.uninterpreted_option,
176                full_name,
177                file,
178                &path,
179            );
180            self.options.push((file, path, encoded));
181        }
182    }
183
184    fn visit_service(
185        &mut self,
186        path: &[i32],
187        full_name: &str,
188        file: FileIndex,
189        _: ServiceIndex,
190        service: &ServiceDescriptorProto,
191    ) {
192        if let Some(options) = &service.options {
193            let path = join_path(path, &[tag::service::OPTIONS]);
194            let encoded = self.resolve_options(
195                "google.protobuf.ServiceOptions",
196                options,
197                &options.value.uninterpreted_option,
198                full_name,
199                file,
200                &path,
201            );
202            self.options.push((file, path, encoded));
203        }
204    }
205
206    fn visit_method(
207        &mut self,
208        path: &[i32],
209        full_name: &str,
210        file: FileIndex,
211        _: ServiceIndex,
212        _: MethodIndex,
213        method: &MethodDescriptorProto,
214    ) {
215        if let Some(options) = &method.options {
216            let path = join_path(path, &[tag::method::OPTIONS]);
217            let encoded = self.resolve_options(
218                "google.protobuf.MethodOptions",
219                options,
220                &options.value.uninterpreted_option,
221                full_name,
222                file,
223                &path,
224            );
225            self.options.push((file, path, encoded));
226        }
227    }
228
229    fn visit_enum(
230        &mut self,
231        path: &[i32],
232        full_name: &str,
233        file: FileIndex,
234        _: Option<MessageIndex>,
235        _: EnumIndex,
236        enum_: &EnumDescriptorProto,
237    ) {
238        if let Some(options) = &enum_.options {
239            let path = join_path(path, &[tag::enum_::OPTIONS]);
240            let encoded = self.resolve_options(
241                "google.protobuf.EnumOptions",
242                options,
243                &options.value.uninterpreted_option,
244                full_name,
245                file,
246                &path,
247            );
248            self.options.push((file, path, encoded));
249        }
250    }
251
252    fn visit_enum_value(
253        &mut self,
254        path: &[i32],
255        full_name: &str,
256        file: FileIndex,
257        _: EnumIndex,
258        _: EnumValueIndex,
259        value: &EnumValueDescriptorProto,
260    ) {
261        if let Some(options) = &value.options {
262            let path = join_path(path, &[tag::enum_value::OPTIONS]);
263            let encoded = self.resolve_options(
264                "google.protobuf.EnumValueOptions",
265                options,
266                &options.value.uninterpreted_option,
267                full_name,
268                file,
269                &path,
270            );
271            self.options.push((file, path, encoded));
272        }
273    }
274
275    fn visit_extension(
276        &mut self,
277        path: &[i32],
278        full_name: &str,
279        file: FileIndex,
280        _: Option<MessageIndex>,
281        _: ExtensionIndex,
282        extension: &FieldDescriptorProto,
283    ) {
284        if let Some(options) = &extension.options {
285            let path = join_path(path, &[tag::field::OPTIONS]);
286            let encoded = self.resolve_options(
287                "google.protobuf.FieldOptions",
288                options,
289                &options.value.uninterpreted_option,
290                full_name,
291                file,
292                &path,
293            );
294            self.options.push((file, path, encoded));
295        }
296    }
297}
298
299impl OptionsVisitor<'_> {
300    fn resolve_options<T>(
301        &mut self,
302        desc_name: &str,
303        options: &Options<T>,
304        uninterpreted: &[UninterpretedOption],
305        scope: &str,
306        file: FileIndex,
307        path: &[i32],
308    ) -> Vec<u8> {
309        let desc = self.pool.get_message_by_name(desc_name).unwrap_or_else(|| {
310            DescriptorPool::global()
311                .get_message_by_name(desc_name)
312                .unwrap()
313        });
314
315        let mut message = match DynamicMessage::decode(desc, options.encoded.as_slice()) {
316            Ok(message) => message,
317            Err(err) => {
318                self.errors
319                    .push(DescriptorErrorKind::DecodeFileDescriptorSet { err });
320                return Vec::new();
321            }
322        };
323
324        for (i, option) in uninterpreted.iter().enumerate() {
325            if let Err(err) = self.set_option(
326                &mut message,
327                option,
328                scope,
329                file,
330                join_path(path, &[tag::UNINTERPRETED_OPTION, i as i32]),
331            ) {
332                self.errors.push(err);
333            }
334        }
335
336        message.clear_field_by_number(tag::UNINTERPRETED_OPTION as u32);
337
338        message.encode_to_vec()
339    }
340
341    #[allow(clippy::result_large_err)]
342    fn set_option(
343        &mut self,
344        mut message: &mut DynamicMessage,
345        option: &UninterpretedOption,
346        scope: &str,
347        file: FileIndex,
348        path: Box<[i32]>,
349    ) -> Result<(), DescriptorErrorKind> {
350        let mut resolved_path = Vec::with_capacity(path.len() - 2 + option.name.len());
351        resolved_path.extend_from_slice(&path[..path.len() - 2]);
352
353        for (i, part) in option.name.iter().enumerate() {
354            let is_last = i == option.name.len() - 1;
355
356            let desc = message.descriptor();
357            if part.is_extension {
358                let extension_desc =
359                    self.find_extension(scope, &part.name_part, file, &path, &desc)?;
360                resolved_path.push(extension_desc.number() as i32);
361
362                if is_last {
363                    if extension_desc.cardinality() != Cardinality::Repeated
364                        && message.has_extension(&extension_desc)
365                    {
366                        return Err(DescriptorErrorKind::DuplicateOption {
367                            name: fmt_option_name(&option.name),
368                            found: Label::new(&self.pool.inner.files, "found here", file, path),
369                        });
370                    } else {
371                        self.set_field_value(
372                            message.get_extension_mut(&extension_desc),
373                            &mut resolved_path,
374                            &extension_desc,
375                            option,
376                            file,
377                            &path,
378                        )?;
379                    }
380                } else if let Value::Message(submessage) =
381                    message.get_extension_mut(&extension_desc)
382                {
383                    message = submessage;
384                } else {
385                    return Err(DescriptorErrorKind::InvalidOptionType {
386                        name: fmt_option_name(&option.name[..i + 1]),
387                        ty: fmt_field_ty(&extension_desc),
388                        value: fmt_value(option),
389                        is_last,
390                        found: Label::new(&self.pool.inner.files, "found here", file, path),
391                    });
392                }
393            } else {
394                match desc.get_field_by_name(&part.name_part) {
395                    Some(field_desc) => {
396                        resolved_path.push(field_desc.number() as i32);
397
398                        if is_last {
399                            if field_desc.cardinality() != Cardinality::Repeated
400                                && message.has_field(&field_desc)
401                            {
402                                return Err(DescriptorErrorKind::DuplicateOption {
403                                    name: fmt_option_name(&option.name),
404                                    found: Label::new(
405                                        &self.pool.inner.files,
406                                        "found here",
407                                        file,
408                                        path,
409                                    ),
410                                });
411                            } else {
412                                self.set_field_value(
413                                    message.get_field_mut(&field_desc),
414                                    &mut resolved_path,
415                                    &field_desc,
416                                    option,
417                                    file,
418                                    &path,
419                                )?;
420                            }
421                        } else if let Value::Message(submessage) =
422                            message.get_field_mut(&field_desc)
423                        {
424                            message = submessage;
425                        } else {
426                            return Err(DescriptorErrorKind::InvalidOptionType {
427                                name: fmt_option_name(&option.name[..i + 1]),
428                                ty: fmt_field_ty(&field_desc),
429                                value: fmt_value(option),
430                                is_last,
431                                found: Label::new(&self.pool.inner.files, "found here", file, path),
432                            });
433                        }
434                    }
435                    None => {
436                        return Err(DescriptorErrorKind::OptionNotFound {
437                            name: fmt_option_name(&option.name[..i + 1]),
438                            found: Label::new(&self.pool.inner.files, "found here", file, path),
439                        })
440                    }
441                }
442            }
443        }
444
445        self.locations.push((file, path, resolved_path.into()));
446
447        Ok(())
448    }
449
450    #[allow(clippy::result_large_err)]
451    fn set_field_value(
452        &self,
453        value: &mut Value,
454        resolved_path: &mut Vec<i32>,
455        desc: &impl FieldDescriptorLike,
456        option: &UninterpretedOption,
457        file: FileIndex,
458        path: &[i32],
459    ) -> Result<(), DescriptorErrorKind> {
460        let err = |()| DescriptorErrorKind::InvalidOptionType {
461            name: fmt_option_name(&option.name),
462            ty: fmt_field_ty(desc),
463            value: fmt_value(option),
464            is_last: true,
465            found: Label::new(&self.pool.inner.files, "found here", file, path.into()),
466        };
467
468        let parse_err = |parse_err| match parse_err {
469            #[cfg(feature = "text-format")]
470            Some(parse_err) => DescriptorErrorKind::InvalidMessageOption {
471                name: fmt_option_name(&option.name),
472                ty: fmt_field_ty(desc),
473                found: Label::new(&self.pool.inner.files, "found here", file, path.into()),
474                err: parse_err,
475            },
476            _ => err(()),
477        };
478
479        match value {
480            Value::Bool(value) => *value = option_to_bool(option).map_err(err)?,
481            Value::I32(value) => *value = option_to_int(option).map_err(err)?,
482            Value::I64(value) => *value = option_to_int(option).map_err(err)?,
483            Value::U32(value) => *value = option_to_int(option).map_err(err)?,
484            Value::U64(value) => *value = option_to_int(option).map_err(err)?,
485            Value::F32(value) => *value = option_to_float(option).map_err(err)? as f32,
486            Value::F64(value) => *value = option_to_float(option).map_err(err)?,
487            Value::String(value) => *value = option_to_string(option).map_err(err)?,
488            Value::Bytes(value) => *value = option_to_bytes(option).map_err(err)?,
489            Value::EnumNumber(value) => {
490                *value = option_to_enum(option, desc.kind().as_enum().unwrap()).map_err(err)?
491            }
492            Value::Message(value) => {
493                *value = option_to_message(option, desc.kind().as_message().unwrap())
494                    .map_err(parse_err)?
495            }
496            Value::List(value) => {
497                resolved_path.push(value.len() as i32);
498
499                let mut entry = Value::default_value(&desc.kind());
500                self.set_field_value(&mut entry, resolved_path, desc, option, file, path)?;
501                value.push(entry);
502            }
503            Value::Map(value) => {
504                let (entry_key, entry_value) =
505                    option_to_map_entry(option, desc.kind().as_message().unwrap())
506                        .map_err(parse_err)?;
507                value.insert(entry_key, entry_value);
508            }
509        }
510
511        Ok(())
512    }
513
514    #[allow(clippy::result_large_err)]
515    fn find_extension(
516        &self,
517        scope: &str,
518        name: &str,
519        file: FileIndex,
520        path: &[i32],
521        extendee: &MessageDescriptor,
522    ) -> Result<ExtensionDescriptor, DescriptorErrorKind> {
523        let (_, def) = resolve_name(
524            &self.pool.inner.files[file as usize].transitive_dependencies,
525            &self.pool.inner.names,
526            scope,
527            name,
528            ResolveNameFilter::Extension,
529        )
530        .into_result(name, &self.pool.inner.files, file, path, &[])?;
531
532        let &Definition {
533            kind: DefinitionKind::Extension(index),
534            ..
535        } = def
536        else {
537            unreachable!()
538        };
539
540        let desc = ExtensionDescriptor {
541            pool: self.pool.clone(),
542            index,
543        };
544
545        if desc.containing_message() == *extendee {
546            Ok(desc)
547        } else {
548            Err(DescriptorErrorKind::InvalidOptionExtendee {
549                name: desc.full_name().to_owned(),
550                expected_extendee: extendee.full_name().to_owned(),
551                actual_extendee: desc.containing_message().full_name().to_owned(),
552                found: Label::new(&self.pool.inner.files, "found here", file, path.into()),
553            })
554        }
555    }
556}
557
558fn fmt_option_name(parts: &[uninterpreted_option::NamePart]) -> String {
559    let mut result = String::new();
560    for part in parts {
561        if !result.is_empty() {
562            result.push('.');
563        }
564        if part.is_extension {
565            result.push('(');
566            result.push_str(&part.name_part);
567            result.push(')');
568        } else {
569            result.push_str(&part.name_part);
570        }
571    }
572    result
573}
574
575pub(super) fn option_to_bool(option: &UninterpretedOption) -> Result<bool, ()> {
576    match option.identifier_value.as_deref() {
577        Some("true") => Ok(true),
578        Some("false") => Ok(false),
579        _ => Err(()),
580    }
581}
582
583pub(super) fn option_to_int<T>(option: &UninterpretedOption) -> Result<T, ()>
584where
585    T: TryFrom<u64> + TryFrom<i64>,
586{
587    if let Some(int) = option.positive_int_value {
588        int.try_into().map_err(drop)
589    } else if let Some(int) = option.negative_int_value {
590        int.try_into().map_err(drop)
591    } else {
592        Err(())
593    }
594}
595
596pub(super) fn option_to_float(option: &UninterpretedOption) -> Result<f64, ()> {
597    if let Some(float) = option.double_value {
598        Ok(float)
599    } else if let Some(int) = option.positive_int_value {
600        Ok(int as f64)
601    } else if let Some(int) = option.negative_int_value {
602        Ok(int as f64)
603    } else {
604        Err(())
605    }
606}
607
608pub(super) fn option_to_string(option: &UninterpretedOption) -> Result<String, ()> {
609    if let Some(bytes) = &option.string_value {
610        String::from_utf8(bytes.clone()).map_err(drop)
611    } else {
612        Err(())
613    }
614}
615
616pub(super) fn option_to_bytes(option: &UninterpretedOption) -> Result<Bytes, ()> {
617    if let Some(bytes) = &option.string_value {
618        Ok(Bytes::copy_from_slice(bytes))
619    } else {
620        Err(())
621    }
622}
623
624pub(super) fn option_to_enum(
625    option: &UninterpretedOption,
626    desc: &EnumDescriptor,
627) -> Result<i32, ()> {
628    if let Some(ident) = &option.identifier_value {
629        if let Some(value) = desc.get_value_by_name(ident) {
630            Ok(value.number())
631        } else {
632            Err(())
633        }
634    } else {
635        Err(())
636    }
637}
638
639#[cfg(feature = "text-format")]
640type ParseError = crate::text_format::ParseError;
641#[cfg(not(feature = "text-format"))]
642type ParseError = ();
643
644#[cfg(feature = "text-format")]
645pub(super) fn option_to_message(
646    option: &UninterpretedOption,
647    desc: &MessageDescriptor,
648) -> Result<DynamicMessage, Option<ParseError>> {
649    if let Some(text_format) = &option.aggregate_value {
650        DynamicMessage::parse_text_format(desc.clone(), text_format).map_err(Some)
651    } else {
652        Err(None)
653    }
654}
655
656#[cfg(not(feature = "text-format"))]
657pub(super) fn option_to_message(
658    option: &UninterpretedOption,
659    desc: &MessageDescriptor,
660) -> Result<DynamicMessage, Option<ParseError>> {
661    if option.aggregate_value.is_some() {
662        Ok(DynamicMessage::new(desc.clone()))
663    } else {
664        Err(None)
665    }
666}
667
668pub(super) fn option_to_map_entry(
669    option: &UninterpretedOption,
670    desc: &MessageDescriptor,
671) -> Result<(MapKey, Value), Option<ParseError>> {
672    debug_assert!(desc.is_map_entry());
673    let entry = option_to_message(option, desc)?;
674    let key = entry
675        .get_field_by_number(MAP_ENTRY_KEY_NUMBER)
676        .ok_or(None)?
677        .into_owned()
678        .into_map_key()
679        .ok_or(None)?;
680    let value = entry
681        .get_field_by_number(MAP_ENTRY_VALUE_NUMBER)
682        .ok_or(None)?
683        .into_owned();
684    Ok((key, value))
685}
686
687fn fmt_field_ty(field: &impl FieldDescriptorLike) -> String {
688    if field.is_map() {
689        let entry = field.kind();
690        let entry = entry.as_message().unwrap();
691        format!(
692            "map<{:?}, {:?}>",
693            entry.map_entry_key_field().kind(),
694            entry.map_entry_value_field().kind()
695        )
696    } else if field.is_list() {
697        format!("repeated {:?}", field.kind())
698    } else {
699        format!("{:?}", field.kind())
700    }
701}
702
703fn fmt_value(option: &UninterpretedOption) -> String {
704    if let Some(value) = &option.identifier_value {
705        value.clone()
706    } else if let Some(value) = &option.positive_int_value {
707        value.to_string()
708    } else if let Some(value) = &option.negative_int_value {
709        value.to_string()
710    } else if let Some(value) = &option.double_value {
711        value.to_string()
712    } else if let Some(value) = &option.string_value {
713        let mut string = String::new();
714        fmt_string(&mut string, value).unwrap();
715        string
716    } else if let Some(value) = &option.aggregate_value {
717        value.clone()
718    } else {
719        String::new()
720    }
721}
722
723fn set_file_option(file: &mut FileDescriptorProto, path: &[i32], encoded: &[u8]) {
724    match path[0] {
725        tag::file::OPTIONS => {
726            debug_assert_eq!(path.len(), 1);
727            file.options = Some(Options::decode(encoded).unwrap());
728        }
729        tag::file::MESSAGE_TYPE => {
730            let message = &mut file.message_type[path[1] as usize];
731            set_message_option(message, &path[2..], encoded);
732        }
733        tag::file::ENUM_TYPE => {
734            let enum_ = &mut file.enum_type[path[1] as usize];
735            set_enum_option(enum_, &path[2..], encoded);
736        }
737        tag::file::SERVICE => {
738            let service = &mut file.service[path[1] as usize];
739            match path[2] {
740                tag::service::OPTIONS => service.options = Some(Options::decode(encoded).unwrap()),
741                tag::service::METHOD => {
742                    debug_assert_eq!(path.len(), 5);
743                    debug_assert_eq!(path[4], tag::method::OPTIONS);
744                    let value = &mut service.method[path[3] as usize];
745                    value.options = Some(Options::decode(encoded).unwrap());
746                }
747                p => panic!("unknown path element {}", p),
748            }
749        }
750        tag::file::EXTENSION => {
751            debug_assert_eq!(path.len(), 3);
752            debug_assert_eq!(path[2], tag::field::OPTIONS);
753            let field = &mut file.extension[path[1] as usize];
754            field.options = Some(Options::decode(encoded).unwrap());
755        }
756        p => panic!("unknown path element {}", p),
757    }
758}
759
760fn set_message_option(message: &mut DescriptorProto, path: &[i32], encoded: &[u8]) {
761    match path[0] {
762        tag::message::OPTIONS => {
763            debug_assert_eq!(path.len(), 1);
764            message.options = Some(Options::decode(encoded).unwrap());
765        }
766        tag::message::EXTENSION_RANGE => {
767            debug_assert_eq!(path.len(), 3);
768            debug_assert_eq!(path[2], tag::message::extension_range::OPTIONS);
769            let extension_range = &mut message.extension_range[path[1] as usize];
770            extension_range.options = Some(Options::decode(encoded).unwrap());
771        }
772        tag::message::FIELD => {
773            debug_assert_eq!(path.len(), 3);
774            debug_assert_eq!(path[2], tag::field::OPTIONS);
775            let field = &mut message.field[path[1] as usize];
776            field.options = Some(Options::decode(encoded).unwrap());
777        }
778        tag::message::ONEOF_DECL => {
779            debug_assert_eq!(path.len(), 3);
780            debug_assert_eq!(path[2], tag::oneof::OPTIONS);
781            let field = &mut message.oneof_decl[path[1] as usize];
782            field.options = Some(Options::decode(encoded).unwrap());
783        }
784        tag::message::NESTED_TYPE => {
785            let nested_message = &mut message.nested_type[path[1] as usize];
786            set_message_option(nested_message, &path[2..], encoded);
787        }
788        tag::message::ENUM_TYPE => {
789            let enum_ = &mut message.enum_type[path[1] as usize];
790            set_enum_option(enum_, &path[2..], encoded);
791        }
792        tag::message::EXTENSION => {
793            debug_assert_eq!(path.len(), 3);
794            debug_assert_eq!(path[2], tag::field::OPTIONS);
795            let field = &mut message.extension[path[1] as usize];
796            field.options = Some(Options::decode(encoded).unwrap());
797        }
798        p => panic!("unknown path element {}", p),
799    }
800}
801
802fn set_enum_option(enum_: &mut EnumDescriptorProto, path: &[i32], encoded: &[u8]) {
803    match path[0] {
804        tag::enum_::OPTIONS => enum_.options = Some(Options::decode(encoded).unwrap()),
805        tag::enum_::VALUE => {
806            debug_assert_eq!(path.len(), 3);
807            debug_assert_eq!(path[2], tag::enum_value::OPTIONS);
808            let value = &mut enum_.value[path[1] as usize];
809            value.options = Some(Options::decode(encoded).unwrap());
810        }
811        p => panic!("unknown path element {}", p),
812    }
813}