ruchei_extra/
lib.rs

1//! Store extra data alongside a [`Future`]/[`Stream`]/[`Sink`].
2//!
3//! Commonly used for storing types with [`Drop`] logic.
4
5#![no_std]
6#![cfg_attr(docsrs, feature(doc_auto_cfg))]
7#![cfg_attr(docsrs, feature(doc_cfg_hide))]
8#![cfg_attr(docsrs, doc(cfg_hide(doc)))]
9
10use core::pin::Pin;
11#[cfg(any(feature = "futures-core", feature = "futures-sink"))]
12use core::task::{Context, Poll};
13
14#[cfg(feature = "futures-core")]
15use futures_core::{FusedFuture, FusedStream, Future, Stream};
16#[cfg(feature = "futures-sink")]
17use futures_sink::Sink;
18use pin_project::pin_project;
19#[cfg(feature = "route-sink")]
20use route_sink::{FlushRoute, ReadyRoute, ReadySome};
21
22/// [`Future`]/[`Stream`]/[`Sink`] with extra data attached.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
24#[pin_project]
25pub struct WithExtra<T, Ex> {
26    #[pin]
27    inner: T,
28    extra: Ex,
29}
30
31impl<T, Ex> WithExtra<T, Ex> {
32    /// Attach extra data to a value.
33    #[must_use]
34    pub const fn new(inner: T, extra: Ex) -> Self {
35        Self { inner, extra }
36    }
37
38    /// Unwrap into parts.
39    #[must_use]
40    pub fn into_inner(self) -> (T, Ex) {
41        (self.inner, self.extra)
42    }
43
44    /// Get a pinned mutable reference to the inner value.
45    #[must_use]
46    pub fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
47        self.project().inner
48    }
49}
50
51impl<T, Ex> From<(T, Ex)> for WithExtra<T, Ex> {
52    fn from((inner, extra): (T, Ex)) -> Self {
53        Self::new(inner, extra)
54    }
55}
56
57impl<T, Ex> From<WithExtra<T, Ex>> for (T, Ex) {
58    fn from(value: WithExtra<T, Ex>) -> Self {
59        value.into_inner()
60    }
61}
62
63impl<T, Ex: Default> From<T> for WithExtra<T, Ex> {
64    fn from(inner: T) -> Self {
65        Self::new(inner, Ex::default())
66    }
67}
68
69impl<T, Ex> AsRef<T> for WithExtra<T, Ex> {
70    fn as_ref(&self) -> &T {
71        &self.inner
72    }
73}
74
75impl<T, Ex> AsMut<T> for WithExtra<T, Ex> {
76    fn as_mut(&mut self) -> &mut T {
77        &mut self.inner
78    }
79}
80
81#[cfg(feature = "futures-core")]
82impl<T: Future, Ex> Future for WithExtra<T, Ex> {
83    type Output = T::Output;
84
85    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
86        self.project().inner.poll(cx)
87    }
88}
89
90#[cfg(feature = "futures-core")]
91impl<T: FusedFuture, Ex> FusedFuture for WithExtra<T, Ex> {
92    fn is_terminated(&self) -> bool {
93        self.inner.is_terminated()
94    }
95}
96
97#[cfg(feature = "futures-core")]
98impl<T: Stream, Ex> Stream for WithExtra<T, Ex> {
99    type Item = T::Item;
100
101    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
102        self.project().inner.poll_next(cx)
103    }
104}
105
106#[cfg(feature = "futures-core")]
107impl<T: FusedStream, Ex> FusedStream for WithExtra<T, Ex> {
108    fn is_terminated(&self) -> bool {
109        self.inner.is_terminated()
110    }
111}
112
113#[cfg(feature = "futures-sink")]
114impl<Item, T: Sink<Item>, Ex> Sink<Item> for WithExtra<T, Ex> {
115    type Error = T::Error;
116
117    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
118        self.project().inner.poll_ready(cx)
119    }
120
121    fn start_send(self: Pin<&mut Self>, item: Item) -> Result<(), Self::Error> {
122        self.project().inner.start_send(item)
123    }
124
125    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
126        self.project().inner.poll_flush(cx)
127    }
128
129    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
130        self.project().inner.poll_close(cx)
131    }
132}
133
134#[cfg(feature = "route-sink")]
135impl<Route, Msg, T: FlushRoute<Route, Msg>, Ex> FlushRoute<Route, Msg> for WithExtra<T, Ex> {
136    fn poll_flush_route(
137        self: Pin<&mut Self>,
138        route: &Route,
139        cx: &mut Context<'_>,
140    ) -> Poll<Result<(), Self::Error>> {
141        self.project().inner.poll_flush_route(route, cx)
142    }
143
144    fn poll_close_route(
145        self: Pin<&mut Self>,
146        route: &Route,
147        cx: &mut Context<'_>,
148    ) -> Poll<Result<(), Self::Error>> {
149        self.project().inner.poll_close_route(route, cx)
150    }
151}
152
153#[cfg(feature = "route-sink")]
154impl<Route, Msg, T: ReadyRoute<Route, Msg>, Ex> ReadyRoute<Route, Msg> for WithExtra<T, Ex> {
155    fn poll_ready_route(
156        self: Pin<&mut Self>,
157        route: &Route,
158        cx: &mut Context<'_>,
159    ) -> Poll<Result<(), Self::Error>> {
160        self.project().inner.poll_ready_route(route, cx)
161    }
162}
163
164#[cfg(feature = "route-sink")]
165impl<Route, Msg, T: ReadySome<Route, Msg>, Ex> ReadySome<Route, Msg> for WithExtra<T, Ex> {
166    fn poll_ready_some(
167        self: Pin<&mut Self>,
168        cx: &mut Context<'_>,
169    ) -> Poll<Result<Route, Self::Error>> {
170        self.project().inner.poll_ready_some(cx)
171    }
172}