use pyo3::prelude::*;
use pyo3::types::PyBytes;
use std::io::{Read, Write};
use crate::error::IpcError;
use crate::pipe::{AnonymousPipe as RustAnonymousPipe, NamedPipe as RustNamedPipe};
#[pyclass(name = "AnonymousPipe")]
pub struct PyAnonymousPipe {
reader: std::sync::Mutex<Option<crate::pipe::PipeReader>>,
writer: std::sync::Mutex<Option<crate::pipe::PipeWriter>>,
}
#[pymethods]
impl PyAnonymousPipe {
#[new]
fn new() -> PyResult<Self> {
let pipe = RustAnonymousPipe::new()?;
let (reader, writer) = pipe.split();
Ok(Self {
reader: std::sync::Mutex::new(Some(reader)),
writer: std::sync::Mutex::new(Some(writer)),
})
}
fn read(&self, py: Python<'_>, size: usize) -> PyResult<Py<PyBytes>> {
let mut guard = self
.reader
.lock()
.map_err(|_| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Lock poisoned"))?;
let reader = guard.as_mut().ok_or(IpcError::Closed)?;
let mut buf = vec![0u8; size];
let n = py.detach(|| reader.read(&mut buf))?;
buf.truncate(n);
Ok(PyBytes::new(py, &buf).into())
}
fn write(&self, py: Python<'_>, data: &[u8]) -> PyResult<usize> {
let mut guard = self
.writer
.lock()
.map_err(|_| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Lock poisoned"))?;
let writer = guard.as_mut().ok_or(IpcError::Closed)?;
let data = data.to_vec(); let n = py.detach(|| writer.write(&data))?;
Ok(n)
}
#[cfg(unix)]
fn reader_fd(&self) -> PyResult<i32> {
use std::os::unix::io::AsRawFd;
let guard = self
.reader
.lock()
.map_err(|_| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Lock poisoned"))?;
let reader = guard.as_ref().ok_or(IpcError::Closed)?;
Ok(reader.as_raw_fd())
}
#[cfg(unix)]
fn writer_fd(&self) -> PyResult<i32> {
use std::os::unix::io::AsRawFd;
let guard = self
.writer
.lock()
.map_err(|_| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Lock poisoned"))?;
let writer = guard.as_ref().ok_or(IpcError::Closed)?;
Ok(writer.as_raw_fd())
}
fn take_reader(&self) -> PyResult<()> {
let mut guard = self
.reader
.lock()
.map_err(|_| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Lock poisoned"))?;
guard.take();
Ok(())
}
fn take_writer(&self) -> PyResult<()> {
let mut guard = self
.writer
.lock()
.map_err(|_| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Lock poisoned"))?;
guard.take();
Ok(())
}
}
#[pyclass(name = "NamedPipe")]
pub struct PyNamedPipe {
inner: RustNamedPipe,
}
#[pymethods]
impl PyNamedPipe {
#[staticmethod]
fn create(name: &str) -> PyResult<Self> {
let inner = RustNamedPipe::create(name)?;
Ok(Self { inner })
}
#[staticmethod]
fn connect(name: &str) -> PyResult<Self> {
let inner = RustNamedPipe::connect(name)?;
Ok(Self { inner })
}
#[getter]
fn name(&self) -> &str {
self.inner.name()
}
#[getter]
fn is_server(&self) -> bool {
self.inner.is_server()
}
fn wait_for_client(&mut self, py: Python<'_>) -> PyResult<()> {
py.detach(|| self.inner.wait_for_client())?;
Ok(())
}
fn read(&mut self, py: Python<'_>, size: usize) -> PyResult<Py<PyBytes>> {
let mut buf = vec![0u8; size];
let n = py.detach(|| self.inner.read(&mut buf))?;
buf.truncate(n);
Ok(PyBytes::new(py, &buf).into())
}
fn write(&mut self, py: Python<'_>, data: Vec<u8>) -> PyResult<usize> {
let n = py.detach(|| self.inner.write(&data))?;
Ok(n)
}
fn read_exact(&mut self, py: Python<'_>, size: usize) -> PyResult<Py<PyBytes>> {
let mut buf = vec![0u8; size];
py.detach(|| self.inner.read_exact(&mut buf))?;
Ok(PyBytes::new(py, &buf).into())
}
fn write_all(&mut self, py: Python<'_>, data: Vec<u8>) -> PyResult<()> {
py.detach(|| self.inner.write_all(&data))?;
Ok(())
}
}