use std::{
cell::RefCell,
pin::Pin,
rc::{Rc, Weak},
};
use cxx::{memory::UniquePtrTarget, UniquePtr};
#[deprecated]
pub use autocxx_macro::subclass as is_subclass;
pub use autocxx_macro::subclass;
pub mod prelude {
pub use super::{
is_subclass, subclass, CppPeerConstructor, CppSubclass, CppSubclassDefault,
CppSubclassRustPeerHolder, CppSubclassSelfOwned, CppSubclassSelfOwnedDefault,
};
}
#[doc(hidden)]
pub trait CppSubclassCppPeer: UniquePtrTarget {
fn relinquish_ownership(&self);
}
#[doc(hidden)]
pub enum CppSubclassRustPeerHolder<T> {
Owned(Rc<RefCell<T>>),
Unowned(Weak<RefCell<T>>),
}
impl<T> CppSubclassRustPeerHolder<T> {
pub fn get(&self) -> Option<Rc<RefCell<T>>> {
match self {
CppSubclassRustPeerHolder::Owned(strong) => Some(strong.clone()),
CppSubclassRustPeerHolder::Unowned(weak) => weak.upgrade(),
}
}
pub fn relinquish_ownership(self) -> Self {
match self {
CppSubclassRustPeerHolder::Owned(strong) => {
CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&strong))
}
_ => self,
}
}
}
#[doc(hidden)]
#[derive(Default)]
pub enum CppSubclassCppPeerHolder<CppPeer: CppSubclassCppPeer> {
#[default]
Empty,
Owned(Box<UniquePtr<CppPeer>>),
Unowned(*mut CppPeer),
}
impl<CppPeer: CppSubclassCppPeer> CppSubclassCppPeerHolder<CppPeer> {
fn pin_mut(&mut self) -> Pin<&mut CppPeer> {
match self {
CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
CppSubclassCppPeerHolder::Owned(peer) => peer.pin_mut(),
CppSubclassCppPeerHolder::Unowned(peer) => unsafe {
Pin::new_unchecked(peer.as_mut().unwrap())
},
}
}
fn get(&self) -> &CppPeer {
match self {
CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
CppSubclassCppPeerHolder::Owned(peer) => peer.as_ref(),
CppSubclassCppPeerHolder::Unowned(peer) => unsafe { peer.as_ref().unwrap() },
}
}
fn set_owned(&mut self, peer: UniquePtr<CppPeer>) {
*self = Self::Owned(Box::new(peer));
}
fn set_unowned(&mut self, peer: &mut UniquePtr<CppPeer>) {
*self = Self::Unowned(unsafe {
std::pin::Pin::<&mut CppPeer>::into_inner_unchecked(peer.pin_mut())
});
}
}
fn make_owning_peer<CppPeer, PeerConstructor, Subclass, PeerBoxer>(
me: Subclass,
peer_constructor: PeerConstructor,
peer_boxer: PeerBoxer,
) -> Rc<RefCell<Subclass>>
where
CppPeer: CppSubclassCppPeer,
Subclass: CppSubclass<CppPeer>,
PeerConstructor:
FnOnce(&mut Subclass, CppSubclassRustPeerHolder<Subclass>) -> UniquePtr<CppPeer>,
PeerBoxer: FnOnce(Rc<RefCell<Subclass>>) -> CppSubclassRustPeerHolder<Subclass>,
{
let me = Rc::new(RefCell::new(me));
let holder = peer_boxer(me.clone());
let cpp_side = peer_constructor(&mut me.as_ref().borrow_mut(), holder);
me.as_ref()
.borrow_mut()
.peer_holder_mut()
.set_owned(cpp_side);
me
}
pub trait CppPeerConstructor<CppPeer: CppSubclassCppPeer>: Sized {
fn make_peer(&mut self, peer_holder: CppSubclassRustPeerHolder<Self>) -> UniquePtr<CppPeer>;
}
pub trait CppSubclass<CppPeer: CppSubclassCppPeer>: CppPeerConstructor<CppPeer> {
fn peer_holder(&self) -> &CppSubclassCppPeerHolder<CppPeer>;
fn peer_holder_mut(&mut self) -> &mut CppSubclassCppPeerHolder<CppPeer>;
fn peer(&self) -> &CppPeer {
self.peer_holder().get()
}
fn peer_mut(&mut self) -> Pin<&mut CppPeer> {
self.peer_holder_mut().pin_mut()
}
fn new_cpp_owned(me: Self) -> UniquePtr<CppPeer> {
let me = Rc::new(RefCell::new(me));
let holder = CppSubclassRustPeerHolder::Owned(me.clone());
let mut borrowed = me.as_ref().borrow_mut();
let mut cpp_side = borrowed.make_peer(holder);
borrowed.peer_holder_mut().set_unowned(&mut cpp_side);
cpp_side
}
fn new_rust_owned(me: Self) -> Rc<RefCell<Self>> {
make_owning_peer(
me,
|obj, holder| obj.make_peer(holder),
|me| CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&me)),
)
}
}
pub trait CppSubclassSelfOwned<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> {
fn new_self_owned(me: Self) -> Rc<RefCell<Self>> {
make_owning_peer(
me,
|obj, holder| obj.make_peer(holder),
CppSubclassRustPeerHolder::Owned,
)
}
fn delete_self(&self) {
self.peer().relinquish_ownership()
}
}
pub trait CppSubclassDefault<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> + Default {
fn default_rust_owned() -> Rc<RefCell<Self>>;
fn default_cpp_owned() -> UniquePtr<CppPeer>;
}
impl<T, CppPeer> CppSubclassDefault<CppPeer> for T
where
T: CppSubclass<CppPeer> + Default,
CppPeer: CppSubclassCppPeer,
{
fn default_rust_owned() -> Rc<RefCell<Self>> {
Self::new_rust_owned(Self::default())
}
fn default_cpp_owned() -> UniquePtr<CppPeer> {
Self::new_cpp_owned(Self::default())
}
}
pub trait CppSubclassSelfOwnedDefault<CppPeer: CppSubclassCppPeer>:
CppSubclassSelfOwned<CppPeer> + Default
{
fn default_self_owned() -> Rc<RefCell<Self>>;
}
impl<T, CppPeer> CppSubclassSelfOwnedDefault<CppPeer> for T
where
T: CppSubclassSelfOwned<CppPeer> + Default,
CppPeer: CppSubclassCppPeer,
{
fn default_self_owned() -> Rc<RefCell<Self>> {
Self::new_self_owned(Self::default())
}
}