onion_vm/types/
async_handle.rs1use 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
32pub struct OnionAsyncHandle {
40 inner: Mutex<(GCArcWeak<OnionObjectCell>, bool)>,
41}
42
43impl OnionAsyncHandle {
44 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 pub fn is_finished(&self) -> bool {
67 self.inner.lock().unwrap().1
68 }
69
70 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; Ok(())
96 }
97
98 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 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 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 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 strong_ref.as_ref().with_data(|data| Ok(data.stabilize()))
159 } else {
160 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}