#[cfg(feature = "std")]
use core::future::Future;
#[cfg(feature = "std")]
use core::pin::Pin;
#[cfg(feature = "std")]
use alloc::boxed::Box;
#[cfg(feature = "std")]
use bytes::Bytes;
#[cfg(feature = "std")]
use futures::io::{AsyncRead, AsyncWrite};
#[cfg(feature = "std")]
use proxima_core::ProximaError;
#[cfg(feature = "std")]
pub trait HijackStream: AsyncRead + AsyncWrite + Send + Unpin {}
#[cfg(feature = "std")]
impl<T: AsyncRead + AsyncWrite + Send + Unpin + ?Sized> HijackStream for T {}
#[cfg(feature = "std")]
pub struct HijackedSocket {
pub stream: Box<dyn HijackStream>,
pub leftover: Bytes,
}
#[cfg(feature = "std")]
impl HijackedSocket {
#[must_use]
pub fn new(stream: Box<dyn HijackStream>, leftover: Bytes) -> Self {
Self { stream, leftover }
}
}
#[cfg(feature = "std")]
pub type UpgradeFuture = Pin<Box<dyn Future<Output = Result<(), ProximaError>> + Send>>;
#[cfg(feature = "std")]
pub struct UpgradeHandler {
inner: Box<dyn FnOnce(HijackedSocket) -> UpgradeFuture + Send>,
}
#[cfg(feature = "std")]
impl UpgradeHandler {
#[must_use]
pub fn new<F, Fut>(handler: F) -> Self
where
F: FnOnce(HijackedSocket) -> Fut + Send + 'static,
Fut: Future<Output = Result<(), ProximaError>> + Send + 'static,
{
Self {
inner: Box::new(move |socket| Box::pin(handler(socket))),
}
}
pub fn invoke(self, socket: HijackedSocket) -> UpgradeFuture {
(self.inner)(socket)
}
}
#[cfg(feature = "std")]
impl core::fmt::Debug for UpgradeHandler {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter
.debug_struct("UpgradeHandler")
.finish_non_exhaustive()
}
}
#[cfg(feature = "std")]
pub type AcceptHandle = crate::pipe::alloc_tier::PipeHandle<(), UpgradeHandler>;
#[cfg(feature = "std")]
pub trait LocalHijackStream: AsyncRead + AsyncWrite + Unpin {}
#[cfg(feature = "std")]
impl<T: AsyncRead + AsyncWrite + Unpin + ?Sized> LocalHijackStream for T {}
#[cfg(feature = "std")]
pub struct LocalHijackedSocket {
pub stream: Box<dyn LocalHijackStream>,
pub leftover: Bytes,
}
#[cfg(feature = "std")]
impl LocalHijackedSocket {
#[must_use]
pub fn new(stream: Box<dyn LocalHijackStream>, leftover: Bytes) -> Self {
Self { stream, leftover }
}
}
#[cfg(feature = "std")]
pub type LocalUpgradeFuture = Pin<Box<dyn Future<Output = Result<(), ProximaError>>>>;
#[cfg(feature = "std")]
pub struct LocalUpgradeHandler {
inner: Box<dyn FnOnce(LocalHijackedSocket) -> LocalUpgradeFuture>,
}
#[cfg(feature = "std")]
impl LocalUpgradeHandler {
#[must_use]
pub fn new<F, Fut>(handler: F) -> Self
where
F: FnOnce(LocalHijackedSocket) -> Fut + 'static,
Fut: Future<Output = Result<(), ProximaError>> + 'static,
{
Self {
inner: Box::new(move |socket| Box::pin(handler(socket))),
}
}
pub fn invoke(self, socket: LocalHijackedSocket) -> LocalUpgradeFuture {
(self.inner)(socket)
}
}
#[cfg(feature = "std")]
impl core::fmt::Debug for LocalUpgradeHandler {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter
.debug_struct("LocalUpgradeHandler")
.finish_non_exhaustive()
}
}
#[cfg(feature = "std")]
pub mod local_slots {
use super::LocalUpgradeHandler;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::sync::atomic::{AtomicU64, Ordering};
thread_local! {
static SLOTS: RefCell<BTreeMap<u64, LocalUpgradeHandler>> = const { RefCell::new(BTreeMap::new()) };
}
static TICKET_GEN: AtomicU64 = AtomicU64::new(1);
#[must_use]
pub fn next_ticket() -> u64 {
TICKET_GEN.fetch_add(1, Ordering::Relaxed)
}
pub fn install(ticket: u64, handler: LocalUpgradeHandler) {
SLOTS.with(|cell| {
cell.borrow_mut().insert(ticket, handler);
});
}
pub fn take(ticket: u64) -> Option<LocalUpgradeHandler> {
SLOTS.with(|cell| cell.borrow_mut().remove(&ticket))
}
pub fn discard(ticket: u64) {
let _ = take(ticket);
}
}