use super::super::ast::{
CSharpClassName, CSharpComment, CSharpEnumUnderlyingType, CSharpExpression,
};
use super::record::{error_param_expr, to_string_call};
use super::{CSharpCallablePlan, CSharpFieldPlan, CSharpMethodPlan};
#[derive(Debug, Clone)]
pub struct CSharpEnumPlan {
pub summary_doc: Option<CSharpComment>,
pub class_name: CSharpClassName,
pub wire_class_name: CSharpClassName,
pub methods_class_name: Option<CSharpClassName>,
pub kind: CSharpEnumKind,
pub underlying_type: Option<CSharpEnumUnderlyingType>,
pub variants: Vec<CSharpEnumVariantPlan>,
pub methods: Vec<CSharpMethodPlan>,
pub is_error: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CSharpEnumKind {
CStyle,
Data,
}
#[derive(Debug, Clone)]
pub struct CSharpEnumVariantPlan {
pub summary_doc: Option<CSharpComment>,
pub name: CSharpClassName,
pub tag: i32,
pub wire_tag: i32,
pub fields: Vec<CSharpFieldPlan>,
}
impl CSharpEnumPlan {
pub fn c_style_underlying_type(&self) -> &CSharpEnumUnderlyingType {
self.underlying_type
.as_ref()
.expect("c_style_underlying_type called on data enum")
}
pub fn has_string_fields(&self) -> bool {
self.variants
.iter()
.flat_map(|v| v.fields.iter())
.any(|f| f.csharp_type.contains_string())
}
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(crate) fn exception_message_expr(&self) -> CSharpExpression {
to_string_call(error_param_expr())
}
}
impl CSharpEnumVariantPlan {
pub fn is_unit(&self) -> bool {
self.fields.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::super::super::ast::{
CSharpArgumentList, CSharpExpression, CSharpIdentity, CSharpLiteral, CSharpLocalName,
CSharpMethodName, CSharpPropertyName, CSharpStatement, CSharpType,
};
use super::super::{CFunctionName, CSharpReceiver, CSharpReturnKind};
use super::*;
fn dummy_throw_expr() -> CSharpExpression {
CSharpExpression::Identity(CSharpIdentity::Local(CSharpLocalName::new("placeholder")))
}
fn enum_with_methods(methods: Vec<CSharpMethodPlan>) -> CSharpEnumPlan {
CSharpEnumPlan {
summary_doc: None,
class_name: CSharpClassName::from_source("status"),
wire_class_name: CSharpClassName::from_source("status_wire"),
methods_class_name: None,
kind: CSharpEnumKind::CStyle,
underlying_type: None,
variants: vec![],
methods,
is_error: false,
}
}
fn method_with_return_kind(return_kind: CSharpReturnKind) -> CSharpMethodPlan {
CSharpMethodPlan {
summary_doc: None,
name: CSharpMethodName::from_source("test"),
native_method_name: CSharpMethodName::from_source("OwnerTest"),
ffi_name: CFunctionName::new("boltffi_test".to_string()),
async_call: None,
receiver: CSharpReceiver::Static,
params: vec![],
return_type: CSharpType::Void,
return_kind,
wire_writers: vec![],
owner_is_blittable: false,
}
}
#[test]
fn variant_with_empty_fields_is_unit() {
let variant = CSharpEnumVariantPlan {
summary_doc: None,
name: CSharpClassName::from_source("active"),
tag: 0,
wire_tag: 0,
fields: vec![],
};
assert!(variant.is_unit());
}
#[test]
fn enum_exception_message_expr_is_error_to_string() {
let enumeration = enum_with_methods(vec![]);
assert_eq!(
enumeration.exception_message_expr().to_string(),
"error.ToString()",
);
}
#[test]
fn has_throwing_methods_is_true_when_an_enum_method_is_a_result() {
let enumeration = enum_with_methods(vec![method_with_return_kind(
CSharpReturnKind::WireDecodeResult {
ok_decode_expr: None,
err_throw_expr: dummy_throw_expr(),
},
)]);
assert!(enumeration.has_throwing_methods());
}
#[test]
fn has_throwing_methods_is_false_when_no_enum_method_is_a_result() {
let enumeration = enum_with_methods(vec![
method_with_return_kind(CSharpReturnKind::Direct),
method_with_return_kind(CSharpReturnKind::WireDecodeString),
]);
assert!(!enumeration.has_throwing_methods());
}
#[test]
fn variant_with_payload_is_not_unit() {
let variant = CSharpEnumVariantPlan {
summary_doc: None,
name: CSharpClassName::from_source("circle"),
tag: 0,
wire_tag: 0,
fields: vec![CSharpFieldPlan {
summary_doc: None,
name: CSharpPropertyName::from_source("radius"),
csharp_type: CSharpType::Double,
wire_decode_expr: CSharpExpression::MethodCall {
receiver: Box::new(CSharpExpression::Identity(CSharpIdentity::Local(
CSharpLocalName::new("reader"),
))),
method: CSharpMethodName::from_source("read_f64"),
type_args: vec![],
args: CSharpArgumentList::default(),
},
wire_size_expr: CSharpExpression::Literal(CSharpLiteral::Int(8)),
wire_encode_stmts: vec![CSharpStatement::Expression(CSharpExpression::Literal(
CSharpLiteral::Int(0),
))],
}],
};
assert!(!variant.is_unit());
}
}