use super::super::super::ast::{
CSharpArgumentList, CSharpComment, CSharpMethodName, CSharpParameterList, CSharpType,
};
use super::super::CFunctionName;
use super::async_call::CSharpAsyncCallPlan;
use super::callable_plan::CSharpCallablePlan;
use super::param::{native_call_arg_list, native_param_list};
use super::return_kind::CSharpReturnKind;
use super::{CSharpParamPlan, CSharpWireWriterPlan};
#[derive(Debug, Clone)]
pub struct CSharpFunctionPlan {
pub summary_doc: Option<CSharpComment>,
pub name: CSharpMethodName,
pub params: Vec<CSharpParamPlan>,
pub return_type: CSharpType,
pub return_kind: CSharpReturnKind,
pub ffi_name: CFunctionName,
pub async_call: Option<CSharpAsyncCallPlan>,
pub wire_writers: Vec<CSharpWireWriterPlan>,
}
impl CSharpFunctionPlan {
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)
}
}
impl CSharpCallablePlan for CSharpFunctionPlan {
fn async_call(&self) -> Option<&CSharpAsyncCallPlan> {
self.async_call.as_ref()
}
fn return_type(&self) -> &CSharpType {
&self.return_type
}
fn return_kind(&self) -> &CSharpReturnKind {
&self.return_kind
}
}
#[cfg(test)]
mod tests {
use super::super::super::super::ast::{CSharpClassName, CSharpLocalName, CSharpParamName};
use super::super::CSharpParamKind;
use super::*;
fn param(name: &str, csharp_type: CSharpType, kind: CSharpParamKind) -> CSharpParamPlan {
CSharpParamPlan {
name: super::super::CSharpParamName::from_source(name),
csharp_type,
kind,
}
}
fn record_type(name: &str) -> CSharpType {
CSharpType::Record(CSharpClassName::from_source(name).into())
}
fn function_with_params(
params: Vec<CSharpParamPlan>,
return_type: CSharpType,
return_kind: CSharpReturnKind,
) -> CSharpFunctionPlan {
CSharpFunctionPlan {
summary_doc: None,
name: CSharpMethodName::from_source("test"),
params,
return_type,
return_kind,
ffi_name: CFunctionName::new("boltffi_test".to_string()),
async_call: None,
wire_writers: vec![],
}
}
#[test]
fn native_param_list_expands_each_slot_by_kind() {
let f = function_with_params(
vec![
param("flag", CSharpType::Bool, CSharpParamKind::Direct),
param("v", CSharpType::String, CSharpParamKind::Utf8Bytes),
param("count", CSharpType::UInt, CSharpParamKind::Direct),
param(
"person",
record_type("person"),
CSharpParamKind::WireEncoded {
binding_name: CSharpLocalName::for_bytes(&CSharpParamName::from_source(
"person",
)),
},
),
],
CSharpType::Void,
CSharpReturnKind::Void,
);
assert_eq!(
f.native_param_list().to_string(),
"[MarshalAs(UnmanagedType.I1)] bool flag, byte[] v, UIntPtr vLen, uint count, byte[] person, UIntPtr personLen",
);
}
#[test]
fn native_call_args_mirror_param_shapes() {
let f = function_with_params(
vec![
param("v", CSharpType::String, CSharpParamKind::Utf8Bytes),
param("count", CSharpType::UInt, CSharpParamKind::Direct),
],
CSharpType::Void,
CSharpReturnKind::Void,
);
assert_eq!(
f.native_call_args().to_string(),
"_vBytes, (UIntPtr)_vBytes.Length, count",
);
}
}