use crate::{
cilassembly::{ChangeRefRc, CilAssembly},
metadata::{
tables::{StateMachineMethodRaw, TableDataOwned, TableId},
token::Token,
},
Error, Result,
};
#[derive(Debug, Clone)]
pub struct StateMachineMethodBuilder {
move_next_method: Option<u32>,
kickoff_method: Option<u32>,
}
impl StateMachineMethodBuilder {
#[must_use]
pub fn new() -> Self {
Self {
move_next_method: None,
kickoff_method: None,
}
}
#[must_use]
pub fn move_next_method(mut self, move_next_method: u32) -> Self {
self.move_next_method = Some(move_next_method);
self
}
#[must_use]
pub fn kickoff_method(mut self, kickoff_method: u32) -> Self {
self.kickoff_method = Some(kickoff_method);
self
}
pub fn build(self, assembly: &mut CilAssembly) -> Result<ChangeRefRc> {
let move_next_method = self.move_next_method.ok_or_else(|| {
Error::ModificationInvalid(
"MoveNext method RID is required for StateMachineMethod".to_string(),
)
})?;
let kickoff_method = self.kickoff_method.ok_or_else(|| {
Error::ModificationInvalid(
"Kickoff method RID is required for StateMachineMethod".to_string(),
)
})?;
let state_machine_method = StateMachineMethodRaw {
rid: 0,
token: Token::new(0),
offset: 0,
move_next_method,
kickoff_method,
};
assembly.table_row_add(
TableId::StateMachineMethod,
TableDataOwned::StateMachineMethod(state_machine_method),
)
}
}
impl Default for StateMachineMethodBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test::factories::table::assemblyref::get_test_assembly;
use std::sync::Arc;
#[test]
fn test_statemachinemethod_builder_new() {
let builder = StateMachineMethodBuilder::new();
assert!(builder.move_next_method.is_none());
assert!(builder.kickoff_method.is_none());
}
#[test]
fn test_statemachinemethod_builder_default() {
let builder = StateMachineMethodBuilder::default();
assert!(builder.move_next_method.is_none());
assert!(builder.kickoff_method.is_none());
}
#[test]
fn test_statemachinemethod_builder_basic() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = StateMachineMethodBuilder::new()
.move_next_method(123)
.kickoff_method(45)
.build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_statemachinemethod_builder_async_mapping() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = StateMachineMethodBuilder::new()
.move_next_method(200) .kickoff_method(78) .build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_statemachinemethod_builder_iterator_mapping() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = StateMachineMethodBuilder::new()
.move_next_method(300) .kickoff_method(99) .build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_statemachinemethod_builder_missing_move_next() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = StateMachineMethodBuilder::new()
.kickoff_method(45)
.build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("MoveNext method RID is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_statemachinemethod_builder_missing_kickoff() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = StateMachineMethodBuilder::new()
.move_next_method(123)
.build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("Kickoff method RID is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_statemachinemethod_builder_clone() {
let builder = StateMachineMethodBuilder::new()
.move_next_method(123)
.kickoff_method(45);
let cloned = builder.clone();
assert_eq!(builder.move_next_method, cloned.move_next_method);
assert_eq!(builder.kickoff_method, cloned.kickoff_method);
}
#[test]
fn test_statemachinemethod_builder_debug() {
let builder = StateMachineMethodBuilder::new()
.move_next_method(123)
.kickoff_method(45);
let debug_str = format!("{builder:?}");
assert!(debug_str.contains("StateMachineMethodBuilder"));
assert!(debug_str.contains("move_next_method"));
assert!(debug_str.contains("kickoff_method"));
}
#[test]
fn test_statemachinemethod_builder_fluent_interface() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = StateMachineMethodBuilder::new()
.move_next_method(456)
.kickoff_method(789)
.build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_statemachinemethod_builder_multiple_builds() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref1 = StateMachineMethodBuilder::new()
.move_next_method(100)
.kickoff_method(50)
.build(&mut assembly)
.expect("Should build first mapping");
let ref2 = StateMachineMethodBuilder::new()
.move_next_method(200)
.kickoff_method(60)
.build(&mut assembly)
.expect("Should build second mapping");
assert!(!Arc::ptr_eq(&ref1, &ref2));
Ok(())
}
#[test]
fn test_statemachinemethod_builder_large_method_ids() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = StateMachineMethodBuilder::new()
.move_next_method(0xFFFF) .kickoff_method(0xFFFE) .build(&mut assembly)
.expect("Should handle large method RIDs");
Ok(())
}
}