Auto merge of #99 - TheNeikos:add-libstore, r=matthiasbeyer
Add libimagstore Alright, do check the file and feel free to post comments/ask questions
This commit is contained in:
commit
469bdd1d94
10 changed files with 517 additions and 3 deletions
51
Cargo.lock
generated
51
Cargo.lock
generated
|
@ -8,6 +8,30 @@ dependencies = [
|
||||||
"libimagutil 0.1.0",
|
"libimagutil 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fs2"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libimagmodule"
|
name = "libimagmodule"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -19,8 +43,35 @@ version = "0.1.0"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libimagstore"
|
name = "libimagstore"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"fs2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"toml 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libimagutil"
|
name = "libimagutil"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-serialize"
|
||||||
|
version = "0.3.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.1.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-build"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,67 @@
|
||||||
Store functionality
|
Store functionality
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
The "libstore" MUST define the programming-language level interface to the
|
||||||
|
store on the file system.
|
||||||
|
The library therefor MUST define and export types which can be used to get data
|
||||||
|
from the filesystem.
|
||||||
|
|
||||||
|
## Types {#sec:libstore:types}
|
||||||
|
|
||||||
|
The types in @tbl:libstore:types are exported by the library.
|
||||||
|
|
||||||
|
| Type | Meaning |
|
||||||
|
| :------------ | :----------------------------------------------- |
|
||||||
|
| Entry | Entity on the Filesystem, File |
|
||||||
|
| EntryContent | User-Content of the Entry |
|
||||||
|
| EntryHeader | Header of the Entry |
|
||||||
|
| Store | Store interface |
|
||||||
|
| FileLockEntry | Handle to an Entry |
|
||||||
|
|
||||||
|
Table: Types the store library exports {#tbl:libstore:types}
|
||||||
|
|
||||||
|
Each of these types MUST export functions to work with the data the objects of
|
||||||
|
the types contain.
|
||||||
|
|
||||||
|
### Entry {#sec:libstore:types:entry}
|
||||||
|
|
||||||
|
The `Entry` type MUST hold the following content:
|
||||||
|
|
||||||
|
- A path where on the filesystem the acutal file lives
|
||||||
|
- An instance of `EntryContent` as interface to the content of the file
|
||||||
|
(@sec:libstore:types:entrycontent).
|
||||||
|
- An instance of `EntryHeader` as interface to the header of the file
|
||||||
|
(@sec:libstore:types:entryheader).
|
||||||
|
|
||||||
|
The entry type MUST export functions to get
|
||||||
|
|
||||||
|
- The content object
|
||||||
|
- The header object
|
||||||
|
- The path of the actual file
|
||||||
|
|
||||||
|
The entry type MUST export functions to set
|
||||||
|
|
||||||
|
- The header object
|
||||||
|
- The content object
|
||||||
|
|
||||||
|
### EntryContent {#sec:libstore:types:entrycontent}
|
||||||
|
|
||||||
|
The `EntryContent` type is an type-alias for `String`.
|
||||||
|
|
||||||
|
### EntryHeader {#sec:libstore:types:entryheader}
|
||||||
|
|
||||||
|
The `EntryHeader` type is an wrapper around the type, the TOML-Parser library
|
||||||
|
exports.
|
||||||
|
|
||||||
|
It SHOULD contain utility functions to work with the header in a convenient way.
|
||||||
|
|
||||||
|
### Store {#sec:libstore:types:store}
|
||||||
|
|
||||||
|
The `Store` type MUST represent the interface to the store on the filesystem.
|
||||||
|
It MUST contain CRUD-functionality to work with the entries in the store.
|
||||||
|
It MUST contain a variable which contains the path of the store on the
|
||||||
|
filesystem which is represented by an object of this type.
|
||||||
|
It also MUST contain a getter for this variable.
|
||||||
|
It MUST NOT contain a setter for this variable, as changing the store while the
|
||||||
|
programm is running is not allowed.
|
||||||
|
|
||||||
|
|
51
libimagstore/Cargo.lock
generated
51
libimagstore/Cargo.lock
generated
|
@ -1,4 +1,55 @@
|
||||||
[root]
|
[root]
|
||||||
name = "libimagstore"
|
name = "libimagstore"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"fs2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"toml 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fs2"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-serialize"
|
||||||
|
version = "0.3.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.1.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-build"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
|
|
@ -2,3 +2,9 @@
|
||||||
name = "libimagstore"
|
name = "libimagstore"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
fs2 = "0.2.2"
|
||||||
|
toml = "0.1.25"
|
||||||
|
|
||||||
|
|
1
libimagstore/src/content.rs
Normal file
1
libimagstore/src/content.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub type EntryContent = String;
|
11
libimagstore/src/entry.rs
Normal file
11
libimagstore/src/entry.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use header::EntryHeader;
|
||||||
|
use content::EntryContent;
|
||||||
|
use store::StoreId;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Entry {
|
||||||
|
location: StoreId,
|
||||||
|
header: EntryHeader,
|
||||||
|
content: EntryContent,
|
||||||
|
}
|
||||||
|
|
77
libimagstore/src/error.rs
Normal file
77
libimagstore/src/error.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use std::fmt::Error as FmtError;
|
||||||
|
use std::clone::Clone;
|
||||||
|
use std::convert::From;
|
||||||
|
|
||||||
|
use std::io::Error as IOError;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum StoreErrorKind {
|
||||||
|
IdNotFound,
|
||||||
|
OutOfMemory,
|
||||||
|
// maybe more
|
||||||
|
}
|
||||||
|
|
||||||
|
fn store_error_type_as_str(e: &StoreErrorKind) -> &'static str {
|
||||||
|
match e {
|
||||||
|
&StoreErrorKind::IdNotFound => "ID not found",
|
||||||
|
&StoreErrorKind::OutOfMemory => "Out of Memory",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for StoreErrorKind {
|
||||||
|
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
||||||
|
try!(write!(fmt, "{}", store_error_type_as_str(self)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StoreError {
|
||||||
|
err_type: StoreErrorKind,
|
||||||
|
cause: Option<Box<Error>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StoreError {
|
||||||
|
|
||||||
|
pub fn new(errtype: StoreErrorKind, cause: Option<Box<Error>>)
|
||||||
|
-> StoreError
|
||||||
|
{
|
||||||
|
StoreError {
|
||||||
|
err_type: errtype,
|
||||||
|
cause: cause,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn err_type(&self) -> StoreErrorKind {
|
||||||
|
self.err_type.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for StoreError {
|
||||||
|
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
||||||
|
try!(write!(fmt, "[{}]", store_error_type_as_str(&self.err_type.clone())));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for StoreError {
|
||||||
|
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
store_error_type_as_str(&self.err_type.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cause(&self) -> Option<&Error> {
|
||||||
|
self.cause.as_ref().map(|e| &**e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
20
libimagstore/src/header.rs
Normal file
20
libimagstore/src/header.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
use toml::Table;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct EntryHeader {
|
||||||
|
toml: Table,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EntryHeader {
|
||||||
|
|
||||||
|
pub fn new(toml: Table) -> EntryHeader {
|
||||||
|
EntryHeader {
|
||||||
|
toml: toml,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toml(&self) -> &Table {
|
||||||
|
&self.toml
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,3 +1,9 @@
|
||||||
#[test]
|
extern crate fs2;
|
||||||
fn it_works() {
|
extern crate toml;
|
||||||
}
|
|
||||||
|
pub mod content;
|
||||||
|
pub mod entry;
|
||||||
|
pub mod error;
|
||||||
|
pub mod header;
|
||||||
|
pub mod store;
|
||||||
|
|
||||||
|
|
227
libimagstore/src/store.rs
Normal file
227
libimagstore/src/store.rs
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::ops::Drop;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::result::Result as RResult;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::{RwLock, Mutex};
|
||||||
|
|
||||||
|
use fs2::FileExt;
|
||||||
|
|
||||||
|
use entry::Entry;
|
||||||
|
use error::StoreError;
|
||||||
|
|
||||||
|
/// The Result Type returned by any interaction with the store that could fail
|
||||||
|
pub type Result<T> = RResult<T, StoreError>;
|
||||||
|
|
||||||
|
/// The Index into the Store
|
||||||
|
pub type StoreId = PathBuf;
|
||||||
|
|
||||||
|
/// This Trait allows you to convert various representations to a single one
|
||||||
|
/// suitable for usage in the Store
|
||||||
|
trait IntoStoreId {
|
||||||
|
fn into_storeid(self) -> StoreId;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoStoreId for &'a str {
|
||||||
|
fn into_storeid(self) -> StoreId {
|
||||||
|
PathBuf::from(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoStoreId for &'a String{
|
||||||
|
fn into_storeid(self) -> StoreId {
|
||||||
|
PathBuf::from(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoStoreId for String{
|
||||||
|
fn into_storeid(self) -> StoreId {
|
||||||
|
PathBuf::from(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoStoreId for PathBuf {
|
||||||
|
fn into_storeid(self) -> StoreId {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoStoreId for &'a PathBuf {
|
||||||
|
fn into_storeid(self) -> StoreId {
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ISI: IntoStoreId> IntoStoreId for (ISI, ISI) {
|
||||||
|
fn into_storeid(self) -> StoreId {
|
||||||
|
let (first, second) = self;
|
||||||
|
let mut res : StoreId = first.into_storeid();
|
||||||
|
res.push(second.into_storeid());
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum StoreEntryPresence {
|
||||||
|
Present,
|
||||||
|
Borrowed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A store entry, depending on the option type it is either borrowed currently
|
||||||
|
/// or not.
|
||||||
|
struct StoreEntry {
|
||||||
|
file: File,
|
||||||
|
entry: StoreEntryPresence
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl StoreEntry {
|
||||||
|
/// The entry is currently borrowed, meaning that some thread is currently
|
||||||
|
/// mutating it
|
||||||
|
fn is_borrowed(&self) -> bool {
|
||||||
|
self.entry == StoreEntryPresence::Borrowed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flush the entry to disk
|
||||||
|
fn set_entry(&mut self, entry: Entry) -> Result<()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// We borrow the entry
|
||||||
|
fn get_entry(&mut self) -> Result<Entry> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// We copy the entry
|
||||||
|
fn copy_entry(&mut self) -> Result<Entry> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Store itself, through this object one can interact with IMAG's entries
|
||||||
|
pub struct Store {
|
||||||
|
location: PathBuf,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal Path->File cache map
|
||||||
|
*
|
||||||
|
* Caches the files, so they remain flock()ed
|
||||||
|
*
|
||||||
|
* Could be optimized for a threadsafe HashMap
|
||||||
|
*/
|
||||||
|
entries: Arc<RwLock<HashMap<StoreId, StoreEntry>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Store {
|
||||||
|
/// Creates the Entry at the given location (inside the entry)
|
||||||
|
pub fn create(&self, entry: Entry) -> Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Borrow a given Entry. When the `FileLockEntry` is either `update`d or
|
||||||
|
/// dropped, the new Entry is written to disk
|
||||||
|
pub fn retrieve<'a>(&'a self, id: StoreId) -> Result<FileLockEntry<'a>> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the `FileLockEntry` and write to disk
|
||||||
|
pub fn update<'a>(&'a self, entry: FileLockEntry<'a>) -> Result<()> {
|
||||||
|
self._update(&entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal method to write to the filesystem store.
|
||||||
|
///
|
||||||
|
/// # Assumptions
|
||||||
|
/// This method assumes that entry is dropped _right after_ the call, hence
|
||||||
|
/// it is not public.
|
||||||
|
fn _update<'a>(&'a self, entry: &FileLockEntry<'a>) -> Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve a copy of a given entry, this cannot be used to mutate
|
||||||
|
/// the one on disk
|
||||||
|
pub fn retrieve_copy(&self, id: StoreId) -> Result<Entry> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete an entry
|
||||||
|
pub fn delete(&self, id: StoreId) -> Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Store {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlock all files on drop
|
||||||
|
*
|
||||||
|
* TODO: Error message when file cannot be unlocked?
|
||||||
|
*/
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.entries.write().unwrap()
|
||||||
|
.iter().map(|f| f.1.file.unlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A struct that allows you to borrow an Entry
|
||||||
|
pub struct FileLockEntry<'a> {
|
||||||
|
store: &'a Store,
|
||||||
|
entry: Entry,
|
||||||
|
key: StoreId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FileLockEntry<'a, > {
|
||||||
|
fn new(store: &'a Store, entry: Entry, key: StoreId) -> FileLockEntry<'a> {
|
||||||
|
FileLockEntry {
|
||||||
|
store: store,
|
||||||
|
entry: entry,
|
||||||
|
key: key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ::std::ops::Deref for FileLockEntry<'a> {
|
||||||
|
type Target = Entry;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ::std::ops::DerefMut for FileLockEntry<'a> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for FileLockEntry<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.store._update(self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use store::{StoreId, IntoStoreId};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn into_storeid_trait() {
|
||||||
|
let buf = PathBuf::from("abc/def");
|
||||||
|
|
||||||
|
let test = ("abc", "def");
|
||||||
|
assert_eq!(buf, test.into_storeid());
|
||||||
|
|
||||||
|
let test = "abc/def";
|
||||||
|
assert_eq!(buf, test.into_storeid());
|
||||||
|
|
||||||
|
let test = String::from("abc/def");
|
||||||
|
assert_eq!(buf, test.into_storeid());
|
||||||
|
|
||||||
|
let test = PathBuf::from("abc/def");
|
||||||
|
assert_eq!(buf, test.into_storeid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue