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}