onion_vm/types/
thread_handle.rs1use std::{
13 any::Any,
14 collections::VecDeque,
15 fmt::{Debug, Formatter},
16 sync::Mutex,
17 thread::JoinHandle,
18};
19
20use arc_gc::{
21 arc::{GCArc, GCArcWeak},
22 gc::GC,
23 traceable::GCTraceable,
24};
25
26use crate::{
27 lambda::runnable::RuntimeError,
28 types::object::{GCArcStorage, OnionStaticObject},
29};
30
31use super::object::{OnionObject, OnionObjectCell, OnionObjectExt};
32
33pub struct OnionThreadHandle {
40 inner: Mutex<(
41 Option<JoinHandle<Result<Box<OnionStaticObject>, RuntimeError>>>,
42 bool,
43 GCArcWeak<OnionObjectCell>,
44 )>,
45}
46
47impl OnionThreadHandle {
48 pub fn new(
57 handle: JoinHandle<Result<Box<OnionStaticObject>, RuntimeError>>,
58 gc: &mut GC<OnionObjectCell>,
59 ) -> (Self, GCArcStorage) {
60 let tmp = gc.create(OnionObjectCell::from(OnionObject::Undefined(None)));
61 (
62 Self {
63 inner: Mutex::new((Some(handle), false, tmp.as_weak())),
64 },
65 GCArcStorage::Single(tmp),
66 )
67 }
68
69 pub fn is_finished(&self) -> bool {
75 let guard = self.inner.lock().unwrap();
76 guard.1 || guard.0.is_none()
77 }
78}
79
80impl Debug for OnionThreadHandle {
81 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
82 let guard = self.inner.lock().unwrap();
83 write!(
84 f,
85 "OnionThreadHandle(finished: {}, has_handle: {})",
86 guard.1 || guard.0.is_none(),
87 guard.0.is_some()
88 )
89 }
90}
91
92impl GCTraceable<OnionObjectCell> for OnionThreadHandle {
93 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
94 let guard = self.inner.lock().unwrap();
95 queue.push_back(guard.2.clone());
96 }
97}
98
99impl OnionObjectExt for OnionThreadHandle {
100 fn as_any(&self) -> &dyn Any {
101 self
102 }
103
104 fn repr(&self, _ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
105 Ok(format!("ThreadHandle(finished: {})", self.is_finished()))
106 }
107
108 fn equals(&self, _other: &OnionObject) -> Result<bool, RuntimeError> {
109 Ok(false)
110 }
111
112 fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
113 let guard = self.inner.lock().unwrap();
114 if let Some(strong) = guard.2.upgrade() {
115 collected.push(strong);
116 }
117 }
118
119 fn to_boolean(&self) -> Result<bool, RuntimeError> {
120 Ok(!self.is_finished())
122 }
123
124 fn type_of(&self) -> Result<String, RuntimeError> {
125 Ok("ThreadHandle".to_string())
126 }
127
128 fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
129 let mut guard = self.inner.lock().unwrap();
130 if guard.0.is_none() {
132 return if let Some(strong_ref) = guard.2.upgrade() {
133 strong_ref.as_ref().with_data(|data| Ok(data.stabilize()))
134 } else {
135 Err(RuntimeError::BrokenReference)
136 };
137 }
138 if let Some(handle) = guard.0.as_ref() {
140 if !handle.is_finished() {
141 return Err(RuntimeError::Pending);
142 }
143 }
144
145 if let Some(handle) = guard.0.take() {
147 guard.1 = true;
148 drop(guard); match handle.join() {
150 Ok(result) => match result {
151 Ok(obj) => {
152 let new_value = obj.weak().clone();
159
160 match self.inner.lock().unwrap().2.upgrade() {
162 Some(arc) => {
163 arc.as_ref().with_data_mut(|to| {
165 *to = new_value;
166 Ok(())
167 })?;
168 }
169 None => return Err(RuntimeError::BrokenReference),
170 };
171
172 return Ok(*obj);
176 }
177 Err(err) => Err(err),
178 },
179 Err(_) => Err(RuntimeError::DetailedError("Thread join failed".into())),
180 }
181 } else {
182 Err(RuntimeError::DetailedError(
183 "Failed to take thread handle after finished check"
184 .to_string()
185 .into(),
186 ))
187 }
188 }
189
190 fn with_attribute(
191 &self,
192 key: &OnionObject,
193 f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
194 ) -> Result<(), RuntimeError> {
195 match key {
196 OnionObject::String(s) => match s.as_ref() {
197 "is_finished" => f(&OnionObject::Boolean(self.is_finished())),
198 "has_handle" => {
199 let guard = self.inner.lock().unwrap();
200 let has_handle = guard.0.is_some();
201 f(&OnionObject::Boolean(has_handle))
202 }
203 "has_result" => {
204 let guard = self.inner.lock().unwrap();
205 let has_result = guard.2.upgrade().is_some();
206 f(&OnionObject::Boolean(has_result))
207 }
208 _ => Err(RuntimeError::InvalidOperation(
209 format!("Attribute '{}' not found in ThreadHandle", s).into(),
210 )),
211 },
212 _ => Err(RuntimeError::InvalidOperation(
213 format!("Attribute {:?} not found in ThreadHandle", key).into(),
214 )),
215 }
216 }
217}