Skip to main content

s2n_tls/connection/
builder.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    config::Config,
6    connection::Connection,
7    enums::Mode,
8    error::Error,
9    pool::{Pool, PooledConnection},
10};
11
12/// A trait indicating that a structure can produce connections.
13pub trait Builder: Clone {
14    type Output: AsMut<Connection> + AsRef<Connection>;
15    fn build_connection(&self, mode: Mode) -> Result<Self::Output, Error>;
16}
17
18/// Produces new connections with the given Config set.
19impl Builder for Config {
20    type Output = Connection;
21    fn build_connection(&self, mode: Mode) -> Result<Self::Output, Error> {
22        let mut conn = Connection::new(mode);
23        conn.set_config(self.clone())?;
24        Ok(conn)
25    }
26}
27
28/// Produces new connections from a pool of reuseable connections.
29impl<T: Pool + Clone> Builder for T {
30    type Output = PooledConnection<T>;
31    fn build_connection(&self, mode: Mode) -> Result<Self::Output, Error> {
32        if mode == self.mode() {
33            Ok(PooledConnection::new(self)?)
34        } else {
35            Err(Error::INVALID_INPUT)
36        }
37    }
38}
39
40/// Produces new connections from a builder, then modifies them.
41///
42/// Can be used to apply connection-level config, for example
43/// when using a [`crate::pool::ConfigPool`].
44#[derive(Clone)]
45pub struct ModifiedBuilder<F, B: Builder>
46where
47    F: Fn(&mut Connection) -> Result<&mut Connection, Error> + Clone,
48{
49    builder: B,
50    modifier: F,
51}
52
53impl<F, B: Builder> ModifiedBuilder<F, B>
54where
55    F: Fn(&mut Connection) -> Result<&mut Connection, Error> + Clone,
56{
57    pub fn new(builder: B, modifier: F) -> Self {
58        Self { builder, modifier }
59    }
60}
61
62impl<F, B: Builder> Builder for ModifiedBuilder<F, B>
63where
64    F: Fn(&mut Connection) -> Result<&mut Connection, Error> + Clone,
65{
66    type Output = B::Output;
67    fn build_connection(&self, mode: Mode) -> Result<Self::Output, Error> {
68        let mut conn = self.builder.build_connection(mode)?;
69        (self.modifier)(conn.as_mut())?;
70        Ok(conn)
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use crate::pool::ConfigPoolBuilder;
78
79    #[test]
80    fn config_builder() -> Result<(), Box<dyn std::error::Error>> {
81        let config = Config::default();
82        let conn = config.build_connection(Mode::Server)?;
83        assert_eq!(conn.config(), Some(config));
84        Ok(())
85    }
86
87    #[test]
88    fn pool_builder() -> Result<(), Box<dyn std::error::Error>> {
89        let config = Config::default();
90        let pool = ConfigPoolBuilder::new(Mode::Server, config.clone()).build();
91        let conn = pool.build_connection(Mode::Server)?;
92        assert_eq!(conn.as_ref().config(), Some(config));
93        Ok(())
94    }
95
96    #[test]
97    fn modified_builder() -> Result<(), Box<dyn std::error::Error>> {
98        let config_a = Config::default();
99        let config_b = Config::default();
100        assert!(config_a != config_b);
101
102        let builder =
103            ModifiedBuilder::new(config_a.clone(), |conn| conn.set_config(config_b.clone()));
104
105        let conn = builder.build_connection(Mode::Server)?;
106        assert!(conn.config() != Some(config_a));
107        assert_eq!(conn.config(), Some(config_b));
108        Ok(())
109    }
110}