use crate::lang::types::kind::TypeKind;
use crate::lang::types::kind::wire::WireOnly;
use crate::output::{FileType, Output};
use crate::pass::output::common::wire::WireCodeGen;
use crate::pass::{OutputResult, PassInfo, model, output};
use interoptopus::inventory::Types as RsTypes;
use interoptopus_backends::template::Context;
use std::collections::HashMap;
#[derive(Default)]
pub struct Config {}
pub struct Pass {
info: PassInfo,
helper_classes: HashMap<Output, Vec<String>>,
}
impl Pass {
#[must_use]
pub fn new(_: Config) -> Self {
Self { info: PassInfo { name: file!() }, helper_classes: HashMap::default() }
}
pub fn process(
&mut self,
_pass_meta: &mut crate::pass::PassMeta,
output_master: &output::common::master::Pass,
types: &model::common::types::all::Pass,
id_map: &model::common::id_map::Pass,
rs_types: &RsTypes,
wire_types: &output::common::wire::wire_type::Pass,
) -> OutputResult {
let templates = output_master.templates();
let codegen = WireCodeGen { rs_types };
let mut helpers_by_output: HashMap<Output, Vec<String>> = HashMap::new();
for (type_id, ty) in types.iter() {
let TypeKind::WireOnly(WireOnly::Composite(composite)) = &ty.kind else {
continue;
};
if wire_types.rendered_inner_type(*type_id) {
continue;
}
let field_decls: Vec<String> = composite
.fields
.iter()
.map(|f| {
let field_type_name = resolve_field_type_name(f.ty, types, id_map, &codegen);
format!("public required {field_type_name} {};", f.name)
})
.collect();
let mut ctx = Context::new();
ctx.insert("class_name", &ty.name);
ctx.insert("field_decls", &field_decls);
let result = templates.render("common/wire/wire_helper_class.cs", &ctx)?;
let target_output = output_master
.outputs_of(FileType::Csharp)
.find(|o| output_master.type_belongs_to(*type_id, o))
.cloned();
if let Some(output) = target_output {
helpers_by_output.entry(output).or_default().push(result);
} else {
if let Some(first) = output_master.outputs_of(FileType::Csharp).next() {
helpers_by_output.entry(first.clone()).or_default().push(result);
}
}
}
for helpers in helpers_by_output.values_mut() {
helpers.sort();
}
for file in output_master.outputs_of(FileType::Csharp) {
self.helper_classes.entry(file.clone()).or_default();
}
self.helper_classes.extend(helpers_by_output);
Ok(())
}
#[must_use]
pub fn helper_classes_for(&self, output: &Output) -> Option<&[String]> {
self.helper_classes.get(output).map(std::vec::Vec::as_slice)
}
}
fn resolve_field_type_name(
cs_ty: crate::lang::TypeId,
types: &model::common::types::all::Pass,
id_map: &model::common::id_map::Pass,
codegen: &WireCodeGen<'_>,
) -> String {
for rs_id in codegen.rs_types.keys() {
if id_map.ty(*rs_id) == Some(cs_ty) {
return codegen.cs_type_name(*rs_id);
}
}
if let Some(t) = types.get(cs_ty) {
return t.name.clone();
}
"object".to_string()
}