creation, insertion of entries

master
Avril 4 years ago
parent 2511939f4e
commit e2eee6beb1
Signed by: flanchan
GPG Key ID: 284488987C31F630

24
Cargo.lock generated

@ -325,6 +325,12 @@ dependencies = [
"libc",
]
[[package]]
name = "itoa"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
[[package]]
name = "jemalloc-sys"
version = "0.3.2"
@ -470,6 +476,7 @@ dependencies = [
"memmap",
"pin-project",
"serde",
"serde_json",
"smallvec",
"tokio",
]
@ -662,6 +669,12 @@ dependencies = [
"rand_core",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "serde"
version = "1.0.118"
@ -682,6 +695,17 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha2"
version = "0.9.2"

@ -17,5 +17,6 @@ jemallocator = "0.3.2"
memmap = "0.7.0"
pin-project = "1.0.2"
serde = {version = "1.0.118", features= ["derive"]}
serde_json = "1.0.60"
smallvec = "1.5.1"
tokio = {version = "0.2", features = ["full"]}

@ -2,6 +2,7 @@ use super::*;
use std::hash::{Hash, Hasher};
use std::borrow::Borrow;
pub mod builder;
#[derive(Debug, Serialize, Deserialize)] // Clone, PartialEq, Eq, Hash
pub struct Entry
@ -32,16 +33,38 @@ pub struct Entry
cache: DataCacheState,
}
// Accessors
impl Entry
{
pub(super) fn purge_from_host(&self, host: &mut Store)
/// The name of this entry
pub fn name(&self) -> &str
{
host.tag_search_any(&self.tags[..]).dedup_ref(); //TODO
&self.name
}
pub fn description(&self) -> &str
{
&self.description
}
/// The *original* filename of this entry
pub fn filename(&self) -> &Path
{
Path::new(&self.filename)
}
/// The path of this entry's file relative to the root of its store
pub fn location(&self) -> &Path
{
self.location.as_path()
}
/// The tags for this entry
pub fn tags(&self) -> &[String]
{
&self.tags[..]
}
/// Is the file of this entry encrypted?
pub fn is_encrypted(&self) -> bool
{
self.key.is_some()
}
}
impl Entry
{
/// The sha256 hash of the data in this entry
pub fn hash(&self) -> &sha256::Sha256Hash
{

@ -0,0 +1,107 @@
use super::*;
use std::{
error,
fmt,
};
use std::ffi::OsStr;
/// Builder for creating [`Entry`] instances.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
pub struct EntryBuilder<'a>
{
name: Option<&'a str>,
desc: Option<&'a str>,
tags: Option<&'a[&'a str]>,
key: Option<aes::AesKey>,
hash: Option<sha256::Sha256Hash>,
location: Option<&'a Path>,
filename: Option<&'a OsStr>,
}
macro_rules! build_fn {
($name:ident: $ty:ty $(, $com:literal)?) => {
$(#[doc=$com])?
#[inline] pub const fn $name(self, $name: $ty) -> Self
{
Self {
$name: Some($name),
..self
}
}
};
}
impl<'a> EntryBuilder<'a>
{
/// Create a new entry builder
#[inline] pub const fn new() -> Self
{
macro_rules! default {
($($name:ident),*) => {
Self {
$(
$name: None
),*
}
}
}
default!{
name, desc, tags, key, hash, location, filename
}
}
build_fn!(name: &'a str, "Insert the name of this entry");
build_fn!(desc: &'a str, "Insert a description for this entry");
build_fn!(tags: &'a [&'a str], "Insert the tags for this entry");
build_fn!(key: aes::AesKey, "Insert the encryption key for this entry");
build_fn!(hash: sha256::Sha256Hash, "Insert the hash for this entry");
build_fn!(location: &'a Path, "Insert the location for this entry");
build_fn!(filename: &'a OsStr, "Insert the original filename for this entry");
/// Try to build an `Entry` from this builder.
#[inline] pub fn build(self) -> Result<Entry, EntryBuildError>
{
macro_rules! fail_on {
($name:ident) => {
self.$name.ok_or(EntryBuildError)?
};
($name:ident: $or:expr) =>{
if let Some(name) = self.$name {
name
} else {
$or
}
};
}
Ok(
Entry {
name: fail_on!(name).into(),
description: fail_on!(desc: "").into(),
tags: fail_on!(tags: &[]).iter().map(|&x| x.to_owned()).collect(),
key: self.key,
hash: fail_on!(hash),
location: fail_on!(location).into(),
filename: fail_on!(filename: OsStr::new("")).into(),
cache: Default::default(),
}
)
}
}
/// Error for when an improporly configured [`EntryBuilder`] called `.build()`.
/// Usually this is because of missing fields.
#[derive(Debug)]
pub struct EntryBuildError;
impl error::Error for EntryBuildError{}
impl fmt::Display for EntryBuildError
{
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "improporly configured builder")
}
}

@ -15,8 +15,10 @@ use memmap::Mmap;
use bytes::Bytes;
use cryptohelpers::{aes, sha256};
mod entry;
pub use entry::Entry;
pub use entry::builder::EntryBuilder;
mod cache;
pub use cache::DataCacheState;
@ -33,6 +35,8 @@ pub use search::*;
mod mutation;
pub use mutation::*;
#[cfg(test)] mod test;
/// The key used to look up a single entry in `O(1)` time.
///
/// # Notes
@ -43,7 +47,7 @@ pub type EntryKey = sha256::Sha256Hash;
///
/// # Notes
/// Change this back to `RandomState` if you change the type of `EntryKey`.
pub type BuildHasher = Sha256TopBuildHasher;
pub type BuildHasher = std::collections::hash_map::RandomState;//Sha256TopBuildHasher; <-- bug here
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
struct PurgeTrack
@ -88,19 +92,6 @@ pub struct Store
tags: BTreeMap<String, ArenaIndex>, // string (tags) -> index (tag_mappings) -> index (data_hashes) -> hash used for lookup (data)
}
// Comptime asserts (TODO: Unneeded. Remove.)
/*impl Store
{
fn _assert_tag_lookup_works(&self, tag: &str) -> &Entry
{
self.data.get(self.data_hashes.get(*self.tag_mappings.get(*self.tags.get(tag).unwrap()).unwrap().first().unwrap()).unwrap()).unwrap() // y-yes this also works...
}
fn _assert_lookup_internal_works(&self, data_idx: ArenaIndex) -> &Entry
{
self.data.get(self.data_hashes.get(data_idx).unwrap()).unwrap() // yes this works..
}
}*/
// Creating
impl Store
{

@ -18,7 +18,8 @@ impl Store
}
/// Insert this entry then return a reference to it.
pub fn insert(&mut self, ent: Entry) -> &Entry
pub fn insert<'a, 'b>(&'a mut self, ent: Entry) -> &'b Entry
where 'a: 'b
{
let ffd = *ent.hash();
self.insert_overwrite(ent);

@ -0,0 +1,61 @@
use super::*;
#[inline] fn gen_meta() -> StoreMetadata
{
StoreMetadata{
name: "test".to_string(),
root: "./test/db".to_owned().into(),
}
}
#[test]
fn create()
{
let store = Store::new(gen_meta());
let freeze = store.into_freeze();
let _ = freeze.into_new();
}
#[test]
fn entries()
{
let mut store = Store::new(gen_meta());
macro_rules! build {
() => {
EntryBuilder::new()
.name("Hello")
.desc("Desc")
.tags(&["Tag1", "Tag2", "Tag3"])
.hash(sha256::compute_slice(b"hello world"))
.location(Path::new("test_file"))
};
}
let entry = build!()
.build().expect("Failed to build entry");
println!("Entry: {:#?}", entry);
let entry = store.insert(entry).clone();
store.insert(build!()
.hash(sha256::compute_slice("something else"))
.name("Entry 2")
.build().expect("Failed to build entry 2"));
println!("Entry ref: {:#?}", entry);
println!("Store: {:#?}", store);
let freeze = store.freeze();
println!("Frozen: {:#?}", freeze);
let store2 = Store::unfreeze(&freeze);
assert_eq!(store2.tag_search("Tag2").filter(|x| x.name() == entry.name()).next().unwrap().hash(), entry.hash());
assert_eq!(store.tag_search_any(vec!["Tag2", "Tag3"]).filter(|x| x.name() == entry.name()).next().unwrap().hash(), entry.hash());
assert_eq!(store2.tag_search_all(vec!["Tag1", "Tag3"]).filter(|x| x.name() == entry.name()).next().unwrap().hash(), entry.hash());
assert!(store.tag_search_all(vec!["Tag1", "Nope"]).next().is_none());
let json = serde_json::to_string_pretty(&freeze).unwrap();
println!("Freeze serialised ({} bytes): '{}'", json.len(), json);
let ufreeze: Freeze = serde_json::from_str(json.as_str()).unwrap();
assert_eq!(ufreeze, freeze);
println!("Freeze unseralised as store: {:#?}", ufreeze.into_new());
}
Loading…
Cancel
Save