Skip to main content

trillium/
conn.rs

1use crate::{
2    Body, HeaderName, HeaderValues, Headers, Method, Status, Swansong, Transport, TypeSet, Version,
3    request_body::RequestBody, type_set::Entry,
4};
5use std::{
6    any::Any,
7    fmt::{self, Debug, Formatter},
8    future::Future,
9    net::IpAddr,
10    time::Instant,
11};
12
13/// # A Trillium HTTP connection.
14///
15/// A Conn represents both the request and response of a http connection,
16/// as well as any application state that is associated with that
17/// connection.
18///
19/// ## `with_{attribute}` naming convention
20///
21/// A convention that is used throughout trillium is that any interface
22/// that is named `with_{attribute}` will take ownership of the conn, set
23/// the attribute and return the conn, enabling chained calls like:
24///
25/// ```
26/// use trillium_testing::TestServer;
27///
28/// struct MyState(&'static str);
29/// async fn handler(mut conn: trillium::Conn) -> trillium::Conn {
30///     conn.with_response_header("content-type", "text/plain")
31///         .with_state(MyState("hello"))
32///         .with_body("hey there")
33///         .with_status(418)
34/// }
35///
36/// # trillium_testing::block_on(async {
37/// let app = TestServer::new(handler).await;
38/// app.get("/")
39///     .await
40///     .assert_status(418)
41///     .assert_body("hey there")
42///     .assert_header("content-type", "text/plain");
43/// # });
44/// ```
45///
46/// If you need to set a property on the conn without moving it,
47/// `set_{attribute}` associated functions will be your huckleberry, as is
48/// conventional in other rust projects.
49///
50/// ## State
51///
52/// Every trillium Conn contains a state type which is a set that contains at most one element for
53/// each type. State is the primary way that handlers attach data to a conn as it passes through a
54/// tuple handler. State access should generally be implemented by libraries using a private type
55/// and exposed with a `ConnExt` trait. See [library
56/// patterns](https://trillium.rs/library_patterns.html#state) for more elaboration and examples.
57///
58/// ## In relation to [`trillium_http::Conn`]
59///
60/// `trillium::Conn` is currently implemented as an abstraction on top of a
61/// [`trillium_http::Conn`]. In particular, `trillium::Conn` boxes the transport so that application
62/// code can be written without transport generics. See
63/// [`Transport`] for further reading on this.
64pub struct Conn {
65    pub(crate) inner: trillium_http::Conn<Box<dyn Transport>>,
66    halted: bool,
67    path: Vec<String>,
68}
69
70impl Debug for Conn {
71    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
72        f.debug_struct("Conn")
73            .field("inner", &self.inner)
74            .field("halted", &self.halted)
75            .field("path", &self.path)
76            .finish()
77    }
78}
79
80impl<T: Transport + 'static> From<trillium_http::Conn<T>> for Conn {
81    fn from(inner: trillium_http::Conn<T>) -> Self {
82        Self {
83            inner: inner.map_transport(|t| Box::new(t) as Box<dyn Transport>),
84            halted: false,
85            path: vec![],
86        }
87    }
88}
89
90impl Conn {
91    /// `Conn::ok` is a convenience function for the common pattern of
92    /// setting a body and a 200 status in one call. It is exactly
93    /// identical to `conn.with_status(200).with_body(body).halt()`
94    ///
95    /// See [`Body::new_streaming`] and [`Body::new_with_trailers`] to construct a body from an
96    /// [`AsyncRead`](futures_lite::AsyncRead) or [`BodySource`](crate::BodySource)
97    ///
98    /// ```
99    /// use trillium::Conn;
100    /// use trillium_testing::TestServer;
101    ///
102    /// # trillium_testing::block_on(async {
103    /// let handler = |conn: Conn| async move { conn.ok("hello") };
104    /// let app = TestServer::new(handler).await;
105    /// app.get("/").await.assert_ok().assert_body("hello");
106    /// # });
107    /// ```
108    #[must_use]
109    pub fn ok(self, body: impl Into<Body>) -> Self {
110        self.with_status(200).with_body(body).halt()
111    }
112
113    /// returns the response status for this `Conn`, if it has been set.
114    /// ```
115    /// use trillium::Conn;
116    /// use trillium_testing::TestServer;
117    ///
118    /// # trillium_testing::block_on(async {
119    /// let handler = |mut conn: Conn| async move {
120    ///     assert!(conn.status().is_none());
121    ///     conn.set_status(200);
122    ///     assert_eq!(conn.status().unwrap(), trillium_http::Status::Ok);
123    ///     conn.ok("pass")
124    /// };
125    /// let app = TestServer::new(handler).await;
126    /// app.get("/").await.assert_ok();
127    /// # });
128    /// ```
129    pub fn status(&self) -> Option<Status> {
130        self.inner.status()
131    }
132
133    /// assigns a status to this response. see [`Conn::status`] for example usage
134    pub fn set_status(&mut self, status: impl TryInto<Status>) -> &mut Self {
135        self.inner.set_status(status);
136        self
137    }
138
139    /// sets the response status for this `Conn` and returns it. note that
140    /// this does not set the halted status.
141    ///
142    /// ```
143    /// use trillium::Conn;
144    /// use trillium_testing::TestServer;
145    ///
146    /// # trillium_testing::block_on(async {
147    /// let handler = |conn: Conn| async move { conn.with_status(418) };
148    /// let app = TestServer::new(handler).await;
149    /// app.get("/").await.assert_status(418);
150    /// # });
151    /// ```
152    #[must_use]
153    pub fn with_status(mut self, status: impl TryInto<Status>) -> Self {
154        self.set_status(status);
155        self
156    }
157
158    /// Sets the response body from any `impl Into<Body>` and returns the
159    /// `Conn` for fluent chaining. Note that this does not set the response
160    /// status or halted. See [`Conn::ok`] for a function that does both
161    /// of those.
162    ///
163    /// See [`Body::new_streaming`] and [`Body::new_with_trailers`] to construct a body from an
164    /// [`AsyncRead`](futures_lite::AsyncRead) or [`BodySource`](crate::BodySource)
165    ///
166    /// ```
167    /// use trillium::Conn;
168    /// use trillium_testing::TestServer;
169    ///
170    /// # trillium_testing::block_on(async {
171    /// let handler = |conn: Conn| async move { conn.with_body("hello") };
172    /// let app = TestServer::new(handler).await;
173    /// app.get("/").await.assert_body_contains("hello");
174    /// # });
175    /// ```
176    #[must_use]
177    pub fn with_body(mut self, body: impl Into<Body>) -> Self {
178        self.set_body(body);
179        self
180    }
181
182    /// Sets the response body from any `impl Into<Body>`. Note that this does not set the response
183    /// status or halted.
184    ///
185    /// See [`Body::new_streaming`] and [`Body::new_with_trailers`] to construct a body from an
186    /// [`AsyncRead`](futures_lite::AsyncRead) or [`BodySource`](crate::BodySource)
187    ///
188    /// ```
189    /// use trillium::Conn;
190    /// use trillium_testing::TestServer;
191    ///
192    /// # trillium_testing::block_on(async {
193    /// let handler = |mut conn: Conn| async move {
194    ///     conn.set_body("hello");
195    ///     assert_eq!(conn.response_len(), Some(5));
196    ///     conn.ok("pass")
197    /// };
198    /// let app = TestServer::new(handler).await;
199    /// app.get("/").await.assert_ok();
200    /// # });
201    /// ```
202    pub fn set_body(&mut self, body: impl Into<Body>) -> &mut Self {
203        self.inner.set_response_body(body);
204        self
205    }
206
207    /// Removes the response body from the `Conn`
208    ///
209    /// ```
210    /// use trillium::Conn;
211    /// use trillium_testing::TestServer;
212    ///
213    /// # trillium_testing::block_on(async {
214    /// let handler = |mut conn: Conn| async move {
215    ///     conn.set_body("hello");
216    ///     let body = conn.take_response_body().unwrap();
217    ///     assert_eq!(body.len(), Some(5));
218    ///     assert_eq!(conn.response_len(), None);
219    ///     conn.ok("pass")
220    /// };
221    /// let app = TestServer::new(handler).await;
222    /// app.get("/").await.assert_ok();
223    /// # });
224    /// ```
225    pub fn take_response_body(&mut self) -> Option<Body> {
226        self.inner.take_response_body()
227    }
228
229    /// Borrows the response body from the `Conn`
230    ///
231    /// ```
232    /// use trillium::Conn;
233    /// use trillium_testing::TestServer;
234    ///
235    /// # trillium_testing::block_on(async {
236    /// let handler = |mut conn: Conn| async move {
237    ///     conn.set_body("hello");
238    ///     let body = conn.response_body().unwrap();
239    ///     assert_eq!(body.len(), Some(5));
240    ///     assert!(body.is_static());
241    ///     assert_eq!(body.static_bytes(), Some(&b"hello"[..]));
242    ///     conn.ok("pass")
243    /// };
244    /// let app = TestServer::new(handler).await;
245    /// app.get("/").await.assert_ok();
246    /// # });
247    /// ```
248    pub fn response_body(&self) -> Option<&Body> {
249        self.inner.response_body()
250    }
251
252    /// Attempts to retrieve a &T from the state set
253    ///
254    /// ```
255    /// use trillium::Conn;
256    /// use trillium_testing::TestServer;
257    ///
258    /// struct Hello;
259    /// # trillium_testing::block_on(async {
260    /// let handler = |mut conn: Conn| async move {
261    ///     assert!(conn.state::<Hello>().is_none());
262    ///     conn.insert_state(Hello);
263    ///     assert!(conn.state::<Hello>().is_some());
264    ///     conn.ok("pass")
265    /// };
266    /// let app = TestServer::new(handler).await;
267    /// app.get("/").await.assert_ok();
268    /// # });
269    /// ```
270    pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
271        self.inner.state().get()
272    }
273
274    /// Attempts to retrieve a &mut T from the state set
275    pub fn state_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
276        self.inner.state_mut().get_mut()
277    }
278
279    /// Inserts a new type into the state set. See [`Conn::state`]
280    /// for an example.
281    ///
282    /// Returns the previously-set instance of this type, if
283    /// any
284    pub fn insert_state<T: Send + Sync + 'static>(&mut self, state: T) -> Option<T> {
285        self.inner.state_mut().insert(state)
286    }
287
288    /// Puts a new type into the state set and returns the
289    /// `Conn`. this is useful for fluent chaining
290    #[must_use]
291    pub fn with_state<T: Send + Sync + 'static>(mut self, state: T) -> Self {
292        self.insert_state(state);
293        self
294    }
295
296    /// Removes a type from the state set and returns it, if present
297    pub fn take_state<T: Send + Sync + 'static>(&mut self) -> Option<T> {
298        self.inner.state_mut().take()
299    }
300
301    /// Returns an [`Entry`] for the state typeset that can be used with functions like
302    /// [`Entry::or_insert`], [`Entry::or_insert_with`], [`Entry::and_modify`], and others.
303    pub fn state_entry<T: Send + Sync + 'static>(&mut self) -> Entry<'_, T> {
304        self.inner.state_mut().entry()
305    }
306
307    /// Attempts to borrow a T from the immutable shared state set
308    pub fn shared_state<T: Send + Sync + 'static>(&self) -> Option<&T> {
309        self.inner.shared_state().get()
310    }
311
312    /// Returns a [`RequestBody`] that references this `Conn`. The `Conn`
313    /// retains all data and holds the singular transport, but the
314    /// [`RequestBody`] provides an interface to read body content.
315    ///
316    /// If the request included an `Expect: 100-continue` header, the 100 Continue response is sent
317    /// lazily on the first read from the returned [`RequestBody`].
318    ///
319    /// See also: [`Conn::request_body_string`] for a convenience function
320    /// when the content is expected to be utf8.
321    ///
322    /// # Examples
323    ///
324    /// ```
325    /// use trillium::Conn;
326    /// use trillium_testing::TestServer;
327    ///
328    /// # trillium_testing::block_on(async {
329    /// let handler = |mut conn: Conn| async move {
330    ///     let request_body = conn.request_body();
331    ///     assert_eq!(request_body.content_length(), Some(12));
332    ///     assert_eq!(request_body.read_string().await.unwrap(), "request body");
333    ///     conn.ok("pass")
334    /// };
335    /// let app = TestServer::new(handler).await;
336    /// app.post("/").with_body("request body").await.assert_ok();
337    /// # });
338    /// ```
339    pub fn request_body(&mut self) -> RequestBody<'_> {
340        self.inner.request_body().into()
341    }
342
343    /// Convenience function to read the content of a request body as a `String`.
344    ///
345    /// # Errors
346    ///
347    /// This will return an error variant if either there is an IO failure
348    /// on the underlying transport or if the body content is not a utf8
349    /// string.
350    ///
351    /// # Examples
352    ///
353    /// ```
354    /// use trillium::Conn;
355    /// use trillium_testing::TestServer;
356    ///
357    /// # trillium_testing::block_on(async {
358    /// let handler = |mut conn: Conn| async move {
359    ///     assert_eq!(conn.request_body_string().await.unwrap(), "request body");
360    ///     conn.ok("pass")
361    /// };
362    /// let app = TestServer::new(handler).await;
363    /// app.post("/").with_body("request body").await.assert_ok();
364    /// # });
365    /// ```
366    #[allow(clippy::missing_errors_doc)] // this is a false positive
367    pub async fn request_body_string(&mut self) -> trillium_http::Result<String> {
368        self.request_body().read_string().await
369    }
370
371    /// if there is a response body for this conn and it has a known
372    /// fixed length, it is returned from this function
373    ///
374    /// ```
375    /// use trillium::Conn;
376    /// use trillium_testing::TestServer;
377    ///
378    /// # trillium_testing::block_on(async {
379    /// let handler = |mut conn: Conn| async move {
380    ///     assert_eq!(conn.response_len(), None); // no body set yet
381    ///     conn.set_body("hello");
382    ///     assert_eq!(conn.response_len(), Some(5));
383    ///     conn.ok("pass")
384    /// };
385    /// let app = TestServer::new(handler).await;
386    /// app.get("/").await.assert_ok();
387    /// # });
388    /// ```
389    pub fn response_len(&self) -> Option<u64> {
390        self.inner.response_body().and_then(Body::len)
391    }
392
393    /// returns the request method for this conn.
394    /// ```
395    /// use trillium::Conn;
396    /// use trillium_http::Method;
397    /// use trillium_testing::TestServer;
398    ///
399    /// # trillium_testing::block_on(async {
400    /// let handler = |conn: Conn| async move {
401    ///     assert_eq!(conn.method(), Method::Get);
402    ///     conn.ok("pass")
403    /// };
404    /// let app = TestServer::new(handler).await;
405    /// app.get("/").await.assert_ok();
406    /// # });
407    /// ```
408    pub fn method(&self) -> Method {
409        self.inner.method()
410    }
411
412    /// Borrow the response headers
413    pub fn response_headers(&self) -> &Headers {
414        self.inner.response_headers()
415    }
416
417    /// Mutably borrow the response headers
418    pub fn response_headers_mut(&mut self) -> &mut Headers {
419        self.inner.response_headers_mut()
420    }
421
422    /// Borrow the request headers
423    pub fn request_headers(&self) -> &Headers {
424        self.inner.request_headers()
425    }
426
427    /// Mutably borrow request headers
428    pub fn request_headers_mut(&mut self) -> &mut Headers {
429        self.inner.request_headers_mut()
430    }
431
432    /// Borrow the request trailers, if any
433    ///
434    /// Trailers are only populated after reading a request body that includes trailers to
435    /// completion.
436    pub fn request_trailers(&self) -> Option<&Headers> {
437        self.inner.request_trailers()
438    }
439
440    /// Insert a header name and value/values into the response headers and return the conn.
441    ///
442    /// See also [`Headers::insert`] and [`Headers::append`]
443    ///
444    /// For a slight performance improvement, use a [`KnownHeaderName`](crate::KnownHeaderName) as
445    /// the first argument instead of a str.
446    #[must_use]
447    pub fn with_response_header(
448        mut self,
449        header_name: impl Into<HeaderName<'static>>,
450        header_value: impl Into<HeaderValues>,
451    ) -> Self {
452        self.insert_response_header(header_name, header_value);
453        self
454    }
455
456    /// Insert a header name and value/values into the response headers.
457    ///
458    /// See also [`Headers::insert`] and [`Headers::append`]
459    ///
460    /// For a slight performance improvement, use a [`KnownHeaderName`](crate::KnownHeaderName).
461    pub fn insert_response_header(
462        &mut self,
463        header_name: impl Into<HeaderName<'static>>,
464        header_value: impl Into<HeaderValues>,
465    ) {
466        self.response_headers_mut()
467            .insert(header_name, header_value);
468    }
469
470    /// returns the path for this request. note that this may not
471    /// represent the entire http request path if running nested
472    /// routers.
473    pub fn path(&self) -> &str {
474        self.path.last().map_or_else(|| self.inner.path(), |p| &**p)
475    }
476
477    /// returns query part of the request path
478    ///
479    /// ```
480    /// use trillium::Conn;
481    /// use trillium_testing::TestServer;
482    ///
483    /// # trillium_testing::block_on(async {
484    /// let handler = |conn: Conn| async move {
485    ///     let querystring = conn.querystring();
486    ///     if querystring == "c&d=e" {
487    ///         conn.ok("has query")
488    ///     } else {
489    ///         conn.ok("no query")
490    ///     }
491    /// };
492    /// let app = TestServer::new(handler).await;
493    /// app.get("/a/b?c&d=e").await.assert_body("has query");
494    /// app.get("/a/b").await.assert_body("no query");
495    /// # });
496    /// ```
497    ///
498    ///
499    /// # Parsing
500    ///
501    /// Trillium does not include a querystring parsing library, as there is no universal standard
502    /// for querystring encodings of arrays, but several library options exist, inluding:
503    ///
504    /// [`QueryStrong`](https://docs.rs/querystrong/) (by the author of trillium)
505    /// [`serde_qs`](https://docs.rs/serde_qs/)
506    /// [`querystring`](https://docs.rs/querystring/)
507    /// [`serde_querystring`](https://docs.rs/serde-querystring/latest/serde_querystring/)
508    pub fn querystring(&self) -> &str {
509        self.inner.querystring()
510    }
511
512    /// sets the `halted` attribute of this conn, preventing later
513    /// processing in a given tuple handler. returns
514    /// the conn for fluent chaining
515    ///
516    /// ```
517    /// use trillium::Conn;
518    /// use trillium_testing::TestServer;
519    ///
520    /// # trillium_testing::block_on(async {
521    /// let handler = |conn: Conn| async move { conn.halt() };
522    /// let app = TestServer::new(handler).await;
523    /// app.get("/").await.assert_status(404);
524    /// # });
525    /// ```
526    #[must_use]
527    pub const fn halt(mut self) -> Self {
528        self.set_halted(true);
529        self
530    }
531
532    /// sets the `halted` attribute of this conn. see [`Conn::halt`].
533    ///
534    /// ```
535    /// use trillium::Conn;
536    /// use trillium_testing::TestServer;
537    ///
538    /// # trillium_testing::block_on(async {
539    /// let handler = |mut conn: Conn| async move {
540    ///     assert!(!conn.is_halted());
541    ///     conn.set_halted(true);
542    ///     assert!(conn.is_halted());
543    ///     conn.ok("pass")
544    /// };
545    /// let app = TestServer::new(handler).await;
546    /// app.get("/").await.assert_ok();
547    /// # });
548    /// ```
549    pub const fn set_halted(&mut self, halted: bool) -> &mut Self {
550        self.halted = halted;
551        self
552    }
553
554    /// retrieves the halted state of this conn.  see [`Conn::halt`].
555    pub const fn is_halted(&self) -> bool {
556        self.halted
557    }
558
559    /// predicate function to indicate whether the connection is
560    /// secure. note that this does not necessarily indicate that the
561    /// transport itself is secure, as it may indicate that
562    /// `trillium_http` is behind a trusted reverse proxy that has
563    /// terminated tls and provided appropriate headers to indicate
564    /// this.
565    pub fn is_secure(&self) -> bool {
566        self.inner.is_secure()
567    }
568
569    /// The [`Instant`] that the first header bytes for this conn were
570    /// received, before any processing or parsing has been performed.
571    pub fn start_time(&self) -> Instant {
572        self.inner.start_time()
573    }
574
575    /// transforms this `trillium::Conn` into a `trillium_http::Conn`
576    /// with the specified transport type. Please note that this will
577    /// panic if you attempt to downcast from trillium's boxed
578    /// transport into the wrong transport type. Also note that this
579    /// is a lossy conversion, dropping the halted state and any
580    /// nested router path data.
581    ///
582    /// # Panics
583    ///
584    /// This will panic if you attempt to downcast to the wrong Transport type.
585    pub fn into_inner<T: Transport>(self) -> trillium_http::Conn<T> {
586        self.inner.map_transport(|t| {
587            *(t as Box<dyn Any>)
588                .downcast()
589                .expect("attempted to downcast to the wrong transport type")
590        })
591    }
592
593    /// retrieves the remote ip address for this conn, if available.
594    pub fn peer_ip(&self) -> Option<IpAddr> {
595        self.inner.peer_ip()
596    }
597
598    /// sets the remote ip address for this conn.
599    pub fn set_peer_ip(&mut self, peer_ip: Option<IpAddr>) -> &mut Self {
600        self.inner.set_peer_ip(peer_ip);
601        self
602    }
603
604    /// for router implementations. pushes a route segment onto the path
605    pub fn push_path(&mut self, path: String) {
606        self.path.push(path);
607    }
608
609    /// for router implementations. removes a route segment onto the path
610    pub fn pop_path(&mut self) {
611        self.path.pop();
612    }
613
614    /// Cancels and drops the future if reading from the transport results in an error or empty read
615    ///
616    /// If the client disconnects from the conn's transport, this function will return None. If the
617    /// future completes without disconnection, this future will return Some containing the output
618    /// of the future.
619    ///
620    /// The use of this method is not advised if your connected http client employs pipelining
621    /// (rarely seen in the wild), as it will buffer an unbounded number of requests
622    ///
623    /// Note that the inner future cannot borrow conn, so you will need to clone or take any
624    /// information needed to execute the future prior to executing this method.
625    ///
626    /// # Example
627    ///
628    /// ```rust
629    /// # use trillium::{Conn, Method};
630    /// async fn something_slow_and_cancel_safe() -> String {
631    ///     String::from("this was not actually slow")
632    /// }
633    /// async fn handler(mut conn: Conn) -> Conn {
634    ///     match conn
635    ///         .cancel_on_disconnect(async { something_slow_and_cancel_safe().await })
636    ///         .await
637    ///     {
638    ///         Some(returned_body) => conn.ok(returned_body),
639    ///         None => conn,
640    ///     }
641    /// }
642    /// ```
643    pub async fn cancel_on_disconnect<'a, Fut>(&'a mut self, fut: Fut) -> Option<Fut::Output>
644    where
645        Fut: Future + Send + 'a,
646    {
647        self.inner.cancel_on_disconnect(fut).await
648    }
649
650    /// Check if the transport is connected by testing attempting to read from the transport
651    ///
652    /// # Example
653    ///
654    /// This is best to use at appropriate points in a long-running handler, like:
655    ///
656    /// ```rust
657    /// # use trillium::{Conn, Method};
658    /// # async fn something_slow_but_not_cancel_safe() {}
659    /// async fn handler(mut conn: Conn) -> Conn {
660    ///     for _ in 0..100 {
661    ///         if conn.is_disconnected().await {
662    ///             return conn;
663    ///         }
664    ///         something_slow_but_not_cancel_safe().await;
665    ///     }
666    ///     conn.ok("ok!")
667    /// }
668    /// ```
669    pub async fn is_disconnected(&mut self) -> bool {
670        self.inner.is_disconnected().await
671    }
672
673    /// Returns the http version over which this Conn is being communicated
674    pub fn http_version(&self) -> Version {
675        self.inner.http_version()
676    }
677
678    /// get the host for this conn, if it exists
679    pub fn host(&self) -> Option<&str> {
680        self.inner.host()
681    }
682
683    /// retrieves the combined path and any query
684    pub fn path_and_query(&self) -> &str {
685        self.inner.path_and_query()
686    }
687
688    /// retrieves a [`Swansong`] graceful shutdown controller
689    pub fn swansong(&self) -> Swansong {
690        self.inner.swansong()
691    }
692}
693
694impl AsMut<trillium_http::Conn<Box<dyn Transport>>> for Conn {
695    fn as_mut(&mut self) -> &mut trillium_http::Conn<Box<dyn Transport>> {
696        &mut self.inner
697    }
698}
699
700impl AsRef<trillium_http::Conn<Box<dyn Transport>>> for Conn {
701    fn as_ref(&self) -> &trillium_http::Conn<Box<dyn Transport>> {
702        &self.inner
703    }
704}
705
706impl AsMut<TypeSet> for Conn {
707    fn as_mut(&mut self) -> &mut TypeSet {
708        self.inner.state_mut()
709    }
710}
711
712impl AsRef<TypeSet> for Conn {
713    fn as_ref(&self) -> &TypeSet {
714        self.inner.state()
715    }
716}