github_actions_models/common/
expr.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, PartialEq, Serialize)]
7pub struct ExplicitExpr(String);
8
9impl ExplicitExpr {
10 pub fn from_curly(expr: impl Into<String>) -> Option<Self> {
15 let expr = expr.into();
18 let trimmed = expr.trim();
19 if !trimmed.starts_with("${{") || !trimmed.ends_with("}}") {
20 return None;
21 }
22
23 Some(ExplicitExpr(expr))
24 }
25
26 pub fn as_raw(&self) -> &str {
29 &self.0
30 }
31
32 pub fn as_curly(&self) -> &str {
37 self.as_raw().trim()
38 }
39
40 pub fn as_bare(&self) -> &str {
44 self.as_curly()
45 .strip_prefix("${{")
46 .and_then(|e| e.strip_suffix("}}"))
47 .map(|e| e.trim())
48 .expect("invariant violated: ExplicitExpr must be an expression")
49 }
50}
51
52impl<'de> Deserialize<'de> for ExplicitExpr {
53 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
54 where
55 D: serde::Deserializer<'de>,
56 {
57 let raw = String::deserialize(deserializer)?;
58
59 let Some(expr) = Self::from_curly(raw) else {
60 return Err(serde::de::Error::custom(
61 "invalid expression: expected '${{' and '}}' delimiters",
62 ));
63 };
64
65 Ok(expr)
66 }
67}
68
69#[derive(Debug, Deserialize, PartialEq, Serialize)]
73#[serde(untagged)]
74pub enum LoE<T> {
75 Expr(ExplicitExpr),
79 Literal(T),
80}
81
82impl<T> Default for LoE<T>
83where
84 T: Default,
85{
86 fn default() -> Self {
87 Self::Literal(T::default())
88 }
89}
90
91pub type BoE = LoE<bool>;
93
94#[cfg(test)]
95mod tests {
96 use super::{ExplicitExpr, LoE};
97
98 #[test]
99 fn test_expr_invalid() {
100 let cases = &[
101 "not an expression",
102 "${{ missing end ",
103 "missing beginning }}",
104 ];
105
106 for case in cases {
107 let case = format!("\"{case}\"");
108 assert!(serde_yaml::from_str::<ExplicitExpr>(&case).is_err());
109 }
110 }
111
112 #[test]
113 fn test_expr() {
114 let expr = "\" ${{ foo }} \\t \"";
115 let expr: ExplicitExpr = serde_yaml::from_str(expr).unwrap();
116 assert_eq!(expr.as_bare(), "foo");
117 }
118
119 #[test]
120 fn test_loe() {
121 let lit = "\"normal string\"";
122 assert_eq!(
123 serde_yaml::from_str::<LoE<String>>(lit).unwrap(),
124 LoE::Literal("normal string".to_string())
125 );
126
127 let expr = "\"${{ expr }}\"";
128 assert!(matches!(
129 serde_yaml::from_str::<LoE<String>>(expr).unwrap(),
130 LoE::Expr(_)
131 ));
132
133 let invalid = "\"${{ invalid \"";
135 assert_eq!(
136 serde_yaml::from_str::<LoE<String>>(invalid).unwrap(),
137 LoE::Literal("${{ invalid ".to_string())
138 );
139 }
140}