Skip to content

Commit

Permalink
Sarthak | Adds support for encoding and decoding Command
Browse files Browse the repository at this point in the history
  • Loading branch information
SarthakMakhija committed Jul 19, 2024
1 parent 5aa0064 commit 0708541
Showing 1 changed file with 100 additions and 5 deletions.
105 changes: 100 additions & 5 deletions src/executor/command.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::io::Error;
use std::io::{Error, Read};

use bytes::{Buf, BufMut, BytesMut};

use crate::memory::key_value::KeyValue;

#[derive(Copy, Clone, PartialEq, Debug)]
pub(crate) enum CommandType {
Get,
Put,
Update,
Get = 1,
Put = 2,
Update = 3,
}
pub(crate) struct Command {
pub(crate) key: Vec<u8>,
Expand All @@ -18,6 +21,17 @@ pub(crate) enum CommandResponse {
Get(Option<Result<KeyValue, Error>>),
}

impl From<u8> for CommandType {
fn from(value: u8) -> Self {
match value {
1 => CommandType::Get,
2 => CommandType::Put,
3 => CommandType::Update,
_ => panic!("Unknown command type")
}
}
}

impl Command {
pub(crate) fn get(key: Vec<u8>) -> Self {
Command {
Expand All @@ -41,6 +55,40 @@ impl Command {
command_type: CommandType::Update,
}
}

pub(crate) fn encode(&self) -> BytesMut {
let mut buffer = BytesMut::new();
buffer.put_u16_le(self.key.len() as u16);
buffer.put_u16_le(self.value.as_ref().map_or(0, |value| value.len()) as u16);
buffer.put_u8(self.command_type as u8);
buffer.put_slice(&self.key);
buffer.put_slice(self.value.as_ref().map_or(&Vec::new(), |value| value));
buffer
}

pub(crate) fn decode_from(mut buffer: BytesMut) -> Result<Self, Error> {
let key_length = buffer.get_u16_le();
let value_length = buffer.get_u16_le();
let command_type = buffer.get_u8();

let mut buffer_reader = buffer.reader();

let mut key = Vec::with_capacity(key_length as usize);
key.resize(key_length as usize, 0);
buffer_reader.read_exact(&mut key)?;

let mut value = Vec::with_capacity(value_length as usize);
value.resize(value_length as usize, 0);
buffer_reader.read_exact(&mut value)?;

Ok(
Command {
key,
value: if value.is_empty() { None } else { Some(value) },
command_type: CommandType::from(command_type),
}
)
}
}

impl CommandResponse {
Expand Down Expand Up @@ -81,8 +129,55 @@ impl CommandResponse {

pub(crate) fn get_response(self) -> Option<Result<KeyValue, Error>> {
if let CommandResponse::Get(response) = self {
return response
return response;
}
None
}
}

#[cfg(test)]
mod tests {
use crate::executor::command::{Command, CommandType};

#[test]
fn encodes_and_decodes_a_get_command() {
let get = Command::get(Vec::from(b"raft"));
let encoded = get.encode();

let decoded_result = Command::decode_from(encoded);
assert_eq!(true, decoded_result.is_ok());

let decoded = decoded_result.unwrap();
assert_eq!(CommandType::Get, decoded.command_type);
assert_eq!(Vec::from(b"raft"), decoded.key);
assert_eq!(true, decoded.value.is_none());
}

#[test]
fn encodes_and_decodes_a_put_command() {
let put = Command::put(Vec::from(b"raft"), Vec::from(b"consensus"));
let encoded = put.encode();

let decoded_result = Command::decode_from(encoded);
assert_eq!(true, decoded_result.is_ok());

let decoded = decoded_result.unwrap();
assert_eq!(CommandType::Put, decoded.command_type);
assert_eq!(Vec::from(b"raft"), decoded.key);
assert_eq!(Vec::from(b"consensus"), decoded.value.unwrap());
}

#[test]
fn encodes_and_decodes_an_update_command() {
let update = Command::update(Vec::from(b"raft"), Vec::from(b"consensus"));
let encoded = update.encode();

let decoded_result = Command::decode_from(encoded);
assert_eq!(true, decoded_result.is_ok());

let decoded = decoded_result.unwrap();
assert_eq!(CommandType::Update, decoded.command_type);
assert_eq!(Vec::from(b"raft"), decoded.key);
assert_eq!(Vec::from(b"consensus"), decoded.value.unwrap());
}
}

0 comments on commit 0708541

Please sign in to comment.