#![deny(missing_docs)]
mod row;
pub use row::*;
pub mod example_schema;
pub mod repr;
use std::{
cmp::Ordering,
collections::HashMap,
fmt, fs,
hash::{Hash, Hasher},
marker::PhantomData,
ops::{Deref, DerefMut},
path::{Path, PathBuf},
sync::{RwLockReadGuard, RwLockWriteGuard},
};
use serde::{de::DeserializeOwned, Serialize};
use serde_derive::{Deserialize as Des, Serialize as Ser};
use uuid::Uuid;
pub use crate::repr::*;
pub mod prelude {
pub use crate::{repr::*, schema, HasRows, HasRowsMut, Id, OwnedRow, Row, RowMut, Table};
pub use serde_derive::{Deserialize, Serialize};
}
#[doc(hidden)]
pub use mashup;
#[derive(Debug)]
pub enum Error {
Io(std::io::Error),
Serialization(String),
}
macro_rules! error_from {
($variant:ident: $type:ty) => {
impl From<$type> for Error {
fn from(e: $type) -> Self {
Error::$variant(e)
}
}
};
($variant:ident<$param:ident>: $type:ty) => {
impl From<$type> for Error<$param> {
fn from(e: $type) -> Self {
Error::$variant(e)
}
}
};
}
error_from!(Io: std::io::Error);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match self {
Io(e) => write!(f, "{}", e),
Serialization(e) => write!(f, "{}", e),
}
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Ser, Des)]
#[serde(transparent)]
pub struct Id<T> {
uuid: Uuid,
#[serde(skip)]
pd: PhantomData<T>,
}
impl<T> Id<T> {
pub fn new() -> Self {
Id {
uuid: Uuid::new_v4(),
pd: PhantomData,
}
}
}
impl<T> Clone for Id<T> {
fn clone(&self) -> Self {
Id {
uuid: self.uuid,
pd: PhantomData,
}
}
}
impl<T> Copy for Id<T> {}
impl<T> PartialEq for Id<T> {
fn eq(&self, other: &Self) -> bool {
self.uuid.eq(&other.uuid)
}
}
impl<T> Eq for Id<T> {}
impl<T> PartialOrd for Id<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.uuid.partial_cmp(&other.uuid)
}
}
impl<T> Ord for Id<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.uuid.cmp(&other.uuid)
}
}
impl<T> Hash for Id<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.uuid.hash(state);
}
}
impl<T> fmt::Debug for Id<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.uuid.to_simple())
}
}
impl<T> fmt::Display for Id<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.uuid.to_simple())
}
}
impl<T> Default for Id<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> std::str::FromStr for Id<T> {
type Err = uuid::Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
s.parse::<Uuid>().map(|uuid| Id {
uuid,
pd: PhantomData,
})
}
}
#[derive(Clone, Ser, Des)]
#[serde(transparent)]
pub struct Table<T> {
map: HashMap<Id<T>, T>,
}
impl<T> Table<T> {
pub fn new() -> Self {
Table {
map: HashMap::new(),
}
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn insert(&mut self, row: T) -> Id<T> {
let id = Id::new();
self.map.insert(id, row);
id
}
pub fn get(&self, id: Id<T>) -> Option<&T> {
self.map.get(&id)
}
pub fn get_mut(&mut self, id: Id<T>) -> Option<&mut T> {
self.map.get_mut(&id)
}
pub fn remove(&mut self, id: Id<T>) -> Option<T> {
self.map.remove(&id)
}
pub fn rows(&self) -> RowIter<T> {
RowIter {
inner: self.map.iter(),
}
}
pub fn rows_mut(&mut self) -> RowIterMut<T> {
RowIterMut {
inner: self.map.iter_mut(),
}
}
pub fn delete_one(&mut self, id: Id<T>) -> Option<T> {
self.remove(id)
}
pub fn delete_where<F>(&mut self, f: F) -> usize
where
F: Fn(&T) -> bool,
{
let count = self.map.values().filter(|data| f(data)).count();
self.map.retain(|_, data| !f(data));
count
}
pub fn delete_iter<'a, F, I, R>(&'a mut self, f: F)
where
F: Fn(&'a Self) -> I,
I: IntoIterator<Item = R>,
R: Idd<RowType = T>,
{
let ids: Vec<Id<T>> = f(unsafe { (self as *mut Self).as_mut() }.unwrap())
.into_iter()
.map(|row| row.id())
.collect();
for id in ids {
self.remove(id);
}
}
}
impl<T> Default for Table<T> {
fn default() -> Self {
Table {
map: Default::default(),
}
}
}
impl<T> fmt::Debug for Table<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list().entries(self.map.iter()).finish()
}
}
impl<T> Table<T>
where
T: Serialize,
{
pub fn save<P>(&self, path: P, repr: Representation) -> Result<()>
where
P: AsRef<Path>,
{
fs::write(path, self.save_to_bytes(repr)?)?;
Ok(())
}
pub fn save_to_bytes(&self, repr: Representation) -> Result<Vec<u8>> {
repr.serialize(self).map_err(|e| Error::Serialization(e))
}
}
impl<T> Table<T>
where
T: DeserializeOwned,
{
pub fn load<P>(path: P, repr: Representation) -> Result<Self>
where
P: AsRef<Path>,
{
Table::load_from_bytes(fs::read(path)?, repr)
}
pub fn load_from_bytes<B: AsRef<[u8]>>(bytes: B, repr: Representation) -> Result<Self> {
repr.deserialize(bytes).map_err(|e| Error::Serialization(e))
}
}
pub trait HasRows: Sized {
type Iter: Iterator;
fn rows(self) -> Self::Iter;
fn select<F, R>(self, f: F) -> Select<Self::Iter, F>
where
F: Fn(<Self::Iter as Iterator>::Item) -> R,
{
Select {
iter: self.rows(),
selector: f,
}
}
fn relate<R, F>(self, other: R, f: F) -> Relate<Self::Iter, R::Iter, F>
where
R: HasRows,
R::Iter: Clone,
<Self::Iter as Iterator>::Item: Clone,
F: Fn(&<Self::Iter as Iterator>::Item, &<R::Iter as Iterator>::Item) -> bool,
{
Relate::new(self.rows(), other.rows(), f)
}
fn wher<F>(self, f: F) -> Where<Self::Iter, F>
where
F: Fn(&<Self::Iter as Iterator>::Item) -> bool,
{
Where {
iter: self.rows(),
clause: f,
}
}
fn find<F>(self, f: F) -> Option<<Self::Iter as Iterator>::Item>
where
F: Fn(&<Self::Iter as Iterator>::Item) -> bool,
{
self.wher(f).next()
}
}
#[derive(Debug)]
pub struct TableGuard<'a, T>(#[doc(hidden)] pub RwLockReadGuard<'a, Table<T>>);
impl<'a, T> Deref for TableGuard<'a, T> {
type Target = Table<T>;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
#[derive(Debug, Clone)]
#[doc(hidden)]
pub struct SaveParams {
pub path: PathBuf,
pub repr: Representation,
}
impl SaveParams {
#[doc(hidden)]
pub fn for_table_guard(&self, table: &str) -> Self {
SaveParams {
path: self.path.join(table).with_extension("yaml"),
repr: self.repr,
}
}
}
impl Default for SaveParams {
fn default() -> Self {
SaveParams {
path: PathBuf::from("database"),
repr: HumanReadable,
}
}
}
#[derive(Debug)]
pub struct TableGuardMut<'a, T>
where
T: Serialize,
{
#[doc(hidden)]
pub guard: RwLockWriteGuard<'a, Table<T>>,
#[doc(hidden)]
pub params: SaveParams,
}
impl<'a, T> TableGuardMut<'a, T>
where
T: Serialize,
{
pub fn path(&self) -> PathBuf {
self.params.path.clone()
}
}
impl<'a, T> Deref for TableGuardMut<'a, T>
where
T: Serialize,
{
type Target = Table<T>;
fn deref(&self) -> &Self::Target {
self.guard.deref()
}
}
impl<'a, T> DerefMut for TableGuardMut<'a, T>
where
T: Serialize,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.guard.deref_mut()
}
}
impl<'a, T> Drop for TableGuardMut<'a, T>
where
T: Serialize,
{
fn drop(&mut self) {
let _ = Table::<T>::save(&self.guard, &self.params.path, self.params.repr);
}
}
impl<I> HasRows for I
where
I: Iterator,
{
type Iter = I;
fn rows(self) -> Self::Iter {
self
}
}
impl<'a, T> HasRows for &'a Table<T> {
type Iter = RowIter<'a, T>;
fn rows(self) -> Self::Iter {
Table::rows(self)
}
}
impl<'a, T> HasRows for &'a mut Table<T> {
type Iter = RowIter<'a, T>;
fn rows(self) -> Self::Iter {
Table::rows(self)
}
}
pub trait HasRowsMut: Sized {
type Iter: Iterator;
fn rows_mut(self) -> Self::Iter;
fn update(self) -> Self::Iter {
self.rows_mut()
}
}
impl<I> HasRowsMut for I
where
I: Iterator,
{
type Iter = I;
fn rows_mut(self) -> Self::Iter {
self
}
}
impl<'a, T> HasRowsMut for &'a mut Table<T> {
type Iter = RowIterMut<'a, T>;
fn rows_mut(self) -> Self::Iter {
Table::rows_mut(self)
}
}
pub struct Select<I, F> {
iter: I,
selector: F,
}
impl<I, F, R> Iterator for Select<I, F>
where
I: Iterator,
F: Fn(I::Item) -> R,
{
type Item = R;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(&self.selector)
}
}
pub struct Relate<A, B, F>
where
A: Iterator,
B: Iterator + Clone,
A::Item: Clone,
{
iter_a: A,
iter_b: B,
curr_a: Option<A::Item>,
curr_b: B,
relation: F,
}
impl<A, B, F> Relate<A, B, F>
where
A: Iterator,
B: Iterator + Clone,
A::Item: Clone,
{
fn new(mut iter_a: A, iter_b: B, f: F) -> Self {
let curr_a = iter_a.next();
Relate {
iter_a,
iter_b: iter_b.clone(),
curr_a,
curr_b: iter_b,
relation: f,
}
}
}
impl<A, B, F> Iterator for Relate<A, B, F>
where
A: Iterator,
B: Iterator + Clone,
A::Item: Clone,
F: Fn(&A::Item, &B::Item) -> bool,
{
type Item = (A::Item, B::Item);
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(ref a) = self.curr_a {
if let Some(b) = self.curr_b.next() {
if (self.relation)(a, &b) {
return Some((a.clone(), b));
}
} else if let Some(next_a) = self.iter_a.next() {
self.curr_a = Some(next_a);
self.curr_b = self.iter_b.clone();
} else {
return None;
}
} else {
return None;
}
}
}
}
pub struct Where<I, F> {
iter: I,
clause: F,
}
impl<I, F> Iterator for Where<I, F>
where
I: Iterator,
F: Fn(&I::Item) -> bool,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(next) = self.iter.next() {
if (self.clause)(&next) {
return Some(next);
}
} else {
return None;
}
}
}
}
#[macro_export]
macro_rules! schema {
($(#[$struct_attr:meta])* $name:ident { $($table:ident: $type:ty),* $(,)* }) => {
$(#[$struct_attr])*
struct $name {
params: rql::SaveParams,
$($table: std::sync::RwLock<rql::Table<$type>>),*
}
schema!(impl $name { $($table: $type),* });
};
($(#[$struct_attr:meta])* pub $name:ident { $($table:ident: $type:ty),* $(,)* }) => {
$(#[$struct_attr])*
pub struct $name {
params: rql::SaveParams,
$($table: std::sync::RwLock<rql::Table<$type>>),*
}
schema!(impl $name { $($table: $type),* });
};
(impl $name:ident { $($table:ident: $type:ty),* }) => {
use mashup::*;
mashup! {
$(
mut_name["mut_name" $table] = $table _mut;
)*
}
impl $name {
#[allow(dead_code)]
pub fn new<P: AsRef<std::path::Path>>(dir: P, repr: rql::Representation) -> rql::Result<Self> {
std::fs::create_dir_all(&dir)?;
let params = rql::SaveParams { path: dir.as_ref().to_path_buf(), repr };
Ok($name {
$(
$table: std::sync::RwLock::new(
Table::<$type>::load(
params.for_table_guard(stringify!($table)).path,
repr
).unwrap_or_default()
),
)*
params,
})
}
$(
#[allow(dead_code)]
pub fn $table(&self) -> rql::TableGuard<$type> {
rql::TableGuard(
self.$table.read()
.expect(concat!("Thread using ", stringify!($table), " table panicked"))
)
}
mut_name! {
#[allow(dead_code)]
pub fn "mut_name" $table (&self) -> rql::TableGuardMut<$type> {
rql::TableGuardMut {
guard: self.$table.write().expect("Thread using table panicked"),
params: self.params.for_table_guard(stringify!($table)),
}
}
}
)*
#[allow(dead_code)]
pub fn reload(&self) {
$(
*self.$table.write().expect("Thread using table panicked")
= Table::<$type>::load(
self.params.for_table_guard(stringify!($table)).path,
self.params.repr
).unwrap_or_default();
)*
}
}
}
}
#[cfg(test)]
mod tests {
mod rql {
pub use crate::*;
}
use super::*;
#[test]
fn compiles() -> Result<()> {
let _ = std::fs::remove_dir_all("test_database_compiles");
schema! {
Schema {
nums: usize,
strings: String,
}
}
let db = Schema::new("test_database_compiles", HumanReadable)?;
db.nums_mut().insert(4);
db.nums_mut().insert(2);
db.nums_mut().insert(5);
db.strings_mut().insert("hi".into());
db.strings_mut().insert("hello".into());
db.strings_mut().insert("world".into());
for s in db
.nums()
.relate(&*db.strings(), |i, s| s.len() == **i)
.select(|(i, s)| format!("{}: {}", s, i))
{
println!("{:?}", s);
}
for s in db.strings().relate(&*db.nums(), |s, n| s.len() == **n) {
println!("{:?}", s);
}
db.strings_mut().delete_where(|s| s.contains('h'));
assert_eq!(1, db.strings().len());
Ok(())
}
}