Merge pull request #1031 from matthiasbeyer/libimagdiary/extension-as-trait

libimagdiary: extension as trait
This commit is contained in:
Matthias Beyer 2017-09-01 13:15:58 +02:00 committed by GitHub
commit 1fe5a23331
11 changed files with 278 additions and 262 deletions

View file

@ -19,16 +19,18 @@
use std::process::exit; use std::process::exit;
use clap::ArgMatches;
use libimagdiary::diary::Diary; use libimagdiary::diary::Diary;
use libimagdiary::diaryid::DiaryId; use libimagdiary::diaryid::DiaryId;
use libimagdiary::error::DiaryErrorKind as DEK; use libimagdiary::error::DiaryErrorKind as DEK;
use libimagdiary::error::MapErrInto; use libimagdiary::error::MapErrInto;
use libimagentryedit::edit::Edit; use libimagentryedit::edit::Edit;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error_exit;
use libimagdiary::entry::Entry;
use libimagdiary::result::Result;
use libimagutil::warn_exit::warn_exit; use libimagutil::warn_exit::warn_exit;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use util::get_diary_name; use util::get_diary_name;
@ -36,88 +38,90 @@ pub fn create(rt: &Runtime) {
let diaryname = get_diary_name(rt) let diaryname = get_diary_name(rt)
.unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); .unwrap_or_else( || warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));
let prevent_edit = rt.cli().subcommand_matches("create").unwrap().is_present("no-edit"); let mut entry = create_entry(rt.store(), &diaryname, rt);
fn create_entry<'a>(diary: &'a Diary, rt: &Runtime) -> Result<Entry<'a>> { let res = if rt.cli().subcommand_matches("create").unwrap().is_present("no-edit") {
use std::str::FromStr; debug!("Not editing new diary entry");
Ok(())
let create = rt.cli().subcommand_matches("create").unwrap(); } else {
if !create.is_present("timed") { debug!("Editing new diary entry");
debug!("Creating non-timed entry"); entry.edit_content(rt)
diary.new_entry_today() .map_err_into(DEK::DiaryEditError)
} else { };
let id = match create.value_of("timed") {
Some("h") | Some("hourly") => {
debug!("Creating hourly-timed entry");
let time = DiaryId::now(String::from(diary.name()));
let hr = create
.value_of("hour")
.map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v })
.and_then(|s| {
FromStr::from_str(s)
.map_err(|_| warn!("Could not parse hour: '{}'", s))
.ok()
})
.unwrap_or(time.hour());
time.with_hour(hr).with_minute(0)
},
Some("m") | Some("minutely") => {
debug!("Creating minutely-timed entry");
let time = DiaryId::now(String::from(diary.name()));
let hr = create
.value_of("hour")
.map(|h| { debug!("hour = {:?}", h); h })
.and_then(|s| {
FromStr::from_str(s)
.map_err(|_| warn!("Could not parse hour: '{}'", s))
.ok()
})
.unwrap_or(time.hour());
let min = create
.value_of("minute")
.map(|m| { debug!("minute = {:?}", m); m })
.and_then(|s| {
FromStr::from_str(s)
.map_err(|_| warn!("Could not parse minute: '{}'", s))
.ok()
})
.unwrap_or(time.minute());
time.with_hour(hr).with_minute(min)
},
Some(_) => {
warn!("Timed creation failed: Unknown spec '{}'",
create.value_of("timed").unwrap());
exit(1);
},
None => warn_exit("Unexpected error, cannot continue", 1)
};
diary.new_entry_by_id(id)
}
}
let diary = Diary::open(rt.store(), &diaryname[..]);
let res = create_entry(&diary, rt)
.and_then(|mut entry| {
if prevent_edit {
debug!("Not editing new diary entry");
Ok(())
} else {
debug!("Editing new diary entry");
entry.edit_content(rt).map_err_into(DEK::DiaryEditError)
}
});
if let Err(e) = res { if let Err(e) = res {
trace_error(&e); trace_error_exit(&e, 1);
} else { } else {
info!("Ok!"); info!("Ok!");
} }
} }
fn create_entry<'a>(diary: &'a Store, diaryname: &str, rt: &Runtime) -> FileLockEntry<'a> {
let create = rt.cli().subcommand_matches("create").unwrap();
let entry = if !create.is_present("timed") {
debug!("Creating non-timed entry");
diary.new_entry_today(diaryname)
} else {
let id = create_id_from_clispec(&create, &diaryname);
diary.retrieve(id).map_err_into(DEK::StoreReadError)
};
match entry {
Err(e) => trace_error_exit(&e, 1),
Ok(e) => {
debug!("Created: {}", e.get_location());
e
}
}
}
fn create_id_from_clispec(create: &ArgMatches, diaryname: &str) -> DiaryId {
use std::str::FromStr;
let get_hourly_id = |create: &ArgMatches| -> DiaryId {
let time = DiaryId::now(String::from(diaryname));
let hr = create
.value_of("hour")
.map(|v| { debug!("Creating hourly entry with hour = {:?}", v); v })
.and_then(|s| {
FromStr::from_str(s)
.map_err(|_| warn!("Could not parse hour: '{}'", s))
.ok()
})
.unwrap_or(time.hour());
time.with_hour(hr)
};
match create.value_of("timed") {
Some("h") | Some("hourly") => {
debug!("Creating hourly-timed entry");
get_hourly_id(create)
},
Some("m") | Some("minutely") => {
let time = get_hourly_id(create);
let min = create
.value_of("minute")
.map(|m| { debug!("minute = {:?}", m); m })
.and_then(|s| {
FromStr::from_str(s)
.map_err(|_| warn!("Could not parse minute: '{}'", s))
.ok()
})
.unwrap_or(time.minute());
time.with_minute(min)
},
Some(_) => {
warn!("Timed creation failed: Unknown spec '{}'",
create.value_of("timed").unwrap());
exit(1);
},
None => warn_exit("Unexpected error, cannot continue", 1)
}
}

