tcp_console/
builder.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use crate::console::{Console, Error};
use crate::ensure_newline;
use crate::subscription::{BoxedSubscription, Subscription};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;

/// A builder for [Console].
pub struct Builder<Services> {
    subscriptions: HashMap<Services, BoxedSubscription>,
    port: Option<u16>,
    welcome: Option<String>,
    accept_only_localhost: bool,
}

impl<Services> Builder<Services>
where
    Services: Eq + Hash + Debug,
{
    pub fn new() -> Self {
        Self {
            subscriptions: HashMap::new(),
            port: None,
            welcome: None,
            accept_only_localhost: false,
        }
    }

    pub fn subscribe<S>(mut self, service_id: Services, subscription: S) -> Result<Self, Error>
    where
        S: Subscription + Send + Sync + 'static,
    {
        // `HashMap::entry(x)` consumes its argument, while we might need this string afterwards.
        let service_id_string = format!("{service_id:?}");

        match self.subscriptions.entry(service_id) {
            Entry::Occupied(_) => Err(Error::ServiceIdUsed(service_id_string)),
            Entry::Vacant(entry) => {
                entry.insert(Box::new(subscription));
                Ok(self)
            }
        }
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }

    pub fn welcome(mut self, message: &str) -> Self {
        self.welcome = Some(message.to_owned());
        self
    }

    pub fn accept_only_localhost(mut self) -> Self {
        self.accept_only_localhost = true;
        self
    }

    pub fn build(self) -> Result<Console<Services>, Error> {
        let Some(port) = self.port else {
            return Err(Error::NoPort);
        };

        Ok(Console::new(
            self.subscriptions,
            port,
            ensure_newline(self.welcome.unwrap_or_default()),
            self.accept_only_localhost
        ))
    }
}

impl<Services> Default for Builder<Services>
where
    Services: Eq + Hash + Debug,
{
    fn default() -> Self {
        Self::new()
    }
}