Merge pull request #916 from matthiasbeyer/superceed-898
Simplify FoldResult implementation
This commit is contained in:
commit
9396accc28
7 changed files with 49 additions and 28 deletions
|
@ -46,7 +46,7 @@ impl<'a> Lister for LineLister<'a> {
|
||||||
use error::ListError as LE;
|
use error::ListError as LE;
|
||||||
use error::ListErrorKind as LEK;
|
use error::ListErrorKind as LEK;
|
||||||
|
|
||||||
entries.fold_defresult(|entry| {
|
entries.fold_result(|entry| {
|
||||||
let s = entry.get_location().to_str().unwrap_or(String::from(self.unknown_output));
|
let s = entry.get_location().to_str().unwrap_or(String::from(self.unknown_output));
|
||||||
write!(stdout(), "{:?}\n", s).map_err(|e| LE::new(LEK::FormatError, Some(Box::new(e))))
|
write!(stdout(), "{:?}\n", s).map_err(|e| LE::new(LEK::FormatError, Some(Box::new(e))))
|
||||||
})
|
})
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl Lister for PathLister {
|
||||||
use error::ListError as LE;
|
use error::ListError as LE;
|
||||||
use error::ListErrorKind as LEK;
|
use error::ListErrorKind as LEK;
|
||||||
|
|
||||||
entries.fold_defresult(|entry| {
|
entries.fold_result(|entry| {
|
||||||
Ok(entry.get_location().clone())
|
Ok(entry.get_location().clone())
|
||||||
.and_then(|pb| pb.into_pathbuf().map_err_into(LEK::FormatError))
|
.and_then(|pb| pb.into_pathbuf().map_err_into(LEK::FormatError))
|
||||||
.and_then(|pb| {
|
.and_then(|pb| {
|
||||||
|
|
|
@ -147,7 +147,7 @@ impl Configuration {
|
||||||
None => Err(CEK::ConfigOverrideKeyNotAvailable.into_error()),
|
None => Err(CEK::ConfigOverrideKeyNotAvailable.into_error()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fold_defresult(|i| i)
|
.fold_result(|i| i)
|
||||||
.map_err(Box::new)
|
.map_err(Box::new)
|
||||||
.map_err(|e| CEK::ConfigOverrideError.into_error_with_cause(e))
|
.map_err(|e| CEK::ConfigOverrideError.into_error_with_cause(e))
|
||||||
}
|
}
|
||||||
|
@ -274,4 +274,3 @@ fn fetch_config(rtp: &PathBuf) -> Result<Value> {
|
||||||
.map(|inner| Value::Table(inner.unwrap()))
|
.map(|inner| Value::Table(inner.unwrap()))
|
||||||
.ok_or(ConfigErrorKind::NoConfigFileFound.into())
|
.ok_or(ConfigErrorKind::NoConfigFileFound.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ pub fn config_is_valid(config: &Option<Value>) -> Result<()> {
|
||||||
})
|
})
|
||||||
.and_then(|t| match *t {
|
.and_then(|t| match *t {
|
||||||
Value::Array(ref a) => {
|
Value::Array(ref a) => {
|
||||||
a.iter().fold_defresult(|elem| if is_match!(*elem, Value::String(_)) {
|
a.iter().fold_result(|elem| if is_match!(*elem, Value::String(_)) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let cause = Box::new(kind.into_error());
|
let cause = Box::new(kind.into_error());
|
||||||
|
@ -122,7 +122,7 @@ pub fn config_is_valid(config: &Option<Value>) -> Result<()> {
|
||||||
})
|
})
|
||||||
.and_then(|section_table| match *section_table { // which is
|
.and_then(|section_table| match *section_table { // which is
|
||||||
Value::Table(ref section_table) => // a table
|
Value::Table(ref section_table) => // a table
|
||||||
section_table.iter().fold_defresult(|(inner_key, cfg)| {
|
section_table.iter().fold_result(|(inner_key, cfg)| {
|
||||||
match *cfg {
|
match *cfg {
|
||||||
Value::Table(ref hook_config) => { // are tables
|
Value::Table(ref hook_config) => { // are tables
|
||||||
// with a key
|
// with a key
|
||||||
|
|
|
@ -73,7 +73,7 @@ impl StoreIdAccessor for Aspect {
|
||||||
return Err(HE::new(HEK::AccessTypeViolation, None));
|
return Err(HE::new(HEK::AccessTypeViolation, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
accessors.iter().fold_defresult(|accessor| {
|
accessors.iter().fold_result(|accessor| {
|
||||||
let res = match accessor {
|
let res = match accessor {
|
||||||
&HDA::StoreIdAccess(accessor) => accessor.access(id),
|
&HDA::StoreIdAccess(accessor) => accessor.access(id),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -94,7 +94,7 @@ impl MutableHookDataAccessor for Aspect {
|
||||||
// More sophisticated version would check whether there are _chunks_ of
|
// More sophisticated version would check whether there are _chunks_ of
|
||||||
// NonMutableAccess accessors and execute these chunks in parallel. We do not have
|
// NonMutableAccess accessors and execute these chunks in parallel. We do not have
|
||||||
// performance concerns yet, so this is okay.
|
// performance concerns yet, so this is okay.
|
||||||
accessors.iter().fold_defresult(|accessor| {
|
accessors.iter().fold_result(|accessor| {
|
||||||
let res = match accessor {
|
let res = match accessor {
|
||||||
&HDA::StoreIdAccess(ref accessor) => accessor.access(fle.get_location()),
|
&HDA::StoreIdAccess(ref accessor) => accessor.access(fle.get_location()),
|
||||||
&HDA::NonMutableAccess(ref accessor) => accessor.access(fle),
|
&HDA::NonMutableAccess(ref accessor) => accessor.access(fle),
|
||||||
|
@ -127,7 +127,7 @@ impl NonMutableHookDataAccessor for Aspect {
|
||||||
return Err(HE::new(HEK::AccessTypeViolation, None));
|
return Err(HE::new(HEK::AccessTypeViolation, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
accessors.iter().fold_defresult(|accessor| {
|
accessors.iter().fold_result(|accessor| {
|
||||||
let res = match accessor {
|
let res = match accessor {
|
||||||
&HDA::NonMutableAccess(accessor) => accessor.access(fle),
|
&HDA::NonMutableAccess(accessor) => accessor.access(fle),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
|
@ -1003,7 +1003,7 @@ impl Store {
|
||||||
match aspects.lock() {
|
match aspects.lock() {
|
||||||
Err(_) => return Err(HookErrorKind::HookExecutionError.into()),
|
Err(_) => return Err(HookErrorKind::HookExecutionError.into()),
|
||||||
Ok(g) => g
|
Ok(g) => g
|
||||||
}.iter().fold_defresult(|aspect| {
|
}.iter().fold_result(|aspect| {
|
||||||
debug!("[Aspect][exec]: {:?}", aspect);
|
debug!("[Aspect][exec]: {:?}", aspect);
|
||||||
(aspect as &StoreIdAccessor).access(id)
|
(aspect as &StoreIdAccessor).access(id)
|
||||||
}).map_err(Box::new)
|
}).map_err(Box::new)
|
||||||
|
@ -1025,7 +1025,7 @@ impl Store {
|
||||||
match aspects.lock() {
|
match aspects.lock() {
|
||||||
Err(_) => return Err(HookErrorKind::HookExecutionError.into()),
|
Err(_) => return Err(HookErrorKind::HookExecutionError.into()),
|
||||||
Ok(g) => g
|
Ok(g) => g
|
||||||
}.iter().fold_defresult(|aspect| {
|
}.iter().fold_result(|aspect| {
|
||||||
debug!("[Aspect][exec]: {:?}", aspect);
|
debug!("[Aspect][exec]: {:?}", aspect);
|
||||||
aspect.access_mut(fle)
|
aspect.access_mut(fle)
|
||||||
}).map_err(Box::new)
|
}).map_err(Box::new)
|
||||||
|
@ -2248,4 +2248,3 @@ aspect = "test"
|
||||||
assert!(store.update(&mut fle).is_ok());
|
assert!(store.update(&mut fle).is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
// imag - the personal information management suite for the commandline
|
||||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||||
//
|
//
|
||||||
|
@ -21,29 +20,53 @@
|
||||||
pub trait FoldResult: Sized {
|
pub trait FoldResult: Sized {
|
||||||
type Item;
|
type Item;
|
||||||
|
|
||||||
/// Processes all contained items returning the last successful result or the first error.
|
/// Apply a `FnMut(Self::Item) -> Result<R, E>` to each item. If each
|
||||||
/// If there are no items, returns `Ok(R::default())`.
|
/// application returns an `Ok(_)`, return `Ok(())`, indicating success.
|
||||||
fn fold_defresult<R, E, F>(self, func: F) -> Result<R, E>
|
/// Otherwise return the first error.
|
||||||
where R: Default,
|
///
|
||||||
F: FnMut(Self::Item)
|
/// The return type of this function only indicates success with the
|
||||||
-> Result<R, E>
|
/// `Ok(())` idiom. To retrieve the values of your application, include an
|
||||||
{
|
/// accumulator in `func`. This is the intended reason for the permissive
|
||||||
self.fold_result(R::default(), func)
|
/// `FnMut` type.
|
||||||
}
|
fn fold_result<R, E, F>(self, mut func: F) -> Result<(), E>
|
||||||
|
|
||||||
/// Processes all contained items returning the last successful result or the first error.
|
|
||||||
/// If there are no items, returns `Ok(default)`.
|
|
||||||
fn fold_result<R, E, F>(self, default: R, mut func: F) -> Result<R, E>
|
|
||||||
where F: FnMut(Self::Item) -> Result<R, E>;
|
where F: FnMut(Self::Item) -> Result<R, E>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<X, I: Iterator<Item = X>> FoldResult for I {
|
impl<X, I: Iterator<Item = X>> FoldResult for I {
|
||||||
type Item = X;
|
type Item = X;
|
||||||
|
|
||||||
fn fold_result<R, E, F>(self, default: R, mut func: F) -> Result<R, E>
|
fn fold_result<R, E, F>(self, mut func: F) -> Result<(), E>
|
||||||
where F: FnMut(Self::Item) -> Result<R, E>
|
where F: FnMut(Self::Item) -> Result<R, E>
|
||||||
{
|
{
|
||||||
self.fold(Ok(default), |acc, item| acc.and_then(|_| func(item)))
|
for item in self {
|
||||||
|
try!(func(item));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fold_result_success() {
|
||||||
|
let v = vec![1, 2, 3];
|
||||||
|
let mut accum = vec![];
|
||||||
|
let result: Result<(), &str> = v.iter().fold_result(|item| {
|
||||||
|
accum.push(*item * 2);
|
||||||
|
Ok(*item)
|
||||||
|
});
|
||||||
|
assert_eq!(result, Ok(()));
|
||||||
|
assert_eq!(accum, vec![2, 4, 6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fold_result_failure() {
|
||||||
|
let v: Vec<usize> = vec![1, 2, 3];
|
||||||
|
let mut accum: Vec<usize> = vec![];
|
||||||
|
let result: Result<(), &str> = v.iter().fold_result(|item| if *item == 2 {
|
||||||
|
Err("failure")
|
||||||
|
} else {
|
||||||
|
accum.push(*item * 2);
|
||||||
|
Ok(*item)
|
||||||
|
});
|
||||||
|
assert_eq!(result, Err("failure"));
|
||||||
|
assert_eq!(accum, vec![2]);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue