use std::marker::PhantomData;
use bytes::Bytes;
use serde::Serialize;
use crate::{Error, Result};
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct ProducerConfig {
pub compression: bool,
}
impl ProducerConfig {
pub fn with_compression(mut self, compression: bool) -> Self {
self.compression = compression;
self
}
}
#[must_use = "write and commit the record; an uncommitted compressed record stops the encoder"]
pub struct Pending<'a, T> {
encoder: &'a mut Encoder<T>,
payload: Bytes,
committed: bool,
}
impl<T> Pending<'_, T> {
pub fn payload(&self) -> &Bytes {
&self.payload
}
pub fn commit(mut self) {
self.committed = true;
}
}
impl<T> Drop for Pending<'_, T> {
fn drop(&mut self) {
if !self.committed {
self.encoder.desync();
}
}
}
pub struct Encoder<T> {
flate: Option<moq_flate::Encoder>,
compression: bool,
desynced: bool,
_marker: PhantomData<fn(T)>,
}
impl<T> Encoder<T> {
pub fn new(config: ProducerConfig) -> Self {
Self {
flate: config.compression.then(moq_flate::Encoder::new),
compression: config.compression,
desynced: false,
_marker: PhantomData,
}
}
pub fn reset(&mut self) {
self.flate = self.compression.then(moq_flate::Encoder::new);
self.desynced = false;
}
fn desync(&mut self) {
self.desynced = self.compression;
}
}
impl<T: Serialize> Encoder<T> {
pub fn encode(&mut self, value: &T) -> Result<Pending<'_, T>> {
if self.desynced {
return Err(Error::Desync);
}
let bytes = serde_json::to_vec(value)?;
let payload = match self.flate.as_mut() {
Some(flate) => flate.frame(&bytes),
None => Bytes::from(bytes),
};
Ok(Pending {
encoder: self,
payload,
committed: false,
})
}
}