diff --git a/Cargo.lock b/Cargo.lock index 1821803..67baf94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,126 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "const_format" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22bc6cd49b0ec407b680c3e380182b6ac63b73991cb7602de350352fc309b614" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef196d5d972878a48da7decb7686eded338b4858fbabeed513d63a7c98b2b82d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "sqlite_clone" version = "0.1.0" +dependencies = [ + "sscanf", +] + +[[package]] +name = "sscanf" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6311683a27f16025db4f8bcf0732662f5fecd1406f53f0aab9adbf6f396f1189" +dependencies = [ + "const_format", + "lazy_static", + "regex", + "sscanf_macro", +] + +[[package]] +name = "sscanf_macro" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d1d364d856d72a52b518c7669df864bdf177de242bcb5b45369ec33190c91c3" +dependencies = [ + "proc-macro2", + "quote", + "regex-syntax", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/Cargo.toml b/Cargo.toml index 3cbba4a..352ae23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +sscanf = {version="0.2.1"} diff --git a/src/main.rs b/src/main.rs index bda67d2..85cfba8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +mod statement; + use std::io; use std::io::Write; use std::process::exit; @@ -6,33 +8,6 @@ struct InputBuffer { buffer: Option, } -enum StatementType { - Insert, - Select, -} - -struct Statement { - statement_type: StatementType, -} - -impl Statement { - fn new(statement_type: StatementType) -> Self { - Self { - statement_type - } - } - - pub(crate) fn execute(&self) { - match self.statement_type { - StatementType::Insert => { - println!("This is where you do an insert") - } - StatementType::Select => { - println!("This is where you do an select") - } - } - } -} impl InputBuffer { pub fn new() -> Self { @@ -69,10 +44,13 @@ impl InputBuffer { if command.starts_with(".") { Self::handle_meta_statement(command); } else { - if let Ok(statement) = Self::prepare_statement(command) { - statement.execute() - } else { - println!("could not recognize statement"); + match Self::prepare_statement(&command.replace("\n", "")) { + Ok(statement) => { + statement.execute() + } + Err(e) => { + println!("{}", e); + } } } } @@ -80,14 +58,8 @@ impl InputBuffer { } } - fn prepare_statement(command: &String) -> Result { - if command.starts_with("insert") { - Ok(Statement::new(StatementType::Insert)) - } else if command.starts_with("select") { - Ok(Statement::new(StatementType::Select)) - } else { - Err(String::from("Unrecognized statement")) - } + fn prepare_statement(command: &String) -> Result { + return statement::Statement::parse_statement(command); } fn handle_meta_statement(command: &String) { diff --git a/src/statement.rs b/src/statement.rs new file mode 100644 index 0000000..2903eb6 --- /dev/null +++ b/src/statement.rs @@ -0,0 +1,95 @@ +use std::io::Write; +use std::mem::size_of; + +pub enum StatementType { + Insert { + row: Row + }, + Select, +} + +const COLUMN_USERNAME_SIZE: usize = 32; +const COLUMN_EMAIL_SIZE: usize = 255; + +pub struct Row { + id: u32, + username: [u8; COLUMN_USERNAME_SIZE], + email: [u8; COLUMN_EMAIL_SIZE], +} + +impl Row { + fn new(id: u32, username: String, email: String) -> Result { + let username_bytes = username.as_bytes(); + let email_bytes = email.as_bytes(); + if username_bytes.len() > COLUMN_USERNAME_SIZE { + Err(String::from("username is too long")) + } else if email_bytes.len() > COLUMN_EMAIL_SIZE { + Err(String::from("email is too long")) + } else { + let username_buffer = &mut [0; COLUMN_USERNAME_SIZE]; + if let Err(_) = pad_buffer(username_buffer, username_bytes) { + panic!("could not pad username buffer") + } + let email_buffer = &mut [0; COLUMN_EMAIL_SIZE]; + if let Err(_) = pad_buffer(email_buffer, username_bytes) { + panic!("could not pad username buffer") + } + Ok(Self { + id, + username: *username_buffer, + email: *email_buffer, + }) + } + } +} + +fn pad_buffer(mut bytes: &mut [u8], source: &[u8]) -> std::io::Result { + bytes.write(source) +} + +pub struct Statement { + statement_type: StatementType, +} + +impl Statement { + pub fn new(statement_type: StatementType) -> Self { + Self { + statement_type, + } + } + + pub fn parse_statement(command: &String) -> Result { + if command.starts_with("insert") { + match sscanf::scanf!(command, "insert {} {} {}", usize, str, str) { + Ok((id, username, email)) => { + match Row::new(u32::try_from(id).unwrap(), username.to_string(), email.to_string()) { + Ok(row) => { + Ok(Statement::new(StatementType::Insert { row: row })) + } + Err(e) => { Err(e) } + } + } + _ => { + Err(String::from("could not parse insert statement")) + } + } + } else if command.starts_with("select") { + Ok(Statement::new(StatementType::Select)) + } else { + return Err(String::from("Could not parse command")); + } + } + + pub(crate) fn execute(&self) { + match &self.statement_type { + StatementType::Insert { row } => { + println!("This is where you do an insert {}", row.id) + } + StatementType::Select => { + println!("This is where you do an select") + } + } + } +} + +