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
use anyhow::Result;
use chrono::prelude::*;
use std::path::PathBuf;

pub trait FileTree {
    fn basepath_fileprefix(&mut self, file_suffix: &str) -> Result<(PathBuf, PathBuf)>;
}

pub struct DateTimeDirTree<'a> {
    basepath_fmt: &'a str,
    filename_prefix_fmt: &'a str,
    timestamp: Option<DateTime<Local>>,
}

impl<'a> DateTimeDirTree<'a> {
    pub fn new(basepath_fmt: &'a str, filename_prefix_fmt: &'a str) -> Self {
        Self {
            basepath_fmt,
            filename_prefix_fmt,
            timestamp: None,
        }
    }

    pub fn set_timestamp(&mut self, ts: DateTime<Local>) {
        self.timestamp = Some(ts);
    }
}

impl<'a> Default for DateTimeDirTree<'a> {
    fn default() -> Self {
        Self {
            basepath_fmt: "%Y/%m/%d/%H/",
            filename_prefix_fmt: "%Y-%m-%d_%H-%M-%S-%3f_",
            timestamp: None,
        }
    }
}

impl<'a> FileTree for DateTimeDirTree<'a> {
    fn basepath_fileprefix(&mut self, file_suffix: &str) -> Result<(PathBuf, PathBuf)> {
        let now = self.timestamp.unwrap_or_else(Local::now);
        let basepath = now.format(self.basepath_fmt).to_string();
        let filename = now.format(self.filename_prefix_fmt).to_string() + file_suffix;
        Ok((basepath.into(), filename.into()))
    }
}

#[derive(Default)]
pub struct CountingTree {
    dir_counter: usize,
    file_counter: usize,
    max_in_dir: usize,
    pub id: String,
}

impl CountingTree {
    pub fn new(max_in_dir: usize) -> Self {
        CountingTree {
            max_in_dir,
            ..Default::default()
        }
    }
}

impl FileTree for CountingTree {
    fn basepath_fileprefix(&mut self, file_suffix: &str) -> Result<(PathBuf, PathBuf)> {
        let basepath: PathBuf = [self.id.clone(), self.dir_counter.to_string()]
            .iter()
            .collect();
        let filename = self.file_counter.to_string() + file_suffix;

        if self.file_counter + 1 > self.max_in_dir {
            self.file_counter = 0;
            self.dir_counter += 1;
        } else {
            self.file_counter += 1;
        }

        Ok((basepath, filename.into()))
    }
}