1use std::collections::HashMap;
4
5#[derive(Debug, Clone, PartialEq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[cfg_attr(feature = "serde", serde(untagged))]
9pub enum Value {
10 String(std::string::String),
11 Int(i64),
12 Float(f64),
13 Bool(bool),
14 Null,
15 Array(Vec<Value>),
16 Object(HashMap<std::string::String, Value>),
17 Secret(std::string::String),
19}
20
21impl Value {
22 pub fn as_str(&self) -> Option<&str> {
23 match self {
24 Value::String(s) | Value::Secret(s) => Some(s),
25 _ => None,
26 }
27 }
28
29 pub fn as_int(&self) -> Option<i64> {
30 match self {
31 Value::Int(n) => Some(*n),
32 _ => None,
33 }
34 }
35
36 pub fn as_float(&self) -> Option<f64> {
37 match self {
38 Value::Float(f) => Some(*f),
39 Value::Int(n) => Some(*n as f64),
40 _ => None,
41 }
42 }
43
44 pub fn as_bool(&self) -> Option<bool> {
45 match self {
46 Value::Bool(b) => Some(*b),
47 _ => None,
48 }
49 }
50
51 pub fn as_object(&self) -> Option<&HashMap<std::string::String, Value>> {
52 match self {
53 Value::Object(m) => Some(m),
54 _ => None,
55 }
56 }
57
58 pub fn as_object_mut(&mut self) -> Option<&mut HashMap<std::string::String, Value>> {
59 match self {
60 Value::Object(m) => Some(m),
61 _ => None,
62 }
63 }
64
65 pub fn as_array(&self) -> Option<&Vec<Value>> {
66 match self {
67 Value::Array(a) => Some(a),
68 _ => None,
69 }
70 }
71
72 pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
73 match self {
74 Value::Array(a) => Some(a),
75 _ => None,
76 }
77 }
78
79 pub fn as_secret(&self) -> Option<&str> {
80 match self {
81 Value::Secret(s) => Some(s),
82 _ => None,
83 }
84 }
85
86 pub fn is_null(&self) -> bool {
87 matches!(self, Value::Null)
88 }
89
90 pub fn as_number_f64(&self) -> Option<f64> {
91 match self {
92 Value::Int(n) => Some(*n as f64),
93 Value::Float(f) => Some(*f),
94 _ => None,
95 }
96 }
97}
98
99impl std::fmt::Display for Value {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 match self {
102 Value::String(s) | Value::Secret(s) => write!(f, "{}", s),
103 Value::Int(n) => write!(f, "{}", n),
104 Value::Float(fl) => {
105 let s = fl.to_string();
106 if s.contains('.') { write!(f, "{}", s) } else { write!(f, "{}.0", s) }
107 }
108 Value::Bool(b) => write!(f, "{}", b),
109 Value::Null => write!(f, "null"),
110 Value::Array(arr) => {
111 write!(f, "[")?;
112 for (i, item) in arr.iter().enumerate() {
113 if i > 0 { write!(f, ", ")?; }
114 write!(f, "{}", item)?;
115 }
116 write!(f, "]")
117 }
118 Value::Object(_) => write!(f, "[Object]"),
119 }
120 }
121}
122
123impl std::ops::Index<&str> for Value {
124 type Output = Value;
125 fn index(&self, key: &str) -> &Value {
126 match self {
127 Value::Object(map) => map.get(key).expect("key not found"),
128 _ => panic!("not an object"),
129 }
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135pub enum Mode {
136 Static,
137 Active,
138}
139
140#[derive(Debug, Clone, PartialEq)]
142pub struct Meta {
143 pub markers: Vec<String>,
144 pub args: Vec<String>,
145 pub type_hint: Option<String>,
146 pub constraints: Option<Constraints>,
147}
148
149#[derive(Debug, Clone, Default, PartialEq)]
151pub struct Constraints {
152 pub min: Option<f64>,
153 pub max: Option<f64>,
154 pub type_name: Option<String>,
155 pub required: bool,
156 pub readonly: bool,
157 pub pattern: Option<String>,
158 pub enum_values: Option<Vec<String>>,
159}
160
161pub type MetaMap = HashMap<String, Meta>;
163
164#[derive(Debug, Clone)]
166pub struct IncludeDirective {
167 pub path: String,
168 pub alias: String,
169}
170
171#[derive(Debug)]
173pub struct ParseResult {
174 pub root: Value,
175 pub mode: Mode,
176 pub locked: bool,
177 pub metadata: HashMap<String, MetaMap>,
180 pub includes: Vec<IncludeDirective>,
182}
183
184#[derive(Debug, Clone, Default)]
186pub struct Options {
187 pub env: Option<HashMap<String, String>>,
188 pub region: Option<String>,
189 pub lang: Option<String>,
190 pub base_path: Option<String>,
191}