use super::{make_callable_name, make_godot_fn};
#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
use crate::builtin::Callable;
use crate::builtin::{CowStr, Variant};
use crate::classes::object::ConnectFlags;
use crate::meta;
use crate::meta::{InParamTuple, ObjectToOwned};
use crate::obj::signal::signal_receiver::{IndirectSignalReceiver, SignalReceiver};
use crate::obj::signal::{ConnectHandle, TypedSignal};
use crate::obj::{Bounds, Gd, GodotClass, WithSignals, bounds};
#[must_use]
pub struct ConnectBuilder<'ts, 'c, C: WithSignals, Ps> {
parent_sig: &'ts TypedSignal<'c, C, Ps>,
data: BuilderData,
}
#[derive(Default)]
struct BuilderData {
callable_name: Option<CowStr>,
connect_flags: Option<ConnectFlags>,
}
#[allow(clippy::needless_lifetimes)] impl<'ts, 'c, C, Ps> ConnectBuilder<'ts, 'c, C, Ps>
where
C: WithSignals,
Ps: meta::ParamTuple,
{
pub(super) fn new(parent_sig: &'ts TypedSignal<'c, C, Ps>) -> Self {
ConnectBuilder {
parent_sig,
data: BuilderData::default(),
}
}
pub fn name(mut self, name: impl Into<CowStr>) -> Self {
assert!(
self.data.callable_name.is_none(),
"name() called twice on the same builder."
);
self.data.callable_name = Some(name.into());
self
}
pub fn flags(mut self, flags: ConnectFlags) -> Self {
assert!(
self.data.connect_flags.is_none(),
"flags() called twice on the same builder."
);
self.data.connect_flags = Some(flags);
self
}
fn inner_connect_godot_fn<F>(
self,
godot_fn: impl FnMut(&[&Variant]) -> Variant + 'static,
bound: &Gd<impl GodotClass>,
) -> ConnectHandle {
let callable_name = self
.data
.callable_name
.unwrap_or_else(make_callable_name::<F>);
let callable = bound.linked_callable(callable_name, godot_fn);
self.parent_sig
.inner_connect_untyped(callable, self.data.connect_flags)
}
}
impl<C: WithSignals, Ps: InParamTuple + 'static> ConnectBuilder<'_, '_, C, Ps> {
pub fn connect<F>(self, mut function: F) -> ConnectHandle
where
for<'c_rcv> F: SignalReceiver<(), Ps>,
for<'c_rcv> IndirectSignalReceiver<'c_rcv, (), Ps, F>: From<&'c_rcv mut F>,
{
let godot_fn = make_godot_fn(move |args| {
IndirectSignalReceiver::from(&mut function)
.function()
.call((), args);
});
let bound = self.parent_sig.receiver_object();
self.inner_connect_godot_fn::<F>(godot_fn, &bound)
}
pub fn connect_self_mut<F>(self, mut function: F) -> ConnectHandle
where
C: Bounds<Declarer = bounds::DeclUser>,
for<'c_rcv> F: SignalReceiver<&'c_rcv mut C, Ps>,
for<'c_rcv> IndirectSignalReceiver<'c_rcv, &'c_rcv mut C, Ps, F>: From<&'c_rcv mut F>,
{
let mut gd = self.parent_sig.receiver_object();
let godot_fn = make_godot_fn(move |args| {
let mut guard = Gd::bind_mut(&mut gd);
IndirectSignalReceiver::from(&mut function)
.function()
.call(&mut *guard, args);
});
let bound = self.parent_sig.receiver_object();
self.inner_connect_godot_fn::<F>(godot_fn, &bound)
}
pub fn connect_self_gd<F>(self, mut function: F) -> ConnectHandle
where
F: SignalReceiver<Gd<C>, Ps>,
for<'c_rcv> IndirectSignalReceiver<'c_rcv, Gd<C>, Ps, F>: From<&'c_rcv mut F>,
{
let gd = self.parent_sig.receiver_object();
let bound = gd.clone();
let godot_fn = make_godot_fn(move |args| {
IndirectSignalReceiver::from(&mut function)
.function()
.call(gd.clone(), args);
});
self.inner_connect_godot_fn::<F>(godot_fn, &bound)
}
pub fn connect_other_mut<F, OtherC>(
self,
object: &impl ObjectToOwned<OtherC>,
mut method: F,
) -> ConnectHandle
where
OtherC: GodotClass + Bounds<Declarer = bounds::DeclUser>,
for<'c_rcv> F: SignalReceiver<&'c_rcv mut OtherC, Ps>,
for<'c_rcv> IndirectSignalReceiver<'c_rcv, &'c_rcv mut OtherC, Ps, F>: From<&'c_rcv mut F>,
{
let mut gd = object.object_to_owned();
let godot_fn = make_godot_fn(move |args| {
let mut guard = Gd::bind_mut(&mut gd);
IndirectSignalReceiver::from(&mut method)
.function()
.call(&mut *guard, args);
});
self.inner_connect_godot_fn::<F>(godot_fn, &object.object_to_owned())
}
pub fn connect_other_gd<F, OtherC>(
self,
object: &impl ObjectToOwned<OtherC>,
mut method: F,
) -> ConnectHandle
where
OtherC: GodotClass,
F: SignalReceiver<Gd<OtherC>, Ps>,
for<'c_rcv> IndirectSignalReceiver<'c_rcv, Gd<OtherC>, Ps, F>: From<&'c_rcv mut F>,
{
let gd = object.object_to_owned();
let godot_fn = make_godot_fn(move |args| {
IndirectSignalReceiver::from(&mut method)
.function()
.call(gd.clone(), args);
});
self.inner_connect_godot_fn::<F>(godot_fn, &object.object_to_owned())
}
#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
pub fn connect_sync<F>(self, mut function: F)
where
for<'c_rcv> F: SignalReceiver<(), Ps> + Send + Sync,
for<'c_rcv> IndirectSignalReceiver<'c_rcv, (), Ps, F>: From<&'c_rcv mut F>,
{
let godot_fn = make_godot_fn(move |args| {
IndirectSignalReceiver::from(&mut function)
.function()
.call((), args);
});
let callable_name = self
.data
.callable_name
.unwrap_or_else(make_callable_name::<F>);
let callable = Callable::from_sync_fn(callable_name, godot_fn);
self.parent_sig
.inner_connect_untyped(callable, self.data.connect_flags);
}
}