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