View file

@ -17,15 +17,17 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use std::process::exit;
use chrono::naive::NaiveDateTime; use chrono::naive::NaiveDateTime;
use libimagdiary::diary::Diary;
use libimagdiary::diaryid::DiaryId; use libimagdiary::diaryid::DiaryId;
use libimagrt::runtime::Runtime; use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error_exit; use libimagerror::trace::trace_error_exit;
use libimagtimeui::datetime::DateTime; use libimagtimeui::datetime::DateTime;
use libimagtimeui::parse::Parse; use libimagtimeui::parse::Parse;
use libimagutil::warn_exit::warn_exit; use libimagutil::warn_exit::warn_exit;
use libimagstore::storeid::IntoStoreId;
use util::get_diary_name; use util::get_diary_name;
@ -35,36 +37,34 @@ pub fn delete(rt: &Runtime) {
let diaryname = get_diary_name(rt) let diaryname = get_diary_name(rt)
.unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1)); .unwrap_or_else(|| warn_exit("No diary selected. Use either the configuration file or the commandline option", 1));
let diary = Diary::open(rt.store(), &diaryname[..]); let to_del_location = rt
debug!("Diary opened: {:?}", diary);
let datetime : Option<NaiveDateTime> = rt
.cli() .cli()
.subcommand_matches("delete") .subcommand_matches("delete")
.unwrap() .unwrap()
.value_of("datetime") .value_of("datetime")
.map(|dt| { debug!("DateTime = {:?}", dt); dt }) .map(|dt| { debug!("DateTime = {:?}", dt); dt })
.and_then(DateTime::parse) .and_then(DateTime::parse)
.map(|dt| dt.into()); .map(|dt| dt.into())
.ok_or_else(|| {
warn!("Not deleting entries, because missing date/time specification");
exit(1);
})
.and_then(|dt: NaiveDateTime| {
DiaryId::from_datetime(diaryname.clone(), dt)
.into_storeid()
.map(|id| rt.store().retrieve(id))
.unwrap_or_else(|e| trace_error_exit(&e, 1))
})
.unwrap_or_else(|e| trace_error_exit(&e, 1))
.get_location()
.clone();
let to_del = match datetime { if !ask_bool(&format!("Deleting {:?}", to_del_location), Some(true)) {
Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))),
None => diary.get_youngest_entry(),
};
let to_del = match to_del {
Some(Ok(e)) => e,
Some(Err(e)) => trace_error_exit(&e, 1),
None => warn_exit("No entry", 1)
};
if !ask_bool(&format!("Deleting {:?}", to_del.get_location())[..], Some(true)) {
info!("Aborting delete action"); info!("Aborting delete action");
return; return;
} }
if let Err(e) = diary.delete_entry(to_del) { if let Err(e) = rt.store().delete(to_del_location) {
trace_error_exit(&e, 1) trace_error_exit(&e, 1)
} }

