small-db 0.4.0

A small database writing in rust, inspired from mit 6.830
Documentation
use std::{
    fmt::{self},
    usize,
};

use super::page::BTreePageID;
use crate::{
    field::*,
    io::{Condensable, Vaporizable},
};

#[derive(Default)]
pub struct Tuple {
    pub scheme: Schema,
    pub fields: Vec<IntField>,
}

impl Tuple {
    pub fn new(scheme: Schema, bytes: &[u8]) -> Tuple {
        let mut cells: Vec<IntField> = Vec::new();
        let mut start: usize = 0;
        let mut end: usize = 0;
        for field in &scheme.fields {
            match field.field_type {
                Type::INT => {
                    end += get_type_length(field.field_type);
                    let cell_bytes = &bytes[start..end];

                    let mut bytes_array = [0; 4];
                    for i in 0..4 {
                        bytes_array[i] = cell_bytes[i];
                    }
                    let value = i32::from_be_bytes(bytes_array);

                    cells.push(IntField::new(value));

                    start = end;
                }
            }
        }
        Tuple {
            scheme,
            fields: cells,
        }
    }

    pub fn new_default_tuple(scheme: Schema, _width: usize) -> Tuple {
        let mut cells: Vec<IntField> = Vec::new();
        for field in &scheme.fields {
            match field.field_type {
                Type::INT => {
                    cells.push(IntField::new(0));
                }
            }
        }
        Tuple {
            scheme,
            fields: cells,
        }
    }

    pub fn new_btree_tuple(value: i32, width: usize) -> Tuple {
        let scheme = small_int_schema(width, "");
        let _bytes = [0];
        let mut tuple = Tuple::new_default_tuple(scheme, width);
        for i in 0..tuple.fields.len() {
            tuple.set_field(i, IntField::new(value));
        }
        tuple
    }

    pub fn set_field(&mut self, i: usize, c: IntField) {
        self.fields[i] = c;
    }

    pub fn get_field(&self, i: usize) -> IntField {
        self.fields[i]
    }

    pub fn clone(&self) -> Tuple {
        Tuple {
            scheme: self.scheme.clone(),
            fields: self.fields.to_vec(),
        }
    }

    pub fn read_from(
        reader: &mut crate::io::SmallReader,
        tuple_scheme: &Schema,
    ) -> Self {
        let mut cells: Vec<IntField> = Vec::new();
        for field in &tuple_scheme.fields {
            match field.field_type {
                Type::INT => {
                    cells.push(IntField::read_from(reader));
                }
            }
        }
        Tuple {
            scheme: tuple_scheme.clone(),
            fields: cells,
        }
    }
}

impl Condensable for Tuple {
    fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::new();
        for cell in &self.fields {
            let mut cell_bytes = cell.to_bytes();
            bytes.append(&mut cell_bytes);
        }
        bytes
    }
}

impl PartialEq for Tuple {
    fn eq(&self, other: &Self) -> bool {
        if self.scheme != other.scheme {
            return false;
        }

        for (i, field) in self.fields.iter().enumerate() {
            if field != &other.fields[i] {
                return false;
            }
        }

        return true;
    }
}

impl Eq for Tuple {}

impl fmt::Display for Tuple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut content: String = "{".to_owned();
        for cell in &self.fields {
            let cell_str = format!("{}, ", cell.value);
            content.push_str(&cell_str);
        }
        content = content[..content.len() - 2].to_string();
        content.push_str(&"}");
        write!(f, "{}", content,)
    }
}

impl fmt::Debug for Tuple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

#[derive(PartialEq)]
pub struct WrappedTuple {
    internal: Tuple,
    slot_number: usize,
    pid: BTreePageID,
}

impl std::ops::Deref for WrappedTuple {
    type Target = Tuple;
    fn deref(&self) -> &Self::Target {
        &self.internal
    }
}

impl std::ops::DerefMut for WrappedTuple {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.internal
    }
}

impl WrappedTuple {
    pub fn new(
        internal: Tuple,
        slot_number: usize,
        pid: BTreePageID,
    ) -> WrappedTuple {
        WrappedTuple {
            internal,
            slot_number,
            pid,
        }
    }

    pub fn get_slot_number(&self) -> usize {
        self.slot_number
    }

    pub fn get_pid(&self) -> BTreePageID {
        self.pid
    }
}

impl Eq for WrappedTuple {}

impl fmt::Display for WrappedTuple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut content: String = "{".to_owned();
        for cell in &self.fields {
            let cell_str = format!("{}, ", cell.value);
            content.push_str(&cell_str);
        }
        content = content[..content.len() - 2].to_string();
        content.push_str(&"}");
        write!(f, "{}", content,)
    }
}

impl fmt::Debug for WrappedTuple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

#[derive(Debug)]
pub struct Schema {
    pub fields: Vec<FieldItem>,
}

impl PartialEq for Schema {
    fn eq(&self, other: &Self) -> bool {
        let matching = self
            .fields
            .iter()
            .zip(&other.fields)
            .filter(|&(a, b)| a == b)
            .count();
        self.fields.len() == matching
    }
}

impl Schema {
    pub fn merge(scheme1: Schema, scheme2: Schema) -> Schema {
        let mut new_scheme = Schema {
            ..Default::default()
        };

        for f in scheme1.fields {
            new_scheme.fields.push(f);
        }
        for f in scheme2.fields {
            new_scheme.fields.push(f);
        }

        new_scheme
    }

    /// get tuple size in bytes
    pub fn get_size(&self) -> usize {
        self.fields.len() * 4
    }
}

impl Clone for Schema {
    fn clone(&self) -> Self {
        Self {
            fields: self.fields.to_vec(),
        }
    }
}

impl Default for Schema {
    fn default() -> Schema {
        Schema { fields: Vec::new() }
    }
}

pub fn small_int_schema(width: usize, name_prefix: &str) -> Schema {
    let mut fields: Vec<FieldItem> = Vec::new();
    for i in 0..width {
        let field = FieldItem {
            field_name: format!("{}-{}", name_prefix, i),
            field_type: Type::INT,
        };
        fields.push(field);
    }

    Schema { fields: fields }
}

#[cfg(test)]
mod tests {
    use log::debug;

    use super::*;
    use crate::utils::init_log;

    #[test]
    fn test_tuple_clone() {
        init_log();

        let tuple = Tuple::new_btree_tuple(35, 2);
        debug!("tuple: {}", tuple);
        let new_tuple = tuple.clone();
        debug!("new tuple: {}", new_tuple);
    }
}