Skip to content

Commit

Permalink
string: Add append cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
XuShaohua committed Jun 9, 2024
1 parent 5cccad7 commit 4b103ca
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 9 deletions.
14 changes: 14 additions & 0 deletions src/cmd/frame_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum FrameConst {
EmptyArray,
Pong,
Queued,
Str(&'static str),
}

impl FrameConst {
Expand All @@ -27,8 +28,15 @@ impl FrameConst {
Self::EmptyArray => Frame::Array(vec![]),
Self::Pong => Frame::Simple("PONG".to_owned()),
Self::Queued => Frame::Simple("QUEUED".to_owned()),
Self::Str(s) => Frame::Simple(s.to_owned()),
}
}

#[must_use]
#[inline]
pub const fn from_str(s: &'static str) -> Frame {
Frame::Const(Self::Str(s))
}
}

impl Frame {
Expand Down Expand Up @@ -67,6 +75,12 @@ impl Frame {
pub const fn queued() -> Self {
Self::Const(FrameConst::Queued)
}

#[must_use]
#[inline]
pub const fn wrong_type_err() -> Self {
Self::Const(FrameConst::Str(WRONG_TYPE_ERR))
}
}

// Shared command error responses
Expand Down
8 changes: 7 additions & 1 deletion src/cmd/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

use bytes::Bytes;

use crate::cmd::parse::{Parser, ParsingCommandError};
use crate::cmd::Command;
use crate::cmd::parse::{Parser, ParsingCommandError};

#[derive(Debug, Clone)]
pub enum StringCommand {
Append(String, Bytes),
Get(String),
Set(String, Bytes),
StrLen(String),
Expand All @@ -20,6 +21,11 @@ impl StringCommand {
parser: &mut Parser,
) -> Result<Option<Command>, ParsingCommandError> {
let str_cmd = match cmd_name {
"append" => {
let key = parser.next_string()?;
let value = parser.next_bytes()?;
Self::Append(key, value)
}
"get" => {
let key = parser.next_string()?;
Self::Get(key)
Expand Down
5 changes: 2 additions & 3 deletions src/mem/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@

use std::collections::HashMap;

use bytes::Bytes;

use crate::cmd::Command;
use crate::cmd::frame::Frame;
use crate::mem::Mem;
use crate::mem::string::StrObject;

pub type Db = HashMap<String, MemObject>;

#[derive(Debug, Clone)]
pub enum MemObject {
Str(Bytes),
Str(StrObject),
List(String),
}

Expand Down
36 changes: 36 additions & 0 deletions src/mem/string/append.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2024 Xu Shaohua <[email protected]>. All rights reserved.
// Use of this source is governed by GNU Affero General Public License
// that can be found in the LICENSE file.

use std::collections::hash_map::Entry;

use bytes::Bytes;

use crate::cmd::frame::Frame;
use crate::mem::db::{Db, MemObject};
use crate::mem::string::StrObject;

/// If key already exists and is a string, this command appends the value at the end of the string.
/// If key does not exist it is created and set as an empty string,
/// so APPEND will be similar to SET in this special case.
///
/// Returns new length of string.
pub fn append(db: &mut Db, key: String, value: Bytes) -> Frame {
match db.entry(key) {
Entry::Occupied(mut occupied) => match occupied.get_mut() {
MemObject::Str(old_str) => {
old_str.append(value);
let len = old_str.len();
Frame::Integer(len as i64)
}
MemObject::List(_) => {
Frame::wrong_type_err()
}
}
Entry::Vacant(vacant) => {
let len = value.len();
vacant.insert(MemObject::Str(StrObject::from_bytes(value)));
Frame::Integer(len as i64)
}
}
}
6 changes: 2 additions & 4 deletions src/mem/string/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ use crate::mem::db::{Db, MemObject};

pub fn get(db: &Db, key: &str) -> Frame {
match db.get(key) {
Some(MemObject::Str(value)) => Frame::Bulk(value.clone()),
Some(_other) => Frame::Error(
"Object type mismatch, expected string".to_owned(),
),
Some(MemObject::Str(value)) => Frame::Bulk(value.to_bytes()),
Some(_other) => Frame::wrong_type_err(),
None => Frame::null(),
}
}
53 changes: 53 additions & 0 deletions src/mem/string/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,70 @@
// Use of this source is governed by GNU Affero General Public License
// that can be found in the LICENSE file.

use bytes::Bytes;

use crate::cmd::frame::Frame;
use crate::cmd::string::StringCommand;
use crate::mem::Mem;

mod get;
mod set;
mod strlen;
mod append;

#[derive(Debug, Clone)]
pub enum StrObject {
Integer(i64),
Vec(Vec<u8>),
}

impl StrObject {
#[must_use]
#[inline]
pub fn from_bytes(bytes: Bytes) -> Self {
Self::Vec(bytes.to_vec())
}

pub fn append(&mut self, bytes: Bytes) {
match self {
StrObject::Integer(_integer) => todo!(),
StrObject::Vec(vec) => {
let mut bytes_vec = bytes.to_vec();
vec.append(&mut bytes_vec);
}
}
}

pub fn to_bytes(&self) -> Bytes {
match self {
StrObject::Integer(_integer) => todo!(),
StrObject::Vec(vec) => {
Bytes::copy_from_slice(&vec)
}
}
}

#[must_use]
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}

#[must_use]
#[inline]
pub fn len(&self) -> usize {
match self {
// TODO(Shaohua):
StrObject::Integer(_) => 8,
StrObject::Vec(vec) => vec.len(),
}
}
}

impl Mem {
pub fn handle_string_command(&mut self, command: StringCommand) -> Frame {
match command {
StringCommand::Append(key, value) => append::append(&mut self.db, key, value),
StringCommand::Get(key) => get::get(&self.db, &key),
StringCommand::Set(key, value) => set::set(&mut self.db, key, value),
StringCommand::StrLen(key) => strlen::strlen(&self.db, &key),
Expand Down
3 changes: 2 additions & 1 deletion src/mem/string/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use bytes::Bytes;

use crate::cmd::frame::Frame;
use crate::mem::db::{Db, MemObject};
use crate::mem::string::StrObject;

pub fn set(db: &mut Db, key: String, value: Bytes) -> Frame {
db.insert(key, MemObject::Str(value));
db.insert(key, MemObject::Str(StrObject::from_bytes(value)));
Frame::ok()
}

0 comments on commit 4b103ca

Please sign in to comment.