1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//! Every repository acts as a container for items

use serde_json::{Map, Value};

use super::Reducer;
use record::{File, OrderedFiles};

#[derive(Debug, Error)]
pub enum ReductionError<Err: ::std::error::Error + ::std::fmt::Debug> {
    ImplementationError(Err)
}

/// Because of SIT's extensible nature, item can
/// be used to represent a wild variety of entities, such
/// as issue, documents, accounts, etc.
pub trait Item: Sized {
    /// Error type used by the implementation
    type Error: ::std::error::Error + ::std::fmt::Debug;
    /// Record type used by the implementation
    type Record : super::Record;
    /// Type used to list records that can be referenced as a slice of records
    type Records : IntoIterator<Item=Self::Record>;
    /// Iterator over lists of records
    type RecordIter : Iterator<Item=Self::Records>;
    /// Issue must have an ID, ideally human-readable
    fn id(&self) -> &str;
    /// Iterates through the tree of records
    fn record_iter(&self) -> Result<Self::RecordIter, Self::Error>;
    /// Creates and returns a new record.
    ///
    /// Will reference all dangling records as its parent, unless
    /// `link_parents` is set to `false`
    fn new_record<'f, F: File + 'f, I: Into<OrderedFiles<'f, F>>>(&self, files: I, link_parents: bool)
       -> Result<Self::Record, Self::Error> where F::Read: 'f;
}

/// [`Issue`] trait extension that defines and implements default reduction algorithms
///
/// [`Issue`]: trait.Issue.html
pub trait ItemReduction: Item {

    /// Reduces item with a given [`Reducer`]
    ///
    /// Will insert item's `id` into the initial state
    ///
    /// [`Reducer`]: ../reducers/trait.Reducer.html
    fn reduce_with_reducer<R: Reducer<State=Map<String, Value>, Item=Self::Record>>(&self, reducer: &mut R) -> Result<Map<String, Value>, ReductionError<Self::Error>> {
        let records = self.record_iter()?;
        let mut state: Map<String, Value> = Default::default();
        state.insert("id".into(), Value::String(self.id().into()));
        Ok(records.fold(state, |acc, recs|
            recs.into_iter().fold(acc, |acc, rec| reducer.reduce(acc, &rec))))
    }


}

impl<T> ItemReduction for T where T: Item {}