View file

@ -17,6 +17,8 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use std::process::exit;
use chrono::naive::NaiveDateTime; use chrono::naive::NaiveDateTime;
use libimagdiary::diary::Diary; use libimagdiary::diary::Diary;
@ -30,33 +32,39 @@ use libimagerror::into::IntoError;
use libimagtimeui::datetime::DateTime; use libimagtimeui::datetime::DateTime;
use libimagtimeui::parse::Parse; use libimagtimeui::parse::Parse;
use libimagutil::warn_exit::warn_exit; use libimagutil::warn_exit::warn_exit;
use libimagerror::trace::trace_error_exit;
use util::get_diary_name; use util::get_diary_name;
pub fn edit(rt: &Runtime) { pub fn edit(rt: &Runtime) {
let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1)); let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1));
let diary = Diary::open(rt.store(), &diaryname[..]);
let datetime : Option<NaiveDateTime> = rt rt.cli()
.cli()
.subcommand_matches("edit") .subcommand_matches("edit")
.unwrap() .unwrap()
.value_of("datetime") .value_of("datetime")
.and_then(DateTime::parse) .and_then(DateTime::parse)
.map(|dt| dt.into()); .map(|dt| dt.into())
.map(|dt: NaiveDateTime| DiaryId::from_datetime(diaryname.clone(), dt))
let to_edit = match datetime { .or_else(|| {
Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))), rt.store()
None => diary.get_youngest_entry(), .get_youngest_entry_id(&diaryname)
}; .map(|optid| match optid {
Ok(id) => id,
match to_edit { Err(e) => trace_error_exit(&e, 1),
Some(Ok(mut e)) => e.edit_content(rt).map_err_into(DEK::IOError), })
})
Some(Err(e)) => Err(e), .ok_or_else(|| {
None => Err(DEK::EntryNotInDiary.into_error()), error!("No entries in diary. Aborting");
} exit(1)
.map_err_trace().ok(); })
.and_then(|id| rt.store().get(id))
.map(|opte| match opte {
Some(mut e) => e.edit_content(rt).map_err_into(DEK::IOError),
None => Err(DEK::EntryNotInDiary.into_error()),
})
.map_err_trace()
.ok();
} }

View file

