use crate::{
cilassembly::{ChangeRefRc, CilAssembly},
metadata::{
tables::{EventPtrRaw, TableDataOwned, TableId},
token::Token,
},
Error, Result,
};
#[derive(Debug, Clone)]
pub struct EventPtrBuilder {
event: Option<u32>,
}
impl EventPtrBuilder {
#[must_use]
pub fn new() -> Self {
Self { event: None }
}
#[must_use]
pub fn event(mut self, event: u32) -> Self {
self.event = Some(event);
self
}
pub fn build(self, assembly: &mut CilAssembly) -> Result<ChangeRefRc> {
let event = self.event.ok_or_else(|| {
Error::ModificationInvalid("Event RID is required for EventPtr".to_string())
})?;
let event_ptr = EventPtrRaw {
rid: 0,
token: Token::new(0),
offset: 0,
event,
};
assembly.table_row_add(TableId::EventPtr, TableDataOwned::EventPtr(event_ptr))
}
}
impl Default for EventPtrBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
cilassembly::ChangeRefKind, test::factories::table::assemblyref::get_test_assembly,
};
#[test]
fn test_eventptr_builder_new() {
let builder = EventPtrBuilder::new();
assert!(builder.event.is_none());
}
#[test]
fn test_eventptr_builder_default() {
let builder = EventPtrBuilder::default();
assert!(builder.event.is_none());
}
#[test]
fn test_eventptr_builder_basic() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = EventPtrBuilder::new()
.event(1)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
Ok(())
}
#[test]
fn test_eventptr_builder_reordering() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = EventPtrBuilder::new()
.event(12) .build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
Ok(())
}
#[test]
fn test_eventptr_builder_missing_event() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = EventPtrBuilder::new().build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("Event RID is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_eventptr_builder_clone() {
let builder = EventPtrBuilder::new().event(4);
let cloned = builder.clone();
assert_eq!(builder.event, cloned.event);
}
#[test]
fn test_eventptr_builder_debug() {
let builder = EventPtrBuilder::new().event(9);
let debug_str = format!("{builder:?}");
assert!(debug_str.contains("EventPtrBuilder"));
assert!(debug_str.contains("event"));
}
#[test]
fn test_eventptr_builder_fluent_interface() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = EventPtrBuilder::new()
.event(20)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
Ok(())
}
#[test]
fn test_eventptr_builder_multiple_builds() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref1 = EventPtrBuilder::new()
.event(8)
.build(&mut assembly)
.expect("Should build first pointer");
let ref2 = EventPtrBuilder::new()
.event(3)
.build(&mut assembly)
.expect("Should build second pointer");
let ref3 = EventPtrBuilder::new()
.event(15)
.build(&mut assembly)
.expect("Should build third pointer");
assert!(!std::sync::Arc::ptr_eq(&ref1, &ref2));
assert!(!std::sync::Arc::ptr_eq(&ref2, &ref3));
assert_eq!(ref1.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
assert_eq!(ref2.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
assert_eq!(ref3.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
Ok(())
}
#[test]
fn test_eventptr_builder_large_event_rid() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = EventPtrBuilder::new()
.event(0xFFFF) .build(&mut assembly)
.expect("Should handle large event RID");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
Ok(())
}
#[test]
fn test_eventptr_builder_event_ordering_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let logical_to_physical = [(1, 10), (2, 5), (3, 12)];
let mut refs = Vec::new();
for (logical_idx, physical_event) in logical_to_physical {
let ref_ = EventPtrBuilder::new()
.event(physical_event)
.build(&mut assembly)
.expect("Should build event pointer");
refs.push((logical_idx, ref_));
}
for (_logical_idx, ref_) in refs.iter() {
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
}
Ok(())
}
#[test]
fn test_eventptr_builder_zero_event() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = EventPtrBuilder::new().event(0).build(&mut assembly);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_eventptr_builder_edit_continue_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let reordered_events = [3, 1, 2];
let mut event_pointers = Vec::new();
for &physical_event in &reordered_events {
let pointer_ref = EventPtrBuilder::new()
.event(physical_event)
.build(&mut assembly)
.expect("Should build event pointer for edit-continue");
event_pointers.push(pointer_ref);
}
for ref_ in event_pointers.iter() {
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
}
Ok(())
}
#[test]
fn test_eventptr_builder_type_event_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let type_events = [5, 10, 7, 15, 2];
let mut event_pointers = Vec::new();
for &event_rid in &type_events {
let pointer_ref = EventPtrBuilder::new()
.event(event_rid)
.build(&mut assembly)
.expect("Should build event pointer");
event_pointers.push(pointer_ref);
}
for ref_ in event_pointers.iter() {
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
}
Ok(())
}
#[test]
fn test_eventptr_builder_hot_reload_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let new_event_implementations = [100, 200, 300];
let mut pointer_refs = Vec::new();
for &new_event in &new_event_implementations {
let pointer_ref = EventPtrBuilder::new()
.event(new_event)
.build(&mut assembly)
.expect("Should build pointer for hot-reload");
pointer_refs.push(pointer_ref);
}
assert_eq!(pointer_refs.len(), 3);
for ref_ in pointer_refs.iter() {
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
}
Ok(())
}
#[test]
fn test_eventptr_builder_complex_indirection_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let complex_mapping = [25, 1, 50, 10, 75, 5, 100];
let mut pointer_sequence = Vec::new();
for &physical_event in &complex_mapping {
let ref_ = EventPtrBuilder::new()
.event(physical_event)
.build(&mut assembly)
.expect("Should build complex indirection mapping");
pointer_sequence.push(ref_);
}
assert_eq!(pointer_sequence.len(), 7);
for ref_ in pointer_sequence.iter() {
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EventPtr));
}
Ok(())
}
}