Skip to main content

nginx_discovery/ast/
value.rs

1//! Value types for NGINX directive arguments
2
3use std::fmt;
4
5/// Represents a value in an NGINX directive
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub enum Value {
9    /// Plain unquoted string: `nginx`
10    Literal(String),
11
12    /// Single-quoted string: `'hello world'`
13    SingleQuoted(String),
14
15    /// Double-quoted string: `"hello world"`
16    DoubleQuoted(String),
17
18    /// Variable reference: `$remote_addr`
19    Variable(String),
20}
21
22impl Value {
23    /// Create a new literal value
24    pub fn literal(s: impl Into<String>) -> Self {
25        Self::Literal(s.into())
26    }
27
28    /// Create a new single-quoted value
29    pub fn single_quoted(s: impl Into<String>) -> Self {
30        Self::SingleQuoted(s.into())
31    }
32
33    /// Create a new double-quoted value
34    pub fn double_quoted(s: impl Into<String>) -> Self {
35        Self::DoubleQuoted(s.into())
36    }
37
38    /// Create a new variable value
39    pub fn variable(s: impl Into<String>) -> Self {
40        Self::Variable(s.into())
41    }
42
43    /// Get the inner string value, regardless of type
44    #[must_use]
45    pub fn as_str(&self) -> &str {
46        match self {
47            Self::Literal(s)
48            | Self::SingleQuoted(s)
49            | Self::DoubleQuoted(s)
50            | Self::Variable(s) => s,
51        }
52    }
53
54    /// Check if this is a variable
55    #[must_use]
56    pub fn is_variable(&self) -> bool {
57        matches!(self, Self::Variable(_))
58    }
59
60    /// Check if this is quoted (single or double)
61    #[must_use]
62    pub fn is_quoted(&self) -> bool {
63        matches!(self, Self::SingleQuoted(_) | Self::DoubleQuoted(_))
64    }
65
66    /// Get the value as it would appear in the config file
67    #[must_use]
68    pub fn to_config_string(&self) -> String {
69        match self {
70            Self::Literal(s) => s.clone(),
71            Self::SingleQuoted(s) => format!("'{s}'"),
72            Self::DoubleQuoted(s) => format!("\"{s}\""),
73            Self::Variable(s) => format!("${s}"),
74        }
75    }
76}
77
78impl fmt::Display for Value {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        write!(f, "{}", self.as_str())
81    }
82}
83
84impl From<String> for Value {
85    fn from(s: String) -> Self {
86        Self::Literal(s)
87    }
88}
89
90impl From<&str> for Value {
91    fn from(s: &str) -> Self {
92        Self::Literal(s.to_string())
93    }
94}
95
96impl From<&String> for Value {
97    fn from(s: &String) -> Self {
98        Self::Literal(s.clone())
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_literal_value() {
108        let val = Value::literal("nginx");
109        assert_eq!(val.as_str(), "nginx");
110        assert!(!val.is_variable());
111        assert!(!val.is_quoted());
112        assert_eq!(val.to_config_string(), "nginx");
113    }
114
115    #[test]
116    fn test_single_quoted_value() {
117        let val = Value::single_quoted("hello world");
118        assert_eq!(val.as_str(), "hello world");
119        assert!(val.is_quoted());
120        assert_eq!(val.to_config_string(), "'hello world'");
121    }
122
123    #[test]
124    fn test_double_quoted_value() {
125        let val = Value::double_quoted("hello world");
126        assert_eq!(val.as_str(), "hello world");
127        assert!(val.is_quoted());
128        assert_eq!(val.to_config_string(), "\"hello world\"");
129    }
130
131    #[test]
132    fn test_variable_value() {
133        let val = Value::variable("remote_addr");
134        assert_eq!(val.as_str(), "remote_addr");
135        assert!(val.is_variable());
136        assert!(!val.is_quoted());
137        assert_eq!(val.to_config_string(), "$remote_addr");
138    }
139
140    #[test]
141    fn test_value_display() {
142        let val = Value::literal("test");
143        assert_eq!(val.to_string(), "test");
144
145        let var = Value::variable("host");
146        assert_eq!(var.to_string(), "host");
147    }
148
149    #[test]
150    fn test_value_from_string() {
151        let val: Value = "nginx".into();
152        assert_eq!(val.as_str(), "nginx");
153
154        let val2: Value = String::from("test").into();
155        assert_eq!(val2.as_str(), "test");
156    }
157
158    #[test]
159    fn test_value_equality() {
160        let val1 = Value::literal("test");
161        let val2 = Value::literal("test");
162        assert_eq!(val1, val2);
163
164        let val3 = Value::single_quoted("test");
165        assert_ne!(val1, val3); // Different types
166    }
167}