gc-lite 0.4.2

A simple partitioned garbage collector
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 John Ray <996351336@qq.com>

//! Advanced features example
//!
//! Demonstrates advanced features of the partitioned garbage collection system, including:
//! - Weak references and circular reference handling
//! - Complex data structures
//! - Reference recovery and validation
//! - Cross-context object detection

use std::ops::Deref;

use gc_lite::{GcHeap, GcRef, GcResult, GcTrace, GcTraceCtx, gc_type_register};

#[derive(Debug)]
struct MyString(String);

impl PartialEq<str> for MyString {
    fn eq(&self, other: &str) -> bool {
        self.0 == other
    }
}

impl GcTrace for MyString {
    fn trace(&self, _: &mut GcTraceCtx) {}
}

impl std::fmt::Display for MyString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

gc_type_register! {
    MyString;
    CyclicNode;
    TreeNode;
    DataContainer;
    TestData;
}

fn new_heap() -> GcHeap {
    GcHeap::new(&GC_TYPE_REGISTRY)
}

fn main() -> GcResult<()> {
    println!("=== Advanced features example of partitioned garbage collection system ===");

    let mut heap = new_heap();
    let partition = heap.create_partition();

    // Demonstrate weak reference functionality
    println!("\n=== Weak reference functionality demonstration ===");
    demonstrate_weak_references(&mut heap, partition)?;

    // Demonstrate circular reference handling
    println!("\n=== Circular reference handling demonstration ===");
    demonstrate_cyclic_references(&mut heap, partition)?;

    // Demonstrate complex data structures
    println!("\n=== Complex data structures demonstration ===");
    demonstrate_complex_structures(&mut heap, partition)?;

    // Demonstrate reference recovery functionality
    println!("\n=== Reference recovery functionality demonstration ===");
    demonstrate_reference_recovery(&mut heap, partition)?;

    // Demonstrate cross-context detection
    println!("\n=== Cross-context detection demonstration ===");
    demonstrate_cross_context_detection()?;

    println!("\nAll advanced feature demonstrations completed!");
    Ok(())
}

/// Demonstrate weak reference functionality
fn demonstrate_weak_references(
    heap: &mut GcHeap,
    partition: gc_lite::GcPartitionId,
) -> GcResult<()> {
    println!("1. Create strong and weak references...");

    let strong_ref =
        unsafe { heap.alloc_root_raw(partition, MyString(String::from("Strong Reference Data"))) }
            .map_err(|(err, _)| err)?;

    let weak_ref = heap.downgrade(&strong_ref);
    println!("  Created strong reference: {:?}", strong_ref);
    println!("  Created weak reference: {:?}", weak_ref);

    // Upgrade weak reference
    println!("\n2. Upgrade weak reference...");
    match weak_ref.upgrade(heap) {
        Some(upgraded) => {
            let data = upgraded.deref();
            println!("  Weak reference upgrade successful: '{}'", data);
            assert_eq!(data, "Strong Reference Data");
        }
        None => println!("  Weak reference upgrade failed"),
    }

    // Try upgrading after releasing strong reference
    println!("\n3. Upgrade weak reference after releasing strong reference...");
    heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);

    match weak_ref.upgrade(heap) {
        Some(_) => {
            println!("  Weak reference can still be upgraded (object may still be in memory)")
        }
        None => println!("  Weak reference upgrade failed (object has been collected)"),
    }

    Ok(())
}

