#![deny(missing_docs)]
use std::os::raw::c_void;
use cpp::{cpp, cpp_class};
use super::*;
type RustFuncType = dyn FnMut(*const *const c_void);
cpp! {{
#include <QtCore/QObject>
#include "qmetaobject_rust.hpp"
class QObjectPrivate {
public:
static QMetaObject::Connection rust_connectImpl(
const QObject *sender,
void **signal,
const QObject *receiver,
void **slotPtr,
QtPrivate::QSlotObjectBase *slot,
Qt::ConnectionType type,
const int *types,
const QMetaObject *senderMetaObject
) {
return QObject::connectImpl(sender, signal, receiver, slotPtr, slot,
type, types, senderMetaObject);
}
};
class QRustClosureSlotObject : public QtPrivate::QSlotObjectBase
{
public:
using Func = TraitObject;
private:
Func function;
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) {
Q_UNUSED(ret);
Q_UNUSED(r);
switch (which) {
case Destroy:
delete static_cast<QRustClosureSlotObject *>(this_);
break;
case Call: {
auto slot = static_cast<QRustClosureSlotObject *>(this_)->function;
rust!(QRustClosureSlotObject_call [
slot: *mut RustFuncType as "Func",
a: *const *const c_void as "void **"
] {
let slot: &mut RustFuncType = unsafe { &mut *slot };
slot(a);
});
break;
}
case Compare:
break;
case NumOperations:
break;
}
}
public:
Q_DISABLE_COPY(QRustClosureSlotObject);
explicit QRustClosureSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
~QRustClosureSlotObject() {
rust!(QRustClosureSlotObject_destruct [
function: *mut RustFuncType as "Func"
] {
let _ = unsafe { Box::from_raw(function) };
});
}
};
}}
cpp_class!(
pub unsafe struct ConnectionHandle as "QMetaObject::Connection"
);
impl ConnectionHandle {
pub fn disconnect(&mut self) {
cpp!(unsafe [self as "const QMetaObject::Connection *"] {
QObject::disconnect(*self);
})
}
pub fn is_valid(&self) -> bool {
cpp!(unsafe [self as "const QMetaObject::Connection *"] -> bool as "bool" {
return *self; })
}
}
cpp_class!(
pub unsafe struct SignalInner as "SignalInner"
);
impl SignalInner {
pub fn from_offset<O: QObject + Sized>(offset: isize) -> Self {
assert!(
offset >= 0 && offset < std::mem::size_of::<O>() as isize,
"Signal is not part of the Object: offset {} is outside of type `{}` object's memory",
offset,
std::any::type_name::<O>()
);
cpp!(unsafe [offset as "ptrdiff_t"] -> SignalInner as "SignalInner" {
return SignalInner(offset);
})
}
}
pub struct Signal<Args> {
inner: SignalInner,
phantom: std::marker::PhantomData<Args>,
}
impl<Args> Signal<Args> {
pub unsafe fn new(inner: SignalInner) -> Self {
Signal { inner, phantom: Default::default() }
}
}
impl<Args> Clone for Signal<Args> {
fn clone(&self) -> Self {
*self
}
}
impl<Args> Copy for Signal<Args> {}
pub struct RustSignal<Args> {
phantom: std::marker::PhantomData<Args>,
_u: bool, }
impl<Args> Default for RustSignal<Args> {
fn default() -> Self {
RustSignal { phantom: Default::default(), _u: Default::default() }
}
}
impl<Args> RustSignal<Args> {
pub fn to_cpp_representation<O: QObject + Sized>(&self, obj: &O) -> Signal<Args> {
let base_ptr = obj as *const _ as isize;
let signal_ptr = self as *const _ as isize;
let offset = signal_ptr - base_ptr;
let inner = SignalInner::from_offset::<O>(offset);
Signal { inner, phantom: Default::default() }
}
}
pub trait Slot<Args> {
unsafe fn apply(&mut self, a: *const *const c_void);
}
pub trait SignalArgArrayToTuple {
type Tuple;
unsafe fn args_array_to_tuple(a: *const *const c_void) -> Self::Tuple;
}
macro_rules! count_repetitions {
() => { 0 };
( $head:tt $( $rest:tt )* ) => { count_repetitions!( $( $rest )* ) + 1 };
}
macro_rules! declare_slot_traits {
(@continue) => {};
(@continue $A:ident : $N:literal $($tail:tt)*) => {
declare_slot_traits![ $($tail)* ];
};
( $( $A:ident : $N:tt )* ) => {
impl<T, $( $A, )* > Slot<fn( $( $A, )* )> for T
where T : FnMut( $( &$A, )* )
{
#[allow(unused_variables)]
unsafe fn apply(&mut self, a: *const *const c_void) {
let argc = count_repetitions!( $( $A )* ) + 1;
self($({
let arg_ptr = *a.offset(argc - $N);
&*( arg_ptr as *const $A )
},)*);
}
}
impl< $( $A: Clone, )* > SignalArgArrayToTuple for fn( $( $A, )* ) {
type Tuple = ( $( $A, )* );
#[allow(unused_variables)]
unsafe fn args_array_to_tuple(a: *const *const c_void) -> Self::Tuple {
let argc = count_repetitions!( $( $A )* ) + 1;
($({
let arg_ptr = *a.offset(argc - $N);
let arg_ref = &*( arg_ptr as *const $A );
arg_ref.clone()
},)*)
}
}
declare_slot_traits![ @continue $( $A: $N )* ];
}
}
declare_slot_traits![A:10 B:9 C:8 D:7 E:6 F:5 G:4 H:3 I:2 J:1];
pub unsafe fn connect<Args, F: Slot<Args>>(
sender: *const c_void,
signal: Signal<Args>,
mut slot: F,
) -> ConnectionHandle {
let mut cpp_signal = signal.inner;
let slot_closure = move |a: *const *const c_void| slot.apply(a);
let slot_closure_boxed: Box<dyn FnMut(*const *const c_void)> = Box::new(slot_closure);
let slot_closure_raw: *mut dyn FnMut(*const *const c_void) = Box::into_raw(slot_closure_boxed);
cpp!(unsafe [
sender as "const QObject *",
mut cpp_signal as "SignalInner",
slot_closure_raw as "TraitObject"
] -> ConnectionHandle as "QMetaObject::Connection" {
return QObjectPrivate::rust_connectImpl(
sender,
cpp_signal.asRawSignal(),
sender,
nullptr, new QRustClosureSlotObject(slot_closure_raw),
Qt::DirectConnection,
nullptr,
sender->metaObject()
);
})
}