use gc_lite::{GcError, GcHeap, GcRef, GcResult, GcTrace, GcTraceCtx, gc_type_register};
fn main() -> GcResult<()> {
println!("=== Error handling example of partitioned garbage collection system ===");
println!("\n=== Out of memory error handling ===");
demonstrate_out_of_memory()?;
println!("\n=== Partition management errors ===");
demonstrate_partition_management_errors()?;
println!("\n=== GC threshold API errors ===");
demonstrate_gc_threshold_errors()?;
println!("\nAll error handling demonstrations completed!");
Ok(())
}
fn demonstrate_out_of_memory() -> GcResult<()> {
println!("1. Create limited memory partition...");
let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
context.set_memory_limit(2048); let partition_id = context.create_partition();
println!("2. Allocate first large object...");
let gc1: GcRef<LargeData> =
match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
Ok(gc_ref) => {
println!(" ✓ Successfully allocated first object (1KB)");
gc_ref
}
Err((error, _)) => {
println!(" ✗ First object allocation failed: {:?}", error);
return Ok(());
}
};
println!("3. Try to allocate second large object...");
match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
Err((GcError::PartitionFull, _)) => {
println!(" ✓ Correctly detected partition full error");
}
Ok(_) => {
println!(" ✗ Expected partition full error, but allocation succeeded");
return Ok(());
}
Err((other_error, _)) => {
println!(
" ✗ Expected partition full error, but got: {:?}",
other_error
);
return Ok(());
}
}
println!(" ✓ Automatic cleanup through GC");
context.garbage_collect(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
Ok(())
}
fn demonstrate_partition_management_errors() -> GcResult<()> {
println!("1. Test non-existent partition operations...");
let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
let invalid_partition = gc_lite::GcPartitionId(9999);
match unsafe {
context.alloc_raw(
invalid_partition,
TestData {
value: 42,
name: "test".to_string(),
},
)
} {
Err((GcError::PartitionNotFound, _)) => {
println!(" ✓ Allocating objects in non-existent partition returns correct error");
}
Ok(_) => {
println!(" ✗ Expected partition not found error, but allocation succeeded");
}
Err((other_error, _)) => {
println!(
" ✗ Expected partition not found error, but got: {:?}",
other_error
);
}
}
let partition_info = context.partition(invalid_partition);
assert!(
partition_info.is_none(),
"Non-existent partition should return None"
);
println!(" ✓ Getting non-existent partition info returns None");
context.remove_partition(invalid_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
println!(" ✓ Removing non-existent partition silently fails");
println!("\n2. Test non-empty partition deletion...");
let partition_id = context.create_partition();
let obj = unsafe {
context.alloc_raw(
partition_id,
TestData {
value: 1,
name: "obj".to_string(),
},
)
}
.unwrap();
let _ = obj;
context.remove_partition(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
println!(" ✓ Successfully deleted non-empty partition (root objects were force cleaned)");
Ok(())
}
fn demonstrate_gc_threshold_errors() -> GcResult<()> {
println!("1. Test GC threshold API...");
let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
context.set_memory_limit(1024);
let _partition_id = context.create_partition();
println!("2. Test default threshold...");
assert_eq!(context.gc_threshold(), 0);
println!(" ✓ Default threshold is 0, automatic GC disabled");
println!("3. Test setting threshold...");
context.set_gc_threshold(512);
assert_eq!(context.gc_threshold(), 512);
println!(" ✓ Successfully set threshold to 512, automatic GC enabled");
println!("4. Test setting threshold exceeding memory limit...");
context.set_gc_threshold(2048);
assert_eq!(context.gc_threshold(), 819);
println!(
" ✓ Setting threshold exceeding memory limit automatically adjusted to 0.8x of memory limit"
);
println!("5. Test disabling automatic GC...");
context.set_gc_threshold(0);
assert_eq!(context.gc_threshold(), 0);
println!(" ✓ Successfully disabled automatic GC, threshold set to 0");
Ok(())
}
#[derive(Debug)]
struct LargeData {
data: [u8; 1024], }
impl GcTrace for LargeData {
fn trace(&self, _: &mut GcTraceCtx) {}
}
#[derive(Debug, PartialEq)]
struct TestData {
value: i32,
name: String,
}
impl GcTrace for TestData {
fn trace(&self, _: &mut GcTraceCtx) {}
}
struct Node {
value: i32,
next: Option<GcRef<Node>>,
}
impl GcTrace for Node {
fn trace(&self, tr: &mut GcTraceCtx) {
if let Some(next) = self.next {
tr.add(next);
}
}
}
gc_type_register! {
LargeData;
TestData;
Node;
}