/// Demonstrate circular reference handling
fn demonstrate_cyclic_references(
    heap: &mut GcHeap,
    partition: gc_lite::GcPartitionId,
) -> GcResult<()> {
    println!("1. Create circular reference nodes...");

    // Create two mutually referencing nodes
    let mut node1 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node A")) }
        .map_err(|(err, _)| err)?;
    let mut node2 = unsafe { heap.alloc_root_raw(partition, CyclicNode::new("Node B")) }
        .map_err(|(err, _)| err)?;

    // Establish circular references
    {
        node1.with_mut(heap, |n| n.set_partner(node2));
        node2.with_mut(heap, |n| n.set_partner(node1));
    }

    println!("  Created node1: {}", node1.deref());
    println!("  Created node2: {}", node2.deref());

    // Trigger garbage collection
    println!("\n2. Trigger garbage collection (circular references still exist)...");
    let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
    println!("  回收了 {} 字节内存", freed);

    // Verify circular references still exist
    println!("\n3. Verify circular references...");
    println!("  Node1's partner: {}", node1.get_partner_name());
    println!("  Node2's partner: {}", node2.get_partner_name());

    // Clear root object status, let circular references be collected
    println!("\n4. Clear root object status and trigger GC again...");
    let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
    println!(
        "  Freed {} bytes of memory (circular references correctly collected)",
        freed
    );

    Ok(())
}

/// Demonstrate complex data structures
fn demonstrate_complex_structures(
    heap: &mut GcHeap,
    partition: gc_lite::GcPartitionId,
) -> GcResult<()> {
    println!("1. Create complex data structures...");

    // Create multiple nodes
    let mut root_node =
        unsafe { heap.alloc_root_raw(partition, TreeNode::new("Root")) }.map_err(|(err, _)| err)?;
    let mut child1 =
        unsafe { heap.alloc_raw(partition, TreeNode::new("Child 1")) }.map_err(|(err, _)| err)?;
    let child2 =
        unsafe { heap.alloc_raw(partition, TreeNode::new("Child 2")) }.map_err(|(err, _)| err)?;
    let grandchild = unsafe { heap.alloc_raw(partition, TreeNode::new("Grandchild")) }
        .map_err(|(err, _)| err)?;

    // Build tree structure
    {
        root_node.with_mut(heap, |n| n.add_child(child1));
        root_node.with_mut(heap, |n| n.add_child(child2));
        child1.with_mut(heap, |n| n.add_child(grandchild));
    }

    // Create data container
    let container = unsafe {
        heap.alloc_root_raw(
            partition,
            DataContainer {
                root: root_node,
                metadata: vec![1, 2, 3],
                optional_data: Some(child1),
            },
        )
    }
    .map_err(|(err, _)| err)?;

    println!("  Created tree structure:");
    println!("    Root -> Child 1 -> Grandchild");
    println!("    Root -> Child 2");
    println!("  Created data container");

    // Trigger garbage collection
    println!("\n2. Trigger garbage collection...");
    let freed = heap.garbage_collect(partition, GcHeap::DUMMY_DISPOSE_CALLBACK);
    println!("  回收了 {} 字节内存", freed);

    // Verify data structure integrity
    println!("\n3. Verify data structure integrity...");
    {
        println!("  Container root node: {}", container.root.name);
        println!("  Metadata length: {}", container.metadata.len());
        println!(
            "  Optional data exists: {}",
            container.optional_data.is_some()
        );
    }

    Ok(())
}

/// Demonstrate reference recovery functionality
fn demonstrate_reference_recovery(
    heap: &mut GcHeap,
    partition: gc_lite::GcPartitionId,
) -> GcResult<()> {
    println!("1. Create object and get reference...");

    let original_ref = unsafe {
        heap.alloc_raw(
            partition,
            TestData {
                value: 42,
                name: "test".to_string(),
            },
        )
    }
    .map_err(|(err, _)| err)?;

    let data_ref = original_ref.deref();
    println!("  Original reference: {:?}", original_ref);
    println!("  Data: {:?}", data_ref);

    // Recover GcRef from reference
    println!("\n2. Recover GcRef from reference...");
    let recovered_ref = GcRef::try_from_ref(heap, data_ref);

    match recovered_ref {
        Some(recovered) => {
            println!("  Recovery successful: {:?}", recovered);
            let recovered_data = recovered.deref();
            println!("  Recovered data: {:?}", recovered_data);
            println!("  Data equal: {}", data_ref == recovered_data);
            println!("  Reference equal: {}", original_ref == recovered);
        }
        None => println!("  Recovery failed (possibly type registration issue)"),
    }

    // Test invalid reference recovery - create an object not in GC heap
    println!("\n3. Test invalid reference recovery...");
    let local_data = TestData {
        value: 100,
        name: "local".to_string(),
    };
    let invalid_result = GcRef::try_from_ref(heap, &local_data);
    println!(
        "  Invalid reference recovery result: {:?} (should be None)",
        invalid_result
    );

    Ok(())
}

