Skip to main content

memcached_async/
types.rs

1use bytes::Bytes;
2
3/// Canonical memcached operation.
4#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
5pub enum Op {
6    Get,
7    Gets,
8    Gat,
9    Gats,
10    Set,
11    Add,
12    Replace,
13    Append,
14    Prepend,
15    Cas,
16    Delete,
17    Flush,
18    Incr,
19    Decr,
20    Touch,
21    Stats,
22    Version,
23    SaslListMechs,
24    SaslAuth,
25    SaslStep,
26    Quit,
27    MetaGet,
28    MetaSet,
29    MetaDelete,
30    MetaArithmetic,
31    MetaDebug,
32    MetaNoop,
33    Noop,
34    Unknown,
35}
36
37/// Connection-level protocol.
38#[derive(Debug, Clone, Copy, Eq, PartialEq)]
39pub enum Protocol {
40    Ascii,
41    Meta,
42    Binary,
43}
44
45/// Reply suppression policy.
46#[derive(Debug, Clone, Copy, Eq, PartialEq)]
47pub enum ReplyMode {
48    /// Always return a response.
49    Always,
50    /// Suppress success responses; errors still returned.
51    SuppressSuccess,
52    /// Suppress miss responses for meta-get.
53    SuppressMiss,
54    /// Binary quiet mode: buffer/suppress based on opcode.
55    QuietBuffered,
56}
57
58/// Parsed request from any protocol.
59#[derive(Debug, Clone)]
60pub struct Request {
61    pub op: Op,
62    pub key: Option<Bytes>,
63    pub keys: Vec<Bytes>,
64    pub value: Option<Bytes>,
65    pub flags: Option<u32>,
66    pub exptime: Option<i64>,
67    pub cas: Option<u64>,
68    pub delta: Option<u64>,
69    pub initial: Option<u64>,
70    pub meta: Option<MetaFlags>,
71}
72
73impl Request {
74    pub fn new(op: Op) -> Self {
75        Self {
76            op,
77            key: None,
78            keys: Vec::new(),
79            value: None,
80            flags: None,
81            exptime: None,
82            cas: None,
83            delta: None,
84            initial: None,
85            meta: None,
86        }
87    }
88}
89
90/// Protocol-specific metadata carried with a request.
91#[derive(Debug, Clone, Copy)]
92pub struct RequestMeta {
93    pub protocol: Protocol,
94    pub reply: ReplyMode,
95    pub opaque: Option<u32>,
96    pub return_key: bool,
97    pub opcode: u8,
98}
99
100impl RequestMeta {
101    pub fn ascii() -> Self {
102        Self {
103            protocol: Protocol::Ascii,
104            reply: ReplyMode::Always,
105            opaque: None,
106            return_key: false,
107            opcode: 0,
108        }
109    }
110}
111
112/// Ordered meta flags with a compact mask for fast lookup.
113#[derive(Debug, Clone)]
114pub struct MetaFlags {
115    pub ordered: Vec<MetaFlag>,
116    pub mask: u64,
117}
118
119impl MetaFlags {
120    pub fn new(ordered: Vec<MetaFlag>) -> Self {
121        let mut mask = 0u64;
122        for flag in &ordered {
123            if let Some(bit) = flag_bit(flag.code) {
124                mask |= 1u64 << bit;
125            }
126        }
127        Self { ordered, mask }
128    }
129
130    pub fn has(&self, code: u8) -> bool {
131        if let Some(bit) = flag_bit(code)
132            && (self.mask & (1u64 << bit)) != 0
133        {
134            return true;
135        }
136        self.ordered.iter().any(|flag| flag.code == code)
137    }
138
139    pub fn token(&self, code: u8) -> Option<&Bytes> {
140        self.ordered
141            .iter()
142            .find(|flag| flag.code == code)
143            .and_then(|flag| flag.token.as_ref())
144    }
145}
146
147fn flag_bit(code: u8) -> Option<u64> {
148    match code {
149        b'a'..=b'z' => Some((code - b'a') as u64),
150        b'A'..=b'Z' => Some((26 + (code - b'A')) as u64),
151        b'0'..=b'9' => Some((52 + (code - b'0')) as u64),
152        _ => None,
153    }
154}
155
156/// A single meta flag token.
157#[derive(Debug, Clone)]
158pub struct MetaFlag {
159    pub code: u8,
160    pub token: Option<Bytes>,
161}
162
163/// Meta response status code.
164#[derive(Debug, Clone, Copy, Eq, PartialEq)]
165pub enum MetaCode {
166    Hd,
167    Va,
168    En,
169    Ns,
170    Ex,
171    Nf,
172}
173
174impl MetaCode {
175    pub fn as_bytes(self) -> &'static [u8] {
176        match self {
177            MetaCode::Hd => b"HD",
178            MetaCode::Va => b"VA",
179            MetaCode::En => b"EN",
180            MetaCode::Ns => b"NS",
181            MetaCode::Ex => b"EX",
182            MetaCode::Nf => b"NF",
183        }
184    }
185
186    pub fn is_success(self) -> bool {
187        matches!(self, MetaCode::Hd | MetaCode::Va)
188    }
189
190    pub fn is_miss(self) -> bool {
191        matches!(self, MetaCode::En)
192    }
193}
194
195/// Meta response payload.
196#[derive(Debug, Clone)]
197pub struct MetaResponse {
198    pub code: MetaCode,
199    pub value: Option<Bytes>,
200    pub cas: Option<u64>,
201    pub flags: Option<u32>,
202    pub ttl: Option<i64>,
203    pub size: Option<usize>,
204    pub hit: Option<bool>,
205    pub last_access: Option<u64>,
206    pub extra: MetaExtra,
207}
208
209impl MetaResponse {
210    pub fn new(code: MetaCode) -> Self {
211        Self {
212            code,
213            value: None,
214            cas: None,
215            flags: None,
216            ttl: None,
217            size: None,
218            hit: None,
219            last_access: None,
220            extra: MetaExtra::default(),
221        }
222    }
223}
224
225/// Extra meta flags (W/X/Z).
226#[derive(Debug, Clone, Default)]
227pub struct MetaExtra {
228    pub won: Option<WinState>,
229    pub stale: bool,
230}
231
232#[derive(Debug, Clone, Copy, Eq, PartialEq)]
233pub enum WinState {
234    Won,
235    AlreadyWon,
236}
237
238/// A single value entry for get/gets responses.
239#[derive(Debug, Clone)]
240pub struct ValueEntry {
241    pub key: Bytes,
242    pub value: Bytes,
243    pub flags: u32,
244    pub cas: Option<u64>,
245}
246
247/// A stat line (key/value pair).
248#[derive(Debug, Clone)]
249pub struct StatLine {
250    pub key: Bytes,
251    pub value: Bytes,
252}
253
254/// Streaming values iterator.
255pub trait ValuesStream {
256    fn next(&mut self) -> Option<ValueEntry>;
257}
258
259/// Streaming stats iterator.
260pub trait StatsStream {
261    fn next(&mut self) -> Option<StatLine>;
262}