jsrmx/
output.rs

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}