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}