@ -42,9 +42,7 @@ pub fn list(rt: &Runtime) {
.unwrap_or(String::from("<<Path Parsing Error>>")) .unwrap_or(String::from("<<Path Parsing Error>>"))
} }
let diary = Diary::open(rt.store(), &diaryname[..]); Diary::entries(rt.store(), &diaryname)
debug!("Diary opened: {:?}", diary);
diary.entries()
.and_then(|es| { .and_then(|es| {
debug!("Iterator for listing: {:?}", es); debug!("Iterator for listing: {:?}", es);

View file

@ -27,10 +27,9 @@ use util::get_diary_name;
pub fn view(rt: &Runtime) { pub fn view(rt: &Runtime) {
let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1)); let diaryname = get_diary_name(rt).unwrap_or_else(|| warn_exit("No diary name", 1));
let diary = Diary::open(rt.store(), &diaryname[..]);
let hdr = rt.cli().subcommand_matches("view").unwrap().is_present("show-header"); let hdr = rt.cli().subcommand_matches("view").unwrap().is_present("show-header");
diary.entries() Diary::entries(rt.store(), &diaryname)
.and_then(|entries| DV::new(hdr).view_entries(entries.into_iter().filter_map(Result::ok))) .and_then(|entries| DV::new(hdr).view_entries(entries.into_iter().filter_map(Result::ok)))
.map_err_trace() .map_err_trace()
.ok(); .ok();

View file

@ -19,110 +19,117 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use libimagerror::trace::trace_error; use libimagerror::trace::trace_error;
use chrono::offset::Local; use chrono::offset::Local;
use chrono::Datelike; use chrono::Datelike;
use itertools::Itertools; use itertools::Itertools;
use chrono::naive::NaiveDateTime; use chrono::naive::NaiveDateTime;
use chrono::Timelike;
use entry::Entry; use entry::DiaryEntry;
use diaryid::DiaryId; use diaryid::DiaryId;
use error::DiaryError as DE;
use error::DiaryErrorKind as DEK; use error::DiaryErrorKind as DEK;
use error::MapErrInto;
use result::Result; use result::Result;
use iter::DiaryEntryIterator; use iter::DiaryEntryIterator;
use is_in_diary::IsInDiary; use iter::DiaryNameIterator;
pub trait Diary {
// create or get a new entry for today
fn new_entry_today(&self, diary_name: &str) -> Result<FileLockEntry>;
// create or get a new entry for now
fn new_entry_now(&self, diary_name: &str) -> Result<FileLockEntry>;
// Get an iterator for iterating over all entries of a Diary
fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator>;
fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>>;
/// Get all diary names
fn diary_names(&self) -> Result<DiaryNameIterator>;
#[derive(Debug)]
pub struct Diary<'a> {
store: &'a Store,
name: &'a str,
} }
impl<'a> Diary<'a> { impl Diary for Store {
pub fn open(store: &'a Store, name: &'a str) -> Diary<'a> { // create or get a new entry for today
Diary { fn new_entry_today(&self, diary_name: &str) -> Result<FileLockEntry> {
store: store, let dt = Local::now();
name: name, let ndt = dt.naive_local();
} let id = DiaryId::new(String::from(diary_name), ndt.year(), ndt.month(), ndt.day(), 0, 0);
self.retrieve(id).map_err_into(DEK::StoreReadError)
} }
// create or get a new entry for today // create or get a new entry for today
pub fn new_entry_today(&self) -> Result<Entry> { fn new_entry_now(&self, diary_name: &str) -> Result<FileLockEntry> {
let dt = Local::now(); let dt = Local::now();
let ndt = dt.naive_local(); let ndt = dt.naive_local();
let id = DiaryId::new(String::from(self.name), ndt.year(), ndt.month(), ndt.day(), 0, 0); let id = DiaryId::new(String::from(diary_name),
self.new_entry_by_id(id) ndt.year(),
} ndt.month(),
ndt.day(),
ndt.minute(),
ndt.second());
pub fn new_entry_by_id(&self, id: DiaryId) -> Result<Entry> { self.retrieve(id).map_err_into(DEK::StoreReadError)
self.retrieve(id.with_diary_name(String::from(self.name)))
}
pub fn retrieve(&self, id: DiaryId) -> Result<Entry> {
id.into_storeid()
.and_then(|id| self.store.retrieve(id))
.map(|fle| Entry::new(fle))
.map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
} }
// Get an iterator for iterating over all entries // Get an iterator for iterating over all entries
pub fn entries(&self) -> Result<DiaryEntryIterator<'a>> { fn entries(&self, diary_name: &str) -> Result<DiaryEntryIterator> {
self.store self.retrieve_for_module("diary")
.retrieve_for_module("diary") .map(|iter| DiaryEntryIterator::new(self, String::from(diary_name), iter))
.map(|iter| DiaryEntryIterator::new(self.name, self.store, iter)) .map_err_into(DEK::StoreReadError)
.map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
} }
pub fn delete_entry(&self, entry: Entry) -> Result<()> { fn get_youngest_entry_id(&self, diary_name: &str) -> Option<Result<DiaryId>> {
if !entry.is_in_diary(self.name) { match Diary::entries(self, diary_name) {
return Err(DE::new(DEK::EntryNotInDiary, None));
}
let id = entry.get_location().clone();
drop(entry);
self.store.delete(id)
.map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
}
pub fn get_youngest_entry(&self) -> Option<Result<Entry>> {
match self.entries() {
Err(e) => Some(Err(e)), Err(e) => Some(Err(e)),
Ok(entries) => { Ok(entries) => {
entries.sorted_by(|a, b| { entries
match (a, b) { .map(|e| e.and_then(|e| e.diary_id()))
(&Ok(ref a), &Ok(ref b)) => { .sorted_by(|a, b| {
let a : NaiveDateTime = a.diary_id().into(); match (a, b) {
let b : NaiveDateTime = b.diary_id().into(); (&Ok(ref a), &Ok(ref b)) => {
let a : NaiveDateTime = a.clone().into();
let b : NaiveDateTime = b.clone().into();
a.cmp(&b) a.cmp(&b)
}, },
(&Ok(_), &Err(ref e)) => { (&Ok(_), &Err(ref e)) => {
trace_error(e); trace_error(e);
Ordering::Less Ordering::Less
}, },
(&Err(ref e), &Ok(_)) => { (&Err(ref e), &Ok(_)) => {
trace_error(e); trace_error(e);
Ordering::Greater Ordering::Greater
}, },
(&Err(ref e1), &Err(ref e2)) => { (&Err(ref e1), &Err(ref e2)) => {
trace_error(e1); trace_error(e1);
trace_error(e2); trace_error(e2);
Ordering::Equal Ordering::Equal
}, },
} }
}).into_iter().next() })
.into_iter()
//.map(|sidres| sidres.map(|sid| DiaryId::from_storeid(&sid)))
.next()
} }
} }
} }
pub fn name(&self) -> &'a str { /// Get all diary names
&self.name fn diary_names(&self) -> Result<DiaryNameIterator> {
self.retrieve_for_module("diary")
.map_err_into(DEK::StoreReadError)
.map(DiaryNameIterator::new)
} }
} }

