use wdev::Device;
use super::super::storage_session::StorageSession;
use crate::api::garnet_status::GarnetStatus;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitmapOp {
And,
Or,
Xor,
Not,
}
#[derive(Debug, Clone, Copy)]
pub enum BitFieldOp {
Get {
is_signed: bool,
bits: u8,
offset: u64,
},
Set {
is_signed: bool,
bits: u8,
offset: u64,
value: i64,
wrap: bool,
sat: bool,
},
IncrBy {
is_signed: bool,
bits: u8,
offset: u64,
increment: i64,
wrap: bool,
sat: bool,
},
}
impl<'a, D: Device> StorageSession<'a, D> {
pub async fn string_set_bit(
&self,
key: &[u8],
offset: u64,
bit: u8,
) -> wkv::Result<(GarnetStatus, u8)> {
let byte_idx = (offset / 8) as usize;
let mut buf = self.read_string(key).await?.unwrap_or_default();
if buf.len() <= byte_idx {
buf.resize(byte_idx + 1, 0);
}
let mask = 0x80u8 >> (offset % 8);
let old = u8::from(buf[byte_idx] & mask != 0);
if bit != 0 {
buf[byte_idx] |= mask;
} else {
buf[byte_idx] &= !mask;
}
self.upsert_string(key, &buf).await?;
Ok((GarnetStatus::Ok, old))
}
pub async fn string_get_bit(&self, key: &[u8], offset: u64) -> wkv::Result<(GarnetStatus, u8)> {
let Some(buf) = self.read_string(key).await? else {
return Ok((GarnetStatus::NotFound, 0));
};
let byte_idx = (offset / 8) as usize;
if byte_idx >= buf.len() {
return Ok((GarnetStatus::Ok, 0));
}
let bit = u8::from(buf[byte_idx] & (0x80u8 >> (offset % 8)) != 0);
Ok((GarnetStatus::Ok, bit))
}
pub async fn string_bit_operation(
&self,
op: BitmapOp,
dest: &[u8],
keys: &[&[u8]],
) -> wkv::Result<(GarnetStatus, usize)> {
if op == BitmapOp::Not {
let Some(key) = keys.first() else {
return Ok((GarnetStatus::NotFound, 0));
};
let flipped: Vec<u8> = self
.read_string(key)
.await?
.unwrap_or_default()
.iter()
.map(|b| !b)
.collect();
let len = flipped.len();
self.upsert_string(dest, &flipped).await?;
return Ok((GarnetStatus::Ok, len));
}
let mut acc: Vec<u8> = Vec::new();
for key in keys {
let buf = self.read_string(key).await?.unwrap_or_default();
let long = acc.len().max(buf.len());
let mut merged = vec![0u8; long];
for (i, slot) in merged.iter_mut().enumerate() {
let x = acc.get(i).copied().unwrap_or(0);
let y = buf.get(i).copied().unwrap_or(0);
*slot = match op {
BitmapOp::And => x & y,
BitmapOp::Or => x | y,
BitmapOp::Xor => x ^ y,
BitmapOp::Not => unreachable!("NOT 分支已提前返回"),
};
}
acc = merged;
}
let len = acc.len();
self.upsert_string(dest, &acc).await?;
Ok((GarnetStatus::Ok, len))
}
pub fn release_overflow_buffers(&self) {}
pub async fn string_bit_count(
&self,
key: &[u8],
start: i64,
end: i64,
bit_mode: bool,
) -> wkv::Result<(GarnetStatus, u64)> {
let Some(buf) = self.read_string(key).await? else {
return Ok((GarnetStatus::NotFound, 0));
};
let total_bits = buf.len() as i64 * 8;
let (lo, hi) = normalize_range(
start,
end,
if bit_mode {
total_bits
} else {
buf.len() as i64
},
);
if lo > hi {
return Ok((GarnetStatus::Ok, 0));
}
if bit_mode {
let mut n = 0u64;
for bit in lo..=hi {
let byte = buf[(bit / 8) as usize];
n += u64::from(byte & (0x80u8 >> (bit % 8)) != 0);
}
Ok((GarnetStatus::Ok, n))
} else {
let mut n = 0u64;
for &b in &buf[lo as usize..=hi as usize] {
n += u64::from(b.count_ones());
}
Ok((GarnetStatus::Ok, n))
}
}
pub async fn string_bit_position(
&self,
key: &[u8],
bit: u8,
start: i64,
end: i64,
bit_mode: bool,
) -> wkv::Result<(GarnetStatus, i64)> {
let Some(buf) = self.read_string(key).await? else {
return Ok((GarnetStatus::NotFound, -1));
};
let total_bits = buf.len() as i64 * 8;
let (lo, hi) = normalize_range(
start,
end,
if bit_mode {
total_bits
} else {
buf.len() as i64
},
);
let want = bit != 0;
for bit_idx in lo..=hi {
let byte = buf[(bit_idx / 8) as usize];
if (byte & (0x80u8 >> (bit_idx % 8)) != 0) == want {
return Ok((GarnetStatus::Ok, bit_idx));
}
}
Ok((GarnetStatus::Ok, -1))
}
pub async fn string_bit_field(
&self,
key: &[u8],
ops: &[BitFieldOp],
) -> wkv::Result<(GarnetStatus, Vec<Option<i64>>)> {
let mut buf = self.read_string(key).await?.unwrap_or_default();
let mut results = Vec::with_capacity(ops.len());
let mut dirty = false;
for op in ops {
let is_write = !matches!(op, BitFieldOp::Get { .. });
let r = bit_field_apply(&mut buf, *op);
results.push(r);
dirty |= is_write;
}
if dirty {
self.upsert_string(key, &buf).await?;
}
Ok((GarnetStatus::Ok, results))
}
pub async fn string_bit_field_read_only(
&self,
key: &[u8],
gets: &[(bool, u8, u64)],
) -> wkv::Result<(GarnetStatus, Vec<Option<i64>>)> {
let Some(buf) = self.read_string(key).await? else {
return Ok((GarnetStatus::NotFound, gets.iter().map(|_| None).collect()));
};
let mut out = Vec::with_capacity(gets.len());
let mut scratch = buf;
for &(is_signed, bits, offset) in gets {
out.push(bit_field_apply(
&mut scratch,
BitFieldOp::Get {
is_signed,
bits,
offset,
},
));
}
Ok((GarnetStatus::Ok, out))
}
}
pub(crate) fn normalize_range(start: i64, end: i64, total: i64) -> (i64, i64) {
let s = if start < 0 { total + start } else { start }.max(0);
let e = if end < 0 { total + end } else { end }.min(total - 1);
if s > e || total == 0 {
(1, 0) } else {
(s, e)
}
}
fn bit_field_apply(buf: &mut Vec<u8>, op: BitFieldOp) -> Option<i64> {
let (is_signed, bits, offset, is_write, _value, wrap, sat) = match op {
BitFieldOp::Get {
is_signed,
bits,
offset,
} => (is_signed, bits, offset, false, 0i64, false, false),
BitFieldOp::Set {
is_signed,
bits,
offset,
value,
wrap,
sat,
} => (is_signed, bits, offset, true, value, wrap, sat),
BitFieldOp::IncrBy {
is_signed,
bits,
offset,
increment,
wrap,
sat,
} => (is_signed, bits, offset, true, increment, wrap, sat),
};
let byte_idx = (offset / 8) as usize;
if is_write {
let end_byte = ((offset + u64::from(bits) - 1) / 8) as usize;
if end_byte >= buf.len() {
buf.resize(end_byte + 1, 0);
}
} else if byte_idx >= buf.len() {
return Some(0);
}
let mut current: i64 = 0;
for k in 0..bits {
let pos = offset + u64::from(k);
let idx = (pos / 8) as usize;
let bit = idx < buf.len() && buf[idx] & (0x80u8 >> (pos % 8)) != 0;
current = (current << 1) | i64::from(bit);
}
let old = if is_signed && bits < 64 {
let shift = 64 - bits;
(current << shift) >> shift
} else {
current
};
if !is_write {
return Some(old);
}
let new_val = match op {
BitFieldOp::Set { value, .. } => value,
BitFieldOp::IncrBy { increment, .. } => old.wrapping_add(increment),
_ => return Some(old),
};
let (min, max) = if bits >= 64 {
(i64::MIN, i64::MAX)
} else if is_signed {
(-(1i64 << (bits - 1)), (1i64 << (bits - 1)) - 1)
} else {
(0, (1i64 << bits) - 1)
};
let (stored, result) = if (min..=max).contains(&new_val) {
(new_val, new_val)
} else if wrap {
let mask = if bits >= 64 {
-1i64
} else {
(1i64 << bits) - 1
};
let masked = new_val & mask;
let sign_ext = if is_signed && bits < 64 && (masked >> (bits - 1)) & 1 == 1 {
masked | !mask
} else {
masked
};
(sign_ext, sign_ext)
} else if sat {
let clamped = new_val.clamp(min, max);
(clamped, clamped)
} else {
return None; };
for k in 0..bits {
let pos = offset + u64::from(k);
let idx = (pos / 8) as usize;
if idx >= buf.len() {
break;
}
let bit_set = (stored >> (bits - 1 - k)) & 1 == 1;
if bit_set {
buf[idx] |= 0x80u8 >> (pos % 8);
} else {
buf[idx] &= !(0x80u8 >> (pos % 8));
}
}
Some(result)
}
#[cfg(test)]
mod tests {
use super::{BitFieldOp, bit_field_apply};
#[test]
fn set_extends_buffer_to_full_field_extent() {
let mut buf = Vec::new(); let r = bit_field_apply(
&mut buf,
BitFieldOp::Set {
is_signed: false,
bits: 16,
offset: 0,
value: 300,
wrap: false,
sat: false,
},
);
assert_eq!(r, Some(300));
assert_eq!(buf, vec![0x01, 0x2C]); let r = bit_field_apply(
&mut buf,
BitFieldOp::Get {
is_signed: false,
bits: 16,
offset: 0,
},
);
assert_eq!(r, Some(300));
}
#[test]
fn get_partial_overlap_reads_available_bits() {
let mut buf = vec![0xFFu8];
let r = bit_field_apply(
&mut buf,
BitFieldOp::Get {
is_signed: false,
bits: 8,
offset: 4,
},
);
assert_eq!(r, Some(0b1111_0000));
let r = bit_field_apply(
&mut buf,
BitFieldOp::Get {
is_signed: true,
bits: 8,
offset: 4,
},
);
assert_eq!(r, Some(-16)); let r = bit_field_apply(
&mut buf,
BitFieldOp::Get {
is_signed: false,
bits: 16,
offset: 8,
},
);
assert_eq!(r, Some(0));
}
#[test]
fn set_unaligned_neighbors_untouched() {
let mut buf = vec![0x00, 0xFF];
let r = bit_field_apply(
&mut buf,
BitFieldOp::Set {
is_signed: false,
bits: 8,
offset: 4,
value: 0xAB,
wrap: false,
sat: false,
},
);
assert_eq!(r, Some(0xAB));
assert_eq!(buf, vec![0x0A, 0xBF]);
}
#[test]
fn incr_overflow_fail_writes_nothing() {
let mut buf = vec![0x00];
let r = bit_field_apply(
&mut buf,
BitFieldOp::IncrBy {
is_signed: false,
bits: 8,
offset: 0,
increment: 300,
wrap: false,
sat: false,
},
);
assert_eq!(r, None);
assert_eq!(buf, vec![0x00]);
}
}