php_codegen/
body.rs

1use std::fmt::Debug;
2
3use crate::Generator;
4use crate::Indentation;
5
6pub struct Body {
7    pub factory: Option<Box<dyn Fn(Indentation, usize) -> String>>,
8    pub semicolon_for_empty: bool,
9}
10
11impl Body {
12    pub fn new() -> Self {
13        Self {
14            factory: None,
15            semicolon_for_empty: true,
16        }
17    }
18
19    pub fn with_factory<T: Fn(Indentation, usize) -> String + 'static>(factory: T) -> Self {
20        Self {
21            factory: Some(Box::new(factory)),
22            semicolon_for_empty: true,
23        }
24    }
25
26    pub fn with_semicolon_for_empty(mut self, semicolon_for_empty: bool) -> Self {
27        self.semicolon_for_empty = semicolon_for_empty;
28
29        self
30    }
31}
32
33impl Debug for Body {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        f.debug_struct("Body")
36            .field("factory:is-some", &self.factory.is_some())
37            .field("semicolon_for_empty", &self.semicolon_for_empty)
38            .finish()
39    }
40}
41
42impl Generator for Body {
43    fn generate(&self, indentation: Indentation, level: usize) -> String {
44        match self.factory {
45            Some(ref factory) => {
46                let mut code = String::new();
47
48                code.push_str(" {");
49                code.push('\n');
50                code.push_str(&factory(indentation, level + 1));
51                code.push('\n');
52                code.push_str(&indentation.indent("}", level));
53                code.push('\n');
54
55                code
56            }
57            None => {
58                let mut code = String::new();
59
60                if self.semicolon_for_empty {
61                    code.push(';');
62                } else {
63                    code.push_str(" {}");
64                }
65
66                code.push('\n');
67
68                code
69            }
70        }
71    }
72}
73
74impl<T: ToString> From<Vec<T>> for Body {
75    fn from(body: Vec<T>) -> Self {
76        let body = body
77            .iter()
78            .map(|line| line.to_string())
79            .collect::<Vec<String>>();
80
81        Self {
82            factory: Some(Box::new(move |indentation, level| {
83                let body = body.clone();
84
85                body.iter()
86                    .map(|line| indentation.indent(line.to_string(), level))
87                    .collect::<Vec<String>>()
88                    .join("\n")
89            })),
90            semicolon_for_empty: true,
91        }
92    }
93}
94
95impl From<String> for Body {
96    fn from(body: String) -> Self {
97        Self {
98            factory: Some(Box::new(move |indentation, level| {
99                let body = body.clone();
100
101                indentation.indent(body, level)
102            })),
103            semicolon_for_empty: true,
104        }
105    }
106}
107
108impl From<&str> for Body {
109    fn from(body: &str) -> Self {
110        body.to_string().into()
111    }
112}
113
114impl<T: Fn(Indentation, usize) -> String + 'static> From<T> for Body {
115    fn from(factory: T) -> Self {
116        Self {
117            factory: Some(Box::new(factory)),
118            semicolon_for_empty: true,
119        }
120    }
121}
122
123impl From<Option<Box<dyn Fn(Indentation, usize) -> String>>> for Body {
124    fn from(factory: Option<Box<dyn Fn(Indentation, usize) -> String>>) -> Self {
125        Self {
126            factory,
127            semicolon_for_empty: true,
128        }
129    }
130}
131
132impl From<Option<String>> for Body {
133    fn from(body: Option<String>) -> Self {
134        match body {
135            Some(body) => body.into(),
136            None => Self {
137                factory: None,
138                semicolon_for_empty: true,
139            },
140        }
141    }
142}
143
144impl Default for Body {
145    fn default() -> Self {
146        Self {
147            factory: None,
148            semicolon_for_empty: true,
149        }
150    }
151}