Skip to main content

over_there/cli/
format.rs

1use crate::core::Content;
2use serde::Serialize;
3use strum_macros::{AsRefStr, EnumString, EnumVariantNames};
4
5pub type FormatResult = Result<String, Box<dyn std::error::Error>>;
6
7#[derive(
8    Copy, Clone, Debug, PartialEq, Eq, EnumString, EnumVariantNames, AsRefStr,
9)]
10#[strum(serialize_all = "snake_case")]
11pub enum FormatOption {
12    /// Human-readable format for input and output
13    Human,
14
15    /// JSON format for input and output
16    Json,
17
18    #[cfg(feature = "format-sexpression")]
19    /// S-Expression format for input and output
20    Sexpression,
21}
22
23/// Tries to convert provided text with the specified format to content
24pub fn text_to_content(
25    format_option: FormatOption,
26    text: &str,
27) -> Result<Content, Box<dyn std::error::Error>> {
28    match format_option {
29        FormatOption::Json => Ok(serde_json::from_str(text)?),
30
31        #[cfg(feature = "format-sexpression")]
32        FormatOption::Sexpression => Ok(serde_lexpr::from_str(&text)?),
33
34        FormatOption::Human => Err("Cannot convert to human format".into()),
35    }
36}
37
38/// Creates a `String` using the given `format_option` and `serializable_data`,
39/// falling back to the `fallback` function to render human-readable text.
40pub fn format<T, F>(
41    format_option: FormatOption,
42    serializable_data: T,
43    fallback: F,
44) -> FormatResult
45where
46    T: Serialize,
47    F: FnOnce(T) -> FormatResult,
48{
49    let text = match format_option {
50        FormatOption::Json => serde_json::to_string(&serializable_data)?,
51
52        #[cfg(feature = "format-sexpression")]
53        FormatOption::Sexpression => {
54            serde_lexpr::to_string(&serializable_data)?
55        }
56
57        FormatOption::Human => fallback(serializable_data)?,
58    };
59
60    Ok(text)
61}
62
63/// Creates a `String` using the given `format_option` and `content`,
64/// falling back to the `fallback` function to render human-readable text.
65pub fn format_content<F>(
66    format_option: FormatOption,
67    content: Content,
68    fallback: F,
69) -> FormatResult
70where
71    F: FnOnce(Content) -> FormatResult,
72{
73    format(format_option, content, fallback)
74}
75
76/// Formats `serializeable_data` using the given `format_option`, falling back
77/// to the `fallback` function to render human-readable text, and prints to
78/// stdout with a newline.
79pub fn format_println<T, F>(
80    format_option: FormatOption,
81    serializeable_data: T,
82    fallback: F,
83) -> Result<(), Box<dyn std::error::Error>>
84where
85    T: Serialize,
86    F: FnOnce(T) -> FormatResult,
87{
88    let text = format(format_option, serializeable_data, fallback)?;
89
90    println!("{}", text);
91
92    Ok(())
93}
94
95/// Formats `content` using the given `format_option`, falling back
96/// to the `fallback` function to render human-readable text, and prints to
97/// stdout with a newline.
98pub fn format_content_println<F>(
99    format_option: FormatOption,
100    content: Content,
101    fallback: F,
102) -> Result<(), Box<dyn std::error::Error>>
103where
104    F: FnOnce(Content) -> FormatResult,
105{
106    format_println(format_option, content, fallback)
107}