cranpose 0.1.145

Cranpose runtime and UI facade
Documentation
#![allow(unsafe_code)]

use std::{
    cell::RefCell,
    future::Future,
    pin::Pin,
    rc::Rc,
    task::{Context, Poll, Waker},
};

use objc2::{ClassType, DefinedClass, MainThreadMarker, MainThreadOnly, msg_send, rc::Retained};

pub(crate) struct PickSlot<T> {
    result: Option<T>,
    waker: Option<Waker>,
}

impl<T> Default for PickSlot<T> {
    fn default() -> Self {
        Self {
            result: None,
            waker: None,
        }
    }
}

pub(crate) type SharedPickSlot<T> = Rc<RefCell<PickSlot<T>>>;

pub(crate) struct PickFuture<T, D> {
    pub(crate) slot: SharedPickSlot<T>,
    pub(crate) _delegate: Retained<D>,
}

impl<T, D> Future for PickFuture<T, D> {
    type Output = T;

    fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<T> {
        let mut slot = self.slot.borrow_mut();
        if let Some(result) = slot.result.take() {
            Poll::Ready(result)
        } else {
            slot.waker = Some(context.waker().clone());
            Poll::Pending
        }
    }
}

pub(crate) fn new_pick_delegate<T, D>(slot: SharedPickSlot<T>, mtm: MainThreadMarker) -> Retained<D>
where
    D: DefinedClass<Ivars = SharedPickSlot<T>> + MainThreadOnly,
    D::Super: ClassType,
{
    let this = D::alloc(mtm).set_ivars(slot);
    unsafe { msg_send![super(this), init] }
}

pub(crate) fn resolve_pick_slot<T>(slot: &SharedPickSlot<T>, result: T) {
    let mut slot = slot.borrow_mut();
    slot.result = Some(result);
    if let Some(waker) = slot.waker.take() {
        waker.wake();
    }
}