use std::fmt::Write;
#[derive(Debug, Default)]
pub struct RustFileBuilder {
doc_header: Option<String>,
imports: Vec<String>,
items: Vec<String>,
}
impl RustFileBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_generated_header(mut self) -> Self {
self.doc_header = Some(
"// This file is auto-generated by alef. DO NOT EDIT.\n\
// Re-generate with: alef generate\n"
.to_string(),
);
self
}
pub fn add_inner_attribute(&mut self, attr: &str) {
if let Some(ref mut header) = self.doc_header {
header.push_str(&format!("#![{attr}]\n"));
} else {
self.doc_header = Some(format!("#![{attr}]\n"));
}
}
pub fn add_import(&mut self, import: &str) {
if !import.contains("::") && !import.contains('*') && !import.contains('{') {
return;
}
if !self.imports.iter().any(|i| i == import) {
self.imports.push(import.to_string());
}
}
pub fn add_item(&mut self, item: &str) {
self.items.push(item.to_string());
}
pub fn build(&self) -> String {
let mut capacity = 256; if let Some(header) = &self.doc_header {
capacity += header.len() + 1;
}
capacity += self.imports.iter().map(|i| i.len() + 6).sum::<usize>(); capacity += self.items.iter().map(|i| i.len() + 2).sum::<usize>();
let mut out = String::with_capacity(capacity);
if let Some(header) = &self.doc_header {
out.push_str(header);
out.push('\n');
}
if !self.imports.is_empty() {
for import in &self.imports {
writeln!(out, "use {import};").ok();
}
out.push('\n');
}
for (i, item) in self.items.iter().enumerate() {
out.push_str(item);
if i < self.items.len() - 1 {
out.push_str("\n\n");
}
}
if !out.ends_with('\n') {
out.push('\n');
}
out
}
}
pub struct StructBuilder {
attrs: Vec<String>,
visibility: String,
name: String,
derives: Vec<String>,
fields: Vec<(String, String, Vec<String>, String)>, }
impl StructBuilder {
pub fn new(name: &str) -> Self {
Self {
attrs: vec![],
visibility: String::from("pub"),
name: name.to_string(),
derives: vec![],
fields: vec![],
}
}
pub fn add_attr(&mut self, attr: &str) -> &mut Self {
self.attrs.push(attr.to_string());
self
}
pub fn add_derive(&mut self, derive: &str) -> &mut Self {
if !self.derives.iter().any(|d| d == derive) {
self.derives.push(derive.to_string());
}
self
}
pub fn add_field(&mut self, name: &str, ty: &str, attrs: Vec<String>) -> &mut Self {
self.add_field_with_doc(name, ty, attrs, "")
}
pub fn add_field_with_doc(&mut self, name: &str, ty: &str, attrs: Vec<String>, doc: &str) -> &mut Self {
self.fields
.push((name.to_string(), ty.to_string(), attrs, doc.to_string()));
self
}
pub fn build(&self) -> String {
let mut capacity = 128; capacity += self.derives.iter().map(|d| d.len() + 2).sum::<usize>(); capacity += self.attrs.iter().map(|a| a.len() + 5).sum::<usize>(); capacity += self.name.len() + self.visibility.len() + 16; capacity += self
.fields
.iter()
.map(|(n, t, attrs, doc)| {
n.len() + t.len() + 12 + doc.len() + 8 + attrs.iter().map(|a| a.len() + 5).sum::<usize>()
})
.sum::<usize>();
let mut out = String::with_capacity(capacity);
if !self.derives.is_empty() {
writeln!(out, "#[derive({})]", self.derives.join(", ")).ok();
}
for attr in &self.attrs {
writeln!(out, "#[{attr}]").ok();
}
writeln!(out, "{} struct {} {{", self.visibility, self.name).ok();
for (name, ty, attrs, doc) in &self.fields {
if !doc.is_empty() {
for line in doc.lines() {
writeln!(out, " /// {line}").ok();
}
}
for attr in attrs {
writeln!(out, " #[{attr}]").ok();
}
writeln!(out, " pub {name}: {ty},").ok();
}
write!(out, "}}").ok();
out
}
}
pub struct ImplBuilder {
target: String,
attrs: Vec<String>,
methods: Vec<String>,
}
impl ImplBuilder {
pub fn new(target: &str) -> Self {
Self {
target: target.to_string(),
attrs: vec![],
methods: vec![],
}
}
pub fn add_attr(&mut self, attr: &str) -> &mut Self {
self.attrs.push(attr.to_string());
self
}
pub fn add_method(&mut self, method: &str) -> &mut Self {
self.methods.push(method.to_string());
self
}
pub fn build(&self) -> String {
let mut capacity = 128; capacity += self.target.len() + 10; capacity += self.attrs.iter().map(|a| a.len() + 5).sum::<usize>(); capacity += self.methods.iter().map(|m| m.len() + 4).sum::<usize>();
let mut out = String::with_capacity(capacity);
for attr in &self.attrs {
writeln!(out, "#[{attr}]").ok();
}
writeln!(out, "impl {} {{", self.target).ok();
for (i, method) in self.methods.iter().enumerate() {
for line in method.lines() {
if line.is_empty() {
out.push('\n');
} else {
writeln!(out, " {line}").ok();
}
}
if i < self.methods.len() - 1 {
out.push('\n');
}
}
write!(out, "}}").ok();
out
}
}