grus_lib/
lib.rs

1pub mod reader;
2pub mod types;
3pub mod writer;
4
5pub use sanakirja::Error;
6use std::io::{Error as IoError, ErrorKind};
7use std::path::Path;
8use sanakirja::{Commit, Env, LoadPage, RootDb};
9use sanakirja::btree;
10use reader::StoreReader;
11use types::{DueDatesDb, LinksDb, NamesDb, RLinksDb, RSessionsDb, SessionsDb};
12use writer::StoreWriter;
13
14const ID_SQ: usize = 0;
15const DB_LINKS: usize = 1;
16const DB_RLINKS: usize = 2;
17const DB_NAMES: usize = 3;
18const DB_DUE_DATES: usize = 4;
19const DB_SESSIONS: usize = 5;
20const DB_RSESSIONS: usize = 6;
21
22pub struct Store {
23	env: Env
24}
25
26impl Store {
27	pub fn open<P: AsRef<Path>>(path: P, n_roots: usize) -> Result<Self, Error> {
28		let store = Store { env: Env::new(path, 1 << 14, n_roots)? };
29		store.create_base()?;
30		Ok(store)
31	}
32
33	pub fn reader(&self) -> Result<StoreReader, Error> {
34		let txn = Env::txn_begin(&self.env)?;
35		let id = txn.root(ID_SQ);
36		let links = txn.root_db(DB_LINKS).ok_or_else(invalid_data_error)?;
37		let rlinks = txn.root_db(DB_RLINKS).ok_or_else(invalid_data_error)?;
38		let names = txn.root_db(DB_NAMES).ok_or_else(invalid_data_error)?;
39		let due_dates = txn.root_db(DB_DUE_DATES).ok_or_else(invalid_data_error)?;
40		let sessions = txn.root_db(DB_SESSIONS).ok_or_else(invalid_data_error)?;
41		let rsessions = txn.root_db(DB_RSESSIONS).ok_or_else(invalid_data_error)?;
42		Ok(StoreReader { txn, id, links, rlinks, names, due_dates, sessions, rsessions })
43	}
44
45	pub fn writer(&self) -> Result<StoreWriter, Error> {
46		let txn = Env::mut_txn_begin(&self.env)?;
47		let id = txn.root(ID_SQ).ok_or_else(invalid_data_error)?;
48		let links = txn.root_db(DB_LINKS).ok_or_else(invalid_data_error)?;
49		let rlinks = txn.root_db(DB_RLINKS).ok_or_else(invalid_data_error)?;
50		let names = txn.root_db(DB_NAMES).ok_or_else(invalid_data_error)?;
51		let due_dates = txn.root_db(DB_DUE_DATES).ok_or_else(invalid_data_error)?;
52		let sessions = txn.root_db(DB_SESSIONS).ok_or_else(invalid_data_error)?;
53		let rsessions = txn.root_db(DB_RSESSIONS).ok_or_else(invalid_data_error)?;
54		Ok(StoreWriter { txn, id, links, rlinks, names, due_dates, sessions, rsessions })
55	}
56
57	fn create_base(&self) -> Result<(), Error> {
58		let mut txn = Env::mut_txn_begin(&self.env)?;
59
60		let id = txn.root(ID_SQ);
61		let links: Option<LinksDb> = txn.root_db(DB_LINKS);
62		let rlinks: Option<RLinksDb> = txn.root_db(DB_RLINKS);
63		let names: Option<NamesDb> = txn.root_db(DB_NAMES);
64		let due_dates: Option<DueDatesDb> = txn.root_db(DB_DUE_DATES);
65		let sessions: Option<SessionsDb> = txn.root_db(DB_SESSIONS);
66		let rsessions: Option<RSessionsDb> = txn.root_db(DB_RSESSIONS);
67		match (id, links, rlinks, names, due_dates, sessions, rsessions) {
68			(Some(_), Some(_), Some(_), Some(_), Some(_), Some(_), Some(_)) => Ok(()),
69			(None, None, None, None, None, None, None) => {
70				unsafe {
71					let links: LinksDb = btree::create_db(&mut txn)?;
72					let rlinks: RLinksDb = btree::create_db(&mut txn)?;
73					let mut names: NamesDb = btree::create_db_(&mut txn)?;
74					let due_dates: DueDatesDb = btree::create_db(&mut txn)?;
75					let sessions: SessionsDb = btree::create_db(&mut txn)?;
76					let rsessions: RSessionsDb = btree::create_db(&mut txn)?;
77
78					btree::put(&mut txn, &mut names, &0, b"/")?;
79
80					txn.set_root(ID_SQ, 1);
81					txn.set_root(DB_LINKS, links.db.into());
82					txn.set_root(DB_RLINKS, rlinks.db.into());
83					txn.set_root(DB_NAMES, names.db.into());
84					txn.set_root(DB_DUE_DATES, due_dates.db.into());
85					txn.set_root(DB_SESSIONS, sessions.db.into());
86					txn.set_root(DB_RSESSIONS, rsessions.db.into());
87				}
88				txn.commit()
89			}
90			_ => {
91				Err(invalid_data_error())
92			}
93		}
94	}
95}
96
97
98pub struct StoreRw<T: LoadPage> {
99	txn: T,
100	id: u64,
101	links: LinksDb,
102	rlinks: RLinksDb,
103	names: NamesDb,
104	due_dates: DueDatesDb,
105	sessions: SessionsDb,
106	rsessions: RSessionsDb,
107}
108
109fn invalid_data_error() -> Error {
110	Error::IO(IoError::new(
111		ErrorKind::InvalidData,
112		"Database is invalid or corrupted"
113	))
114}