onion_vm/types/
async_handle.rs1use std::{
2 any::Any,
3 collections::VecDeque,
4 fmt::{Debug, Formatter},
5 sync::{Arc, Mutex},
6};
7
8use arc_gc::{
9 arc::{GCArc, GCArcWeak},
10 gc::GC,
11 traceable::GCTraceable,
12};
13
14use crate::{
15 lambda::runnable::RuntimeError,
16 types::object::{GCArcStorage, OnionStaticObject},
17};
18
19use super::object::{OnionObject, OnionObjectCell, OnionObjectExt};
20
21pub struct OnionAsyncHandle {
22 inner: Mutex<(GCArcWeak<OnionObjectCell>, bool)>,
23}
24
25impl OnionAsyncHandle {
26 pub fn new(gc: &mut GC<OnionObjectCell>) -> (Arc<Self>, GCArcStorage) {
28 let tmp = gc.create(OnionObjectCell::from(OnionObject::Undefined(None)));
29 (
30 Arc::new(Self {
31 inner: Mutex::new((tmp.as_weak(), false)),
32 }),
33 GCArcStorage::Single(tmp),
34 )
35 }
36
37 pub fn is_finished(&self) -> bool {
39 self.inner.lock().unwrap().1
40 }
41
42 pub fn set_result(&self, result: &OnionObject) -> Result<(), RuntimeError> {
45 let mut guard = self.inner.lock().unwrap();
46 guard.0.upgrade().map_or_else(
47 || Err(RuntimeError::BrokenReference),
48 |strong_ref| {
49 result.with_data(|data| {
50 strong_ref.as_ref().with_data_mut(|strong_data| {
51 *strong_data = data.clone();
52 Ok(())
53 })
54 })
55 },
56 )?;
57 guard.1 = true; Ok(())
59 }
60
61 pub fn set_finished(&self) {
63 let mut guard = self.inner.lock().unwrap();
64 guard.1 = true;
65 }
66}
67
68impl Debug for OnionAsyncHandle {
69 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70 let guard = self.inner.lock().unwrap();
72 write!(f, "OnionAsyncHandle(finished: {})", guard.1)
73 }
74}
75
76impl GCTraceable<OnionObjectCell> for OnionAsyncHandle {
77 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
78 let guard = self.inner.lock().unwrap();
79 queue.push_back(guard.0.clone());
80 }
81}
82
83impl OnionObjectExt for OnionAsyncHandle {
84 fn as_any(&self) -> &dyn Any {
85 self
86 }
87
88 fn repr(&self, _ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
89 Ok(format!("AsyncHandle(finished: {})", self.is_finished()))
90 }
91
92 fn equals(&self, _other: &OnionObject) -> Result<bool, RuntimeError> {
93 Ok(false)
95 }
96
97 fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
98 let guard = self.inner.lock().unwrap();
99 if let Some(strong_ref) = guard.0.upgrade() {
100 collected.push(strong_ref);
101 }
102 }
103
104 fn is_same(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
105 if let OnionObject::Custom(other_custom) = other {
106 if let Some(other_handle) = other_custom.as_any().downcast_ref::<OnionAsyncHandle>() {
107 Ok(std::ptr::eq(self, other_handle))
109 } else {
110 Ok(false)
111 }
112 } else {
113 Ok(false)
114 }
115 }
116
117 fn to_boolean(&self) -> Result<bool, RuntimeError> {
118 Ok(!self.is_finished())
120 }
121
122 fn type_of(&self) -> Result<String, RuntimeError> {
123 Ok("AsyncHandle".to_string())
124 }
125
126 fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
127 let guard = self.inner.lock().unwrap();
128 let (ref weak_result, is_finished) = *guard;
129 if is_finished {
130 if let Some(strong_ref) = weak_result.upgrade() {
131 strong_ref.as_ref().with_data(|data| Ok(data.stabilize()))
133 } else {
134 Err(RuntimeError::BrokenReference)
136 }
137 } else {
138 Err(RuntimeError::Pending)
139 }
140 }
141
142 fn to_string(&self, ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
143 let finished = self.is_finished();
144 if finished {
145 match self.value_of() {
146 Ok(val) => Ok(format!(
147 "AsyncHandle(finished: true, result: {})",
148 val.weak().to_string(ptrs)?
149 )),
150 Err(RuntimeError::BrokenReference) => {
151 Ok("AsyncHandle(finished: true, result: <broken reference>)".to_string())
152 }
153 Err(_) => Ok("AsyncHandle(finished: true, result: <unknown error>)".to_string()),
154 }
155 } else {
156 let guard = self.inner.lock().unwrap();
157 let (ref weak_result, _) = *guard;
158 match weak_result.upgrade() {
159 Some(v) => Ok(format!(
160 "AsyncHandle(finished: false, result: {:?})",
161 v.as_ref().0.read().unwrap().to_string(ptrs)
162 )),
163 None => Ok("AsyncHandle(finished: false, result: <broken reference>)".to_string()),
164 }
165 }
166 }
167
168 fn with_attribute(
169 &self,
170 key: &OnionObject,
171 f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
172 ) -> Result<(), RuntimeError> {
173 match key {
174 OnionObject::String(s) => match s.as_ref() {
175 "is_finished" => f(&OnionObject::Boolean(self.is_finished())),
176 "has_result" => {
177 let guard = self.inner.lock().unwrap();
178 let has_result = guard.0.upgrade().is_some();
179 f(&OnionObject::Boolean(has_result))
180 }
181 _ => Err(RuntimeError::InvalidOperation(
182 format!("Attribute '{}' not found in AsyncHandle", s).into(),
183 )),
184 },
185 _ => Err(RuntimeError::InvalidOperation(
186 format!("Attribute {:?} not found in AsyncHandle", key).into(),
187 )),
188 }
189 }
190}