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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use super::*;

use std::{
    fmt::Debug,
    fs::File,
    io::{BufReader, BufWriter},
};

pub trait InputOutput: Input + Output {}
pub trait Input: Debug {
    fn reader<'a>(&'a mut self) -> io::Result<&'a mut dyn io::Read>;
}
pub trait Output: Debug {
    fn writer<'a>(&'a mut self) -> io::Result<&'a mut dyn io::Write>;
    fn extension<'a>(&'a self) -> Option<&'a OsStr> {
        None
    }

    /// Take effects before [`Output::get_writer`].
    #[allow(unused_variables)]
    fn set_file_name(&mut self, file_name: &OsStr) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Unsupported, "unsupported"))
    }

    /// Remove only if the DST file is empty. `bool` here indicates whether the file is empty.
    fn remove_dst(&mut self) -> io::Result<bool> {
        Err(io::Error::new(io::ErrorKind::Unsupported, "unsupported"))
    }
    /// **Anyway** remove the DST file.
    fn remove_dst_anyway(&mut self) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Unsupported, "unsupported"))
    }
}

/// Just a simple wrapper.
#[derive(Debug)]
pub struct ClarifiedIo {
    i: Box<dyn Input>,
    o: Box<dyn Output>,
}
impl ClarifiedIo {
    pub fn new<I, O>(i: I, o: O) -> Self
    where
        I: 'static + Input,
        O: 'static + Output,
    {
        Self {
            i: Box::new(i),
            o: Box::new(o),
        }
    }

    pub fn with_input<I: 'static + Input>(&mut self, i: I) {
        self.i = Box::new(i);
    }
    pub fn with_output<O: 'static + Output>(&mut self, o: O) {
        self.o = Box::new(o);
    }
}
impl InputOutput for ClarifiedIo {}
impl Input for ClarifiedIo {
    fn reader<'a>(&'a mut self) -> io::Result<&'a mut dyn io::Read> {
        self.i.reader()
    }
}
impl Output for ClarifiedIo {
    fn writer<'a>(&'a mut self) -> io::Result<&'a mut dyn io::Write> {
        self.o.writer()
    }
    fn extension<'a>(&'a self) -> Option<&'a OsStr> {
        self.o.extension()
    }
    fn set_file_name(&mut self, file_name: &OsStr) -> io::Result<()> {
        self.o.set_file_name(file_name)
    }
    fn remove_dst(&mut self) -> io::Result<bool> {
        self.o.remove_dst()
    }
    fn remove_dst_anyway(&mut self) -> io::Result<()> {
        self.o.remove_dst_anyway()
    }
}

#[derive(Debug)]
pub struct ReadFile {
    src: PathBuf,
    reader: Option<BufReader<File>>,
}
impl ReadFile {
    pub fn new<P: AsRef<Path>>(src: P) -> Self {
        Self {
            src: src.as_ref().to_owned(),
            reader: None,
        }
    }
}
impl Input for ReadFile {
    fn reader<'a>(&'a mut self) -> io::Result<&'a mut dyn io::Read> {
        if self.reader.is_none() {
            self.reader = Some(BufReader::new(File::open(&self.src)?));
        }
        Ok(self.reader.as_mut().unwrap())
    }
}

#[derive(Debug)]
pub struct WriteFile {
    dst: PathBuf,
    writer: Option<BufWriter<File>>,
}
impl WriteFile {
    pub fn new<P: AsRef<Path>>(dst: P) -> Self {
        Self {
            dst: dst.as_ref().to_owned(),
            writer: None,
        }
    }
}
impl Output for WriteFile {
    fn writer<'a>(&'a mut self) -> io::Result<&'a mut dyn io::Write> {
        if self.writer.is_none() {
            self.writer = Some(BufWriter::new(File::create(&self.dst)?));
        }
        Ok(self.writer.as_mut().unwrap())
    }
    fn extension<'a>(&'a self) -> Option<&'a OsStr> {
        Some(match self.dst.extension() {
            Some(ext) => ext,
            None => OsStr::new(""),
        })
    }

    fn set_file_name(&mut self, file_name: &OsStr) -> io::Result<()> {
        Ok(self.dst.set_file_name(file_name))
    }

    fn remove_dst(&mut self) -> io::Result<bool> {
        match self.dst.metadata()?.len() == 0 {
            true => self.remove_dst_anyway().and(Ok(true)),
            false => Ok(false),
        }
    }
    fn remove_dst_anyway(&mut self) -> io::Result<()> {
        drop(self.writer.take());
        fs::remove_file(&self.dst)
    }
}

#[derive(Debug)]
pub struct ReadStdin(io::Stdin);
impl ReadStdin {
    pub fn new() -> Self {
        Self(io::stdin())
    }
}
impl Input for ReadStdin {
    fn reader<'a>(&'a mut self) -> io::Result<&'a mut dyn io::Read> {
        Ok(&mut self.0)
    }
}

#[derive(Debug)]
pub struct WriteStdout(io::Stdout);
impl WriteStdout {
    pub fn new() -> Self {
        Self(io::stdout())
    }
}
impl Output for WriteStdout {
    fn writer<'a>(&'a mut self) -> io::Result<&'a mut dyn io::Write> {
        Ok(&mut self.0)
    }
}