use {
crate::{
nodes::NodesWithState,
prefix::Prefix,
printer::PrinterInner,
writer::Writer,
Bluegum,
BluegumWithState,
Nodes,
},
std::borrow::BorrowMut,
};
pub(crate) type FieldDebug = Vec<(String, String)>;
#[derive(Debug, Clone)]
pub(crate) struct BuilderName {
pub(crate) name: String,
pub(crate) alt: Option<String>,
pub(crate) debug: FieldDebug,
}
#[derive(Debug, Clone)]
pub(crate) enum Field {
KeyValue {
name: String,
value: String,
alt: Option<String>,
debug: FieldDebug,
},
Divider,
}
impl Field {
pub(crate) fn set_alt(&mut self, alt: String) {
match self {
| Field::KeyValue { alt: ref mut a, .. } => *a = Some(alt),
| Field::Divider => (),
}
}
pub(crate) fn set_debug(&mut self, debug: (String, String)) {
match self {
| Field::KeyValue {
debug: ref mut d, ..
} => d.push(debug),
| Field::Divider => (),
}
}
}
pub(crate) type Fields = Vec<Field>;
#[derive(Debug, Clone)]
pub struct Builder {
pub(crate) name: BuilderName,
pub(crate) fields: Fields,
pub(crate) unlabled_nodes: Vec<Builder>,
pub(crate) nodes: Vec<(String, Vec<Builder>)>,
pub(crate) total_nodes_len: usize,
}
impl Builder {
pub fn new() -> Self {
Self {
name: BuilderName {
name: "".to_string(),
alt: None,
debug: vec![],
},
fields: Vec::new(),
nodes: Vec::new(),
unlabled_nodes: Vec::new(),
total_nodes_len: 0,
}
}
}
impl Default for Builder {
fn default() -> Self {
Self::new()
}
}
impl Builder {
pub fn render<T: Bluegum>(node: &T) -> Self {
let mut builder = Builder::new();
Bluegum::node(node, &mut builder);
builder
}
pub fn render_with_state<State: ?Sized, T: BluegumWithState<State>>(
node: &T,
state: &State,
) -> Self {
let mut builder = Builder::new();
<dyn BluegumWithState<State>>::node_with_state(node, &mut builder, state);
builder
}
}
impl Builder {
pub fn name(&mut self, name: &str) -> &mut Self {
self.name.name = name.to_string();
self
}
pub fn get_name(&self) -> &str {
&self.name.name
}
pub fn divider(&mut self) -> &mut Self {
self.fields.push(Field::Divider);
self
}
pub fn field(
&mut self,
name: &str,
value: impl std::fmt::Display,
) -> &mut Self {
self.fields.push(Field::KeyValue {
name: name.to_string(),
value: format!("{value}"),
alt: None,
debug: vec![],
});
self
}
pub fn option_field(
&mut self,
name: &str,
value: Option<impl std::fmt::Display>,
) -> &mut Self {
value.map(|val| self.field(name, val));
self
}
pub fn alt(&mut self, value: impl std::fmt::Display) -> &mut Self {
if self.fields.is_empty() {
self.name.alt = Some(format!("{value}"));
} else if let Some(mut last) = self.fields.last_mut() {
last.set_alt(format!("{value}"));
}
self
}
pub fn option_alt(
&mut self,
value: Option<impl std::fmt::Display>,
) -> &mut Self {
value.map(|val| self.alt(val));
self
}
pub fn debug(
&mut self,
name: &str,
value: impl std::fmt::Display,
) -> &mut Self {
if self.fields.is_empty() {
self.name.debug.push((name.to_string(), format!("{value}")));
} else if let Some(mut last) = self.fields.last_mut() {
last.set_debug((name.to_string(), format!("{value}")));
}
self
}
pub fn option_debug(
&mut self,
name: &str,
value: Option<impl std::fmt::Display>,
) -> &mut Self {
value.map(|val| self.debug(name, val));
self
}
pub fn add_node(&mut self, name: &str, node: &dyn Bluegum) -> &mut Self {
let mut builder = Builder::new();
Bluegum::node(node, &mut builder);
self.total_nodes_len += 1;
self.nodes.push((name.to_string(), vec![builder]));
self
}
pub fn add_option_node(
&mut self,
name: &str,
node: Option<&dyn Bluegum>,
) -> &mut Self {
node.map(|n| self.add_node(name, n));
self
}
pub fn add_node_with_state<State: ?Sized, T: BluegumWithState<State>>(
&mut self,
state: &State,
name: &str,
c: &T,
) -> &mut Self {
let mut builder = Builder::new();
c.node_with_state(&mut builder, state);
self.total_nodes_len += 1;
self.nodes.push((name.to_string(), vec![builder]));
self
}
pub fn add_unlabled_node(&mut self, node: &dyn Bluegum) -> &mut Self {
let mut builder = Builder::new();
node.node(&mut builder);
self.total_nodes_len += 1;
self.unlabled_nodes.push(builder);
self
}
pub fn add_unlabled_node_with_state<State: ?Sized, T: BluegumWithState<State>>(
&mut self,
state: &State,
c: &T,
) -> &mut Self {
let mut builder = Builder::new();
c.node_with_state(&mut builder, state);
self.total_nodes_len += 1;
self.unlabled_nodes.push(builder);
self
}
pub fn add_option_node_with_state<State: ?Sized, T: BluegumWithState<State>>(
&mut self,
state: &State,
name: &str,
node: Option<&T>,
) -> &mut Self {
node.map(|n| self.add_node_with_state(state, name, n));
self
}
pub fn add_nodes<'a>(
&mut self,
name: &str,
nodes: impl Nodes<'a>,
) -> &mut Self {
let c = nodes.render();
self.total_nodes_len += c.len();
self.nodes.push((name.to_string(), c));
self
}
pub fn add_option_nodes<'a>(
&mut self,
name: &str,
nodes: Option<impl Nodes<'a>>,
) -> &mut Self {
nodes.map(|nds| self.add_nodes(name, nds));
self
}
pub fn add_nodes_with_state<'a, State: ?Sized>(
&mut self,
state: &State,
name: &str,
nodes: impl NodesWithState<'a, State>,
) -> &mut Self {
let c = nodes.render_with_state(state);
self.total_nodes_len += c.len();
self.nodes.push((name.to_string(), c));
self
}
pub fn add_nodes_of_builders(
&mut self,
name: &str,
nodes: Vec<Builder>,
) -> &mut Self {
self.total_nodes_len += nodes.len();
self.nodes.push((name.to_string(), nodes));
self
}
pub fn add_builders(&mut self, builders: Vec<Builder>) -> &mut Self {
self.total_nodes_len += builders.len();
self.unlabled_nodes.extend(builders);
self
}
pub fn add_builder(&mut self, builder: Builder) -> &mut Self {
self.total_nodes_len += 1;
self.unlabled_nodes.push(builder);
self
}
pub fn add_named_builder(&mut self, name: &str, node: Builder) -> &mut Self {
self.total_nodes_len += 1;
self.nodes.push((name.to_string(), vec![node]));
self
}
}