1use std::{error::Error as StdError, fmt};
2
3pub type Result<T> = std::result::Result<T, Error>;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum ErrorKind {
10 Io,
12 Archive,
14 Xml,
16 InvalidData,
18 Unsupported,
20 LimitExceeded,
22 NoVisibleSheet,
24 MemoryBudgetExceeded,
26 SheetNotFound,
28 InvalidState,
30}
31
32pub struct Error {
35 details: Box<ErrorDetails>,
36}
37
38struct ErrorDetails {
39 kind: ErrorKind,
40 message: String,
41 part: Option<String>,
42 cell: Option<crate::CellAddress>,
43 source: Option<Box<dyn StdError + Send + Sync>>,
44}
45
46impl Error {
47 #[cold]
49 pub fn new(kind: ErrorKind, message: impl Into<String>) -> Self {
50 Self {
51 details: Box::new(ErrorDetails {
52 kind,
53 message: message.into(),
54 part: None,
55 cell: None,
56 source: None,
57 }),
58 }
59 }
60
61 #[cold]
63 pub fn caused_by(
64 kind: ErrorKind,
65 message: impl Into<String>,
66 source: impl StdError + Send + Sync + 'static,
67 ) -> Self {
68 let mut error = Self::new(kind, message);
69 error.details.source = Some(Box::new(source));
70 error
71 }
72
73 pub fn with_part(mut self, part: impl Into<String>) -> Self {
75 self.details.part = Some(part.into());
76 self
77 }
78
79 pub fn with_cell(mut self, cell: crate::CellAddress) -> Self {
81 self.details.cell = Some(cell);
82 self
83 }
84
85 pub fn kind(&self) -> ErrorKind {
87 self.details.kind
88 }
89 pub fn part(&self) -> Option<&str> {
91 self.details.part.as_deref()
92 }
93 pub fn cell(&self) -> Option<crate::CellAddress> {
95 self.details.cell
96 }
97}
98
99impl fmt::Display for Error {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 write!(f, "{}", self.details.message)?;
102 if let Some(part) = &self.details.part {
103 write!(f, " [part: {part}]")?;
104 }
105 if let Some(cell) = self.details.cell {
106 write!(f, " [cell: {cell}]")?;
107 }
108 Ok(())
109 }
110}
111
112impl StdError for Error {
113 fn source(&self) -> Option<&(dyn StdError + 'static)> {
114 self.details
115 .source
116 .as_deref()
117 .map(|e| e as &(dyn StdError + 'static))
118 }
119}
120
121impl fmt::Debug for Error {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 f.debug_struct("Error")
124 .field("kind", &self.details.kind)
125 .field("message", &self.details.message)
126 .field("part", &self.details.part)
127 .field("cell", &self.details.cell)
128 .field("source", &self.details.source)
129 .finish()
130 }
131}