spinoso_exception/core/
syntaxerror.rs1use alloc::borrow::Cow;
4use alloc::string::String;
5use alloc::vec::Vec;
6use core::error;
7use core::fmt;
8
9use bstr::ByteSlice;
10use scolapasta_string_escape::format_debug_escape_into;
11
12use crate::RubyException;
13
14#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
27pub struct SyntaxError {
28 message: Cow<'static, [u8]>,
29}
30
31impl fmt::Debug for SyntaxError {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.debug_struct("SyntaxError")
34 .field("message", &self.message().as_bstr())
35 .finish()
36 }
37}
38
39impl SyntaxError {
40 #[inline]
52 #[must_use]
53 pub const fn new() -> Self {
54 const DEFAULT_MESSAGE: &[u8] = b"SyntaxError";
55
56 let message = Cow::Borrowed(DEFAULT_MESSAGE);
60 Self { message }
61 }
62
63 #[inline]
74 #[must_use]
75 pub const fn with_message(message: &'static str) -> Self {
76 let message = Cow::Borrowed(message.as_bytes());
77 Self { message }
78 }
79
80 #[inline]
92 #[must_use]
93 pub fn message(&self) -> &[u8] {
94 self.message.as_ref()
95 }
96
97 #[inline]
107 #[must_use]
108 pub const fn name(&self) -> &'static str {
109 "SyntaxError"
110 }
111}
112
113impl From<String> for SyntaxError {
114 #[inline]
115 fn from(message: String) -> Self {
116 let message = Cow::Owned(message.into_bytes());
117 Self { message }
118 }
119}
120
121impl From<&'static str> for SyntaxError {
122 #[inline]
123 fn from(message: &'static str) -> Self {
124 let message = Cow::Borrowed(message.as_bytes());
125 Self { message }
126 }
127}
128
129impl From<Cow<'static, str>> for SyntaxError {
130 #[inline]
131 fn from(message: Cow<'static, str>) -> Self {
132 let message = match message {
133 Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
134 Cow::Owned(s) => Cow::Owned(s.into_bytes()),
135 };
136 Self { message }
137 }
138}
139
140impl From<Vec<u8>> for SyntaxError {
141 #[inline]
142 fn from(message: Vec<u8>) -> Self {
143 let message = Cow::Owned(message);
144 Self { message }
145 }
146}
147
148impl From<&'static [u8]> for SyntaxError {
149 #[inline]
150 fn from(message: &'static [u8]) -> Self {
151 let message = Cow::Borrowed(message);
152 Self { message }
153 }
154}
155
156impl From<Cow<'static, [u8]>> for SyntaxError {
157 #[inline]
158 fn from(message: Cow<'static, [u8]>) -> Self {
159 Self { message }
160 }
161}
162
163impl fmt::Display for SyntaxError {
164 #[inline]
165 fn fmt(&self, mut f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 f.write_str(self.name())?;
167 f.write_str(" (")?;
168 let message = self.message.as_ref();
169 format_debug_escape_into(&mut f, message)?;
170 f.write_str(")")?;
171 Ok(())
172 }
173}
174
175impl error::Error for SyntaxError {}
176
177impl RubyException for SyntaxError {
178 #[inline]
179 fn message(&self) -> Cow<'_, [u8]> {
180 Cow::Borrowed(Self::message(self))
181 }
182
183 #[inline]
184 fn name(&self) -> Cow<'_, str> {
185 Cow::Borrowed(Self::name(self))
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use alloc::borrow::Cow;
192 use alloc::format;
193 use alloc::string::ToString;
194 use core::cmp::Ordering;
195 use core::error;
196
197 use bstr::ByteSlice;
198
199 use super::*;
200
201 #[test]
202 fn test_new() {
203 let exception = SyntaxError::new();
204 assert_eq!(exception.message().as_bstr(), b"SyntaxError".as_bstr());
205 assert_eq!(exception.name(), "SyntaxError");
206 }
207
208 #[test]
209 fn test_with_message() {
210 let custom_message = "custom message";
211 let exception = SyntaxError::with_message(custom_message);
212 assert_eq!(exception.message().as_bstr(), custom_message.as_bytes().as_bstr());
213 assert_eq!(exception.name(), "SyntaxError");
215 }
216
217 #[test]
218 fn test_from_string() {
219 let message = "from String".to_string();
220 let exception: SyntaxError = message.into();
221 assert_eq!(exception.message().as_bstr(), b"from String".as_bstr());
222 }
223
224 #[test]
225 fn test_from_static_str() {
226 let message: &'static str = "from &'static str";
227 let exception: SyntaxError = message.into();
228 assert_eq!(exception.message().as_bstr(), b"from &'static str".as_bstr());
229 }
230
231 #[test]
232 fn test_from_cow_str_borrowed() {
233 let cow: Cow<'static, str> = Cow::Borrowed("from Cow borrowed");
234 let exception: SyntaxError = cow.into();
235 assert_eq!(exception.message().as_bstr(), b"from Cow borrowed".as_bstr());
236 }
237
238 #[test]
239 fn test_from_cow_str_owned() {
240 let cow: Cow<'static, str> = Cow::Owned("from Cow owned".to_string());
241 let exception: SyntaxError = cow.into();
242 assert_eq!(exception.message().as_bstr(), b"from Cow owned".as_bstr());
243 }
244
245 #[test]
246 fn test_from_vec_u8() {
247 let vec = b"from Vec<u8>".to_vec();
248 let exception: SyntaxError = vec.into();
249 assert_eq!(exception.message().as_bstr(), b"from Vec<u8>".as_bstr());
250 }
251
252 #[test]
253 fn test_from_static_slice() {
254 let slice: &'static [u8] = b"from &'static [u8]";
255 let exception: SyntaxError = slice.into();
256 assert_eq!(exception.message().as_bstr(), b"from &'static [u8]".as_bstr());
257 }
258
259 #[test]
260 fn test_from_cow_u8_borrowed() {
261 let cow: Cow<'static, [u8]> = Cow::Borrowed(b"from Cow<u8> borrowed");
262 let exception: SyntaxError = cow.into();
263 assert_eq!(exception.message().as_bstr(), b"from Cow<u8> borrowed".as_bstr());
264 }
265
266 #[test]
267 fn test_from_cow_u8_owned() {
268 let cow: Cow<'static, [u8]> = Cow::Owned(b"from Cow<u8> owned".to_vec());
269 let exception: SyntaxError = cow.into();
270 assert_eq!(exception.message().as_bstr(), b"from Cow<u8> owned".as_bstr());
271 }
272
273 #[test]
274 fn test_debug() {
275 let exception = SyntaxError::with_message("display test");
276 let output = format!("{exception:?}");
277 assert!(output.contains("SyntaxError"));
279 assert!(output.contains("display test"));
280 assert!(output.starts_with("SyntaxError {"));
282 assert!(output.ends_with('}'));
283 }
284
285 #[test]
286 fn test_display() {
287 let exception = SyntaxError::with_message("display test");
288 let output = format!("{exception}");
289 assert!(output.contains("SyntaxError"));
291 assert!(output.contains("display test"));
292 assert!(output.starts_with("SyntaxError ("));
294 assert!(output.ends_with(')'));
295 }
296
297 #[test]
298 fn test_error_trait() {
299 let exception = SyntaxError::with_message("error trait test");
300 let error_obj: &dyn error::Error = &exception;
301 assert!(error_obj.source().is_none());
303 assert_eq!(error_obj.to_string(), format!("{exception}"));
305 }
306
307 #[test]
308 fn test_ruby_exception_trait() {
309 let exception = SyntaxError::with_message("ruby trait test");
310 let msg = RubyException::message(&exception);
311 let name = RubyException::name(&exception);
312 assert_eq!(msg.as_bstr(), exception.message().as_bstr());
313 assert_eq!(name, exception.name());
314 }
315
316 #[test]
317 fn test_default() {
318 let default_error = SyntaxError::default();
319 assert_eq!(default_error.message(), b"");
321 assert_eq!(default_error.name(), "SyntaxError");
323 }
324
325 #[test]
326 fn test_clone() {
327 let original = SyntaxError::with_message("clone test");
328 let cloned = original.clone();
329 assert_eq!(original, cloned, "Cloned error should be equal to the original");
330 }
331
332 #[test]
333 fn test_partial_eq() {
334 let error_a = SyntaxError::with_message("test message");
335 let error_b = SyntaxError::with_message("test message");
336 let error_c = SyntaxError::with_message("different message");
337 assert_eq!(error_a, error_b, "Errors with the same message should be equal");
338 assert_ne!(error_a, error_c, "Errors with different messages should not be equal");
339 }
340
341 #[test]
342 fn test_partial_ord() {
343 let error_a = SyntaxError::with_message("aaa");
344 let error_b = SyntaxError::with_message("bbb");
345 assert_eq!(error_a.partial_cmp(&error_a), Some(Ordering::Equal));
347 assert_eq!(error_a.partial_cmp(&error_b), Some(Ordering::Less));
349 assert_eq!(error_b.partial_cmp(&error_a), Some(Ordering::Greater));
350 }
351
352 #[test]
353 fn test_ord() {
354 let error_a = SyntaxError::with_message("aaa");
355 let error_b = SyntaxError::with_message("bbb");
356 assert_eq!(error_a.cmp(&error_a), Ordering::Equal);
358 assert_eq!(error_a.cmp(&error_b), Ordering::Less);
360 assert_eq!(error_b.cmp(&error_a), Ordering::Greater);
361 }
362}