edifact_mapper/error.rs
1//! Error types for the edifact-mapper facade crate.
2
3/// Errors that can occur when using the [`Mapper`](crate::Mapper) API.
4#[derive(Debug, thiserror::Error)]
5pub enum MapperError {
6 /// The specified data directory does not exist on disk.
7 #[error("Data directory not found: {path}")]
8 DataDirNotFound { path: String },
9
10 /// No data bundle file found for the requested format version.
11 #[error("No data bundle found for format version {fv}")]
12 BundleNotFound { fv: String },
13
14 /// The requested variant (e.g., "UTILMD_Strom") is not present in the bundle.
15 #[error("No variant '{variant}' in bundle for {fv}")]
16 VariantNotFound { fv: String, variant: String },
17
18 /// No mapping engine definitions exist for the given PID within the variant.
19 #[error("No mapping engine for PID {pid} in {fv}/{variant}")]
20 PidNotFound {
21 fv: String,
22 variant: String,
23 pid: String,
24 },
25
26 /// An error from the MIG assembly layer.
27 #[error("Assembly error: {0}")]
28 Assembly(#[from] mig_assembly::AssemblyError),
29
30 /// An error from the TOML mapping engine.
31 #[error("Mapping error: {0}")]
32 Mapping(#[from] mig_bo4e::MappingError),
33
34 /// JSON serialization failed (e.g., when converting a typed struct to JSON).
35 #[error("Serialization error: {0}")]
36 Serialization(String),
37
38 /// The variant has no MIG schema (required for reverse pipeline).
39 #[error("No MIG schema for {fv}/{variant}")]
40 NoMigSchema { fv: String, variant: String },
41
42 /// The BO4E input fills a group's segments but not the segment that opens
43 /// the group in the MIG (e.g. `Zaehler.geraeteNummer` without
44 /// `Zaehler.zaehlertypMerkmal` would yield SG10 `CAV` without `CCI`).
45 /// Rendering it would produce EDIFACT no receiver can assemble, so the
46 /// conversion is refused. Boxed to keep `MapperError` small.
47 #[error(transparent)]
48 MissingGroupEntrySegment(Box<GroupEntrySegmentError>),
49
50 /// A standard I/O error.
51 #[error("IO error: {0}")]
52 Io(#[from] std::io::Error),
53}
54
55/// Details of [`MapperError::MissingGroupEntrySegment`].
56#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
57#[error(
58 "Cannot render PID {pid}: group {group_path} ({source_path}) would contain {present_segments:?} but not its entry segment '{entry_segment}'{}",
59 entry_segment_hint(.entities, .entry_fields)
60)]
61pub struct GroupEntrySegmentError {
62 pub pid: String,
63 /// MIG group path, e.g. `"SG4.SG8.SG10"`.
64 pub group_path: String,
65 /// The group in TOML `source_path` notation, e.g. `"sg4.sg8_z03.sg10"`.
66 pub source_path: String,
67 /// Tag of the missing entry segment, e.g. `"CCI"`.
68 pub entry_segment: String,
69 /// Tags of the segments the group would have carried.
70 pub present_segments: Vec<String>,
71 /// BO4E entities mapped from this group (e.g. `["Zaehler"]`).
72 pub entities: Vec<String>,
73 /// `Entity.field` values the entry segment is built from
74 /// (e.g. `["Zaehler.zaehlertypMerkmal"]`); supplying one fixes the input.
75 pub entry_fields: Vec<String>,
76}
77
78fn entry_segment_hint(entities: &[String], entry_fields: &[String]) -> String {
79 if !entry_fields.is_empty() {
80 format!(" (set {})", entry_fields.join(" or "))
81 } else if !entities.is_empty() {
82 format!(" (entity {})", entities.join(", "))
83 } else {
84 String::new()
85 }
86}