1use btoi::{btoi, btou};
2use nom::{
3 branch::alt,
4 bytes::streaming::{tag, take_while_m_n},
5 character::{is_digit, streaming::crlf},
6 combinator::{map, map_res, value},
7 sequence::terminated,
8 IResult,
9};
10use std::fmt;
11
12mod ascii_parser;
13pub use ascii_parser::{
14 parse_ascii_metadump_response, parse_ascii_response, parse_ascii_stats_response,
15};
16
17mod meta_parser;
18pub use meta_parser::{
19 parse_meta_arithmetic_response, parse_meta_delete_response, parse_meta_get_response,
20 parse_meta_set_response,
21};
22
23#[derive(Clone, Debug, PartialEq)]
25pub struct Value {
26 pub key: Vec<u8>,
28 pub cas: Option<u64>,
30 pub flags: Option<u32>,
33 pub data: Option<Vec<u8>>,
35}
36
37#[derive(Clone, Debug, PartialEq, Default)]
39pub struct MetaValue {
40 pub key: Option<Vec<u8>>,
42 pub cas: Option<u64>,
44 pub flags: Option<u32>,
46 pub data: Option<Vec<u8>>,
48 pub status: Option<Status>,
50 pub hit_before: Option<bool>,
52 pub last_accessed: Option<u64>,
54 pub ttl_remaining: Option<i64>,
56 pub size: Option<u64>,
58 pub opaque_token: Option<Vec<u8>>,
60 pub is_stale: Option<bool>,
62 pub is_recache_winner: Option<bool>,
64}
65
66#[derive(Clone, Debug, PartialEq)]
68pub enum Status {
69 Stored,
71 NotStored,
73 Deleted,
75 Touched,
77 NoOp,
79 Exists,
81 Value,
83 NotFound,
85 Error(ErrorKind),
87}
88
89#[derive(Clone, Debug, PartialEq)]
91pub enum ErrorKind {
92 Generic(String),
94 NonexistentCommand,
96 Protocol(Option<String>),
98 Client(String),
100 Server(String),
102 KeyTooLong,
104 OpaqueTooLong,
106}
107
108#[derive(Clone, Debug, PartialEq)]
110pub enum Response {
111 Status(Status),
113 Data(Option<Vec<Value>>),
115 IncrDecr(u64),
117}
118
119#[derive(Clone, Debug, PartialEq)]
121pub enum MetaResponse {
122 Status(Status),
124 Data(Option<Vec<MetaValue>>),
126}
127
128#[derive(Clone, Debug, PartialEq)]
130pub enum MetadumpResponse {
131 Busy(String),
133 BadClass(String),
135 Entry(KeyMetadata),
137 End,
139}
140
141#[derive(Clone, Debug, PartialEq)]
143pub enum StatsResponse {
144 Entry(String, String),
146 End,
148}
149
150#[derive(Clone, Debug, PartialEq)]
152pub struct KeyMetadata {
153 pub key: Vec<u8>,
155 pub expiration: i64,
157 pub last_accessed: u64,
159 pub cas: u64,
161 pub fetched: bool,
163 pub class_id: u32,
165 pub size: u32,
167}
168
169impl fmt::Display for Status {
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 match self {
172 Self::Stored => write!(f, "stored"),
173 Self::NotStored => write!(f, "not stored"),
174 Self::Deleted => write!(f, "deleted"),
175 Self::Touched => write!(f, "touched"),
176 Self::NoOp => write!(f, "no-op"),
177 Self::Exists => write!(f, "exists"),
178 Self::Value => write!(f, "value"),
179 Self::NotFound => write!(f, "not found"),
180 Self::Error(ek) => write!(f, "error: {}", ek),
181 }
182 }
183}
184
185impl fmt::Display for ErrorKind {
186 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187 match self {
188 Self::Generic(s) => write!(f, "generic: {}", s),
189 Self::NonexistentCommand => write!(f, "command does not exist"),
190 Self::Protocol(s) => match s {
191 Some(s) => write!(f, "protocol: {}", s),
192 None => write!(f, "protocol"),
193 },
194 Self::Client(s) => write!(f, "client: {}", s),
195 Self::Server(s) => write!(f, "server: {}", s),
196 Self::KeyTooLong => write!(f, "Key exceeds maximum allowed length of 250 characters"),
197 Self::OpaqueTooLong => {
198 write!(f, "Opaque exceeds maximum allowed length of 32 characters")
199 }
200 }
201 }
202}
203
204impl From<MetadumpResponse> for Status {
205 fn from(resp: MetadumpResponse) -> Self {
206 match resp {
207 MetadumpResponse::BadClass(s) => {
208 Status::Error(ErrorKind::Generic(format!("BADCLASS {}", s)))
209 }
210 MetadumpResponse::Busy(s) => Status::Error(ErrorKind::Generic(format!("BUSY {}", s))),
211 _ => unreachable!("Metadump Entry/End states should never be used as a Status!"),
212 }
213 }
214}
215
216pub(crate) fn parse_u64(buf: &[u8]) -> IResult<&[u8], u64> {
218 map_res(take_while_m_n(1, 20, is_digit), btou)(buf)
219}
220
221pub(crate) fn parse_i64(buf: &[u8]) -> IResult<&[u8], i64> {
222 map_res(take_while_m_n(1, 20, is_signed_digit), btoi)(buf)
223}
224
225pub(crate) fn parse_bool(buf: &[u8]) -> IResult<&[u8], bool> {
226 alt((value(true, tag(b"yes")), value(false, tag(b"no"))))(buf)
227}
228
229pub(crate) fn parse_incrdecr(buf: &[u8]) -> IResult<&[u8], Response> {
230 terminated(map(parse_u64, Response::IncrDecr), crlf)(buf)
231}
232
233pub(crate) fn is_key_char(chr: u8) -> bool {
234 chr > 32 && chr < 127
235}
236
237pub(crate) fn is_signed_digit(chr: u8) -> bool {
238 chr == 45 || (48..=57).contains(&chr)
239}
240
241pub(crate) fn parse_u32(buf: &[u8]) -> IResult<&[u8], u32> {
242 map_res(take_while_m_n(1, 10, is_digit), btou)(buf)
243}