use super::super::ast::{
CSharpArgumentList, CSharpClassName, CSharpComment, CSharpMethodName, CSharpParameterList,
};
use super::callable::{native_call_arg_list, native_param_list};
use super::{
CFunctionName, CSharpCallablePlan, CSharpMethodPlan, CSharpParamPlan, CSharpStreamPlan,
CSharpWireWriterPlan,
};
#[derive(Debug, Clone)]
pub struct CSharpClassPlan {
pub summary_doc: Option<CSharpComment>,
pub class_name: CSharpClassName,
pub ffi_free: CFunctionName,
pub native_free_method_name: CSharpMethodName,
pub constructors: Vec<CSharpConstructorPlan>,
pub methods: Vec<CSharpMethodPlan>,
pub streams: Vec<CSharpStreamPlan>,
}
#[derive(Debug, Clone)]
pub struct CSharpConstructorPlan {
pub summary_doc: Option<CSharpComment>,
pub kind: CSharpConstructorKind,
pub native_method_name: CSharpMethodName,
pub ffi_name: CFunctionName,
pub params: Vec<CSharpParamPlan>,
pub wire_writers: Vec<CSharpWireWriterPlan>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CSharpConstructorKind {
Primary {
helper_method_name: CSharpMethodName,
},
StaticFactory { name: CSharpMethodName },
}
impl CSharpConstructorPlan {
pub fn native_param_list(&self) -> CSharpParameterList {
native_param_list(&self.params)
}
pub fn native_call_args(&self) -> CSharpArgumentList {
native_call_arg_list(&self.params)
}
pub fn has_pinned_params(&self) -> bool {
self.params.iter().any(CSharpParamPlan::is_pinned)
}
pub fn needs_system_text(&self) -> bool {
self.params.iter().any(|p| p.csharp_type.contains_string())
}
}
impl CSharpClassPlan {
pub fn has_pinned_params(&self) -> bool {
self.constructors
.iter()
.any(CSharpConstructorPlan::has_pinned_params)
|| self.methods.iter().any(CSharpMethodPlan::has_pinned_params)
}
pub fn needs_system_text(&self) -> bool {
self.constructors
.iter()
.any(CSharpConstructorPlan::needs_system_text)
|| self.methods.iter().any(method_needs_system_text)
}
pub fn has_wire_params(&self) -> bool {
self.constructors.iter().any(|c| !c.wire_writers.is_empty())
|| self.methods.iter().any(|m| !m.wire_writers.is_empty())
}
pub fn has_throwing_methods(&self) -> bool {
self.methods.iter().any(|m| m.return_kind.is_result())
}
pub fn has_async_methods(&self) -> bool {
self.methods.iter().any(CSharpMethodPlan::is_async)
}
pub fn has_streams(&self) -> bool {
!self.streams.is_empty()
}
}
fn method_needs_system_text(method: &CSharpMethodPlan) -> bool {
method
.params
.iter()
.any(|p| p.csharp_type.contains_string())
|| method.return_type.contains_string()
}
#[cfg(test)]
mod tests {
use super::super::super::ast::{CSharpExpression, CSharpIdentity, CSharpLocalName, CSharpType};
use super::super::CSharpReturnKind;
use super::*;
fn dummy_throw_expr() -> CSharpExpression {
CSharpExpression::Identity(CSharpIdentity::Local(CSharpLocalName::new("placeholder")))
}
fn class_with_methods(methods: Vec<CSharpMethodPlan>) -> CSharpClassPlan {
CSharpClassPlan {
summary_doc: None,
class_name: CSharpClassName::from_source("counter"),
ffi_free: CFunctionName::new("boltffi_counter_free".to_string()),
native_free_method_name: CSharpMethodName::from_source("CounterFree"),
constructors: vec![],
methods,
streams: vec![],
}
}
fn method_with_return_kind(return_kind: CSharpReturnKind) -> CSharpMethodPlan {
CSharpMethodPlan {
summary_doc: None,
name: CSharpMethodName::from_source("test"),
native_method_name: CSharpMethodName::from_source("CounterTest"),
ffi_name: CFunctionName::new("boltffi_test".to_string()),
async_call: None,
receiver: super::super::CSharpReceiver::ClassInstance,
params: vec![],
return_type: CSharpType::Void,
return_kind,
wire_writers: vec![],
owner_is_blittable: false,
}
}
#[test]
fn has_throwing_methods_is_true_when_a_class_method_is_a_result() {
let class = class_with_methods(vec![method_with_return_kind(
CSharpReturnKind::WireDecodeResult {
ok_decode_expr: None,
err_throw_expr: dummy_throw_expr(),
},
)]);
assert!(class.has_throwing_methods());
}
#[test]
fn has_throwing_methods_is_false_when_no_class_method_is_a_result() {
let class = class_with_methods(vec![
method_with_return_kind(CSharpReturnKind::Direct),
method_with_return_kind(CSharpReturnKind::WireDecodeString),
]);
assert!(!class.has_throwing_methods());
}
}