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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::{
    borrow::Cow,
    fmt::{self, Display, Formatter},
    result, time,
};

use bytes::Bytes;

use crate::error::{Error, Result};

use super::DataType;

#[derive(Eq, PartialEq, PartialOrd, Ord, Debug, Hash, Clone)]
/// Represents a Pop3 number data type.
///
/// Get its real value by calling `value()` from the [DataType] trait
pub struct Number {
    inner: Bytes,
}

impl TryInto<usize> for Number {
    type Error = Error;

    fn try_into(self) -> result::Result<usize, Self::Error> {
        self.value()
    }
}

impl From<&[u8]> for Number {
    fn from(value: &[u8]) -> Self {
        Self {
            inner: Bytes::copy_from_slice(value),
        }
    }
}

impl AsRef<[u8]> for Number {
    fn as_ref(&self) -> &[u8] {
        &self.inner
    }
}

impl From<Bytes> for Number {
    fn from(value: Bytes) -> Self {
        Self { inner: value }
    }
}

impl Display for Number {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let number = self.as_str_lossy();

        write!(f, "{}", number)
    }
}

impl DataType<usize> for Number {
    fn raw(&self) -> &[u8] {
        &self.inner
    }

    fn as_str_lossy(&self) -> Cow<'_, str> {
        String::from_utf8_lossy(&self.inner)
    }

    fn as_str(&self) -> Result<&str> {
        Ok(std::str::from_utf8(&self.inner)?)
    }

    fn value(&self) -> Result<usize> {
        let string = self.as_str()?;

        let number: usize = string.parse()?;

        Ok(number)
    }
}

#[derive(Eq, PartialEq, PartialOrd, Ord, Debug, Hash, Clone)]
/// Represents a Pop3 duration data type.
///
/// Get its real value by calling `value()` from the [DataType] trait
pub struct Duration {
    inner: Number,
    to_secs_multiplier: u64,
}

impl Duration {
    pub fn new<N: Into<Number>>(number: N, to_secs_multiplier: u64) -> Self {
        Self {
            inner: number.into(),
            to_secs_multiplier,
        }
    }
}

impl Display for Duration {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let number = self.as_str_lossy();

        write!(f, "{}", number)
    }
}

impl TryInto<time::Duration> for Duration {
    type Error = Error;

    fn try_into(self) -> result::Result<time::Duration, Self::Error> {
        self.value()
    }
}

impl DataType<time::Duration> for Duration {
    fn raw(&self) -> &[u8] {
        self.inner.raw()
    }

    fn as_str_lossy(&self) -> Cow<'_, str> {
        self.inner.as_str_lossy()
    }

    fn as_str(&self) -> Result<&str> {
        self.inner.as_str()
    }

    fn value(&self) -> Result<time::Duration> {
        let number = self.inner.value()? as u64;

        let duration = time::Duration::from_secs(number * self.to_secs_multiplier);

        Ok(duration)
    }
}