aldrin_parser/error/
duplicate_event_id.rs

1use super::Error;
2use crate::ast::{Ident, LitPosInt, ServiceDef, ServiceItem};
3use crate::diag::{Diagnostic, DiagnosticKind, Formatted, Formatter};
4use crate::validate::Validate;
5use crate::{util, Parsed, Span};
6
7#[derive(Debug)]
8pub struct DuplicateEventId {
9    schema_name: String,
10    duplicate: LitPosInt,
11    first: Span,
12    service_ident: Ident,
13    free_id: u32,
14}
15
16impl DuplicateEventId {
17    pub(crate) fn validate(service: &ServiceDef, validate: &mut Validate) {
18        let events = service.items().iter().filter_map(|item| match item {
19            ServiceItem::Event(ev) => Some(ev),
20            _ => None,
21        });
22
23        let mut max_id = events
24            .clone()
25            .fold(0, |cur, ev| match ev.id().value().parse() {
26                Ok(id) if id > cur => id,
27                _ => cur,
28            });
29
30        util::find_duplicates(
31            events,
32            |ev| ev.id().value(),
33            |duplicate, first| {
34                max_id += 1;
35                let free_id = max_id;
36                validate.add_error(Self {
37                    schema_name: validate.schema_name().to_owned(),
38                    duplicate: duplicate.id().clone(),
39                    first: first.id().span(),
40                    service_ident: service.name().clone(),
41                    free_id,
42                })
43            },
44        );
45    }
46
47    pub fn duplicate(&self) -> &LitPosInt {
48        &self.duplicate
49    }
50
51    pub fn first(&self) -> Span {
52        self.first
53    }
54
55    pub fn service_ident(&self) -> &Ident {
56        &self.service_ident
57    }
58
59    pub fn free_id(&self) -> u32 {
60        self.free_id
61    }
62}
63
64impl Diagnostic for DuplicateEventId {
65    fn kind(&self) -> DiagnosticKind {
66        DiagnosticKind::Error
67    }
68
69    fn schema_name(&self) -> &str {
70        &self.schema_name
71    }
72
73    fn format<'a>(&'a self, parsed: &'a Parsed) -> Formatted<'a> {
74        let mut fmt = Formatter::new(
75            self,
76            format!(
77                "duplicate event id `{}` in service `{}`",
78                self.duplicate.value(),
79                self.service_ident.value()
80            ),
81        );
82
83        if let Some(schema) = parsed.get_schema(&self.schema_name) {
84            fmt.main_block(
85                schema,
86                self.duplicate.span().from,
87                self.duplicate.span(),
88                "duplicate defined here",
89            )
90            .info_block(schema, self.first.from, self.first, "first defined here");
91        }
92
93        fmt.help(format!("use a free id, e.g. {}", self.free_id));
94        fmt.format()
95    }
96}
97
98impl From<DuplicateEventId> for Error {
99    fn from(e: DuplicateEventId) -> Self {
100        Self::DuplicateEventId(e)
101    }
102}