use std::time::Duration;
use pyo3::exceptions::{PyIndexError, PyValueError};
use pyo3::prelude::*;
use pyo3::types::PyBytes;
use super::enums::{Bandwidth, FrameSize, Mode};
#[pyclass(module = "ruopus", name = "Toc", eq, hash, frozen, from_py_object)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Toc {
inner: crate::packet::Toc,
}
#[pymethods]
impl Toc {
#[new]
fn new(byte: u8) -> Self {
Self {
inner: crate::packet::Toc::new(byte),
}
}
#[staticmethod]
fn from_parts(config: u8, stereo: bool, frame_count_code: u8) -> PyResult<Self> {
if config > 31 {
return Err(PyValueError::new_err("config must be 0..=31"));
}
if frame_count_code > 3 {
return Err(PyValueError::new_err("frame_count_code must be 0..=3"));
}
Ok(Self {
inner: crate::packet::Toc::from_parts(config, stereo, frame_count_code),
})
}
#[getter]
fn byte(&self) -> u8 {
self.inner.byte()
}
#[getter]
fn config(&self) -> u8 {
self.inner.config()
}
#[getter]
fn stereo(&self) -> bool {
self.inner.stereo()
}
#[getter]
fn channels(&self) -> u8 {
self.inner.channels()
}
#[getter]
fn frame_count_code(&self) -> u8 {
self.inner.frame_count_code()
}
#[getter]
fn mode(&self) -> Mode {
self.inner.mode().into()
}
#[getter]
fn bandwidth(&self) -> Bandwidth {
self.inner.bandwidth().into()
}
#[getter]
fn frame_size(&self) -> FrameSize {
self.inner.frame_size().into()
}
fn __int__(&self) -> u8 {
self.inner.byte()
}
fn __repr__(&self) -> String {
format!(
"Toc(byte={}, config={}, channels={}, frame_count_code={})",
self.inner.byte(),
self.inner.config(),
self.inner.channels(),
self.inner.frame_count_code(),
)
}
}
#[pyclass(module = "ruopus", name = "Packet", frozen, sequence)]
pub struct Packet {
toc: Toc,
frames: Vec<Vec<u8>>,
padding: usize,
duration: Duration,
}
impl Packet {
fn from_parsed(p: &crate::packet::Packet) -> Self {
Self {
toc: Toc { inner: p.toc() },
frames: p.frames().iter().map(|f| f.to_vec()).collect(),
padding: p.padding(),
duration: p.duration(),
}
}
}
#[pymethods]
impl Packet {
#[new]
fn parse(data: &[u8]) -> PyResult<Self> {
Ok(Self::from_parsed(&crate::packet::Packet::parse(data)?))
}
#[staticmethod]
#[pyo3(signature = (data) -> "tuple[Packet, int]")]
fn parse_self_delimited(data: &[u8]) -> PyResult<(Self, usize)> {
let (p, used) = crate::packet::Packet::parse_self_delimited(data)?;
Ok((Self::from_parsed(&p), used))
}
#[getter]
fn toc(&self) -> Toc {
self.toc
}
#[getter]
fn frames<'py>(&self, py: Python<'py>) -> Vec<Bound<'py, PyBytes>> {
self.frames.iter().map(|f| PyBytes::new(py, f)).collect()
}
#[getter]
fn padding(&self) -> usize {
self.padding
}
#[getter]
fn duration(&self) -> Duration {
self.duration
}
fn __len__(&self) -> usize {
self.frames.len()
}
fn __getitem__<'py>(&self, py: Python<'py>, index: isize) -> PyResult<Bound<'py, PyBytes>> {
let n = self.frames.len() as isize;
let i = if index < 0 { index + n } else { index };
if i < 0 || i >= n {
return Err(PyIndexError::new_err("frame index out of range"));
}
Ok(PyBytes::new(py, &self.frames[i as usize]))
}
fn __repr__(&self) -> String {
format!(
"Packet(frames={}, channels={}, duration={:?})",
self.frames.len(),
self.toc.channels(),
self.duration,
)
}
}