1use std::borrow::Borrow;
2use std::convert::TryFrom;
3use std::ffi::CString;
4use std::fmt::Display;
5use std::ops::Deref;
6use std::os::raw::{c_char, c_int, c_void};
7use std::ptr::{null_mut, NonNull};
8use std::slice;
9use std::str;
10use std::str::Utf8Error;
11use std::string::FromUtf8Error;
12use std::{fmt, ptr};
13
14use serde::de::{Error, SeqAccess};
15
16pub use crate::raw;
17pub use crate::rediserror::ValkeyError;
18pub use crate::redisvalue::ValkeyValue;
19use crate::Context;
20
21pub type ValkeyResult<T = ValkeyValue> = Result<T, ValkeyError>;
24pub type ValkeyValueResult = ValkeyResult<ValkeyValue>;
26
27impl From<ValkeyValue> for ValkeyValueResult {
28 fn from(v: ValkeyValue) -> Self {
29 Ok(v)
30 }
31}
32
33impl From<ValkeyError> for ValkeyValueResult {
34 fn from(v: ValkeyError) -> Self {
35 Err(v)
36 }
37}
38
39pub const VALKEY_OK: ValkeyValueResult = Ok(ValkeyValue::SimpleStringStatic("OK"));
40pub const TYPE_METHOD_VERSION: u64 = raw::REDISMODULE_TYPE_METHOD_VERSION as u64;
41
42pub trait NextArg {
43 fn next_arg(&mut self) -> Result<ValkeyString, ValkeyError>;
44 fn next_string(&mut self) -> Result<String, ValkeyError>;
45 fn next_str<'a>(&mut self) -> Result<&'a str, ValkeyError>;
46 fn next_i64(&mut self) -> Result<i64, ValkeyError>;
47 fn next_u64(&mut self) -> Result<u64, ValkeyError>;
48 fn next_f64(&mut self) -> Result<f64, ValkeyError>;
49 fn done(&mut self) -> Result<(), ValkeyError>;
50}
51
52impl<T> NextArg for T
53where
54 T: Iterator<Item = ValkeyString>,
55{
56 #[inline]
57 fn next_arg(&mut self) -> Result<ValkeyString, ValkeyError> {
58 self.next().ok_or(ValkeyError::WrongArity)
59 }
60
61 #[inline]
62 fn next_string(&mut self) -> Result<String, ValkeyError> {
63 self.next()
64 .map_or(Err(ValkeyError::WrongArity), |v| Ok(v.to_string_lossy()))
65 }
66
67 #[inline]
68 fn next_str<'a>(&mut self) -> Result<&'a str, ValkeyError> {
69 self.next()
70 .map_or(Err(ValkeyError::WrongArity), |v| v.try_as_str())
71 }
72
73 #[inline]
74 fn next_i64(&mut self) -> Result<i64, ValkeyError> {
75 self.next()
76 .map_or(Err(ValkeyError::WrongArity), |v| v.parse_integer())
77 }
78
79 #[inline]
80 fn next_u64(&mut self) -> Result<u64, ValkeyError> {
81 self.next()
82 .map_or(Err(ValkeyError::WrongArity), |v| v.parse_unsigned_integer())
83 }
84
85 #[inline]
86 fn next_f64(&mut self) -> Result<f64, ValkeyError> {
87 self.next()
88 .map_or(Err(ValkeyError::WrongArity), |v| v.parse_float())
89 }
90
91 #[inline]
93 fn done(&mut self) -> Result<(), ValkeyError> {
94 self.next().map_or(Ok(()), |_| Err(ValkeyError::WrongArity))
95 }
96}
97
98#[allow(clippy::not_unsafe_ptr_arg_deref)]
99pub fn decode_args(
100 ctx: *mut raw::RedisModuleCtx,
101 argv: *mut *mut raw::RedisModuleString,
102 argc: c_int,
103) -> Vec<ValkeyString> {
104 if argv.is_null() {
105 return Vec::new();
106 }
107 unsafe { slice::from_raw_parts(argv, argc as usize) }
108 .iter()
109 .map(|&arg| ValkeyString::new(NonNull::new(ctx), arg))
110 .collect()
111}
112
113#[derive(Debug)]
116pub struct ValkeyString {
117 ctx: *mut raw::RedisModuleCtx,
118 pub inner: *mut raw::RedisModuleString,
119}
120
121impl ValkeyString {
122 pub(crate) fn take(mut self) -> *mut raw::RedisModuleString {
123 let inner = self.inner;
124 self.inner = std::ptr::null_mut();
125 inner
126 }
127
128 pub fn new(
129 ctx: Option<NonNull<raw::RedisModuleCtx>>,
130 inner: *mut raw::RedisModuleString,
131 ) -> Self {
132 let ctx = ctx.map_or(std::ptr::null_mut(), |v| v.as_ptr());
133 raw::string_retain_string(ctx, inner);
134 Self { ctx, inner }
135 }
136
137 pub fn safe_clone(&self, _ctx: &Context) -> Self {
141 raw::string_retain_string(ptr::null_mut(), self.inner);
147 Self {
148 ctx: ptr::null_mut(),
149 inner: self.inner,
150 }
151 }
152
153 #[allow(clippy::not_unsafe_ptr_arg_deref)]
154 pub fn create<T: Into<Vec<u8>>>(ctx: Option<NonNull<raw::RedisModuleCtx>>, s: T) -> Self {
155 let ctx = ctx.map_or(std::ptr::null_mut(), |v| v.as_ptr());
156 let str = CString::new(s).unwrap();
157 let inner = unsafe {
158 raw::RedisModule_CreateString.unwrap()(ctx, str.as_ptr(), str.as_bytes().len())
159 };
160
161 Self { ctx, inner }
162 }
163
164 #[allow(clippy::not_unsafe_ptr_arg_deref)]
165 pub fn create_from_slice(ctx: *mut raw::RedisModuleCtx, s: &[u8]) -> Self {
166 let inner = unsafe {
167 raw::RedisModule_CreateString.unwrap()(ctx, s.as_ptr().cast::<c_char>(), s.len())
168 };
169
170 Self { ctx, inner }
171 }
172
173 pub fn create_and_retain(arg: &str) -> ValkeyString {
175 let arg = ValkeyString::create(None, arg);
176 raw::string_retain_string(null_mut(), arg.inner);
177 arg
178 }
179
180 pub const fn from_redis_module_string(
181 ctx: *mut raw::RedisModuleCtx,
182 inner: *mut raw::RedisModuleString,
183 ) -> Self {
184 Self { ctx, inner }
186 }
187
188 #[allow(clippy::not_unsafe_ptr_arg_deref)]
189 pub fn from_ptr<'a>(ptr: *const raw::RedisModuleString) -> Result<&'a str, Utf8Error> {
190 str::from_utf8(Self::string_as_slice(ptr))
191 }
192
193 pub fn append(&mut self, s: &str) -> raw::Status {
194 raw::string_append_buffer(self.ctx, self.inner, s)
195 }
196
197 #[must_use]
198 pub fn len(&self) -> usize {
199 let mut len: usize = 0;
200 raw::string_ptr_len(self.inner, &mut len);
201 len
202 }
203
204 #[must_use]
205 pub fn is_empty(&self) -> bool {
206 let mut len: usize = 0;
207 raw::string_ptr_len(self.inner, &mut len);
208 len == 0
209 }
210
211 pub fn try_as_str<'a>(&self) -> Result<&'a str, ValkeyError> {
212 Self::from_ptr(self.inner).map_err(|_| ValkeyError::Str("Couldn't parse as UTF-8 string"))
213 }
214
215 #[must_use]
216 pub fn as_slice(&self) -> &[u8] {
217 Self::string_as_slice(self.inner)
218 }
219
220 #[allow(clippy::not_unsafe_ptr_arg_deref)]
221 pub fn string_as_slice<'a>(ptr: *const raw::RedisModuleString) -> &'a [u8] {
222 let mut len: libc::size_t = 0;
223 let bytes = unsafe { raw::RedisModule_StringPtrLen.unwrap()(ptr, &mut len) };
224
225 unsafe { slice::from_raw_parts(bytes.cast::<u8>(), len) }
226 }
227
228 #[must_use]
236 pub fn to_string_lossy(&self) -> String {
237 String::from_utf8_lossy(self.as_slice()).into_owned()
238 }
239
240 pub fn parse_unsigned_integer(&self) -> Result<u64, ValkeyError> {
241 let val = self.parse_integer()?;
242 u64::try_from(val)
243 .map_err(|_| ValkeyError::Str("Couldn't parse negative number as unsigned integer"))
244 }
245
246 pub fn parse_integer(&self) -> Result<i64, ValkeyError> {
247 let mut val: i64 = 0;
248 match raw::string_to_longlong(self.inner, &mut val) {
249 raw::Status::Ok => Ok(val),
250 raw::Status::Err => Err(ValkeyError::Str("Couldn't parse as integer")),
251 }
252 }
253
254 pub fn parse_float(&self) -> Result<f64, ValkeyError> {
255 let mut val: f64 = 0.0;
256 match raw::string_to_double(self.inner, &mut val) {
257 raw::Status::Ok => Ok(val),
258 raw::Status::Err => Err(ValkeyError::Str("Couldn't parse as float")),
259 }
260 }
261
262 }
268
269impl Drop for ValkeyString {
270 fn drop(&mut self) {
271 if !self.inner.is_null() {
272 unsafe {
273 raw::RedisModule_FreeString.unwrap()(self.ctx, self.inner);
274 }
275 }
276 }
277}
278
279impl PartialEq for ValkeyString {
280 fn eq(&self, other: &Self) -> bool {
281 self.cmp(other).is_eq()
282 }
283}
284
285impl Eq for ValkeyString {}
286
287impl PartialOrd for ValkeyString {
288 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
289 Some(self.cmp(other))
290 }
291}
292
293impl Ord for ValkeyString {
294 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
295 raw::string_compare(self.inner, other.inner)
296 }
297}
298
299impl core::hash::Hash for ValkeyString {
300 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
301 self.as_slice().hash(state);
302 }
303}
304
305impl Display for ValkeyString {
306 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
307 write!(f, "{}", self.to_string_lossy())
308 }
309}
310
311impl Borrow<str> for ValkeyString {
312 fn borrow(&self) -> &str {
313 self.try_as_str().unwrap_or("<Invalid UTF-8 data>")
315 }
316}
317
318impl Clone for ValkeyString {
319 fn clone(&self) -> Self {
320 let inner =
321 unsafe { raw::RedisModule_CreateStringFromString.unwrap()(ptr::null_mut(), self.inner) };
326 Self::from_redis_module_string(ptr::null_mut(), inner)
327 }
328}
329
330impl From<ValkeyString> for String {
331 fn from(rs: ValkeyString) -> Self {
332 rs.to_string_lossy()
333 }
334}
335
336impl Deref for ValkeyString {
337 type Target = [u8];
338
339 fn deref(&self) -> &Self::Target {
340 self.as_slice()
341 }
342}
343
344impl From<ValkeyString> for Vec<u8> {
345 fn from(rs: ValkeyString) -> Self {
346 rs.as_slice().to_vec()
347 }
348}
349
350impl serde::Serialize for ValkeyString {
351 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
352 where
353 S: serde::Serializer,
354 {
355 serializer.serialize_bytes(self.as_slice())
356 }
357}
358
359struct RedisStringVisitor;
360
361impl<'de> serde::de::Visitor<'de> for RedisStringVisitor {
362 type Value = ValkeyString;
363
364 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
365 formatter.write_str("A bytes buffer")
366 }
367
368 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
369 where
370 E: Error,
371 {
372 Ok(ValkeyString::create(None, v))
373 }
374
375 fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
376 where
377 V: SeqAccess<'de>,
378 {
379 let mut v = if let Some(size_hint) = visitor.size_hint() {
380 Vec::with_capacity(size_hint)
381 } else {
382 Vec::new()
383 };
384 while let Some(elem) = visitor.next_element()? {
385 v.push(elem);
386 }
387
388 Ok(ValkeyString::create(None, v.as_slice()))
389 }
390}
391
392impl<'de> serde::Deserialize<'de> for ValkeyString {
393 fn deserialize<D>(deserializer: D) -> Result<ValkeyString, D::Error>
394 where
395 D: serde::Deserializer<'de>,
396 {
397 deserializer.deserialize_bytes(RedisStringVisitor)
398 }
399}
400
401#[derive(Debug)]
404pub struct RedisBuffer {
405 buffer: *mut c_char,
406 len: usize,
407}
408
409impl RedisBuffer {
410 pub const fn new(buffer: *mut c_char, len: usize) -> Self {
411 Self { buffer, len }
412 }
413
414 pub fn to_string(&self) -> Result<String, FromUtf8Error> {
415 String::from_utf8(self.as_ref().to_vec())
416 }
417}
418
419impl AsRef<[u8]> for RedisBuffer {
420 fn as_ref(&self) -> &[u8] {
421 unsafe { slice::from_raw_parts(self.buffer as *const u8, self.len) }
422 }
423}
424
425impl Drop for RedisBuffer {
426 fn drop(&mut self) {
427 unsafe {
428 raw::RedisModule_Free.unwrap()(self.buffer.cast::<c_void>());
429 }
430 }
431}