shardmap 0.3.1

Sharded embedded in-memory map with optional cache, protocol, and server internals
Documentation
use bytes::BytesMut;

use crate::commands::redis::{
    define_redis_command, error, int, optional_string_value, write_frame, wrong_arity,
};
use crate::commands::string_bits::{BitOpKind, apply_bitop};
use crate::protocol::Frame;
#[cfg(feature = "server")]
use crate::server::wire::ServerWire;
use crate::storage::EmbeddedStore;

define_redis_command!(BitOp, "BITOP", true);

impl crate::commands::redis::RedisCommand for BitOp {
    fn execute(store: &EmbeddedStore, args: &[&[u8]]) -> Frame {
        match bitop_value(store, args) {
            Ok(len) => int(len),
            Err(frame) => frame,
        }
    }

    #[cfg(feature = "server")]
    fn write_resp(store: &EmbeddedStore, args: &[&[u8]], out: &mut BytesMut) {
        match bitop_value(store, args) {
            Ok(len) => ServerWire::write_resp_integer(out, len),
            Err(frame) => write_frame(out, &frame),
        }
    }
}

fn bitop_value(store: &EmbeddedStore, args: &[&[u8]]) -> std::result::Result<i64, Frame> {
    let [operation, dest, sources @ ..] = args else {
        return Err(wrong_arity("BITOP"));
    };
    let Some(operation) = BitOpKind::parse(operation) else {
        return Err(error("ERR syntax error"));
    };
    if sources.is_empty() || (operation == BitOpKind::Not && sources.len() != 1) {
        return Err(wrong_arity("BITOP"));
    }

    let mut values = Vec::with_capacity(sources.len());
    for source in sources {
        match optional_string_value(store, source, true) {
            Ok(Some(value)) => values.push(value),
            Ok(None) => values.push(Vec::new()),
            Err(frame) => return Err(frame),
        }
    }
    let result = apply_bitop(operation, &values);
    let len = result.len() as i64;
    store.set((*dest).to_vec(), result, None);
    Ok(len)
}