Skip to main content

nexus_net/
maybe_tls.rs

1//! Stream that may or may not be wrapped in TLS (sync only).
2//!
3//! Implements `Read + Write` by delegating to either the plain
4//! stream or the `TlsStream` wrapper (requires `tls` feature).
5//!
6//! Protocol clients use `MaybeTls<S>` as their stream type when the
7//! TLS decision happens at runtime (`ws://` vs `wss://`). For async
8//! TLS, see `nexus-async-web::maybe_tls`.
9
10use std::io::{self, Read, Write};
11
12#[cfg(feature = "tls")]
13use crate::tls::TlsStream;
14
15/// A stream that may or may not be wrapped in TLS.
16///
17/// The `Tls` variant is boxed because `TlsStream` includes rustls's
18/// ~1KB connection state. TLS connections are established once at
19/// startup — the box indirection is not on the hot path.
20pub enum MaybeTls<S> {
21    /// Plaintext stream.
22    Plain(S),
23    /// TLS-wrapped stream.
24    #[cfg(feature = "tls")]
25    Tls(Box<TlsStream<S>>),
26}
27
28impl<S> MaybeTls<S> {
29    /// Whether this is a TLS-wrapped stream.
30    pub fn is_tls(&self) -> bool {
31        #[cfg(feature = "tls")]
32        if matches!(self, Self::Tls(_)) {
33            return true;
34        }
35        false
36    }
37}
38
39// =============================================================================
40// Read + Write (blocking)
41// =============================================================================
42
43impl<S: Read + Write> Read for MaybeTls<S> {
44    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
45        match self {
46            Self::Plain(s) => s.read(buf),
47            #[cfg(feature = "tls")]
48            Self::Tls(s) => s.read(buf),
49        }
50    }
51}
52
53impl<S: Read + Write> Write for MaybeTls<S> {
54    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
55        match self {
56            Self::Plain(s) => s.write(buf),
57            #[cfg(feature = "tls")]
58            Self::Tls(s) => s.write(buf),
59        }
60    }
61
62    fn flush(&mut self) -> io::Result<()> {
63        match self {
64            Self::Plain(s) => s.flush(),
65            #[cfg(feature = "tls")]
66            Self::Tls(s) => s.flush(),
67        }
68    }
69}