1mod directory;
2mod file;
3mod stream;
4use directory::DirectoryOutput;
5use file::FileOutput;
6use stream::StreamOutput;
7
8use serde::Serialize;
9use serde_json::Value;
10use std::path::{Path, PathBuf};
11
12trait Writeable {
13 fn append<T: Serialize>(&self, content: T) -> std::io::Result<()>;
14 fn set_pretty(&mut self, pretty: bool);
15 fn write<T: Serialize>(&self, content: T) -> std::io::Result<()>;
16 fn write_entries(&self, entries: Vec<(String, Value)>) -> std::io::Result<()>;
17}
18
19#[derive(Clone, Debug)]
20pub enum Output {
21 Directory(DirectoryOutput),
22 File(FileOutput),
23 Stdout(StreamOutput),
24}
25
26impl Output {
27 pub fn append<T: Serialize>(&self, content: T) -> std::io::Result<()> {
28 match self {
29 Self::Directory(output) => output.append(content),
30 Self::File(output) => output.append(content),
31 Self::Stdout(output) => output.append(content),
32 }
33 }
34
35 pub fn write<T: Serialize>(&self, content: T) -> std::io::Result<()> {
36 match self {
37 Self::Directory(output) => output.write(content),
38 Self::File(output) => output.write(content),
39 Self::Stdout(output) => output.write(content),
40 }
41 }
42
43 pub fn set_pretty(&mut self) {
44 match self {
45 Self::Directory(output) => output.set_pretty(true),
46 Self::File(output) => output.set_pretty(true),
47 Self::Stdout(output) => output.set_pretty(true),
48 }
49 }
50
51 pub fn write_entries(&self, entries: Vec<(String, Value)>) -> std::io::Result<()> {
52 match self {
53 Self::Directory(output) => output.write_entries(entries),
54 Self::File(output) => output.write_entries(entries),
55 Self::Stdout(output) => output.write_entries(entries),
56 }
57 }
58}
59
60impl AsRef<Path> for Output {
61 fn as_ref(&self) -> &Path {
62 match self {
63 Output::Directory(output) => output.path.as_path(),
64 Output::File(output) => output.path.as_path(),
65 Output::Stdout(_) => Path::new("-"),
66 }
67 }
68}
69
70impl std::fmt::Display for Output {
71 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
72 match self {
73 Output::Directory(output) => write!(f, "{}", output.path.display()),
74 Output::File(output) => write!(f, "{}", output.path.display()),
75 Output::Stdout(_) => write!(f, "-"),
76 }
77 }
78}
79
80impl std::str::FromStr for Output {
81 type Err = String;
82
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 if s == "-" {
85 return Ok(Output::Stdout(StreamOutput::new(false)));
86 }
87
88 let path = PathBuf::from(s);
89 if path.is_dir() {
90 Ok(Output::Directory(DirectoryOutput::new(path, false)))
91 } else if path.extension().is_none() {
92 Ok(Output::Directory(DirectoryOutput::new(path, false)))
93 } else if path.is_file() {
94 Ok(Output::File(FileOutput::new(path, false)))
95 } else {
96 log::info!("Creating file: {}", &path.display());
97 Ok(Output::File(FileOutput::new(path, false)))
98 }
99 }
100}