use super::{AtomicFragment, CodeFragment, NestedFragment};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Default)]
pub struct FunctionCallFragment {
pub call: AtomicFragment,
pub arguments: Vec<Rc<RefCell<dyn CodeFragment>>>,
pub is_macro: bool,
}
impl FunctionCallFragment {
pub fn new(name: AtomicFragment) -> Self {
Self {
call: name,
..Self::default()
}
}
pub fn add_argument(&mut self, argument: Rc<RefCell<dyn CodeFragment>>) {
self.arguments.push(argument);
}
pub fn add_argument_str(&mut self, argument: &str) {
self.add_argument(Rc::new(RefCell::new(AtomicFragment::new(
argument.to_owned(),
))));
}
pub fn mark_macro(&mut self) {
self.is_macro = true;
}
}
impl CodeFragment for FunctionCallFragment {
fn body(&self, line_width: usize) -> String {
let preamble = if self.is_macro {
format!("{}!(", self.call.atom)
} else {
format!("{}(", self.call.atom)
};
let mut nested = NestedFragment::new(AtomicFragment::new(preamble), ");");
nested.set_separator(", ");
if !self.is_macro {
nested.set_nesting_postfix(",");
}
for arg in &self.arguments {
nested.append(arg.clone());
}
nested.body(line_width)
}
fn imports(&self) -> Vec<String> {
let mut imports = self.call.imports();
for arg in &self.arguments {
imports.append(&mut arg.borrow().imports());
}
imports
}
}
#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
#[test]
fn test_empty_call() {
let f = FunctionCallFragment::new(AtomicFragment::new("foo".to_owned()));
assert_eq!(f.body(80), "foo();");
}
#[test]
fn test_call_arguments() {
let mut f = FunctionCallFragment::new(AtomicFragment::new("foo".to_owned()));
f.add_argument(Rc::new(RefCell::new(AtomicFragment::new("bar".to_owned()))));
f.add_argument(Rc::new(RefCell::new(AtomicFragment::new("baz".to_owned()))));
assert_eq!(f.body(80), "foo(bar, baz);");
}
#[test]
fn test_call_arguments_multiline() {
let mut f = FunctionCallFragment::new(AtomicFragment::new("foo".to_owned()));
f.add_argument(Rc::new(RefCell::new(AtomicFragment::new("bar".to_owned()))));
f.add_argument(Rc::new(RefCell::new(AtomicFragment::new("baz".to_owned()))));
assert_eq!(
f.body(8),
indoc! {"
foo(
bar,
baz,
);"}
);
}
#[test]
fn test_call_macro_multiline() {
let mut f = FunctionCallFragment::new(AtomicFragment::new("assert_eq".to_owned()));
f.mark_macro();
f.add_argument(Rc::new(RefCell::new(AtomicFragment::new("bar".to_owned()))));
f.add_argument(Rc::new(RefCell::new(AtomicFragment::new("baz".to_owned()))));
assert_eq!(
f.body(8),
indoc! {"
assert_eq!(
bar,
baz
);"}
);
}
}