Skip to main content

advanced_features/
advanced_features.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright (c) 2025-2026 John Ray <996351336@qq.com>
3
4//! Advanced features example
5//!
6//! Demonstrates advanced features of the partitioned garbage collection system, including:
7//! - Weak references and circular reference handling
8//! - Complex data structures
9//! - Reference recovery and validation
10//! - Cross-context object detection
11
12use gc_lite::{GcHeap, GcRef, GcResult, GcTrace, GcTraceCtx, gc_type_register};
13
14#[derive(Debug)]
15struct MyString(String);
16
17impl PartialEq<str> for MyString {
18    fn eq(&self, other: &str) -> bool {
19        self.0 == other
20    }
21}
22
23impl GcTrace for MyString {
24    fn trace(&self, _: &mut GcTraceCtx) {}
25}
26
27impl std::fmt::Display for MyString {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        self.0.fmt(f)
30    }
31}
32
33gc_type_register! {
34    MyString;
35    CyclicNode;
36    TreeNode;
37    DataContainer;
38    TestData;
39}
40
41fn new_heap() -> GcHeap {
42    GcHeap::new(&GC_TYPE_REGISTRY)
43}
44
45fn main() -> GcResult<()> {
46    println!("=== Advanced features example of partitioned garbage collection system ===");
47
48    let mut heap = new_heap();
49    let partition = heap.create_partition(64 * 1024, 16 * 1024);
50
51    // Demonstrate weak reference functionality
52    println!("\n=== Weak reference functionality demonstration ===");
53    demonstrate_weak_references(&mut heap, partition)?;
54
55    // Demonstrate circular reference handling
56    println!("\n=== Circular reference handling demonstration ===");
57    demonstrate_cyclic_references(&mut heap, partition)?;
58
59    // Demonstrate complex data structures
60    println!("\n=== Complex data structures demonstration ===");
61    demonstrate_complex_structures(&mut heap, partition)?;
62
63    // Demonstrate reference recovery functionality
64    println!("\n=== Reference recovery functionality demonstration ===");
65    demonstrate_reference_recovery(&mut heap, partition)?;
66
67    // Demonstrate cross-context detection
68    println!("\n=== Cross-context detection demonstration ===");
69    demonstrate_cross_context_detection()?;
70
71    println!("\nAll advanced feature demonstrations completed!");
72    Ok(())
73}
74
75/// Demonstrate weak reference functionality
76fn demonstrate_weak_references(
77    heap: &mut GcHeap,
78    partition: gc_lite::GcPartitionId,
79) -> GcResult<()> {
80    println!("1. Create strong and weak references...");
81
82    let strong_ref =
83        unsafe { heap.alloc_root_raw(partition, MyString(String::from("Strong Reference Data"))) }
84            .map_err(|(err, _)| err)?;
85
86    let weak_ref = heap.downgrade(&strong_ref);
87    println!("  Created strong reference: {:?}", strong_ref);
88    println!("  Created weak reference: {:?}", weak_ref);
89
90    // Upgrade weak reference
91    println!("\n2. Upgrade weak reference...");
92    match weak_ref.upgrade(heap) {
93        Some(upgraded) => {
94            let data = &*upgraded;
95            println!("  Weak reference upgrade successful: '{}'", data);
96            assert_eq!(data, "Strong Reference Data");
97        }
98        None => println!("  Weak reference upgrade failed"),
99    }
100
101    // Try upgrading after releasing strong reference
102    println!("\n3. Upgrade weak reference after releasing strong reference...");
103    heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
104
105    match weak_ref.upgrade(heap) {
106        Some(_) => {
107            println!("  Weak reference can still be upgraded (object may still be in memory)")
108        }
109        None => println!("  Weak reference upgrade failed (object has been collected)"),
110    }
111
112    Ok(())
113}
114
115/// Demonstrate circular reference handling
116fn demonstrate_cyclic_references(
117    heap: &mut GcHeap,
118    partition: gc_lite::GcPartitionId,
119) -> GcResult<()> {
120    println!("1. Create circular reference nodes...");
121
122    // Create two mutually referencing nodes
123    let mut node1 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node A")) }
124        .map_err(|(err, _)| err)?;
125    let mut node2 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node B")) }
126        .map_err(|(err, _)| err)?;
127
128    // Establish circular references
129    {
130        unsafe {
131            node1.with_write_barrier(heap, |n| n.set_partner(node2));
132        }
133        unsafe {
134            node2.with_write_barrier(heap, |n| n.set_partner(node1));
135        }
136    }
137
138    println!("  Created node1: {}", unsafe { node1.as_ref() });
139    println!("  Created node2: {}", unsafe { node2.as_ref() });
140
141    // Trigger garbage collection
142    println!("\n2. Trigger garbage collection (circular references still exist)...");
143    let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
144    println!("  回收了 {} 字节内存", freed);
145
146    // Verify circular references still exist
147    println!("\n3. Verify circular references...");
148    println!(
149        "  Node1's partner: {}",
150        unsafe { node1.as_ref() }.get_partner_name()
151    );
152    println!(
153        "  Node2's partner: {}",
154        unsafe { node2.as_ref() }.get_partner_name()
155    );
156
157    // Clear root object status, let circular references be collected
158    println!("\n4. Clear root object status and trigger GC again...");
159    let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
160    println!(
161        "  Freed {} bytes of memory (circular references correctly collected)",
162        freed
163    );
164
165    Ok(())
166}
167
168/// Demonstrate complex data structures
169fn demonstrate_complex_structures(
170    heap: &mut GcHeap,
171    partition: gc_lite::GcPartitionId,
172) -> GcResult<()> {
173    println!("1. Create complex data structures...");
174
175    // Create multiple nodes
176    let mut root_node =
177        unsafe { heap.alloc_root_raw(partition, TreeNode::new("Root")) }.map_err(|(err, _)| err)?;
178    let mut child1 =
179        unsafe { heap.alloc_raw(partition, TreeNode::new("Child 1")) }.map_err(|(err, _)| err)?;
180    let child2 =
181        unsafe { heap.alloc_raw(partition, TreeNode::new("Child 2")) }.map_err(|(err, _)| err)?;
182    let grandchild = unsafe { heap.alloc_raw(partition, TreeNode::new("Grandchild")) }
183        .map_err(|(err, _)| err)?;
184
185    // Build tree structure
186    {
187        unsafe {
188            root_node.with_write_barrier(heap, |n| n.add_child(child1));
189        }
190        unsafe {
191            root_node.with_write_barrier(heap, |n| n.add_child(child2));
192        }
193        unsafe {
194            child1.with_write_barrier(heap, |n| n.add_child(grandchild));
195        }
196    }
197
198    // Create data container
199    let container = unsafe {
200        heap.alloc_root_raw(
201            partition,
202            DataContainer {
203                root: root_node,
204                metadata: vec![1, 2, 3],
205                optional_data: Some(child1),
206            },
207        )
208    }
209    .map_err(|(err, _)| err)?;
210
211    println!("  Created tree structure:");
212    println!("    Root -> Child 1 -> Grandchild");
213    println!("    Root -> Child 2");
214    println!("  Created data container");
215
216    // Trigger garbage collection
217    println!("\n2. Trigger garbage collection...");
218    let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
219    println!("  回收了 {} 字节内存", freed);
220
221    // Verify data structure integrity
222    println!("\n3. Verify data structure integrity...");
223    {
224        let container_ref = unsafe { container.as_ref() };
225        println!(
226            "  Container root node: {}",
227            unsafe { container_ref.root.as_ref() }.name
228        );
229        println!("  Metadata length: {}", container_ref.metadata.len());
230        println!(
231            "  Optional data exists: {}",
232            container_ref.optional_data.is_some()
233        );
234    }
235
236    Ok(())
237}
238
239/// Demonstrate reference recovery functionality
240fn demonstrate_reference_recovery(
241    heap: &mut GcHeap,
242    partition: gc_lite::GcPartitionId,
243) -> GcResult<()> {
244    println!("1. Create object and get reference...");
245
246    let original_ref = unsafe {
247        heap.alloc_raw(
248            partition,
249            TestData {
250                value: 42,
251                name: "test".to_string(),
252            },
253        )
254    }
255    .map_err(|(err, _)| err)?;
256
257    let data_ref = unsafe { original_ref.as_ref() };
258    println!("  Original reference: {:?}", original_ref);
259    println!("  Data: {:?}", data_ref);
260
261    // Recover GcRef from reference
262    println!("\n2. Recover GcRef from reference...");
263    let recovered_ref = unsafe { GcRef::try_from_ref(heap, data_ref) };
264
265    match recovered_ref {
266        Some(recovered) => {
267            println!("  Recovery successful: {:?}", recovered);
268            let recovered_data = unsafe { recovered.as_ref() };
269            println!("  Recovered data: {:?}", recovered_data);
270            println!("  Data equal: {}", data_ref == recovered_data);
271            println!("  Reference equal: {}", original_ref == recovered);
272        }
273        None => println!("  Recovery failed (possibly type registration issue)"),
274    }
275
276    // Test invalid reference recovery - create an object not in GC heap
277    println!("\n3. Test invalid reference recovery...");
278    let local_data = TestData {
279        value: 100,
280        name: "local".to_string(),
281    };
282    let invalid_result = unsafe { GcRef::try_from_ref(heap, &local_data) };
283    println!(
284        "  Invalid reference recovery result: {:?} (should be None)",
285        invalid_result
286    );
287
288    Ok(())
289}
290
291/// Demonstrate cross-context detection
292fn demonstrate_cross_context_detection() -> GcResult<()> {
293    println!("1. Create two independent heaps...");
294
295    let mut heap1 = new_heap();
296    let mut heap2 = new_heap();
297
298    let partition1 = heap1.create_partition(64 * 1024, 16 * 1024);
299    let partition2 = heap2.create_partition(64 * 1024, 16 * 1024);
300
301    let obj1 = unsafe {
302        heap1.alloc_root_raw(
303            partition1,
304            TestData {
305                value: 1,
306                name: "obj1".to_string(),
307            },
308        )
309    }
310    .map_err(|(e, _)| e)?;
311    let obj2 = unsafe {
312        heap2.alloc_raw(
313            partition2,
314            TestData {
315                value: 2,
316                name: "obj2".to_string(),
317            },
318        )
319    }
320    .map_err(|(e, _)| e)?;
321
322    println!("2. Test object source detection...");
323    assert!(heap1.contains(obj1.node_ptr()), "obj1 should be from heap1");
324    assert!(
325        !heap1.contains(obj2.node_ptr()),
326        "obj2 should not be from heap1"
327    );
328    assert!(heap2.contains(obj2.node_ptr()), "obj2 should be from heap2");
329    assert!(
330        !heap2.contains(obj1.node_ptr()),
331        "obj1 should not be from heap2"
332    );
333
334    println!("  ✓ Cross-context detection correct");
335
336    // Clean up
337    heap1.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
338    heap2.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);
339
340    Ok(())
341}
342
343// Supporting type definitions
344
345/// Circular reference node
346#[derive(Debug)]
347struct CyclicNode {
348    name: String,
349    partner: Option<GcRef<CyclicNode>>,
350}
351
352impl CyclicNode {
353    fn new(name: &str) -> Self {
354        Self {
355            name: name.to_string(),
356            partner: None,
357        }
358    }
359
360    fn set_partner(&mut self, partner: GcRef<CyclicNode>) {
361        self.partner = Some(partner);
362    }
363
364    fn get_partner_name(&self) -> String {
365        self.partner
366            .map(|p| unsafe { p.as_ref() }.name.clone())
367            .unwrap_or_else(|| "None".to_string())
368    }
369}
370
371impl GcTrace for CyclicNode {
372    fn trace(&self, tr: &mut GcTraceCtx) {
373        if let Some(partner) = self.partner {
374            tr.add(partner);
375        }
376    }
377}
378
379impl std::fmt::Display for CyclicNode {
380    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
381        write!(f, "CyclicNode({})", self.name)
382    }
383}
384
385/// Tree node
386#[derive(Debug)]
387struct TreeNode {
388    name: String,
389    children: Vec<GcRef<TreeNode>>,
390}
391
392impl TreeNode {
393    fn new(name: &str) -> Self {
394        Self {
395            name: name.to_string(),
396            children: Vec::new(),
397        }
398    }
399
400    fn add_child(&mut self, child: GcRef<TreeNode>) {
401        self.children.push(child);
402    }
403}
404
405impl GcTrace for TreeNode {
406    fn trace(&self, tr: &mut GcTraceCtx) {
407        for child in &self.children {
408            tr.add(*child);
409        }
410    }
411}
412
413impl std::fmt::Display for TreeNode {
414    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415        write!(
416            f,
417            "TreeNode({}, {} children)",
418            self.name,
419            self.children.len()
420        )
421    }
422}
423
424/// Data container
425#[derive(Debug)]
426struct DataContainer {
427    root: GcRef<TreeNode>,
428    metadata: Vec<i32>,
429    optional_data: Option<GcRef<TreeNode>>,
430}
431
432impl GcTrace for DataContainer {
433    fn trace(&self, tr: &mut GcTraceCtx) {
434        tr.add(self.root);
435        if let Some(data) = self.optional_data {
436            tr.add(data);
437        }
438    }
439}
440
441/// Test data
442#[derive(Debug, PartialEq)]
443struct TestData {
444    value: i32,
445    name: String,
446}
447
448impl GcTrace for TestData {
449    fn trace(&self, _: &mut GcTraceCtx) {
450        // No references to trace
451    }
452}