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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::collections::HashMap;
use std::ops::AddAssign;

#[derive(Debug, Default)]
struct Count {
    accessed_bytes: u64,
    modified_bytes: u64,
    accessed_files: u64,
    modified_files: u64,
}

impl AddAssign for Count {
    fn add_assign(&mut self, other: Self) {
        *self = Self {
            accessed_bytes: self.accessed_bytes + other.accessed_bytes,
            modified_bytes: self.modified_bytes + other.modified_bytes,
            accessed_files: self.accessed_files + other.accessed_files,
            modified_files: self.modified_files + other.modified_files,
        }
    }
}

#[derive(Debug, Default)]
pub struct Data {
    total_bytes: u64,
    total_files: u64,
    data: HashMap<u64, Count>,
}

impl Data {
    #[must_use]
    pub fn with_ages(mut self, ages: &[u64]) -> Self {
        for age in ages {
            self.insert(*age, 0, 0, 0, 0);
        }

        self
    }

    #[must_use]
    pub const fn with_total_bytes(mut self, bytes: u64) -> Self {
        self.total_bytes = bytes;
        self
    }

    #[must_use]
    pub const fn with_total_files(mut self, files: u64) -> Self {
        self.total_files = files;
        self
    }

    #[must_use]
    pub fn get_accessed_bytes(&self, age: u64) -> Option<u64> {
        self.data.get(&age).map(|data| data.accessed_bytes)
    }

    #[must_use]
    pub fn get_modified_bytes(&self, age: u64) -> Option<u64> {
        self.data.get(&age).map(|data| data.modified_bytes)
    }

    #[must_use]
    pub fn get_accessed_files(&self, age: u64) -> Option<u64> {
        self.data.get(&age).map(|data| data.accessed_files)
    }

    #[must_use]
    pub fn get_modified_files(&self, age: u64) -> Option<u64> {
        self.data.get(&age).map(|data| data.modified_files)
    }

    #[must_use]
    pub const fn get_total_bytes(&self) -> u64 {
        self.total_bytes
    }

    #[must_use]
    pub const fn get_total_files(&self) -> u64 {
        self.total_files
    }

    #[must_use]
    pub fn get_ages(&self) -> Vec<&u64> {
        let mut ages: Vec<&u64> = self.data.keys().collect();
        ages.sort();
        ages
    }

    pub fn insert(
        &mut self,
        age: u64,
        accessed_bytes: u64,
        modified_bytes: u64,
        accessed_files: u64,
        modified_files: u64,
    ) {
        let a = Count {
            accessed_bytes,
            modified_bytes,
            accessed_files,
            modified_files,
        };

        self.data.insert(age, a);
    }
}

impl AddAssign for Data {
    fn add_assign(&mut self, other: Self) {
        self.total_bytes += other.total_bytes;
        self.total_files += other.total_files;

        for (age, acc) in other.data {
            let sum = self.data.entry(age).or_default();
            *sum += acc;
        }
    }
}