Skip to content

Commit

Permalink
Merge branch 'dev-database' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
maxfierrog committed Apr 11, 2024
2 parents 516ec0c + 619b64d commit d64aba6
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 94 deletions.
1 change: 1 addition & 0 deletions src/database/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ impl fmt::Display for DatabaseError {
table,
} => {
let rule = match data {
Datatype::BOOL => "of exactly 1 bit",
Datatype::DPFP => "of exactly 64 bits",
Datatype::SPFP => "of exactly 32 bits",
Datatype::SINT => "greater than 1 bit",
Expand Down
17 changes: 7 additions & 10 deletions src/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ use std::path::Path;

use crate::{model::State, solver::RecordType};

/* RE-EXPORTS */

pub use util::SchemaBuilder;

/* UTILITY MODULES */

#[cfg(test)]
Expand Down Expand Up @@ -44,15 +48,6 @@ pub struct Schema {
size: usize,
}

/// Builder pattern intermediary for constructing a schema declaratively out of
/// provided attributes. This is here to help ensure schemas are not changed
/// accidentally after being instantiated.
pub struct SchemaBuilder {
attributes: Vec<Attribute>,
record: Option<RecordType>,
size: usize,
}

/// Represents a triad of a name string, a size in bits corresponding to an
/// "attribute" or "feature" associated with a database record, and the type
/// of the data it represents.
Expand All @@ -66,6 +61,7 @@ pub struct Attribute {
/// Specifies the type of data being stored within a record within a specific
/// contiguous subset of bits. This is used for interpretation. Here is the
/// meaning of each variant, with its possible sizes in bits:
/// - `BOOL`: Boolean of size exactly 1.
/// - `ENUM`: Enumeration of arbitrary size.
/// - `UINT`: Unsigned integer of arbitrary size.
/// - `SINT`: Signed integer of size greater than 1.
Expand All @@ -74,6 +70,7 @@ pub struct Attribute {
/// - `CSTR`: C-style string (ASCII character array) of a size divisible by 8.
#[derive(Debug, Copy, Clone)]
pub enum Datatype {
BOOL,
ENUM,
UINT,
SINT,
Expand All @@ -89,7 +86,7 @@ pub enum Datatype {
pub trait KVStore<R: Record> {
fn put(&mut self, key: State, record: &R);
fn get(&self, key: State) -> Option<&BitSlice<u8, Msb0>>;
fn del(&self, key: State);
fn del(&mut self, key: State);
}

/// Allows a database to be evicted to persistent media. Implementing this trait
Expand Down
180 changes: 98 additions & 82 deletions src/database/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,26 @@ use crate::database::error::DatabaseError;
use crate::database::Attribute;
use crate::database::Datatype;
use crate::database::Schema;
use crate::database::SchemaBuilder;
use crate::solver::RecordType;

/* DEFINITIONS */

/// Builder pattern intermediary for constructing a schema declaratively out of
/// provided attributes. This is here to help ensure schemas are not changed
/// accidentally after being instantiated.
pub struct SchemaBuilder {
attributes: Vec<Attribute>,
record: Option<RecordType>,
size: usize,
}

/// Iterator over borrows of the attributes that form a database table schema.
pub struct SchemaIterator<'a> {
schema: &'a Schema,
index: usize,
}

/* UTILITY IMPLEMENTATIONS */

impl ToString for Datatype {
fn to_string(&self) -> String {
match self {
Datatype::DPFP => "Double-Precision Floating Point".to_string(),
Datatype::SPFP => "Single-Precision Floating Point".to_string(),
Datatype::CSTR => "C-Style ASCII String".to_string(),
Datatype::UINT => "Unsigned Integer".to_string(),
Datatype::SINT => "Signed Integer".to_string(),
Datatype::ENUM => "Enumeration".to_string(),
}
}
}

impl<'a> IntoIterator for &'a Schema {
type IntoIter = SchemaIterator<'a>;
type Item = &'a Attribute;

fn into_iter(self) -> Self::IntoIter {
SchemaIterator {
schema: self,
index: 0,
}
}
}

impl<'a> Iterator for SchemaIterator<'a> {
type Item = &'a Attribute;

fn next(&mut self) -> Option<Self::Item> {
self.index += 1;
self.schema
.attributes
.get(self.index - 1)
}
}
/* BUILDER IMPLEMENTATION */

impl SchemaBuilder {
/// Returns a new instance of a `SchemaBuilder`, which can be used to
Expand All @@ -77,7 +49,7 @@ impl SchemaBuilder {
/// Associates `attr` to the schema under construction. Returns an error
/// if adding `attr` to the schema would result in an invalid state.
pub fn add(mut self, attr: Attribute) -> Result<Self> {
check_attribute_validity(&self.attributes, &attr)?;
self.check_attribute_validity(&attr)?;
self.size += attr.size();
Ok(self)
}
Expand All @@ -96,53 +68,97 @@ impl SchemaBuilder {
size: self.size,
}
}

/* VERIFICATION METHODS */

/// Verifies that adding a `new` attribute to tje existing set of attributes
/// would not result in an invalid state for the schema under construction,
/// and that the added attribute does not break any datatype sizing rules.
fn check_attribute_validity(
&self,
new: &Attribute,
) -> Result<(), DatabaseError> {
if new.name().is_empty() {
Err(DatabaseError::UnnamedAttribute { table: None })
} else if new.size() == 0 {
Err(DatabaseError::EmptyAttribute { table: None })
} else if self
.attributes
.iter()
.any(|a| a.name() == new.name())
{
Err(DatabaseError::RepeatedAttribute {
name: new.name().to_string(),
table: None,
})
} else {
Self::check_datatype_validity(new)?;
Ok(())
}
}

/// Verifies that the datatype in an attribute is coherent with its
/// indicated size, which is specific to each valid datatype.
fn check_datatype_validity(new: &Attribute) -> Result<(), DatabaseError> {
let s = new.size();
if match new.datatype() {
Datatype::SINT => s < 2,
Datatype::BOOL => s != 1,
Datatype::SPFP => s != 32,
Datatype::DPFP => s != 64,
Datatype::CSTR => s % 8 != 0,
Datatype::UINT | Datatype::ENUM => {
unreachable!("UINTs and ENUMs can be of any nonzero size.")
},
} {
Err(DatabaseError::InvalidSize {
size: new.size(),
name: new.name().to_string(),
data: new.datatype(),
table: None,
})
} else {
Ok(())
}
}
}

/* FUNCTIONS */

/// Verifies that adding a `new` attribute to an `existing` set of attributes
/// would not result in an invalid state for the schema who owns `existing`,
/// and that the added attribute does not break any datatype sizing rules.
pub fn check_attribute_validity(
existing: &Vec<Attribute>,
new: &Attribute,
) -> Result<(), DatabaseError> {
if new.name().is_empty() {
Err(DatabaseError::UnnamedAttribute { table: None })
} else if new.size() == 0 {
Err(DatabaseError::EmptyAttribute { table: None })
} else if existing
.iter()
.any(|a| a.name() == new.name())
{
Err(DatabaseError::RepeatedAttribute {
name: new.name().to_string(),
table: None,
})
} else {
check_datatype_validity(new)?;
Ok(())
/* UTILITY IMPLEMENTATIONS */

impl ToString for Datatype {
fn to_string(&self) -> String {
match self {
Datatype::DPFP => "Double-Precision Floating Point".to_string(),
Datatype::SPFP => "Single-Precision Floating Point".to_string(),
Datatype::CSTR => "C-Style ASCII String".to_string(),
Datatype::UINT => "Unsigned Integer".to_string(),
Datatype::SINT => "Signed Integer".to_string(),
Datatype::ENUM => "Enumeration".to_string(),
Datatype::BOOL => "Boolean".to_string(),
}
}
}

fn check_datatype_validity(new: &Attribute) -> Result<(), DatabaseError> {
let s = new.size();
if match new.datatype() {
Datatype::SINT => s < 2,
Datatype::SPFP => s != 32,
Datatype::DPFP => s != 64,
Datatype::CSTR => s % 8 != 0,
Datatype::UINT | Datatype::ENUM => {
unreachable!("UINTs and ENUMs can be of any nonzero size.")
},
} {
Err(DatabaseError::InvalidSize {
size: new.size(),
name: new.name().to_string(),
data: new.datatype(),
table: None,
})
} else {
Ok(())
impl<'a> IntoIterator for &'a Schema {
type IntoIter = SchemaIterator<'a>;

type Item = &'a Attribute;

fn into_iter(self) -> Self::IntoIter {
SchemaIterator {
schema: self,
index: 0,
}
}
}

impl<'a> Iterator for SchemaIterator<'a> {
type Item = &'a Attribute;

fn next(&mut self) -> Option<Self::Item> {
self.index += 1;
self.schema
.attributes
.get(self.index - 1)
}
}
2 changes: 1 addition & 1 deletion src/database/vector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<R: Record> KVStore<R> for Database<'_> {
todo!()
}

fn del(&self, key: State) {
fn del(&mut self, key: State) {
todo!()
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/database/volatile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl<R: Record> KVStore<R> for Database<'_> {
todo!()
}

fn del(&self, key: State) {
fn del(&mut self, key: State) {
todo!()
}
}
Expand Down

0 comments on commit d64aba6

Please sign in to comment.