2016-09-05 16:21:34 +00:00
|
|
|
use std::ops::Deref;
|
|
|
|
use std::path::Path;
|
2016-01-19 18:00:35 +00:00
|
|
|
use std::path::PathBuf;
|
2016-04-14 11:20:35 +00:00
|
|
|
|
2016-06-30 09:02:58 +00:00
|
|
|
use std::fmt::{Display, Debug, Formatter};
|
2016-04-18 16:40:59 +00:00
|
|
|
use std::fmt::Error as FmtError;
|
|
|
|
use std::result::Result as RResult;
|
2016-08-25 16:39:24 +00:00
|
|
|
use std::path::Components;
|
2016-03-13 19:56:23 +00:00
|
|
|
|
2016-08-24 13:55:26 +00:00
|
|
|
use libimagerror::into::IntoError;
|
|
|
|
|
2016-05-26 20:19:29 +00:00
|
|
|
use error::StoreErrorKind as SEK;
|
2016-09-05 16:21:34 +00:00
|
|
|
use error::MapErrInto;
|
2016-03-13 19:56:23 +00:00
|
|
|
use store::Result;
|
2016-01-19 18:00:35 +00:00
|
|
|
|
|
|
|
/// The Index into the Store
|
2016-04-14 11:20:35 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
|
2016-08-07 14:45:41 +00:00
|
|
|
pub struct StoreId {
|
2016-08-07 14:53:33 +00:00
|
|
|
base: Option<PathBuf>,
|
|
|
|
id: PathBuf,
|
2016-08-07 14:45:41 +00:00
|
|
|
}
|
2016-04-14 11:20:35 +00:00
|
|
|
|
2016-07-02 15:52:12 +00:00
|
|
|
impl StoreId {
|
|
|
|
|
2016-08-25 12:27:42 +00:00
|
|
|
pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
|
2016-08-25 12:29:15 +00:00
|
|
|
StoreId::new_baseless(id).map(|mut sid| { sid.base = base; sid })
|
|
|
|
}
|
|
|
|
|
2016-09-05 16:21:34 +00:00
|
|
|
/// 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.
|
|
|
|
///
|
|
|
|
/// Returns a `StoreErrorKind::StoreIdBuildFromFullPathError` if stripping failes.
|
|
|
|
pub fn from_full_path<D>(store_part: &PathBuf, full_path: D) -> Result<StoreId>
|
|
|
|
where D: Deref<Target = Path>
|
|
|
|
{
|
|
|
|
let p = try!(
|
|
|
|
full_path.strip_prefix(store_part).map_err_into(SEK::StoreIdBuildFromFullPathError)
|
|
|
|
);
|
|
|
|
StoreId::new(Some(store_part.clone()), PathBuf::from(p))
|
|
|
|
}
|
|
|
|
|
2016-08-25 12:29:15 +00:00
|
|
|
pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
|
2016-08-25 12:27:42 +00:00
|
|
|
if id.is_absolute() {
|
|
|
|
Err(SEK::StoreIdLocalPartAbsoluteError.into_error())
|
|
|
|
} else {
|
|
|
|
Ok(StoreId {
|
2016-08-25 12:29:15 +00:00
|
|
|
base: None,
|
2016-08-25 12:27:42 +00:00
|
|
|
id: id
|
|
|
|
})
|
|
|
|
}
|
2016-08-07 14:54:36 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 14:17:23 +00:00
|
|
|
pub fn without_base(mut self) -> StoreId {
|
|
|
|
self.base = None;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2016-08-25 15:54:14 +00:00
|
|
|
pub fn with_base(mut self, base: PathBuf) -> Self {
|
|
|
|
self.base = Some(base);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2016-09-05 14:32:50 +00:00
|
|
|
/// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
|
|
|
|
/// specified.
|
|
|
|
pub fn into_pathbuf(self) -> Result<PathBuf> {
|
2016-09-05 14:51:37 +00:00
|
|
|
let mut base = try!(self.base.ok_or(SEK::StoreIdHasNoBaseError.into_error()));
|
|
|
|
base.push(self.id);
|
|
|
|
Ok(base)
|
2016-09-05 14:32:50 +00:00
|
|
|
}
|
|
|
|
|
2016-08-07 14:48:40 +00:00
|
|
|
pub fn exists(&self) -> bool {
|
2016-09-05 14:51:37 +00:00
|
|
|
// TODO: hiding error here.
|
|
|
|
self.clone().into_pathbuf().map(|pb| pb.exists()).unwrap_or(false)
|
2016-08-07 14:48:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_file(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_dir(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2016-08-24 13:55:26 +00:00
|
|
|
pub fn to_str(&self) -> Result<String> {
|
|
|
|
if self.base.is_some() {
|
|
|
|
let mut base = self.base.as_ref().cloned().unwrap();
|
|
|
|
base.push(self.id.clone());
|
|
|
|
base
|
|
|
|
} else {
|
|
|
|
self.id.clone()
|
|
|
|
}
|
|
|
|
.to_str()
|
|
|
|
.map(String::from)
|
|
|
|
.ok_or(SEK::StoreIdHandlingError.into_error())
|
|
|
|
}
|
|
|
|
|
2016-08-25 16:39:24 +00:00
|
|
|
/// Returns the components of the `id` part of the StoreId object.
|
|
|
|
///
|
|
|
|
/// 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()
|
|
|
|
}
|
|
|
|
|
2016-09-04 08:40:38 +00:00
|
|
|
/// 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
|
2016-08-28 11:39:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-02 15:52:12 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 09:02:58 +00:00
|
|
|
impl Display for StoreId {
|
|
|
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
|
2016-08-07 14:46:31 +00:00
|
|
|
match self.id.to_str() {
|
2016-06-30 09:02:58 +00:00
|
|
|
Some(s) => write!(fmt, "{}", s),
|
2016-08-07 14:46:31 +00:00
|
|
|
None => write!(fmt, "{}", self.id.to_string_lossy()),
|
2016-06-30 09:02:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-01-19 18:00:35 +00:00
|
|
|
/// This Trait allows you to convert various representations to a single one
|
|
|
|
/// suitable for usage in the Store
|
2016-01-29 16:00:29 +00:00
|
|
|
pub trait IntoStoreId {
|
2016-08-25 15:52:23 +00:00
|
|
|
fn into_storeid(self) -> Result<StoreId>;
|
2016-01-19 18:00:35 +00:00
|
|
|
}
|
|
|
|
|
2016-05-03 13:45:06 +00:00
|
|
|
impl IntoStoreId for StoreId {
|
2016-08-25 15:52:23 +00:00
|
|
|
fn into_storeid(self) -> Result<StoreId> {
|
|
|
|
Ok(self)
|
2016-05-03 13:45:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-26 10:18:00 +00:00
|
|
|
impl IntoStoreId for PathBuf {
|
|
|
|
fn into_storeid(self) -> Result<StoreId> {
|
|
|
|
StoreId::new_baseless(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-19 18:00:35 +00:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! module_entry_path_mod {
|
2016-08-30 09:40:32 +00:00
|
|
|
($name:expr) => (
|
2016-01-22 17:22:01 +00:00
|
|
|
#[deny(missing_docs,
|
|
|
|
missing_copy_implementations,
|
|
|
|
trivial_casts, trivial_numeric_casts,
|
|
|
|
unsafe_code,
|
|
|
|
unstable_features,
|
|
|
|
unused_import_braces, unused_qualifications,
|
|
|
|
unused_imports)]
|
2016-01-29 16:02:35 +00:00
|
|
|
/// A helper module to create valid module entry paths
|
2016-01-19 18:00:35 +00:00
|
|
|
pub mod module_path {
|
|
|
|
use std::convert::AsRef;
|
|
|
|
use std::path::Path;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
2016-05-03 12:53:14 +00:00
|
|
|
use $crate::storeid::StoreId;
|
2016-08-25 15:52:23 +00:00
|
|
|
use $crate::store::Result;
|
2016-05-03 12:53:14 +00:00
|
|
|
|
2016-01-19 18:00:35 +00:00
|
|
|
/// A Struct giving you the ability to choose store entries assigned
|
|
|
|
/// to it.
|
|
|
|
///
|
|
|
|
/// It is created through a call to `new`.
|
|
|
|
pub struct ModuleEntryPath(PathBuf);
|
|
|
|
|
|
|
|
impl ModuleEntryPath {
|
|
|
|
/// Path has to be a valid UTF-8 string or this will panic!
|
|
|
|
pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
|
|
|
|
let mut path = PathBuf::new();
|
2016-03-10 17:44:24 +00:00
|
|
|
path.push(format!("{}", $name));
|
2016-01-19 18:00:35 +00:00
|
|
|
path.push(pa.as_ref().clone());
|
|
|
|
let name = pa.as_ref().file_name().unwrap()
|
|
|
|
.to_str().unwrap();
|
2016-08-30 08:52:00 +00:00
|
|
|
path.set_file_name(name);
|
2016-01-19 18:00:35 +00:00
|
|
|
ModuleEntryPath(path)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl $crate::storeid::IntoStoreId for ModuleEntryPath {
|
2016-08-25 15:52:23 +00:00
|
|
|
fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
|
2016-08-07 14:54:48 +00:00
|
|
|
StoreId::new(None, self.0)
|
2016-01-19 18:00:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2016-05-12 15:21:04 +00:00
|
|
|
pub struct StoreIdIterator {
|
|
|
|
iter: Box<Iterator<Item = StoreId>>,
|
|
|
|
}
|
|
|
|
|
2016-04-18 16:40:59 +00:00
|
|
|
impl Debug for StoreIdIterator {
|
|
|
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
|
|
|
|
write!(fmt, "StoreIdIterator")
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-01-24 11:17:25 +00:00
|
|
|
impl StoreIdIterator {
|
|
|
|
|
2016-05-12 15:21:04 +00:00
|
|
|
pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
|
2016-01-24 11:17:25 +00:00
|
|
|
StoreIdIterator {
|
2016-05-12 15:21:04 +00:00
|
|
|
iter: iter,
|
2016-01-24 11:17:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for StoreIdIterator {
|
|
|
|
type Item = StoreId;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<StoreId> {
|
2016-05-12 15:21:04 +00:00
|
|
|
self.iter.next()
|
2016-01-24 11:17:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-01-19 18:00:35 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
|
|
|
|
use storeid::IntoStoreId;
|
|
|
|
|
2016-08-30 09:40:32 +00:00
|
|
|
module_entry_path_mod!("test");
|
2016-01-19 18:00:35 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn correct_path() {
|
|
|
|
let p = module_path::ModuleEntryPath::new("test");
|
|
|
|
|
2016-08-30 08:52:00 +00:00
|
|
|
assert_eq!(p.into_storeid().unwrap().to_str().unwrap(), "test/test");
|
2016-01-19 18:00:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|