View file

@ -17,74 +17,24 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
// //
use std::ops::Deref; use libimagstore::store::Entry;
use std::ops::DerefMut;
use libimagstore::store::FileLockEntry;
use libimagentryedit::edit::Edit;
use libimagentryedit::result::Result as EditResult;
use libimagrt::runtime::Runtime;
use diaryid::DiaryId; use diaryid::DiaryId;
use diaryid::FromStoreId; use diaryid::FromStoreId;
use result::Result;
#[derive(Debug)] pub trait DiaryEntry {
pub struct Entry<'a>(FileLockEntry<'a>); fn diary_id(&self) -> Result<DiaryId>;
impl<'a> Deref for Entry<'a> {
type Target = FileLockEntry<'a>;
fn deref(&self) -> &FileLockEntry<'a> {
&self.0
}
} }
impl<'a> DerefMut for Entry<'a> { impl DiaryEntry for Entry {
fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
&mut self.0
}
}
impl<'a> Entry<'a> {
pub fn new(fle: FileLockEntry<'a>) -> Entry<'a> {
Entry(fle)
}
/// Get the diary id for this entry. /// Get the diary id for this entry.
/// ///
/// TODO: calls Option::unwrap() as it assumes that an existing Entry has an ID that is parsable /// TODO: calls Option::unwrap() as it assumes that an existing Entry has an ID that is parsable
pub fn diary_id(&self) -> DiaryId { fn diary_id(&self) -> Result<DiaryId> {
DiaryId::from_storeid(&self.0.get_location().clone()).unwrap() DiaryId::from_storeid(&self.get_location().clone())
} }
} }
impl<'a> Into<FileLockEntry<'a>> for Entry<'a> {
fn into(self) -> FileLockEntry<'a> {
self.0
}
}
impl<'a> From<FileLockEntry<'a>> for Entry<'a> {
fn from(fle: FileLockEntry<'a>) -> Entry<'a> {
Entry::new(fle)
}
}
impl<'a> Edit for Entry<'a> {
fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
self.0.edit_content(rt)
}
}

