aldrin_parser/error/
duplicate_event_id.rs1use 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}