aldrin_parser/
link_resolver.rs

1#![allow(unused_imports)]
2#![allow(unused_variables)]
3
4use crate::ast::{
5    ConstDef, Definition, EnumDef, EnumFallback, EnumVariant, EventDef, EventFallback, FunctionDef,
6    FunctionFallback, FunctionPart, InlineEnum, InlineStruct, NewtypeDef, ServiceDef, ServiceItem,
7    StructDef, StructFallback, StructField, TypeNameOrInline,
8};
9use crate::{Parser, Schema, Span};
10use std::collections::HashMap;
11use std::mem;
12use thiserror::Error;
13
14type Result<'a, T> = std::result::Result<T, ResolveLinkError<'a>>;
15type ResolveResult<'a> = Result<'a, ResolvedLink<'a>>;
16
17#[derive(Debug, Copy, Clone)]
18pub struct LinkResolver<'a> {
19    schemas: &'a HashMap<String, Schema>,
20    schema: &'a Schema,
21}
22
23impl<'a> LinkResolver<'a> {
24    pub fn new(parser: &'a Parser, schema: &'a Schema) -> Self {
25        Self::from_parts(parser.schemas(), schema)
26    }
27
28    pub(crate) fn from_parts(schemas: &'a HashMap<String, Schema>, schema: &'a Schema) -> Self {
29        Self { schemas, schema }
30    }
31
32    pub fn with_schema(self, schema: &'a Schema) -> Self {
33        Self::from_parts(self.schemas, schema)
34    }
35
36    pub fn with_schema_name(self, schema: &str) -> Self {
37        let schema = self.schemas.get(schema).expect("valid schema name");
38        self.with_schema(schema)
39    }
40
41    pub fn schema(self) -> &'a Schema {
42        self.schema
43    }
44
45    pub fn convert_broken_link(mut link: &str) -> Option<&str> {
46        if (link != " ") && (link != "x") && (link != "X") {
47            if link.starts_with('`') && link.ends_with('`') && (link.len() > 1) {
48                link = &link[1..link.len() - 1];
49            }
50
51            Self::is_doc_link(link).then_some(link)
52        } else {
53            None
54        }
55    }
56
57    pub fn resolve(mut self, link: &'a str) -> ResolveResult<'a> {
58        if !Self::is_doc_link(link) {
59            return Ok(ResolvedLink::Foreign);
60        }
61
62        let mut components = Components::new(link);
63
64        if let Some(schema) = components.schema()? {
65            if schema != "self" {
66                if self
67                    .schema
68                    .imports()
69                    .iter()
70                    .all(|import| import.schema_name().value() != schema)
71                {
72                    return Err(ResolveLinkError::SchemaNotFound(schema));
73                }
74
75                let schema = self
76                    .schemas
77                    .get(schema)
78                    .ok_or(ResolveLinkError::SchemaNotFound(schema))?;
79
80                self.schema = schema;
81            }
82        }
83
84        self.resolve_def(components)
85    }
86
87    pub fn convert_broken_link_if_valid(self, link: &str) -> Option<&str> {
88        match Self::convert_broken_link(link) {
89            Some(link) => match self.resolve(link) {
90                Ok(_) => Some(link),
91                Err(_) => None,
92            },
93
94            None => None,
95        }
96    }
97
98    fn is_doc_link(link: &str) -> bool {
99        !link.is_empty()
100            && link
101                .chars()
102                .all(|c| (c == ':') || (c == '_') || c.is_ascii_alphanumeric())
103    }
104
105    fn resolve_def(self, mut components: Components<'a>) -> ResolveResult<'a> {
106        let Some(name) = components.next()? else {
107            return Ok(ResolvedLink::Schema(self.schema));
108        };
109
110        let def = self
111            .schema
112            .definitions()
113            .iter()
114            .find(|def| def.name().value() == name)
115            .ok_or(ResolveLinkError::DefinitionNotFound(self.schema, name))?;
116
117        match def {
118            Definition::Struct(struct_def) => self.resolve_struct(struct_def, components),
119            Definition::Enum(enum_def) => self.resolve_enum(enum_def, components),
120            Definition::Service(svc) => self.resolve_service(svc, components),
121
122            Definition::Const(const_def) => {
123                if components.next()?.is_none() {
124                    Ok(ResolvedLink::Const(self.schema, const_def))
125                } else {
126                    Err(ResolveLinkError::LinkIntoConst(const_def))
127                }
128            }
129
130            Definition::Newtype(newtype) => {
131                if components.next()?.is_none() {
132                    Ok(ResolvedLink::Newtype(self.schema, newtype))
133                } else {
134                    Err(ResolveLinkError::LinkIntoNewtype(newtype))
135                }
136            }
137        }
138    }
139
140    fn resolve_struct(
141        self,
142        struct_def: &'a StructDef,
143        components: Components<'a>,
144    ) -> ResolveResult<'a> {
145        let Some(name) = components.finish(ResolveLinkError::LinkIntoField)? else {
146            return Ok(ResolvedLink::Struct(self.schema, struct_def));
147        };
148
149        if let Some(field) = struct_def
150            .fields()
151            .iter()
152            .find(|field| field.name().value() == name)
153        {
154            return Ok(ResolvedLink::Field(self.schema, struct_def, field));
155        }
156
157        if let Some(fallback) = struct_def.fallback() {
158            if fallback.name().value() == name {
159                return Ok(ResolvedLink::FallbackField(
160                    self.schema,
161                    struct_def,
162                    fallback,
163                ));
164            }
165        }
166
167        Err(ResolveLinkError::FieldNotFound(struct_def, name))
168    }
169
170    fn resolve_inline_struct(
171        self,
172        inline_struct: &'a InlineStruct,
173        components: Components<'a>,
174        ok_struct: impl FnOnce(&'a InlineStruct) -> ResolvedLink<'a>,
175        ok_field: impl FnOnce(&'a InlineStruct, &'a StructField) -> ResolvedLink<'a>,
176        ok_fallback: impl FnOnce(&'a InlineStruct, &'a StructFallback) -> ResolvedLink<'a>,
177    ) -> ResolveResult<'a> {
178        let Some(name) = components.finish(ResolveLinkError::LinkIntoField)? else {
179            return Ok(ok_struct(inline_struct));
180        };
181
182        if let Some(field) = inline_struct
183            .fields()
184            .iter()
185            .find(|field| field.name().value() == name)
186        {
187            return Ok(ok_field(inline_struct, field));
188        }
189
190        if let Some(fallback) = inline_struct.fallback() {
191            if fallback.name().value() == name {
192                return Ok(ok_fallback(inline_struct, fallback));
193            }
194        }
195
196        Err(ResolveLinkError::InlineFieldNotFound(name))
197    }
198
199    fn resolve_enum(self, enum_def: &'a EnumDef, components: Components<'a>) -> ResolveResult<'a> {
200        let Some(name) = components.finish(ResolveLinkError::LinkIntoVariant)? else {
201            return Ok(ResolvedLink::Enum(self.schema, enum_def));
202        };
203
204        if let Some(var) = enum_def
205            .variants()
206            .iter()
207            .find(|var| var.name().value() == name)
208        {
209            return Ok(ResolvedLink::Variant(self.schema, enum_def, var));
210        }
211
212        if let Some(fallback) = enum_def.fallback() {
213            if fallback.name().value() == name {
214                return Ok(ResolvedLink::FallbackVariant(
215                    self.schema,
216                    enum_def,
217                    fallback,
218                ));
219            }
220        }
221
222        Err(ResolveLinkError::VariantNotFound(enum_def, name))
223    }
224
225    fn resolve_inline_enum(
226        self,
227        inline_enum: &'a InlineEnum,
228        components: Components<'a>,
229        ok_enum: impl FnOnce(&'a InlineEnum) -> ResolvedLink<'a>,
230        ok_variant: impl FnOnce(&'a InlineEnum, &'a EnumVariant) -> ResolvedLink<'a>,
231        ok_fallback: impl FnOnce(&'a InlineEnum, &'a EnumFallback) -> ResolvedLink<'a>,
232    ) -> ResolveResult<'a> {
233        let Some(name) = components.finish(ResolveLinkError::LinkIntoVariant)? else {
234            return Ok(ok_enum(inline_enum));
235        };
236
237        if let Some(var) = inline_enum
238            .variants()
239            .iter()
240            .find(|var| var.name().value() == name)
241        {
242            return Ok(ok_variant(inline_enum, var));
243        }
244
245        if let Some(fallback) = inline_enum.fallback() {
246            if fallback.name().value() == name {
247                return Ok(ok_fallback(inline_enum, fallback));
248            }
249        }
250
251        Err(ResolveLinkError::InlineVariantNotFound(name))
252    }
253
254    fn resolve_service(
255        self,
256        svc: &'a ServiceDef,
257        mut components: Components<'a>,
258    ) -> ResolveResult<'a> {
259        let Some(name) = components.next()? else {
260            return Ok(ResolvedLink::Service(self.schema, svc));
261        };
262
263        if let Some(item) = svc.items().iter().find(|item| item.name().value() == name) {
264            match item {
265                ServiceItem::Function(func) => return self.resolve_function(svc, func, components),
266                ServiceItem::Event(ev) => return self.resolve_event(svc, ev, components),
267            }
268        }
269
270        if let Some(fallback) = svc.function_fallback() {
271            if fallback.name().value() == name {
272                return Ok(ResolvedLink::FunctionFallback(self.schema, svc, fallback));
273            }
274        }
275
276        if let Some(fallback) = svc.event_fallback() {
277            if fallback.name().value() == name {
278                return Ok(ResolvedLink::EventFallback(self.schema, svc, fallback));
279            }
280        }
281
282        Err(ResolveLinkError::ItemNotFound(svc, name))
283    }
284
285    fn resolve_function(
286        self,
287        svc: &'a ServiceDef,
288        func: &'a FunctionDef,
289        mut components: Components<'a>,
290    ) -> ResolveResult<'a> {
291        let Some(name) = components.next()? else {
292            return Ok(ResolvedLink::Function(self.schema, svc, func));
293        };
294
295        match name {
296            "args" => match func.args() {
297                Some(args) => self.resolve_type_name_or_inline(
298                    args.part_type(),
299                    components,
300                    |inline_struct| {
301                        ResolvedLink::FunctionArgsStruct(
302                            self.schema,
303                            svc,
304                            func,
305                            args,
306                            inline_struct,
307                        )
308                    },
309                    |inline_struct, field| {
310                        ResolvedLink::FunctionArgsField(
311                            self.schema,
312                            svc,
313                            func,
314                            args,
315                            inline_struct,
316                            field,
317                        )
318                    },
319                    |inline_struct, fallback| {
320                        ResolvedLink::FunctionArgsFallbackField(
321                            self.schema,
322                            svc,
323                            func,
324                            args,
325                            inline_struct,
326                            fallback,
327                        )
328                    },
329                    |inline_enum| {
330                        ResolvedLink::FunctionArgsEnum(self.schema, svc, func, args, inline_enum)
331                    },
332                    |inline_enum, var| {
333                        ResolvedLink::FunctionArgsVariant(
334                            self.schema,
335                            svc,
336                            func,
337                            args,
338                            inline_enum,
339                            var,
340                        )
341                    },
342                    |inline_enum, fallback| {
343                        ResolvedLink::FunctionArgsFallbackVariant(
344                            self.schema,
345                            svc,
346                            func,
347                            args,
348                            inline_enum,
349                            fallback,
350                        )
351                    },
352                    ResolveLinkError::NoFunctionArgsInlineType(func),
353                ),
354
355                None => Err(ResolveLinkError::NoFunctionArgsInlineType(func)),
356            },
357
358            "ok" => match func.ok() {
359                Some(ok) => self.resolve_type_name_or_inline(
360                    ok.part_type(),
361                    components,
362                    |inline_struct| {
363                        ResolvedLink::FunctionOkStruct(self.schema, svc, func, ok, inline_struct)
364                    },
365                    |inline_struct, field| {
366                        ResolvedLink::FunctionOkField(
367                            self.schema,
368                            svc,
369                            func,
370                            ok,
371                            inline_struct,
372                            field,
373                        )
374                    },
375                    |inline_struct, fallback| {
376                        ResolvedLink::FunctionOkFallbackField(
377                            self.schema,
378                            svc,
379                            func,
380                            ok,
381                            inline_struct,
382                            fallback,
383                        )
384                    },
385                    |inline_enum| {
386                        ResolvedLink::FunctionOkEnum(self.schema, svc, func, ok, inline_enum)
387                    },
388                    |inline_enum, var| {
389                        ResolvedLink::FunctionOkVariant(
390                            self.schema,
391                            svc,
392                            func,
393                            ok,
394                            inline_enum,
395                            var,
396                        )
397                    },
398                    |inline_enum, fallback| {
399                        ResolvedLink::FunctionOkFallbackVariant(
400                            self.schema,
401                            svc,
402                            func,
403                            ok,
404                            inline_enum,
405                            fallback,
406                        )
407                    },
408                    ResolveLinkError::NoFunctionOkInlineType(func),
409                ),
410
411                None => Err(ResolveLinkError::NoFunctionOkInlineType(func)),
412            },
413
414            "err" => match func.err() {
415                Some(err) => self.resolve_type_name_or_inline(
416                    err.part_type(),
417                    components,
418                    |inline_struct| {
419                        ResolvedLink::FunctionErrStruct(self.schema, svc, func, err, inline_struct)
420                    },
421                    |inline_struct, field| {
422                        ResolvedLink::FunctionErrField(
423                            self.schema,
424                            svc,
425                            func,
426                            err,
427                            inline_struct,
428                            field,
429                        )
430                    },
431                    |inline_struct, fallback| {
432                        ResolvedLink::FunctionErrFallbackField(
433                            self.schema,
434                            svc,
435                            func,
436                            err,
437                            inline_struct,
438                            fallback,
439                        )
440                    },
441                    |inline_enum| {
442                        ResolvedLink::FunctionErrEnum(self.schema, svc, func, err, inline_enum)
443                    },
444                    |inline_enum, var| {
445                        ResolvedLink::FunctionErrVariant(
446                            self.schema,
447                            svc,
448                            func,
449                            err,
450                            inline_enum,
451                            var,
452                        )
453                    },
454                    |inline_enum, fallback| {
455                        ResolvedLink::FunctionErrFallbackVariant(
456                            self.schema,
457                            svc,
458                            func,
459                            err,
460                            inline_enum,
461                            fallback,
462                        )
463                    },
464                    ResolveLinkError::NoFunctionErrInlineType(func),
465                ),
466
467                None => Err(ResolveLinkError::NoFunctionErrInlineType(func)),
468            },
469
470            _ => Err(ResolveLinkError::InvalidFunctionPart(name)),
471        }
472    }
473
474    fn resolve_event(
475        self,
476        svc: &'a ServiceDef,
477        ev: &'a EventDef,
478        mut components: Components<'a>,
479    ) -> ResolveResult<'a> {
480        let Some(name) = components.next()? else {
481            return Ok(ResolvedLink::Event(self.schema, svc, ev));
482        };
483
484        if name != "args" {
485            return Err(ResolveLinkError::InvalidEventPart(name));
486        }
487
488        match ev.event_type() {
489            Some(ty) => self.resolve_type_name_or_inline(
490                ty,
491                components,
492                |inline_struct| ResolvedLink::EventStruct(self.schema, svc, ev, inline_struct),
493                |inline_struct, field| {
494                    ResolvedLink::EventField(self.schema, svc, ev, inline_struct, field)
495                },
496                |inline_struct, fallback| {
497                    ResolvedLink::EventFallbackField(self.schema, svc, ev, inline_struct, fallback)
498                },
499                |inline_enum| ResolvedLink::EventEnum(self.schema, svc, ev, inline_enum),
500                |inline_enum, var| {
501                    ResolvedLink::EventVariant(self.schema, svc, ev, inline_enum, var)
502                },
503                |inline_enum, fallback| {
504                    ResolvedLink::EventFallbackVariant(self.schema, svc, ev, inline_enum, fallback)
505                },
506                ResolveLinkError::NoEventInlineType(ev),
507            ),
508
509            None => Err(ResolveLinkError::NoEventInlineType(ev)),
510        }
511    }
512
513    #[allow(clippy::too_many_arguments)]
514    fn resolve_type_name_or_inline(
515        self,
516        ty: &'a TypeNameOrInline,
517        components: Components<'a>,
518        ok_struct: impl FnOnce(&'a InlineStruct) -> ResolvedLink<'a>,
519        ok_field: impl FnOnce(&'a InlineStruct, &'a StructField) -> ResolvedLink<'a>,
520        ok_struct_fallback: impl FnOnce(&'a InlineStruct, &'a StructFallback) -> ResolvedLink<'a>,
521        ok_enum: impl FnOnce(&'a InlineEnum) -> ResolvedLink<'a>,
522        ok_variant: impl FnOnce(&'a InlineEnum, &'a EnumVariant) -> ResolvedLink<'a>,
523        ok_enum_fallback: impl FnOnce(&'a InlineEnum, &'a EnumFallback) -> ResolvedLink<'a>,
524        err_no_inline_type: ResolveLinkError<'a>,
525    ) -> ResolveResult<'a> {
526        match ty {
527            TypeNameOrInline::TypeName(_) => Err(err_no_inline_type),
528
529            TypeNameOrInline::Struct(inline_struct) => self.resolve_inline_struct(
530                inline_struct,
531                components,
532                ok_struct,
533                ok_field,
534                ok_struct_fallback,
535            ),
536
537            TypeNameOrInline::Enum(inline_enum) => self.resolve_inline_enum(
538                inline_enum,
539                components,
540                ok_enum,
541                ok_variant,
542                ok_enum_fallback,
543            ),
544        }
545    }
546}
547
548#[derive(Debug, Copy, Clone)]
549pub enum ResolvedLink<'a> {
550    Foreign,
551    Schema(&'a Schema),
552    Struct(&'a Schema, &'a StructDef),
553    Field(&'a Schema, &'a StructDef, &'a StructField),
554    FallbackField(&'a Schema, &'a StructDef, &'a StructFallback),
555    Enum(&'a Schema, &'a EnumDef),
556    Variant(&'a Schema, &'a EnumDef, &'a EnumVariant),
557    FallbackVariant(&'a Schema, &'a EnumDef, &'a EnumFallback),
558    Service(&'a Schema, &'a ServiceDef),
559    Function(&'a Schema, &'a ServiceDef, &'a FunctionDef),
560
561    FunctionArgsStruct(
562        &'a Schema,
563        &'a ServiceDef,
564        &'a FunctionDef,
565        &'a FunctionPart,
566        &'a InlineStruct,
567    ),
568
569    FunctionArgsField(
570        &'a Schema,
571        &'a ServiceDef,
572        &'a FunctionDef,
573        &'a FunctionPart,
574        &'a InlineStruct,
575        &'a StructField,
576    ),
577
578    FunctionArgsFallbackField(
579        &'a Schema,
580        &'a ServiceDef,
581        &'a FunctionDef,
582        &'a FunctionPart,
583        &'a InlineStruct,
584        &'a StructFallback,
585    ),
586
587    FunctionArgsEnum(
588        &'a Schema,
589        &'a ServiceDef,
590        &'a FunctionDef,
591        &'a FunctionPart,
592        &'a InlineEnum,
593    ),
594
595    FunctionArgsVariant(
596        &'a Schema,
597        &'a ServiceDef,
598        &'a FunctionDef,
599        &'a FunctionPart,
600        &'a InlineEnum,
601        &'a EnumVariant,
602    ),
603
604    FunctionArgsFallbackVariant(
605        &'a Schema,
606        &'a ServiceDef,
607        &'a FunctionDef,
608        &'a FunctionPart,
609        &'a InlineEnum,
610        &'a EnumFallback,
611    ),
612
613    FunctionOkStruct(
614        &'a Schema,
615        &'a ServiceDef,
616        &'a FunctionDef,
617        &'a FunctionPart,
618        &'a InlineStruct,
619    ),
620
621    FunctionOkField(
622        &'a Schema,
623        &'a ServiceDef,
624        &'a FunctionDef,
625        &'a FunctionPart,
626        &'a InlineStruct,
627        &'a StructField,
628    ),
629
630    FunctionOkFallbackField(
631        &'a Schema,
632        &'a ServiceDef,
633        &'a FunctionDef,
634        &'a FunctionPart,
635        &'a InlineStruct,
636        &'a StructFallback,
637    ),
638
639    FunctionOkEnum(
640        &'a Schema,
641        &'a ServiceDef,
642        &'a FunctionDef,
643        &'a FunctionPart,
644        &'a InlineEnum,
645    ),
646
647    FunctionOkVariant(
648        &'a Schema,
649        &'a ServiceDef,
650        &'a FunctionDef,
651        &'a FunctionPart,
652        &'a InlineEnum,
653        &'a EnumVariant,
654    ),
655
656    FunctionOkFallbackVariant(
657        &'a Schema,
658        &'a ServiceDef,
659        &'a FunctionDef,
660        &'a FunctionPart,
661        &'a InlineEnum,
662        &'a EnumFallback,
663    ),
664
665    FunctionErrStruct(
666        &'a Schema,
667        &'a ServiceDef,
668        &'a FunctionDef,
669        &'a FunctionPart,
670        &'a InlineStruct,
671    ),
672
673    FunctionErrField(
674        &'a Schema,
675        &'a ServiceDef,
676        &'a FunctionDef,
677        &'a FunctionPart,
678        &'a InlineStruct,
679        &'a StructField,
680    ),
681
682    FunctionErrFallbackField(
683        &'a Schema,
684        &'a ServiceDef,
685        &'a FunctionDef,
686        &'a FunctionPart,
687        &'a InlineStruct,
688        &'a StructFallback,
689    ),
690
691    FunctionErrEnum(
692        &'a Schema,
693        &'a ServiceDef,
694        &'a FunctionDef,
695        &'a FunctionPart,
696        &'a InlineEnum,
697    ),
698
699    FunctionErrVariant(
700        &'a Schema,
701        &'a ServiceDef,
702        &'a FunctionDef,
703        &'a FunctionPart,
704        &'a InlineEnum,
705        &'a EnumVariant,
706    ),
707
708    FunctionErrFallbackVariant(
709        &'a Schema,
710        &'a ServiceDef,
711        &'a FunctionDef,
712        &'a FunctionPart,
713        &'a InlineEnum,
714        &'a EnumFallback,
715    ),
716
717    FunctionFallback(&'a Schema, &'a ServiceDef, &'a FunctionFallback),
718    Event(&'a Schema, &'a ServiceDef, &'a EventDef),
719    EventStruct(&'a Schema, &'a ServiceDef, &'a EventDef, &'a InlineStruct),
720
721    EventField(
722        &'a Schema,
723        &'a ServiceDef,
724        &'a EventDef,
725        &'a InlineStruct,
726        &'a StructField,
727    ),
728
729    EventFallbackField(
730        &'a Schema,
731        &'a ServiceDef,
732        &'a EventDef,
733        &'a InlineStruct,
734        &'a StructFallback,
735    ),
736
737    EventEnum(&'a Schema, &'a ServiceDef, &'a EventDef, &'a InlineEnum),
738
739    EventVariant(
740        &'a Schema,
741        &'a ServiceDef,
742        &'a EventDef,
743        &'a InlineEnum,
744        &'a EnumVariant,
745    ),
746
747    EventFallbackVariant(
748        &'a Schema,
749        &'a ServiceDef,
750        &'a EventDef,
751        &'a InlineEnum,
752        &'a EnumFallback,
753    ),
754
755    EventFallback(&'a Schema, &'a ServiceDef, &'a EventFallback),
756    Const(&'a Schema, &'a ConstDef),
757    Newtype(&'a Schema, &'a NewtypeDef),
758}
759
760/// Error when resolving a link.
761#[derive(Error, Debug, Copy, Clone)]
762pub enum ResolveLinkError<'a> {
763    #[error("invalid format")]
764    InvalidFormat,
765
766    #[error("schema `{0}` not found")]
767    SchemaNotFound(&'a str),
768
769    #[error("definition `{1}` not found in schema `{schema}`", schema = .0.name())]
770    DefinitionNotFound(&'a Schema, &'a str),
771
772    #[error("field `{1}` not found in struct `{ty}`", ty = .0.name().value())]
773    FieldNotFound(&'a StructDef, &'a str),
774
775    #[error("field `{0}` not found in inline struct")]
776    InlineFieldNotFound(&'a str),
777
778    #[error("cannot link into field `{0}`")]
779    LinkIntoField(&'a str),
780
781    #[error("variant `{1}` not found in enum `{ty}`", ty = .0.name().value())]
782    VariantNotFound(&'a EnumDef, &'a str),
783
784    #[error("variant `{0}` not found in inline enum")]
785    InlineVariantNotFound(&'a str),
786
787    #[error("cannot link into variant `{0}`")]
788    LinkIntoVariant(&'a str),
789
790    #[error("item `{1}` not found in service `{svc}`", svc = .0.name().value())]
791    ItemNotFound(&'a ServiceDef, &'a str),
792
793    #[error("invalid function part `{0}`")]
794    InvalidFunctionPart(&'a str),
795
796    #[error("`args` of function `{func}` isn't an inline type", func = .0.name().value())]
797    NoFunctionArgsInlineType(&'a FunctionDef),
798
799    #[error("`ok` of function `{func}` isn't an inline type", func = .0.name().value())]
800    NoFunctionOkInlineType(&'a FunctionDef),
801
802    #[error("`err` of function `{func}` isn't an inline type", func = .0.name().value())]
803    NoFunctionErrInlineType(&'a FunctionDef),
804
805    #[error("invalid event part `{0}`")]
806    InvalidEventPart(&'a str),
807
808    #[error("event `{ev}` has no inline type", ev = .0.name().value())]
809    NoEventInlineType(&'a EventDef),
810
811    #[error("cannot link into constant `{const}`", const = .0.name().value())]
812    LinkIntoConst(&'a ConstDef),
813
814    #[error("cannot link into newtype `{ty}`", ty = .0.name().value())]
815    LinkIntoNewtype(&'a NewtypeDef),
816}
817
818struct Components<'a> {
819    link: &'a str,
820}
821
822impl<'a> Components<'a> {
823    fn new(link: &'a str) -> Self {
824        Self { link }
825    }
826
827    fn schema(&mut self) -> Result<'a, Option<&'a str>> {
828        match self.link.strip_prefix("::") {
829            Some(rest) => {
830                self.link = rest;
831
832                self.next()?
833                    .map(Some)
834                    .ok_or(ResolveLinkError::InvalidFormat)
835            }
836
837            None => Ok(None),
838        }
839    }
840
841    fn next(&mut self) -> Result<'a, Option<&'a str>> {
842        match self.link.split_once("::") {
843            Some((component, rest)) => {
844                if component.is_empty() || rest.is_empty() {
845                    Err(ResolveLinkError::InvalidFormat)
846                } else {
847                    self.link = rest;
848                    Ok(Some(component))
849                }
850            }
851
852            None => {
853                if self.link.is_empty() {
854                    Ok(None)
855                } else {
856                    Ok(Some(mem::take(&mut self.link)))
857                }
858            }
859        }
860    }
861
862    fn finish(
863        self,
864        err: impl FnOnce(&'a str) -> ResolveLinkError<'a>,
865    ) -> Result<'a, Option<&'a str>> {
866        if self.link.is_empty() {
867            Ok(None)
868        } else if let Some((component, _)) = self.link.split_once("::") {
869            Err(err(component))
870        } else {
871            Ok(Some(self.link))
872        }
873    }
874}