View file

@ -28,7 +28,8 @@ generate_error_module!(
EntryNotInDiary => "Entry not in Diary", EntryNotInDiary => "Entry not in Diary",
IOError => "IO Error", IOError => "IO Error",
ViewError => "Error viewing diary entry", ViewError => "Error viewing diary entry",
IdParseError => "Error while parsing ID" IdParseError => "Error while parsing ID",
DiaryNameFindingError => "Error while finding a diary name"
); );
); );

View file

@ -24,6 +24,8 @@ pub trait IsInDiary {
fn is_in_diary(&self, name: &str) -> bool; fn is_in_diary(&self, name: &str) -> bool;
fn is_a_diary_entry(&self) -> bool;
} }
impl IsInDiary for Entry { impl IsInDiary for Entry {
@ -32,6 +34,10 @@ impl IsInDiary for Entry {
self.get_location().clone().is_in_diary(name) self.get_location().clone().is_in_diary(name)
} }
fn is_a_diary_entry(&self) -> bool {
self.get_location().clone().is_a_diary_entry()
}
} }
impl IsInDiary for StoreId { impl IsInDiary for StoreId {
@ -40,5 +46,9 @@ impl IsInDiary for StoreId {
self.local().starts_with(format!("diary/{}", name)) self.local().starts_with(format!("diary/{}", name))
} }
fn is_a_diary_entry(&self) -> bool {
self.local().starts_with("diary")
}
} }

View file

