#![deny(missing_docs)]
#![deny(rustdoc::missing_doc_code_examples)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(html_root_url = "https://docs.rs/safe_en/1.8.0")]
use core::fmt;
use std::{fs::File, io::Write};
use table::{Table, TableRow, TypeDefs};
pub mod table;
pub mod utils;
#[derive(Debug, Clone)]
pub struct LoadError;
impl fmt::Display for LoadError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Failed to load db from file")
}
}
pub struct Database {
name: String,
size: usize,
tables: Vec<table::Table>,
}
impl Database {
pub fn new() -> Self {
Database {
tables: Vec::new(),
name: "".to_string(),
size: 0,
}
}
pub fn load(path: &str) -> Result<Self, LoadError> {
let mut db = Database::new();
match db.load_file(path) {
Ok(_) => Ok(db),
Err(_) => Err(LoadError),
}
}
pub fn set_name(&mut self, name: &str) {
self.name = name.to_string();
}
pub fn get_name(&self) -> String {
self.name.clone()
}
#[deprecated(since = "1.5.3")]
pub fn get_size(&self) -> usize {
self.size
}
pub fn get_table_count(&self) -> usize {
self.tables.len()
}
pub fn table(&mut self, table_name: &str) -> Option<&mut Table> {
self.tables.iter_mut().find(|x| x.name == table_name)
}
pub fn table_unwrap(&mut self, table_name: &str) -> &mut Table {
self.tables
.iter_mut()
.find(|x| x.name == table_name)
.unwrap()
}
pub fn remove_table(&mut self, table_name: &str) -> Result<(), ()> {
match self.tables.iter().position(|x| x.get_name() == table_name) {
Some(e) => {
self.tables.remove(e);
Ok(())
}
None => Err(()),
}
}
pub fn create_table(&mut self, table_name: &str, rows: Vec<TableRow>) -> Result<(), ()> {
let table = table::Table {
name: table_name.to_owned(),
headers: rows,
columns: vec![],
};
if self.tables.iter().find(|x| x.name == table_name).is_some() {
return Err(());
} else {
self.tables.push(table);
Ok(())
}
}
fn load_file(&mut self, path: &str) -> Result<(), LoadError> {
let mut file = match File::open(path) {
Ok(it) => it,
Err(_) => return Err(LoadError),
};
let db_name: String = utils::read_data(&mut file, TypeDefs::String).get();
let table_len: u64 = utils::read_data(&mut file, TypeDefs::U64).get();
self.set_name(&db_name);
for _ in 0..table_len {
let table_name: String = utils::read_data(&mut file, TypeDefs::String).get();
let table_headers_len: u64 = utils::read_data(&mut file, TypeDefs::U64).get();
let mut table_rows: Vec<TableRow> = Vec::new();
for _ in 0..table_headers_len {
let table_header: String = utils::read_data(&mut file, TypeDefs::String).get();
let base_header_type: i8 = utils::read_one(&mut file);
let second_header_type: i8 = utils::read_one(&mut file);
let row = TableRow::new(
&table_header,
TypeDefs::from_base_and_second_layer(
base_header_type as u8,
second_header_type as u8,
),
);
table_rows.push(row);
}
match self.create_table(&table_name, table_rows.clone()) {
Ok(it) => it,
Err(_) => return Err(LoadError),
};
let table_rows_len: u64 = utils::read_data(&mut file, TypeDefs::U64).get();
for _ in 0..table_rows_len {
let mut tables = vec![];
for table_row in &table_rows {
let row_value = utils::read_data(&mut file, table_row.rtype.clone());
tables.push(row_value);
}
match self.table(&table_name) {
Some(it) => match it.insert(tables.clone()) {
Ok(_) => (),
Err(_) => return Err(LoadError),
},
None => return Err(LoadError),
}
}
}
Ok(())
}
pub fn save(&self, path: &str) {
let mut bytes = vec![];
utils::extend_bytes_from_raw_type(&mut bytes, &utils::type_to_bytes(self.name.clone()));
utils::extend_bytes_from_raw_type(
&mut bytes,
&utils::type_to_bytes(self.tables.len() as u64),
);
for table in self.tables.iter() {
utils::extend_bytes_from_raw_type(
&mut bytes,
&utils::type_to_bytes(table.name.clone()),
);
utils::extend_bytes_from_raw_type(
&mut bytes,
&utils::type_to_bytes(table.headers.len() as u64),
);
for header in table.headers.iter() {
utils::extend_bytes_from_raw_type(
&mut bytes,
&utils::type_to_bytes(header.key.clone()),
);
bytes.extend(header.rtype.get_base_and_second_layer());
}
utils::extend_bytes_from_raw_type(
&mut bytes,
&utils::type_to_bytes(table.columns.len() as u64),
);
for row in table.columns.iter() {
for _data in row.iter() {
let data = utils::type_to_bytes(_data.clone().get_type());
utils::extend_bytes_from_raw_type(&mut bytes, &data);
}
}
}
let mut file = match File::create(path) {
Ok(it) => it,
Err(_) => return,
};
match file.write_all(&bytes) {
Ok(it) => it,
Err(_) => return,
};
}
}