1use core::fmt;
4
5use alloc::vec::Vec;
6
7use super::{Comment, Field, List};
8
9#[derive(Debug, Clone, Eq)]
11pub struct Error<'a> {
12 name: &'a str,
14 fields: List<'a, Field<'a>>,
16 comments: List<'a, Comment<'a>>,
18}
19
20impl<'a> Error<'a> {
21 pub const fn new(
23 name: &'a str,
24 fields: &'a [&'a Field<'a>],
25 comments: &'a [&'a Comment<'a>],
26 ) -> Self {
27 Self {
28 name,
29 fields: List::Borrowed(fields),
30 comments: List::Borrowed(comments),
31 }
32 }
33
34 pub fn new_owned(name: &'a str, fields: Vec<Field<'a>>, comments: Vec<Comment<'a>>) -> Self {
37 Self {
38 name,
39 fields: List::from(fields),
40 comments: List::from(comments),
41 }
42 }
43
44 pub fn name(&self) -> &'a str {
46 self.name
47 }
48
49 pub fn fields(&self) -> impl Iterator<Item = &Field<'a>> {
51 self.fields.iter()
52 }
53
54 pub fn has_no_fields(&self) -> bool {
56 self.fields.is_empty()
57 }
58
59 pub fn comments(&self) -> impl Iterator<Item = &Comment<'a>> {
61 self.comments.iter()
62 }
63}
64
65impl<'a> fmt::Display for Error<'a> {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 for comment in self.comments.iter() {
69 writeln!(f, "{comment}")?;
70 }
71 write!(f, "error {} (", self.name)?;
72 let mut first = true;
73 for field in self.fields.iter() {
74 if !first {
75 write!(f, ", ")?;
76 }
77 first = false;
78 write!(f, "{field}")?;
79 }
80 write!(f, ")")
81 }
82}
83
84impl<'a> PartialEq for Error<'a> {
85 fn eq(&self, other: &Self) -> bool {
86 self.name == other.name && self.fields == other.fields
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use crate::idl::Type;
94
95 #[test]
96 fn error_creation() {
97 let message_field = Field::new("message", &Type::String, &[]);
98 let code_field = Field::new("code", &Type::Int, &[]);
99 let fields = [&message_field, &code_field];
100
101 let error = Error::new("InvalidInput", &fields, &[]);
102 assert_eq!(error.name(), "InvalidInput");
103 assert_eq!(error.fields().count(), 2);
104 assert!(!error.has_no_fields());
105
106 let fields_vec: Vec<_> = error.fields().collect();
108 assert_eq!(fields_vec[0].name(), "message");
109 assert_eq!(fields_vec[0].ty(), &Type::String);
110 assert_eq!(fields_vec[1].name(), "code");
111 assert_eq!(fields_vec[1].ty(), &Type::Int);
112 }
113
114 #[test]
115 fn error_no_fields() {
116 let error = Error::new("UnknownError", &[], &[]);
117 assert_eq!(error.name(), "UnknownError");
118 assert!(error.has_no_fields());
119 }
120
121 #[test]
122 fn display_with_comments() {
123 use crate::idl::Comment;
124 use core::fmt::Write;
125
126 let comment1 = Comment::new("Authentication failed");
127 let comment2 = Comment::new("Invalid credentials provided");
128 let comments = [&comment1, &comment2];
129
130 let message_field = Field::new("message", &Type::String, &[]);
131 let code_field = Field::new("code", &Type::Int, &[]);
132 let fields = [&message_field, &code_field];
133
134 let error = Error::new("AuthError", &fields, &comments);
135 let mut displayed = String::new();
136 write!(&mut displayed, "{}", error).unwrap();
137 assert_eq!(
138 displayed,
139 "# Authentication failed\n# Invalid credentials provided\nerror AuthError (message: string, code: int)"
140 );
141 }
142}