protofish/context/
builder.rs

1use std::borrow::Cow;
2use std::collections::BTreeMap;
3use std::path::PathBuf;
4
5use super::*;
6
7#[derive(Default)]
8pub(crate) struct ContextBuilder
9{
10    pub(crate) packages: Vec<PackageBuilder>,
11}
12
13#[derive(Default, Debug, PartialEq)]
14pub(crate) struct PackageBuilder
15{
16    pub(crate) path: PathBuf,
17    pub(crate) name: Option<String>,
18    pub(crate) imported_types: Vec<String>,
19    pub(crate) types: Vec<ProtobufItemBuilder>,
20}
21
22#[derive(Debug, PartialEq)]
23pub(crate) enum ProtobufItemBuilder
24{
25    Type(ProtobufTypeBuilder),
26    Service(ServiceBuilder),
27}
28
29#[derive(Debug, PartialEq)]
30pub(crate) enum ProtobufTypeBuilder
31{
32    Message(MessageBuilder),
33    Enum(EnumBuilder),
34}
35
36#[derive(Default, Debug, PartialEq, Clone)]
37pub(crate) struct MessageBuilder
38{
39    pub(crate) name: String,
40    pub(crate) fields: Vec<FieldBuilder>,
41    pub(crate) oneofs: Vec<OneofBuilder>,
42    pub(crate) inner_types: Vec<InnerTypeBuilder>,
43    pub(crate) options: Vec<ProtoOption>,
44}
45
46#[derive(Debug, PartialEq, Clone)]
47pub(crate) enum InnerTypeBuilder
48{
49    Message(MessageBuilder),
50    Enum(EnumBuilder),
51}
52
53#[derive(Default, Debug, PartialEq, Clone)]
54pub(crate) struct EnumBuilder
55{
56    pub(crate) name: String,
57    pub(crate) fields: Vec<EnumField>,
58    pub(crate) options: Vec<ProtoOption>,
59}
60
61#[derive(Default, Debug, PartialEq)]
62pub(crate) struct ServiceBuilder
63{
64    pub(crate) name: String,
65    pub(crate) rpcs: Vec<RpcBuilder>,
66    pub(crate) options: Vec<ProtoOption>,
67}
68
69#[derive(Debug, PartialEq, Clone)]
70pub(crate) struct FieldBuilder
71{
72    pub(crate) multiplicity: Multiplicity,
73    pub(crate) field_type: FieldTypeBuilder,
74    pub(crate) name: String,
75    pub(crate) number: u64,
76    pub(crate) options: Vec<ProtoOption>,
77}
78
79#[derive(Default, Debug, PartialEq, Clone)]
80pub(crate) struct OneofBuilder
81{
82    pub(crate) name: String,
83    pub(crate) fields: Vec<FieldBuilder>,
84    pub(crate) options: Vec<ProtoOption>,
85}
86
87#[derive(Debug, PartialEq, Clone)]
88pub(crate) enum FieldTypeBuilder
89{
90    Builtin(ValueType),
91    Unknown(String),
92}
93
94#[derive(Default, Debug, PartialEq)]
95pub(crate) struct RpcBuilder
96{
97    pub(crate) name: String,
98    pub(crate) input: RpcArgBuilder,
99    pub(crate) output: RpcArgBuilder,
100    pub(crate) options: Vec<ProtoOption>,
101}
102
103#[derive(Default, Debug, PartialEq)]
104pub(crate) struct RpcArgBuilder
105{
106    pub(crate) stream: bool,
107    pub(crate) message: String,
108}
109
110impl ContextBuilder
111{
112    pub fn build(mut self) -> Result<Context, ParseError>
113    {
114        let mut cache = BuildCache::default();
115        for (i, p) in self.packages.iter().enumerate() {
116            p.populate(&mut cache, &mut vec![i])?;
117        }
118
119        // Iterate the types through the cache, since the cache has enough
120        // details to find the original type, the types don't have details
121        // to find the cache data without re-building the full path.
122        let mut types = vec![];
123        for cache_data in &cache.types {
124            match cache_data.item_type {
125                ItemType::Message | ItemType::Enum => {
126                    let ty = self.take_type(&cache_data.idx_path);
127                    let mut t = ty.build(cache_data, &cache)?;
128                    match &mut t {
129                        TypeInfo::Message(m) => assert_eq!(m.self_ref.0 .0, types.len()),
130                        TypeInfo::Enum(e) => assert_eq!(e.self_ref.0 .0, types.len()),
131                    }
132                    types.push(t);
133                }
134                ItemType::Service => unreachable!("Service in type cache"),
135            }
136        }
137
138        let services: Vec<_> = cache
139            .services
140            .iter()
141            .map(|s| self.take_service(&s.idx_path).build(s, &cache))
142            .collect::<Result<_, _>>()?;
143
144        let types_by_name = types
145            .iter()
146            .enumerate()
147            .map(|(idx, t)| (t.full_name().to_string(), idx))
148            .collect();
149        let services_by_name = services
150            .iter()
151            .enumerate()
152            .map(|(idx, t)| (t.full_name.clone(), idx))
153            .collect();
154
155        let mut packages: Vec<Package> = self
156            .packages
157            .into_iter()
158            .enumerate()
159            .map(|(idx, p)| Package {
160                name: p.name,
161                self_ref: PackageRef(InternalRef(idx)),
162                types: Vec::new(),
163                services: Vec::new(),
164            })
165            .collect();
166
167        for s in &services {
168            let p = &mut packages[s.parent.0 .0];
169            p.services.push(s.self_ref.0 .0);
170        }
171
172        for t in &types {
173            let (raw_self_ref, parent) = match t {
174                TypeInfo::Message(m) => (TypeRef::Message(m.self_ref), &m.parent),
175                TypeInfo::Enum(e) => (TypeRef::Enum(e.self_ref), &e.parent),
176            };
177            match parent {
178                TypeParent::Package(p_ref) => {
179                    let p = &mut packages[p_ref.0 .0];
180                    p.types.push(raw_self_ref);
181                }
182                TypeParent::Message(_) => {
183                    // Messages handle their inner types on their own.
184                }
185            }
186        }
187
188        Ok(Context {
189            packages,
190            types,
191            types_by_name,
192            services,
193            services_by_name,
194        })
195    }
196
197    fn take_type(&mut self, idx: &[usize]) -> ProtobufTypeBuilder
198    {
199        self.packages[idx[0]].take_type(&idx[1..])
200    }
201
202    fn take_service(&mut self, idx: &[usize]) -> ServiceBuilder
203    {
204        self.packages[idx[0]].take_service(&idx[1..])
205    }
206}
207
208impl PackageBuilder
209{
210    fn populate(&self, cache: &mut BuildCache, idx: &mut Vec<usize>) -> Result<(), ParseError>
211    {
212        let mut path = match &self.name {
213            Some(name) => name.split('.').collect(),
214            None => vec![],
215        };
216
217        idx.push(0);
218        for (i, t) in self.types.iter().enumerate() {
219            *idx.last_mut().unwrap() = i;
220
221            match t {
222                ProtobufItemBuilder::Type(ProtobufTypeBuilder::Message(m)) => {
223                    m.populate(cache, &mut path, idx)?
224                }
225                ProtobufItemBuilder::Type(ProtobufTypeBuilder::Enum(e)) => {
226                    e.populate(cache, &mut path, idx)?
227                }
228                ProtobufItemBuilder::Service(m) => m.populate(cache, &mut path, idx)?,
229            }
230        }
231        idx.pop();
232
233        Ok(())
234    }
235
236    fn take_type(&mut self, idx: &[usize]) -> ProtobufTypeBuilder
237    {
238        match &mut self.types[idx[0]] {
239            ProtobufItemBuilder::Type(t) => match t {
240                ProtobufTypeBuilder::Message(m) => m.take_type(&idx[1..]),
241                ProtobufTypeBuilder::Enum(e) => e.take_type(&idx[1..]),
242            },
243
244            // Panic here means something went wrong in populating the cache
245            ProtobufItemBuilder::Service(..) => {
246                panic!("Trying to take a service as a type");
247            }
248        }
249    }
250
251    fn take_service(&mut self, idx: &[usize]) -> ServiceBuilder
252    {
253        match &mut self.types[idx[0]] {
254            ProtobufItemBuilder::Service(e) => std::mem::take(e),
255
256            // Panic here means something went wrong in populating the cache
257            _ => panic!("Trying to take a non-service as a service"),
258        }
259    }
260}
261
262impl ProtobufTypeBuilder
263{
264    fn build(self, self_data: &CacheData, cache: &BuildCache) -> Result<TypeInfo, ParseError>
265    {
266        Ok(match self {
267            ProtobufTypeBuilder::Message(m) => TypeInfo::Message(m.build(self_data, cache)?),
268            ProtobufTypeBuilder::Enum(e) => TypeInfo::Enum(e.build(self_data, cache)?),
269        })
270    }
271}
272
273impl MessageBuilder
274{
275    /// Lists types found in this message builder recursively into the build cache.
276    ///
277    /// On error the `path` and `idx` will be left in an undefined state.
278    fn populate<'a>(
279        &'a self,
280        cache: &mut BuildCache,
281        path: &mut Vec<&'a str>,
282        idx: &mut Vec<usize>,
283    ) -> Result<(), ParseError>
284    {
285        path.push(&self.name);
286        let full_name = path.join(".");
287        let cache_idx = cache.types.len();
288        if cache
289            .items
290            .insert(full_name.clone(), (ItemType::Message, cache_idx))
291            .is_some()
292            || cache
293                .items_by_idx
294                .insert(idx.clone(), (ItemType::Message, cache_idx))
295                .is_some()
296        {
297            return Err(ParseError::DuplicateType {
298                name: path.join("."),
299            });
300        }
301
302        // Make sure to push the current type into the cache before processing the possible
303        // embedded types.
304        cache.types.push(CacheData {
305            item_type: ItemType::Message,
306            full_name,
307            idx_path: idx.clone(),
308            final_idx: cache_idx,
309        });
310
311        idx.push(0);
312        for (i, t) in self.inner_types.iter().enumerate() {
313            *idx.last_mut().unwrap() = i;
314            t.populate(cache, path, idx)?;
315        }
316
317        idx.pop();
318        path.pop();
319
320        Ok(())
321    }
322
323    fn take_type(&mut self, idx: &[usize]) -> ProtobufTypeBuilder
324    {
325        if idx.is_empty() {
326            ProtobufTypeBuilder::Message(MessageBuilder {
327                name: self.name.clone(),
328                fields: std::mem::take(&mut self.fields),
329                oneofs: std::mem::take(&mut self.oneofs),
330                options: std::mem::take(&mut self.options),
331                inner_types: self
332                    .inner_types
333                    .iter()
334                    .map(InnerTypeBuilder::clone_name)
335                    .collect(),
336            })
337        } else {
338            self.inner_types[idx[0]].take_type(&idx[1..])
339        }
340    }
341
342    fn build(self, self_data: &CacheData, cache: &BuildCache) -> Result<MessageInfo, ParseError>
343    {
344        let inner_types: Vec<_> = self
345            .inner_types
346            .iter()
347            .map(|inner| match inner {
348                InnerTypeBuilder::Message(m) => TypeRef::Message(MessageRef::from(
349                    cache
350                        .type_by_full_name(&format!("{}.{}", self_data.full_name, m.name))
351                        .expect("Existing type wasn't added to the cache"),
352                )),
353                InnerTypeBuilder::Enum(e) => TypeRef::Enum(EnumRef::from(
354                    cache
355                        .type_by_full_name(&format!("{}.{}", self_data.full_name, e.name))
356                        .expect("Existing type wasn't added to the cache"),
357                )),
358            })
359            .collect();
360
361        let mut fields: Vec<_> = self
362            .fields
363            .into_iter()
364            .map(|field| field.build(self_data, cache, None))
365            .collect::<Result<_, _>>()?;
366
367        let mut oneofs: Vec<_> = self
368            .oneofs
369            .into_iter()
370            .enumerate()
371            .map(|(idx, oneof)| {
372                let oneof_ref = OneofRef(InternalRef(idx));
373                let mut new_fields: Vec<_> = oneof
374                    .fields
375                    .into_iter()
376                    .map(|field| field.build(self_data, cache, Some(oneof_ref)))
377                    .collect::<Result<_, _>>()?;
378                fields.append(&mut new_fields);
379                Ok(Oneof {
380                    name: oneof.name,
381                    self_ref: oneof_ref,
382                    options: oneof.options,
383                    fields: vec![],
384                })
385            })
386            .collect::<Result<_, _>>()?;
387
388        // Sort the fields by number just for sanity.
389        let fields: BTreeMap<u64, MessageField> =
390            fields.into_iter().map(|f| (f.number, f)).collect();
391        for (idx, oneof) in oneofs.iter_mut().enumerate() {
392            oneof.fields = fields
393                .iter()
394                .filter_map(
395                    |(num, f)| match f.oneof == Some(OneofRef(InternalRef(idx))) {
396                        true => Some(*num),
397                        false => None,
398                    },
399                )
400                .collect();
401        }
402
403        let parent = cache.parent_type(&self_data.idx_path);
404        let fields_by_name = fields
405            .iter()
406            .map(|(i, f)| (f.name.to_string(), *i))
407            .collect();
408
409        Ok(MessageInfo {
410            name: self.name,
411            full_name: self_data.full_name.clone(),
412            parent,
413            self_ref: MessageRef(InternalRef(self_data.final_idx)),
414            inner_types,
415            oneofs,
416            fields,
417            fields_by_name,
418        })
419    }
420}
421
422impl InnerTypeBuilder
423{
424    fn clone_name(&self) -> InnerTypeBuilder
425    {
426        match self {
427            InnerTypeBuilder::Message(m) => InnerTypeBuilder::Message(MessageBuilder {
428                name: m.name.clone(),
429                ..Default::default()
430            }),
431            InnerTypeBuilder::Enum(e) => InnerTypeBuilder::Enum(EnumBuilder {
432                name: e.name.clone(),
433                ..Default::default()
434            }),
435        }
436    }
437}
438
439impl FieldBuilder
440{
441    fn build(
442        self,
443        self_data: &CacheData,
444        cache: &BuildCache,
445        oneof: Option<OneofRef>,
446    ) -> Result<MessageField, ParseError>
447    {
448        let multiplicity = resolve_multiplicity(self.multiplicity, &self.field_type, &self.options);
449        Ok(MessageField {
450            name: self.name,
451            number: self.number,
452            multiplicity,
453            field_type: self.field_type.build(self_data, cache)?,
454            oneof,
455            options: self.options,
456        })
457    }
458}
459
460fn resolve_multiplicity(
461    proto_multiplicity: Multiplicity,
462    field_type: &FieldTypeBuilder,
463    options: &[ProtoOption],
464) -> Multiplicity
465{
466    // If this isn't a repeated field, the multiplicity follows the proto one (single or optional).
467    if proto_multiplicity != Multiplicity::Repeated {
468        return proto_multiplicity;
469    }
470
471    // Repeated field.
472    match field_type {
473        // Non-scalar fields are always repeated.
474        FieldTypeBuilder::Unknown(..) => return Multiplicity::Repeated,
475        FieldTypeBuilder::Builtin(vt) if vt.wire_type() == 2 => return Multiplicity::Repeated,
476
477        // Scalar field.
478        _ => {}
479    }
480
481    // Check the options.
482    if let Some(opt) = options.iter().find(|o| o.name == "packed") {
483        return match opt.value {
484            Constant::Bool(true) => Multiplicity::RepeatedPacked,
485            _ => Multiplicity::Repeated,
486        };
487    }
488
489    Multiplicity::RepeatedPacked
490}
491
492impl FieldTypeBuilder
493{
494    fn build(self, self_data: &CacheData, cache: &BuildCache) -> Result<ValueType, ParseError>
495    {
496        Ok(match self {
497            FieldTypeBuilder::Builtin(vt) => vt,
498            FieldTypeBuilder::Unknown(s) => {
499                let t = cache
500                    .resolve_type(&s, &self_data.full_name)
501                    .ok_or_else(|| ParseError::TypeNotFound {
502                        name: s,
503                        context: self_data.full_name.to_string(),
504                    })?;
505
506                match t.item_type {
507                    ItemType::Message => ValueType::Message(MessageRef(InternalRef(t.final_idx))),
508                    ItemType::Enum => ValueType::Enum(EnumRef(InternalRef(t.final_idx))),
509                    _ => unreachable!("Service as field type"),
510                }
511            }
512        })
513    }
514}
515
516impl InnerTypeBuilder
517{
518    fn populate<'a>(
519        &'a self,
520        cache: &mut BuildCache,
521        path: &mut Vec<&'a str>,
522        idx: &mut Vec<usize>,
523    ) -> Result<(), ParseError>
524    {
525        match self {
526            InnerTypeBuilder::Message(m) => m.populate(cache, path, idx),
527            InnerTypeBuilder::Enum(e) => e.populate(cache, path, idx),
528        }
529    }
530
531    fn take_type(&mut self, idx: &[usize]) -> ProtobufTypeBuilder
532    {
533        match self {
534            InnerTypeBuilder::Message(m) => m.take_type(idx),
535            InnerTypeBuilder::Enum(e) => e.take_type(idx),
536        }
537    }
538}
539
540impl EnumBuilder
541{
542    /// Lists types found in this message builder recursively into the build cache.
543    ///
544    /// On error the `path` and `idx` will be left in an undefined state.
545    fn populate<'a>(
546        &'a self,
547        cache: &mut BuildCache,
548        path: &mut Vec<&'a str>,
549        idx: &mut Vec<usize>,
550    ) -> Result<(), ParseError>
551    {
552        path.push(&self.name);
553        let full_name = path.join(".");
554        let cache_idx = cache.types.len();
555        if cache
556            .items
557            .insert(full_name.clone(), (ItemType::Enum, cache_idx))
558            .is_some()
559        {
560            return Err(ParseError::DuplicateType {
561                name: path.join("."),
562            });
563        }
564        path.pop();
565
566        cache.types.push(CacheData {
567            item_type: ItemType::Enum,
568            full_name,
569            idx_path: idx.clone(),
570            final_idx: cache_idx,
571        });
572
573        Ok(())
574    }
575
576    fn build(self, self_data: &CacheData, cache: &BuildCache) -> Result<EnumInfo, ParseError>
577    {
578        let fields_by_name = self
579            .fields
580            .iter()
581            .map(|f| (f.name.clone(), f.value))
582            .collect();
583        let fields_by_value = self.fields.into_iter().map(|f| (f.value, f)).collect();
584
585        let parent = cache.parent_type(&self_data.idx_path);
586
587        Ok(EnumInfo {
588            name: self.name,
589            full_name: self_data.full_name.to_string(),
590            self_ref: EnumRef(InternalRef(self_data.final_idx)),
591            parent,
592            fields_by_value,
593            fields_by_name,
594        })
595    }
596
597    fn take_type(&mut self, idx: &[usize]) -> ProtobufTypeBuilder
598    {
599        if !idx.is_empty() {
600            panic!("Trying to take an inner type from an enum");
601        }
602
603        ProtobufTypeBuilder::Enum(std::mem::take(self))
604    }
605}
606
607impl ServiceBuilder
608{
609    /// Lists types found in this message builder recursively into the build cache.
610    ///
611    /// On error the `path` and `idx` will be left in an undefined state.
612    fn populate<'a>(
613        &'a self,
614        cache: &mut BuildCache,
615        path: &mut Vec<&'a str>,
616        idx: &mut Vec<usize>,
617    ) -> Result<(), ParseError>
618    {
619        path.push(&self.name);
620        let full_name = path.join(".");
621        let cache_idx = cache.services.len();
622        if let Some(..) = cache
623            .items
624            .insert(full_name.clone(), (ItemType::Service, cache_idx))
625        {
626            return Err(ParseError::DuplicateType {
627                name: path.join("."),
628            });
629        }
630        path.pop();
631
632        cache.services.push(CacheData {
633            item_type: ItemType::Service,
634            full_name,
635            idx_path: idx.clone(),
636            final_idx: cache_idx,
637        });
638
639        Ok(())
640    }
641
642    fn build(self, self_data: &CacheData, cache: &BuildCache) -> Result<Service, ParseError>
643    {
644        let rpcs: Vec<_> = self
645            .rpcs
646            .into_iter()
647            .map(|rpc| rpc.build(self_data, cache))
648            .collect::<Result<_, _>>()?;
649        let rpcs_by_name = rpcs
650            .iter()
651            .enumerate()
652            .map(|(idx, rpc)| (rpc.name.to_string(), idx))
653            .collect();
654
655        let parent = match cache.parent_type(&self_data.idx_path) {
656            TypeParent::Package(p) => p,
657            _ => panic!("Service inside a message"),
658        };
659
660        Ok(Service {
661            name: self.name,
662            self_ref: ServiceRef(InternalRef(self_data.final_idx)),
663            parent,
664            full_name: self_data.full_name.clone(),
665            rpcs,
666            rpcs_by_name,
667            options: vec![],
668        })
669    }
670}
671
672impl RpcBuilder
673{
674    fn build(self, self_data: &CacheData, cache: &BuildCache) -> Result<Rpc, ParseError>
675    {
676        Ok(Rpc {
677            name: self.name,
678            input: self.input.build(self_data, cache)?,
679            output: self.output.build(self_data, cache)?,
680            options: vec![],
681        })
682    }
683}
684
685impl RpcArgBuilder
686{
687    fn build(self, rpc_data: &CacheData, cache: &BuildCache) -> Result<RpcArg, ParseError>
688    {
689        // Fetch the type data from the cache so we can figure out the type reference.
690        let self_data = match cache.resolve_type(&self.message, &rpc_data.full_name) {
691            Some(data) => data,
692            None => {
693                return Err(ParseError::TypeNotFound {
694                    name: self.message,
695                    context: rpc_data.full_name.clone(),
696                })
697            }
698        };
699
700        // All rpc input/output types must be messages.
701        if self_data.item_type != ItemType::Message {
702            return Err(ParseError::InvalidTypeKind {
703                type_name: self.message,
704                context: "service input/output",
705                expected: ItemType::Message,
706                actual: self_data.item_type,
707            });
708        }
709
710        let message = MessageRef(InternalRef(self_data.final_idx));
711        Ok(RpcArg {
712            stream: self.stream,
713            message,
714        })
715    }
716}
717
718impl MessageRef
719{
720    fn from(data: &CacheData) -> Self
721    {
722        if data.item_type != ItemType::Message {
723            panic!("Trying to create MessageRef for {:?}", data.item_type);
724        }
725        MessageRef(InternalRef(data.final_idx))
726    }
727}
728
729impl EnumRef
730{
731    fn from(data: &CacheData) -> Self
732    {
733        if data.item_type != ItemType::Enum {
734            panic!("Trying to create EnumRef for {:?}", data.item_type);
735        }
736        EnumRef(InternalRef(data.final_idx))
737    }
738}
739
740#[derive(Default)]
741struct BuildCache
742{
743    items: BTreeMap<String, (ItemType, usize)>,
744    items_by_idx: BTreeMap<Vec<usize>, (ItemType, usize)>,
745    types: Vec<CacheData>,
746    services: Vec<CacheData>,
747}
748
749struct CacheData
750{
751    item_type: ItemType,
752    idx_path: Vec<usize>,
753    final_idx: usize,
754    full_name: String,
755}
756
757impl BuildCache
758{
759    fn resolve_type(&self, relative_name: &str, mut current_path: &str) -> Option<&CacheData>
760    {
761        if let Some(absolute) = relative_name.strip_prefix('.') {
762            return self.type_by_full_name(absolute);
763        }
764
765        loop {
766            let lookup: Cow<str> = match current_path.is_empty() {
767                true => relative_name.into(),
768                false => format!("{}.{}", current_path, relative_name).into(),
769            };
770
771            if let Some(t) = self.type_by_full_name(&lookup) {
772                return Some(t);
773            }
774
775            if current_path.is_empty() {
776                return None;
777            }
778
779            match current_path.rfind('.') {
780                Some(i) => {
781                    let (start, _) = current_path.split_at(i);
782                    current_path = start;
783                }
784                None => {
785                    current_path = "";
786                }
787            }
788        }
789    }
790
791    fn parent_type(&self, current: &[usize]) -> TypeParent
792    {
793        match current.len() {
794            0 | 1 => panic!("Empty type ID path"),
795            2 => TypeParent::Package(PackageRef(InternalRef(current[0]))),
796            _ => self
797                .type_by_idx_path(&current[..current.len() - 1])
798                .map(|data| TypeParent::Message(MessageRef(InternalRef(data.final_idx))))
799                .unwrap_or_else(|| panic!("Parent type not found: {:?}", current)),
800        }
801    }
802
803    fn type_by_full_name(&self, full_name: &str) -> Option<&CacheData>
804    {
805        self.items
806            .get(full_name)
807            .and_then(|(ty, i)| self.type_by_idx(*ty, *i))
808    }
809
810    fn type_by_idx_path(&self, idx: &[usize]) -> Option<&CacheData>
811    {
812        self.items_by_idx
813            .get(idx)
814            .and_then(|(ty, i)| self.type_by_idx(*ty, *i))
815    }
816
817    fn type_by_idx(&self, item_type: ItemType, idx: usize) -> Option<&CacheData>
818    {
819        match item_type {
820            ItemType::Message => self.types.get(idx),
821            ItemType::Enum => self.types.get(idx),
822            ItemType::Service => self.services.get(idx),
823        }
824    }
825}