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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use crate::formats::EbookResult;

/// Retrieve simple statistical information, such as the character
/// or word count of an ebook.
///
/// # Examples
/// Counting from an epub:
/// ```
/// use rbook::{Ebook, Stats};
///
/// let epub = rbook::Epub::new("tests/ebooks/moby-dick.epub").unwrap();
/// let file_content = epub.read_bytes_file("chapter_022.xhtml").unwrap();
/// let word_count = epub.count_words(&file_content).unwrap();
///
/// assert_eq!(1683, word_count);
/// ```
/// Counting total characters:
/// ```
/// use rbook::{Ebook, Stats};
///
/// let epub = rbook::Epub::new("tests/ebooks/childrens-literature.epub").unwrap();
/// let char_count = epub.try_count_total_chars().unwrap();
///
/// assert_eq!(329289, char_count);
/// ```
pub trait Stats {
    /// Iterate through all resource elements and perform a function.
    ///
    /// Resource elements that fail to be retrieved will be skipped and
    /// the next one will be retrieved and so on.
    ///
    /// To view and handle errors, [try_count_total(...)](Self::try_count_total) can be
    /// used instead.
    fn count_total<F>(&self, f: F) -> usize
    where
        F: Fn(&[u8]) -> EbookResult<usize>;

    /// Iterate through all resource elements and perform a function.
    fn try_count_total<F>(&self, f: F) -> EbookResult<usize>
    where
        F: Fn(&[u8]) -> EbookResult<usize>;

    /// Calculate the count of all characters from a given collection
    /// of bytes.
    fn count_chars(&self, data: &[u8]) -> EbookResult<usize>;

    /// Calculate the count of all characters from a given collection
    /// of bytes.
    fn count_words(&self, data: &[u8]) -> EbookResult<usize>;

    /// Calculate the count of all characters in the ebook file.
    ///
    /// If retrieving a page fails, the next will be retrieved
    /// instead and so on.
    ///
    /// To view and handle errors,
    /// [try_count_total_chars(...)](Self::try_count_total_chars)
    /// can be used instead.
    fn count_total_chars(&self) -> usize {
        self.count_total(|data| self.count_chars(data))
    }

    /// Calculate the count of all characters in the ebook file and
    /// handle errors if any.
    ///
    /// To ignore errors, [count_total_chars()](Self::count_total_chars)
    /// can be used instead.
    fn try_count_total_chars(&self) -> EbookResult<usize> {
        self.try_count_total(|data| self.count_chars(data))
    }

    /// Calculate the count of all words in the ebook file. Any
    /// errors are skipped
    ///
    /// If retrieving a page fails, the next will be retrieved
    /// instead and so on.
    ///
    /// To view and handle errors,
    /// [try_count_total_words(...)](Self::try_count_total_words)
    /// can be used instead.
    fn count_total_words(&self) -> usize {
        self.count_total(|data| self.count_words(data))
    }

    /// Calculate the count of all words in the ebook file and
    /// handle errors if any.
    ///
    /// To ignore errors, [count_total_words()](Self::count_total_words)
    /// can be used instead.
    fn try_count_total_words(&self) -> EbookResult<usize> {
        self.try_count_total(|data| self.count_words(data))
    }
}