Rewrite library
libimagcontact stores all contact information in the entry header now.
This commit is contained in:
parent
3eab3af7b0
commit
abc142f4b5
7 changed files with 88 additions and 71 deletions
|
@ -25,15 +25,11 @@ log = "0.3"
|
|||
toml = "0.4"
|
||||
toml-query = "0.6"
|
||||
vobject = "0.4"
|
||||
uuid = { version = "0.6", features = ["v4"] }
|
||||
serde = { version = "1", optional = true }
|
||||
serde_derive = { version = "1", optional = true }
|
||||
uuid = "0.6"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
|
||||
libimagstore = { version = "0.8.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagerror = { version = "0.8.0", path = "../../../lib/core/libimagerror" }
|
||||
libimagentryutil = { version = "0.8.0", path = "../../../lib/entry/libimagentryutil/" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
deser = ["serde", "serde_derive"]
|
||||
|
||||
|
|
|
@ -17,16 +17,18 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use vobject::Component;
|
||||
use toml::to_string as toml_to_string;
|
||||
use toml::from_str as toml_from_str;
|
||||
use toml_query::read::TomlValueReadExt;
|
||||
|
||||
use libimagstore::store::Entry;
|
||||
use libimagentryutil::isa::Is;
|
||||
use libimagentryutil::isa::IsKindHeaderPathProvider;
|
||||
|
||||
use deser::DeserVcard;
|
||||
use error::Result;
|
||||
use util;
|
||||
use error::ContactError as CE;
|
||||
use error::ContactErrorKind as CEK;
|
||||
|
||||
/// Trait to be implemented on ::libimagstore::store::Entry
|
||||
pub trait Contact {
|
||||
|
@ -35,7 +37,7 @@ pub trait Contact {
|
|||
|
||||
// getting data
|
||||
|
||||
fn get_contact_data(&self) -> Result<ContactData>;
|
||||
fn deser(&self) -> Result<DeserVcard>;
|
||||
|
||||
// More convenience functionality may follow
|
||||
|
||||
|
@ -49,28 +51,18 @@ impl Contact for Entry {
|
|||
self.is::<IsContact>().map_err(From::from)
|
||||
}
|
||||
|
||||
fn get_contact_data(&self) -> Result<ContactData> {
|
||||
unimplemented!()
|
||||
fn deser(&self) -> Result<DeserVcard> {
|
||||
let data = self
|
||||
.get_header()
|
||||
.read("contact.data")?
|
||||
.ok_or_else(|| CE::from_kind(CEK::HeaderDataMissing("contact.data")))?;
|
||||
|
||||
// ugly hack
|
||||
let data_str = toml_to_string(&data)?;
|
||||
let deser : DeserVcard = toml_from_str(&data_str)?;
|
||||
|
||||
Ok(deser)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub struct ContactData(Component);
|
||||
|
||||
impl ContactData {
|
||||
|
||||
pub fn into_inner(self) -> Component {
|
||||
self.0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Deref for ContactData {
|
||||
type Target = Component;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,13 +20,7 @@
|
|||
use vobject::vcard::Vcard;
|
||||
|
||||
/// A type which can be build from a Vcard and be serialized.
|
||||
///
|
||||
/// # Details
|
||||
///
|
||||
/// Deserializing is not supported by libimagcontact yet
|
||||
/// Elements which are "empty" (as in empty list) or optional and not present are not serialized.
|
||||
///
|
||||
#[derive(Serialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DeserVcard {
|
||||
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
|
|
|
@ -32,6 +32,8 @@ error_chain! {
|
|||
|
||||
foreign_links {
|
||||
Io(::std::io::Error);
|
||||
TomlDe(::toml::de::Error);
|
||||
TomlSer(::toml::ser::Error);
|
||||
TomlQueryError(::toml_query::error::Error);
|
||||
UuidError(::uuid::ParseError);
|
||||
}
|
||||
|
@ -43,14 +45,19 @@ error_chain! {
|
|||
display("Type error in header, expected {} at '{}', found other type", ty, loc)
|
||||
}
|
||||
|
||||
HeaderDataMissing(datapath: &'static str) {
|
||||
description("Data missing in header")
|
||||
display("Data missing in header at '{}'", datapath)
|
||||
}
|
||||
|
||||
EntryNotFound(sid: StoreId) {
|
||||
description("Entry not found with StoreId")
|
||||
display("Entry {:?} not found", sid)
|
||||
}
|
||||
|
||||
UidMissing(path: String) {
|
||||
UidMissing(buf: String) {
|
||||
description("Vcard object has no UID")
|
||||
display("Vcard at {:?} has no UID", path)
|
||||
display("Vcard has no UID : {}", buf)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,12 +33,16 @@
|
|||
while_true,
|
||||
)]
|
||||
|
||||
#![recursion_limit="128"]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate error_chain;
|
||||
extern crate vobject;
|
||||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
extern crate uuid;
|
||||
extern crate serde;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
#[macro_use] extern crate libimagstore;
|
||||
extern crate libimagerror;
|
||||
|
@ -50,15 +54,6 @@ pub mod contact;
|
|||
pub mod error;
|
||||
pub mod iter;
|
||||
pub mod store;
|
||||
pub mod deser;
|
||||
mod util;
|
||||
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
#[cfg(feature = "deser")]
|
||||
pub mod deser;
|
||||
|
||||
|
|
|
@ -17,18 +17,24 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::result::Result as RResult;
|
||||
|
||||
use vobject::parse_component;
|
||||
use toml::Value;
|
||||
use toml::to_string as toml_to_string;
|
||||
use toml::from_str as toml_from_str;
|
||||
use toml_query::insert::TomlValueInsertExt;
|
||||
use vobject::vcard::Vcard;
|
||||
|
||||
use libimagstore::storeid::IntoStoreId;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::store::Store;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::storeid::StoreIdIterator;
|
||||
use libimagentryutil::isa::Is;
|
||||
|
||||
use contact::IsContact;
|
||||
use deser::DeserVcard;
|
||||
use module_path::ModuleEntryPath;
|
||||
use error::ContactError as CE;
|
||||
use error::ContactErrorKind as CEK;
|
||||
use error::Result;
|
||||
|
@ -38,10 +44,11 @@ pub trait ContactStore<'a> {
|
|||
|
||||
// creating
|
||||
|
||||
fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
|
||||
fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
|
||||
fn retrieve_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
|
||||
|
||||
/// Create contact ref from buffer
|
||||
fn create_from_buf(&'a self, buf: &String) -> Result<FileLockEntry<'a>>;
|
||||
fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>>;
|
||||
fn retrieve_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>>;
|
||||
|
||||
// getting
|
||||
|
||||
|
@ -55,12 +62,19 @@ impl<'a> ContactStore<'a> for Store {
|
|||
util::read_to_string(p).and_then(|buf| self.create_from_buf(&buf))
|
||||
}
|
||||
|
||||
/// Create contact ref from buffer
|
||||
fn create_from_buf(&'a self, buf: &String) -> Result<FileLockEntry<'a>> {
|
||||
let component = parse_component(&buf)?;
|
||||
debug!("Parsed: {:?}", component);
|
||||
fn retrieve_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>> {
|
||||
util::read_to_string(p).and_then(|buf| self.retrieve_from_buf(&buf))
|
||||
}
|
||||
|
||||
unimplemented!()
|
||||
/// Create contact ref from buffer
|
||||
fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
|
||||
let (sid, value) = prepare_fetching_from_store(buf)?;
|
||||
postprocess_fetched_entry(self.create(sid)?, value)
|
||||
}
|
||||
|
||||
fn retrieve_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
|
||||
let (sid, value) = prepare_fetching_from_store(buf)?;
|
||||
postprocess_fetched_entry(self.retrieve(sid)?, value)
|
||||
}
|
||||
|
||||
fn all_contacts(&'a self) -> Result<StoreIdIterator> {
|
||||
|
@ -74,3 +88,30 @@ impl<'a> ContactStore<'a> for Store {
|
|||
|
||||
}
|
||||
|
||||
/// Prepare the fetching from the store.
|
||||
///
|
||||
/// That means calculating the StoreId and the Value from the vcard data
|
||||
fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> {
|
||||
let vcard = Vcard::build(&buf)?;
|
||||
debug!("Parsed: {:?}", vcard);
|
||||
|
||||
let uid = vcard.uid().ok_or_else(|| CE::from_kind(CEK::UidMissing(buf.to_string())))?;
|
||||
|
||||
let value = { // dirty ugly hack
|
||||
let serialized = DeserVcard::from(vcard);
|
||||
let serialized = toml_to_string(&serialized)?;
|
||||
toml_from_str::<Value>(&serialized)?
|
||||
};
|
||||
|
||||
let sid = ModuleEntryPath::new(uid.raw()).into_storeid()?;
|
||||
|
||||
Ok((sid, value))
|
||||
}
|
||||
|
||||
/// Postprocess the entry just fetched from the store
|
||||
fn postprocess_fetched_entry<'a>(mut entry: FileLockEntry<'a>, value: Value) -> Result<FileLockEntry<'a>> {
|
||||
entry.set_isflag::<IsContact>()?;
|
||||
entry.get_header_mut().insert("contact.data", value)?;
|
||||
Ok(entry)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@ use std::io::Read;
|
|||
|
||||
use error::Result;
|
||||
|
||||
use vobject::Component;
|
||||
|
||||
pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> {
|
||||
let mut cont = String::new();
|
||||
|
||||
|
@ -37,9 +35,3 @@ pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> {
|
|||
Ok(cont)
|
||||
}
|
||||
|
||||
/// Helper for chaining results nicely
|
||||
pub fn parse(buf: String) -> Result<Component> {
|
||||
use vobject::parse_component;
|
||||
parse_component(&buf).map_err(From::from)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue