1use core::fmt::Write;
2use std::fmt;
3
4use num_bigint::BigInt;
5use regex::Regex;
6use lazy_static::lazy_static;
7
8
9use crate::global::binary_codes::BinaryCode;
10
11use super::{Value, Error, ValueResult, Quantity, Endpoint, primitives::time::Time, Url};
12
13#[derive(Clone)]
14pub enum PrimitiveValue {
15 Int8(i8),
16 Uint8(u8),
17 Int16(i16),
18 Int32(i32),
19 UInt16(u16),
20 UInt32(u32),
21 Int64(i64),
22 Float64(f64),
23 BigInt(BigInt),
24 Text(String),
25 Buffer(Vec<u8>),
26 Boolean(bool),
27 Quantity(Quantity),
28 Time(Time),
29 Endpoint(Endpoint),
30 Url(Url),
31 Null,
32 Void
33}
34
35
36
37impl Default for PrimitiveValue {
38 fn default() -> Self { PrimitiveValue::Void }
39}
40
41impl fmt::Display for PrimitiveValue {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 write!(f, "{}", Value::to_string(self))
44 }
45}
46
47fn escape_string(value:&String) -> String {
48 value
56 .replace("\\", "\\\\")
57 .replace("\"", "\\\"")
58 .replace("\n", "\\n")
59 .replace("\r", "\\r")
60 .replace("\t", "\\t")
61 .replace("\u{0008}", "\\b")
62 .replace("\u{000c}", "\\f")
63 .replace("\u{001b}", "\\u001b")
64}
65
66impl Value for PrimitiveValue {
67 fn to_string(&self) -> String {
68 match &self {
69 PrimitiveValue::Int8(value) => value.to_string(),
70 PrimitiveValue::Uint8(value) => value.to_string(),
71 PrimitiveValue::Int16(value) => value.to_string(),
72 PrimitiveValue::UInt16(value) => value.to_string(),
73 PrimitiveValue::Int32(value) => value.to_string(),
74 PrimitiveValue::UInt32(value) => value.to_string(),
75 PrimitiveValue::Int64(value) => value.to_string(),
76 PrimitiveValue::BigInt(value) => value.to_string(),
77 PrimitiveValue::Float64(value) => {
78 if value.is_infinite() {
79 if value.is_sign_negative() {return "-infinity".to_string()}
80 else {return "infinity".to_string()}
81 }
82 else if value.is_nan() {return "nan".to_string()}
83 else {
84 let mut string = value.to_string();
85 if !string.contains('.') {string += ".0";}
86 return string;
87 }
88 },
89 PrimitiveValue::Text(value) => {
90 let string = escape_string(value);
91 return format!("\"{string}\"");
92 }
93 PrimitiveValue::Buffer(value) => {
94 let n = value.len();
95
96 let mut s = String::with_capacity(2 * n);
97 for byte in value {
98 write!(s, "{:02X}", byte).expect("could not parse buffer")
99 }
100 return format!("`{s}`");
101 },
102 PrimitiveValue::Boolean(value) => value.to_string(),
103 PrimitiveValue::Void => "void".to_string(),
104 PrimitiveValue::Null => "null".to_string(),
105 PrimitiveValue::Quantity(value) => value.to_string(false),
106 PrimitiveValue::Endpoint(value) => value.to_string(false),
107 PrimitiveValue::Time(value) => value.to_string(),
108 PrimitiveValue::Url(value) => value.to_string()
109 }
110 }
111
112 fn binary_operation(&self, code: BinaryCode, other: Box<dyn Value>) -> ValueResult {
113 if other.is::<PrimitiveValue>() {
114 let other_prim = other.downcast_ref::<PrimitiveValue>().expect("error casting stack value to primitive");
115
116 return match
117 match code {
118 BinaryCode::ADD => self.sum(other_prim),
119 BinaryCode::SUBTRACT => self.difference(other_prim),
120 BinaryCode::MULTIPLY => self.product(other_prim),
121 BinaryCode::DIVIDE => self.quotient(other_prim),
122 BinaryCode::MODULO => self.modulo(other_prim),
123 BinaryCode::POWER => self.power(other_prim),
124
125 _ => Err(Error {message:"invalid binary operation".to_string()})
126 }
127 {
128 Ok(result) => Ok(Box::new(result)),
129 Err(err) => Err(err)
130 }
131
132 }
133
134 return Err(Error {message:"invalid binary operation".to_string()})
135 }
136
137 fn cast(&self, dx_type: super::Type) -> ValueResult {
138
139 if dx_type.name == "text" {
141 Ok(Box::new(PrimitiveValue::Text(Value::to_string(self))))
142 }
143
144 else {Err(Error {message:format!("cannot cast to {dx_type}")})}
145 }
146
147}
148
149impl PrimitiveValue {
150
151 pub fn to_string_colorized(&self) -> String {
153 match &self {
154 PrimitiveValue::Quantity(value) => value.to_string(true),
155 PrimitiveValue::Endpoint(value) => value.to_string(true),
156 _ => Value::to_string(self)
157 }
158 }
159
160
161 fn sum(&self, other: &PrimitiveValue) -> Result<PrimitiveValue,Error> {
162 if self.is_number() && other.is_number() {
163 match self {
164 PrimitiveValue::Int8(val) => Ok(PrimitiveValue::Int8 (val + other.get_as_integer() as i8)),
165 PrimitiveValue::Int16(val) => Ok(PrimitiveValue::Int16 (val + other.get_as_integer() as i16)),
166 PrimitiveValue::Int32(val) => Ok(PrimitiveValue::Int32 (val + other.get_as_integer() as i32)),
167 PrimitiveValue::Int64(val) => Ok(PrimitiveValue::Int64 (val + other.get_as_integer() as i64)),
168 PrimitiveValue::Float64(val) => Ok(PrimitiveValue::Float64(val + other.get_as_float())),
169 _ => Err(Error {message:"cannot perform an add operation".to_string()})
170 }
171 }
172
173 else if self.is_text() && other.is_text() {
174 return Ok(PrimitiveValue::Text(self.get_as_text().to_owned() + other.get_as_text()));
175 }
176
177 else {return Err(Error {message:"cannot perform an add operation".to_string()})}
178 }
179
180 fn difference(&self, other: &PrimitiveValue) -> Result<PrimitiveValue,Error> {
181 if self.is_number() && other.is_number() {
182 match self {
183 PrimitiveValue::Int8(val) => Ok(PrimitiveValue::Int8 (val - other.get_as_integer() as i8)),
184 PrimitiveValue::Int16(val) => Ok(PrimitiveValue::Int16 (val - other.get_as_integer() as i16)),
185 PrimitiveValue::Int32(val) => Ok(PrimitiveValue::Int32 (val - other.get_as_integer() as i32)),
186 PrimitiveValue::Int64(val) => Ok(PrimitiveValue::Int64 (val - other.get_as_integer() as i64)),
187 PrimitiveValue::Float64(val) => Ok(PrimitiveValue::Float64(val - other.get_as_float())),
188 _ => Err(Error {message:"cannot perform a subtract operation".to_string()})
189 }
190 }
191 else {return Err(Error {message:"cannot perform a subtract operation".to_string()})}
192 }
193
194
195 fn product(&self, other: &PrimitiveValue) -> Result<PrimitiveValue,Error> {
196 if self.is_number() && other.is_number() {
197 match self {
198 PrimitiveValue::Int8(val) => Ok(PrimitiveValue::Int8 (val * other.get_as_integer() as i8)),
199 PrimitiveValue::Int16(val) => Ok(PrimitiveValue::Int16 (val * other.get_as_integer() as i16)),
200 PrimitiveValue::Int32(val) => Ok(PrimitiveValue::Int32 (val * other.get_as_integer() as i32)),
201 PrimitiveValue::Int64(val) => Ok(PrimitiveValue::Int64 (val * other.get_as_integer() as i64)),
202 PrimitiveValue::Float64(val) => Ok(PrimitiveValue::Float64(val * other.get_as_float())),
203 _ => Err(Error {message:"cannot perform a subtract operation".to_string()})
204 }
205 }
206 else {return Err(Error {message:"cannot perform a subtract operation".to_string()})}
207 }
208
209 fn quotient(&self, other: &PrimitiveValue) -> Result<PrimitiveValue,Error> {
210 if self.is_number() && other.is_number() {
211 match self {
212 PrimitiveValue::Int8(val) => Ok(PrimitiveValue::Int8 (val / other.get_as_integer() as i8)),
213 PrimitiveValue::Int16(val) => Ok(PrimitiveValue::Int16 (val / other.get_as_integer() as i16)),
214 PrimitiveValue::Int32(val) => Ok(PrimitiveValue::Int32 (val / other.get_as_integer() as i32)),
215 PrimitiveValue::Int64(val) => Ok(PrimitiveValue::Int64 (val / other.get_as_integer() as i64)),
216 PrimitiveValue::Float64(val) => Ok(PrimitiveValue::Float64(val / other.get_as_float())),
217 _ => Err(Error {message:"cannot perform a subtract operation".to_string()})
218 }
219 }
220 else {return Err(Error {message:"cannot perform a subtract operation".to_string()})}
221 }
222
223 fn modulo(&self, other: &PrimitiveValue) -> Result<PrimitiveValue,Error> {
224 if self.is_number() && other.is_number() {
225 match self {
226 PrimitiveValue::Int8(val) => Ok(PrimitiveValue::Int8 (val % other.get_as_integer() as i8)),
227 PrimitiveValue::Int16(val) => Ok(PrimitiveValue::Int16 (val % other.get_as_integer() as i16)),
228 PrimitiveValue::Int32(val) => Ok(PrimitiveValue::Int32 (val % other.get_as_integer() as i32)),
229 PrimitiveValue::Int64(val) => Ok(PrimitiveValue::Int64 (val % other.get_as_integer() as i64)),
230 PrimitiveValue::Float64(val) => Ok(PrimitiveValue::Float64(val % other.get_as_float())),
231 _ => Err(Error {message:"cannot perform a subtract operation".to_string()})
232 }
233 }
234 else {return Err(Error {message:"cannot perform a subtract operation".to_string()})}
235 }
236
237 fn power(&self, other: &PrimitiveValue) -> Result<PrimitiveValue,Error> {
238 if self.is_number() && other.is_number() {
239 match self {
240 PrimitiveValue::Int8(val) => Ok(PrimitiveValue::Int8 (val.pow(other.get_as_integer() as u32))),
241 PrimitiveValue::Int16(val) => Ok(PrimitiveValue::Int16 (val.pow(other.get_as_integer() as u32))),
242 PrimitiveValue::Int32(val) => Ok(PrimitiveValue::Int32 (val.pow(other.get_as_integer() as u32))),
243 PrimitiveValue::Int64(val) => Ok(PrimitiveValue::Int64 (val.pow(other.get_as_integer() as u32))),
244 PrimitiveValue::Float64(val) => Ok(PrimitiveValue::Float64(val.powf(other.get_as_integer() as f64))),
245 _ => Err(Error {message:"cannot perform a subtract operation".to_string()})
246 }
247 }
248 else {return Err(Error {message:"cannot perform a subtract operation".to_string()})}
249 }
250
251 pub fn is_number(&self) -> bool {
252 match &self {
253 PrimitiveValue::Int8(_) => true,
254 PrimitiveValue::Int16(_) => true,
255 PrimitiveValue::Int32(_) => true,
256 PrimitiveValue::Int64(_) => true,
257 PrimitiveValue::Float64(_) => true,
258 PrimitiveValue::BigInt(_) => true,
259 _ => false
260 }
261 }
262
263 pub fn is_text(&self) -> bool {
264 match &self {
265 PrimitiveValue::Text(_) => true,
266 _ => false
267 }
268 }
269
270 pub fn get_as_text(&self) -> &str {
271 match &self {
272 PrimitiveValue::Text(value) => value,
273 _ => ""
274 }
275 }
276
277 pub fn get_as_buffer(&self) -> Vec<u8> {
278 match &self {
279 PrimitiveValue::Buffer(value) => value.to_vec(),
280 _ => Vec::new()
281 }
282 }
283
284 pub fn get_as_integer(&self) -> isize {
285 match &self {
286 PrimitiveValue::Int8(value) => *value as isize,
287 PrimitiveValue::Uint8(value) => *value as isize,
288 PrimitiveValue::UInt16(value) => *value as isize,
289 PrimitiveValue::Int16(value) => *value as isize,
290 PrimitiveValue::Int32(value) => *value as isize,
291 PrimitiveValue::UInt32(value) => *value as isize,
292 PrimitiveValue::Int64(value) => *value as isize,
293 PrimitiveValue::Float64(value) => *value as isize,
294 _ => 0
295 }
296 }
297
298 pub fn get_as_unsigned_integer(&self) -> usize {
299 match &self {
300 PrimitiveValue::Int8(value) => *value as usize,
301 PrimitiveValue::Uint8(value) => *value as usize,
302 PrimitiveValue::UInt16(value) => *value as usize,
303 PrimitiveValue::Int16(value) => *value as usize,
304 PrimitiveValue::Int32(value) => *value as usize,
305 PrimitiveValue::UInt32(value) => *value as usize,
306 PrimitiveValue::Int64(value) => *value as usize,
307 PrimitiveValue::Float64(value) => *value as usize,
308 _ => 0
309 }
310 }
311
312 pub fn get_as_float(&self) -> f64 {
313 match &self {
314 PrimitiveValue::Int8(value) => *value as f64,
315 PrimitiveValue::Uint8(value) => *value as f64,
316 PrimitiveValue::UInt16(value) => *value as f64,
317 PrimitiveValue::Int16(value) => *value as f64,
318 PrimitiveValue::Int32(value) => *value as f64,
319 PrimitiveValue::UInt32(value) => *value as f64,
320 PrimitiveValue::Int64(value) => *value as f64,
321 PrimitiveValue::Float64(value) => *value as f64,
322 _ => 0.0
323 }
324 }
325
326
327 pub fn to_key_string(&self) -> String {
329 match &self {
330 PrimitiveValue::Text(value) => {
331 let string = escape_string(value);
332 if KEY_CAN_OMIT_QUOTES.is_match(&string) {
334 return string;
335 }
336 else {return format!("\"{string}\"");}
338 }
339 _ => Value::to_string(self)
340 }
341 }
342
343 pub fn can_omit_quotes(&self) -> bool {
345 match &self {
346 PrimitiveValue::Text(value) => KEY_CAN_OMIT_QUOTES.is_match(&escape_string(value)),
347 _ => true
348 }
349 }
350}
351
352lazy_static! {
353 static ref KEY_CAN_OMIT_QUOTES:Regex = Regex::new(r"^[A-Za-z_][A-Za-z_0-9]*$").unwrap();
354}