use crate::util::*;
use crate::value::*;
use crate::{Entry, Store, StoreError};
use std::time::{Duration, Instant};
impl Store {
pub fn set(
&mut self,
key: &[u8],
value: Vec<u8>,
expire: Option<Duration>,
nx: bool,
xx: bool,
) -> bool {
let expire_at = expire.map(|d| Instant::now() + d);
let new_value = Value::Str(SmallBytes::from_vec(value));
let pending_insert = match self.live_entry_mut(key) {
Some(e) => {
if nx {
return false;
}
e.value = new_value;
e.expire_at_ns = expire_at.and_then(crate::pack_deadline);
None
}
None => {
if xx {
return false;
}
Some(Entry::new(new_value, expire_at))
}
};
match pending_insert {
None => self.reweigh_entry(key),
Some(entry) => {
self.insert_entry(SmallBytes::from_slice(key), entry);
}
}
true
}
pub fn get(&mut self, key: &[u8]) -> Result<Option<&[u8]>, StoreError> {
match self.live_entry(key) {
None => Ok(None),
Some(e) => match &e.value {
Value::Str(v) => Ok(Some(v.as_slice())),
_ => Err(StoreError::WrongType),
},
}
}
pub fn strlen(&mut self, key: &[u8]) -> Result<usize, StoreError> {
Ok(self.get(key)?.map_or(0, |v| v.len()))
}
pub fn append(&mut self, key: &[u8], data: &[u8]) -> Result<usize, StoreError> {
let outcome = match self.live_entry_mut(key) {
Some(e) => match &mut e.value {
Value::Str(v) => {
let mut owned = std::mem::take(v).into_vec();
owned.extend_from_slice(data);
let new_len = owned.len();
*v = SmallBytes::from_vec(owned);
AppendOutcome::Reweigh(new_len)
}
_ => return Err(StoreError::WrongType),
},
None => AppendOutcome::Insert,
};
match outcome {
AppendOutcome::Reweigh(new_len) => {
self.reweigh_entry(key);
Ok(new_len)
}
AppendOutcome::Insert => {
self.insert_entry(
SmallBytes::from_slice(key),
Entry::new(Value::Str(SmallBytes::from_slice(data)), None),
);
Ok(data.len())
}
}
}
pub fn incr_by(&mut self, key: &[u8], delta: i64) -> Result<i64, StoreError> {
let outcome = match self.live_entry_mut(key) {
Some(e) => match &mut e.value {
Value::Str(v) => {
let next = parse_i64(v.as_slice())
.ok_or(StoreError::NotInteger)?
.checked_add(delta)
.ok_or(StoreError::Overflow)?;
*v = SmallBytes::from_vec(next.to_string().into_bytes());
IncrOutcome::Reweigh(next)
}
_ => return Err(StoreError::WrongType),
},
None => IncrOutcome::Insert(delta),
};
match outcome {
IncrOutcome::Reweigh(next) => {
self.reweigh_entry(key);
Ok(next)
}
IncrOutcome::Insert(next) => {
self.insert_entry(
SmallBytes::from_slice(key),
Entry::new(
Value::Str(SmallBytes::from_vec(next.to_string().into_bytes())),
None,
),
);
Ok(next)
}
}
}
pub fn getset(&mut self, key: &[u8], val: Vec<u8>) -> Result<Option<Vec<u8>>, StoreError> {
let old = match self.live_entry(key) {
Some(e) => match &e.value {
Value::Str(v) => Some(v.to_vec()),
_ => return Err(StoreError::WrongType),
},
None => None,
};
self.insert_entry(
SmallBytes::from_slice(key),
Entry::new(Value::Str(SmallBytes::from_vec(val)), None),
);
Ok(old)
}
pub fn getdel(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>, StoreError> {
let is_str = match self.live_entry(key) {
None => return Ok(None),
Some(e) => matches!(e.value, Value::Str(_)),
};
if !is_str {
return Err(StoreError::WrongType);
}
match self.remove_entry(key) {
Some(Entry {
value: Value::Str(v),
..
}) => Ok(Some(v.into_vec())),
_ => Ok(None),
}
}
pub fn incr_by_float(&mut self, key: &[u8], delta: f64) -> Result<Vec<u8>, StoreError> {
let outcome = match self.live_entry_mut(key) {
Some(e) => match &mut e.value {
Value::Str(v) => {
let next = parse_f64(v.as_slice()).ok_or(StoreError::NotFloat)? + delta;
if !next.is_finite() {
return Err(StoreError::NotFloat);
}
let bytes = fmt_num(next);
*v = SmallBytes::from_slice(&bytes);
FloatOutcome::Reweigh(bytes)
}
_ => return Err(StoreError::WrongType),
},
None => {
if !delta.is_finite() {
return Err(StoreError::NotFloat);
}
FloatOutcome::Insert(fmt_num(delta))
}
};
match outcome {
FloatOutcome::Reweigh(bytes) => {
self.reweigh_entry(key);
Ok(bytes)
}
FloatOutcome::Insert(bytes) => {
self.insert_entry(
SmallBytes::from_slice(key),
Entry::new(Value::Str(SmallBytes::from_slice(&bytes)), None),
);
Ok(bytes)
}
}
}
}
enum AppendOutcome {
Reweigh(usize),
Insert,
}
enum IncrOutcome {
Reweigh(i64),
Insert(i64),
}
enum FloatOutcome {
Reweigh(Vec<u8>),
Insert(Vec<u8>),
}