use crate::{
parser::ParsedData,
rust_types::{Id, RustEnum, RustEnumVariant, RustStruct, RustTypeAlias},
};
use itertools::Itertools;
use std::{collections::HashMap, io::Write};
mod go;
mod kotlin;
mod swift;
mod typescript;
use crate::rust_types::{RustType, RustTypeFormatError, SpecialRustType};
pub use go::Go;
pub use kotlin::Kotlin;
pub use swift::Swift;
pub use typescript::TypeScript;
pub trait Language {
fn generate_types(&self, writable: &mut dyn Write, data: &ParsedData) -> std::io::Result<()> {
self.begin_file(writable)?;
for a in data.aliases.iter() {
self.write_type_alias(writable, a)?;
}
for s in data.structs.iter() {
self.write_struct(writable, s)?;
}
for e in data.enums.iter() {
self.write_enum(writable, e)?;
}
self.end_file(writable)?;
Ok(())
}
fn type_map(&self) -> &HashMap<String, String>;
fn format_type(
&self,
ty: &RustType,
generic_types: &[String],
) -> Result<String, RustTypeFormatError> {
match ty {
RustType::Simple { id } => self.format_simple_type(id, generic_types),
RustType::Generic { id, parameters } => {
self.format_generic_type(id, parameters.as_slice(), generic_types)
}
RustType::Special(special) => self.format_special_type(special, generic_types),
}
}
#[allow(clippy::ptr_arg)]
fn format_simple_type(
&self,
base: &String,
_generic_types: &[String],
) -> Result<String, RustTypeFormatError> {
Ok(if let Some(mapped) = self.type_map().get(base) {
mapped.into()
} else {
base.into()
})
}
#[allow(clippy::ptr_arg)]
fn format_generic_type(
&self,
base: &String,
parameters: &[RustType],
generic_types: &[String],
) -> Result<String, RustTypeFormatError> {
if let Some(mapped) = self.type_map().get(base) {
Ok(mapped.into())
} else {
let parameters: Result<Vec<String>, RustTypeFormatError> = parameters
.iter()
.map(|p| self.format_type(p, generic_types))
.collect();
let parameters = parameters?;
Ok(format!(
"{}{}",
self.format_simple_type(base, generic_types)?,
(!parameters.is_empty())
.then(|| format!("<{}>", parameters.into_iter().join(", ")))
.unwrap_or_default()
))
}
}
fn format_special_type(
&self,
special_ty: &SpecialRustType,
generic_types: &[String],
) -> Result<String, RustTypeFormatError>;
fn begin_file(&self, _w: &mut dyn Write) -> std::io::Result<()> {
Ok(())
}
fn end_file(&self, _w: &mut dyn Write) -> std::io::Result<()> {
Ok(())
}
fn write_type_alias(&self, _w: &mut dyn Write, _t: &RustTypeAlias) -> std::io::Result<()> {
Ok(())
}
fn write_struct(&self, _w: &mut dyn Write, _rs: &RustStruct) -> std::io::Result<()> {
Ok(())
}
fn write_enum(&self, _w: &mut dyn Write, _e: &RustEnum) -> std::io::Result<()> {
Ok(())
}
fn write_types_for_anonymous_structs(
&self,
w: &mut dyn Write,
e: &RustEnum,
make_struct_name: &dyn Fn(&str) -> String,
) -> std::io::Result<()> {
for (fields, shared) in e.shared().variants.iter().filter_map(|v| match v {
RustEnumVariant::AnonymousStruct { fields, shared } => Some((fields, shared)),
_ => None,
}) {
let struct_name = make_struct_name(&shared.id.original);
let generic_types = fields
.iter()
.flat_map(|field| {
e.shared()
.generic_types
.iter()
.filter(|g| field.ty.contains_type(g))
})
.unique()
.cloned()
.collect();
self.write_struct(
w,
&RustStruct {
id: Id {
original: struct_name.clone(),
renamed: struct_name.clone(),
},
fields: fields.clone(),
generic_types,
comments: vec![format!(
"Generated type representing the anonymous struct variant `{}` of the `{}` Rust enum",
&shared.id.original,
&e.shared().id.original,
)],
decorators: HashMap::new(),
},
)?;
}
Ok(())
}
}