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