1use std::fmt;
7
8use facet::Facet;
9
10#[derive(Clone, Debug, Eq, Facet, PartialEq)]
27#[facet(rename_all = "snake_case")]
28#[repr(u8)]
29pub enum Expr {
30 Literal(String),
32 Environment(String),
34 Variable(String),
36 Secret(String),
38 File(Box<Self>),
40 First(Vec<Self>),
42}
43
44impl fmt::Display for Expr {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 match self {
47 Self::Literal(text) => write!(f, "literal \"{text}\""),
48 Self::Environment(name) => write!(f, "environment {name}"),
49 Self::Variable(name) => write!(f, "variable {name}"),
50 Self::Secret(name) => write!(f, "secret {name}"),
51 Self::File(inner) => write!(f, "file from {inner}"),
52 Self::First(exprs) => {
53 let exprs: Vec<_> = exprs.iter().map(ToString::to_string).collect();
54 write!(f, "first of [{}]", exprs.join(", "))
55 }
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::Expr;
63
64 fn decode(json: &str) -> Expr {
65 facet_json::from_str(json).expect("expression decodes")
66 }
67
68 #[test]
69 fn every_variant_decodes() {
70 assert_eq!(
71 decode(r#"{"literal":"text"}"#),
72 Expr::Literal("text".to_owned())
73 );
74 assert_eq!(
75 decode(r#"{"environment":"A"}"#),
76 Expr::Environment("A".to_owned())
77 );
78 assert_eq!(
79 decode(r#"{"variable":"B"}"#),
80 Expr::Variable("B".to_owned())
81 );
82 assert_eq!(decode(r#"{"secret":"C"}"#), Expr::Secret("C".to_owned()));
83 assert_eq!(
84 decode(r#"{"file":{"environment":"D"}}"#),
85 Expr::File(Box::new(Expr::Environment("D".to_owned())))
86 );
87 assert_eq!(
88 decode(r#"{"first":[{"literal":"x"},{"secret":"E"}]}"#),
89 Expr::First(vec![
90 Expr::Literal("x".to_owned()),
91 Expr::Secret("E".to_owned())
92 ])
93 );
94 }
95}