1use std::fmt;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
20pub struct Loc {
21 pub line: u32,
22 pub column: u32,
23}
24
25impl Loc {
26 pub const UNKNOWN: Loc = Loc { line: 0, column: 0 };
28
29 pub const fn new(line: u32, column: u32) -> Self {
31 Self { line, column }
32 }
33
34 pub fn is_unknown(self) -> bool {
36 self.line == 0 && self.column == 0
37 }
38}
39
40impl fmt::Display for Loc {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 write!(f, "{}:{}", self.line, self.column)
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
48pub enum CssErrorKind {
49 InvalidColor(String),
51 InvalidSelector(String),
53 InvalidLength(String),
55 UndefinedVariable(String),
57 CircularVariable(String),
59 UnknownProperty(String),
61 Io(String),
63}
64
65impl fmt::Display for CssErrorKind {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::InvalidColor(v) => write!(f, "invalid color: {v}"),
69 Self::InvalidSelector(v) => write!(f, "invalid selector: {v}"),
70 Self::InvalidLength(v) => write!(f, "invalid length: {v}"),
71 Self::UndefinedVariable(v) => write!(f, "undefined variable: {v}"),
72 Self::CircularVariable(v) => write!(f, "circular variable reference: {v}"),
73 Self::UnknownProperty(v) => write!(f, "unknown property: {v}"),
74 Self::Io(v) => write!(f, "io error: {v}"),
75 }
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
86pub struct CssError {
87 pub kind: CssErrorKind,
88 pub loc: Option<Loc>,
89}
90
91impl CssError {
92 pub fn from_kind(kind: CssErrorKind) -> Self {
96 Self { kind, loc: None }
97 }
98
99 pub fn invalid_color(msg: impl Into<String>) -> Self {
100 Self::from_kind(CssErrorKind::InvalidColor(msg.into()))
101 }
102 pub fn invalid_selector(msg: impl Into<String>) -> Self {
103 Self::from_kind(CssErrorKind::InvalidSelector(msg.into()))
104 }
105 pub fn invalid_length(msg: impl Into<String>) -> Self {
106 Self::from_kind(CssErrorKind::InvalidLength(msg.into()))
107 }
108 pub fn undefined_variable(msg: impl Into<String>) -> Self {
109 Self::from_kind(CssErrorKind::UndefinedVariable(msg.into()))
110 }
111 pub fn circular_variable(msg: impl Into<String>) -> Self {
112 Self::from_kind(CssErrorKind::CircularVariable(msg.into()))
113 }
114 pub fn unknown_property(msg: impl Into<String>) -> Self {
116 Self::from_kind(CssErrorKind::UnknownProperty(msg.into()))
117 }
118 pub fn io(msg: impl Into<String>) -> Self {
119 Self::from_kind(CssErrorKind::Io(msg.into()))
120 }
121
122 pub fn at(mut self, line: u32, column: u32) -> Self {
126 self.loc = Some(Loc::new(line, column));
127 self
128 }
129
130 pub fn with_loc(mut self, loc: Loc) -> Self {
132 self.loc = Some(loc);
133 self
134 }
135
136 pub fn kind(&self) -> &CssErrorKind {
138 &self.kind
139 }
140}
141
142impl fmt::Display for CssError {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 match self.loc {
145 Some(loc) if !loc.is_unknown() => write!(f, "{} at line {}:{}", self.kind, loc.line, loc.column),
146 _ => write!(f, "{}", self.kind),
147 }
148 }
149}
150
151impl std::error::Error for CssError {}
152
153pub type Result<T> = std::result::Result<T, CssError>;