summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2018-11-28 02:14:39 +0100
committerMatthias Beyer <mail@beyermatthias.de>2019-02-15 20:53:28 +0100
commit04a8c5f721e7ad9c04fe46f3488c2fa2bef7d0cf (patch)
tree5d6050c9bc2ebead8c961230012adc52fed6d0b4
parentdc162cb16707486fccbd017972dcf00f6aa9f76d (diff)
downloadimag-04a8c5f721e7ad9c04fe46f3488c2fa2bef7d0cf.zip
imag-04a8c5f721e7ad9c04fe46f3488c2fa2bef7d0cf.tar.gz
Move to simpler implementation of Storeid
This changes the implementation of the StoreId type to be less complex. Before we always had to re-attach the path of the store itself each time a StoreId object was passed to the store. Now we do not do this anymore, hopefully we can move to a implementation of the Store API which takes references of StoreId objects in the future. Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--lib/core/libimagstore/src/file_abstraction/fs.rs10
-rw-r--r--lib/core/libimagstore/src/file_abstraction/inmemory.rs6
-rw-r--r--lib/core/libimagstore/src/file_abstraction/iter.rs18
-rw-r--r--lib/core/libimagstore/src/file_abstraction/mod.rs19
-rw-r--r--lib/core/libimagstore/src/iter.rs22
-rw-r--r--lib/core/libimagstore/src/store.rs76
-rw-r--r--lib/core/libimagstore/src/storeid.rs222
7 files changed, 175 insertions, 198 deletions
diff --git a/lib/core/libimagstore/src/file_abstraction/fs.rs b/lib/core/libimagstore/src/file_abstraction/fs.rs
index f68d2aa..05f48b8 100644
--- a/lib/core/libimagstore/src/file_abstraction/fs.rs
+++ b/lib/core/libimagstore/src/file_abstraction/fs.rs
@@ -28,7 +28,7 @@ use super::FileAbstraction;
use super::FileAbstractionInstance;
use super::Drain;
use store::Entry;
-use storeid::StoreId;
+use storeid::StoreIdWithBase;
use file_abstraction::iter::PathIterator;
use file_abstraction::iter::PathIterBuilder;
@@ -45,7 +45,7 @@ impl FileAbstractionInstance for FSFileAbstractionInstance {
/**
* Get the content behind this file
*/
- fn get_file_content(&mut self, id: StoreId) -> Result<Option<Entry>> {
+ fn get_file_content<'a>(&mut self, id: StoreIdWithBase<'a>) -> Result<Option<Entry>> {
debug!("Getting lazy file: {:?}", self);
let mut file = match open_file(&self.0) {
@@ -153,11 +153,11 @@ impl FileAbstraction for FSFileAbstraction {
})
}
- fn pathes_recursively(&self,
+ fn pathes_recursively<'a>(&self,
basepath: PathBuf,
- storepath: PathBuf,
+ storepath: &'a PathBuf,
backend: Arc<FileAbstraction>)
- -> Result<PathIterator>
+ -> Result<PathIterator<'a>>
{
trace!("Building PathIterator object");
Ok(PathIterator::new(Box::new(WalkDirPathIterBuilder { basepath }), storepath, backend))
diff --git a/lib/core/libimagstore/src/file_abstraction/inmemory.rs b/lib/core/libimagstore/src/file_abstraction/inmemory.rs
index 292aea1..49f7c56 100644
--- a/lib/core/libimagstore/src/file_abstraction/inmemory.rs
+++ b/lib/core/libimagstore/src/file_abstraction/inmemory.rs
@@ -33,7 +33,7 @@ use super::FileAbstraction;
use super::FileAbstractionInstance;
use super::Drain;
use store::Entry;
-use storeid::StoreId;
+use storeid::StoreIdWithBase;
use file_abstraction::iter::PathIterator;
use file_abstraction::iter::PathIterBuilder;
@@ -64,7 +64,7 @@ impl FileAbstractionInstance for InMemoryFileAbstractionInstance {
/**
* Get the mutable file behind a InMemoryFileAbstraction object
*/
- fn get_file_content(&mut self, _: StoreId) -> Result<Option<Entry>> {
+ fn get_file_content(&mut self, _: StoreIdWithBase<'_>) -> Result<Option<Entry>> {
debug!("Getting lazy file: {:?}", self);
self.fs_abstraction
@@ -187,7 +187,7 @@ impl FileAbstraction for InMemoryFileAbstraction {
Ok(())
}
- fn pathes_recursively(&self, _basepath: PathBuf, storepath: PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator> {
+ fn pathes_recursively<'a>(&self, _basepath: PathBuf, storepath: &'a PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator<'a>> {
trace!("Building PathIterator object (inmemory implementation)");
let keys : Vec<PathBuf> = self
.backend()
diff --git a/lib/core/libimagstore/src/file_abstraction/iter.rs b/lib/core/libimagstore/src/file_abstraction/iter.rs
index 9df59a2..7a5a5c8 100644
--- a/lib/core/libimagstore/src/file_abstraction/iter.rs
+++ b/lib/core/libimagstore/src/file_abstraction/iter.rs
@@ -22,7 +22,7 @@ use std::sync::Arc;
use failure::Fallible as Result;
-use storeid::StoreId;
+use storeid::StoreIdWithBase;
use file_abstraction::FileAbstraction;
/// See documentation for PathIterator
@@ -45,19 +45,19 @@ pub trait PathIterBuilder {
///
/// This means quite a few allocations down the road, as the PathIterator itself is not generic, but
/// this seems to be the best way to implement this.
-pub struct PathIterator {
+pub(crate) struct PathIterator<'a> {
iter_builder: Box<PathIterBuilder>,
iter: Box<Iterator<Item = Result<PathBuf>>>,
- storepath: PathBuf,
+ storepath: &'a PathBuf,
backend: Arc<FileAbstraction>,
}
-impl PathIterator {
+impl<'a> PathIterator<'a> {
pub fn new(iter_builder: Box<PathIterBuilder>,
- storepath: PathBuf,
+ storepath: &'a PathBuf,
backend: Arc<FileAbstraction>)
- -> PathIterator
+ -> PathIterator<'a>
{
trace!("Generating iterator object with PathIterBuilder");
let iter = iter_builder.build_iter();
@@ -73,8 +73,8 @@ impl PathIterator {
}
-impl Iterator for PathIterator {
- type Item = Result<StoreId>;
+impl<'a> Iterator for PathIterator<'a> {
+ type Item = Result<StoreIdWithBase<'a>>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(next) = self.iter.next() {
@@ -82,7 +82,7 @@ impl Iterator for PathIterator {
Err(e) => return Some(Err(e)),
Ok(next) => match self.backend.is_file(&next) {
Err(e) => return Some(Err(e)),
- Ok(true) => return Some(StoreId::from_full_path(&self.storepath, next)),
+ Ok(true) => return Some(StoreIdWithBase::from_full_path(&self.storepath, next)),
Ok(false) => { continue },
}
}
diff --git a/lib/core/libimagstore/src/file_abstraction/mod.rs b/lib/core/libimagstore/src/file_abstraction/mod.rs
index d7716a5..13fd727 100644
--- a/lib/core/libimagstore/src/file_abstraction/mod.rs
+++ b/lib/core/libimagstore/src/file_abstraction/mod.rs
@@ -25,7 +25,7 @@ use std::sync::Arc;
use failure::Fallible as Result;
use store::Entry;
-use storeid::StoreId;
+use storeid::StoreIdWithBase;
mod fs;
mod inmemory;
@@ -52,7 +52,7 @@ pub trait FileAbstraction : Debug {
fn drain(&self) -> Result<Drain>;
fn fill<'a>(&'a mut self, d: Drain) -> Result<()>;
- fn pathes_recursively(&self, basepath: PathBuf, storepath: PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator>;
+ fn pathes_recursively<'a>(&self, basepath: PathBuf, storepath: &'a PathBuf, backend: Arc<FileAbstraction>) -> Result<PathIterator<'a>>;
}
/// An abstraction trait over actions on files
@@ -60,9 +60,9 @@ pub trait FileAbstractionInstance : Debug {
/// Get the contents of the FileAbstractionInstance, as Entry object.
///
- /// The `StoreId` is passed because the backend does not know where the Entry lives, but the
+ /// The `StoreIdWithBase` is passed because the backend does not know where the Entry lives, but the
/// Entry type itself must be constructed with the id.
- fn get_file_content(&mut self, id: StoreId) -> Result<Option<Entry>>;
+ fn get_file_content<'a>(&mut self, id: StoreIdWithBase<'a>) -> Result<Option<Entry>>;
fn write_file_content(&mut self, buf: &Entry) -> Result<()>;
}
@@ -101,18 +101,19 @@ mod test {
use super::FileAbstractionInstance;
use super::inmemory::InMemoryFileAbstraction;
use super::inmemory::InMemoryFileAbstractionInstance;
- use storeid::StoreId;
+ use storeid::StoreIdWithBase;
use store::Entry;
#[test]
fn lazy_file() {
+ let store_path = PathBuf::from("/");
let fs = InMemoryFileAbstraction::default();
let mut path = PathBuf::from("tests");
path.set_file_name("test1");
let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());
- let loca = StoreId::new_baseless(path).unwrap();
+ let loca = StoreIdWithBase::new(&store_path, path);
let file = Entry::from_str(loca.clone(), &format!(r#"---
[imag]
version = "{}"
@@ -126,13 +127,14 @@ Hello World"#, env!("CARGO_PKG_VERSION"))).unwrap();
#[test]
fn lazy_file_multiline() {
+ let store_path = PathBuf::from("/");
let fs = InMemoryFileAbstraction::default();
let mut path = PathBuf::from("tests");
path.set_file_name("test1");
let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());
- let loca = StoreId::new_baseless(path).unwrap();
+ let loca = StoreIdWithBase::new(&store_path, path);
let file = Entry::from_str(loca.clone(), &format!(r#"---
[imag]
version = "{}"
@@ -147,13 +149,14 @@ baz"#, env!("CARGO_PKG_VERSION"))).unwrap();
#[test]
fn lazy_file_multiline_trailing_newlines() {
+ let store_path = PathBuf::from("/");
let fs = InMemoryFileAbstraction::default();
let mut path = PathBuf::from("tests");
path.set_file_name("test1");
let mut lf = InMemoryFileAbstractionInstance::new(fs.backend().clone(), path.clone());
- let loca = StoreId::new_baseless(path).unwrap();
+ let loca = StoreIdWithBase::new(&store_path, path);
let file = Entry::from_str(loca.clone(), &format!(r#"---
[imag]
version = "{}"
diff --git a/lib/core/libimagstore/src/iter.rs b/lib/core/libimagstore/src/iter.rs
index 1639b02..e236d98 100644
--- a/lib/core/libimagstore/src/iter.rs
+++ b/lib/core/libimagstore/src/iter.rs
@@ -138,7 +138,6 @@ mod compile_test {
}
use storeid::StoreId;
-use storeid::StoreIdIterator;
use self::delete::StoreDeleteIterator;
use self::get::StoreGetIterator;
use self::retrieve::StoreRetrieveIterator;
@@ -167,11 +166,11 @@ use failure::Fallible as Result;
///
/// Functionality to exclude subdirectories is not possible with the current implementation and has
/// to be done during iteration, with filtering (as usual).
-pub struct Entries<'a>(PathIterator, &'a Store);
+pub struct Entries<'a>(PathIterator<'a>, &'a Store);
impl<'a> Entries<'a> {
- pub(crate) fn new(pi: PathIterator, store: &'a Store) -> Self {
+ pub(crate) fn new(pi: PathIterator<'a>, store: &'a Store) -> Self {
Entries(pi, store)
}
@@ -179,29 +178,30 @@ impl<'a> Entries<'a> {
Entries(self.0.in_collection(c), self.1)
}
- pub fn without_store(self) -> StoreIdIterator {
- StoreIdIterator::new(Box::new(self.0))
- }
+ // TODO: Remove or fix me
+ //pub fn without_store(self) -> StoreIdIterator {
+ // StoreIdIterator::new(Box::new(self.0.map(|r| r.map(|id| id.without_base()))))
+ //}
/// Transform the iterator into a StoreDeleteIterator
///
/// This immitates the API from `libimagstore::iter`.
pub fn into_delete_iter(self) -> StoreDeleteIterator<'a> {
- StoreDeleteIterator::new(Box::new(self.0), self.1)
+ StoreDeleteIterator::new(Box::new(self.0.map(|r| r.map(|id| id.without_base()))), self.1)
}
/// Transform the iterator into a StoreGetIterator
///
/// This immitates the API from `libimagstore::iter`.
pub fn into_get_iter(self) -> StoreGetIterator<'a> {
- StoreGetIterator::new(Box::new(self.0), self.1)
+ StoreGetIterator::new(Box::new(self.0.map(|r| r.map(|id| id.without_base()))), self.1)
}
/// Transform the iterator into a StoreRetrieveIterator
///
/// This immitates the API from `libimagstore::iter`.
pub fn into_retrieve_iter(self) -> StoreRetrieveIterator<'a> {
- StoreRetrieveIterator::new(Box::new(self.0), self.1)
+ StoreRetrieveIterator::new(Box::new(self.0.map(|r| r.map(|id| id.without_base()))), self.1)
}
}
@@ -210,7 +210,7 @@ impl<'a> Iterator for Entries<'a> {
type Item = Result<StoreId>;
fn next(&mut self) -> Option<Self::Item> {
- self.0.next()
+ self.0.next().map(|r| r.map(|id| id.without_base()))
}
}
@@ -244,7 +244,7 @@ mod tests {
let base = String::from("entry");
let variants = vec!["coll_1", "coll_2", "coll_3"];
let modifier = |base: &String, v: &&str| {
- StoreId::new(Some(store.path().clone()), PathBuf::from(format!("{}/{}", *v, base))).unwrap()
+ StoreId::new(PathBuf::from(format!("{}/{}", *v, base))).unwrap()
};
generate_variants(&base, variants.iter(), &modifier)
diff --git a/lib/core/libimagstore/src/store.rs b/lib/core/libimagstore/src/store.rs
index aa3ae4b..cb85177 100644
--- a/lib/core/libimagstore/src/store.rs
+++ b/lib/core/libimagstore/src/store.rs
@@ -64,14 +64,15 @@ enum StoreEntryStatus {
#[derive(Debug)]
struct StoreEntry {
id: StoreId,
+ store_base: PathBuf, // small sacrefice over lifetimes on the Store type
file: Box<FileAbstractionInstance>,
status: StoreEntryStatus,
}
impl StoreEntry {
- fn new(id: StoreId, backend: &Arc<FileAbstraction>) -> Result<StoreEntry> {
- let pb = id.clone().into_pathbuf()?;
+ fn new(store_base: PathBuf, id: StoreId, backend: &Arc<FileAbstraction>) -> Result<StoreEntry> {
+ let pb = id.clone().with_base(&store_base).into_pathbuf()?;
#[cfg(feature = "fs-lock")]
{
@@ -82,6 +83,7 @@ impl StoreEntry {
Ok(StoreEntry {
id,
+ store_base,
file: backend.new_instance(pb),
status: StoreEntryStatus::Present,
})
@@ -95,7 +97,7 @@ impl StoreEntry {
fn get_entry(&mut self) -> Result<Entry> {
if !self.is_borrowed() {
- match self.file.get_file_content(self.id.clone())? {
+ match self.file.get_file_content(self.id.clone().with_base(&self.store_base))? {
Some(file) => Ok(file),
None => Ok(Entry::new(self.id.clone()))
}
@@ -218,7 +220,7 @@ impl Store {
/// On success: FileLockEntry
///
pub fn create<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
- let id = id.into_storeid()?.with_base(self.path().clone());
+ let id = id.into_storeid()?;
debug!("Creating id: '{}'", id);
@@ -244,7 +246,7 @@ impl Store {
}
hsmap.insert(id.clone(), {
debug!("Creating: '{}'", id);
- let mut se = StoreEntry::new(id.clone(), &self.backend)?;
+ let mut se = StoreEntry::new(self.path().clone(), id.clone(), &self.backend)?;
se.status = StoreEntryStatus::Borrowed;
se
});
@@ -266,14 +268,14 @@ impl Store {
/// On success: FileLockEntry
///
pub fn retrieve<'a, S: IntoStoreId>(&'a self, id: S) -> Result<FileLockEntry<'a>> {
- let id = id.into_storeid()?.with_base(self.path().clone());
+ let id = id.into_storeid()?;
debug!("Retrieving id: '{}'", id);
let entry = self
.entries
.write()
.map_err(|_| Error::from(EM::LockError))
.and_then(|mut es| {
- let new_se = StoreEntry::new(id.clone(), &self.backend)?;
+ let new_se = StoreEntry::new(self.path().clone(), id.clone(), &self.backend)?;
let se = es.entry(id.clone()).or_insert(new_se);
let entry = se.get_entry();
se.status = StoreEntryStatus::Borrowed;
@@ -296,7 +298,7 @@ impl Store {
/// - Errors Store::retrieve() might return
///
pub fn get<'a, S: IntoStoreId + Clone>(&'a self, id: S) -> Result<Option<FileLockEntry<'a>>> {
- let id = id.into_storeid()?.with_base(self.path().clone());
+ let id = id.into_storeid()?;
debug!("Getting id: '{}'", id);
@@ -409,7 +411,7 @@ impl Store {
/// On success: Entry
///
pub fn get_copy<S: IntoStoreId>(&self, id: S) -> Result<Entry> {
- let id = id.into_storeid()?.with_base(self.path().clone());
+ let id = id.into_storeid()?;
debug!("Retrieving copy of '{}'", id);
let entries = self.entries.write()
.map_err(|_| Error::from(EM::LockError))
@@ -422,7 +424,7 @@ impl Store {
.map_err(Error::from)
}
- StoreEntry::new(id, &self.backend)?.get_entry()
+ StoreEntry::new(self.path().clone(), id, &self.backend)?.get_entry()
}
/// Delete an entry and the corrosponding file on disk
@@ -432,7 +434,7 @@ impl Store {
/// On success: ()
///
pub fn delete<S: IntoStoreId>(&self, id: S) -> Result<()> {
- let id = id.into_storeid()?.with_base(self.path().clone());
+ let id = id.into_storeid()?;
debug!("Deleting id: '{}'", id);
@@ -440,7 +442,7 @@ impl Store {
// StoreId::exists(), a PathBuf object gets allocated. So we simply get a
// PathBuf here, check whether it is there and if it is, we can re-use it to
// delete the filesystem file.
- let pb = id.clone().into_pathbuf()?;
+ let pb = id.clone().with_base(self.path()).into_pathbuf()?;
{
let mut entries = self
@@ -507,7 +509,6 @@ impl Store {
fn save_to_other_location(&self, entry: &FileLockEntry, new_id: StoreId, remove_old: bool)
-> Result<()>
{
- let new_id = new_id.with_base(self.path().clone());
let hsmap = self
.entries
.write()
@@ -522,8 +523,8 @@ impl Store {
let old_id = entry.get_location().clone();
- let old_id_as_path = old_id.clone().with_base(self.path().clone()).into_pathbuf()?;
- let new_id_as_path = new_id.clone().with_base(self.path().clone()).into_pathbuf()?;
+ let old_id_as_path = old_id.clone().with_base(self.path()).into_pathbuf()?;
+ let new_id_as_path = new_id.clone().with_base(self.path()).into_pathbuf()?;
self.backend
.copy(&old_id_as_path, &new_id_as_path)
.and_then(|_| if remove_old {
@@ -571,9 +572,6 @@ impl Store {
/// So the link is _partly dangling_, so to say.
///
pub fn move_by_id(&self, old_id: StoreId, new_id: StoreId) -> Result<()> {
- let new_id = new_id.with_base(self.path().clone());
- let old_id = old_id.with_base(self.path().clone());
-
debug!("Moving '{}' to '{}'", old_id, new_id);
{
@@ -594,8 +592,8 @@ impl Store {
debug!("Old id is not yet borrowed");
- let old_id_pb = old_id.clone().with_base(self.path().clone()).into_pathbuf()?;
- let new_id_pb = new_id.clone().with_base(self.path().clone()).into_pathbuf()?;
+ let old_id_pb = old_id.clone().with_base(self.path()).into_pathbuf()?;
+ let new_id_pb = new_id.clone().with_base(self.path()).into_pathbuf()?;
if self.backend.exists(&new_id_pb)? {
return Err(format_err!("Entry already exists: {}", new_id));
@@ -618,8 +616,8 @@ impl Store {
assert!(hsmap
.remove(&old_id)
.and_then(|mut entry| {
- entry.id = new_id.clone();
- hsmap.insert(new_id.clone(), entry)
+ entry.id = new_id.clone().into();
+ hsmap.insert(new_id.clone().into(), entry)
}).is_none())
}
@@ -631,7 +629,7 @@ impl Store {
pub fn entries<'a>(&'a self) -> Result<Entries<'a>> {
trace!("Building 'Entries' iterator");
self.backend
- .pathes_recursively(self.path().clone(), self.path().clone(), self.backend.clone())
+ .pathes_recursively(self.path().clone(), self.path(), self.backend.clone())
.map(|i| Entries::new(i, self))
}
@@ -645,7 +643,7 @@ impl Store {
.context(format_err!("CreateCallError: {}", id));
let backend_has_entry = |id: StoreId|
- self.backend.exists(&id.with_base(self.path().to_path_buf()).into_pathbuf()?);
+ self.backend.exists(&id.with_base(self.path()).into_pathbuf()?);
Ok(cache_has_entry(&id)? || backend_has_entry(id)?)
}
@@ -1000,7 +998,7 @@ Hai
setup_logging();
debug!("{}", TEST_ENTRY);
- let entry = Entry::from_str(StoreId::new_baseless(PathBuf::from("test/foo~1.3")).unwrap(),
+ let entry = Entry::from_str(StoreId::new(PathBuf::from("test/foo~1.3")).unwrap(),
TEST_ENTRY).unwrap();
assert_eq!(entry.content, "Hai");
@@ -1014,7 +1012,7 @@ Hai
setup_logging();
debug!("{}", TEST_ENTRY);
- let entry = Entry::from_str(StoreId::new_baseless(PathBuf::from("test/foo~1.3")).unwrap(),
+ let entry = Entry::from_str(StoreId::new(PathBuf::from("test/foo~1.3")).unwrap(),
TEST_ENTRY).unwrap();
let string = entry.to_str().unwrap();
@@ -1029,7 +1027,7 @@ Hai
setup_logging();
debug!("{}", TEST_ENTRY_TNL);
- let entry = Entry::from_str(StoreId::new_baseless(PathBuf::from("test/foo~1.3")).unwrap(),
+ let entry = Entry::from_str(StoreId::new(PathBuf::from("test/foo~1.3")).unwrap(),
TEST_ENTRY_TNL).unwrap();
let string = entry.to_str().unwrap();
@@ -1072,7 +1070,7 @@ mod store_tests {
let s = format!("test-{}", n);
let entry = store.create(PathBuf::from(s.clone())).unwrap();
assert!(entry.verify().is_ok());
- let loc = entry.get_location().clone().into_pathbuf().unwrap();
+ let loc = entry.get_location().clone().with_base(store.path()).into_pathbuf().unwrap();
assert!(loc.starts_with("/"));
assert!(loc.ends_with(s));
}
@@ -1093,7 +1091,7 @@ mod store_tests {
assert!(entry.verify().is_ok());
- let loc = entry.get_location().clone().into_pathbuf().unwrap();
+ let loc = entry.get_location().clone().with_base(store.path()).into_pathbuf().unwrap();
assert!(loc.starts_with("/"));
assert!(loc.ends_with(s));
@@ -1125,7 +1123,7 @@ mod store_tests {
.ok()
.map(|entry| {
assert!(entry.verify().is_ok());
- let loc = entry.get_location().clone().into_pathbuf().unwrap();
+ let loc = entry.get_location().clone().with_base(store.path()).into_pathbuf().unwrap();
assert!(loc.starts_with("/"));
assert!(loc.ends_with(s));
});
@@ -1139,12 +1137,10 @@ mod store_tests {
let store = get_store();
for n in 1..100 {
- let pb = StoreId::new_baseless(PathBuf::from(format!("test-{}", n))).unwrap();
+ let pb = StoreId::new(PathBuf::from(format!("test-{}", n))).unwrap();
assert!(store.entries.read().unwrap().get(&pb).is_none());
assert!(store.create(pb.clone()).is_ok());
-
- let pb = pb.with_base(store.path().clone());
assert!(store.entries.read().unwrap().get(&pb).is_some());
}
}
@@ -1156,12 +1152,10 @@ mod store_tests {
let store = get_store();
for n in 1..100 {
- let pb = StoreId::new_baseless(PathBuf::from(format!("test-{}", n))).unwrap();
+ let pb = StoreId::new(PathBuf::from(format!("test-{}", n))).unwrap();
assert!(store.entries.read().unwrap().get(&pb).is_none());
assert!(store.retrieve(pb.clone()).is_ok());
-
- let pb = pb.with_base(store.path().clone());
assert!(store.entries.read().unwrap().get(&pb).is_some());
}
}
@@ -1199,8 +1193,8 @@ mod store_tests {
for n in 1..100 {
if n % 2 == 0 { // every second
- let id = StoreId::new_baseless(PathBuf::from(format!("t-{}", n))).unwrap();
- let id_mv = StoreId::new_baseless(PathBuf::from(format!("t-{}", n - 1))).unwrap();
+ let id = StoreId::new(PathBuf::from(format!("t-{}", n))).unwrap();
+ let id_mv = StoreId::new(PathBuf::from(format!("t-{}", n - 1))).unwrap();
{
assert!(store.entries.read().unwrap().get(&id).is_none());
@@ -1211,16 +1205,14 @@ mod store_tests {
}
{
- let id_with_base = id.clone().with_base(store.path().clone());
- assert!(store.entries.read().unwrap().get(&id_with_base).is_some());
+ assert!(store.entries.read().unwrap().get(&id).is_some());
}
let r = store.move_by_id(id.clone(), id_mv.clone());
assert!(r.map_err(|e| debug!("ERROR: {:?}", e)).is_ok());
{
- let id_mv_with_base = id_mv.clone().with_base(store.path().clone());
- assert!(store.entries.read().unwrap().get(&id_mv_with_base).is_some());
+ assert!(store.entries.read().unwrap().get(&id_mv).is_some());
}
let res = store.get(id.clone());
diff --git a/lib/core/libimagstore/src/storeid.rs b/lib/core/libimagstore/src/storeid.rs
index 17d9b67..cc7b288 100644
--- a/lib/core/libimagstore/src/storeid.rs
+++ b/lib/core/libimagstore/src/storeid.rs
@@ -43,87 +43,28 @@ use iter::retrieve::StoreRetrieveIterator;
/// A StoreId object is a unique identifier for one entry in the store which might be present or
/// not.
///
-#[derive(Debug, Clone, Hash, Eq, PartialOrd, Ord)]
-pub struct StoreId {
- base: Option<PathBuf>,
- id: PathBuf,
-}
-
-impl PartialEq for StoreId {
- fn eq(&self, other: &StoreId) -> bool {
- self.id == other.id
- }
-}
+#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub struct StoreId(PathBuf);
impl StoreId {
- pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
- StoreId::new_baseless(id).map(|mut sid| { sid.base = base; sid })
- }
-
- /// Try to create a StoreId object from a filesystem-absolute path.
- ///
- /// Automatically creates a StoreId object which has a `base` set to `store_part` if stripping
- /// the `store_part` from the `full_path` succeeded.
- pub fn from_full_path<D>(store_part: &PathBuf, full_path: D) -> Result<StoreId>
- where D: Deref<Target = Path>
- {
- let p = full_path
- .strip_prefix(store_part)
- .map_err(Error::from)
- .context(err_msg("Error building Store Id from full path"))?;
- StoreId::new(Some(store_part.clone()), PathBuf::from(p))
- }
-
- pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
+ pub fn new(id: PathBuf) -> Result<StoreId> {
debug!("Trying to get a new baseless id from: {:?}", id);
if id.is_absolute() {
debug!("Error: Id is absolute!");
Err(format_err!("Store Id local part is absolute: {}", id.display()))
} else {
debug!("Building Storeid object baseless");
- Ok(StoreId {
- base: None,
- id
- })
+ Ok(StoreId(id))
}
}
- pub fn without_base(mut self) -> StoreId {
- self.base = None;
- self
- }
-
- pub fn with_base(mut self, base: PathBuf) -> Self {
- self.base = Some(base);
- self
- }
-
- /// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
- /// specified.
- pub fn into_pathbuf(mut self) -> Result<PathBuf> {
- let base = self.base.take();
- let mut base = base.ok_or_else(|| {
- format_err!("Store Id has no base: {:?}", self.id.display().to_string())
- })?;
- base.push(self.id);
- Ok(base)
- }
-
- /// Check whether the StoreId exists (as in whether the file exists)
- ///
- /// # Warning
- ///
- /// Should be considered deprecated
- pub fn exists(&self) -> Result<bool> {
- self.clone().into_pathbuf().map(|pb| pb.exists())
+ pub fn with_base<'a>(self, base: &'a PathBuf) -> StoreIdWithBase<'a> {
+ StoreIdWithBase(base, self.0)
}
pub fn to_str(&self) -> Result<String> {
- match self.base.as_ref() {
- None => Ok(self.id.display().to_string()),
- Some(ref base) => Ok(format!("{}/{}", base.display(), self.id.display())),
- }
+ Ok(self.0.display().to_string())
}
/// Helper function for creating a displayable String from StoreId
@@ -145,12 +86,12 @@ impl StoreId {
/// Can be used to check whether a StoreId points to an entry in a specific collection of
/// StoreIds.
pub fn components(&self) -> Components {
- self.id.components()
+ self.0.components()
}
/// Get the _local_ part of a StoreId object, as in "the part from the store root to the entry".
pub fn local(&self) -> &PathBuf {
- &self.id
+ &self.0
}
/// Check whether a StoreId points to an entry in a specific collection.
@@ -166,7 +107,7 @@ impl StoreId {
pub fn is_in_collection<S: AsRef<str>, V: AsRef<[S]>>(&self, colls: &V) -> bool {
use std::path::Component;
- self.id
+ self.0
.components()
.zip(colls.as_ref().iter())
.all(|(component, pred_coll)| match component {
@@ -179,7 +120,7 @@ impl StoreId {
}
pub fn local_push<P: AsRef<Path>>(&mut self, path: P) {
- self.id.push(path)
+ self.0.push(path)
}
}
@@ -187,7 +128,7 @@ impl StoreId {
impl Display for StoreId {
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
- write!(fmt, "{}", self.id.display())
+ write!(fmt, "{}", self.0.display())
}
}
@@ -206,10 +147,75 @@ impl IntoStoreId for StoreId {
impl IntoStoreId for PathBuf {
fn into_storeid(self) -> Result<StoreId> {
- StoreId::new_baseless(self)
+ StoreId::new(self)
}
}
+#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
+pub(crate) struct StoreIdWithBase<'a>(&'a PathBuf, PathBuf);
+
+impl<'a> StoreIdWithBase<'a> {
+ pub(crate) fn new(base: &'a PathBuf, path: PathBuf) -> Self {
+ StoreIdWithBase(base, path)
+ }
+
+ pub(crate) fn without_base(self) -> StoreId {
+ StoreId(self.1)
+ }
+
+ /// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
+ /// specified.
+ pub(crate) fn into_pathbuf(self) -> Result<PathBuf> {
+ let mut base = self.0.clone();
+ base.push(self.1);
+ Ok(base)
+ }
+
+ /// Check whether the StoreId exists (as in whether the file exists)
+ pub fn exists(&self) -> Result<bool> {
+ self.clone().into_pathbuf().map(|pb| pb.exists())
+ }
+
+ pub fn to_str(&self) -> Result<String> {
+ let mut base = self.0.clone();
+ base.push(self.1.clone());
+ Ok(base.display().to_string())
+ }
+
+ /// Try to create a StoreId object from a filesystem-absolute path.
+ ///
+ /// Automatically creates a StoreId object which has a `base` set to `store_part` if stripping
+ /// the `store_part` from the `full_path` succeeded.
+ pub(crate) fn from_full_path<D>(store_part: &'a PathBuf, full_path: D) -> Result<StoreIdWithBase<'a>>
+ where D: Deref<Target = Path>
+ {
+ let p = full_path
+ .strip_prefix(store_part)
+ .map_err(Error::from)
+ .context(err_msg("Error building Store Id from full path"))?;
+ Ok(StoreIdWithBase(store_part, PathBuf::from(p)))
+ }
+}
+
+impl<'a> IntoStoreId for StoreIdWithBase<'a> {
+ fn into_storeid(self) -> Result<StoreId> {
+ Ok(StoreId(self.1))
+ }
+}
+
+impl<'a> Into<StoreId> for StoreIdWithBase<'a> {
+ fn into(self) -> StoreId {
+ StoreId(self.1)
+ }
+}
+
+impl<'a> Display for StoreIdWithBase<'a> {
+ fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
+ write!(fmt, "{}/{}", self.0.display(), self.1.display())
+ }
+}
+
+
#[macro_export]
macro_rules! module_entry_path_mod {
($name:expr) => (
@@ -249,7 +255,7 @@ macro_rules! module_entry_path_mod {
impl $crate::storeid::IntoStoreId for ModuleEntryPath {
fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
- StoreId::new(None, self.0)
+ StoreId::new(self.0)
}
}
}
@@ -355,6 +361,7 @@ mod test {
use std::path::PathBuf;
use storeid::StoreId;
+ use storeid::StoreIdWithBase;
use storeid::IntoStoreId;
module_entry_path_mod!("test");
@@ -368,88 +375,63 @@ mod test {
#[test]
fn test_baseless_path() {
- let id = StoreId::new_baseless(PathBuf::from("test"));
+ let id = StoreId::new(PathBuf::from("test"));
assert!(id.is_ok());
- assert_eq!(id.unwrap(), StoreId {
- base: None,
- id: PathBuf::from("test")
- });
+ assert_eq!(id.unwrap(), StoreId(PathBuf::from("test")));
}
#[test]
fn test_base_path() {
- let id = StoreId::from_full_path(&PathBuf::from("/tmp/"), PathBuf::from("/tmp/test"));
+ let id = StoreId::new(PathBuf::from("test"));
assert!(id.is_ok());
- assert_eq!(id.unwrap(), StoreId {
- base: Some(PathBuf::from("/tmp/")),
- id: PathBuf::from("test")
- });
+ assert_eq!(id.unwrap(), StoreId(PathBuf::from("test")));
}
#[test]
fn test_adding_base_to_baseless_path() {
- let id = StoreId::new_baseless(PathBuf::from("test"));
+ let id = StoreId::new(PathBuf::from("test"));
assert!(id.is_ok());
let id = id.unwrap();
- assert_eq!(id, StoreId { base: None, id: PathBuf::from("test") });
+ assert_eq!(id, StoreId(PathBuf::from("test")));
- let id = id.with_base(PathBuf::from("/tmp/"));
- assert_eq!(id, StoreId {
- base: Some(PathBuf::from("/tmp/")),
- id: PathBuf::from("test")
- });
+ let storebase = PathBuf::from("/tmp/");
+ let id = id.with_base(&storebase);
+ assert_eq!(id, StoreIdWithBase(&PathBuf::from("/tmp/"), PathBuf::from("test")));
}
#[test]
fn test_removing_base_from_base_path() {
- let id = StoreId::from_full_path(&PathBuf::from("/tmp/"), PathBuf::from("/tmp/test"));
+ let id = StoreId::new(PathBuf::from("/tmp/test"));
assert!(id.is_ok());
- let id = id.unwrap();
+ let storebase = PathBuf::from("/tmp/");
+ let id = id.unwrap().with_base(&storebase);
- assert_eq!(id, StoreId {
- base: Some(PathBuf::from("/tmp/")),
- id: PathBuf::from("test")
- });
+ assert_eq!(id, StoreIdWithBase(&PathBuf::from("/tmp/"), PathBuf::from("test")));
let id = id.without_base();
- assert_eq!(id, StoreId {
- base: None,
- id: PathBuf::from("test")
- });
- }
-
- #[test]
- fn test_baseless_into_pathbuf_is_err() {
- let id = StoreId::new_baseless(PathBuf::from("test"));
- assert!(id.is_ok());
- assert!(id.unwrap().into_pathbuf().is_err());
- }
-
- #[test]
- fn test_baseless_into_pathbuf_is_storeidhasnobaseerror() {
- let id = StoreId::new_baseless(PathBuf::from("test"));
- assert!(id.is_ok());
-
- let pb = id.unwrap().into_pathbuf();
- assert!(pb.is_err());
+ assert_eq!(id, StoreId(PathBuf::from("test")));
}
#[test]
fn test_basefull_into_pathbuf_is_ok() {
- let id = StoreId::from_full_path(&PathBuf::from("/tmp/"), PathBuf::from("/tmp/test"));
+ let id = StoreId::new(PathBuf::from("/tmp/test"));
assert!(id.is_ok());
- assert!(id.unwrap().into_pathbuf().is_ok());
+
+ let storebase = PathBuf::from("/tmp/");
+ let id = id.unwrap().with_base(&storebase);
+ assert!(id.into_pathbuf().is_ok());
}
#[test]
fn test_basefull_into_pathbuf_is_correct() {
- let id = StoreId::from_full_path(&PathBuf::from("/tmp/"), PathBuf::from("/tmp/test"));
+ let id = StoreId::new(PathBuf::from("/tmp/test"));
assert!(id.is_ok());
- let pb = id.unwrap().into_pathbuf();
+ let storebase = PathBuf::from("/tmp/");
+ let pb = id.unwrap().with_base(&storebase).into_pathbuf();
assert!(pb.is_ok());
assert_eq!(pb.unwrap(), PathBuf::from("/tmp/test"));