use crate::file::{AbiFile, AbiMetadata};
use crate::resolver::ImportResolver;
use abi_types::{TypeDef, TypeKind};
use std::path::{Path, PathBuf};
pub fn flatten(file_path: &Path, include_dirs: &[PathBuf]) -> anyhow::Result<AbiFile> {
flatten_with_options(file_path, include_dirs, false)
}
pub fn flatten_with_options(
file_path: &Path,
include_dirs: &[PathBuf],
verbose: bool,
) -> anyhow::Result<AbiFile> {
let mut resolver = ImportResolver::new(include_dirs.to_vec());
resolver.load_file_with_imports(file_path, verbose)?;
let all_files = resolver.get_all_files();
if all_files.is_empty() {
anyhow::bail!("No ABI files loaded");
}
let root_file = all_files.last().unwrap();
let mut all_types: Vec<TypeDef> = resolver.get_all_types().to_vec();
normalize_type_refs(&mut all_types, &resolver);
let flattened = AbiFile {
abi: AbiMetadata {
package: root_file.abi.package.clone(),
name: root_file.abi.name.clone(),
abi_version: root_file.abi.abi_version,
package_version: root_file.abi.package_version.clone(),
description: root_file.abi.description.clone(),
imports: Vec::new(),
options: root_file.abi.options.clone(),
},
types: all_types,
};
if verbose {
println!(
"[~] Flattened {} files into {} types",
resolver.loaded_file_count(),
flattened.types.len()
);
}
Ok(flattened)
}
pub fn flatten_to_yaml(file_path: &Path, include_dirs: &[PathBuf]) -> anyhow::Result<String> {
let flattened = flatten(file_path, include_dirs)?;
let yaml = serde_yml::to_string(&flattened)?;
Ok(yaml)
}
pub fn normalize_type_refs(typedefs: &mut [TypeDef], resolver: &ImportResolver) {
for typedef in typedefs.iter_mut() {
normalize_type_kind(&mut typedef.kind, resolver);
}
}
fn normalize_type_kind(kind: &mut TypeKind, resolver: &ImportResolver) {
match kind {
TypeKind::TypeRef(type_ref) => {
if let Some(simple_name) = resolver.resolve_type_name(&type_ref.name) {
type_ref.name = simple_name;
}
type_ref.package = None;
}
TypeKind::Struct(struct_type) => {
for field in &mut struct_type.fields {
normalize_type_kind(&mut field.field_type, resolver);
}
}
TypeKind::Union(union_type) => {
for variant in &mut union_type.variants {
normalize_type_kind(&mut variant.variant_type, resolver);
}
}
TypeKind::Enum(enum_type) => {
for variant in &mut enum_type.variants {
normalize_type_kind(&mut variant.variant_type, resolver);
}
}
TypeKind::Array(array_type) => {
normalize_type_kind(&mut array_type.element_type, resolver);
}
TypeKind::SizeDiscriminatedUnion(sdu_type) => {
for variant in &mut sdu_type.variants {
normalize_type_kind(&mut variant.variant_type, resolver);
}
}
TypeKind::Primitive(_) => { }
}
}