use caption_strategy::{ArgumentCaptionStrategy, MethodCaptionStrategy, TypeCaptionStrategy};
use cpp_method::{CppMethod, ReturnValueAllocationPlace};
use cpp_operator::CppOperator;
use cpp_type::{CppType, CppTypeBase};
use cpp_data::{CppFunctionPointerType, CppData};
use errors::Result;
use utils::MapIfOk;
pub use serializable::IndirectionChange;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum CppFfiArgumentMeaning {
This,
Argument(i8),
ReturnValue,
}
impl CppFfiArgumentMeaning {
pub fn is_argument(&self) -> bool {
match *self {
CppFfiArgumentMeaning::Argument(..) => true,
_ => false,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CppFfiFunctionArgument {
pub name: String,
pub argument_type: CppFfiType,
pub meaning: CppFfiArgumentMeaning,
}
impl CppFfiFunctionArgument {
pub fn caption(&self, strategy: ArgumentCaptionStrategy) -> Result<String> {
Ok(match strategy {
ArgumentCaptionStrategy::NameOnly => self.name.clone(),
ArgumentCaptionStrategy::TypeOnly(type_strategy) => {
try!(self.argument_type.original_type.caption(type_strategy))
}
ArgumentCaptionStrategy::TypeAndName(type_strategy) => {
format!("{}_{}",
try!(self.argument_type.original_type.caption(type_strategy)),
self.name)
}
})
}
pub fn to_cpp_code(&self) -> Result<String> {
if let CppTypeBase::FunctionPointer(..) = self.argument_type.ffi_type.base {
Ok(try!(self.argument_type.ffi_type.to_cpp_code(Some(&self.name))))
} else {
Ok(format!("{} {}",
try!(self.argument_type.ffi_type.to_cpp_code(None)),
self.name))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CppFfiFunctionSignature {
pub arguments: Vec<CppFfiFunctionArgument>,
pub return_type: CppFfiType,
}
impl CppFfiFunctionSignature {
pub fn has_const_this(&self) -> bool {
self.arguments
.iter()
.any(|arg| arg.meaning == CppFfiArgumentMeaning::This && arg.argument_type.ffi_type.is_const)
}
pub fn arguments_caption(&self, strategy: ArgumentCaptionStrategy) -> Result<String> {
let r = try!(self.arguments
.iter()
.filter(|x| x.meaning.is_argument())
.map_if_ok(|arg| arg.caption(strategy.clone())));
Ok(if r.is_empty() {
"no_args".to_string()
} else {
r.join("_")
})
}
pub fn caption(&self, strategy: MethodCaptionStrategy) -> Result<String> {
Ok(match strategy {
MethodCaptionStrategy::ArgumentsOnly(s) => try!(self.arguments_caption(s)),
MethodCaptionStrategy::ConstOnly => {
if self.has_const_this() {
"const".to_string()
} else {
"".to_string()
}
}
MethodCaptionStrategy::ConstAndArguments(s) => {
let r = if self.has_const_this() {
"const_".to_string()
} else {
"".to_string()
};
r + &try!(self.arguments_caption(s))
}
})
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CppFfiType {
pub original_type: CppType,
pub ffi_type: CppType,
pub conversion: IndirectionChange,
}
impl CppFfiType {
pub fn void() -> Self {
CppFfiType {
original_type: CppType::void(),
ffi_type: CppType::void(),
conversion: IndirectionChange::NoChange,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CppMethodWithFfiSignature {
pub cpp_method: CppMethod,
pub allocation_place: ReturnValueAllocationPlace,
pub c_signature: CppFfiFunctionSignature,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CppAndFfiMethod {
pub cpp_method: CppMethod,
pub allocation_place: ReturnValueAllocationPlace,
pub c_signature: CppFfiFunctionSignature,
pub c_name: String,
}
pub fn c_base_name(cpp_method: &CppMethod,
allocation_place: &ReturnValueAllocationPlace,
include_file: &str)
-> Result<String> {
let scope_prefix = match cpp_method.class_membership {
Some(ref info) => format!("{}_", try!(info.class_type.caption())),
None => format!("{}_G_", include_file),
};
let add_place_note = |name| {
match *allocation_place {
ReturnValueAllocationPlace::Stack => format!("{}_to_output", name),
ReturnValueAllocationPlace::Heap => format!("{}_as_ptr", name),
ReturnValueAllocationPlace::NotApplicable => name,
}
};
let method_name = if cpp_method.is_constructor() {
match *allocation_place {
ReturnValueAllocationPlace::Stack => "constructor".to_string(),
ReturnValueAllocationPlace::Heap => "new".to_string(),
ReturnValueAllocationPlace::NotApplicable => {
return Err("NotApplicable in constructor".into());
}
}
} else if cpp_method.is_destructor() {
match *allocation_place {
ReturnValueAllocationPlace::Stack => "destructor".to_string(),
ReturnValueAllocationPlace::Heap => "delete".to_string(),
ReturnValueAllocationPlace::NotApplicable => {
return Err("NotApplicable in destructor".into());
}
}
} else if let Some(ref operator) = cpp_method.operator {
add_place_note(match *operator {
CppOperator::Conversion(ref cpp_type) => {
format!("convert_to_{}",
try!(cpp_type.caption(TypeCaptionStrategy::Full)))
}
_ => format!("operator_{}", try!(operator.c_name())),
})
} else {
add_place_note(cpp_method.name.replace("::", "_"))
};
let template_args_text = match cpp_method.template_arguments_values {
Some(ref args) => {
format!("_{}",
try!(args.iter().map_if_ok(|x| x.caption(TypeCaptionStrategy::Full))).join("_"))
}
None => String::new(),
};
Ok(scope_prefix + &method_name + &template_args_text)
}
impl CppAndFfiMethod {
pub fn new(data: CppMethodWithFfiSignature, c_name: String) -> CppAndFfiMethod {
CppAndFfiMethod {
cpp_method: data.cpp_method,
allocation_place: data.allocation_place,
c_signature: data.c_signature,
c_name: c_name,
}
}
pub fn short_text(&self) -> String {
self.cpp_method.short_text()
}
}
#[derive(Debug, Clone)]
pub struct QtSlotWrapper {
pub class_name: String,
pub arguments: Vec<CppFfiType>,
pub function_type: CppFunctionPointerType,
pub receiver_id: String,
}
#[derive(Debug, Clone)]
pub struct CppFfiHeaderData {
pub include_file_base_name: String,
pub methods: Vec<CppAndFfiMethod>,
pub qt_slot_wrappers: Vec<QtSlotWrapper>,
}
pub struct CppAndFfiData {
pub cpp_data: CppData,
pub cpp_ffi_headers: Vec<CppFfiHeaderData>,
}