fast_cache/commands/
psetex.rs1use crate::Result;
4use crate::protocol::{FastCommand, Frame};
5#[cfg(feature = "server")]
6use crate::server::commands::{BorrowedCommandContext, DirectCommandContext};
7#[cfg(feature = "server")]
8use crate::server::commands::{RawCommandContext, RawDirectCommand};
9#[cfg(feature = "server")]
10use crate::server::wire::ServerWire;
11use crate::storage::{Command, EngineCommandContext, EngineFrameFuture};
12
13use super::DecodedFastCommand;
14use super::parsing::{CommandArity, TtlMillis};
15use super::setex::SetEx;
16
17pub(crate) struct PSetEx;
18pub(crate) static COMMAND: PSetEx = PSetEx;
19
20#[derive(Debug, Clone)]
21pub(crate) struct OwnedPSetEx {
22 key: Vec<u8>,
23 ttl_ms: u64,
24 value: Vec<u8>,
25}
26
27impl OwnedPSetEx {
28 fn new(key: Vec<u8>, ttl_ms: u64, value: Vec<u8>) -> Self {
29 Self { key, ttl_ms, value }
30 }
31}
32
33impl super::OwnedCommandData for OwnedPSetEx {
34 type Spec = PSetEx;
35
36 fn route_key(&self) -> Option<&[u8]> {
37 Some(&self.key)
38 }
39
40 fn to_borrowed_command(&self) -> super::BorrowedCommandBox<'_> {
41 Box::new(BorrowedPSetEx::new(&self.key, self.ttl_ms, &self.value))
42 }
43}
44
45#[derive(Debug, Clone, Copy)]
46pub(crate) struct BorrowedPSetEx<'a> {
47 key: &'a [u8],
48 ttl_ms: u64,
49 value: &'a [u8],
50}
51
52impl<'a> BorrowedPSetEx<'a> {
53 fn new(key: &'a [u8], ttl_ms: u64, value: &'a [u8]) -> Self {
54 Self { key, ttl_ms, value }
55 }
56}
57
58impl<'a> super::BorrowedCommandData<'a> for BorrowedPSetEx<'a> {
59 type Spec = PSetEx;
60
61 fn route_key(&self) -> Option<&'a [u8]> {
62 Some(self.key)
63 }
64
65 fn to_owned_command(&self) -> Command {
66 Command::new(Box::new(OwnedPSetEx::new(
67 self.key.to_vec(),
68 self.ttl_ms,
69 self.value.to_vec(),
70 )))
71 }
72
73 fn execute_engine<'b>(&'b self, ctx: EngineCommandContext<'b>) -> EngineFrameFuture<'b>
74 where
75 'a: 'b,
76 {
77 let key = self.key;
78 let ttl_ms = self.ttl_ms;
79 let value = self.value;
80 Box::pin(async move {
81 SetEx::store_value(ctx, key, ttl_ms, value)
82 .await
83 .map(|_| Frame::SimpleString("OK".into()))
84 })
85 }
86
87 #[cfg(feature = "server")]
88 fn execute_borrowed_frame(&self, store: &crate::storage::EmbeddedStore, _now_ms: u64) -> Frame {
89 store.set(self.key.to_vec(), self.value.to_vec(), Some(self.ttl_ms));
90 Frame::SimpleString("OK".into())
91 }
92
93 #[cfg(feature = "server")]
94 fn execute_borrowed(&self, ctx: BorrowedCommandContext<'_, '_, '_>) {
95 ctx.store
96 .set(self.key.to_vec(), self.value.to_vec(), Some(self.ttl_ms));
97 ctx.out.extend_from_slice(b"+OK\r\n");
98 }
99
100 #[cfg(feature = "server")]
101 fn execute_direct_borrowed(&self, ctx: DirectCommandContext) -> Frame {
102 ctx.set_owned(self.key.to_vec(), self.value.to_vec(), Some(self.ttl_ms));
103 Frame::SimpleString("OK".into())
104 }
105}
106
107impl super::CommandSpec for PSetEx {
108 const NAME: &'static str = "PSETEX";
109 const MUTATES_VALUE: bool = true;
110}
111
112impl super::OwnedCommandParse for PSetEx {
113 fn parse_owned(parts: &[Vec<u8>]) -> Result<Command> {
114 CommandArity::<Self>::exact(parts.len(), 4)?;
115 Ok(Command::new(Box::new(OwnedPSetEx::new(
116 parts[1].clone(),
117 TtlMillis::<Self>::millis(&parts[2])?,
118 parts[3].clone(),
119 ))))
120 }
121}
122
123impl<'a> super::BorrowedCommandParse<'a> for PSetEx {
124 fn parse_borrowed(parts: &[&'a [u8]]) -> Result<super::BorrowedCommandBox<'a>> {
125 CommandArity::<Self>::exact(parts.len(), 4)?;
126 Ok(Box::new(BorrowedPSetEx::new(
127 parts[1],
128 TtlMillis::<Self>::millis(parts[2])?,
129 parts[3],
130 )))
131 }
132}
133
134impl DecodedFastCommand for PSetEx {
135 fn matches_decoded_fast(&self, _command: &FastCommand<'_>) -> bool {
136 false
137 }
138}
139
140#[cfg(feature = "server")]
141impl RawDirectCommand for PSetEx {
142 fn execute(&self, ctx: RawCommandContext<'_, '_, '_>) {
143 match ctx.args.as_slice() {
144 [key, ttl, value] => match TtlMillis::<()>::ascii_millis(ttl) {
145 Some(ttl_ms) => {
146 ctx.store.set(key.to_vec(), value.to_vec(), Some(ttl_ms));
147 ctx.out.extend_from_slice(b"+OK\r\n");
148 }
149 None => ServerWire::write_resp_error(ctx.out, "ERR value is not an integer"),
150 },
151 _ => ServerWire::write_resp_error(
152 ctx.out,
153 "ERR wrong number of arguments for 'PSETEX' command",
154 ),
155 }
156 }
157}