1use std::{io, path::PathBuf};
2use thiserror::Error;
3
4#[derive(Error, Debug, Clone)]
6pub enum ValueError {
7 #[error("unknown concept: {concept}")]
8 UnknownConcept { concept: String },
9
10 #[error("missing context reference: {context_ref}")]
11 MissingContext { context_ref: String },
12
13 #[error("missing unit reference: {unit_ref}")]
14 MissingUnit { unit_ref: String },
15
16 #[error("invalid boolean value '{raw}'")]
17 InvalidBoolean { raw: String },
18
19 #[error("invalid integer value '{raw}'")]
20 InvalidInteger { raw: String },
21
22 #[error("invalid decimal value '{raw}'")]
23 InvalidDecimal { raw: String },
24
25 #[error("invalid date value '{raw}'")]
26 InvalidDate { raw: String },
27
28 #[error("invalid dateTime value '{raw}'")]
29 InvalidDateTime { raw: String },
30
31 #[error("invalid QName value '{raw}': {reason}")]
32 InvalidQName { raw: String, reason: String },
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum LinkbaseType {
38 Label,
39 Presentation,
40 Calculation,
41 Definition,
42 Reference,
43}
44
45impl std::fmt::Display for LinkbaseType {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 match self {
48 LinkbaseType::Label => write!(f, "label"),
49 LinkbaseType::Presentation => write!(f, "presentation"),
50 LinkbaseType::Calculation => write!(f, "calculation"),
51 LinkbaseType::Definition => write!(f, "definition"),
52 LinkbaseType::Reference => write!(f, "reference"),
53 }
54 }
55}
56
57#[derive(Error, Debug)]
59pub enum XbrlError {
60 #[error("Error parsing XML at position {position}{}{}: {source}", path.as_ref().map(|path| format!(" in file {}", path.display())).unwrap_or_default(), element.as_ref().map(|err| format!(" in element <{}>", err)).unwrap_or_default())]
62 XmlParse {
63 path: Option<PathBuf>,
64 position: u64,
65 element: Option<String>,
66 #[source]
67 source: quick_xml::Error,
68 },
69
70 #[error("Error parsing {linkbase_type} linkbase{}: {source}", file_path.as_ref().map(|path| format!(" from {}", path.display())).unwrap_or_default())]
72 LinkbaseParse {
73 linkbase_type: LinkbaseType,
74 file_path: Option<PathBuf>,
75 #[source]
76 source: quick_xml::Error,
77 },
78
79 #[error("Failed to open file: {}", path.display())]
81 FileOpen {
82 path: PathBuf,
83 #[source]
84 source: io::Error,
85 },
86
87 #[error("Failed to read file: {}", path.display())]
89 FileRead {
90 path: PathBuf,
91 #[source]
92 source: io::Error,
93 },
94
95 #[error("Failed to write file: {}", path.display())]
97 FileWrite {
98 path: PathBuf,
99 #[source]
100 source: io::Error,
101 },
102
103 #[error("{element} missing required attribute: {attribute}")]
105 MissingAttribute { element: String, attribute: String },
106
107 #[error("Failed to discover taxonomy for schema ref '{schema_ref}' with entry point {}", entry_point.display())]
109 TaxonomyDiscovery {
110 schema_ref: String,
111 entry_point: PathBuf,
112 #[source]
113 source: Box<XbrlError>,
114 },
115
116 #[error(
118 "Schema refs have mismatched versions: expected '{expected}', \
119 found '{found}' in '{schema_ref}'"
120 )]
121 VersionMismatch {
122 expected: String,
123 found: String,
124 schema_ref: String,
125 },
126
127 #[error("Invalid XLink href '{href}': {reason}")]
129 InvalidHref { href: String, reason: String },
130
131 #[error("Invalid schema document '{}': {reason}", path.as_ref().map(|path| path.display().to_string()).unwrap_or_else(|| "unknown".to_string()))]
133 InvalidSchemaDocument {
134 path: Option<PathBuf>,
135 reason: String,
136 },
137
138 #[error("Error resolving schema: {reason}")]
140 InvalidSchemaResolution { reason: String },
141
142 #[error("Invalid instance document '{}': {reason}", path.as_ref().map(|path| path.display().to_string()).unwrap_or_else(|| "unknown".to_string()))]
144 InvalidInstanceDocument {
145 path: Option<PathBuf>,
146 reason: String,
147 },
148
149 #[error("Invalid linkbase document '{}': {reason}", path.as_ref().map(|path| path.display().to_string()).unwrap_or_else(|| "unknown".to_string()))]
151 InvalidLinkbaseDocument {
152 path: Option<PathBuf>,
153 reason: String,
154 },
155
156 #[error("Error resolving linkbase: {reason}")]
158 InvalidLinkbaseResolution { reason: String },
159
160 #[error("invalid {expected} value '{value}'")]
162 ParseError {
163 expected: &'static str,
164 value: String,
165 },
166
167 #[error(transparent)]
169 Value(#[from] ValueError),
170
171 #[error(transparent)]
173 Io(#[from] io::Error),
174
175 #[error(transparent)]
177 Xml(#[from] quick_xml::Error),
178
179 #[error(transparent)]
181 Utf8(#[from] std::str::Utf8Error),
182
183 #[error(transparent)]
185 Escape(#[from] quick_xml::escape::EscapeError),
186}
187
188pub type Result<T> = std::result::Result<T, XbrlError>;