use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::{Bytes, BytesMut};
use futures::{Sink, SinkExt};
use pin_project_lite::pin_project;
use tokio_util::codec::Decoder;
use crate::Protocol;
pin_project! {
pub struct DecodedSink<T: Protocol> {
#[pin]
sink: T::SinkHalf,
decoder: T::Codec,
}
}
impl<T: Protocol> DecodedSink<T> {
pub fn new(sink: T::SinkHalf, decoder: T::Codec) -> Self {
Self { sink, decoder }
}
pub fn into_inner(self) -> T::SinkHalf {
self.sink
}
}
impl<T: Protocol> Sink<Bytes> for DecodedSink<T> {
type Error = io::Error;
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.project().sink.poll_ready_unpin(cx).map_err(Into::into)
}
fn start_send(self: Pin<&mut Self>, bytes: Bytes) -> Result<(), Self::Error> {
let mut this = self.project();
match this.decoder.decode(&mut BytesMut::from(bytes)) {
Ok(Some(msg)) => this.sink.start_send_unpin(msg).map_err(Into::into),
Ok(None) => Err(io::ErrorKind::InvalidData.into()),
Err(e) => Err(e.into()),
}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.project().sink.poll_flush_unpin(cx).map_err(Into::into)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.project().sink.poll_close_unpin(cx).map_err(Into::into)
}
}