use crate::cpp_checker::cpp_checker_step;
use crate::cpp_data::CppPath;
use crate::cpp_type::CppType;
use crate::database::CppItemData;
use crate::database::DatabaseItem;
use crate::database::RustItem;
use crate::processor::ProcessingStep;
use crate::processor::ProcessorData;
use crate::rust_type::RustPath;
use log::trace;
use ritual_common::errors::{bail, Result};
use std::collections::HashMap;
use std::collections::HashSet;
use std::iter::once;
struct State {
db_items: HashMap<CppPath, DatabaseItem>,
rust_names: HashSet<RustPath>,
}
impl State {
fn new(data: &ProcessorData) -> State {
let all_items = once(&data.current_database as &_)
.chain(data.dep_databases.iter())
.flat_map(|d| d.items.iter());
let db_items = all_items
.filter_map(|db_item| {
let cpp_path = match db_item.cpp_data {
CppItemData::Namespace(ref path) => path,
CppItemData::Type(ref t) => &t.path,
_ => return None,
};
Some((cpp_path.clone(), db_item.clone()))
})
.collect();
let local_items = data.current_database.items();
let rust_names = local_items
.iter()
.filter_map(|db_item| db_item.rust_items.as_ref()) .flatten() .filter_map(|rust_item| rust_item.rust_path()) .cloned() .collect();
State {
db_items,
rust_names,
}
}
fn check_type(&self, cpp_type: &CppType) -> Result<()> {
match cpp_type {
CppType::Class(ref path) => {
if !self
.db_items
.get(&path)
.iter()
.filter_map(|item| item.cpp_data.as_type_ref())
.any(|t| t.kind.is_class())
{
bail!("class not found: {}", path.to_cpp_pseudo_code());
}
if let Some(ref template_arguments) = path.last().template_arguments {
if template_arguments
.iter()
.any(|arg| arg.is_or_contains_template_parameter())
{
bail!("template parameters are not supported");
}
}
}
CppType::Enum { path } => {
if !self
.db_items
.get(&path)
.iter()
.filter_map(|item| item.cpp_data.as_type_ref())
.any(|t| t.kind.is_enum())
{
bail!("enum not found: {}", path);
}
}
CppType::PointerLike { ref target, .. } => {
self.check_type(target)?;
}
CppType::FunctionPointer(t) => {
self.check_type(&t.return_type)?;
for arg in &t.arguments {
self.check_type(arg)?;
}
}
CppType::TemplateParameter { .. } => {
bail!("template parameters are not supported");
}
_ => {}
}
Ok(())
}
fn check_cpp_item_resolvable(&self, item: &CppItemData) -> Result<()> {
for cpp_type in &item.all_involved_types() {
self.check_type(cpp_type)?;
}
Ok(())
}
fn give_name(&mut self, cpp_item: &CppItemData, rust_item: &mut RustItem) -> Result<()> {
unimplemented!("{:?}", (&self.rust_names, cpp_item, rust_item))
}
}
fn run(data: &mut ProcessorData) -> Result<()> {
let mut state = State::new(data);
for item in &mut data.current_database.items {
if let Err(err) = state.check_cpp_item_resolvable(&item.cpp_data) {
trace!("skipping item: {}: {}", &item.cpp_data, err);
continue;
}
if let Some(ref mut rust_items) = item.rust_items {
for mut rust_item in rust_items {
if rust_item.has_rust_path_resolved() {
continue;
}
state.give_name(&item.cpp_data, &mut rust_item)?;
}
}
}
Ok(())
}
pub fn rust_name_resolver_step() -> ProcessingStep {
ProcessingStep::new("rust_name_resolver", vec![cpp_checker_step().name], run)
}