-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
397 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,19 @@ | ||
type Id = i64; | ||
//! Tkacz, a library | ||
// * Type | ||
pub mod config; | ||
pub mod query; | ||
pub mod store; | ||
pub mod taxonomy; | ||
pub mod thing; | ||
pub mod types; | ||
|
||
trait Type { | ||
fn type_id(self) -> Id; | ||
fn read_data (self) -> (); | ||
} | ||
pub use crate::query::{Query, QueryParser}; | ||
pub use crate::store::Store; | ||
pub use crate::taxonomy::{ContentSource, Taxon}; | ||
pub use crate::thing::Thing; | ||
pub use crate::types::{Class, Named, NamedType, NamedValue, Object, Type, Value}; | ||
|
||
trait Link { | ||
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION"); | ||
|
||
} | ||
|
||
// ** The Book type | ||
|
||
struct Book { | ||
|
||
} | ||
|
||
// * Thing | ||
|
||
pub struct Thing { | ||
id: Id, | ||
pub name: String, | ||
typ: dyn Type, | ||
} | ||
|
||
// * Store | ||
|
||
pub struct Store { | ||
things: () | ||
} | ||
pub type Id = i64; | ||
pub const TKACZ_DIR_NAME: &str = "tkacz"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
use std::path::Path; | ||
|
||
use tkacz::*; | ||
|
||
fn main() { | ||
println!("This is Tkacz {}!", tkacz::VERSION); | ||
match Store::init(Path::new("/home/thblt/.tkcz")) { | ||
Ok(_) => println!("Got a store"), | ||
Err(e) => println!("Cannot create store: {}", e), | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
use crate::store::Store; | ||
use crate::thing::Thing; | ||
|
||
// * The Query trait | ||
|
||
/// A Query provides a function that determines if a thing should be | ||
/// selected or not. | ||
pub trait Query<'a> { | ||
/// Return a filter that can be used to filter an iterator over | ||
/// the Store's entities. | ||
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool; | ||
} | ||
|
||
// ** Booleans | ||
|
||
// *** Not | ||
|
||
pub struct NotQuery<'a> { | ||
other: dyn Query<'a>, | ||
} | ||
|
||
impl<'a> Query<'a> for NotQuery<'a> { | ||
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool { | ||
!self.other.matches(store, thing) | ||
} | ||
} | ||
|
||
// *** And | ||
|
||
pub struct AndQuery<'a> { | ||
left: Box<dyn Query<'a>>, | ||
right: Box<dyn Query<'a>>, | ||
} | ||
|
||
impl<'a> Query<'a> for AndQuery<'a> { | ||
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool { | ||
self.left.matches(store, thing) && self.right.matches(store, thing) | ||
} | ||
} | ||
|
||
// *** Or | ||
|
||
pub struct OrQuery<'a> { | ||
left: Box<dyn Query<'a>>, | ||
right: Box<dyn Query<'a>>, | ||
} | ||
|
||
impl<'a> Query<'a> for OrQuery<'a> { | ||
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool { | ||
self.left.matches(store, thing) || self.right.matches(store, thing) | ||
} | ||
} | ||
|
||
// *** Xor | ||
|
||
pub struct XorQuery<'a> { | ||
left: Box<dyn Query<'a>>, | ||
right: Box<dyn Query<'a>>, | ||
} | ||
|
||
impl<'a> Query<'a> for XorQuery<'a> { | ||
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool { | ||
self.left.matches(store, thing) != self.right.matches(store, thing) | ||
} | ||
} | ||
|
||
// * The Query<'a> parser | ||
|
||
/** | ||
Queries in Tkacz are made by combining Query<'a>s. The standard | ||
format is Query<'a>:argument, for example: | ||
authors:Foucault | ||
:MyCollection | ||
context:SomeContext | ||
title:"*lambda*" | ||
Some Query<'a>s allow for a more complex structures, with (eg) comparison operators: | ||
date>2020-01-01 | ||
in:authors:Foucault | ||
The Query<'a> parser has macros. Some non-alphabetic characters expand | ||
to Query<'a>s. The most simple example is tag selection with #some-tag, | ||
which expands to | ||
in:(tag)some-tag | ||
The parser also recognizes the classic boolean infix operators | ||
`and`, `or`, and `xor` (aliased to &, |, !=) and the prefix not, !. | ||
*/ | ||
|
||
pub struct QueryParser {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
use crate::*; | ||
use std::path::{Path, PathBuf}; | ||
use std::{fmt, fs, io}; | ||
|
||
// * The Store type | ||
|
||
/// A Store | ||
pub struct Store { | ||
path: PathBuf, | ||
writable: bool, | ||
pub(crate) things: std::vec::Vec<Thing>, | ||
} | ||
|
||
// * Implementation | ||
|
||
impl<'a> Store { | ||
/// Open an existing Tkacz store. | ||
pub fn open(path: &Path, read_only: bool) -> Result<Store, StoreAccessError> { | ||
let metadata = fs::metadata(path)?; | ||
if metadata.is_dir() { | ||
let ret = Store { | ||
path: path.to_path_buf(), | ||
writable: !(read_only || metadata.permissions().readonly()), | ||
things: std::vec!(), | ||
}; | ||
return Ok(ret); | ||
} else { | ||
Err(StoreAccessError::new("Not a directory.".to_string())) | ||
} | ||
} | ||
|
||
/// Initialize a new store into an existing, empty directory. | ||
pub fn init(path: &Path) -> Result<(), StoreAccessError> { | ||
let metadata = fs::metadata(path)?; | ||
if !metadata.is_dir() { | ||
Err(StoreAccessError::new("Not a directory.".to_string())) | ||
} else if metadata.permissions().readonly() { | ||
Err(StoreAccessError::new("Not writable.".to_string())) | ||
} else if fs::read_dir(path)?.next().is_some() { | ||
Err(StoreAccessError::new("Not empty.".to_string())) | ||
} else { | ||
// Todo create store. | ||
Ok(()) | ||
} | ||
} | ||
/// Add a [Thing] to that store. | ||
pub fn new_thing(&mut self, name: String) -> &mut Thing { | ||
let id = self.things.len(); | ||
self.things.push(Thing { id: id as Id, name }); | ||
&mut self.things[id] | ||
} | ||
} | ||
|
||
// * Errors | ||
|
||
#[derive(Debug, Clone)] | ||
/// Errors raised when accessing stores. | ||
pub struct StoreAccessError { | ||
msg: String, | ||
} | ||
|
||
impl StoreAccessError { | ||
fn new(msg: String) -> StoreAccessError { | ||
StoreAccessError { msg } | ||
} | ||
} | ||
|
||
impl fmt::Display for StoreAccessError { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
write!(f, "[StoreAccessError] {}", self.msg) | ||
} | ||
} | ||
|
||
impl From<io::Error> for StoreAccessError { | ||
fn from(error: io::Error) -> Self { | ||
StoreAccessError { | ||
msg: format!("IO Error: {}", error).to_string(), | ||
} | ||
} | ||
} |
Oops, something went wrong.