use std::fmt::Debug;
use crate::{Error, coding::*, ietf};
pub struct Writer<S: web_transport_trait::SendStream, V> {
stream: Option<S>,
buffer: bytes::BytesMut,
version: V,
}
impl<S: web_transport_trait::SendStream, V> Writer<S, V> {
pub fn new(stream: S, version: V) -> Self {
Self {
stream: Some(stream),
buffer: Default::default(),
version,
}
}
pub async fn encode<T: Encode<V> + Debug>(&mut self, msg: &T) -> Result<(), Error>
where
V: Clone,
{
self.buffer.clear();
msg.encode(&mut self.buffer, self.version.clone())?;
while !self.buffer.is_empty() {
self.stream
.as_mut()
.unwrap()
.write_buf(&mut self.buffer)
.await
.map_err(Error::from_transport)?;
}
Ok(())
}
async fn write<Buf: bytes::Buf + Send>(&mut self, buf: &mut Buf) -> Result<usize, Error> {
self.stream
.as_mut()
.unwrap()
.write_buf(buf)
.await
.map_err(Error::from_transport)
}
pub async fn write_all<Buf: bytes::Buf + Send>(&mut self, buf: &mut Buf) -> Result<(), Error> {
while buf.has_remaining() {
self.write(buf).await?;
}
Ok(())
}
pub fn finish(&mut self) -> Result<(), Error> {
self.stream.as_mut().unwrap().finish().map_err(Error::from_transport)
}
pub fn abort(&mut self, err: &Error) {
self.stream.as_mut().unwrap().reset(err.to_code());
}
pub async fn closed(&mut self) -> Result<(), Error> {
self.stream
.as_mut()
.unwrap()
.closed()
.await
.map_err(Error::from_transport)?;
Ok(())
}
pub fn set_priority(&mut self, priority: u8) {
self.stream.as_mut().unwrap().set_priority(priority);
}
pub fn with_version<O>(mut self, version: O) -> Writer<S, O> {
Writer {
stream: self.stream.take(),
buffer: std::mem::take(&mut self.buffer),
version,
}
}
}
impl<S: web_transport_trait::SendStream> Writer<S, ietf::Version> {
pub async fn encode_message<T: ietf::Message>(&mut self, msg: &T) -> Result<(), Error> {
self.encode(&T::ID).await?;
self.encode(msg).await
}
}
impl<S: web_transport_trait::SendStream, V> Drop for Writer<S, V> {
fn drop(&mut self) {
if let Some(mut stream) = self.stream.take() {
stream.reset(Error::Cancel.to_code());
}
}
}