#[cfg(not(feature = "std"))]
use crate::nostd_prelude::*;
use crate::string_set::pick_value_for_set_owned;
use crate::util::{fmt_num, format_i64_into, itoa_i64_stack, parse_f64};
use crate::value::{SmallBytes, Value};
use crate::{Entry, Store, StoreError};
impl Store {
pub fn append(&mut self, key: &[u8], data: &[u8]) -> Result<usize, StoreError> {
self.tier_resolve(key, crate::value::COLD_TAG_STRING)?; let outcome = match self.live_entry_mut(key) {
Some(e) => match &mut e.value {
Value::Str(v) => {
let mut owned = core::mem::take(v).into_vec();
owned.extend_from_slice(data);
let new_len = owned.len();
*v = SmallBytes::from_vec(owned);
AppendOutcome::Reweigh(new_len)
}
Value::Int(n) => {
let mut buf = itoa_i64_stack();
let mut owned = format_i64_into(*n, &mut buf).to_vec();
owned.extend_from_slice(data);
let new_len = owned.len();
e.value = pick_value_for_set_owned(owned);
AppendOutcome::Reweigh(new_len)
}
Value::ArcBulk(a) => {
let mut owned: Vec<u8> = a.as_ref().to_vec();
owned.extend_from_slice(data);
let new_len = owned.len();
e.value = pick_value_for_set_owned(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 getset(&mut self, key: &[u8], val: Vec<u8>) -> Result<Option<Vec<u8>>, StoreError> {
self.tier_resolve(key, crate::value::COLD_TAG_STRING)?;
let old = match self.live_entry(key) {
Some(e) => match &e.value {
Value::Str(v) => Some(v.to_vec()),
Value::Int(n) => {
let mut buf = itoa_i64_stack();
Some(format_i64_into(*n, &mut buf).to_vec())
}
Value::ArcBulk(a) => Some(a.as_ref().to_vec()),
_ => return Err(StoreError::WrongType),
},
None => None,
};
self.insert_entry(
SmallBytes::from_slice(key),
Entry::new(pick_value_for_set_owned(val), None),
);
Ok(old)
}
pub fn getdel(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>, StoreError> {
self.tier_resolve(key, crate::value::COLD_TAG_STRING)?;
match self.live_entry(key) {
None => return Ok(None),
Some(e) => match &e.value {
Value::Str(_) | Value::Int(_) | Value::ArcBulk(_) => {}
_ => return Err(StoreError::WrongType),
},
}
match self.remove_entry(key) {
Some(Entry {
value: Value::Str(v),
..
}) => Ok(Some(v.into_vec())),
Some(Entry {
value: Value::Int(n),
..
}) => {
let mut buf = itoa_i64_stack();
Ok(Some(format_i64_into(n, &mut buf).to_vec()))
}
Some(Entry {
value: Value::ArcBulk(a),
..
}) => Ok(Some(a.as_ref().to_vec())),
_ => Ok(None),
}
}
pub fn incr_by_float(&mut self, key: &[u8], delta: f64) -> Result<Vec<u8>, StoreError> {
self.tier_resolve(key, crate::value::COLD_TAG_STRING)?;
let outcome = if let Some(e) = self.live_entry_mut(key) { match &mut e.value {
Value::Str(v) => {
let cur = parse_f64(v.as_slice()).ok_or(StoreError::NotFloat)?;
let bytes = float_incr_bytes(cur, delta)?;
*v = SmallBytes::from_slice(&bytes);
FloatOutcome::Reweigh(bytes)
}
Value::Int(n) => {
let bytes = float_incr_bytes(*n as f64, delta)?;
e.value = Value::Str(SmallBytes::from_slice(&bytes));
FloatOutcome::Reweigh(bytes)
}
Value::ArcBulk(a) => {
let cur = parse_f64(a.as_ref()).ok_or(StoreError::NotFloat)?;
let bytes = float_incr_bytes(cur, delta)?;
e.value = Value::Str(SmallBytes::from_slice(&bytes));
FloatOutcome::Reweigh(bytes)
}
_ => return Err(StoreError::WrongType),
} } else {
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 FloatOutcome {
Reweigh(Vec<u8>),
Insert(Vec<u8>),
}
#[inline]
fn float_incr_bytes(cur: f64, delta: f64) -> Result<Vec<u8>, StoreError> {
let next = cur + delta;
if !next.is_finite() {
return Err(StoreError::NotFloat);
}
Ok(fmt_num(next))
}