use super::{
super::{
basic_commands::MAX_STRING_PAYLOAD_BYTES,
cmd_strings as cs,
cmd_strings::{abort_with_error_message, abort_with_wrong_number_of_arguments},
parser::resp_ext::{RespSliceExt, RespVecExt},
resp_server_session::RespServerSession,
},
bitmap_manager::{try_validate_bit_pos_offsets, try_validate_bitfield_offset},
bitmap_manager_bit_op::{BitmapOperation, invoke_bit_operation_unsafe},
bitmap_manager_bit_pos::bit_pos_driver,
bitmap_manager_bitfield::{
BitFieldCmdArgs, BitFieldOverflow, BitFieldSecondaryCommand, bit_field_execute,
new_block_alloc_length_from_type,
},
};
const RESP_ERR_WRONG_NUMBER_OF_ARGUMENTS: &str = "ERR wrong number of arguments";
const RESP_ERR_BITOP_KEY_LIMIT: &str = "ERR Bitop source key limit (64) exceeded";
const RESP_ERR_BITOP_DIFF_TWO_SOURCE_KEYS_REQUIRED: &str =
"ERR BITOP DIFF must be called with at least two source keys.";
const RESP_ERR_BITOP_NOT_SINGLE_SOURCE_KEY: &str =
"ERR BITOP NOT must be called with a single source key.";
const RESP_ERR_INVALID_BITFIELD_TYPE: &str =
"ERR Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is";
const RESP_ERR_INVALID_OVERFLOW_TYPE: &str = "ERR Invalid OVERFLOW type specified";
const RESP_ERRNOTFOUND: &[u8] = b"$-1\r\n";
const RESP3_NULL_REPLY: &[u8] = b"_\r\n";
const MAX_BIT_OFFSET: i64 = (MAX_STRING_PAYLOAD_BYTES as i64 * 8) - 1;
fn parse_bit_offset(raw: &[u8]) -> Option<i64> {
let offset = raw.try_parse_i64()?;
(0..=MAX_BIT_OFFSET).contains(&offset).then_some(offset)
}
fn write_bitfield_nil(session: &RespServerSession, output: &mut Vec<u8>) {
if session.resp_protocol_version >= 3 {
output.extend_from_slice(RESP3_NULL_REPLY);
} else {
output.extend_from_slice(RESP_ERRNOTFOUND);
}
}
fn parse_bitfield_encoding(encoding: &[u8]) -> Option<(u8, bool)> {
if encoding.len() <= 1 {
return None;
}
let signed = match encoding[0] {
b'i' => true,
b'u' => false,
_ => return None,
};
let bit_count = encoding[1..].try_parse_i64()?;
(bit_count > 0
&& if signed {
bit_count <= 64
} else {
bit_count < 64
})
.then_some((bit_count as u8, signed))
}
fn parse_bitfield_offset(raw: &[u8]) -> Option<(i64, bool)> {
let (digits, multiply_offset) = match raw {
[b'#', rest @ ..] if !rest.is_empty() => (rest, true),
_ => (raw, false),
};
let offset = digits.try_parse_i64()?;
(offset >= 0).then_some((offset, multiply_offset))
}
fn parse_bitfield_type_offset(encoding: &[u8], offset_raw: &[u8]) -> Option<(u8, i64)> {
let (bit_count, signed) = parse_bitfield_encoding(encoding)?;
let (offset, multiply_offset) = parse_bitfield_offset(offset_raw)?;
let (normalized_offset, _) = try_validate_bitfield_offset(offset, bit_count, multiply_offset)?;
let type_info = if signed { 0x80 | bit_count } else { bit_count };
Some((type_info, normalized_offset))
}
fn parse_bitfield_overflow(raw: &[u8]) -> Option<BitFieldOverflow> {
if raw.eq_ignore_ascii_case(b"WRAP") {
Some(BitFieldOverflow::Wrap)
} else if raw.eq_ignore_ascii_case(b"SAT") {
Some(BitFieldOverflow::Sat)
} else if raw.eq_ignore_ascii_case(b"FAIL") {
Some(BitFieldOverflow::Fail)
} else {
None
}
}
impl RespServerSession {
pub fn network_string_set_bit<'a, D: wdev::Device>(
&mut self,
parse_state: &[&[u8]],
store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
if parse_state.len() != 3 {
abort_with_wrong_number_of_arguments(output, "SETBIT");
return Ok(true);
}
let key = parse_state[0];
let Some(offset) = parse_bit_offset(parse_state[1]) else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_BITOFFSET_IS_NOT_INTEGER);
return Ok(true);
};
if !matches!(parse_state[2], b"0" | b"1") {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_BIT_IS_NOT_INTEGER);
return Ok(true);
}
let bit = parse_state[2][0] - b'0';
let mut val = match store.try_read_sync(key, |v| v.to_vec()) {
Ok(Some(Some(v))) => v,
Ok(Some(None)) => Vec::new(),
Ok(None) => return Ok(false),
Err(_) => {
output.write_resp_error("generic error");
return Ok(true);
}
};
let byte_idx = (offset / 8) as usize;
let bit_idx = 7 - (offset % 8) as u32;
val.resize(byte_idx + 1, 0);
let old_bit = (val[byte_idx] >> bit_idx) & 1;
if bit == 1 {
val[byte_idx] |= 1 << bit_idx;
} else {
val[byte_idx] &= !(1 << bit_idx);
}
match store.try_upsert_sync(key, &val) {
Ok(Ok(_)) => output.write_resp_int(old_bit as i64),
Ok(Err(_)) => return Ok(false),
Err(_) => output.write_resp_error("generic error"),
}
Ok(true)
}
pub fn network_string_get_bit<'a, D: wdev::Device>(
&mut self,
parse_state: &[&[u8]],
store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
if parse_state.len() != 2 {
abort_with_wrong_number_of_arguments(output, "GETBIT");
return Ok(true);
}
let key = parse_state[0];
let Some(offset) = parse_bit_offset(parse_state[1]) else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_BITOFFSET_IS_NOT_INTEGER);
return Ok(true);
};
let bit = match store.try_read_sync(key, |v| v.to_vec()) {
Ok(Some(Some(val))) => {
let byte_idx = (offset / 8) as usize;
if byte_idx < val.len() {
(val[byte_idx] >> (7 - (offset % 8) as u32)) & 1
} else {
0
}
}
Ok(Some(None)) => 0,
Ok(None) => return Ok(false),
Err(_) => {
output.write_resp_error("generic error");
return Ok(true);
}
};
output.write_resp_int(bit as i64);
Ok(true)
}
pub fn network_string_bit_count<'a, D: wdev::Device>(
&mut self,
parse_state: &[&[u8]],
store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
let count = parse_state.len();
if count != 1 && count != 3 && count != 4 {
abort_with_wrong_number_of_arguments(output, "BITCOUNT");
return Ok(true);
}
let key = parse_state[0];
let mut start = 0i64;
let mut end = -1i64;
let mut use_bit_index = false;
if count > 1 {
let (Some(s), Some(e)) = (
parse_state[1].try_parse_i64(),
parse_state[2].try_parse_i64(),
) else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return Ok(true);
};
start = s;
end = e;
if count > 3 {
let flag = parse_state[3];
if flag.eq_ignore_ascii_case(b"BIT") {
use_bit_index = true;
} else if flag.eq_ignore_ascii_case(b"BYTE") {
use_bit_index = false;
} else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_SYNTAX_ERROR);
return Ok(true);
}
}
}
let val = match store.try_read_sync(key, |v| v.to_vec()) {
Ok(Some(Some(v))) => v,
Ok(Some(None)) => {
output.write_resp_int(0);
return Ok(true);
}
Ok(None) => return Ok(false),
Err(_) => {
output.write_resp_error("generic error");
return Ok(true);
}
};
let total = if use_bit_index {
bit_index_count(&val, start, end)
} else {
byte_index_count(&val, start, end)
};
output.write_resp_int(total);
Ok(true)
}
pub fn network_string_bit_position<'a, D: wdev::Device>(
&mut self,
parse_state: &[&[u8]],
store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
let count = parse_state.len();
if !(2..=5).contains(&count) {
abort_with_wrong_number_of_arguments(output, "BITPOS");
return Ok(true);
}
let key = parse_state[0];
let bit_slice = parse_state[1];
if bit_slice.len() != 1 || (bit_slice[0] != b'0' && bit_slice[0] != b'1') {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_BIT_IS_NOT_INTEGER);
return Ok(true);
}
let search_for = bit_slice[0] - b'0';
let mut start_offset = 0i64;
let mut end_offset = -1i64;
let mut offset_type = 0x0u8;
let mut has_start_offset = false;
let mut has_end_offset = false;
if count > 2 {
let Some(start) = parse_state[2].try_parse_i64() else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return Ok(true);
};
start_offset = start;
has_start_offset = true;
if count > 3 {
let Some(end) = parse_state[3].try_parse_i64() else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return Ok(true);
};
end_offset = end;
has_end_offset = true;
if count > 4 {
let flag = parse_state[4];
if flag.eq_ignore_ascii_case(b"BIT") {
offset_type = 0x1;
} else if !flag.eq_ignore_ascii_case(b"BYTE") {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_SYNTAX_ERROR);
return Ok(true);
}
}
}
}
if try_validate_bit_pos_offsets(
start_offset,
end_offset,
offset_type,
has_start_offset,
has_end_offset,
) {
output.write_resp_int(-1);
return Ok(true);
}
match store.try_read_sync(key, |v| v.to_vec()) {
Ok(Some(Some(val))) => {
let pos = bit_pos_driver(
&val,
val.len() as i64,
start_offset,
end_offset,
search_for,
offset_type,
);
output.write_resp_int(pos);
}
Ok(Some(None)) => {
let resp = if search_for == 0 {
cs::RESP_RETURN_VAL_0
} else {
cs::RESP_RETURN_VAL_N1
};
output.extend_from_slice(resp);
}
Ok(None) => return Ok(false),
Err(_) => output.write_resp_error("generic error"),
}
Ok(true)
}
pub fn network_string_bit_operation<'a, D: wdev::Device>(
&mut self,
bit_op: BitmapOperation,
parse_state: &[&[u8]],
store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
let count = parse_state.len();
if count < 2 {
abort_with_error_message(output, RESP_ERR_WRONG_NUMBER_OF_ARGUMENTS);
return Ok(true);
}
if bit_op == BitmapOperation::Diff && count < 3 {
abort_with_error_message(output, RESP_ERR_BITOP_DIFF_TWO_SOURCE_KEYS_REQUIRED);
return Ok(true);
}
if bit_op == BitmapOperation::Not && count > 2 {
abort_with_error_message(output, RESP_ERR_BITOP_NOT_SINGLE_SOURCE_KEY);
return Ok(true);
}
if count > 64 {
abort_with_error_message(output, RESP_ERR_BITOP_KEY_LIMIT);
return Ok(true);
}
let dest_key = parse_state[0];
let mut srcs: Vec<Vec<u8>> = Vec::with_capacity(count - 1);
for src_key in &parse_state[1..] {
match store.try_read_sync(src_key, |v| v.to_vec()) {
Ok(Some(Some(v))) => srcs.push(v),
Ok(Some(None)) => {}
Ok(None) => return Ok(false),
Err(_) => {
output.write_resp_error("generic error");
return Ok(true);
}
}
}
let result = if srcs.is_empty() {
0i64
} else {
let shortest = srcs.iter().map(|s| s.len()).min().unwrap();
let longest = srcs.iter().map(|s| s.len()).max().unwrap();
let slices: Vec<&[u8]> = srcs.iter().map(|s| s.as_slice()).collect();
let mut dst = vec![0u8; longest];
match invoke_bit_operation_unsafe(bit_op, &slices, &mut dst, shortest) {
Ok(()) => {
if longest > 0 {
match store.try_upsert_sync(dest_key, &dst) {
Ok(Ok(_)) => longest as i64,
Ok(Err(_)) => return Ok(false),
Err(_) => {
output.write_resp_error("generic error");
return Ok(true);
}
}
} else {
0
}
}
Err(_) => {
output.write_resp_error("generic error");
return Ok(true);
}
}
};
output.write_resp_int(result);
Ok(true)
}
pub fn string_bit_field<'a, D: wdev::Device>(
&mut self,
parse_state: &[&[u8]],
store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
if parse_state.is_empty() {
abort_with_wrong_number_of_arguments(output, "BITFIELD");
return Ok(true);
}
let key = parse_state[0];
let mut overflow_type = BitFieldOverflow::Wrap;
let mut secondary_command_args: Vec<BitFieldCmdArgs> = Vec::new();
let mut has_write_sub_commands = false;
let mut curr_token_idx = 1usize;
while curr_token_idx < parse_state.len() {
let command = parse_state[curr_token_idx];
curr_token_idx += 1;
if command.eq_ignore_ascii_case(b"OVERFLOW") {
let Some(next) = parse_state.get(curr_token_idx) else {
abort_with_error_message(output, RESP_ERR_INVALID_OVERFLOW_TYPE);
return Ok(true);
};
let Some(parsed) = parse_bitfield_overflow(next) else {
abort_with_error_message(output, RESP_ERR_INVALID_OVERFLOW_TYPE);
return Ok(true);
};
curr_token_idx += 1;
overflow_type = parsed;
continue;
}
let Some(encoding_slice) = parse_state.get(curr_token_idx).copied() else {
abort_with_error_message(output, RESP_ERR_INVALID_BITFIELD_TYPE);
return Ok(true);
};
if parse_bitfield_encoding(encoding_slice).is_none() {
abort_with_error_message(output, RESP_ERR_INVALID_BITFIELD_TYPE);
return Ok(true);
}
curr_token_idx += 1;
let Some(offset_raw) = parse_state.get(curr_token_idx).copied() else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_BITOFFSET_IS_NOT_INTEGER);
return Ok(true);
};
let Some((type_info, offset)) = parse_bitfield_type_offset(encoding_slice, offset_raw) else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_BITOFFSET_IS_NOT_INTEGER);
return Ok(true);
};
curr_token_idx += 1;
if command.eq_ignore_ascii_case(b"GET") {
secondary_command_args.push(BitFieldCmdArgs::new(
BitFieldSecondaryCommand::Get,
type_info,
offset,
0,
overflow_type as u8,
));
continue;
}
let op = if command.eq_ignore_ascii_case(b"SET") {
BitFieldSecondaryCommand::Set
} else if command.eq_ignore_ascii_case(b"INCRBY") {
BitFieldSecondaryCommand::IncrBy
} else {
let err = format!(
"ERR Bitfield command {} not supported",
command.as_str_safe()
);
abort_with_error_message(output, &err);
return Ok(true);
};
has_write_sub_commands = true;
let Some(value_slice) = parse_state.get(curr_token_idx).copied() else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return Ok(true);
};
let Some(value) = value_slice.try_parse_i64() else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return Ok(true);
};
curr_token_idx += 1;
secondary_command_args.push(BitFieldCmdArgs::new(
op,
type_info,
offset,
value,
overflow_type as u8,
));
}
self.string_bit_field_action(
key,
secondary_command_args,
has_write_sub_commands,
store,
output,
)
}
pub fn string_bit_field_read_only<'a, D: wdev::Device>(
&mut self,
parse_state: &[&[u8]],
store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
if parse_state.is_empty() {
abort_with_wrong_number_of_arguments(output, "BITFIELD_RO");
return Ok(true);
}
let key = parse_state[0];
let mut secondary_command_args: Vec<BitFieldCmdArgs> = Vec::new();
let mut curr_token_idx = 1usize;
while curr_token_idx < parse_state.len() {
let command = parse_state[curr_token_idx];
curr_token_idx += 1;
if !command.eq_ignore_ascii_case(b"GET") {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_SYNTAX_ERROR);
return Ok(true);
}
let Some(encoding_slice) = parse_state.get(curr_token_idx).copied() else {
abort_with_error_message(output, RESP_ERR_INVALID_BITFIELD_TYPE);
return Ok(true);
};
curr_token_idx += 1;
let Some(offset_raw) = parse_state.get(curr_token_idx).copied() else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_BITOFFSET_IS_NOT_INTEGER);
return Ok(true);
};
let Some((type_info, offset)) = parse_bitfield_type_offset(encoding_slice, offset_raw) else {
abort_with_error_message(output, cs::RESP_ERR_GENERIC_BITOFFSET_IS_NOT_INTEGER);
return Ok(true);
};
curr_token_idx += 1;
secondary_command_args.push(BitFieldCmdArgs::new(
BitFieldSecondaryCommand::Get,
type_info,
offset,
0,
BitFieldOverflow::Wrap as u8,
));
}
self.string_bit_field_action(key, secondary_command_args, false, store, output)
}
pub fn string_bit_field_action<'a, D: wdev::Device>(
&mut self,
key: &[u8],
secondary_command_args: Vec<BitFieldCmdArgs>,
has_write_commands: bool,
store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
let _ = has_write_commands;
output.write_resp_array_len(secondary_command_args.len());
let mut value: Option<Vec<u8>> = match store.try_read_sync(key, |v| v.to_vec()) {
Ok(Some(Some(v))) => Some(v),
Ok(Some(None)) => None,
Ok(None) => return Ok(false),
Err(_) => {
output.write_resp_error("generic error");
return Ok(true);
}
};
let mut dirty = false;
for (i, args) in secondary_command_args.iter().enumerate() {
if i == 0 {
if self.handle_first_sub_command(key, args, &mut value, &mut dirty, store, output)? {
return Ok(true);
}
continue;
}
let is_get = args.secondary_command == BitFieldSecondaryCommand::Get;
if is_get {
match value.as_mut() {
None => output.write_resp_int(0),
Some(buf) => match bit_field_execute(args, buf) {
Some((v, false)) => output.write_resp_int(v),
_ => write_bitfield_nil(self, output),
},
}
} else {
let need = new_block_alloc_length_from_type(args, 0) as usize;
let buf = value.get_or_insert_with(|| Vec::with_capacity(need));
if buf.len() < need {
buf.resize(need, 0);
}
match bit_field_execute(args, buf) {
Some((v, false)) => output.write_resp_int(v),
Some((_, true)) => write_bitfield_nil(self, output),
None => output.write_resp_error("generic error"),
}
dirty = true;
}
}
if let Some(buf) = dirty.then_some(value).flatten() {
match store.try_upsert_sync(key, &buf) {
Ok(Ok(_)) => {}
Ok(Err(_)) => return Ok(false),
Err(_) => output.write_resp_error("generic error"),
}
}
Ok(true)
}
pub fn handle_first_sub_command<'a, D: wdev::Device>(
&mut self,
_key: &[u8],
args: &BitFieldCmdArgs,
value: &mut Option<Vec<u8>>,
dirty: &mut bool,
_store: &wkv::BatchStoreSession<'a, D>,
output: &mut Vec<u8>,
) -> wresp::Result<bool> {
let is_get = args.secondary_command == BitFieldSecondaryCommand::Get;
if is_get {
match value.as_mut() {
None => output.write_resp_int(0),
Some(buf) => match bit_field_execute(args, buf) {
Some((v, false)) => output.write_resp_int(v),
_ => write_bitfield_nil(self, output),
},
}
} else {
let need = new_block_alloc_length_from_type(args, 0) as usize;
let buf = value.get_or_insert_with(|| Vec::with_capacity(need));
if buf.len() < need {
buf.resize(need, 0);
}
match bit_field_execute(args, buf) {
Some((v, false)) => output.write_resp_int(v),
Some((_, true)) => write_bitfield_nil(self, output),
None => output.write_resp_error("generic error"),
}
*dirty = true;
}
Ok(false)
}
}
fn byte_index_count(val: &[u8], start: i64, end: i64) -> i64 {
let len = val.len() as i64;
let s = if start < 0 { len + start } else { start };
let e = if end < 0 { len + end } else { end };
let e = e.min(len - 1);
if s < 0 || e < 0 || s >= len || s > e {
return 0;
}
val[s as usize..=e as usize]
.iter()
.map(|b| b.count_ones() as i64)
.sum()
}
fn bit_index_count(val: &[u8], start: i64, end: i64) -> i64 {
let bit_len = val.len() as i64 * 8;
if bit_len == 0 {
return 0;
}
let s = if start < 0 { bit_len + start } else { start };
let e = if end < 0 { bit_len + end } else { end };
if s < 0 || e < 0 || s >= bit_len || s > e {
return 0;
}
let e = e.min(bit_len - 1);
let (fb, lb) = ((s / 8) as usize, (e / 8) as usize);
let mask_first = 0xffu8 >> (s % 8);
let mask_last = 0xffu8 << (7 - e % 8);
if fb == lb {
return (val[fb] & mask_first & mask_last).count_ones() as i64;
}
let mut total =
(val[fb] & mask_first).count_ones() as i64 + (val[lb] & mask_last).count_ones() as i64;
for b in &val[fb + 1..lb] {
total += b.count_ones() as i64;
}
total
}
#[cfg(test)]
mod tests {
use super::{super::super::batch_harness::with_batch, bit_index_count, byte_index_count};
use crate::resp::bitmap::bitmap_manager_bit_op::BitmapOperation;
#[test]
fn byte_index_count_ranges() {
let val = [0b1011_0001u8, 0b0100_1111];
assert_eq!(byte_index_count(&val, 0, -1), 4 + 5);
assert_eq!(byte_index_count(&val, 0, 0), 4);
assert_eq!(byte_index_count(&val, -1, -1), 5);
assert_eq!(byte_index_count(&val, 1, 1), 5);
assert_eq!(byte_index_count(&val, 2, 3), 0);
assert_eq!(byte_index_count(&val, -3, -3), 0);
assert_eq!(byte_index_count(&val, 5, 9), 0);
assert_eq!(byte_index_count(&[], 0, -1), 0);
assert_eq!(byte_index_count(&val, 0, 100), 4 + 5);
}
#[test]
fn bit_index_count_ranges() {
let val = [0b1011_0001u8];
assert_eq!(bit_index_count(&val, 0, 7), 4);
assert_eq!(bit_index_count(&val, 0, 0), 1);
assert_eq!(bit_index_count(&val, 6, 7), 1);
assert_eq!(bit_index_count(&val, 1, 4), 2);
let v2 = [0b1000_0000, 0b0000_0001];
assert_eq!(bit_index_count(&v2, 0, 15), 2);
assert_eq!(bit_index_count(&v2, 7, 8), 0);
assert_eq!(bit_index_count(&v2, 1, 14), 0);
assert_eq!(bit_index_count(&val, -8, -1), 4);
assert_eq!(bit_index_count(&val, 8, 15), 0);
assert_eq!(bit_index_count(&[], 0, -1), 0);
assert_eq!(bit_index_count(&val, 0, 100), 4);
}
#[test]
fn setbit_getbit_roundtrip_and_growth() {
with_batch(|s, batch| {
let mut out = Vec::new();
let _ = s
.network_string_set_bit(&[b"bm", b"0", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b":0\r\n");
let mut out = Vec::new();
let _ = s
.network_string_set_bit(&[b"bm", b"0", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b":1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_set_bit(&[b"bm", b"9", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b":0\r\n");
let mut out = Vec::new();
let _ = s
.network_string_get_bit(&[b"bm", b"0"], batch, &mut out)
.unwrap();
assert_eq!(out, b":1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_get_bit(&[b"bm", b"9"], batch, &mut out)
.unwrap();
assert_eq!(out, b":1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_get_bit(&[b"nk", b"3"], batch, &mut out)
.unwrap();
assert_eq!(out, b":0\r\n");
let mut out = Vec::new();
let _ = s
.network_string_get_bit(&[b"bm", b"100"], batch, &mut out)
.unwrap();
assert_eq!(out, b":0\r\n");
});
}
#[test]
fn setbit_getbit_strict_validation() {
with_batch(|s, batch| {
let mut out = Vec::new();
let _ = s
.network_string_set_bit(&[b"bm", b"0", b"01"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR bit is not an integer or out of range\r\n");
let mut out = Vec::new();
let _ = s
.network_string_set_bit(&[b"bm", b"0", b"2"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR bit is not an integer or out of range\r\n");
for bad in [b"-1".as_slice(), b"x".as_slice(), b"4294967296".as_slice()] {
let mut out = Vec::new();
let _ = s
.network_string_set_bit(&[b"bm", bad, b"1"], batch, &mut out)
.unwrap();
assert_eq!(
out,
b"-ERR bit offset is not an integer or out of range\r\n"
);
}
});
}
#[test]
fn bitcount_forms_byte_and_bit() {
with_batch(|s, batch| {
let _ = s
.network_set(&[b"bm", &[0xA5, 0x0F]], batch, &mut Vec::new())
.unwrap();
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm"], batch, &mut out)
.unwrap();
assert_eq!(out, b":8\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm", b"0", b"0"], batch, &mut out)
.unwrap();
assert_eq!(out, b":4\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm", b"-1", b"-1"], batch, &mut out)
.unwrap();
assert_eq!(out, b":4\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm", b"0", b"7", b"BIT"], batch, &mut out)
.unwrap();
assert_eq!(out, b":4\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm", b"1", b"2", b"BIT"], batch, &mut out)
.unwrap();
assert_eq!(out, b":1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm", b"3", b"4", b"BIT"], batch, &mut out)
.unwrap();
assert_eq!(out, b":0\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"nk"], batch, &mut out)
.unwrap();
assert_eq!(out, b":0\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm", b"1"], batch, &mut out)
.unwrap();
assert_eq!(
out,
b"-ERR wrong number of arguments for 'BITCOUNT' command\r\n"
);
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm", b"x", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR value is not an integer or out of range.\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_count(&[b"bm", b"0", b"1", b"BAD"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR syntax error\r\n");
});
}
#[test]
fn bitpos_forms_and_errors() {
with_batch(|s, batch| {
let _ = s
.network_set(&[b"bp", &[0x00, 0x08]], batch, &mut Vec::new())
.unwrap();
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b":12\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp", b"0"], batch, &mut out)
.unwrap();
assert_eq!(out, b":0\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp", b"1", b"0", b"0"], batch, &mut out)
.unwrap();
assert_eq!(out, b":-1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp", b"1", b"0", b"11", b"BIT"], batch, &mut out)
.unwrap();
assert_eq!(out, b":-1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"nk", b"0"], batch, &mut out)
.unwrap();
assert_eq!(out, b":0\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"nk", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b":-1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp", b"1", b"999999999999", b"-1"], batch, &mut out)
.unwrap();
assert_eq!(out, b":-1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp"], batch, &mut out)
.unwrap();
assert_eq!(
out,
b"-ERR wrong number of arguments for 'BITPOS' command\r\n"
);
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp", b"2"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR bit is not an integer or out of range\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp", b"1", b"x"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR value is not an integer or out of range.\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_position(&[b"bp", b"1", b"0", b"0", b"BAD"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR syntax error\r\n");
});
}
#[test]
fn bitop_operations_and_guards() {
with_batch(|s, batch| {
let _ = s
.network_set(&[b"a", &[0b1100_0011u8, 0x0F]], batch, &mut Vec::new())
.unwrap();
let _ = s
.network_set(&[b"b", &[0b1010_1010u8]], batch, &mut Vec::new())
.unwrap();
let mut out = Vec::new();
let _ = s
.network_string_bit_operation(BitmapOperation::And, &[b"d", b"a", b"b"], batch, &mut out)
.unwrap();
assert_eq!(out, b":2\r\n");
let mut out = Vec::new();
let _ = s.network_get(&[b"d"], batch, &mut out).unwrap();
assert_eq!(out, b"$2\r\n\x82\x00\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_operation(BitmapOperation::Or, &[b"d", b"a", b"b"], batch, &mut out)
.unwrap();
assert_eq!(out, b":2\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_operation(BitmapOperation::Not, &[b"d", b"b"], batch, &mut out)
.unwrap();
assert_eq!(out, b":1\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_operation(BitmapOperation::Not, &[b"d", b"a", b"b"], batch, &mut out)
.unwrap();
assert_eq!(
out,
b"-ERR BITOP NOT must be called with a single source key.\r\n"
);
let mut out = Vec::new();
let _ = s
.network_string_bit_operation(BitmapOperation::Diff, &[b"d", b"a"], batch, &mut out)
.unwrap();
assert_eq!(
out,
b"-ERR BITOP DIFF must be called with at least two source keys.\r\n"
);
let mut out = Vec::new();
let _ = s
.network_string_bit_operation(BitmapOperation::And, &[b"d"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR wrong number of arguments\r\n");
let mut out = Vec::new();
let _ = s
.network_string_bit_operation(
BitmapOperation::And,
&[b"miss", b"n1", b"n2"],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b":0\r\n");
let mut out = Vec::new();
let _ = s.network_get(&[b"miss"], batch, &mut out).unwrap();
assert_eq!(out, b"$-1\r\n"); });
}
#[test]
fn bitfield_full_option_matrix() {
with_batch(|s, batch| {
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"SET", b"u4", b"1", b"15"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:0\r\n");
let mut out = Vec::new();
let _ = s.network_get(&[b"bf"], batch, &mut out).unwrap();
assert_eq!(&out[4..5], b"x");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"GET", b"u4", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:15\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"GET", b"i4", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:-1\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(
&[b"bf", b"INCRBY", b"u4", b"1", b"1", b"OVERFLOW", b"WRAP"],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b"*1\r\n:0\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"INCRBY", b"u4", b"1", b"-1"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:15\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(
&[b"bf", b"OVERFLOW", b"SAT", b"INCRBY", b"u8", b"8", b"250"],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b"*1\r\n:250\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(
&[b"bf", b"OVERFLOW", b"SAT", b"INCRBY", b"u8", b"8", b"10"],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b"*1\r\n:255\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(
&[b"bf", b"OVERFLOW", b"FAIL", b"INCRBY", b"u8", b"8", b"10"],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b"*1\r\n$-1\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"SET", b"u2", b"#4", b"3"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:0\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"GET", b"u2", b"8"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:3\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(
&[
b"bf",
b"GET",
b"u4",
b"1",
b"INCRBY",
b"u4",
b"1",
b"1",
b"OVERFLOW",
b"SAT",
b"INCRBY",
b"u4",
b"1",
b"5",
],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b"*3\r\n:15\r\n:0\r\n:5\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(
&[b"i64k", b"SET", b"i64", b"0", b"-9223372036854775808"],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b"*1\r\n:0\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"i64k", b"GET", b"i64", b"0"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:-9223372036854775808\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"nokey", b"GET", b"u4", b"0"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:0\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"SET", b"x4", b"0", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"SET", b"u64", b"0", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"FOO", b"u4", b"0"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR Bitfield command FOO not supported\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"GET", b"u4"], batch, &mut out)
.unwrap();
assert_eq!(
out,
b"-ERR bit offset is not an integer or out of range\r\n"
);
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"SET", b"u4", b"0", b"x"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR value is not an integer or out of range.\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"OVERFLOW", b"BAD"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR Invalid OVERFLOW type specified\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"OVERFLOW"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR Invalid OVERFLOW type specified\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field(&[b"bf", b"GET", b"u4", b"-8"], batch, &mut out)
.unwrap();
assert_eq!(
out,
b"-ERR bit offset is not an integer or out of range\r\n"
);
});
}
#[test]
fn bitfield_read_only() {
with_batch(|s, batch| {
let _ = s
.string_bit_field(&[b"bf", b"SET", b"u4", b"1", b"15"], batch, &mut Vec::new())
.unwrap();
let mut out = Vec::new();
let _ = s
.string_bit_field_read_only(&[b"bf", b"GET", b"u4", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b"*1\r\n:15\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field_read_only(
&[b"bf", b"GET", b"u4", b"1", b"GET", b"u4", b"0"],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b"*2\r\n:15\r\n:7\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field_read_only(&[b"bf", b"SET", b"u4", b"1", b"1"], batch, &mut out)
.unwrap();
assert_eq!(out, b"-ERR syntax error\r\n");
let mut out = Vec::new();
let _ = s
.string_bit_field_read_only(
&[b"bf", b"OVERFLOW", b"SAT", b"GET", b"u4", b"1"],
batch,
&mut out,
)
.unwrap();
assert_eq!(out, b"-ERR syntax error\r\n");
});
}
}