rillrate-py 0.40.0

rillrate bindings for python
use crate::utils::get_from;
use pyo3::prelude::*;
use pyo3::types::PyDict;
use rill_protocol::flow::core::Activity;
use rillrate::prime;

pub fn init(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
    m.add_class::<Click>()?;
    m.add_class::<Input>()?;
    m.add_class::<Selector>()?;
    m.add_class::<Slider>()?;
    m.add_class::<Switch>()?;
    Ok(())
}

fn activity(py: Python<'_>, activity: Activity) -> PyResult<&'_ PyAny> {
    let attr = {
        match activity {
            Activity::Suspend => "SUSPEND",
            Activity::Awake => "AWAKE",
            Activity::Disconnected => "DISCONNECTED",
            Activity::Connected => "CONNECTED",
            Activity::Action => "ACTION",
        }
    };
    let module = PyModule::import(py, "rillrate")?;
    let activity = module.getattr("Activity")?;
    activity.getattr(attr)
}

fn action<A: IntoPy<PyObject>>(py: Python<'_>, action: Option<A>) -> PyResult<PyObject> {
    match action {
        None => Ok(py.None()),
        Some(value) => {
            let module = PyModule::import(py, "rillrate")?;
            let class = module.getattr("Action")?;
            let instance = class.call1((value,))?;
            Ok(instance.into())
        }
    }
}

#[pyclass]
pub struct Click {
    tracer: prime::Click,
}

#[pymethods]
impl Click {
    #[new]
    #[args(kwargs = "**")]
    fn new(path: String, kwargs: Option<&PyDict>) -> PyResult<Self> {
        let opts = prime::ClickOpts {
            label: get_from(kwargs, "label")?,
        };
        let tracer = prime::Click::new(path, opts);
        Ok(Self { tracer })
    }

    fn sync_callback(&mut self, callback: PyObject) {
        self.tracer.sync_callback(move |envelope| {
            Python::with_gil(|py| {
                let activity = activity(py, envelope.activity)?;
                let action = action(py, envelope.action)?;
                callback.call1(py, (activity, action))
            })
            .map_err(|err| err.into())
            .map(drop)
        });
    }

    fn apply(&mut self) {
        self.tracer.apply();
    }
}

#[pyclass]
pub struct Input {
    tracer: prime::Input,
}

#[pymethods]
impl Input {
    #[new]
    #[args(kwargs = "**")]
    fn new(path: String, kwargs: Option<&PyDict>) -> PyResult<Self> {
        let opts = prime::InputOpts {
            label: get_from(kwargs, "label")?,
        };
        let tracer = prime::Input::new(path, opts);
        Ok(Self { tracer })
    }

    fn sync_callback(&mut self, callback: PyObject) {
        self.tracer.sync_callback(move |envelope| {
            Python::with_gil(|py| {
                let activity = activity(py, envelope.activity)?;
                let action = action(py, envelope.action)?;
                callback.call1(py, (activity, action))
            })
            .map_err(|err| err.into())
            .map(drop)
        });
    }
}

#[pyclass]
pub struct Selector {
    tracer: prime::Selector,
}

#[pymethods]
impl Selector {
    #[new]
    #[args(kwargs = "**")]
    fn new(path: String, kwargs: Option<&PyDict>) -> PyResult<Self> {
        let opts = prime::SelectorOpts {
            label: get_from(kwargs, "label")?,
            options: get_from(kwargs, "options")?,
        };
        let tracer = prime::Selector::new(path, opts);
        Ok(Self { tracer })
    }

    fn sync_callback(&mut self, callback: PyObject) {
        self.tracer.sync_callback(move |envelope| {
            Python::with_gil(|py| {
                let activity = activity(py, envelope.activity)?;
                let action = action(py, envelope.action)?;
                callback.call1(py, (activity, action))
            })
            .map_err(|err| err.into())
            .map(drop)
        });
    }

    fn apply(&mut self, value: Option<String>) {
        self.tracer.apply(value);
    }
}

#[pyclass]
pub struct Slider {
    tracer: prime::Slider,
}

#[pymethods]
impl Slider {
    #[new]
    #[args(kwargs = "**")]
    fn new(path: String, kwargs: Option<&PyDict>) -> PyResult<Self> {
        let opts = prime::SliderOpts {
            label: get_from(kwargs, "label")?,
            min: get_from(kwargs, "min")?,
            max: get_from(kwargs, "max")?,
            step: get_from(kwargs, "step")?,
        };
        let tracer = prime::Slider::new(path, opts);
        Ok(Self { tracer })
    }

    fn sync_callback(&mut self, callback: PyObject) {
        self.tracer.sync_callback(move |envelope| {
            Python::with_gil(|py| {
                let activity = activity(py, envelope.activity)?;
                let action = action(py, envelope.action)?;
                callback.call1(py, (activity, action))
            })
            .map_err(|err| err.into())
            .map(drop)
        });
    }

    fn apply(&mut self, value: f64) {
        self.tracer.apply(value);
    }
}

#[pyclass]
pub struct Switch {
    tracer: prime::Switch,
}

#[pymethods]
impl Switch {
    #[new]
    #[args(kwargs = "**")]
    fn new(path: String, kwargs: Option<&PyDict>) -> PyResult<Self> {
        let opts = prime::SwitchOpts {
            label: get_from(kwargs, "label")?,
        };
        let tracer = prime::Switch::new(path, opts);
        Ok(Self { tracer })
    }

    fn sync_callback(&mut self, callback: PyObject) {
        self.tracer.sync_callback(move |envelope| {
            Python::with_gil(|py| {
                let activity = activity(py, envelope.activity)?;
                let action = action(py, envelope.action)?;
                callback.call1(py, (activity, action))
            })
            .map_err(|err| err.into())
            .map(drop)
        });
    }

    fn apply(&mut self, value: bool) {
        self.tracer.apply(value);
    }
}