smtp_server/
protocol.rs

1use std::pin::Pin;
2
3use futures::StreamExt;
4
5use smtp_server_types::Decision;
6
7#[derive(PartialEq, Eq, Clone, Copy, Debug)]
8pub enum ProtocolName {
9    Smtp,
10    Lmtp,
11}
12
13pub trait Protocol<'resp>: private::Sealed {
14    const PROTOCOL: ProtocolName;
15
16    // TODO: when we have GATs, 'resp should be a parameter of HandleMailReturnType
17    // and not of the whole Protocol trait.
18    type HandleMailReturnType;
19
20    // TODO: we might be able to remove the Box type here Rust gains GATs (generic
21    // associated types) and TAIT (type Alias = impl Trait) is implemented
22    fn handle_mail_return_type_as_stream(
23        _resp: Self::HandleMailReturnType,
24    ) -> Pin<Box<dyn futures::Stream<Item = Decision<()>> + Send + 'resp>>;
25}
26
27pub struct Smtp;
28impl<'resp> Protocol<'resp> for Smtp {
29    type HandleMailReturnType = Decision<()>;
30
31    const PROTOCOL: ProtocolName = ProtocolName::Smtp;
32
33    fn handle_mail_return_type_as_stream(
34        resp: Self::HandleMailReturnType,
35    ) -> Pin<Box<dyn futures::Stream<Item = Decision<()>> + Send + 'resp>> {
36        futures::stream::once(async move { resp }).boxed()
37    }
38}
39
40pub struct Lmtp;
41impl<'resp> Protocol<'resp> for Lmtp {
42    // TODO: same as above, GAT+TAIT might allow us to remove Box here
43    type HandleMailReturnType = Pin<Box<dyn futures::Stream<Item = Decision<()>> + Send + 'resp>>;
44
45    const PROTOCOL: ProtocolName = ProtocolName::Lmtp;
46
47    fn handle_mail_return_type_as_stream(
48        resp: Self::HandleMailReturnType,
49    ) -> Pin<Box<dyn futures::Stream<Item = Decision<()>> + Send + 'resp>> {
50        resp
51    }
52}
53
54mod private {
55    pub trait Sealed {}
56    impl Sealed for super::Smtp {}
57    impl Sealed for super::Lmtp {}
58}