imap_types/extensions/
compress.rs1use std::fmt::{Display, Formatter};
14
15#[cfg(feature = "arbitrary")]
16use arbitrary::Arbitrary;
17#[cfg(feature = "bounded-static")]
18use bounded_static::ToStatic;
19#[cfg(feature = "serde")]
20use serde::{Deserialize, Serialize};
21
22use crate::{
23 command::CommandBody,
24 core::Atom,
25 error::{ValidationError, ValidationErrorKind},
26};
27
28impl<'a> CommandBody<'a> {
29 pub fn compress(algorithm: CompressionAlgorithm) -> Self {
30 CommandBody::Compress { algorithm }
31 }
32}
33
34#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
35#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
36#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
37#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38#[non_exhaustive]
39pub enum CompressionAlgorithm {
40 Deflate,
41}
42
43impl Display for CompressionAlgorithm {
44 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
45 f.write_str(match self {
46 Self::Deflate => "DEFLATE",
47 })
48 }
49}
50
51impl<'a> TryFrom<&'a str> for CompressionAlgorithm {
52 type Error = ValidationError;
53
54 fn try_from(value: &str) -> Result<Self, Self::Error> {
55 match value.to_ascii_lowercase().as_ref() {
56 "deflate" => Ok(Self::Deflate),
57 _ => Err(ValidationError::new(ValidationErrorKind::Invalid)),
58 }
59 }
60}
61
62impl<'a> TryFrom<&'a [u8]> for CompressionAlgorithm {
63 type Error = ValidationError;
64
65 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
66 match value.to_ascii_lowercase().as_slice() {
67 b"deflate" => Ok(Self::Deflate),
68 _ => Err(ValidationError::new(ValidationErrorKind::Invalid)),
69 }
70 }
71}
72
73impl<'a> TryFrom<Atom<'a>> for CompressionAlgorithm {
74 type Error = ValidationError;
75
76 fn try_from(atom: Atom<'a>) -> Result<Self, Self::Error> {
77 match atom.as_ref().to_ascii_lowercase().as_ref() {
78 "deflate" => Ok(Self::Deflate),
79 _ => Err(ValidationError::new(ValidationErrorKind::Invalid)),
80 }
81 }
82}
83
84impl AsRef<str> for CompressionAlgorithm {
85 fn as_ref(&self) -> &str {
86 match self {
87 CompressionAlgorithm::Deflate => "DEFLATE",
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn test_conversion() {
98 let tests = [(CompressionAlgorithm::Deflate, "DEFLATE")];
99
100 for (object, string) in tests {
101 let got = CompressionAlgorithm::try_from(string.as_bytes()).unwrap();
103 assert_eq!(object, got);
104
105 let got = CompressionAlgorithm::try_from(string).unwrap();
107 assert_eq!(object, got);
108
109 let got = CompressionAlgorithm::try_from(Atom::try_from(string).unwrap()).unwrap();
111 assert_eq!(object, got);
112
113 let encoded = object.as_ref();
115 assert_eq!(encoded, string);
116 }
117 }
118
119 #[test]
120 fn test_conversion_failing() {
121 let tests = [
122 "", "D", "DE", "DEF", "DEFL", "DEFLA", "DEFLAT", "DEFLATX", "DEFLATEX", "XDEFLATE",
123 ];
124
125 for string in tests {
126 assert!(CompressionAlgorithm::try_from(string.as_bytes()).is_err());
128
129 assert!(CompressionAlgorithm::try_from(string).is_err());
131
132 if !string.is_empty() {
133 assert!(CompressionAlgorithm::try_from(Atom::try_from(string).unwrap()).is_err());
135 }
136 }
137 }
138}