use std::fmt;
use super::{CSharpAttribute, CSharpParamName, CSharpType};
#[derive(Debug, Clone)]
pub(crate) struct CSharpParameter {
pub(crate) attributes: Vec<CSharpAttribute>,
pub(crate) modifier: Option<CSharpParameterModifier>,
pub(crate) csharp_type: CSharpType,
pub(crate) name: CSharpParamName,
}
impl CSharpParameter {
pub(crate) fn bare(csharp_type: CSharpType, name: CSharpParamName) -> Self {
Self {
attributes: vec![],
modifier: None,
csharp_type,
name,
}
}
pub(crate) fn out(csharp_type: CSharpType, name: CSharpParamName) -> Self {
Self {
attributes: vec![],
modifier: Some(CSharpParameterModifier::Out),
csharp_type,
name,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum CSharpParameterModifier {
Out,
}
impl fmt::Display for CSharpParameterModifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Out => f.write_str("out"),
}
}
}
impl fmt::Display for CSharpParameter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for attr in &self.attributes {
write!(f, "{attr} ")?;
}
if let Some(modifier) = self.modifier {
write!(f, "{modifier} ")?;
}
write!(f, "{} {}", self.csharp_type, self.name)
}
}
#[derive(Debug, Clone, Default)]
pub(crate) struct CSharpParameterList(Vec<CSharpParameter>);
impl CSharpParameterList {
pub(crate) fn empty() -> Self {
Self(Vec::new())
}
pub(crate) fn push(&mut self, param: CSharpParameter) {
self.0.push(param);
}
pub(crate) fn extend(&mut self, params: impl IntoIterator<Item = CSharpParameter>) {
self.0.extend(params);
}
}
impl From<Vec<CSharpParameter>> for CSharpParameterList {
fn from(params: Vec<CSharpParameter>) -> Self {
Self(params)
}
}
impl fmt::Display for CSharpParameterList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, p) in self.0.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{p}")?;
}
Ok(())
}
}
impl IntoIterator for CSharpParameterList {
type Item = CSharpParameter;
type IntoIter = std::vec::IntoIter<CSharpParameter>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[cfg(test)]
mod tests {
use super::super::{
CSharpAttribute, CSharpAttributeArg, CSharpClassName, CSharpExpression, CSharpPropertyName,
CSharpTypeReference,
};
use super::*;
fn marshal_as(member: &str) -> CSharpAttribute {
CSharpAttribute {
name: CSharpClassName::new("MarshalAs"),
args: vec![CSharpAttributeArg::Positional(
CSharpExpression::MemberAccess {
receiver: Box::new(CSharpExpression::TypeRef(CSharpTypeReference::Plain(
CSharpClassName::new("UnmanagedType"),
))),
name: CSharpPropertyName::from_source(member),
},
)],
}
}
fn param(name: &str, csharp_type: CSharpType) -> CSharpParameter {
CSharpParameter::bare(csharp_type, CSharpParamName::from_source(name))
}
#[test]
fn bare_parameter_renders_type_space_name() {
let p = param("value", CSharpType::Int);
assert_eq!(p.to_string(), "int value");
}
#[test]
fn parameter_with_attribute_renders_attribute_then_type_name() {
let p = CSharpParameter {
attributes: vec![marshal_as("I1")],
modifier: None,
csharp_type: CSharpType::Bool,
name: CSharpParamName::from_source("flag"),
};
assert_eq!(p.to_string(), "[MarshalAs(UnmanagedType.I1)] bool flag");
}
#[test]
fn out_parameter_renders_modifier_before_type() {
let p = CSharpParameter::out(CSharpType::IntPtr, CSharpParamName::from_source("ptr"));
assert_eq!(p.to_string(), "out IntPtr ptr");
}
#[test]
fn empty_list_renders_as_empty_string() {
assert_eq!(CSharpParameterList::empty().to_string(), "");
}
#[test]
fn single_param_renders_without_separator() {
let list: CSharpParameterList = vec![param("v", CSharpType::String)].into();
assert_eq!(list.to_string(), "string v");
}
#[test]
fn mixed_list_pins_canonical_dllimport_param_spacing() {
let list: CSharpParameterList = vec![
CSharpParameter {
attributes: vec![marshal_as("I1")],
modifier: None,
csharp_type: CSharpType::Bool,
name: CSharpParamName::from_source("flag"),
},
param("v", CSharpType::Array(Box::new(CSharpType::Byte))),
param("vLen", CSharpType::UIntPtr),
param("count", CSharpType::UInt),
]
.into();
assert_eq!(
list.to_string(),
"[MarshalAs(UnmanagedType.I1)] bool flag, byte[] v, UIntPtr vLen, uint count"
);
}
}