agent_first_data/
output.rs1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::str::FromStr;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "lowercase")]
8pub enum OutputFormat {
9 Json,
10 Yaml,
12 Plain,
13}
14
15impl OutputFormat {
16 pub const fn as_str(self) -> &'static str {
18 match self {
19 Self::Json => "json",
20 Self::Yaml => "yaml",
21 Self::Plain => "plain",
22 }
23 }
24}
25
26impl fmt::Display for OutputFormat {
27 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28 formatter.write_str(self.as_str())
29 }
30}
31
32impl FromStr for OutputFormat {
33 type Err = String;
34
35 fn from_str(value: &str) -> Result<Self, Self::Err> {
36 match value {
37 "json" => Ok(Self::Json),
38 "yaml" => Ok(Self::Yaml),
39 "plain" => Ok(Self::Plain),
40 _ => Err("invalid output format: expected json, yaml, or plain".to_string()),
41 }
42 }
43}
44
45#[cfg(feature = "cli")]
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
48#[serde(rename_all = "lowercase")]
49pub enum OutputTo {
50 Split,
52 Stdout,
54 Stderr,
56}
57
58#[cfg(feature = "cli")]
59impl OutputTo {
60 pub const fn as_str(self) -> &'static str {
62 match self {
63 Self::Split => "split",
64 Self::Stdout => "stdout",
65 Self::Stderr => "stderr",
66 }
67 }
68
69 pub fn parse(value: &str) -> Result<Self, String> {
71 value.parse()
72 }
73}
74
75#[cfg(feature = "cli")]
76impl fmt::Display for OutputTo {
77 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
78 formatter.write_str(self.as_str())
79 }
80}
81
82#[cfg(feature = "cli")]
83impl FromStr for OutputTo {
84 type Err = String;
85
86 fn from_str(value: &str) -> Result<Self, Self::Err> {
87 match value {
88 "split" => Ok(Self::Split),
89 "stdout" => Ok(Self::Stdout),
90 "stderr" => Ok(Self::Stderr),
91 _ => Err("unsupported --output-to: expected split, stdout, or stderr".to_string()),
92 }
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::OutputFormat;
99 #[cfg(feature = "cli")]
100 use super::OutputTo;
101
102 #[test]
103 fn output_types_round_trip_text_and_serde() {
104 for format in [OutputFormat::Json, OutputFormat::Yaml, OutputFormat::Plain] {
105 assert_eq!(format.to_string().parse(), Ok(format));
106 assert_eq!(
107 serde_json::from_str::<OutputFormat>(
108 &serde_json::to_string(&format).unwrap_or_default()
109 )
110 .ok(),
111 Some(format)
112 );
113 }
114 #[cfg(feature = "cli")]
115 {
116 for destination in [OutputTo::Split, OutputTo::Stdout, OutputTo::Stderr] {
117 assert_eq!(destination.to_string().parse(), Ok(destination));
118 assert_eq!(
119 serde_json::from_str::<OutputTo>(
120 &serde_json::to_string(&destination).unwrap_or_default()
121 )
122 .ok(),
123 Some(destination)
124 );
125 }
126 }
127
128 let format_canary = "canary-output-format-secret";
129 let format_error = format_canary.parse::<OutputFormat>().unwrap_err();
130 assert!(!format_error.contains(format_canary));
131 assert!(format_error.contains("json"));
132
133 #[cfg(feature = "cli")]
134 {
135 let destination_canary = "canary-output-to-secret";
136 let destination_error = destination_canary.parse::<OutputTo>().unwrap_err();
137 assert!(!destination_error.contains(destination_canary));
138 assert!(destination_error.contains("split"));
139 }
140 }
141}