| 
 | 1 | +/*  | 
 | 2 | + * Copyright (c) godot-rust; Bromeon and contributors.  | 
 | 3 | + * This Source Code Form is subject to the terms of the Mozilla Public  | 
 | 4 | + * License, v. 2.0. If a copy of the MPL was not distributed with this  | 
 | 5 | + * file, You can obtain one at https://mozilla.org/MPL/2.0/.  | 
 | 6 | + */  | 
 | 7 | + | 
 | 8 | +use core::panic;  | 
 | 9 | +use std::fmt::Display;  | 
 | 10 | +use std::future::{Future, IntoFuture};  | 
 | 11 | +use std::pin::Pin;  | 
 | 12 | +use std::sync::{Arc, Mutex};  | 
 | 13 | +use std::task::{Context, Poll, Waker};  | 
 | 14 | + | 
 | 15 | +use crate::builtin::{Callable, RustCallable, Signal, Variant};  | 
 | 16 | +use crate::classes::object::ConnectFlags;  | 
 | 17 | +use crate::meta::ParamTuple;  | 
 | 18 | +use crate::obj::{EngineBitfield, WithBaseField};  | 
 | 19 | +use crate::registry::signal::TypedSignal;  | 
 | 20 | + | 
 | 21 | +/// The panicking counter part to the [`FallibleSignalFuture`].  | 
 | 22 | +///  | 
 | 23 | +/// This future works in the same way as `FallibleSignalFuture`, but panics when the signal object is freed, instead of resolving to a  | 
 | 24 | +/// [`Result::Err`].  | 
 | 25 | +pub struct SignalFuture<R: ParamTuple + Sync + Send>(FallibleSignalFuture<R>);  | 
 | 26 | + | 
 | 27 | +impl<R: ParamTuple + Sync + Send> SignalFuture<R> {  | 
 | 28 | +    fn new(signal: Signal) -> Self {  | 
 | 29 | +        Self(FallibleSignalFuture::new(signal))  | 
 | 30 | +    }  | 
 | 31 | +}  | 
 | 32 | + | 
 | 33 | +impl<R: ParamTuple + Sync + Send> Future for SignalFuture<R> {  | 
 | 34 | +    type Output = R;  | 
 | 35 | + | 
 | 36 | +    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {  | 
 | 37 | +        let poll_result = self.get_mut().0.poll(cx);  | 
 | 38 | + | 
 | 39 | +        match poll_result {  | 
 | 40 | +            Poll::Pending => Poll::Pending,  | 
 | 41 | +            Poll::Ready(Ok(value)) => Poll::Ready(value),  | 
 | 42 | +            Poll::Ready(Err(FallibleSignalFutureError)) => panic!(  | 
 | 43 | +                "the signal object of a SignalFuture was freed, while the future was still waiting for the signal to be emitted"  | 
 | 44 | +            ),  | 
 | 45 | +        }  | 
 | 46 | +    }  | 
 | 47 | +}  | 
 | 48 | + | 
 | 49 | +// Not derived, otherwise an extra bound `Output: Default` is required.  | 
 | 50 | +struct SignalFutureData<T> {  | 
 | 51 | +    state: SignalFutureState<T>,  | 
 | 52 | +    waker: Option<Waker>,  | 
 | 53 | +}  | 
 | 54 | + | 
 | 55 | +impl<T> Default for SignalFutureData<T> {  | 
 | 56 | +    fn default() -> Self {  | 
 | 57 | +        Self {  | 
 | 58 | +            state: Default::default(),  | 
 | 59 | +            waker: None,  | 
 | 60 | +        }  | 
 | 61 | +    }  | 
 | 62 | +}  | 
 | 63 | + | 
 | 64 | +// Only public for itest.  | 
 | 65 | +#[cfg_attr(feature = "trace", derive(Default))]  | 
 | 66 | +pub struct SignalFutureResolver<R> {  | 
 | 67 | +    data: Arc<Mutex<SignalFutureData<R>>>,  | 
 | 68 | +}  | 
 | 69 | + | 
 | 70 | +impl<R> Clone for SignalFutureResolver<R> {  | 
 | 71 | +    fn clone(&self) -> Self {  | 
 | 72 | +        Self {  | 
 | 73 | +            data: self.data.clone(),  | 
 | 74 | +        }  | 
 | 75 | +    }  | 
 | 76 | +}  | 
 | 77 | + | 
 | 78 | +impl<R> SignalFutureResolver<R> {  | 
 | 79 | +    fn new(data: Arc<Mutex<SignalFutureData<R>>>) -> Self {  | 
 | 80 | +        Self { data }  | 
 | 81 | +    }  | 
 | 82 | +}  | 
 | 83 | + | 
 | 84 | +impl<R> std::hash::Hash for SignalFutureResolver<R> {  | 
 | 85 | +    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {  | 
 | 86 | +        state.write_usize(Arc::as_ptr(&self.data) as usize);  | 
 | 87 | +    }  | 
 | 88 | +}  | 
 | 89 | + | 
 | 90 | +impl<R> PartialEq for SignalFutureResolver<R> {  | 
 | 91 | +    fn eq(&self, other: &Self) -> bool {  | 
 | 92 | +        Arc::ptr_eq(&self.data, &other.data)  | 
 | 93 | +    }  | 
 | 94 | +}  | 
 | 95 | + | 
 | 96 | +impl<R: ParamTuple + Sync + Send> RustCallable for SignalFutureResolver<R> {  | 
 | 97 | +    fn invoke(&mut self, args: &[&Variant]) -> Result<Variant, ()> {  | 
 | 98 | +        let waker = {  | 
 | 99 | +            let mut data = self.data.lock().unwrap();  | 
 | 100 | +            data.state = SignalFutureState::Ready(R::from_variant_array(args));  | 
 | 101 | + | 
 | 102 | +            // We no longer need the waker after we resolved. If the future is polled again, we'll also get a new waker.  | 
 | 103 | +            data.waker.take()  | 
 | 104 | +        };  | 
 | 105 | + | 
 | 106 | +        if let Some(waker) = waker {  | 
 | 107 | +            waker.wake();  | 
 | 108 | +        }  | 
 | 109 | + | 
 | 110 | +        Ok(Variant::nil())  | 
 | 111 | +    }  | 
 | 112 | +}  | 
 | 113 | + | 
 | 114 | +impl<R> Display for SignalFutureResolver<R> {  | 
 | 115 | +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {  | 
 | 116 | +        write!(f, "SignalFutureResolver::<{}>", std::any::type_name::<R>())  | 
 | 117 | +    }  | 
 | 118 | +}  | 
 | 119 | + | 
 | 120 | +// This resolver will change the futures state when it's being dropped (i.e. the engine removes all connected signal callables). By marking  | 
 | 121 | +// the future as dead we can resolve it to an error value the next time it gets polled.  | 
 | 122 | +impl<R> Drop for SignalFutureResolver<R> {  | 
 | 123 | +    fn drop(&mut self) {  | 
 | 124 | +        let mut data = self.data.lock().unwrap();  | 
 | 125 | + | 
 | 126 | +        if !matches!(data.state, SignalFutureState::Pending) {  | 
 | 127 | +            // The future is no longer pending, so no clean up is required.  | 
 | 128 | +            return;  | 
 | 129 | +        }  | 
 | 130 | + | 
 | 131 | +        // We mark the future as dead, so the next time it gets polled we can react to it's inability to resolve.  | 
 | 132 | +        data.state = SignalFutureState::Dead;  | 
 | 133 | + | 
 | 134 | +        // If we got a waker we trigger it to get the future polled. If there is no waker, then the future has not been polled yet and we  | 
 | 135 | +        // simply wait for the runtime to perform the first poll.  | 
 | 136 | +        if let Some(ref waker) = data.waker {  | 
 | 137 | +            waker.wake_by_ref();  | 
 | 138 | +        }  | 
 | 139 | +    }  | 
 | 140 | +}  | 
 | 141 | + | 
 | 142 | +#[derive(Default)]  | 
 | 143 | +enum SignalFutureState<T> {  | 
 | 144 | +    #[default]  | 
 | 145 | +    Pending,  | 
 | 146 | +    Ready(T),  | 
 | 147 | +    Dead,  | 
 | 148 | +    Dropped,  | 
 | 149 | +}  | 
 | 150 | + | 
 | 151 | +impl<T> SignalFutureState<T> {  | 
 | 152 | +    fn take(&mut self) -> Self {  | 
 | 153 | +        let new_value = match self {  | 
 | 154 | +            Self::Pending => Self::Pending,  | 
 | 155 | +            Self::Ready(_) | Self::Dead => Self::Dead,  | 
 | 156 | +            Self::Dropped => Self::Dropped,  | 
 | 157 | +        };  | 
 | 158 | + | 
 | 159 | +        std::mem::replace(self, new_value)  | 
 | 160 | +    }  | 
 | 161 | +}  | 
 | 162 | + | 
 | 163 | +/// A future that tries to resolve as soon as the provided Godot signal was emitted.  | 
 | 164 | +///  | 
 | 165 | +/// The future might resolve to an error if the signal object is freed before the signal is emitted.  | 
 | 166 | +pub struct FallibleSignalFuture<R: ParamTuple + Sync + Send> {  | 
 | 167 | +    data: Arc<Mutex<SignalFutureData<R>>>,  | 
 | 168 | +    callable: SignalFutureResolver<R>,  | 
 | 169 | +    signal: Signal,  | 
 | 170 | +}  | 
 | 171 | + | 
 | 172 | +impl<R: ParamTuple + Sync + Send> FallibleSignalFuture<R> {  | 
 | 173 | +    fn new(signal: Signal) -> Self {  | 
 | 174 | +        debug_assert!(  | 
 | 175 | +            !signal.is_null(),  | 
 | 176 | +            "Failed to create a future for an invalid Signal!\nEither the signal object was already freed or the signal was not registered in the object before using it.",  | 
 | 177 | +        );  | 
 | 178 | + | 
 | 179 | +        let data = Arc::new(Mutex::new(SignalFutureData::default()));  | 
 | 180 | + | 
 | 181 | +        // The callable currently requires that the return value is Sync + Send.  | 
 | 182 | +        let callable = SignalFutureResolver::new(data.clone());  | 
 | 183 | + | 
 | 184 | +        signal.connect(  | 
 | 185 | +            &Callable::from_custom(callable.clone()),  | 
 | 186 | +            ConnectFlags::ONE_SHOT.ord() as i64,  | 
 | 187 | +        );  | 
 | 188 | + | 
 | 189 | +        Self {  | 
 | 190 | +            data,  | 
 | 191 | +            callable,  | 
 | 192 | +            signal,  | 
 | 193 | +        }  | 
 | 194 | +    }  | 
 | 195 | +    fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Result<R, FallibleSignalFutureError>> {  | 
 | 196 | +        let mut data = self.data.lock().unwrap();  | 
 | 197 | + | 
 | 198 | +        data.waker.replace(cx.waker().clone());  | 
 | 199 | + | 
 | 200 | +        let value = data.state.take();  | 
 | 201 | + | 
 | 202 | +        match value {  | 
 | 203 | +            SignalFutureState::Pending => Poll::Pending,  | 
 | 204 | +            SignalFutureState::Dropped => unreachable!(),  | 
 | 205 | +            SignalFutureState::Dead => Poll::Ready(Err(FallibleSignalFutureError)),  | 
 | 206 | +            SignalFutureState::Ready(value) => Poll::Ready(Ok(value)),  | 
 | 207 | +        }  | 
 | 208 | +    }  | 
 | 209 | +}  | 
 | 210 | + | 
 | 211 | +/// Error that might be returned  by the [`FallibleSignalFuture`].  | 
 | 212 | +///  | 
 | 213 | +/// This error is being resolved to when the signal object is freed before the awaited singal is emitted.  | 
 | 214 | +#[derive(Debug)]  | 
 | 215 | +pub struct FallibleSignalFutureError;  | 
 | 216 | + | 
 | 217 | +impl Display for FallibleSignalFutureError {  | 
 | 218 | +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {  | 
 | 219 | +        write!(  | 
 | 220 | +            f,  | 
 | 221 | +            "The signal object was freed before the awaited signal was emitted"  | 
 | 222 | +        )  | 
 | 223 | +    }  | 
 | 224 | +}  | 
 | 225 | + | 
 | 226 | +impl std::error::Error for FallibleSignalFutureError {}  | 
 | 227 | + | 
 | 228 | +impl<R: ParamTuple + Sync + Send> Future for FallibleSignalFuture<R> {  | 
 | 229 | +    type Output = Result<R, FallibleSignalFutureError>;  | 
 | 230 | + | 
 | 231 | +    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {  | 
 | 232 | +        self.get_mut().poll(cx)  | 
 | 233 | +    }  | 
 | 234 | +}  | 
 | 235 | + | 
 | 236 | +impl<R: ParamTuple + Sync + Send> Drop for FallibleSignalFuture<R> {  | 
 | 237 | +    fn drop(&mut self) {  | 
 | 238 | +        // The callable might alredy be destroyed, this occurs during engine shutdown.  | 
 | 239 | +        if self.signal.object().is_none() {  | 
 | 240 | +            return;  | 
 | 241 | +        }  | 
 | 242 | + | 
 | 243 | +        let mut data_lock = self.data.lock().unwrap();  | 
 | 244 | + | 
 | 245 | +        data_lock.state = SignalFutureState::Dropped;  | 
 | 246 | + | 
 | 247 | +        drop(data_lock);  | 
 | 248 | + | 
 | 249 | +        // We create a new Godot Callable from our RustCallable so we get independent reference counting.  | 
 | 250 | +        let gd_callable = Callable::from_custom(self.callable.clone());  | 
 | 251 | + | 
 | 252 | +        // is_connected will return true if the signal was never emited before the future is dropped.  | 
 | 253 | +        if self.signal.is_connected(&gd_callable) {  | 
 | 254 | +            self.signal.disconnect(&gd_callable);  | 
 | 255 | +        }  | 
 | 256 | +    }  | 
 | 257 | +}  | 
 | 258 | + | 
 | 259 | +impl Signal {  | 
 | 260 | +    /// Creates a fallible future for this signal.  | 
 | 261 | +    ///  | 
 | 262 | +    /// The future will resolve the next time the signal is emitted.  | 
 | 263 | +    /// See [`TrySignalFuture`] for details.  | 
 | 264 | +    ///  | 
 | 265 | +    /// Since the `Signal` type does not contain information on the signal argument types, the future output type has to be inferred from  | 
 | 266 | +    /// the call to this function.  | 
 | 267 | +    pub fn to_fallible_future<R: ParamTuple + Sync + Send>(&self) -> FallibleSignalFuture<R> {  | 
 | 268 | +        FallibleSignalFuture::new(self.clone())  | 
 | 269 | +    }  | 
 | 270 | + | 
 | 271 | +    /// Creates a future for this signal.  | 
 | 272 | +    ///  | 
 | 273 | +    /// The future will resolve the next time the signal is emitted, but might panic if the signal object is freed.  | 
 | 274 | +    /// See [`SignalFuture`] for details.  | 
 | 275 | +    ///  | 
 | 276 | +    /// Since the `Signal` type does not contain information on the signal argument types, the future output type has to be inferred from  | 
 | 277 | +    /// the call to this function.  | 
 | 278 | +    pub fn to_future<R: ParamTuple + Sync + Send>(&self) -> SignalFuture<R> {  | 
 | 279 | +        SignalFuture::new(self.clone())  | 
 | 280 | +    }  | 
 | 281 | +}  | 
 | 282 | + | 
 | 283 | +impl<C: WithBaseField, R: ParamTuple + Sync + Send> TypedSignal<'_, C, R> {  | 
 | 284 | +    /// Creates a fallible future for this signal.  | 
 | 285 | +    ///  | 
 | 286 | +    /// The future will resolve the next time the signal is emitted.  | 
 | 287 | +    /// See [`FallibleSignalFuture`] for details.  | 
 | 288 | +    pub fn to_fallible_future(&self) -> FallibleSignalFuture<R> {  | 
 | 289 | +        FallibleSignalFuture::new(self.to_untyped())  | 
 | 290 | +    }  | 
 | 291 | + | 
 | 292 | +    /// Creates a future for this signal.  | 
 | 293 | +    ///  | 
 | 294 | +    /// The future will resolve the next time the signal is emitted, but might panic if the signal object is freed.  | 
 | 295 | +    /// See [`SignalFuture`] for details.  | 
 | 296 | +    pub fn to_future(&self) -> SignalFuture<R> {  | 
 | 297 | +        SignalFuture::new(self.to_untyped())  | 
 | 298 | +    }  | 
 | 299 | +}  | 
 | 300 | + | 
 | 301 | +impl<C: WithBaseField, R: ParamTuple + Sync + Send> IntoFuture for &TypedSignal<'_, C, R> {  | 
 | 302 | +    type Output = R;  | 
 | 303 | + | 
 | 304 | +    type IntoFuture = SignalFuture<R>;  | 
 | 305 | + | 
 | 306 | +    fn into_future(self) -> Self::IntoFuture {  | 
 | 307 | +        self.to_future()  | 
 | 308 | +    }  | 
 | 309 | +}  | 
 | 310 | + | 
 | 311 | +#[cfg(test)]  | 
 | 312 | +mod tests {  | 
 | 313 | +    use crate::sys;  | 
 | 314 | +    use std::sync::Arc;  | 
 | 315 | + | 
 | 316 | +    use super::SignalFutureResolver;  | 
 | 317 | + | 
 | 318 | +    /// Test that the hash of a cloned future resolver is equal to its original version. With this equality in place, we can create new  | 
 | 319 | +    /// Callables that are equal to their original version but have separate reference counting.  | 
 | 320 | +    #[test]  | 
 | 321 | +    fn future_resolver_cloned_hash() {  | 
 | 322 | +        let resolver_a = SignalFutureResolver::<u8>::new(Arc::default());  | 
 | 323 | +        let resolver_b = resolver_a.clone();  | 
 | 324 | + | 
 | 325 | +        let hash_a = sys::hash_value(&resolver_a);  | 
 | 326 | +        let hash_b = sys::hash_value(&resolver_b);  | 
 | 327 | + | 
 | 328 | +        assert_eq!(hash_a, hash_b);  | 
 | 329 | +    }  | 
 | 330 | +}  | 
0 commit comments