imap_types/extensions/
enable.rs1use std::fmt::{Display, Formatter};
10
11#[cfg(feature = "arbitrary")]
12use arbitrary::Arbitrary;
13#[cfg(feature = "bounded-static")]
14use bounded_static::ToStatic;
15#[cfg(feature = "serde")]
16use serde::{Deserialize, Serialize};
17
18use crate::{
19 command::CommandBody,
20 core::{Atom, NonEmptyVec},
21 error::ValidationError,
22};
23
24impl<'a> CommandBody<'a> {
25 pub fn enable<C>(capabilities: C) -> Result<Self, C::Error>
26 where
27 C: TryInto<NonEmptyVec<CapabilityEnable<'a>>>,
28 {
29 Ok(CommandBody::Enable {
30 capabilities: capabilities.try_into()?,
31 })
32 }
33}
34
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 CapabilityEnable<'a> {
40 Utf8(Utf8Kind),
41 #[cfg(feature = "ext_condstore_qresync")]
42 #[cfg_attr(docsrs, doc(cfg(feature = "ext_condstore_qresync")))]
43 CondStore,
44 Other(CapabilityEnableOther<'a>),
45}
46
47impl<'a> TryFrom<&'a str> for CapabilityEnable<'a> {
48 type Error = ValidationError;
49
50 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
51 Ok(Self::from(Atom::try_from(value)?))
52 }
53}
54
55impl<'a> From<Atom<'a>> for CapabilityEnable<'a> {
56 fn from(atom: Atom<'a>) -> Self {
57 match atom.as_ref().to_ascii_lowercase().as_ref() {
58 "utf8=accept" => Self::Utf8(Utf8Kind::Accept),
59 "utf8=only" => Self::Utf8(Utf8Kind::Only),
60 #[cfg(feature = "ext_condstore_qresync")]
61 "condstore" => Self::CondStore,
62 _ => Self::Other(CapabilityEnableOther(atom)),
63 }
64 }
65}
66
67impl<'a> Display for CapabilityEnable<'a> {
68 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
69 match self {
70 Self::Utf8(kind) => write!(f, "UTF8={}", kind),
71 #[cfg(feature = "ext_condstore_qresync")]
72 Self::CondStore => write!(f, "CONDSTORE"),
73 Self::Other(other) => write!(f, "{}", other.0),
74 }
75 }
76}
77
78#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
82#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
83#[derive(Debug, Clone, PartialEq, Eq, Hash)]
84pub struct CapabilityEnableOther<'a>(Atom<'a>);
85
86#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
87#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
88#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
89#[derive(Debug, Clone, PartialEq, Eq, Hash)]
90#[non_exhaustive]
91pub enum Utf8Kind {
92 Accept,
93 Only,
94}
95
96impl Display for Utf8Kind {
97 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
98 f.write_str(match self {
99 Self::Accept => "ACCEPT",
100 Self::Only => "ONLY",
101 })
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_conversion_capability_enable() {
111 assert_eq!(
112 CapabilityEnable::from(Atom::try_from("utf8=only").unwrap()),
113 CapabilityEnable::Utf8(Utf8Kind::Only)
114 );
115 assert_eq!(
116 CapabilityEnable::from(Atom::try_from("utf8=accept").unwrap()),
117 CapabilityEnable::Utf8(Utf8Kind::Accept)
118 );
119 assert_eq!(
120 CapabilityEnable::try_from("utf").unwrap(),
121 CapabilityEnable::Other(CapabilityEnableOther(Atom::try_from("utf").unwrap()))
122 );
123 assert_eq!(
124 CapabilityEnable::try_from("xxxxx").unwrap(),
125 CapabilityEnable::Other(CapabilityEnableOther(Atom::try_from("xxxxx").unwrap()))
126 );
127 }
128}