use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::Bytes;
use foundation_core::valtron::Pipe;
use foundation_errstacks::ErrorTrace;
use foundation_netio::shared::http::SimpleHeaders;
use crate::shared::error::ConnectError;
pub const DEFAULT_PIPE_DEPTH: usize = 4;
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub enum Frame {
Message(Bytes),
EndStream {
error: Option<ErrorTrace<ConnectError>>,
trailers: SimpleHeaders,
},
}
impl core::fmt::Debug for Frame {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Frame::Message(b) => f.debug_tuple("Message").field(&b.len()).finish(),
Frame::EndStream { error, trailers } => f
.debug_struct("EndStream")
.field("error", &error.is_some())
.field("trailers", &trailers.len())
.finish(),
}
}
}
pub type FramePipe = Pipe<Frame>;
pub enum Either<A, B> {
Left(A),
Right(B),
}
pub fn race<A: Future, B: Future>(a: A, b: B) -> Race<A, B> {
Race { a, b }
}
#[must_use]
pub fn copy_error(error: &ErrorTrace<ConnectError>) -> ErrorTrace<ConnectError> {
let ctx = error.current_context();
ConnectError::new(ctx.code(), ctx.message().to_string()).into()
}
pub async fn fail_stream(
tx: &foundation_core::valtron::PipeSender<Frame>,
error: &ErrorTrace<ConnectError>,
cancel: &crate::shared::context::CancelSignal,
) {
let frame = Frame::EndStream {
error: Some(copy_error(error)),
trailers: SimpleHeaders::new(),
};
let _ = race(tx.send(frame), cancel.cancelled()).await;
tx.close();
}
pub struct Race<A, B> {
a: A,
b: B,
}
impl<A: Future, B: Future> Future for Race<A, B> {
type Output = Either<A::Output, B::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
let a = unsafe { Pin::new_unchecked(&mut this.a) };
if let Poll::Ready(v) = a.poll(cx) {
return Poll::Ready(Either::Left(v));
}
let b = unsafe { Pin::new_unchecked(&mut this.b) };
if let Poll::Ready(v) = b.poll(cx) {
return Poll::Ready(Either::Right(v));
}
Poll::Pending
}
}