use std::{collections::BTreeMap, panic};
use std::fmt::Display;
use serde::{Deserialize, Serialize};
use super::{Entry, Index, State};
use crate::error::Result;
const BINCODE: bincode::config::Configuration = bincode::config::standard();
pub fn encode<T: Serialize>(value: &T) -> Vec<u8> {
bincode::serde::encode_to_vec(value, BINCODE).expect("value must be serializable")
}
pub fn decode<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T> {
Ok(bincode::serde::borrow_decode_from_slice(bytes, BINCODE)?.0)
}
#[derive(Default)]
pub struct Kv {
applied_index: Index,
data: BTreeMap<String, String>,
}
impl Kv {
pub fn new() -> Box<Self> {
Box::new(Self::default())
}
pub fn data(&self) -> &BTreeMap<String, String> {
&self.data
}
}
impl State for Kv {
fn get_applied_index(&self) -> Index {
self.applied_index
}
fn apply(&mut self, entry: Entry) -> Result<Vec<u8>> {
let command = entry.command.as_deref().map(decode::<Command>).transpose()?;
let response = match command {
Some(Command::Put { key, value }) => {
self.data.insert(key, value);
encode(&Response::Put(entry.index))
}
Some(c @ (Command::Get { .. } | Command::Scan)) => {
panic!("{c} submitted as write command")
}
None => Vec::new(),
};
self.applied_index = entry.index;
Ok(response)
}
fn read(&self, command: Vec<u8>) -> Result<Vec<u8>> {
match decode::<Command>(&command)? {
Command::Get { key } => Ok(encode(&Response::Get(self.data.get(&key).cloned()))),
Command::Scan => Ok(encode(&Response::Scan(self.data.clone()))),
c @ Command::Put { .. } => panic!("{c} submitted as read command"),
}
}
fn snapshot(&self) -> Result<Vec<u8>> {
Ok(encode(&(self.applied_index, &self.data)))
}
fn restore(&mut self, snapshot: &[u8], index: Index) -> Result<()> {
let (applied, data): (Index, BTreeMap<String, String>) = decode(snapshot)?;
self.applied_index = index.max(applied);
self.data = data;
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Command {
Get { key: String },
Put { key: String, value: String },
Scan,
}
impl Display for Command {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Get { key } => write!(f, "get {key}"),
Self::Put { key, value } => write!(f, "put {key}={value}"),
Self::Scan => write!(f, "scan"),
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Response {
Get(Option<String>),
Put(Index),
Scan(BTreeMap<String, String>),
}
impl Display for Response {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Get(Some(value)) => write!(f, "{value}"),
Self::Get(None) => write!(f, "None"),
Self::Put(applied_index) => write!(f, "{applied_index}"),
Self::Scan(kvs) => {
let mut first = true;
for (k, v) in kvs {
if !first {
write!(f, ",")?;
}
write!(f, "{k}={v}")?;
first = false;
}
Ok(())
}
}
}
}