use std::{collections::HashMap, sync::Arc};
use tokio::sync::Mutex;
use crate::{
info::{ByteStreamInfo, TextStreamInfo},
outgoing::{constants::STREAM_CHUNK_SIZE_BYTES, raw_stream::RawStream},
utf8_chunk::Utf8AwareChunkExt,
utils::StreamResult,
};
pub trait StreamWriter<'a> {
type Input: 'a;
type Info;
fn info(&self) -> &Self::Info;
fn write(
&self,
input: Self::Input,
) -> impl std::future::Future<Output = StreamResult<()>> + Send;
fn close(self) -> impl std::future::Future<Output = StreamResult<()>> + Send;
fn close_with_reason(
self,
reason: &str,
) -> impl std::future::Future<Output = StreamResult<()>> + Send;
fn close_with_options(
self,
reason: Option<&str>,
attributes: Option<HashMap<String, String>>,
) -> impl std::future::Future<Output = StreamResult<()>> + Send;
}
#[derive(Clone)]
pub struct ByteStreamWriter {
info: Arc<ByteStreamInfo>,
stream: Arc<Mutex<RawStream>>,
}
impl ByteStreamWriter {
pub(crate) fn new(info: Arc<ByteStreamInfo>, stream: Arc<Mutex<RawStream>>) -> Self {
Self { info, stream }
}
}
#[derive(Clone)]
pub struct TextStreamWriter {
info: Arc<TextStreamInfo>,
stream: Arc<Mutex<RawStream>>,
}
impl TextStreamWriter {
pub(crate) fn new(info: Arc<TextStreamInfo>, stream: Arc<Mutex<RawStream>>) -> Self {
Self { info, stream }
}
}
impl<'a> StreamWriter<'a> for ByteStreamWriter {
type Input = &'a [u8];
type Info = ByteStreamInfo;
fn info(&self) -> &Self::Info {
&self.info
}
async fn write(&self, bytes: &'a [u8]) -> StreamResult<()> {
let mut stream = self.stream.lock().await;
for chunk in bytes.chunks(STREAM_CHUNK_SIZE_BYTES) {
stream.write_chunk(chunk).await?;
}
Ok(())
}
async fn close(self) -> StreamResult<()> {
self.stream.lock().await.close(None, None).await
}
async fn close_with_reason(self, reason: &str) -> StreamResult<()> {
self.stream.lock().await.close(Some(reason), None).await
}
async fn close_with_options(
self,
reason: Option<&str>,
attributes: Option<HashMap<String, String>>,
) -> StreamResult<()> {
self.stream.lock().await.close(reason, attributes).await
}
}
impl<'a> StreamWriter<'a> for TextStreamWriter {
type Input = &'a str;
type Info = TextStreamInfo;
fn info(&self) -> &Self::Info {
&self.info
}
async fn write(&self, text: &'a str) -> StreamResult<()> {
let mut stream = self.stream.lock().await;
for chunk in text.as_bytes().utf8_aware_chunks(STREAM_CHUNK_SIZE_BYTES) {
stream.write_chunk(chunk).await?;
}
Ok(())
}
async fn close(self) -> StreamResult<()> {
self.stream.lock().await.close(None, None).await
}
async fn close_with_reason(self, reason: &str) -> StreamResult<()> {
self.stream.lock().await.close(Some(reason), None).await
}
async fn close_with_options(
self,
reason: Option<&str>,
attributes: Option<HashMap<String, String>>,
) -> StreamResult<()> {
self.stream.lock().await.close(reason, attributes).await
}
}