roplat 0.2.0

roplat: just a robot operation system
Documentation
//! 进程内 mpsc 环回后端
//!
//! 用于单元测试与示例。将 `publish` 写入的字节直接塞入内存 channel,
//! `try_recv` 从 channel 读取。不跨进程、不走网络,仅验证语义层契约。

use super::super::transport::{IpcError, IpcResult, IpcTransport};
use std::sync::Mutex;
use std::sync::mpsc;

/// 进程内环回传输后端。
///
/// 仅用于测试与示例,不提供跨进程能力。
pub struct LoopbackTransport {
    tx: Mutex<mpsc::Sender<Vec<u8>>>,
    rx: Mutex<mpsc::Receiver<Vec<u8>>>,
}

impl Default for LoopbackTransport {
    fn default() -> Self {
        Self::new()
    }
}

impl LoopbackTransport {
    /// 创建一个新的环回后端实例。
    pub fn new() -> Self {
        let (tx, rx) = mpsc::channel();
        Self { tx: Mutex::new(tx), rx: Mutex::new(rx) }
    }
}

impl IpcTransport for LoopbackTransport {
    fn kind(&self) -> &'static str {
        "loopback"
    }

    fn publish(&self, bytes: &[u8]) -> IpcResult<()> {
        self.tx
            .lock()
            .expect("loopback tx poisoned")
            .send(bytes.to_vec())
            .map_err(|_| IpcError::PeerGone)
    }

    fn try_recv(&self) -> IpcResult<Option<Vec<u8>>> {
        match self.rx.lock().expect("loopback rx poisoned").try_recv() {
            Ok(v) => Ok(Some(v)),
            Err(mpsc::TryRecvError::Empty) => Ok(None),
            Err(mpsc::TryRecvError::Disconnected) => Err(IpcError::PeerGone),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn publish_then_recv() {
        let t = LoopbackTransport::new();
        assert!(t.try_recv().unwrap().is_none());
        t.publish(&[1, 2, 3]).unwrap();
        assert_eq!(t.try_recv().unwrap(), Some(vec![1, 2, 3]));
        assert!(t.try_recv().unwrap().is_none());
    }
}