onion_vm/types/
async_handle.rs

1//! Onion 异步句柄模块。
2//!
3//! 提供 Onion 语言运行时的异步任务句柄实现,支持异步任务的状态管理、
4//! 结果缓存、GC 跟踪与类型扩展。可用于异步计算、并发调度和任务结果获取。
5//!
6//! # 主要功能
7//! - 异步任务的完成状态检测
8//! - 任务结果的安全存取与幂等设置
9//! - 支持 GC 跟踪与升级
10//! - 提供类型扩展与属性访问
11
12use std::{
13    any::Any,
14    collections::VecDeque,
15    fmt::{Debug, Formatter},
16    sync::{Arc, Mutex},
17};
18
19use arc_gc::{
20    arc::{GCArc, GCArcWeak},
21    gc::GC,
22    traceable::GCTraceable,
23};
24
25use crate::{
26    lambda::runnable::RuntimeError,
27    types::object::{GCArcStorage, OnionStaticObject},
28};
29
30use super::object::{OnionObject, OnionObjectCell, OnionObjectExt};
31
32/// Onion 异步任务句柄。
33///
34/// 封装异步任务的状态与结果,支持线程安全的并发访问。
35/// 通过内部弱引用缓存任务结果,避免循环引用导致的内存泄漏。
36///
37/// # 字段
38/// - `inner`: (弱引用结果, 完成状态) 的互斥封装
39pub struct OnionAsyncHandle {
40    inner: Mutex<(GCArcWeak<OnionObjectCell>, bool)>,
41}
42
43impl OnionAsyncHandle {
44    /// 创建一个新的异步句柄(未完成状态)。
45    ///
46    /// # 参数
47    /// - `gc`: Onion GC 管理器,用于分配初始结果对象
48    ///
49    /// # 返回
50    /// - `(Arc<Self>, GCArcStorage)`: 新的异步句柄和对应的 GC 存储
51    pub fn new(gc: &mut GC<OnionObjectCell>) -> (Arc<Self>, GCArcStorage) {
52        let tmp = gc.create(OnionObjectCell::from(OnionObject::Undefined(None)));
53        (
54            Arc::new(Self {
55                inner: Mutex::new((tmp.as_weak(), false)),
56            }),
57            GCArcStorage::Single(tmp),
58        )
59    }
60
61    /// 检查异步任务是否已完成。
62    ///
63    /// # 返回
64    /// - `true`: 任务已完成
65    /// - `false`: 任务仍在进行中
66    pub fn is_finished(&self) -> bool {
67        self.inner.lock().unwrap().1
68    }
69
70    /// 设置异步任务的结果。
71    ///
72    /// 线程安全地将结果写入内部缓存,并标记为完成。
73    /// 幂等操作,多次调用只会以最后一次为准。
74    ///
75    /// # 参数
76    /// - `result`: 要设置的任务结果对象
77    ///
78    /// # 返回
79    /// - `Ok(())`: 设置成功
80    /// - `Err(RuntimeError)`: 异步句柄已失效或引用断裂
81    pub fn set_result(&self, result: &OnionObject) -> Result<(), RuntimeError> {
82        let mut guard = self.inner.lock().unwrap();
83        guard.0.upgrade().map_or_else(
84            || Err(RuntimeError::BrokenReference),
85            |strong_ref| {
86                result.with_data(|data| {
87                    strong_ref.as_ref().with_data_mut(|strong_data| {
88                        *strong_data = data.clone();
89                        Ok(())
90                    })
91                })
92            },
93        )?;
94        guard.1 = true; // 设置为完成状态
95        Ok(())
96    }
97
98    /// 仅设置任务为完成状态,不写入结果。
99    ///
100    /// 适用于无返回值的异步任务。
101    pub fn set_finished(&self) {
102        let mut guard = self.inner.lock().unwrap();
103        guard.1 = true;
104    }
105}
106
107impl Debug for OnionAsyncHandle {
108    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
109        // 只打印 is_finished 状态,避免 Debug trait 问题
110        let guard = self.inner.lock().unwrap();
111        write!(f, "OnionAsyncHandle(finished: {})", guard.1)
112    }
113}
114
115impl GCTraceable<OnionObjectCell> for OnionAsyncHandle {
116    fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
117        let guard = self.inner.lock().unwrap();
118        queue.push_back(guard.0.clone());
119    }
120}
121
122impl OnionObjectExt for OnionAsyncHandle {
123    fn as_any(&self) -> &dyn Any {
124        self
125    }
126
127    fn repr(&self, _ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
128        Ok(format!("AsyncHandle(finished: {})", self.is_finished()))
129    }
130
131    fn equals(&self, _other: &OnionObject) -> Result<bool, RuntimeError> {
132        // Async handles are only equal if they're the exact same handle
133        Ok(false)
134    }
135
136    fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
137        let guard = self.inner.lock().unwrap();
138        if let Some(strong_ref) = guard.0.upgrade() {
139            collected.push(strong_ref);
140        }
141    }
142
143    fn to_boolean(&self) -> Result<bool, RuntimeError> {
144        // A async handle is "truthy" if it hasn't finished yet
145        Ok(!self.is_finished())
146    }
147
148    fn type_of(&self) -> Result<String, RuntimeError> {
149        Ok("AsyncHandle".to_string())
150    }
151
152    fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
153        let guard = self.inner.lock().unwrap();
154        let (ref weak_result, is_finished) = *guard;
155        if is_finished {
156            if let Some(strong_ref) = weak_result.upgrade() {
157                // 获取对象内容并 stabilize
158                strong_ref.as_ref().with_data(|data| Ok(data.stabilize()))
159            } else {
160                // 这种情况发生在用户尝试跨GC堆传递等情况,考虑到我们没有分布式GC,直接返回 BrokenReference
161                Err(RuntimeError::BrokenReference)
162            }
163        } else {
164            Err(RuntimeError::Pending)
165        }
166    }
167
168    fn to_string(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
169        let finished = self.is_finished();
170        if finished {
171            match self.value_of() {
172                Ok(val) => Ok(format!(
173                    "AsyncHandle(finished: true, result: {})",
174                    val.weak().to_string(ptrs)?
175                )),
176                Err(RuntimeError::BrokenReference) => {
177                    Ok("AsyncHandle(finished: true, result: <broken reference>)".to_string())
178                }
179                Err(_) => Ok("AsyncHandle(finished: true, result: <unknown error>)".to_string()),
180            }
181        } else {
182            let guard = self.inner.lock().unwrap();
183            let (ref weak_result, _) = *guard;
184            match weak_result.upgrade() {
185                Some(v) => Ok(format!(
186                    "AsyncHandle(finished: false, result: {:?})",
187                    v.as_ref().0.read().unwrap().to_string(ptrs)
188                )),
189                None => Ok("AsyncHandle(finished: false, result: <broken reference>)".to_string()),
190            }
191        }
192    }
193
194    fn with_attribute(
195        &self,
196        key: &OnionObject,
197        f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
198    ) -> Result<(), RuntimeError> {
199        match key {
200            OnionObject::String(s) => match s.as_ref() {
201                "is_finished" => f(&OnionObject::Boolean(self.is_finished())),
202                "has_result" => {
203                    let guard = self.inner.lock().unwrap();
204                    let has_result = guard.0.upgrade().is_some();
205                    f(&OnionObject::Boolean(has_result))
206                }
207                _ => Err(RuntimeError::InvalidOperation(
208                    format!("Attribute '{}' not found in AsyncHandle", s).into(),
209                )),
210            },
211            _ => Err(RuntimeError::InvalidOperation(
212                format!("Attribute {:?} not found in AsyncHandle", key).into(),
213            )),
214        }
215    }
216}