use core::fmt;
use alloc::vec::Vec;
use super::{Comment, List, Parameter};
#[derive(Debug, Clone, Eq)]
pub struct Method<'a> {
name: &'a str,
inputs: List<'a, Parameter<'a>>,
outputs: List<'a, Parameter<'a>>,
comments: List<'a, Comment<'a>>,
}
impl<'a> Method<'a> {
pub const fn new(
name: &'a str,
inputs: &'a [&'a Parameter<'a>],
outputs: &'a [&'a Parameter<'a>],
comments: &'a [&'a Comment<'a>],
) -> Self {
Self {
name,
inputs: List::Borrowed(inputs),
outputs: List::Borrowed(outputs),
comments: List::Borrowed(comments),
}
}
pub fn new_owned(
name: &'a str,
inputs: Vec<Parameter<'a>>,
outputs: Vec<Parameter<'a>>,
comments: Vec<Comment<'a>>,
) -> Self {
Self {
name,
inputs: List::from(inputs),
outputs: List::from(outputs),
comments: List::from(comments),
}
}
pub fn name(&self) -> &'a str {
self.name
}
pub fn inputs(&self) -> impl Iterator<Item = &Parameter<'a>> {
self.inputs.iter()
}
pub fn outputs(&self) -> impl Iterator<Item = &Parameter<'a>> {
self.outputs.iter()
}
pub fn has_no_inputs(&self) -> bool {
self.inputs.is_empty()
}
pub fn has_no_outputs(&self) -> bool {
self.outputs.is_empty()
}
pub fn comments(&self) -> impl Iterator<Item = &Comment<'a>> {
self.comments.iter()
}
}
impl<'a> fmt::Display for Method<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for comment in self.comments.iter() {
writeln!(f, "{comment}")?;
}
write!(f, "method {}(", self.name)?;
let mut first = true;
for param in self.inputs.iter() {
if !first {
write!(f, ", ")?;
}
first = false;
write!(f, "{param}")?;
}
write!(f, ")")?;
write!(f, " -> (")?;
let mut first = true;
for param in self.outputs.iter() {
if !first {
write!(f, ", ")?;
}
first = false;
write!(f, "{param}")?;
}
write!(f, ")")?;
Ok(())
}
}
impl PartialEq for Method<'_> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.inputs == other.inputs && self.outputs == other.outputs
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::idl::{Parameter, Type};
#[test]
fn method_creation() {
let input = Parameter::new("id", &Type::Int, &[]);
let output = Parameter::new("name", &Type::String, &[]);
let inputs = [&input];
let outputs = [&output];
let method = Method::new("GetName", &inputs, &outputs, &[]);
assert_eq!(method.name(), "GetName");
assert_eq!(method.inputs().count(), 1);
assert_eq!(method.outputs().count(), 1);
assert!(!method.has_no_inputs());
assert!(!method.has_no_outputs());
let inputs_vec: Vec<_> = method.inputs().collect();
assert_eq!(inputs_vec[0].name(), "id");
assert_eq!(inputs_vec[0].ty(), &Type::Int);
let outputs_vec: Vec<_> = method.outputs().collect();
assert_eq!(outputs_vec[0].name(), "name");
assert_eq!(outputs_vec[0].ty(), &Type::String);
}
#[test]
fn method_no_params() {
let method = Method::new("Ping", &[], &[], &[]);
assert_eq!(method.name(), "Ping");
assert!(method.has_no_inputs());
assert!(method.has_no_outputs());
}
#[test]
fn method_display_with_no_outputs() {
use core::fmt::Write;
let method = Method::new("Ping", &[], &[], &[]);
let mut displayed = String::new();
write!(&mut displayed, "{}", method).unwrap();
assert_eq!(displayed, "method Ping() -> ()");
let name_param = Parameter::new("name", &Type::String, &[]);
let id_param = Parameter::new("id", &Type::String, &[]);
let params = [&name_param, &id_param];
let method = Method::new("Register", ¶ms, &[], &[]);
let mut displayed = String::new();
write!(&mut displayed, "{}", method).unwrap();
assert_eq!(displayed, "method Register(name: string, id: string) -> ()");
}
#[test]
fn display_with_comments() {
use crate::idl::Comment;
use core::fmt::Write;
let comment1 = Comment::new("Get user information");
let comment2 = Comment::new("Returns user details by ID");
let comments = [&comment1, &comment2];
let input = Parameter::new("id", &Type::Int, &[]);
let output = Parameter::new("user", &Type::Custom("User"), &[]);
let inputs = [&input];
let outputs = [&output];
let method = Method::new("GetUser", &inputs, &outputs, &comments);
let mut displayed = String::new();
write!(&mut displayed, "{}", method).unwrap();
assert_eq!(
displayed,
"# Get user information\n# Returns user details by ID\nmethod GetUser(id: int) -> (user: User)"
);
}
}