Skip to main content

oxihuman_core/
weak_reference.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Weak reference stub — tracks whether an associated strong handle is still
6//! alive using a shared liveness flag, without prolonging the object's
7//! lifetime.
8
9use std::cell::Cell;
10use std::rc::Rc;
11
12/// Shared liveness token.
13struct Token {
14    alive: Cell<bool>,
15}
16
17/// A strong owner that keeps the liveness token set.
18pub struct StrongOwner<T> {
19    value: T,
20    token: Rc<Token>,
21}
22
23impl<T> StrongOwner<T> {
24    /// Create a new strong owner.
25    pub fn new(value: T) -> (Self, WeakRef<T>) {
26        let token = Rc::new(Token {
27            alive: Cell::new(true),
28        });
29        let weak = WeakRef {
30            token: Rc::clone(&token),
31            _marker: std::marker::PhantomData,
32        };
33        (Self { value, token }, weak)
34    }
35
36    /// Access the inner value.
37    pub fn get(&self) -> &T {
38        &self.value
39    }
40}
41
42impl<T> Drop for StrongOwner<T> {
43    fn drop(&mut self) {
44        self.token.alive.set(false);
45    }
46}
47
48/// A weak reference that cannot prevent the owner from dropping.
49pub struct WeakRef<T> {
50    token: Rc<Token>,
51    _marker: std::marker::PhantomData<*const T>,
52}
53
54impl<T> WeakRef<T> {
55    /// Returns true if the associated strong owner is still alive.
56    pub fn is_alive(&self) -> bool {
57        self.token.alive.get()
58    }
59
60    /// Returns false if the strong owner has been dropped.
61    pub fn is_dangling(&self) -> bool {
62        !self.is_alive()
63    }
64
65    /// Count of alive references to the token.
66    pub fn token_ref_count(&self) -> usize {
67        Rc::strong_count(&self.token)
68    }
69}
70
71/// Create a strong owner and its weak reference.
72pub fn new_weak_pair<T>(value: T) -> (StrongOwner<T>, WeakRef<T>) {
73    StrongOwner::new(value)
74}
75
76/// Check whether a weak reference is still alive.
77pub fn weak_is_alive<T>(w: &WeakRef<T>) -> bool {
78    w.is_alive()
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_alive_while_owner_exists() {
87        let (owner, weak) = StrongOwner::new(42);
88        assert!(weak.is_alive()); /* alive while owner lives */
89        drop(owner);
90    }
91
92    #[test]
93    fn test_dangling_after_owner_drop() {
94        let (owner, weak) = StrongOwner::new(42);
95        drop(owner);
96        assert!(weak.is_dangling()); /* dangling after drop */
97    }
98
99    #[test]
100    fn test_get() {
101        let (owner, _weak) = StrongOwner::new(99);
102        assert_eq!(*owner.get(), 99); /* value accessible */
103    }
104
105    #[test]
106    fn test_is_alive_helper() {
107        let (_owner, weak) = StrongOwner::new(0);
108        assert!(weak_is_alive(&weak)); /* helper works */
109    }
110
111    #[test]
112    fn test_new_pair_helper() {
113        let (_owner, weak) = new_weak_pair(1u32);
114        assert!(weak.is_alive()); /* pair helper works */
115    }
116
117    #[test]
118    fn test_multiple_weakrefs_not_supported_directly() {
119        /* WeakRef is not Clone; only one per owner, test owner drop */
120        let (owner, weak) = StrongOwner::new("hello");
121        assert!(weak.is_alive());
122        drop(owner);
123        assert!(!weak.is_alive()); /* confirmed dead */
124    }
125
126    #[test]
127    fn test_token_ref_count_alive() {
128        let (_owner, weak) = StrongOwner::new(5);
129        /* owner holds one Rc, weak holds one */
130        assert_eq!(weak.token_ref_count(), 2); /* two refs to token */
131    }
132
133    #[test]
134    fn test_token_ref_count_dead() {
135        let (owner, weak) = StrongOwner::new(5);
136        drop(owner);
137        assert_eq!(weak.token_ref_count(), 1); /* only weak left */
138    }
139
140    #[test]
141    fn test_is_not_dangling_when_alive() {
142        let (_owner, weak) = StrongOwner::new(0);
143        assert!(!weak.is_dangling()); /* not dangling while alive */
144    }
145
146    #[test]
147    fn test_string_value() {
148        let (owner, weak) = StrongOwner::new(String::from("hello"));
149        assert_eq!(owner.get(), "hello");
150        drop(owner);
151        assert!(weak.is_dangling()); /* dangling after drop */
152    }
153}