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