use crate::TypeName;
use itertools::Itertools;
pub(crate) enum AdditionalNeed {
MakeUnique(TypeName, Vec<TypeName>),
}
struct AdditionalFunction {
declaration: String,
definition: String,
name: String,
}
pub(crate) struct AdditionalCpp {
pub(crate) declarations: String,
pub(crate) definitions: String,
pub(crate) extra_allowlist: Vec<String>,
}
pub(crate) struct AdditionalCppGenerator {
additional_functions: Vec<AdditionalFunction>,
inclusions: String,
}
impl AdditionalCppGenerator {
pub(crate) fn new(inclusions: String) -> Self {
AdditionalCppGenerator {
additional_functions: Vec::new(),
inclusions,
}
}
pub(crate) fn add_needs(&mut self, additions: Vec<AdditionalNeed>) {
for need in additions {
match need {
AdditionalNeed::MakeUnique(ty, args) => self.generate_make_unique(&ty, &args),
}
}
}
pub(crate) fn generate(&self) -> Option<AdditionalCpp> {
if self.additional_functions.is_empty() {
None
} else {
let declarations = self.concat_additional_items(|x| &x.declaration);
let declarations = format!("#include <memory>\n{}\n{}", self.inclusions, declarations);
let definitions = self.concat_additional_items(|x| &x.definition);
let definitions = format!("#include \"autocxxgen.h\"\n{}", definitions);
let extra_allowlist = self
.additional_functions
.iter()
.map(|x| x.name.to_string())
.collect();
Some(AdditionalCpp {
declarations,
definitions,
extra_allowlist,
})
}
}
fn concat_additional_items<F>(&self, field_access: F) -> String
where
F: FnMut(&AdditionalFunction) -> &str,
{
let mut s = self
.additional_functions
.iter()
.map(field_access)
.collect::<Vec<&str>>()
.join("\n\n");
s.push('\n');
s
}
fn generate_make_unique(&mut self, ty: &TypeName, constructor_arg_types: &[TypeName]) {
let name = format!("{}_make_unique", ty.to_cxx_name());
let constructor_args = constructor_arg_types
.iter()
.enumerate()
.map(|(counter, ty)| format!("{} arg{}", ty.to_cxx_name(), counter))
.join(", ");
let declaration = format!("std::unique_ptr<{}> {}({})", ty, name, constructor_args);
let arg_list = constructor_arg_types
.iter()
.enumerate()
.map(|(counter, _)| format!("arg{}", counter))
.join(", ");
let definition = format!(
"{} {{ return std::make_unique<{}>({}); }}",
declaration, ty, arg_list
);
let declaration = format!("{};", declaration);
self.additional_functions.push(AdditionalFunction {
name,
declaration,
definition,
})
}
}