1use core::fmt;
4
5use alloc::vec::Vec;
6
7use super::{Comment, List, Parameter};
8
9#[derive(Debug, Clone, Eq)]
11pub struct Method<'a> {
12 name: &'a str,
14 inputs: List<'a, Parameter<'a>>,
16 outputs: List<'a, Parameter<'a>>,
18 comments: List<'a, Comment<'a>>,
20}
21
22impl<'a> Method<'a> {
23 pub const fn new(
25 name: &'a str,
26 inputs: &'a [&'a Parameter<'a>],
27 outputs: &'a [&'a Parameter<'a>],
28 comments: &'a [&'a Comment<'a>],
29 ) -> Self {
30 Self {
31 name,
32 inputs: List::Borrowed(inputs),
33 outputs: List::Borrowed(outputs),
34 comments: List::Borrowed(comments),
35 }
36 }
37
38 pub fn new_owned(
40 name: &'a str,
41 inputs: Vec<Parameter<'a>>,
42 outputs: Vec<Parameter<'a>>,
43 comments: Vec<Comment<'a>>,
44 ) -> Self {
45 Self {
46 name,
47 inputs: List::from(inputs),
48 outputs: List::from(outputs),
49 comments: List::from(comments),
50 }
51 }
52
53 pub fn name(&self) -> &'a str {
55 self.name
56 }
57
58 pub fn inputs(&self) -> impl Iterator<Item = &Parameter<'a>> {
60 self.inputs.iter()
61 }
62
63 pub fn outputs(&self) -> impl Iterator<Item = &Parameter<'a>> {
65 self.outputs.iter()
66 }
67
68 pub fn has_no_inputs(&self) -> bool {
70 self.inputs.is_empty()
71 }
72
73 pub fn has_no_outputs(&self) -> bool {
75 self.outputs.is_empty()
76 }
77
78 pub fn comments(&self) -> impl Iterator<Item = &Comment<'a>> {
80 self.comments.iter()
81 }
82}
83
84impl<'a> fmt::Display for Method<'a> {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 for comment in self.comments.iter() {
88 writeln!(f, "{comment}")?;
89 }
90 write!(f, "method {}(", self.name)?;
91 let mut first = true;
92 for param in self.inputs.iter() {
93 if !first {
94 write!(f, ", ")?;
95 }
96 first = false;
97 write!(f, "{param}")?;
98 }
99 write!(f, ")")?;
100
101 write!(f, " -> (")?;
102 let mut first = true;
103 for param in self.outputs.iter() {
104 if !first {
105 write!(f, ", ")?;
106 }
107 first = false;
108 write!(f, "{param}")?;
109 }
110 write!(f, ")")?;
111
112 Ok(())
113 }
114}
115
116impl PartialEq for Method<'_> {
117 fn eq(&self, other: &Self) -> bool {
118 self.name == other.name && self.inputs == other.inputs && self.outputs == other.outputs
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use crate::idl::{Parameter, Type};
126
127 #[test]
128 fn method_creation() {
129 let input = Parameter::new("id", &Type::Int, &[]);
130 let output = Parameter::new("name", &Type::String, &[]);
131 let inputs = [&input];
132 let outputs = [&output];
133
134 let method = Method::new("GetName", &inputs, &outputs, &[]);
135 assert_eq!(method.name(), "GetName");
136 assert_eq!(method.inputs().count(), 1);
137 assert_eq!(method.outputs().count(), 1);
138 assert!(!method.has_no_inputs());
139 assert!(!method.has_no_outputs());
140
141 let inputs_vec: Vec<_> = method.inputs().collect();
143 assert_eq!(inputs_vec[0].name(), "id");
144 assert_eq!(inputs_vec[0].ty(), &Type::Int);
145
146 let outputs_vec: Vec<_> = method.outputs().collect();
147 assert_eq!(outputs_vec[0].name(), "name");
148 assert_eq!(outputs_vec[0].ty(), &Type::String);
149 }
150
151 #[test]
152 fn method_no_params() {
153 let method = Method::new("Ping", &[], &[], &[]);
154 assert_eq!(method.name(), "Ping");
155 assert!(method.has_no_inputs());
156 assert!(method.has_no_outputs());
157 }
158
159 #[test]
160 fn method_display_with_no_outputs() {
161 use core::fmt::Write;
162
163 let method = Method::new("Ping", &[], &[], &[]);
164 let mut displayed = String::new();
165 write!(&mut displayed, "{}", method).unwrap();
166 assert_eq!(displayed, "method Ping() -> ()");
167
168 let name_param = Parameter::new("name", &Type::String, &[]);
169 let id_param = Parameter::new("id", &Type::String, &[]);
170 let params = [&name_param, &id_param];
171 let method = Method::new("Register", ¶ms, &[], &[]);
172 let mut displayed = String::new();
173 write!(&mut displayed, "{}", method).unwrap();
174 assert_eq!(displayed, "method Register(name: string, id: string) -> ()");
175 }
176
177 #[test]
178 fn display_with_comments() {
179 use crate::idl::Comment;
180 use core::fmt::Write;
181
182 let comment1 = Comment::new("Get user information");
183 let comment2 = Comment::new("Returns user details by ID");
184 let comments = [&comment1, &comment2];
185
186 let input = Parameter::new("id", &Type::Int, &[]);
187 let output = Parameter::new("user", &Type::Custom("User"), &[]);
188 let inputs = [&input];
189 let outputs = [&output];
190
191 let method = Method::new("GetUser", &inputs, &outputs, &comments);
192 let mut displayed = String::new();
193 write!(&mut displayed, "{}", method).unwrap();
194 assert_eq!(displayed, "# Get user information\n# Returns user details by ID\nmethod GetUser(id: int) -> (user: User)");
195 }
196}