use crate::error::{Error, Result};
pub const BE_LEN: usize = 8;
pub const ERR_MIN_NOT_INT: &str = "ERR the min isn't integer";
pub const ERR_MAX_NOT_INT: &str = "ERR the max isn't integer";
pub const ERR_MIN_GT_MAX: &str = "ERR min > max";
pub use crate::error::ERR_WRONG_TYPE;
#[derive(Debug, Clone, PartialEq, Eq, bitcode::Encode, bitcode::Decode)]
pub struct SortedintRangeSpec {
pub min: u64,
pub max: u64,
pub minex: bool,
pub maxex: bool,
pub offset: usize,
pub count: Option<usize>,
pub reversed: bool,
}
impl Default for SortedintRangeSpec {
#[inline]
fn default() -> Self {
Self {
min: u64::MIN,
max: u64::MAX,
minex: false,
maxex: false,
offset: 0,
count: None,
reversed: false,
}
}
}
impl SortedintRangeSpec {
#[inline]
pub const fn all() -> Self {
Self {
min: u64::MIN,
max: u64::MAX,
minex: false,
maxex: false,
offset: 0,
count: None,
reversed: false,
}
}
#[inline]
pub const fn with_offset(mut self, offset: usize) -> Self {
self.offset = offset;
self
}
#[inline]
pub const fn with_count(mut self, count: usize) -> Self {
self.count = Some(count);
self
}
#[inline]
pub const fn with_reversed(mut self, reversed: bool) -> Self {
self.reversed = reversed;
self
}
#[inline]
pub const fn with_min(mut self, min: u64, minex: bool) -> Self {
self.min = min;
self.minex = minex;
self
}
#[inline]
pub const fn with_max(mut self, max: u64, maxex: bool) -> Self {
self.max = max;
self.maxex = maxex;
self
}
#[inline]
pub const fn is_empty_range(&self) -> bool {
if self.min > self.max {
return true;
}
if self.min == self.max && (self.minex || self.maxex) {
return true;
}
if self.minex && self.min == u64::MAX {
return true;
}
if self.maxex && self.max == 0 {
return true;
}
false
}
#[inline]
pub const fn contains(&self, val: u64) -> bool {
if self.minex {
if val <= self.min {
return false;
}
} else if val < self.min {
return false;
}
if self.maxex {
if val >= self.max {
return false;
}
} else if val > self.max {
return false;
}
true
}
}
#[inline]
fn parse_bound(s: &str, is_min: bool) -> Result<(u64, bool)> {
let (num_str, ex) = if let Some(stripped) = s.strip_prefix('(') {
(stripped, true)
} else if let Some(stripped) = s.strip_prefix('[') {
(stripped, false)
} else {
(s, false)
};
let num_str = num_str.strip_prefix('+').unwrap_or(num_str);
let val = num_str.parse::<u64>().map_err(|_| {
if is_min {
Error::redis(ERR_MIN_NOT_INT)
} else {
Error::redis(ERR_MAX_NOT_INT)
}
})?;
Ok((val, ex))
}
pub fn parse_range_spec(min_str: &str, max_str: &str) -> Result<SortedintRangeSpec> {
let min_str = min_str.trim();
let max_str = max_str.trim();
if min_str == "+inf" || max_str == "-inf" {
return Err(Error::redis(ERR_MIN_GT_MAX));
}
let (min, minex) = if min_str == "-inf" {
(u64::MIN, false)
} else {
parse_bound(min_str, true)?
};
let (max, maxex) = if max_str == "+inf" {
(u64::MAX, false)
} else {
parse_bound(max_str, false)?
};
Ok(SortedintRangeSpec {
min,
max,
minex,
maxex,
offset: 0,
count: None,
reversed: false,
})
}
#[inline(always)]
pub const fn encode_be_u64(val: u64) -> [u8; 8] {
val.to_be_bytes()
}
#[inline(always)]
pub const fn decode_be_u64(bytes: &[u8]) -> Option<u64> {
if bytes.len() < 8 {
return None;
}
let buf = [
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
];
Some(u64::from_be_bytes(buf))
}