Skip to main content

aldrin_parser/
link_resolver.rs

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