onion_vm/types/
thread_handle.rs

1use std::{
2    any::Any,
3    collections::VecDeque,
4    fmt::{Debug, Formatter},
5    sync::{Arc, Mutex},
6    thread::JoinHandle,
7};
8
9use arc_gc::{arc::GCArc, arc::GCArcWeak, traceable::GCTraceable};
10
11use crate::{lambda::runnable::RuntimeError, types::object::OnionStaticObject};
12
13use super::object::{OnionObject, OnionObjectCell, OnionObjectExt};
14
15/// A wrapper around JoinHandle to make it work with OnionObject
16pub struct OnionThreadHandle {
17    handle: Mutex<Option<JoinHandle<Result<Box<OnionStaticObject>, RuntimeError>>>>,
18    is_finished: Mutex<bool>,
19    cached_result: Mutex<Option<Result<OnionStaticObject, RuntimeError>>>,
20}
21
22impl OnionThreadHandle {
23    pub fn new(handle: JoinHandle<Result<Box<OnionStaticObject>, RuntimeError>>) -> Self {
24        Self {
25            handle: Mutex::new(Some(handle)),
26            is_finished: Mutex::new(false),
27            cached_result: Mutex::new(None),
28        }
29    }
30    /// Check if the thread has finished without blocking
31    pub fn is_finished(&self) -> bool {
32        *self.is_finished.lock().unwrap() || self.handle.lock().unwrap().is_none()
33    }
34}
35
36impl Clone for OnionThreadHandle {
37    fn clone(&self) -> Self {
38        // JoinHandle cannot be cloned, so we create a new handle that's already finished
39        Self {
40            handle: Mutex::new(None),
41            is_finished: Mutex::new(*self.is_finished.lock().unwrap()),
42            cached_result: Mutex::new(self.cached_result.lock().unwrap().clone()),
43        }
44    }
45}
46
47impl Debug for OnionThreadHandle {
48    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
49        write!(
50            f,
51            "OnionThreadHandle(finished: {}, has_handle: {})",
52            self.is_finished(),
53            self.handle.lock().unwrap().is_some()
54        )
55    }
56}
57
58impl GCTraceable<OnionObjectCell> for OnionThreadHandle {
59    fn collect(&self, _queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
60        // Thread handles don't contain OnionObjects, so nothing to collect
61    }
62}
63
64impl OnionObjectExt for OnionThreadHandle {
65    fn as_any(&self) -> &dyn Any {
66        self
67    }
68
69    fn repr(&self, _ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
70        Ok(format!("ThreadHandle(finished: {})", self.is_finished()))
71    }
72
73    fn equals(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
74        // Thread handles are only equal if they're the exact same handle
75        if let OnionObject::Custom(other_custom) = other {
76            if let Some(_other_handle) = other_custom.as_any().downcast_ref::<OnionThreadHandle>() {
77                // Since we can't compare JoinHandles directly, we consider them not equal
78                // unless they're the exact same Arc (which would be checked by is_same)
79                Ok(false)
80            } else {
81                Ok(false)
82            }
83        } else {
84            Ok(false)
85        }
86    }
87
88    fn upgrade(&self, _collected: &mut Vec<GCArc<OnionObjectCell>>) {
89        // Thread handles don't contain OnionObjects, so nothing to upgrade
90    }
91
92    fn reconstruct_container(&self) -> Result<OnionObject, RuntimeError> {
93        Ok(OnionObject::Custom(Arc::new(self.clone())))
94    }
95
96    fn is_same(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
97        if let OnionObject::Custom(other_custom) = other {
98            if let Some(other_handle) = other_custom.as_any().downcast_ref::<OnionThreadHandle>() {
99                // Use pointer equality to check if it's the same Arc
100                Ok(std::ptr::eq(self, other_handle))
101            } else {
102                Ok(false)
103            }
104        } else {
105            Ok(false)
106        }
107    }
108
109    fn to_boolean(&self) -> Result<bool, RuntimeError> {
110        // A thread handle is "truthy" if it hasn't finished yet
111        Ok(!self.is_finished())
112    }
113
114    fn type_of(&self) -> Result<String, RuntimeError> {
115        Ok("ThreadHandle".to_string())
116    }
117
118    fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
119        // 检查是否已有缓存结果
120        if let Some(ref cached) = *self.cached_result.lock().unwrap() {
121            return cached.clone();
122        }
123
124        // 阻塞并获取线程结果
125        let mut handle_guard = self.handle.lock().unwrap();
126        if let Some(handle) = handle_guard.take() {
127            *self.is_finished.lock().unwrap() = true;
128            drop(handle_guard); // 释放锁
129
130            let result = match handle.join() {
131                Ok(result) => match result {
132                    Ok(object) => Ok(object.as_ref().clone()),
133                    Err(err) => Err(err),
134                },
135                Err(_) => Err(RuntimeError::DetailedError(
136                    "Thread panicked during execution".to_string().into(),
137                )),
138            };
139
140            // 缓存结果
141            *self.cached_result.lock().unwrap() = Some(result.clone());
142            result
143        } else {
144            Err(RuntimeError::DetailedError(
145                "Thread has already finished".to_string().into(),
146            ))
147        }
148    }
149
150    fn with_attribute(
151        &self,
152        key: &OnionObject,
153        f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
154    ) -> Result<(), RuntimeError> {
155        match key {
156            OnionObject::String(s) => match s.as_str() {
157                "is_finished" => f(&OnionObject::Boolean(self.is_finished())),
158                "has_handle" => {
159                    let has_handle = self.handle.lock().unwrap().is_some();
160                    f(&OnionObject::Boolean(has_handle))
161                }
162                "has_result" => {
163                    let has_result = self.cached_result.lock().unwrap().is_some();
164                    f(&OnionObject::Boolean(has_result))
165                }
166                "is_success" => {
167                    if let Some(ref cached) = *self.cached_result.lock().unwrap() {
168                        f(&OnionObject::Boolean(cached.is_ok()))
169                    } else {
170                        f(&OnionObject::Boolean(false)) // 还没有结果
171                    }
172                }
173                "is_error" => {
174                    if let Some(ref cached) = *self.cached_result.lock().unwrap() {
175                        f(&OnionObject::Boolean(cached.is_err()))
176                    } else {
177                        f(&OnionObject::Boolean(false)) // 还没有结果
178                    }
179                }
180                "error" => {
181                    // 只返回错误信息,如果成功或未完成则返回 null
182                    if let Some(ref cached) = *self.cached_result.lock().unwrap() {
183                        match cached {
184                            Ok(_) => f(&OnionObject::Null),
185                            Err(err) => f(&OnionObject::String(format!("{}", err).into())),
186                        }
187                    } else {
188                        f(&OnionObject::Null)
189                    }
190                }
191                _ => Err(RuntimeError::InvalidOperation(
192                    format!("Attribute '{}' not found in ThreadHandle", s).into(),
193                )),
194            },
195            _ => Err(RuntimeError::InvalidOperation(
196                format!("Attribute {:?} not found in ThreadHandle", key).into(),
197            )),
198        }
199    }
200}