samotop_core/
lib.rs

1//! The domain model of Samotop and core functionality. A base crate for samotop extensions.
2
3#[macro_use]
4extern crate log;
5
6pub mod io;
7pub mod mail;
8pub mod smtp;
9
10#[cfg(feature = "server")]
11pub mod server;
12
13pub mod common {
14    pub type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
15    pub type Result<T> = std::result::Result<T, Error>;
16    pub mod io {
17        pub use futures_io::{
18            AsyncBufRead as BufRead, AsyncRead as Read, AsyncSeek as Seek, AsyncWrite as Write,
19        };
20        pub use std::io::{Error, ErrorKind, Result};
21    }
22    //pub use async_std::io;
23    //pub use async_std::io::prelude::{ReadExt, WriteExt};
24    //pub use async_std::io::{Read, Write};
25    pub use futures_core::ready;
26    use std::any::TypeId;
27    pub use std::future::*;
28    pub type S3Fut<T> = Pin<Box<dyn Future<Output = T> + Sync + Send + 'static>>;
29    pub type S2Fut<'a, T> = Pin<Box<dyn Future<Output = T> + Sync + Send + 'a>>;
30    pub type S1Fut<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
31    pub use std::fmt;
32    pub use std::pin::Pin;
33    use std::sync::atomic::AtomicU32;
34    use std::sync::atomic::Ordering;
35    pub use std::sync::Arc;
36    pub use std::task::{Context, Poll};
37
38    #[derive(Debug, Copy, Clone)]
39    pub struct Dummy;
40
41    // pub async fn ready<T>(val: T) -> T {
42    //     val
43    // }
44
45    // replace with std once stable - use of unstable library feature 'future_poll_fn'
46    pub async fn poll_fn<F, T>(f: F) -> T
47    where
48        F: FnMut(&mut Context<'_>) -> Poll<T>,
49    {
50        let fut = PollFn { f };
51        fut.await
52    }
53
54    struct PollFn<F> {
55        f: F,
56    }
57
58    impl<F> Unpin for PollFn<F> {}
59
60    impl<T, F> Future for PollFn<F>
61    where
62        F: FnMut(&mut Context<'_>) -> Poll<T>,
63    {
64        type Output = T;
65
66        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
67            (&mut self.f)(cx)
68        }
69    }
70
71    /// In the absence of random number generator produces a time based identifier
72    /// It is not reliable nor secure, RNG/PRNG should be preffered.
73    #[deprecated(
74        since = "0.13.1",
75        note = "Use Identify::now() instead. This shall be removed in 0.14.0"
76    )]
77    pub fn time_based_id() -> String {
78        Identify::now().to_string()
79    }
80
81    pub struct Identify;
82    impl Identify {
83        pub fn instance() -> u32 {
84            static INSTANCE: AtomicU32 = AtomicU32::new(0);
85            // CHECKME: what about all these Ordering styles?
86            let mut value = INSTANCE.load(Ordering::Relaxed);
87            if value == 0 {
88                value = Self::now();
89                match INSTANCE.compare_exchange(0, value, Ordering::Relaxed, Ordering::Relaxed) {
90                    Ok(_) => value,
91                    Err(value) => value,
92                }
93            } else {
94                value
95            }
96        }
97        pub fn now() -> u32 {
98            // for the lack of better unique string without extra dependencies
99            Self::hash(
100                format!(
101                    "{}.{}.{:?}.{:?}",
102                    env!("CARGO_PKG_VERSION"),
103                    std::process::id(),
104                    std::time::Instant::now(),
105                    TypeId::of::<crate::smtp::SmtpSession>()
106                )
107                .as_str(),
108            )
109        }
110        const fn hash(s: &str) -> u32 {
111            let s = s.as_bytes();
112            let mut hash = 3581u32;
113            let mut i = 0usize;
114            while i < s.len() {
115                hash = hash.wrapping_mul(33).wrapping_add(s[i] as u32);
116                i += 1;
117            }
118            hash
119        }
120    }
121}
122
123#[test]
124fn identify_instance_is_not_zero() {
125    assert_ne!(common::Identify::instance(), 0)
126}
127#[test]
128fn identify_instance_stays_constant() {
129    assert_eq!(common::Identify::instance(), common::Identify::instance())
130}
131#[test]
132fn identify_now_is_not_zero() {
133    assert_ne!(common::Identify::now(), 0)
134}
135#[test]
136fn identify_now_is_unique() {
137    assert_ne!(common::Identify::now(), common::Identify::now())
138}