Skip to content

Commit e9838b5

Browse files
committed
restructure & v0.2 compat
1 parent d31963d commit e9838b5

File tree

6 files changed

+330
-306
lines changed

6 files changed

+330
-306
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1-
use std::any::type_name;
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+
28
use std::cell::RefCell;
3-
use std::fmt::{Debug, Display};
49
use std::future::Future;
510
use std::marker::PhantomData;
611
use std::pin::Pin;
7-
use std::sync::{Arc, Mutex};
12+
use std::sync::Arc;
813
use std::task::{Context, Poll, Wake, Waker};
914
use std::thread::{self, ThreadId};
1015

11-
use crate::builtin::{Callable, RustCallable, Signal, Variant};
12-
use crate::classes::object::ConnectFlags;
16+
use crate::builtin::{Callable, Variant};
1317
use crate::classes::Os;
14-
use crate::meta::{FromGodot, ToGodot};
15-
use crate::obj::EngineEnum;
18+
use crate::meta::ToGodot;
19+
20+
// ----------------------------------------------------------------------------------------------------------------------------------------------
21+
// Public interface
1622

1723
pub fn godot_task(future: impl Future<Output = ()> + 'static) -> TaskHandle {
1824
let os = Os::singleton();
@@ -44,6 +50,9 @@ pub fn godot_task(future: impl Future<Output = ()> + 'static) -> TaskHandle {
4450
task_handle
4551
}
4652

53+
// ----------------------------------------------------------------------------------------------------------------------------------------------
54+
// Async Runtime
55+
4756
thread_local! { pub(crate) static ASYNC_RUNTIME: RefCell<AsyncRuntime> = RefCell::new(AsyncRuntime::new()); }
4857

4958
#[derive(Default)]
@@ -244,7 +253,7 @@ impl GodotWaker {
244253

245254
impl Wake for GodotWaker {
246255
fn wake(self: std::sync::Arc<Self>) {
247-
let callable = Callable::from_fn("GodotWaker::wake", move |_args| {
256+
let callable = Callable::from_local_fn("GodotWaker::wake", move |_args| {
248257
let current_thread = thread::current().id();
249258

250259
if self.thread_id != current_thread {
@@ -293,294 +302,3 @@ impl Wake for GodotWaker {
293302
callable.to_variant().call("call_deferred", &[]);
294303
}
295304
}
296-
297-
pub struct SignalFuture<R: FromSignalArgs> {
298-
state: Arc<Mutex<(Option<R>, Option<Waker>)>>,
299-
callable: Callable,
300-
signal: Signal,
301-
}
302-
303-
impl<R: FromSignalArgs> SignalFuture<R> {
304-
fn new(signal: Signal) -> Self {
305-
let state = Arc::new(Mutex::new((None, Option::<Waker>::None)));
306-
let callback_state = state.clone();
307-
308-
// the callable currently requires that the return value is Sync + Send
309-
let callable = Callable::from_fn("async_task", move |args: &[&Variant]| {
310-
let mut lock = callback_state.lock().unwrap();
311-
let waker = lock.1.take();
312-
313-
lock.0.replace(R::from_args(args));
314-
drop(lock);
315-
316-
if let Some(waker) = waker {
317-
waker.wake();
318-
}
319-
320-
Ok(Variant::nil())
321-
});
322-
323-
signal.connect(callable.clone(), ConnectFlags::ONE_SHOT.ord() as i64);
324-
325-
Self {
326-
state,
327-
callable,
328-
signal,
329-
}
330-
}
331-
}
332-
333-
impl<R: FromSignalArgs> Future for SignalFuture<R> {
334-
type Output = R;
335-
336-
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
337-
let mut lock = self.state.lock().unwrap();
338-
339-
if let Some(result) = lock.0.take() {
340-
return Poll::Ready(result);
341-
}
342-
343-
lock.1.replace(cx.waker().clone());
344-
345-
Poll::Pending
346-
}
347-
}
348-
349-
impl<R: FromSignalArgs> Drop for SignalFuture<R> {
350-
fn drop(&mut self) {
351-
if !self.callable.is_valid() {
352-
return;
353-
}
354-
355-
if self.signal.object().is_none() {
356-
return;
357-
}
358-
359-
if self.signal.is_connected(self.callable.clone()) {
360-
self.signal.disconnect(self.callable.clone());
361-
}
362-
}
363-
}
364-
365-
struct GuaranteedSignalFutureWaker<R> {
366-
state: Arc<Mutex<(GuaranteedSignalFutureState<R>, Option<Waker>)>>,
367-
}
368-
369-
impl<R> Clone for GuaranteedSignalFutureWaker<R> {
370-
fn clone(&self) -> Self {
371-
Self {
372-
state: self.state.clone(),
373-
}
374-
}
375-
}
376-
377-
impl<R> GuaranteedSignalFutureWaker<R> {
378-
fn new(state: Arc<Mutex<(GuaranteedSignalFutureState<R>, Option<Waker>)>>) -> Self {
379-
Self { state }
380-
}
381-
}
382-
383-
impl<R> std::hash::Hash for GuaranteedSignalFutureWaker<R> {
384-
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
385-
state.write_usize(Arc::as_ptr(&self.state) as usize);
386-
}
387-
}
388-
389-
impl<R> PartialEq for GuaranteedSignalFutureWaker<R> {
390-
fn eq(&self, other: &Self) -> bool {
391-
Arc::ptr_eq(&self.state, &other.state)
392-
}
393-
}
394-
395-
impl<R: FromSignalArgs> RustCallable for GuaranteedSignalFutureWaker<R> {
396-
fn invoke(&mut self, args: &[&Variant]) -> Result<Variant, ()> {
397-
let mut lock = self.state.lock().unwrap();
398-
let waker = lock.1.take();
399-
400-
lock.0 = GuaranteedSignalFutureState::Ready(R::from_args(args));
401-
drop(lock);
402-
403-
if let Some(waker) = waker {
404-
waker.wake();
405-
}
406-
407-
Ok(Variant::nil())
408-
}
409-
}
410-
411-
impl<R> Display for GuaranteedSignalFutureWaker<R> {
412-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413-
write!(f, "SafeCallable::<{}>", type_name::<R>())
414-
}
415-
}
416-
417-
impl<R> Drop for GuaranteedSignalFutureWaker<R> {
418-
fn drop(&mut self) {
419-
let mut lock = self.state.lock().unwrap();
420-
421-
if !matches!(lock.0, GuaranteedSignalFutureState::Pending) {
422-
return;
423-
}
424-
425-
lock.0 = GuaranteedSignalFutureState::Dead;
426-
427-
if let Some(ref waker) = lock.1 {
428-
waker.wake_by_ref();
429-
}
430-
}
431-
}
432-
433-
#[derive(Default)]
434-
enum GuaranteedSignalFutureState<T> {
435-
#[default]
436-
Pending,
437-
Ready(T),
438-
Dead,
439-
Dropped,
440-
}
441-
442-
impl<T> GuaranteedSignalFutureState<T> {
443-
fn take(&mut self) -> Self {
444-
let new_value = match self {
445-
Self::Pending => Self::Pending,
446-
Self::Ready(_) | Self::Dead => Self::Dead,
447-
Self::Dropped => Self::Dropped,
448-
};
449-
450-
std::mem::replace(self, new_value)
451-
}
452-
}
453-
454-
pub struct GuaranteedSignalFuture<R: FromSignalArgs> {
455-
state: Arc<Mutex<(GuaranteedSignalFutureState<R>, Option<Waker>)>>,
456-
callable: GuaranteedSignalFutureWaker<R>,
457-
signal: Signal,
458-
}
459-
460-
impl<R: FromSignalArgs + Debug> GuaranteedSignalFuture<R> {
461-
fn new(signal: Signal) -> Self {
462-
let state = Arc::new(Mutex::new((
463-
GuaranteedSignalFutureState::Pending,
464-
Option::<Waker>::None,
465-
)));
466-
467-
// the callable currently requires that the return value is Sync + Send
468-
let callable = GuaranteedSignalFutureWaker::new(state.clone());
469-
470-
signal.connect(
471-
Callable::from_custom(callable.clone()),
472-
ConnectFlags::ONE_SHOT.ord() as i64,
473-
);
474-
475-
Self {
476-
state,
477-
callable,
478-
signal,
479-
}
480-
}
481-
}
482-
483-
impl<R: FromSignalArgs> Future for GuaranteedSignalFuture<R> {
484-
type Output = Option<R>;
485-
486-
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
487-
let mut lock = self.state.lock().unwrap();
488-
489-
lock.1.replace(cx.waker().clone());
490-
491-
let value = lock.0.take();
492-
493-
match value {
494-
GuaranteedSignalFutureState::Pending => Poll::Pending,
495-
GuaranteedSignalFutureState::Dropped => unreachable!(),
496-
GuaranteedSignalFutureState::Dead => Poll::Ready(None),
497-
GuaranteedSignalFutureState::Ready(value) => Poll::Ready(Some(value)),
498-
}
499-
}
500-
}
501-
502-
impl<R: FromSignalArgs> Drop for GuaranteedSignalFuture<R> {
503-
fn drop(&mut self) {
504-
if self.signal.object().is_none() {
505-
return;
506-
}
507-
508-
self.state.lock().unwrap().0 = GuaranteedSignalFutureState::Dropped;
509-
510-
let gd_callable = Callable::from_custom(self.callable.clone());
511-
512-
if self.signal.is_connected(gd_callable.clone()) {
513-
self.signal.disconnect(gd_callable);
514-
}
515-
}
516-
}
517-
518-
pub trait FromSignalArgs: Sync + Send + 'static {
519-
fn from_args(args: &[&Variant]) -> Self;
520-
}
521-
522-
impl<R: FromGodot + Sync + Send + 'static> FromSignalArgs for R {
523-
fn from_args(args: &[&Variant]) -> Self {
524-
args.first()
525-
.map(|arg| (*arg).to_owned())
526-
.unwrap_or_default()
527-
.to()
528-
}
529-
}
530-
531-
// more of these should be generated via macro to support more than two signal arguments
532-
impl<R1: FromGodot + Sync + Send + 'static, R2: FromGodot + Sync + Send + 'static> FromSignalArgs
533-
for (R1, R2)
534-
{
535-
fn from_args(args: &[&Variant]) -> Self {
536-
(args[0].to(), args[0].to())
537-
}
538-
}
539-
540-
// Signal should implement IntoFuture for convenience. Keeping ToSignalFuture around might still be desirable, though. It allows to reuse i
541-
// the same signal instance multiple times.
542-
pub trait ToSignalFuture<R: FromSignalArgs> {
543-
fn to_future(&self) -> SignalFuture<R>;
544-
}
545-
546-
impl<R: FromSignalArgs> ToSignalFuture<R> for Signal {
547-
fn to_future(&self) -> SignalFuture<R> {
548-
SignalFuture::new(self.clone())
549-
}
550-
}
551-
552-
pub trait ToGuaranteedSignalFuture<R: FromSignalArgs + Debug> {
553-
fn to_guaranteed_future(&self) -> GuaranteedSignalFuture<R>;
554-
}
555-
556-
impl<R: FromSignalArgs + Debug> ToGuaranteedSignalFuture<R> for Signal {
557-
fn to_guaranteed_future(&self) -> GuaranteedSignalFuture<R> {
558-
GuaranteedSignalFuture::new(self.clone())
559-
}
560-
}
561-
562-
#[cfg(test)]
563-
mod tests {
564-
use std::{
565-
hash::{DefaultHasher, Hash, Hasher},
566-
sync::Arc,
567-
};
568-
569-
use super::GuaranteedSignalFutureWaker;
570-
571-
#[test]
572-
fn guaranteed_future_waker_cloned_hash() {
573-
let waker_a = GuaranteedSignalFutureWaker::<u8>::new(Arc::default());
574-
let waker_b = waker_a.clone();
575-
576-
let mut hasher = DefaultHasher::new();
577-
waker_a.hash(&mut hasher);
578-
let hash_a = hasher.finish();
579-
580-
let mut hasher = DefaultHasher::new();
581-
waker_b.hash(&mut hasher);
582-
let hash_b = hasher.finish();
583-
584-
assert_eq!(hash_a, hash_b);
585-
}
586-
}

godot-core/src/builtin/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub mod __prelude_reexport {
155155
use super::*;
156156

157157
pub use aabb::*;
158+
pub use async_runtime::*;
158159
pub use basis::*;
159160
pub use callable::*;
160161
pub use collections::containers::*;
@@ -203,6 +204,7 @@ mod macros;
203204

204205
// Other modules
205206
mod aabb;
207+
mod async_runtime;
206208
mod basis;
207209
mod callable;
208210
mod collections;

0 commit comments

Comments
 (0)