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
pub struct FmtWrite<W: std::fmt::Write>(pub W);
pub struct IoWrite<W: std::io::Write>(pub W);
pub trait Writable {
    type Fmt: std::fmt::Write;
    type IO: std::io::Write;
    fn as_fmt(&mut self) -> Option<&mut Self::Fmt>;
    fn as_io(&mut self) -> Option<&mut Self::IO>;
}

impl<W: std::fmt::Write> Writable for FmtWrite<W> {
    type Fmt = W;
    type IO = std::io::Stdout;
    fn as_fmt(&mut self) -> Option<&mut Self::Fmt> {
        Some(&mut self.0)
    }
    fn as_io(&mut self) -> Option<&mut Self::IO> {
        None
    }
}

impl<W: std::io::Write> Writable for IoWrite<W> {
    type Fmt = String;
    type IO = W;
    fn as_fmt(&mut self) -> Option<&mut Self::Fmt> {
        None
    }
    fn as_io(&mut self) -> Option<&mut Self::IO> {
        Some(&mut self.0)
    }
}

macro_rules! write_writable {
    ($dst:expr, $($arg:tt)*) => {{
        use $crate::error::Error;
        use std::io::Write as IOWrite;
        use std::fmt::Write as FmtWrite;
        if let Some(w) = $dst.as_fmt() {
            write!(w, $($arg)*).map_err(|e| Into::<Error>::into(e))
        } else if let Some(w) = $dst.as_io() {
            write!(w, $($arg)*).map_err(|e| Into::<Error>::into(e))
        } else {
            panic!()
        }
    }};
}
pub(crate) use write_writable;

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_writable() {
        let mut s = String::new();
        let mut w = FmtWrite(&mut s);
        write_writable!(w, "{}", 123).unwrap();
        assert_eq!("123", s);

        let mut stdout = std::io::stdout().lock();
        let mut w = IoWrite(&mut stdout);
        write_writable!(w, "{}", 123).unwrap();
    }
}