/// Demonstrate cross-context detection
fn demonstrate_cross_context_detection() -> GcResult<()> {
    println!("1. Create two independent heaps...");

    let mut heap1 = new_heap();
    let mut heap2 = new_heap();

    let partition1 = heap1.create_partition();
    let partition2 = heap2.create_partition();

    let obj1 = unsafe {
        heap1.alloc_root_raw(
            partition1,
            TestData {
                value: 1,
                name: "obj1".to_string(),
            },
        )
    }
    .map_err(|(e, _)| e)?;
    let obj2 = unsafe {
        heap2.alloc_raw(
            partition2,
            TestData {
                value: 2,
                name: "obj2".to_string(),
            },
        )
    }
    .map_err(|(e, _)| e)?;

    println!("2. Test object source detection...");
    assert!(heap1.contains(obj1.node_ptr()), "obj1 should be from heap1");
    assert!(
        !heap1.contains(obj2.node_ptr()),
        "obj2 should not be from heap1"
    );
    assert!(heap2.contains(obj2.node_ptr()), "obj2 should be from heap2");
    assert!(
        !heap2.contains(obj1.node_ptr()),
        "obj1 should not be from heap2"
    );

    println!("  ✓ Cross-context detection correct");

    // Clean up
    heap1.garbage_collect(partition1, GcHeap::DUMMY_DISPOSE_CALLBACK);
    heap2.garbage_collect(partition2, GcHeap::DUMMY_DISPOSE_CALLBACK);

    Ok(())
}

// Supporting type definitions

/// Circular reference node
#[derive(Debug)]
struct CyclicNode {
    name: String,
    partner: Option<GcRef<CyclicNode>>,
}

impl CyclicNode {
    fn new(name: &str) -> Self {
        Self {
            name: name.to_string(),
            partner: None,
        }
    }

    fn set_partner(&mut self, partner: GcRef<CyclicNode>) {
        self.partner = Some(partner);
    }

    fn get_partner_name(&self) -> String {
        self.partner
            .map(|p| p.name.clone())
            .unwrap_or_else(|| "None".to_string())
    }
}

impl GcTrace for CyclicNode {
    fn trace(&self, tr: &mut GcTraceCtx) {
        if let Some(partner) = self.partner {
            tr.add(partner);
        }
    }
}

impl std::fmt::Display for CyclicNode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "CyclicNode({})", self.name)
    }
}

/// Tree node
#[derive(Debug)]
struct TreeNode {
    name: String,
    children: Vec<GcRef<TreeNode>>,
}

impl TreeNode {
    fn new(name: &str) -> Self {
        Self {
            name: name.to_string(),
            children: Vec::new(),
        }
    }

    fn add_child(&mut self, child: GcRef<TreeNode>) {
        self.children.push(child);
    }
}

impl GcTrace for TreeNode {
    fn trace(&self, tr: &mut GcTraceCtx) {
        for child in &self.children {
            tr.add(*child);
        }
    }
}

impl std::fmt::Display for TreeNode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "TreeNode({}, {} children)",
            self.name,
            self.children.len()
        )
    }
}

/// Data container
#[derive(Debug)]
struct DataContainer {
    root: GcRef<TreeNode>,
    metadata: Vec<i32>,
    optional_data: Option<GcRef<TreeNode>>,
}

impl GcTrace for DataContainer {
    fn trace(&self, tr: &mut GcTraceCtx) {
        tr.add(self.root);
        if let Some(data) = self.optional_data {
            tr.add(data);
        }
    }
}

/// Test data
#[derive(Debug, PartialEq)]
struct TestData {
    value: i32,
    name: String,
}

impl GcTrace for TestData {
    fn trace(&self, _: &mut GcTraceCtx) {
        // No references to trace
    }
}