1use std::{any::Any, any::TypeId, fmt, io, ops, task::Context, task::Poll};
2
3use crate::filter::{Filter, FilterReadStatus};
4use crate::{FilterCtx, Io, Readiness};
5
6pub struct Sealed(pub(crate) Box<dyn Filter>);
8
9impl fmt::Debug for Sealed {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 f.debug_struct("Sealed").finish()
12 }
13}
14
15impl Filter for Sealed {
16 #[inline]
17 fn query(&self, id: TypeId) -> Option<Box<dyn Any>> {
18 self.0.query(id)
19 }
20
21 #[inline]
22 fn process_read_buf(
23 &self,
24 ctx: FilterCtx<'_>,
25 nbytes: usize,
26 ) -> io::Result<FilterReadStatus> {
27 self.0.process_read_buf(ctx, nbytes)
28 }
29
30 #[inline]
31 fn process_write_buf(&self, ctx: FilterCtx<'_>) -> io::Result<()> {
32 self.0.process_write_buf(ctx)
33 }
34
35 #[inline]
36 fn shutdown(&self, ctx: FilterCtx<'_>) -> io::Result<Poll<()>> {
37 self.0.shutdown(ctx)
38 }
39
40 #[inline]
41 fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Readiness> {
42 self.0.poll_read_ready(cx)
43 }
44
45 #[inline]
46 fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<Readiness> {
47 self.0.poll_write_ready(cx)
48 }
49}
50
51#[derive(Debug)]
52pub struct IoBoxed(Io<Sealed>);
54
55impl IoBoxed {
56 #[inline]
57 #[must_use]
58 pub fn take(&mut self) -> Self {
62 IoBoxed(self.0.take())
63 }
64}
65
66impl<F: Filter> From<Io<F>> for IoBoxed {
67 fn from(io: Io<F>) -> Self {
68 Self(io.seal())
69 }
70}
71
72impl ops::Deref for IoBoxed {
73 type Target = Io<Sealed>;
74
75 #[inline]
76 fn deref(&self) -> &Self::Target {
77 &self.0
78 }
79}
80
81impl From<IoBoxed> for Io<Sealed> {
82 fn from(value: IoBoxed) -> Self {
83 value.0
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use ntex_bytes::Bytes;
90 use ntex_codec::BytesCodec;
91 use ntex_service::{ServiceFactory, cfg::SharedCfg, fn_service};
92
93 use super::*;
94 use crate::{testing::IoTest, utils::seal};
95
96 #[ntex::test]
97 async fn test_seal() {
98 let (client, server) = IoTest::create();
99 client.remote_buffer_cap(1024);
100 client.write("REQ");
101
102 let svc = seal(fn_service(|io: IoBoxed| async move {
103 let t = io.recv(&BytesCodec).await.unwrap().unwrap();
104 assert_eq!(t, b"REQ".as_ref());
105 io.send(Bytes::from_static(b"RES"), &BytesCodec)
106 .await
107 .unwrap();
108 Ok::<_, ()>(())
109 }))
110 .pipeline(())
111 .await
112 .unwrap();
113
114 let srv: Io<Sealed> = Io::new(server, SharedCfg::default()).boxed().into();
115 let _ = svc.call(srv).await;
116
117 let buf = client.read().await.unwrap();
118 assert_eq!(buf, b"RES".as_ref());
119 }
120}