Skip to main content

xbrl_rs/
error.rs

1use std::{io, path::PathBuf};
2use thiserror::Error;
3
4/// Error type for typed fact value conversion.
5#[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/// The type of linkbase being parsed
36#[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/// Error type for XBRL operations
58#[derive(Error, Debug)]
59pub enum XbrlError {
60    /// Error parsing XML content
61    #[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 parsing linkbase file
71    #[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 opening file
80    #[error("Failed to open file: {}", path.display())]
81    FileOpen {
82        path: PathBuf,
83        #[source]
84        source: io::Error,
85    },
86
87    /// Error reading file
88    #[error("Failed to read file: {}", path.display())]
89    FileRead {
90        path: PathBuf,
91        #[source]
92        source: io::Error,
93    },
94
95    /// Error writing file
96    #[error("Failed to write file: {}", path.display())]
97    FileWrite {
98        path: PathBuf,
99        #[source]
100        source: io::Error,
101    },
102
103    /// Missing required XML attribute
104    #[error("{element} missing required attribute: {attribute}")]
105    MissingAttribute { element: String, attribute: String },
106
107    /// Error discovering taxonomy
108    #[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    /// Schema refs belong to different taxonomy versions
117    #[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    /// Invalid XLink href in a linkbase (e.g. illegal pointer scheme).
128    #[error("Invalid XLink href '{href}': {reason}")]
129    InvalidHref { href: String, reason: String },
130
131    /// Invalid schema document
132    #[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 resolving schema
139    #[error("Error resolving schema: {reason}")]
140    InvalidSchemaResolution { reason: String },
141
142    // Invalid instance document
143    #[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    /// Invalid linkbase document
150    #[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 resolving linkbase
157    #[error("Error resolving linkbase: {reason}")]
158    InvalidLinkbaseResolution { reason: String },
159
160    /// A string value could not be parsed as the expected XBRL type.
161    #[error("invalid {expected} value '{value}'")]
162    ParseError {
163        expected: &'static str,
164        value: String,
165    },
166
167    /// Error while converting or parsing typed fact values.
168    #[error(transparent)]
169    Value(#[from] ValueError),
170
171    /// IO error
172    #[error(transparent)]
173    Io(#[from] io::Error),
174
175    /// XML error
176    #[error(transparent)]
177    Xml(#[from] quick_xml::Error),
178
179    /// UTF-8 encoding error
180    #[error(transparent)]
181    Utf8(#[from] std::str::Utf8Error),
182
183    /// XML escape error
184    #[error(transparent)]
185    Escape(#[from] quick_xml::escape::EscapeError),
186}
187
188/// Result type alias for XBRL operations
189pub type Result<T> = std::result::Result<T, XbrlError>;