use crate::{
error::{RedisError, RedisErrorKind},
interfaces::{ClientLike, Resp3Frame},
protocol::{connection::OK, utils as protocol_utils},
types::{FromRedis, FromRedisKey, Server, QUEUED},
utils,
};
use bytes::Bytes;
use bytes_utils::Str;
use float_cmp::approx_eq;
use redis_protocol::resp2::types::NULL;
use std::{
borrow::Cow,
collections::{BTreeMap, HashMap, HashSet, VecDeque},
convert::{TryFrom, TryInto},
fmt,
hash::{Hash, Hasher},
iter::FromIterator,
mem,
ops::{Deref, DerefMut},
str,
};
#[cfg(feature = "i-scripts")]
use crate::types::Function;
#[cfg(feature = "i-geo")]
use crate::types::{GeoPosition, GeoRadiusInfo};
#[cfg(feature = "i-streams")]
use crate::types::{XReadResponse, XReadValue};
#[cfg(feature = "serde-json")]
use serde_json::Value;
static TRUE_STR: Str = utils::static_str("true");
static FALSE_STR: Str = utils::static_str("false");
macro_rules! impl_string_or_number(
($t:ty) => {
impl From<$t> for StringOrNumber {
fn from(val: $t) -> Self {
StringOrNumber::Number(val as i64)
}
}
}
);
macro_rules! impl_from_str_for_redis_key(
($t:ty) => {
impl From<$t> for RedisKey {
fn from(val: $t) -> Self {
RedisKey { key: val.to_string().into() }
}
}
}
);
#[derive(Clone, Debug)]
pub enum StringOrNumber {
String(Str),
Number(i64),
Double(f64),
}
impl PartialEq for StringOrNumber {
fn eq(&self, other: &Self) -> bool {
match *self {
StringOrNumber::String(ref s) => match *other {
StringOrNumber::String(ref _s) => s == _s,
_ => false,
},
StringOrNumber::Number(ref i) => match *other {
StringOrNumber::Number(ref _i) => *i == *_i,
_ => false,
},
StringOrNumber::Double(ref d) => match *other {
StringOrNumber::Double(ref _d) => utils::f64_eq(*d, *_d),
_ => false,
},
}
}
}
impl Eq for StringOrNumber {}
impl StringOrNumber {
pub fn from_static_str(s: &'static str) -> Self {
StringOrNumber::String(utils::static_str(s))
}
#[cfg(feature = "i-streams")]
pub(crate) fn into_arg(self) -> RedisValue {
match self {
StringOrNumber::String(s) => RedisValue::String(s),
StringOrNumber::Number(n) => RedisValue::Integer(n),
StringOrNumber::Double(f) => RedisValue::Double(f),
}
}
}
impl TryFrom<RedisValue> for StringOrNumber {
type Error = RedisError;
fn try_from(value: RedisValue) -> Result<Self, Self::Error> {
let val = match value {
RedisValue::String(s) => StringOrNumber::String(s),
RedisValue::Integer(i) => StringOrNumber::Number(i),
RedisValue::Double(f) => StringOrNumber::Double(f),
RedisValue::Bytes(b) => StringOrNumber::String(Str::from_inner(b)?),
_ => return Err(RedisError::new(RedisErrorKind::InvalidArgument, "")),
};
Ok(val)
}
}
impl<'a> From<&'a str> for StringOrNumber {
fn from(s: &'a str) -> Self {
StringOrNumber::String(s.into())
}
}
impl From<String> for StringOrNumber {
fn from(s: String) -> Self {
StringOrNumber::String(s.into())
}
}
impl From<Str> for StringOrNumber {
fn from(s: Str) -> Self {
StringOrNumber::String(s)
}
}
impl_string_or_number!(i8);
impl_string_or_number!(i16);
impl_string_or_number!(i32);
impl_string_or_number!(i64);
impl_string_or_number!(isize);
impl_string_or_number!(u8);
impl_string_or_number!(u16);
impl_string_or_number!(u32);
impl_string_or_number!(u64);
impl_string_or_number!(usize);
impl From<f32> for StringOrNumber {
fn from(f: f32) -> Self {
StringOrNumber::Double(f as f64)
}
}
impl From<f64> for StringOrNumber {
fn from(f: f64) -> Self {
StringOrNumber::Double(f)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct RedisKey {
key: Bytes,
}
impl RedisKey {
pub fn from_static(b: &'static [u8]) -> Self {
RedisKey {
key: Bytes::from_static(b),
}
}
pub fn from_static_str(b: &'static str) -> Self {
RedisKey {
key: Bytes::from_static(b.as_bytes()),
}
}
pub fn as_str(&self) -> Option<&str> {
str::from_utf8(&self.key).ok()
}
pub fn as_bytes(&self) -> &[u8] {
&self.key
}
pub fn inner(&self) -> &Bytes {
&self.key
}
pub fn as_str_lossy(&self) -> Cow<str> {
String::from_utf8_lossy(&self.key)
}
pub fn into_string(self) -> Option<String> {
String::from_utf8(self.key.to_vec()).ok()
}
pub fn into_bytes(self) -> Bytes {
self.key
}
pub fn as_bytes_str(&self) -> Option<Str> {
Str::from_inner(self.key.clone()).ok()
}
pub fn cluster_hash(&self) -> u16 {
redis_protocol::redis_keyslot(&self.key)
}
pub fn cluster_owner<C>(&self, client: &C) -> Option<Server>
where
C: ClientLike,
{
if client.is_clustered() {
let hash_slot = self.cluster_hash();
client
.inner()
.with_cluster_state(|state| Ok(state.get_server(hash_slot).cloned()))
.ok()
.and_then(|server| server)
} else {
None
}
}
pub fn take(&mut self) -> Bytes {
self.key.split_to(self.key.len())
}
pub fn convert<K>(self) -> Result<K, RedisError>
where
K: FromRedisKey,
{
K::from_key(self)
}
}
impl TryFrom<RedisValue> for RedisKey {
type Error = RedisError;
fn try_from(value: RedisValue) -> Result<Self, Self::Error> {
let val = match value {
RedisValue::String(s) => RedisKey { key: s.into_inner() },
RedisValue::Integer(i) => RedisKey {
key: i.to_string().into(),
},
RedisValue::Double(f) => RedisKey {
key: f.to_string().into(),
},
RedisValue::Bytes(b) => RedisKey { key: b },
RedisValue::Boolean(b) => match b {
true => RedisKey {
key: TRUE_STR.clone().into_inner(),
},
false => RedisKey {
key: FALSE_STR.clone().into_inner(),
},
},
RedisValue::Queued => utils::static_str(QUEUED).into(),
_ => {
return Err(RedisError::new(
RedisErrorKind::InvalidArgument,
"Cannot convert to key.",
))
},
};
Ok(val)
}
}
impl From<Bytes> for RedisKey {
fn from(b: Bytes) -> Self {
RedisKey { key: b }
}
}
impl From<Box<[u8]>> for RedisKey {
fn from(b: Box<[u8]>) -> Self {
RedisKey { key: b.into() }
}
}
impl<'a> From<&'a [u8]> for RedisKey {
fn from(b: &'a [u8]) -> Self {
RedisKey { key: b.to_vec().into() }
}
}
impl From<String> for RedisKey {
fn from(s: String) -> Self {
RedisKey { key: s.into() }
}
}
impl From<&str> for RedisKey {
fn from(s: &str) -> Self {
RedisKey {
key: s.as_bytes().to_vec().into(),
}
}
}
impl From<&String> for RedisKey {
fn from(s: &String) -> Self {
RedisKey { key: s.clone().into() }
}
}
impl From<Str> for RedisKey {
fn from(s: Str) -> Self {
RedisKey { key: s.into_inner() }
}
}
impl From<&Str> for RedisKey {
fn from(s: &Str) -> Self {
RedisKey { key: s.inner().clone() }
}
}
impl From<&RedisKey> for RedisKey {
fn from(k: &RedisKey) -> RedisKey {
k.clone()
}
}
impl From<bool> for RedisKey {
fn from(b: bool) -> Self {
match b {
true => RedisKey::from_static_str("true"),
false => RedisKey::from_static_str("false"),
}
}
}
impl_from_str_for_redis_key!(u8);
impl_from_str_for_redis_key!(u16);
impl_from_str_for_redis_key!(u32);
impl_from_str_for_redis_key!(u64);
impl_from_str_for_redis_key!(u128);
impl_from_str_for_redis_key!(usize);
impl_from_str_for_redis_key!(i8);
impl_from_str_for_redis_key!(i16);
impl_from_str_for_redis_key!(i32);
impl_from_str_for_redis_key!(i64);
impl_from_str_for_redis_key!(i128);
impl_from_str_for_redis_key!(isize);
impl_from_str_for_redis_key!(f32);
impl_from_str_for_redis_key!(f64);
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RedisMap {
pub(crate) inner: HashMap<RedisKey, RedisValue>,
}
impl RedisMap {
pub fn new() -> Self {
RedisMap { inner: HashMap::new() }
}
pub fn take(&mut self) -> Self {
RedisMap {
inner: std::mem::take(&mut self.inner),
}
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn inner(self) -> HashMap<RedisKey, RedisValue> {
self.inner
}
}
impl Deref for RedisMap {
type Target = HashMap<RedisKey, RedisValue>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for RedisMap {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<'a> From<&'a RedisMap> for RedisMap {
fn from(vals: &'a RedisMap) -> Self {
vals.clone()
}
}
impl<K, V> TryFrom<HashMap<K, V>> for RedisMap
where
K: TryInto<RedisKey>,
K::Error: Into<RedisError>,
V: TryInto<RedisValue>,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(value: HashMap<K, V>) -> Result<Self, Self::Error> {
Ok(RedisMap {
inner: utils::into_redis_map(value.into_iter())?,
})
}
}
impl<K, V> TryFrom<BTreeMap<K, V>> for RedisMap
where
K: TryInto<RedisKey>,
K::Error: Into<RedisError>,
V: TryInto<RedisValue>,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(value: BTreeMap<K, V>) -> Result<Self, Self::Error> {
Ok(RedisMap {
inner: utils::into_redis_map(value.into_iter())?,
})
}
}
impl From<()> for RedisMap {
fn from(_: ()) -> Self {
RedisMap::new()
}
}
impl<K, V> TryFrom<(K, V)> for RedisMap
where
K: TryInto<RedisKey>,
K::Error: Into<RedisError>,
V: TryInto<RedisValue>,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from((key, value): (K, V)) -> Result<Self, Self::Error> {
let mut inner = HashMap::with_capacity(1);
inner.insert(to!(key)?, to!(value)?);
Ok(RedisMap { inner })
}
}
impl<K, V> TryFrom<Vec<(K, V)>> for RedisMap
where
K: TryInto<RedisKey>,
K::Error: Into<RedisError>,
V: TryInto<RedisValue>,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(values: Vec<(K, V)>) -> Result<Self, Self::Error> {
let mut inner = HashMap::with_capacity(values.len());
for (key, value) in values.into_iter() {
inner.insert(to!(key)?, to!(value)?);
}
Ok(RedisMap { inner })
}
}
impl<K, V, const N: usize> TryFrom<[(K, V); N]> for RedisMap
where
K: TryInto<RedisKey>,
K::Error: Into<RedisError>,
V: TryInto<RedisValue>,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(value: [(K, V); N]) -> Result<Self, Self::Error> {
let mut inner = HashMap::with_capacity(value.len());
for (key, value) in value.into_iter() {
inner.insert(to!(key)?, to!(value)?);
}
Ok(RedisMap { inner })
}
}
impl<'a, K, V, const N: usize> TryFrom<&'a [(K, V); N]> for RedisMap
where
K: TryInto<RedisKey> + Clone,
K::Error: Into<RedisError>,
V: TryInto<RedisValue> + Clone,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(value: &'a [(K, V); N]) -> Result<Self, Self::Error> {
let mut inner = HashMap::with_capacity(value.len());
for (key, value) in value.iter() {
let (key, value) = (key.clone(), value.clone());
inner.insert(to!(key)?, to!(value)?);
}
Ok(RedisMap { inner })
}
}
impl<K, V> TryFrom<VecDeque<(K, V)>> for RedisMap
where
K: TryInto<RedisKey>,
K::Error: Into<RedisError>,
V: TryInto<RedisValue>,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(values: VecDeque<(K, V)>) -> Result<Self, Self::Error> {
let mut inner = HashMap::with_capacity(values.len());
for (key, value) in values.into_iter() {
inner.insert(to!(key)?, to!(value)?);
}
Ok(RedisMap { inner })
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RedisValueKind {
Boolean,
Integer,
Double,
String,
Bytes,
Null,
Queued,
Map,
Array,
}
impl fmt::Display for RedisValueKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match *self {
RedisValueKind::Boolean => "Boolean",
RedisValueKind::Integer => "Integer",
RedisValueKind::Double => "Double",
RedisValueKind::String => "String",
RedisValueKind::Bytes => "Bytes",
RedisValueKind::Null => "nil",
RedisValueKind::Queued => "Queued",
RedisValueKind::Map => "Map",
RedisValueKind::Array => "Array",
};
write!(f, "{}", s)
}
}
#[derive(Clone, Debug)]
pub enum RedisValue {
Boolean(bool),
Integer(i64),
Double(f64),
String(Str),
Bytes(Bytes),
Null,
Queued,
Map(RedisMap),
Array(Vec<RedisValue>),
}
#[allow(clippy::match_like_matches_macro)]
impl PartialEq for RedisValue {
fn eq(&self, other: &Self) -> bool {
use RedisValue::*;
match self {
Boolean(ref s) => match other {
Boolean(ref o) => *s == *o,
_ => false,
},
Integer(ref s) => match other {
Integer(ref o) => *s == *o,
_ => false,
},
Double(ref s) => match other {
Double(ref o) => approx_eq!(f64, *s, *o, ulps = 2),
_ => false,
},
String(ref s) => match other {
String(ref o) => s == o,
_ => false,
},
Bytes(ref s) => match other {
Bytes(ref o) => s == o,
_ => false,
},
Null => match other {
Null => true,
_ => false,
},
Queued => match other {
Queued => true,
_ => false,
},
Map(ref s) => match other {
Map(ref o) => s == o,
_ => false,
},
Array(ref s) => match other {
Array(ref o) => s == o,
_ => false,
},
}
}
}
impl Eq for RedisValue {}
impl RedisValue {
pub fn from_static(b: &'static [u8]) -> Self {
RedisValue::Bytes(Bytes::from_static(b))
}
pub fn from_static_str(s: &'static str) -> Self {
RedisValue::String(utils::static_str(s))
}
pub fn new_ok() -> Self {
Self::from_static_str(OK)
}
pub fn is_ok(&self) -> bool {
match *self {
RedisValue::String(ref s) => *s == OK,
_ => false,
}
}
pub fn into_integer(self) -> Result<RedisValue, RedisValue> {
match self {
RedisValue::String(s) => match s.parse::<i64>() {
Ok(i) => Ok(RedisValue::Integer(i)),
Err(_) => Err(RedisValue::String(s)),
},
RedisValue::Integer(i) => Ok(RedisValue::Integer(i)),
_ => Err(self),
}
}
pub fn kind(&self) -> RedisValueKind {
match *self {
RedisValue::Boolean(_) => RedisValueKind::Boolean,
RedisValue::Integer(_) => RedisValueKind::Integer,
RedisValue::Double(_) => RedisValueKind::Double,
RedisValue::String(_) => RedisValueKind::String,
RedisValue::Bytes(_) => RedisValueKind::Bytes,
RedisValue::Null => RedisValueKind::Null,
RedisValue::Queued => RedisValueKind::Queued,
RedisValue::Map(_) => RedisValueKind::Map,
RedisValue::Array(_) => RedisValueKind::Array,
}
}
pub fn is_null(&self) -> bool {
matches!(*self, RedisValue::Null)
}
pub fn is_integer(&self) -> bool {
matches!(self, RedisValue::Integer(_))
}
pub fn is_string(&self) -> bool {
matches!(*self, RedisValue::String(_))
}
pub fn is_bytes(&self) -> bool {
matches!(*self, RedisValue::Bytes(_))
}
#[allow(clippy::match_like_matches_macro)]
pub fn is_boolean(&self) -> bool {
match *self {
RedisValue::Boolean(_) => true,
RedisValue::Integer(i) => match i {
0 | 1 => true,
_ => false,
},
RedisValue::String(ref s) => match s.as_bytes() {
b"true" | b"false" | b"t" | b"f" | b"TRUE" | b"FALSE" | b"T" | b"F" | b"1" | b"0" => true,
_ => false,
},
_ => false,
}
}
pub fn is_double(&self) -> bool {
match *self {
RedisValue::Double(_) => true,
RedisValue::String(ref s) => utils::redis_string_to_f64(s).is_ok(),
_ => false,
}
}
pub fn is_queued(&self) -> bool {
matches!(*self, RedisValue::Queued)
}
pub fn is_aggregate_type(&self) -> bool {
matches!(*self, RedisValue::Array(_) | RedisValue::Map(_))
}
pub fn is_map(&self) -> bool {
matches!(*self, RedisValue::Map(_))
}
pub fn is_maybe_map(&self) -> bool {
match *self {
RedisValue::Map(_) => true,
RedisValue::Array(ref arr) => utils::is_maybe_array_map(arr),
_ => false,
}
}
pub fn is_array(&self) -> bool {
matches!(*self, RedisValue::Array(_))
}
pub fn as_u64(&self) -> Option<u64> {
match self {
RedisValue::Integer(ref i) => {
if *i >= 0 {
Some(*i as u64)
} else {
None
}
},
RedisValue::String(ref s) => s.parse::<u64>().ok(),
RedisValue::Array(ref inner) => {
if inner.len() == 1 {
inner.first().and_then(|v| v.as_u64())
} else {
None
}
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(0),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
RedisValue::Integer(ref i) => Some(*i),
RedisValue::String(ref s) => s.parse::<i64>().ok(),
RedisValue::Array(ref inner) => {
if inner.len() == 1 {
inner.first().and_then(|v| v.as_i64())
} else {
None
}
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(0),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn as_usize(&self) -> Option<usize> {
match self {
RedisValue::Integer(i) => {
if *i >= 0 {
Some(*i as usize)
} else {
None
}
},
RedisValue::String(ref s) => s.parse::<usize>().ok(),
RedisValue::Array(ref inner) => {
if inner.len() == 1 {
inner.first().and_then(|v| v.as_usize())
} else {
None
}
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(0),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
RedisValue::Double(ref f) => Some(*f),
RedisValue::String(ref s) => utils::redis_string_to_f64(s).ok(),
RedisValue::Integer(ref i) => Some(*i as f64),
RedisValue::Array(ref inner) => {
if inner.len() == 1 {
inner.first().and_then(|v| v.as_f64())
} else {
None
}
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(0.0),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn into_string(self) -> Option<String> {
match self {
RedisValue::Boolean(b) => Some(b.to_string()),
RedisValue::Double(f) => Some(f.to_string()),
RedisValue::String(s) => Some(s.to_string()),
RedisValue::Bytes(b) => String::from_utf8(b.to_vec()).ok(),
RedisValue::Integer(i) => Some(i.to_string()),
RedisValue::Queued => Some(QUEUED.to_owned()),
RedisValue::Array(mut inner) => {
if inner.len() == 1 {
inner.pop().and_then(|v| v.into_string())
} else {
None
}
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(String::new()),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn into_bytes_str(self) -> Option<Str> {
match self {
RedisValue::Boolean(b) => match b {
true => Some(TRUE_STR.clone()),
false => Some(FALSE_STR.clone()),
},
RedisValue::Double(f) => Some(f.to_string().into()),
RedisValue::String(s) => Some(s),
RedisValue::Bytes(b) => Str::from_inner(b).ok(),
RedisValue::Integer(i) => Some(i.to_string().into()),
RedisValue::Queued => Some(utils::static_str(QUEUED)),
RedisValue::Array(mut inner) => {
if inner.len() == 1 {
inner.pop().and_then(|v| v.into_bytes_str())
} else {
None
}
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(Str::new()),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn as_bytes_str(&self) -> Option<Str> {
match self {
RedisValue::Boolean(ref b) => match *b {
true => Some(TRUE_STR.clone()),
false => Some(FALSE_STR.clone()),
},
RedisValue::Double(ref f) => Some(f.to_string().into()),
RedisValue::String(ref s) => Some(s.clone()),
RedisValue::Bytes(ref b) => Str::from_inner(b.clone()).ok(),
RedisValue::Integer(ref i) => Some(i.to_string().into()),
RedisValue::Queued => Some(utils::static_str(QUEUED)),
RedisValue::Array(ref inner) => {
if inner.len() == 1 {
inner[0].as_bytes_str()
} else {
None
}
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(Str::new()),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn as_string(&self) -> Option<String> {
match self {
RedisValue::Boolean(ref b) => Some(b.to_string()),
RedisValue::Double(ref f) => Some(f.to_string()),
RedisValue::String(ref s) => Some(s.to_string()),
RedisValue::Bytes(ref b) => str::from_utf8(b).ok().map(|s| s.to_owned()),
RedisValue::Integer(ref i) => Some(i.to_string()),
RedisValue::Queued => Some(QUEUED.to_owned()),
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(String::new()),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn as_str(&self) -> Option<Cow<str>> {
let s: Cow<str> = match *self {
RedisValue::Double(ref f) => Cow::Owned(f.to_string()),
RedisValue::Boolean(ref b) => Cow::Owned(b.to_string()),
RedisValue::String(ref s) => Cow::Borrowed(s.deref()),
RedisValue::Integer(ref i) => Cow::Owned(i.to_string()),
RedisValue::Queued => Cow::Borrowed(QUEUED),
RedisValue::Bytes(ref b) => return str::from_utf8(b).ok().map(Cow::Borrowed),
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Cow::Borrowed(""),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => return None,
_ => return None,
};
Some(s)
}
pub fn as_str_lossy(&self) -> Option<Cow<str>> {
let s: Cow<str> = match *self {
RedisValue::Boolean(ref b) => Cow::Owned(b.to_string()),
RedisValue::Double(ref f) => Cow::Owned(f.to_string()),
RedisValue::String(ref s) => Cow::Borrowed(s.deref()),
RedisValue::Integer(ref i) => Cow::Owned(i.to_string()),
RedisValue::Queued => Cow::Borrowed(QUEUED),
RedisValue::Bytes(ref b) => String::from_utf8_lossy(b),
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Cow::Borrowed(""),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => return None,
_ => return None,
};
Some(s)
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match *self {
RedisValue::String(ref s) => Some(s.as_bytes()),
RedisValue::Bytes(ref b) => Some(b),
RedisValue::Queued => Some(QUEUED.as_bytes()),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match *self {
RedisValue::Boolean(b) => Some(b),
RedisValue::Integer(ref i) => match *i {
0 => Some(false),
1 => Some(true),
_ => None,
},
RedisValue::String(ref s) => match s.as_bytes() {
b"true" | b"TRUE" | b"t" | b"T" | b"1" => Some(true),
b"false" | b"FALSE" | b"f" | b"F" | b"0" => Some(false),
_ => None,
},
RedisValue::Array(ref inner) => {
if inner.len() == 1 {
inner.first().and_then(|v| v.as_bool())
} else {
None
}
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Some(false),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => None,
_ => None,
}
}
pub fn into_map(self) -> Result<RedisMap, RedisError> {
match self {
RedisValue::Map(map) => Ok(map),
RedisValue::Array(mut values) => {
if values.len() % 2 != 0 {
return Err(RedisError::new(
RedisErrorKind::Unknown,
"Expected an even number of elements.",
));
}
let mut inner = HashMap::with_capacity(values.len() / 2);
while values.len() >= 2 {
let value = values.pop().unwrap();
let key: RedisKey = values.pop().unwrap().try_into()?;
inner.insert(key, value);
}
Ok(RedisMap { inner })
},
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Ok(RedisMap::new()),
_ => Err(RedisError::new(RedisErrorKind::Unknown, "Could not convert to map.")),
}
}
pub(crate) fn into_multiple_values(self) -> Vec<RedisValue> {
match self {
RedisValue::Array(values) => values,
RedisValue::Map(map) => map
.inner()
.into_iter()
.flat_map(|(k, v)| [RedisValue::Bytes(k.into_bytes()), v])
.collect(),
RedisValue::Null => Vec::new(),
_ => vec![self],
}
}
pub fn into_set(self) -> Result<HashSet<RedisValue>, RedisError> {
match self {
RedisValue::Array(values) => Ok(values.into_iter().collect()),
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Ok(HashSet::new()),
_ => Err(RedisError::new_parse("Could not convert to set.")),
}
}
pub fn into_zset_result(self) -> Result<Vec<(RedisValue, f64)>, RedisError> {
protocol_utils::value_to_zset_result(self)
}
pub fn into_array(self) -> Vec<RedisValue> {
match self {
RedisValue::Array(values) => values,
RedisValue::Map(map) => {
let mut out = Vec::with_capacity(map.len() * 2);
for (key, value) in map.inner().into_iter() {
out.push(key.into());
out.push(value);
}
out
},
_ => vec![self],
}
}
pub fn into_owned_bytes(self) -> Option<Vec<u8>> {
let v = match self {
RedisValue::String(s) => s.to_string().into_bytes(),
RedisValue::Bytes(b) => b.to_vec(),
RedisValue::Queued => QUEUED.as_bytes().to_vec(),
RedisValue::Array(mut inner) => {
if inner.len() == 1 {
return inner.pop().and_then(|v| v.into_owned_bytes());
} else {
return None;
}
},
RedisValue::Integer(i) => i.to_string().into_bytes(),
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Vec::new(),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => return None,
_ => return None,
};
Some(v)
}
pub fn into_bytes(self) -> Option<Bytes> {
let v = match self {
RedisValue::String(s) => s.inner().clone(),
RedisValue::Bytes(b) => b,
RedisValue::Queued => Bytes::from_static(QUEUED.as_bytes()),
RedisValue::Array(mut inner) => {
if inner.len() == 1 {
return inner.pop().and_then(|v| v.into_bytes());
} else {
return None;
}
},
RedisValue::Integer(i) => i.to_string().into(),
#[cfg(feature = "default-nil-types")]
RedisValue::Null => Bytes::new(),
#[cfg(not(feature = "default-nil-types"))]
RedisValue::Null => return None,
_ => return None,
};
Some(v)
}
pub fn array_len(&self) -> Option<usize> {
match self {
RedisValue::Array(ref a) => Some(a.len()),
_ => None,
}
}
pub(crate) fn is_single_element_vec(&self) -> bool {
if let RedisValue::Array(ref d) = self {
d.len() == 1
} else {
false
}
}
pub(crate) fn pop_or_take(self) -> Self {
if let RedisValue::Array(mut values) = self {
values.pop().unwrap()
} else {
self
}
}
pub fn flatten_array_values(self, depth: usize) -> Self {
utils::flatten_nested_array_values(self, depth)
}
#[cfg(feature = "i-streams")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-streams")))]
pub fn into_xread_response<K1, I, K2, V>(self) -> Result<XReadResponse<K1, I, K2, V>, RedisError>
where
K1: FromRedisKey + Hash + Eq,
K2: FromRedisKey + Hash + Eq,
I: FromRedis,
V: FromRedis,
{
self.flatten_array_values(2).convert()
}
#[cfg(feature = "i-streams")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-streams")))]
pub fn into_xread_value<I, K, V>(self) -> Result<Vec<XReadValue<I, K, V>>, RedisError>
where
K: FromRedisKey + Hash + Eq,
I: FromRedis,
V: FromRedis,
{
self.flatten_array_values(1).convert()
}
#[cfg(feature = "i-streams")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-streams")))]
pub fn into_xautoclaim_values<I, K, V>(self) -> Result<(String, Vec<XReadValue<I, K, V>>), RedisError>
where
K: FromRedisKey + Hash + Eq,
I: FromRedis,
V: FromRedis,
{
if let RedisValue::Array(mut values) = self {
if values.len() == 3 {
trace!("Removing the third message PID elements from XAUTOCLAIM response.");
values.pop();
}
let entries = values.pop().unwrap();
let cursor: String = values.pop().unwrap().convert()?;
Ok((cursor, entries.flatten_array_values(1).convert()?))
} else {
Err(RedisError::new_parse("Expected array response."))
}
}
#[cfg(feature = "i-scripts")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-scripts")))]
pub fn as_functions(&self, name: &str) -> Result<Vec<Function>, RedisError> {
utils::value_to_functions(self, name)
}
#[cfg(feature = "i-geo")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-geo")))]
pub fn as_geo_position(&self) -> Result<Option<GeoPosition>, RedisError> {
if self.is_null() {
Ok(None)
} else {
GeoPosition::try_from(self.clone()).map(Some)
}
}
#[cfg(feature = "i-geo")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-geo")))]
pub fn into_geo_radius_result(
self,
withcoord: bool,
withdist: bool,
withhash: bool,
) -> Result<Vec<GeoRadiusInfo>, RedisError> {
match self {
RedisValue::Array(data) => data
.into_iter()
.map(|value| GeoRadiusInfo::from_redis_value(value, withcoord, withdist, withhash))
.collect(),
RedisValue::Null => Ok(Vec::new()),
_ => Err(RedisError::new(RedisErrorKind::Parse, "Expected array.")),
}
}
pub fn take(&mut self) -> RedisValue {
mem::replace(self, RedisValue::Null)
}
pub fn convert<R>(self) -> Result<R, RedisError>
where
R: FromRedis,
{
R::from_value(self)
}
pub fn can_hash(&self) -> bool {
matches!(
self.kind(),
RedisValueKind::String
| RedisValueKind::Boolean
| RedisValueKind::Double
| RedisValueKind::Integer
| RedisValueKind::Bytes
| RedisValueKind::Null
| RedisValueKind::Array
| RedisValueKind::Queued
)
}
#[cfg(feature = "serde-json")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde-json")))]
pub fn into_json(self) -> Result<Value, RedisError> {
Value::from_value(self)
}
}
impl Hash for RedisValue {
fn hash<H: Hasher>(&self, state: &mut H) {
let prefix = match self.kind() {
RedisValueKind::Boolean => b'B',
RedisValueKind::Double => b'd',
RedisValueKind::Integer => b'i',
RedisValueKind::String => b's',
RedisValueKind::Null => b'n',
RedisValueKind::Queued => b'q',
RedisValueKind::Array => b'a',
RedisValueKind::Map => b'm',
RedisValueKind::Bytes => b'b',
};
prefix.hash(state);
match *self {
RedisValue::Boolean(b) => b.hash(state),
RedisValue::Double(f) => f.to_be_bytes().hash(state),
RedisValue::Integer(d) => d.hash(state),
RedisValue::String(ref s) => s.hash(state),
RedisValue::Bytes(ref b) => b.hash(state),
RedisValue::Null => NULL.hash(state),
RedisValue::Queued => QUEUED.hash(state),
RedisValue::Array(ref arr) => {
for value in arr.iter() {
value.hash(state);
}
},
_ => panic!("Cannot hash aggregate value."),
}
}
}
impl From<u8> for RedisValue {
fn from(d: u8) -> Self {
RedisValue::Integer(d as i64)
}
}
impl From<u16> for RedisValue {
fn from(d: u16) -> Self {
RedisValue::Integer(d as i64)
}
}
impl From<u32> for RedisValue {
fn from(d: u32) -> Self {
RedisValue::Integer(d as i64)
}
}
impl From<i8> for RedisValue {
fn from(d: i8) -> Self {
RedisValue::Integer(d as i64)
}
}
impl From<i16> for RedisValue {
fn from(d: i16) -> Self {
RedisValue::Integer(d as i64)
}
}
impl From<i32> for RedisValue {
fn from(d: i32) -> Self {
RedisValue::Integer(d as i64)
}
}
impl From<i64> for RedisValue {
fn from(d: i64) -> Self {
RedisValue::Integer(d)
}
}
impl From<f32> for RedisValue {
fn from(f: f32) -> Self {
RedisValue::Double(f as f64)
}
}
impl From<f64> for RedisValue {
fn from(f: f64) -> Self {
RedisValue::Double(f)
}
}
impl TryFrom<u64> for RedisValue {
type Error = RedisError;
fn try_from(d: u64) -> Result<Self, Self::Error> {
if d >= (i64::MAX as u64) {
return Err(RedisError::new(RedisErrorKind::Unknown, "Unsigned integer too large."));
}
Ok((d as i64).into())
}
}
impl TryFrom<u128> for RedisValue {
type Error = RedisError;
fn try_from(d: u128) -> Result<Self, Self::Error> {
if d >= (i64::MAX as u128) {
return Err(RedisError::new(RedisErrorKind::Unknown, "Unsigned integer too large."));
}
Ok((d as i64).into())
}
}
impl TryFrom<i128> for RedisValue {
type Error = RedisError;
fn try_from(d: i128) -> Result<Self, Self::Error> {
if d >= (i64::MAX as i128) {
return Err(RedisError::new(RedisErrorKind::Unknown, "Signed integer too large."));
}
Ok((d as i64).into())
}
}
impl TryFrom<usize> for RedisValue {
type Error = RedisError;
fn try_from(d: usize) -> Result<Self, Self::Error> {
if d >= (i64::MAX as usize) {
return Err(RedisError::new(RedisErrorKind::Unknown, "Unsigned integer too large."));
}
Ok((d as i64).into())
}
}
impl From<Str> for RedisValue {
fn from(s: Str) -> Self {
RedisValue::String(s)
}
}
impl From<Bytes> for RedisValue {
fn from(b: Bytes) -> Self {
RedisValue::Bytes(b)
}
}
impl From<&Box<[u8]>> for RedisValue {
fn from(b: &Box<[u8]>) -> Self {
b.into()
}
}
impl From<Box<[u8]>> for RedisValue {
fn from(b: Box<[u8]>) -> Self {
RedisValue::Bytes(b.into())
}
}
impl From<String> for RedisValue {
fn from(d: String) -> Self {
RedisValue::String(Str::from(d))
}
}
impl<'a> From<&'a String> for RedisValue {
fn from(d: &'a String) -> Self {
RedisValue::String(Str::from(d))
}
}
impl<'a> From<&'a str> for RedisValue {
fn from(d: &'a str) -> Self {
RedisValue::String(Str::from(d))
}
}
impl<'a> From<&'a [u8]> for RedisValue {
fn from(b: &'a [u8]) -> Self {
RedisValue::Bytes(Bytes::from(b.to_vec()))
}
}
impl From<bool> for RedisValue {
fn from(d: bool) -> Self {
RedisValue::Boolean(d)
}
}
impl<T> TryFrom<Option<T>> for RedisValue
where
T: TryInto<RedisValue>,
T::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(d: Option<T>) -> Result<Self, Self::Error> {
match d {
Some(i) => to!(i),
None => Ok(RedisValue::Null),
}
}
}
impl<'a, T, const N: usize> TryFrom<&'a [T; N]> for RedisValue
where
T: TryInto<RedisValue> + Clone,
T::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(value: &'a [T; N]) -> Result<Self, Self::Error> {
let values = value
.iter()
.map(|v| v.clone().try_into().map_err(|e| e.into()))
.collect::<Result<Vec<RedisValue>, RedisError>>()?;
Ok(RedisValue::Array(values))
}
}
impl<T, const N: usize> TryFrom<[T; N]> for RedisValue
where
T: TryInto<RedisValue> + Clone,
T::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(value: [T; N]) -> Result<Self, Self::Error> {
let values = value
.into_iter()
.map(|v| v.try_into().map_err(|e| e.into()))
.collect::<Result<Vec<RedisValue>, RedisError>>()?;
Ok(RedisValue::Array(values))
}
}
impl<T> TryFrom<Vec<T>> for RedisValue
where
T: TryInto<RedisValue>,
T::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
let values = value
.into_iter()
.map(|v| v.try_into().map_err(|e| e.into()))
.collect::<Result<Vec<RedisValue>, RedisError>>()?;
Ok(RedisValue::Array(values))
}
}
impl<T> TryFrom<VecDeque<T>> for RedisValue
where
T: TryInto<RedisValue>,
T::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(value: VecDeque<T>) -> Result<Self, Self::Error> {
let values = value
.into_iter()
.map(|v| v.try_into().map_err(|e| e.into()))
.collect::<Result<Vec<RedisValue>, RedisError>>()?;
Ok(RedisValue::Array(values))
}
}
impl<V> FromIterator<V> for RedisValue
where
V: Into<RedisValue>,
{
fn from_iter<I: IntoIterator<Item = V>>(iter: I) -> Self {
RedisValue::Array(iter.into_iter().map(|v| v.into()).collect())
}
}
impl<K, V> TryFrom<HashMap<K, V>> for RedisValue
where
K: TryInto<RedisKey>,
K::Error: Into<RedisError>,
V: TryInto<RedisValue>,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(d: HashMap<K, V>) -> Result<Self, Self::Error> {
Ok(RedisValue::Map(RedisMap {
inner: utils::into_redis_map(d.into_iter())?,
}))
}
}
impl<K, V> TryFrom<BTreeMap<K, V>> for RedisValue
where
K: TryInto<RedisKey>,
K::Error: Into<RedisError>,
V: TryInto<RedisValue>,
V::Error: Into<RedisError>,
{
type Error = RedisError;
fn try_from(d: BTreeMap<K, V>) -> Result<Self, Self::Error> {
Ok(RedisValue::Map(RedisMap {
inner: utils::into_redis_map(d.into_iter())?,
}))
}
}
impl From<RedisKey> for RedisValue {
fn from(d: RedisKey) -> Self {
RedisValue::Bytes(d.key)
}
}
impl From<RedisMap> for RedisValue {
fn from(m: RedisMap) -> Self {
RedisValue::Map(m)
}
}
impl From<()> for RedisValue {
fn from(_: ()) -> Self {
RedisValue::Null
}
}
impl TryFrom<Resp3Frame> for RedisValue {
type Error = RedisError;
fn try_from(value: Resp3Frame) -> Result<Self, Self::Error> {
protocol_utils::frame_to_results(value)
}
}