1use crate::{AsMemcachedValue, Client, Error, ErrorKind, Status};
2
3use crate::parser::{
4 parse_meta_arithmetic_response, parse_meta_delete_response, parse_meta_get_response,
5 parse_meta_set_response,
6};
7use crate::parser::{MetaResponse, MetaValue};
8
9use std::future::Future;
10
11use tokio::io::AsyncWriteExt;
12
13type MetaResponseParser = fn(&[u8]) -> Result<Option<(usize, MetaResponse)>, ErrorKind>;
14
15async fn drain_quiet_noop_response(
16 client: &mut Client,
17 parser: MetaResponseParser,
18) -> Result<(), Error> {
19 match client.drive_receive(parser).await? {
20 MetaResponse::Status(Status::NoOp) => Ok(()),
21 MetaResponse::Status(status) => Err(Status::Error(ErrorKind::Protocol(Some(format!(
22 "Expected quiet-mode no-op response, got status {status}"
23 ))))
24 .into()),
25 MetaResponse::Data(_) => Err(Status::Error(ErrorKind::Protocol(Some(
26 "Expected quiet-mode no-op response, got data response".to_string(),
27 )))
28 .into()),
29 }
30}
31
32pub trait MetaProtocol {
34 fn meta_get<K: AsRef<[u8]>>(
50 &mut self,
51 key: K,
52 is_quiet: bool,
53 opaque: Option<&[u8]>,
54 meta_flags: Option<&[&str]>,
55 ) -> impl Future<Output = Result<Option<MetaValue>, Error>>;
56
57 fn meta_set<K, V>(
75 &mut self,
76 key: K,
77 value: V,
78 is_quiet: bool,
79 opaque: Option<&[u8]>,
80 meta_flags: Option<&[&str]>,
81 ) -> impl Future<Output = Result<Option<MetaValue>, Error>>
82 where
83 K: AsRef<[u8]>,
84 V: AsMemcachedValue;
85
86 fn meta_delete<K: AsRef<[u8]>>(
99 &mut self,
100 key: K,
101 is_quiet: bool,
102 opaque: Option<&[u8]>,
103 meta_flags: Option<&[&str]>,
104 ) -> impl Future<Output = Result<Option<MetaValue>, Error>>;
105
106 fn meta_increment<K: AsRef<[u8]>>(
130 &mut self,
131 key: K,
132 is_quiet: bool,
133 opaque: Option<&[u8]>,
134 delta: Option<u64>,
135 meta_flags: Option<&[&str]>,
136 ) -> impl Future<Output = Result<Option<MetaValue>, Error>>;
137
138 fn meta_decrement<K: AsRef<[u8]>>(
162 &mut self,
163 key: K,
164 is_quiet: bool,
165 opaque: Option<&[u8]>,
166 delta: Option<u64>,
167 meta_flags: Option<&[&str]>,
168 ) -> impl Future<Output = Result<Option<MetaValue>, Error>>;
169}
170
171impl MetaProtocol for Client {
172 async fn meta_get<K: AsRef<[u8]>>(
173 &mut self,
174 key: K,
175 is_quiet: bool,
176 opaque: Option<&[u8]>,
177 meta_flags: Option<&[&str]>,
178 ) -> Result<Option<MetaValue>, Error> {
179 let kr = Self::validate_key_length(key.as_ref())?;
180
181 if let Some(opaque) = &opaque {
182 Self::validate_opaque_length(opaque)?;
183 }
184
185 self.conn.write_all(b"mg ").await?;
186 self.conn.write_all(kr).await?;
187
188 Self::check_and_write_opaque(self, opaque).await?;
189
190 Self::check_and_write_meta_flags(self, meta_flags, opaque).await?;
191
192 Self::check_and_write_quiet_mode(self, is_quiet).await?;
193
194 self.conn.flush().await?;
195
196 let response = self.drive_receive(parse_meta_get_response).await?;
197 if is_quiet && !matches!(response, MetaResponse::Status(Status::NoOp)) {
198 drain_quiet_noop_response(self, parse_meta_get_response).await?;
199 }
200
201 match response {
202 MetaResponse::Status(Status::NotFound) => Ok(None),
203 MetaResponse::Status(Status::NoOp) => Ok(None),
204 MetaResponse::Status(s) => Err(s.into()),
205 MetaResponse::Data(d) => d
206 .map(|mut items| {
207 let item = items.remove(0);
208 Ok(item)
209 })
210 .transpose(),
211 }
212 }
213
214 async fn meta_set<K, V>(
215 &mut self,
216 key: K,
217 value: V,
218 is_quiet: bool,
219 opaque: Option<&[u8]>,
220 meta_flags: Option<&[&str]>,
221 ) -> Result<Option<MetaValue>, Error>
222 where
223 K: AsRef<[u8]>,
224 V: AsMemcachedValue,
225 {
226 let kr = Self::validate_key_length(key.as_ref())?;
227
228 if let Some(opaque) = &opaque {
229 Self::validate_opaque_length(opaque)?;
230 }
231
232 let vr = value.as_bytes();
233
234 self.conn.write_all(b"ms ").await?;
235 self.conn.write_all(kr).await?;
236
237 let vlen = vr.len().to_string();
238 self.conn.write_all(b" ").await?;
239 self.conn.write_all(vlen.as_ref()).await?;
240
241 Self::check_and_write_opaque(self, opaque).await?;
242
243 Self::check_and_write_meta_flags(self, meta_flags, opaque).await?;
244
245 if is_quiet {
246 self.conn.write_all(b" q").await?;
247 }
248
249 self.conn.write_all(b"\r\n").await?;
250 self.conn.write_all(vr.as_ref()).await?;
251 self.conn.write_all(b"\r\n").await?;
252
253 if is_quiet {
254 self.conn.write_all(b"mn\r\n").await?;
255 }
256
257 self.conn.flush().await?;
258
259 let response = self.drive_receive(parse_meta_set_response).await?;
260 if is_quiet && !matches!(response, MetaResponse::Status(Status::NoOp)) {
261 drain_quiet_noop_response(self, parse_meta_set_response).await?;
262 }
263
264 match response {
265 MetaResponse::Status(Status::Stored) => Ok(None),
266 MetaResponse::Status(Status::NoOp) => Ok(None),
267 MetaResponse::Status(s) => Err(s.into()),
268 MetaResponse::Data(d) => d
269 .map(|mut items| {
270 let item = items.remove(0);
271 Ok(item)
272 })
273 .transpose(),
274 }
275 }
276
277 async fn meta_delete<K: AsRef<[u8]>>(
278 &mut self,
279 key: K,
280 is_quiet: bool,
281 opaque: Option<&[u8]>,
282 meta_flags: Option<&[&str]>,
283 ) -> Result<Option<MetaValue>, Error> {
284 let kr = Self::validate_key_length(key.as_ref())?;
285
286 if let Some(opaque) = &opaque {
287 Self::validate_opaque_length(opaque)?;
288 }
289
290 self.conn.write_all(b"md ").await?;
291 self.conn.write_all(kr).await?;
292
293 Self::check_and_write_opaque(self, opaque).await?;
294
295 Self::check_and_write_meta_flags(self, meta_flags, opaque).await?;
296
297 Self::check_and_write_quiet_mode(self, is_quiet).await?;
298
299 self.conn.flush().await?;
300
301 let response = self.drive_receive(parse_meta_delete_response).await?;
302 if is_quiet && !matches!(response, MetaResponse::Status(Status::NoOp)) {
303 drain_quiet_noop_response(self, parse_meta_delete_response).await?;
304 }
305
306 match response {
307 MetaResponse::Status(Status::Deleted) => Ok(None),
308 MetaResponse::Status(Status::Exists) => Err(Error::Protocol(Status::Exists)),
309 MetaResponse::Status(Status::NoOp) => Ok(None),
310 MetaResponse::Status(s) => Err(s.into()),
311 MetaResponse::Data(d) => d
312 .map(|mut items| {
313 let item = items.remove(0);
314 Ok(item)
315 })
316 .transpose(),
317 }
318 }
319
320 async fn meta_increment<K: AsRef<[u8]>>(
321 &mut self,
322 key: K,
323 is_quiet: bool,
324 opaque: Option<&[u8]>,
325 delta: Option<u64>,
326 meta_flags: Option<&[&str]>,
327 ) -> Result<Option<MetaValue>, Error> {
328 let kr = Self::validate_key_length(key.as_ref())?;
329
330 if let Some(opaque) = &opaque {
331 Self::validate_opaque_length(opaque)?;
332 }
333
334 self.conn.write_all(b"ma ").await?;
335 self.conn.write_all(kr).await?;
336
337 Self::check_and_write_opaque(self, opaque).await?;
338
339 if let Some(delta) = delta {
341 if delta != 1 {
342 self.conn.write_all(b" D").await?;
343 self.conn.write_all(delta.to_string().as_bytes()).await?;
344 }
345 }
346
347 if let Some(meta_flags) = meta_flags {
348 for flag in meta_flags {
349 if flag.starts_with('M')
352 || flag.starts_with('q')
353 || (flag.starts_with('D') && delta.is_some())
354 || (flag.starts_with('O') && opaque.is_some())
355 {
356 continue;
357 } else {
358 self.conn.write_all(b" ").await?;
359 self.conn.write_all(flag.as_bytes()).await?;
360 }
361 }
362 }
363
364 Self::check_and_write_quiet_mode(self, is_quiet).await?;
365
366 self.conn.flush().await?;
367
368 let response = self.drive_receive(parse_meta_arithmetic_response).await?;
369 if is_quiet && !matches!(response, MetaResponse::Status(Status::NoOp)) {
370 drain_quiet_noop_response(self, parse_meta_arithmetic_response).await?;
371 }
372
373 match response {
374 MetaResponse::Status(Status::Stored) => Ok(None),
375 MetaResponse::Status(Status::NoOp) => Ok(None),
376 MetaResponse::Status(s) => Err(s.into()),
377 MetaResponse::Data(d) => d
378 .map(|mut items| {
379 let item = items.remove(0);
380 Ok(item)
381 })
382 .transpose(),
383 }
384 }
385
386 async fn meta_decrement<K: AsRef<[u8]>>(
387 &mut self,
388 key: K,
389 is_quiet: bool,
390 opaque: Option<&[u8]>,
391 delta: Option<u64>,
392 meta_flags: Option<&[&str]>,
393 ) -> Result<Option<MetaValue>, Error> {
394 let kr = Self::validate_key_length(key.as_ref())?;
395
396 if let Some(opaque) = &opaque {
397 Self::validate_opaque_length(opaque)?;
398 }
399
400 self.conn.write_all(b"ma ").await?;
401 self.conn.write_all(kr).await?;
402 self.conn.write_all(b" MD").await?;
403
404 Self::check_and_write_opaque(self, opaque).await?;
405
406 if let Some(delta) = delta {
407 if delta != 1 {
408 self.conn.write_all(b" D").await?;
409 self.conn.write_all(delta.to_string().as_bytes()).await?;
410 }
411 }
412
413 if let Some(meta_flags) = meta_flags {
414 for flag in meta_flags {
415 if flag.starts_with('M')
418 || flag.starts_with('q')
419 || (flag.starts_with('D') && delta.is_some())
420 || (flag.starts_with('O') && opaque.is_some())
421 {
422 continue;
423 } else {
424 self.conn.write_all(b" ").await?;
425 self.conn.write_all(flag.as_bytes()).await?;
426 }
427 }
428 }
429
430 Self::check_and_write_quiet_mode(self, is_quiet).await?;
431
432 self.conn.flush().await?;
433
434 let response = self.drive_receive(parse_meta_arithmetic_response).await?;
435 if is_quiet && !matches!(response, MetaResponse::Status(Status::NoOp)) {
436 drain_quiet_noop_response(self, parse_meta_arithmetic_response).await?;
437 }
438
439 match response {
440 MetaResponse::Status(Status::Stored) => Ok(None),
441 MetaResponse::Status(Status::NoOp) => Ok(None),
442 MetaResponse::Status(s) => Err(s.into()),
443 MetaResponse::Data(d) => d
444 .map(|mut items| {
445 let item = items.remove(0);
446 Ok(item)
447 })
448 .transpose(),
449 }
450 }
451}