fastboop-core 0.0.1-rc.21

Core profile matching and boot orchestration primitives for fastboop.
Documentation
extern crate alloc;

use alloc::vec::Vec;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};

use crate::DeviceProfile;
use crate::fastboot::FastbootWire;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct DeviceFilter {
    pub vid: u16,
    pub pid: u16,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DeviceEvent<D> {
    Arrived { device: D },
    Left { device: D },
}

pub trait DeviceHandle: Clone + Send + Sync + 'static {
    type FastbootWire: FastbootWire;
    type OpenFastbootError;

    type OpenFastbootFuture<'a>: Future<Output = Result<Self::FastbootWire, Self::OpenFastbootError>>
        + 'a
    where
        Self: 'a;

    fn vid(&self) -> u16;
    fn pid(&self) -> u16;
    fn open_fastboot<'a>(&'a self) -> Self::OpenFastbootFuture<'a>;
}

pub trait DeviceWatcher {
    type Device: DeviceHandle;
    type Error;

    fn poll_next_event(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<DeviceEvent<Self::Device>, Self::Error>>;

    fn next_event(&mut self) -> NextDeviceEvent<'_, Self>
    where
        Self: Sized + Unpin,
    {
        NextDeviceEvent { watcher: self }
    }

    fn try_next_event(&mut self) -> Poll<Result<DeviceEvent<Self::Device>, Self::Error>>
    where
        Self: Sized + Unpin,
    {
        let waker = noop_waker();
        let mut cx = Context::from_waker(&waker);
        Pin::new(self).poll_next_event(&mut cx)
    }
}

pub struct NextDeviceEvent<'a, W: DeviceWatcher + Unpin + ?Sized> {
    watcher: &'a mut W,
}

impl<W> Future for NextDeviceEvent<'_, W>
where
    W: DeviceWatcher + Unpin + ?Sized,
{
    type Output = Result<DeviceEvent<W::Device>, W::Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        Pin::new(&mut *self.watcher).poll_next_event(cx)
    }
}

pub fn profile_filters(profiles: &[DeviceProfile]) -> Vec<DeviceFilter> {
    let mut filters = Vec::new();
    for profile in profiles {
        for rule in &profile.r#match {
            let filter = DeviceFilter {
                vid: rule.fastboot.vid,
                pid: rule.fastboot.pid,
            };
            if !filters.contains(&filter) {
                filters.push(filter);
            }
        }
    }
    filters
}

fn noop_raw_waker() -> RawWaker {
    unsafe fn clone(_: *const ()) -> RawWaker {
        noop_raw_waker()
    }

    unsafe fn wake(_: *const ()) {}

    unsafe fn wake_by_ref(_: *const ()) {}

    unsafe fn drop(_: *const ()) {}

    static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
    RawWaker::new(core::ptr::null(), &VTABLE)
}

fn noop_waker() -> Waker {
    unsafe { Waker::from_raw(noop_raw_waker()) }
}