@ -21,21 +21,23 @@ use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult; use std::result::Result as RResult;
use libimagstore::store::Store; use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreIdIterator; use libimagstore::storeid::StoreIdIterator;
use libimagerror::trace::trace_error;
use libimagerror::into::IntoError;
use diaryid::DiaryId; use diaryid::DiaryId;
use diaryid::FromStoreId; use diaryid::FromStoreId;
use is_in_diary::IsInDiary;
use entry::Entry as DiaryEntry;
use error::DiaryError as DE; use error::DiaryError as DE;
use error::DiaryErrorKind as DEK; use error::DiaryErrorKind as DEK;
use error::MapErrInto;
use result::Result; use result::Result;
use libimagerror::trace::trace_error; use is_in_diary::IsInDiary;
/// A iterator for iterating over diary entries /// A iterator for iterating over diary entries
pub struct DiaryEntryIterator<'a> { pub struct DiaryEntryIterator<'a> {
store: &'a Store, store: &'a Store,
name: &'a str, name: String,
iter: StoreIdIterator, iter: StoreIdIterator,
year: Option<i32>, year: Option<i32>,
@ -54,7 +56,7 @@ impl<'a> Debug for DiaryEntryIterator<'a> {
impl<'a> DiaryEntryIterator<'a> { impl<'a> DiaryEntryIterator<'a> {
pub fn new(diaryname: &'a str, store: &'a Store, iter: StoreIdIterator) -> DiaryEntryIterator<'a> { pub fn new(store: &'a Store, diaryname: String, iter: StoreIdIterator) -> DiaryEntryIterator<'a> {
DiaryEntryIterator { DiaryEntryIterator {
store: store, store: store,
name: diaryname, name: diaryname,
@ -87,9 +89,9 @@ impl<'a> DiaryEntryIterator<'a> {
} }
impl<'a> Iterator for DiaryEntryIterator<'a> { impl<'a> Iterator for DiaryEntryIterator<'a> {
type Item = Result<DiaryEntry<'a>>; type Item = Result<FileLockEntry<'a>>;
fn next(&mut self) -> Option<Result<DiaryEntry<'a>>> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
let next = match self.iter.next() { let next = match self.iter.next() {
Some(s) => s, Some(s) => s,
@ -97,7 +99,7 @@ impl<'a> Iterator for DiaryEntryIterator<'a> {
}; };
debug!("Next element: {:?}", next); debug!("Next element: {:?}", next);
if next.is_in_diary(self.name) { if next.is_in_diary(&self.name) {
debug!("Seems to be in diary: {:?}", next); debug!("Seems to be in diary: {:?}", next);
let id = match DiaryId::from_storeid(&next) { let id = match DiaryId::from_storeid(&next) {
Ok(i) => i, Ok(i) => i,
@ -118,7 +120,6 @@ impl<'a> Iterator for DiaryEntryIterator<'a> {
return Some(self return Some(self
.store .store
.retrieve(next) .retrieve(next)
.map(|fle| DiaryEntry::new(fle))
.map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e)))) .map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
); );
} }
@ -130,3 +131,37 @@ impl<'a> Iterator for DiaryEntryIterator<'a> {
} }
/// Get diary names.
///
/// # Warning
///
/// Does _not_ run a `unique` on the iterator!
pub struct DiaryNameIterator(StoreIdIterator);
impl DiaryNameIterator {
pub fn new(s: StoreIdIterator) -> DiaryNameIterator {
DiaryNameIterator(s)
}
}
impl Iterator for DiaryNameIterator {
type Item = Result<String>;
fn next(&mut self) -> Option<Self::Item> {
self.0
.next()
.map(|s| {
s.to_str()
.map_err_into(DEK::DiaryNameFindingError)
.and_then(|s| {
s.split("diary/")
.nth(1)
.and_then(|n| n.split("/").nth(0).map(String::from))
.ok_or(DEK::DiaryNameFindingError.into_error())
})
})
}
}

View file

@ -19,13 +19,15 @@
//! A diary viewer built on libimagentryview. //! A diary viewer built on libimagentryview.
use entry::Entry; use entry::DiaryEntry;
use error::DiaryErrorKind as DEK; use error::DiaryErrorKind as DEK;
use error::MapErrInto; use error::MapErrInto;
use result::Result; use result::Result;
use libimagstore::store::FileLockEntry;
use libimagentryview::viewer::Viewer; use libimagentryview::viewer::Viewer;
use libimagentryview::builtin::plain::PlainViewer; use libimagentryview::builtin::plain::PlainViewer;
use libimagerror::trace::trace_error;
/// This viewer does _not_ implement libimagentryview::viewer::Viewer because we need to be able to /// This viewer does _not_ implement libimagentryview::viewer::Viewer because we need to be able to
/// call some diary-type specific functions on the entries passed to this. /// call some diary-type specific functions on the entries passed to this.
@ -46,10 +48,12 @@ impl DiaryViewer {
/// View all entries from the iterator, or stop immediately if an error occurs, returning that /// View all entries from the iterator, or stop immediately if an error occurs, returning that
/// error. /// error.
pub fn view_entries<'a, I: Iterator<Item = Entry<'a>>>(&self, entries: I) -> Result<()> { pub fn view_entries<'a, I: Iterator<Item = FileLockEntry<'a>>>(&self, entries: I) -> Result<()> {
for entry in entries { for entry in entries {
let id = entry.diary_id(); match entry.diary_id() {
println!("{} :\n", id); Ok(id) => println!("{} :\n", id),
Err(e) => trace_error(&e),
}
let _ = try!(self.0 let _ = try!(self.0
.view_entry(&entry) .view_entry(&entry)
.map_err_into(DEK::ViewError) .map_err_into(DEK::ViewError)