ramp2 1.0.2

RAMP is the glue for Maverick OS, Air Servers, And Prisms UI abstraction
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;

use prism::hardware::{Cancelled, Data, Image, Media, PickResult};
use prism::traits;

#[derive(Clone)]
pub struct Hardware(pub maverick_os::Hardware);
impl traits::Hardware for Hardware {
    type Camera = Camera;
    type Video = Video;

    fn start_camera(&self) -> Self::Camera {Camera(self.0.start_camera())}
    fn video(&self, bytes: Vec<u8>) -> Option<Self::Video> {maverick_os::Video::new(bytes).map(Video::from)}
    fn share(&self, data: &Data) {self.0.share(&Self::to_maverick(data))}
    fn set_clipboard(&self, data: &Data) {self.0.set_clipboard(&Self::to_maverick(data))}
    fn get_clipboard(&self) -> Option<Data> {self.0.get_clipboard().map(Self::from_maverick)}
    fn set_cache(&self, key: &str, data: &Data) {self.0.set_cache(key, &Self::to_maverick(data))}
    fn get_cache(&self, key: &str) -> Option<Data> {self.0.get_cache(key).map(Self::from_maverick)}
    fn trigger_haptic(&self) {self.0.trigger_haptic()}
}
impl Hardware {
    fn from_maverick(data: maverick_os::Data) -> Data {
        match data {
            maverick_os::Data::Text(text) => Data::Text(text),
            maverick_os::Data::Image(image) => Data::Image(image),
            maverick_os::Data::Video(video) => Data::Video(prism::hardware::Video::new(Video::from(video))),
            maverick_os::Data::File(path) => Data::File(path),
        }
    }
    fn to_maverick(data: &Data) -> maverick_os::Data {
        match data {
            Data::Text(text) => maverick_os::Data::Text(text.clone()),
            Data::Image(image) => maverick_os::Data::Image(image.clone()),
            Data::Video(video) => {
                let video = maverick_os::Video::new(video.bytes().as_ref().clone())
                    .expect("A validated video must remain readable");
                maverick_os::Data::Video(video)
            }
            Data::File(path) => maverick_os::Data::File(path.clone()),
        }
    }
}

macro_rules! picker {
    ($native:ty, $item:ty, $convert:expr) => {
        impl traits::Picker<$item> for Hardware {
            type Picked = Picked<$native, $item>;
            fn pick(&self) -> Self::Picked {Picked(self.0.pick(), $convert)}
        }
        impl traits::Picker<Vec<$item>> for Hardware {
            type Picked = Picked<Vec<$native>, Vec<$item>>;
            fn pick(&self) -> Self::Picked {
                Picked(self.0.pick(), |items| items.into_iter().map($convert).collect())
            }
        }
    };
}
picker!(maverick_os::Data, Data, Hardware::from_maverick);
picker!(maverick_os::Image, Image, std::convert::identity);
picker!(maverick_os::Video, prism::hardware::Video, |video| {
    prism::hardware::Video::new(Video::from(video))
});
picker!(maverick_os::Media, Media, |media| match media {
    maverick_os::Media::Image(image) => Media::Image(image),
    maverick_os::Media::Video(video) => Media::Video(prism::hardware::Video::new(Video::from(video))),
});
picker!(PathBuf, PathBuf, std::convert::identity);

#[derive(Clone)]
pub struct Camera(maverick_os::Camera);
impl traits::Camera for Camera {
    fn frame(&self) -> Image {self.0.frame()}
}

pub struct Picked<N: maverick_os::Pickable, T>(maverick_os::Picked<N>, fn(N) -> T);
impl<N: maverick_os::Pickable + 'static, T: Clone + 'static> traits::Picked<T> for Picked<N, T> {
    async fn get(self) -> PickResult<T> {self.0.get().await.map(self.1).map_err(|_| Cancelled)}
    fn try_get(&mut self) -> Option<PickResult<T>> {
        self.0.try_get().map(|result| result.map(self.1).map_err(|_| Cancelled))
    }
}

#[derive(Clone, Debug)]
pub struct Video(maverick_os::Video);
impl From<maverick_os::Video> for Video {
    fn from(video: maverick_os::Video) -> Self {Self(video)}
}
impl traits::Video for Video {
    fn bytes(&self) -> &Arc<Vec<u8>> {self.0.bytes()}
    fn duration(&self) -> Option<Duration> {self.0.duration()}
    fn dimensions(&self) -> (u32, u32) {self.0.dimensions()}
    fn thumbnail(&self) -> Image {self.0.thumbnail()}
    fn format(&self) -> &str {self.0.format()}
    fn codec(&self) -> &str {self.0.codec()}
    fn player(&self) -> Result<Box<dyn traits::Player>, String> {
        maverick_os::Player::new(&self.0).map(|player| Box::new(Player(player)) as _)
    }
}

#[derive(Clone, Debug)]
pub struct Player(maverick_os::Player);
impl traits::Player for Player {
    fn start(&self) {self.0.start()}
    fn stop(&self) {self.0.stop()}
    fn set_speed(&self, speed: f64) {self.0.set_speed(speed)}
    fn speed(&self) -> f64 {self.0.speed()}
    fn seek(&self, position: Duration) {self.0.seek(position)}
    fn position(&self) -> Duration {self.0.position()}
    fn duration(&self) -> Option<Duration> {self.0.duration()}
    fn is_playing(&self) -> bool {self.0.is_playing()}
    fn frame(&self) -> Image {self.0.frame()}
}