use crate::converter::CTypeConverter;
use crate::converter::Converter;
use crate::Config;
use interoptopus::indented;
use interoptopus::lang::c::{CType, CompositeType, Constant, Documentation, EnumType, Field, FnPointerType, Function, OpaqueType, Variant};
use interoptopus::patterns::TypePattern;
use interoptopus::util::sort_types_by_dependencies;
use interoptopus::writer::IndentWriter;
use interoptopus::{Error, Library};
pub trait CWriter {
fn config(&self) -> &Config;
fn library(&self) -> &Library;
fn converter(&self) -> &Converter;
fn write_custom_defines(&self, w: &mut IndentWriter) -> Result<(), Error> {
indented!(w, "{}", &self.config().custom_defines)
}
fn write_file_header_comments(&self, w: &mut IndentWriter) -> Result<(), Error> {
indented!(w, "{}", &self.config().file_header_comment)
}
fn write_imports(&self, w: &mut IndentWriter) -> Result<(), Error> {
indented!(w, r#"#include <stdint.h>"#)?;
indented!(w, r#"#include <stdbool.h>"#)?;
Ok(())
}
fn write_constants(&self, w: &mut IndentWriter) -> Result<(), Error> {
for constant in self.library().constants() {
self.write_constant(w, constant)?;
}
Ok(())
}
fn write_constant(&self, w: &mut IndentWriter, constant: &Constant) -> Result<(), Error> {
let name = self.converter().const_name_to_name(constant);
let the_type = match constant.the_type() {
CType::Primitive(x) => self.converter().primitive_to_typename(&x),
_ => return Err(Error::Null),
};
indented!(w, r#"const {} {} = {};"#, the_type, name, self.converter().constant_value_to_value(constant.value()))
}
fn write_functions(&self, w: &mut IndentWriter) -> Result<(), Error> {
for function in self.library().functions() {
self.write_function(w, function)?;
}
Ok(())
}
fn write_function(&self, w: &mut IndentWriter, function: &Function) -> Result<(), Error> {
self.write_function_declaration(w, function)
}
fn write_documentation(&self, w: &mut IndentWriter, documentation: &Documentation) -> Result<(), Error> {
for line in documentation.lines() {
indented!(w, r#"/// {}"#, line)?;
}
Ok(())
}
fn write_function_declaration(&self, w: &mut IndentWriter, function: &Function) -> Result<(), Error> {
let attr = &self.config().function_attribute;
let rval = self.converter().to_type_specifier(function.signature().rval());
let name = self.converter().function_name_to_c_name(function);
let mut params = Vec::new();
for (_, p) in function.signature().params().iter().enumerate() {
match p.the_type() {
CType::Array(a) => {
params.push(format!("{} {}[{}]", self.converter().to_type_specifier(a.array_type()), p.name(), a.len(),));
}
_ => {
params.push(format!("{} {}", self.converter().to_type_specifier(p.the_type()), p.name()));
}
}
}
indented!(w, r#"{}{} {}({});"#, attr, rval, name, params.join(", "))
}
fn write_type_definitions(&self, w: &mut IndentWriter) -> Result<(), Error> {
for the_type in &sort_types_by_dependencies(self.library().ctypes().to_vec()) {
self.write_type_definition(w, the_type)?;
}
Ok(())
}
fn write_type_definition(&self, w: &mut IndentWriter, the_type: &CType) -> Result<(), Error> {
match the_type {
CType::Primitive(_) => {}
CType::Array(_) => {}
CType::Enum(e) => {
self.write_type_definition_enum(w, e)?;
w.newline()?;
}
CType::Opaque(o) => {
self.write_type_definition_opaque(w, o)?;
}
CType::Composite(c) => {
self.write_type_definition_composite(w, c)?;
w.newline()?;
}
CType::FnPointer(f) => {
self.write_type_definition_fn_pointer(w, f)?;
w.newline()?;
}
CType::ReadPointer(_) => {}
CType::ReadWritePointer(_) => {}
CType::Pattern(p) => match p {
TypePattern::AsciiPointer => {}
TypePattern::NamedCallback(e) => {
self.write_type_definition_fn_pointer(w, e.fnpointer())?;
w.newline()?;
}
TypePattern::SuccessEnum(e) => {
self.write_type_definition_enum(w, e.the_enum())?;
w.newline()?;
}
TypePattern::Slice(x) => {
self.write_type_definition_composite(w, x)?;
w.newline()?;
}
TypePattern::SliceMut(x) => {
self.write_type_definition_composite(w, x)?;
w.newline()?;
}
TypePattern::Option(x) => {
self.write_type_definition_composite(w, x)?;
w.newline()?;
}
TypePattern::Bool => {}
},
}
Ok(())
}
fn write_type_definition_fn_pointer(&self, w: &mut IndentWriter, the_type: &FnPointerType) -> Result<(), Error> {
self.write_type_definition_fn_pointer_body(w, the_type)
}
fn write_type_definition_fn_pointer_body(&self, w: &mut IndentWriter, the_type: &FnPointerType) -> Result<(), Error> {
let rval = self.converter().to_type_specifier(the_type.signature().rval());
let name = self.converter().fnpointer_to_typename(the_type);
let mut params = Vec::new();
for (i, param) in the_type.signature().params().iter().enumerate() {
params.push(format!("{} x{}", self.converter().to_type_specifier(param.the_type()), i));
}
indented!(w, "typedef {} (*{})({});", rval, name, params.join(", "))
}
fn write_type_definition_enum(&self, w: &mut IndentWriter, the_type: &EnumType) -> Result<(), Error> {
let name = self.converter().enum_to_typename(the_type);
indented!(w, "typedef enum {}", name)?;
indented!(w, [_], "{{")?;
w.indent();
for variant in the_type.variants() {
self.write_type_definition_enum_variant(w, variant, the_type)?;
}
w.unindent();
indented!(w, [_], "}} {};", name)
}
fn write_type_definition_enum_variant(&self, w: &mut IndentWriter, variant: &Variant, _the_type: &EnumType) -> Result<(), Error> {
let variant_name = self.converter().enum_variant_to_name(variant);
let variant_value = variant.value();
indented!(w, r#"{} = {},"#, variant_name, variant_value)
}
fn write_type_definition_opaque(&self, w: &mut IndentWriter, the_type: &OpaqueType) -> Result<(), Error> {
self.write_type_definition_opaque_body(w, the_type)
}
fn write_type_definition_opaque_body(&self, w: &mut IndentWriter, the_type: &OpaqueType) -> Result<(), Error> {
let name = self.converter().opaque_to_typename(the_type);
indented!(w, r#"typedef struct {} {};"#, name, name)
}
fn write_type_definition_composite(&self, w: &mut IndentWriter, the_type: &CompositeType) -> Result<(), Error> {
let name = self.converter().composite_to_typename(the_type);
if the_type.is_empty() {
indented!(w, r#"typedef struct {} {};"#, name, name)?;
Ok(())
} else {
self.write_type_definition_composite_body(w, the_type)
}
}
fn write_type_definition_composite_body(&self, w: &mut IndentWriter, the_type: &CompositeType) -> Result<(), Error> {
let name = self.converter().composite_to_typename(the_type);
indented!(w, r#"typedef struct {}"#, name)?;
indented!(w, [_], "{{")?;
w.indent();
for field in the_type.fields() {
self.write_type_definition_composite_body_field(w, field, the_type)?;
}
w.unindent();
indented!(w, [_], "}} {};", name)
}
fn write_type_definition_composite_body_field(&self, w: &mut IndentWriter, field: &Field, _the_type: &CompositeType) -> Result<(), Error> {
match field.the_type() {
CType::Array(x) => {
let field_name = field.name();
let type_name = self.converter().to_type_specifier(x.array_type());
indented!(w, r#"{} {}[{}];"#, type_name, field_name, x.len())
}
_ => {
let field_name = field.name();
let type_name = self.converter().to_type_specifier(field.the_type());
indented!(w, r#"{} {};"#, type_name, field_name)
}
}
}
fn write_ifndef(&self, w: &mut IndentWriter, f: impl FnOnce(&mut IndentWriter) -> Result<(), Error>) -> Result<(), Error> {
if self.config().directives {
indented!(w, r#"#ifndef {}"#, self.config().ifndef)?;
indented!(w, r#"#define {}"#, self.config().ifndef)?;
w.newline()?;
}
f(w)?;
if self.config().directives {
w.newline()?;
indented!(w, r#"#endif /* {} */"#, self.config().ifndef)?;
}
Ok(())
}
fn write_ifdefcpp(&self, w: &mut IndentWriter, f: impl FnOnce(&mut IndentWriter) -> Result<(), Error>) -> Result<(), Error> {
if self.config().directives {
indented!(w, r#"#ifdef __cplusplus"#)?;
indented!(w, r#"extern "C" {{"#)?;
indented!(w, r#"#endif"#)?;
w.newline()?;
}
f(w)?;
if self.config().directives {
w.newline()?;
indented!(w, r#"#ifdef __cplusplus"#)?;
indented!(w, r#"}}"#)?;
indented!(w, r#"#endif"#)?;
}
Ok(())
}
fn write_all(&self, w: &mut IndentWriter) -> Result<(), Error> {
self.write_file_header_comments(w)?;
w.newline()?;
self.write_ifndef(w, |w| {
self.write_ifdefcpp(w, |w| {
if self.config().imports {
self.write_imports(w)?;
w.newline()?;
}
self.write_custom_defines(w)?;
w.newline()?;
self.write_constants(w)?;
w.newline()?;
self.write_type_definitions(w)?;
w.newline()?;
self.write_functions(w)?;
Ok(())
})?;
Ok(())
})?;
Ok(())
}
}