error_handling/
error_handling.rs1use gc_lite::{GcError, GcHeap, GcRef, GcResult, GcTrace, GcTraceCtx, gc_type_register};
13
14fn main() -> GcResult<()> {
15 println!("=== Error handling example of partitioned garbage collection system ===");
16
17 println!("\n=== Out of memory error handling ===");
19 demonstrate_out_of_memory()?;
20
21 println!("\n=== Partition management errors ===");
23 demonstrate_partition_management_errors()?;
24
25 println!("\n=== GC threshold API errors ===");
27 demonstrate_gc_threshold_errors()?;
28
29 println!("\nAll error handling demonstrations completed!");
30 Ok(())
31}
32
33fn demonstrate_out_of_memory() -> GcResult<()> {
35 println!("1. Create limited memory partition...");
36
37 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
38 context.set_memory_limit(2048); let partition_id = context.create_partition(64 * 1024, 16 * 1024);
40
41 println!("2. Allocate first large object...");
43 let gc1: GcRef<LargeData> =
44 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
45 Ok(gc_ref) => {
46 println!(" ✓ Successfully allocated first object (1KB)");
47 gc_ref
48 }
49 Err((error, _)) => {
50 println!(" ✗ First object allocation failed: {:?}", error);
51 return Ok(());
52 }
53 };
54
55 println!("3. Try to allocate second large object...");
57 match unsafe { context.alloc_raw(partition_id, LargeData { data: [0; 1024] }) } {
58 Err((GcError::PartitionFull, _)) => {
59 println!(" ✓ Correctly detected partition full error");
60 }
61 Ok(_) => {
62 println!(" ✗ Expected partition full error, but allocation succeeded");
63 return Ok(());
64 }
65 Err((other_error, _)) => {
66 println!(
67 " ✗ Expected partition full error, but got: {:?}",
68 other_error
69 );
70 return Ok(());
71 }
72 }
73
74 println!(" ✓ Automatic cleanup through GC");
76 context.garbage_collect(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
77
78 Ok(())
79}
80
81fn demonstrate_partition_management_errors() -> GcResult<()> {
83 println!("1. Test non-existent partition operations...");
84
85 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
86 let invalid_partition = gc_lite::GcPartitionId(9999); match unsafe {
90 context.alloc_raw(
91 invalid_partition,
92 TestData {
93 value: 42,
94 name: "test".to_string(),
95 },
96 )
97 } {
98 Err((GcError::PartitionNotFound, _)) => {
99 println!(" ✓ Allocating objects in non-existent partition returns correct error");
100 }
101 Ok(_) => {
102 println!(" ✗ Expected partition not found error, but allocation succeeded");
103 }
104 Err((other_error, _)) => {
105 println!(
106 " ✗ Expected partition not found error, but got: {:?}",
107 other_error
108 );
109 }
110 }
111
112 let partition_info = context.partition(invalid_partition);
114 assert!(
115 partition_info.is_none(),
116 "Non-existent partition should return None"
117 );
118 println!(" ✓ Getting non-existent partition info returns None");
119
120 context.remove_partition(invalid_partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
122 println!(" ✓ Removing non-existent partition silently fails");
123
124 println!("\n2. Test non-empty partition deletion...");
125 let partition_id = context.create_partition(64 * 1024, 16 * 1024);
126
127 let obj = unsafe {
129 context.alloc_raw(
130 partition_id,
131 TestData {
132 value: 1,
133 name: "obj".to_string(),
134 },
135 )
136 }
137 .unwrap();
138 let _ = obj;
139
140 context.remove_partition(partition_id, GcHeap::DUMMY_DISPOSE_CALLBACK);
142 println!(" ✓ Successfully deleted non-empty partition (root objects were force cleaned)");
143
144 Ok(())
145}
146
147fn demonstrate_gc_threshold_errors() -> GcResult<()> {
149 println!("1. Test GC threshold API...");
150
151 let mut context = GcHeap::new(&GC_TYPE_REGISTRY);
152 context.set_memory_limit(1024);
153 let _partition_id = context.create_partition(64 * 1024, 16 * 1024);
154
155 println!("2. Test default threshold...");
157 assert_eq!(context.gc_threshold(), 0);
158 println!(" ✓ Default threshold is 0, automatic GC disabled");
159
160 println!("3. Test setting threshold...");
162 context.set_gc_threshold(512);
163 assert_eq!(context.gc_threshold(), 512);
164 println!(" ✓ Successfully set threshold to 512, automatic GC enabled");
165
166 println!("4. Test setting threshold exceeding memory limit...");
168 context.set_gc_threshold(2048);
169 assert_eq!(context.gc_threshold(), 819);
171 println!(
172 " ✓ Setting threshold exceeding memory limit automatically adjusted to 0.8x of memory limit"
173 );
174
175 println!("5. Test disabling automatic GC...");
177 context.set_gc_threshold(0);
178 assert_eq!(context.gc_threshold(), 0);
179 println!(" ✓ Successfully disabled automatic GC, threshold set to 0");
180
181 Ok(())
182}
183
184#[derive(Debug)]
188struct LargeData {
189 data: [u8; 1024], }
191
192impl GcTrace for LargeData {
193 fn trace(&self, _: &mut GcTraceCtx) {}
194}
195
196#[derive(Debug, PartialEq)]
198struct TestData {
199 value: i32,
200 name: String,
201}
202
203impl GcTrace for TestData {
204 fn trace(&self, _: &mut GcTraceCtx) {}
205}
206
207struct Node {
209 value: i32,
210 next: Option<GcRef<Node>>,
211}
212
213impl GcTrace for Node {
214 fn trace(&self, tr: &mut GcTraceCtx) {
215 if let Some(next) = self.next {
216 tr.add(next);
217 }
218 }
219}
220
221gc_type_register! {
222 LargeData;
223 TestData;
224 Node;
225}