#![warn(missing_docs)]
use std::{rc::Rc, sync::Arc, sync::RwLock};
pub trait RedisCommandHandler {
fn exec(&self, _: AsyncLockedStore, _: Rc<RedisCommand>) -> String;
}
pub type AsyncLockedStore<'a> = Arc<RwLock<&'a mut (dyn IStore + Send + Sync)>>;
#[derive(Debug, Copy, Clone)]
pub struct RedisCommand<'a> {
cmd: &'a str,
}
impl<'a> RedisCommand<'a> {
pub fn new(cmd: &'a str) -> Self {
Self { cmd }
}
pub fn params(&self) -> Vec<String> {
let mut args: Vec<String> = vec![];
let binding = self.cmd;
let elems: Vec<&str> = binding.split("\r\n").collect::<Vec<_>>();
for (idx, pat) in elems[1..].iter().enumerate() {
if idx.rem_euclid(2) == 0 {
continue;
}
args.push(pat.to_string())
}
args.clone()
}
pub fn name(&self) -> String {
self.params()[0].clone().to_lowercase()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_args() {
let c = RedisCommand::new("*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$11\r\nHello World\r\n");
assert_eq!(vec!["SET", "key", "Hello World"], c.params());
}
#[test]
fn test_name() {
let c = RedisCommand::new("*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$11\r\nHello World\r\n");
assert_eq!("set", c.name());
}
}
use std::collections::HashMap;
use std::fmt::{Debug, Display};
#[derive(Debug, PartialEq)]
pub enum StoreError {
KeyNotFoundError,
KeyMismatchError(String),
}
impl Display for StoreError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::KeyNotFoundError => {
write!(f, "-ERR key not found")
}
Self::KeyMismatchError(m) => {
write!(f, "-ERR {:}", m)
}
}
}
}
type StoreResult<T> = Result<T, StoreError>;
pub trait IStore {
fn set(&mut self, k: String, v: Value) -> StoreResult<()>;
fn get(&self, k: String, vk: ValueKind) -> StoreResult<&Value>;
}
#[derive(Default)]
pub struct RedisStore {
store: HashMap<String, Value>,
}
impl IStore for RedisStore {
fn set(&mut self, k: String, v: Value) -> StoreResult<()> {
self.store.insert(k, v);
Ok(())
}
fn get(&self, k: String, vk: ValueKind) -> StoreResult<&Value> {
match self.store.get(&k.clone()) {
Some(value) => {
if value.kind == vk {
return Ok(value);
}
Err(StoreError::KeyMismatchError(
"key xxx does not match yyy".to_string(),
))
}
None => Err(StoreError::KeyNotFoundError),
}
}
}
#[cfg(test)]
mod test {
use super::{RedisStore, StoreError, Value, ValueKind};
use IStore;
#[test]
fn test_store_get_set() {
let mut s = RedisStore::default();
let value = Value::new_string("hello pedis".to_string().as_bytes().to_vec());
let set_result = s.set("key:001".to_string(), value);
assert_eq!(set_result, Result::Ok(()));
let expected_value = Value::new_string("hello pedis".to_string().as_bytes().to_vec());
let get_result = s.get("key:001".to_string(), ValueKind::String);
assert_eq!(Result::Ok(&expected_value), get_result);
let get_key_kind_mistmatch_result = s.get("key:001".to_string(), ValueKind::Map);
assert_eq!(
Err(StoreError::KeyMismatchError(
"key xxx does not match yyy".to_string()
)),
get_key_kind_mistmatch_result
);
let get_key_not_found_result = s.get("key:013".to_string(), ValueKind::String);
assert_eq!(Err(StoreError::KeyNotFoundError), get_key_not_found_result);
}
}
#[derive(PartialEq)]
pub struct Value {
pub kind: ValueKind,
pub data: Vec<u8>, }
impl Value {
pub fn new(data: Vec<u8>, kind: ValueKind) -> Self {
Self { kind, data }
}
pub fn new_string(data: Vec<u8>) -> Self {
Self {
kind: ValueKind::String,
data,
}
}
pub fn new_map(data: Vec<u8>) -> Self {
Self {
kind: ValueKind::Map,
data,
}
}
}
impl Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "k={:} len={:}", self.kind, self.data.len())
}
}
#[derive(PartialEq)]
pub enum ValueKind {
String,
Map,
Json,
List,
}
impl Display for ValueKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
ValueKind::Map => {
write!(f, "map")
}
ValueKind::Json => {
write!(f, "json")
}
ValueKind::List => {
write!(f, "list")
}
ValueKind::String => {
write!(f, "string")
}
}
}
}
pub struct Teststore {
pub err: bool,
}
impl IStore for Teststore {
fn set(&mut self, _: String, _: Value) -> Result<(), StoreError> {
if self.err {
return Err(StoreError::KeyNotFoundError);
}
Ok(())
}
fn get(&self, _: String, _: ValueKind) -> Result<&Value, StoreError> {
todo!()
}
}