use crate::commands::custom::CustomCommand;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use bytes::Bytes;
use redis_protocol::resp2::types::{BytesFrame as Resp2Frame, Resp2Frame as _};
use redis_protocol::resp3::types::{BytesFrame as Resp3Frame, Resp3Frame as _};
#[derive(Clone, Default)]
pub struct CommandBuilder {
pub(crate) elements: Vec<Bytes>,
}
impl CommandBuilder {
pub fn new(keyword: &'static str) -> Self {
CommandBuilder {
elements: vec![Bytes::from_static(keyword.as_bytes())],
}
}
pub fn to_command(self) -> CustomCommand {
self.into()
}
pub fn arg_static(mut self, arg: &'static str) -> Self {
self.elements.push(Bytes::from_static(arg.as_bytes()));
self
}
pub fn arg_static_option(mut self, arg: Option<&'static str>) -> Self {
if let Some(arg_str) = arg {
self.elements.push(Bytes::from_static(arg_str.as_bytes()));
}
self
}
pub fn arg_uint(mut self, arg: usize) -> Self {
self.elements.push(Bytes::from(arg.to_string()));
self
}
pub fn arg(mut self, arg: &Bytes) -> Self {
self.elements.push(arg.clone());
self
}
pub fn arg_option(mut self, arg: Option<&Bytes>) -> Self {
if let Some(inner) = arg {
self.elements.push(inner.clone());
}
self
}
}
impl From<CommandBuilder> for Resp2Frame {
fn from(builder: CommandBuilder) -> Self {
let mut frames = Vec::with_capacity(builder.elements.len());
for byte in builder.elements {
frames.push(Resp2Frame::BulkString(byte));
}
Resp2Frame::Array(frames)
}
}
impl From<CommandBuilder> for Resp3Frame {
fn from(builder: CommandBuilder) -> Self {
let mut frames = Vec::with_capacity(builder.elements.len());
for byte in builder.elements {
frames.push(Resp3Frame::BlobString {
data: byte,
attributes: None,
});
}
Resp3Frame::Array {
data: frames,
attributes: None,
}
}
}
impl From<CommandBuilder> for CustomCommand {
fn from(builder: CommandBuilder) -> Self {
CustomCommand::new(builder)
}
}
pub trait ToStringOption {
fn to_string_option(&self) -> Option<String>;
}
impl ToStringOption for Resp2Frame {
fn to_string_option(&self) -> Option<String> {
self.to_string()
}
}
impl ToStringOption for Resp3Frame {
fn to_string_option(&self) -> Option<String> {
self.to_string()
}
}
pub trait IsNullFrame {
fn is_null_frame(&self) -> bool;
}
impl IsNullFrame for Resp2Frame {
fn is_null_frame(&self) -> bool {
self == &Resp2Frame::Null
}
}
impl IsNullFrame for Resp3Frame {
fn is_null_frame(&self) -> bool {
self == &Resp3Frame::Null
}
}
pub trait ToInteger {
fn to_integer(&self) -> Option<i64>;
}
impl ToInteger for Resp2Frame {
fn to_integer(&self) -> Option<i64> {
match self {
Resp2Frame::Integer(number) => Some(*number),
_ => None,
}
}
}
impl ToInteger for Resp3Frame {
fn to_integer(&self) -> Option<i64> {
match self {
Resp3Frame::Number { data, attributes: _ } => Some(*data),
_ => None,
}
}
}
pub trait ToStringBytes {
fn to_string_bytes(&self) -> Option<Bytes>;
}
impl ToStringBytes for Resp2Frame {
fn to_string_bytes(&self) -> Option<Bytes> {
match self {
Resp2Frame::BulkString(data) => Some(data.clone()),
_ => None,
}
}
}
impl ToStringBytes for Resp3Frame {
fn to_string_bytes(&self) -> Option<Bytes> {
match self {
Resp3Frame::BlobString { data, attributes: _ } => Some(data.clone()),
_ => None,
}
}
}
pub trait ToBytesMap {
fn to_map(&self) -> Option<BTreeMap<Bytes, Bytes>>;
}
impl ToBytesMap for Resp2Frame {
fn to_map(&self) -> Option<BTreeMap<Bytes, Bytes>> {
let mut map = BTreeMap::new();
match self {
Resp2Frame::Array(array) => {
for item in array.chunks(2) {
if item.len() < 2 {
return None;
}
let field = match &item[0] {
Resp2Frame::SimpleString(value) | Resp2Frame::BulkString(value) => value.clone(),
_ => return None,
};
let value = match &item[1] {
Resp2Frame::SimpleString(value) | Resp2Frame::BulkString(value) => value.clone(),
_ => return None,
};
map.insert(field, value);
}
}
_ => return None,
}
Some(map)
}
}
impl ToBytesMap for Resp3Frame {
fn to_map(&self) -> Option<BTreeMap<Bytes, Bytes>> {
let mut map = BTreeMap::new();
match self {
Resp3Frame::Map { data, attributes: _ } => {
for item in data {
let field = match item.0 {
Resp3Frame::BlobString { data, attributes: _ }
| Resp3Frame::SimpleString { data, attributes: _ } => data.clone(),
_ => return None,
};
let value = match item.1 {
Resp3Frame::BlobString { data, attributes: _ }
| Resp3Frame::SimpleString { data, attributes: _ } => data.clone(),
_ => return None,
};
map.insert(field, value);
}
}
_ => return None,
}
Some(map)
}
}