motorcortex-rust 0.5.0

Motorcortex Rust: a Rust client for the Motorcortex Core real-time control system (async + blocking).
Documentation
//! Blocking wrapper around [`crate::core::Request`].

use std::sync::{Arc, RwLock};

use tokio::runtime::Runtime;

use crate::client::ParameterTree;
use crate::connection::ConnectionOptions;
use crate::core;
use crate::error::{MotorcortexError, Result};
use crate::msg::{GroupStatusMsg, StatusCode};
use crate::parameter_value::{
    GetParameterTuple, GetParameterValue, SetParameterTuple, SetParameterValue,
};

/// Blocking analogue of [`core::Request`]. Every method mirrors the
/// async one without the `.await`. The hidden current-thread runtime
/// runs the await internally.
///
/// `Request` is `!Sync` because the `Runtime` it owns is; clone one
/// via [`new`](Self::new) per thread that needs independent blocking
/// access, or use the async API if you need `Sync`.
pub struct Request {
    inner: core::Request,
    pub(crate) rt: Arc<Runtime>,
}

impl Request {
    /// Create a new handle. Spawns the async driver thread and
    /// allocates a single-threaded tokio runtime to drive its
    /// futures to completion.
    pub fn new() -> Result<Self> {
        let rt = tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .build()
            .map_err(|e| MotorcortexError::Connection(e.to_string()))?;
        Ok(Self {
            inner: core::Request::new(),
            rt: Arc::new(rt),
        })
    }

    /// Construct + connect in one call.
    ///
    /// ```no_run
    /// use motorcortex_rust::{ConnectionOptions, blocking::Request};
    /// # fn demo() -> motorcortex_rust::Result<()> {
    /// let opts = ConnectionOptions::new("mcx.cert.crt".into(), 1000, 1000);
    /// let req = Request::connect_to("wss://127.0.0.1:5568", opts)?;
    /// req.request_parameter_tree()?;
    /// let v: f64 = req.get_parameter("root/Control/dummyDouble")?;
    /// println!("{v}");
    /// # Ok(()) }
    /// ```
    pub fn connect_to(url: &str, opts: ConnectionOptions) -> Result<Self> {
        let request = Self::new()?;
        request.connect(url, opts)?;
        Ok(request)
    }

    pub fn connect(&self, url: &str, opts: ConnectionOptions) -> Result<()> {
        self.rt.block_on(self.inner.connect(url, opts))
    }

    pub fn disconnect(&self) -> Result<()> {
        self.rt.block_on(self.inner.disconnect())
    }

    pub fn login(&self, user: &str, pass: &str) -> Result<StatusCode> {
        self.rt.block_on(self.inner.login(user, pass))
    }

    pub fn logout(&self) -> Result<StatusCode> {
        self.rt.block_on(self.inner.logout())
    }

    pub fn request_parameter_tree(&self) -> Result<StatusCode> {
        self.rt.block_on(self.inner.request_parameter_tree())
    }

    pub fn get_parameter_tree_hash(&self) -> Result<u32> {
        self.rt.block_on(self.inner.get_parameter_tree_hash())
    }

    pub fn get_parameter<V>(&self, path: &str) -> Result<V>
    where
        V: GetParameterValue + Default,
    {
        self.rt.block_on(self.inner.get_parameter(path))
    }

    pub fn set_parameter<V>(&self, path: &str, value: V) -> Result<StatusCode>
    where
        V: SetParameterValue,
    {
        self.rt.block_on(self.inner.set_parameter(path, value))
    }

    pub fn get_parameters<T>(&self, paths: &[&str]) -> Result<T>
    where
        T: GetParameterTuple,
    {
        self.rt.block_on(self.inner.get_parameters(paths))
    }

    pub fn set_parameters<T>(&self, paths: &[&str], values: T) -> Result<StatusCode>
    where
        T: SetParameterTuple,
    {
        self.rt.block_on(self.inner.set_parameters(paths, values))
    }

    pub fn create_group<I>(
        &self,
        paths: I,
        alias: &str,
        fdiv: u32,
    ) -> Result<GroupStatusMsg>
    where
        I: crate::client::Parameters,
    {
        self.rt.block_on(self.inner.create_group(paths, alias, fdiv))
    }

    pub fn remove_group(&self, alias: &str) -> Result<StatusCode> {
        self.rt.block_on(self.inner.remove_group(alias))
    }

    /// Shared parameter-tree cache. Populated by
    /// [`request_parameter_tree`](Self::request_parameter_tree).
    pub fn parameter_tree(&self) -> Arc<RwLock<ParameterTree>> {
        self.inner.parameter_tree()
    }

    /// Access the inner async handle — useful when one part of your
    /// program is blocking and another is async.
    pub fn as_async(&self) -> &core::Request {
        &self.inner
    }
}