parent
2511939f4e
commit
e2eee6beb1
@ -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")
|
||||
}
|
||||
}
|
@ -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…
Reference in new issue