cacao/src/utils/properties.rs
2022-07-15 16:14:02 +02:00

78 lines
2.4 KiB
Rust

use std::cell::RefCell;
use std::rc::Rc;
use objc::runtime::Object;
use objc_id::Id;
use crate::foundation::id;
/// A wrapper for single-threaded `ObjcProperty` types.
///
/// An `ObjcProperty` is something that exists on the Objective-C side that we want to interact with, and
/// support cloning with respect to our side and the general Rust rules. Thus, we do a layer of
/// Rc/RefCell to shield things and make life easier.
///
/// It is possible we could remove the `Id` wrapper in here if we're just doing this ourselves, and
/// is probably worth investigating at some point.
#[derive(Clone, Debug)]
pub struct ObjcProperty(Rc<RefCell<Id<Object>>>);
impl ObjcProperty {
/// Given an Objective-C object, retains it and wraps it as a `Property`.
pub fn retain(obj: id) -> Self {
ObjcProperty(Rc::new(RefCell::new(unsafe { Id::from_ptr(obj) })))
}
/// Given an Objective-C object, retains it and wraps it as a `Property`.
pub fn from_retained(obj: id) -> Self {
ObjcProperty(Rc::new(RefCell::new(unsafe { Id::from_retained_ptr(obj) })))
}
/// Runs a handler with mutable access for the underlying Objective-C object.
///
/// Note that this is mutable access from the Rust side; we make every effort to ensure things are valid
/// on the Objective-C side as well, but there be dragons.
pub fn with_mut<F: Fn(id)>(&self, handler: F) {
let mut obj = self.0.borrow_mut();
handler(&mut **obj);
}
/// Runs a handler with the underlying Objective-C type.
///
/// The handler can return whatever; this is primarily intended for dynamically calling getters
/// on the underlying type.
pub fn get<R, F: Fn(&Object) -> R>(&self, handler: F) -> R {
let obj = self.0.borrow();
handler(&**obj)
}
}
/// A wrapper for a single-threaded nullable `Property`.
#[derive(Debug, Default)]
pub struct PropertyNullable<T>(Rc<RefCell<Option<T>>>);
impl<T> PropertyNullable<T> {
pub fn new(obj: T) -> Self {
Self(Rc::new(RefCell::new(Some(obj))))
}
pub fn clone(&self) -> Self {
Self(Rc::clone(&self.0))
}
pub fn with<F>(&self, handler: F)
where
F: Fn(&T)
{
let borrow = self.0.borrow();
if let Some(s) = &*borrow {
handler(s);
}
}
pub fn set(&self, obj: T) {
let mut borrow = self.0.borrow_mut();
*borrow = Some(obj);
}
}