csml_interpreter/data/
literal.rs

1use crate::data::position::Position;
2use crate::data::primitive::{Primitive, PrimitiveObject, PrimitiveString};
3use crate::data::{Data, Interval};
4use crate::error_format::*;
5
6use std::cmp::Ordering;
7use std::collections::HashMap;
8use std::ops::Add;
9
10////////////////////////////////////////////////////////////////////////////////
11// DATA STRUCTURES
12////////////////////////////////////////////////////////////////////////////////
13
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct Literal {
18    pub content_type: String,
19    pub primitive: Box<dyn Primitive>,
20    // this adds complementary information about the origin of the variable
21    pub additional_info: Option<HashMap<String, Literal>>,
22    pub secure_variable: bool,
23    pub interval: Interval,
24}
25
26#[derive(Debug)]
27pub enum ContentType {
28    Event(String),
29    Http,
30    Smtp,
31    Base64,
32    Hex,
33    Jwt,
34    Crypto,
35    Time,
36    Primitive,
37}
38
39////////////////////////////////////////////////////////////////////////////////
40// PUBLIC FUNCTIONS
41////////////////////////////////////////////////////////////////////////////////
42
43pub fn get_info(
44    args: &HashMap<String, Literal>,
45    additional_info: &Option<HashMap<String, Literal>>,
46    interval: Interval,
47    data: &mut Data,
48) -> Result<Literal, ErrorInfo> {
49    let usage = "get_info(Optional<String: search_key>) => Literal";
50
51    match (additional_info, args.get("arg0")) {
52        (Some(map), None) => Ok(PrimitiveObject::get_literal(map, interval)),
53
54        (Some(map), Some(key)) => {
55            let key = Literal::get_value::<String>(
56                &key.primitive,
57                &data.context.flow,
58                interval,
59                usage.to_owned(),
60            )?;
61
62            match map.get(key) {
63                Some(value) => Ok(value.to_owned()),
64                None => {
65                    let mut lit = PrimitiveObject::get_literal(map, interval);
66                    let error_msg = format!("get_info() failed, key '{}' not found", key);
67
68                    // add error message in additional info
69                    lit.add_error_to_info(&error_msg);
70
71                    Ok(lit)
72                }
73            }
74        }
75
76        _ => Ok(PrimitiveString::get_literal("Null", interval)),
77    }
78}
79
80pub fn create_error_info(error_msg: &str, interval: Interval) -> HashMap<String, Literal> {
81    let mut map = HashMap::new();
82
83    map.insert(
84        "error".to_owned(),
85        PrimitiveString::get_literal(error_msg, interval),
86    );
87
88    map
89}
90
91////////////////////////////////////////////////////////////////////////////////
92// Implementations
93////////////////////////////////////////////////////////////////////////////////
94
95impl Literal {
96    pub fn get_value<'lifetime, 'a, T: 'static>(
97        primitive: &'lifetime Box<dyn Primitive>,
98        flow_name: &'a str,
99        interval: Interval,
100        error_message: String,
101    ) -> Result<&'lifetime T, ErrorInfo> {
102        match primitive.get_value().downcast_ref::<T>() {
103            Some(sep) => Ok(sep),
104            None => Err(gen_error_info(
105                Position::new(interval, flow_name),
106                error_message,
107            )),
108        }
109    }
110
111    pub fn get_mut_value<'lifetime, 'a, T: 'static>(
112        primitive: &'lifetime mut Box<dyn Primitive>,
113        flow_name: &'a str,
114        interval: Interval,
115        error_message: String,
116    ) -> Result<&'lifetime mut T, ErrorInfo> {
117        match primitive.get_mut_value().downcast_mut::<T>() {
118            Some(sep) => Ok(sep),
119            None => Err(gen_error_info(
120                Position::new(interval, flow_name),
121                error_message,
122            )),
123        }
124    }
125
126    pub fn set_content_type(&mut self, content_type: &str) {
127        self.content_type = content_type.to_owned();
128    }
129
130    pub fn add_info(&mut self, key: &str, value: Literal) {
131        match self.additional_info {
132            Some(ref mut map) => {
133                map.insert(key.to_owned(), value);
134            }
135            None => {
136                let mut info = HashMap::new();
137                info.insert(key.to_owned(), value);
138
139                self.additional_info = Some(info);
140            }
141        }
142    }
143
144    pub fn add_info_block(&mut self, info: HashMap<String, Literal>) {
145        match self.additional_info {
146            Some(ref mut map) => {
147                for (key, value) in info {
148                    map.insert(key, value);
149                }
150            }
151            None => {
152                self.additional_info = Some(info);
153            }
154        }
155    }
156
157    pub fn add_error_to_info(&mut self, error_msg: &str) {
158        match self.additional_info {
159            Some(ref mut map) => {
160                map.insert(
161                    "error".to_owned(),
162                    PrimitiveString::get_literal(error_msg, self.interval),
163                );
164            }
165            None => {
166                let error_info = create_error_info(error_msg, self.interval);
167                self.additional_info = Some(error_info);
168            }
169        }
170    }
171
172    pub fn add_literal_to_info(&mut self, key: String, lit: Literal) {
173        match self.additional_info {
174            Some(ref mut map) => {
175                map.insert(key, lit);
176            }
177            None => {
178                let mut map = HashMap::new();
179                map.insert(key, lit);
180
181                self.additional_info = Some(map);
182            }
183        }
184    }
185}
186
187impl ContentType {
188    pub fn get(literal: &Literal) -> ContentType {
189        match literal.content_type.as_ref() {
190            "http" => ContentType::Http,
191            "smtp" => ContentType::Smtp,
192            "base64" => ContentType::Base64,
193            "hex" => ContentType::Hex,
194            "jwt" => ContentType::Jwt,
195            "crypto" => ContentType::Crypto,
196            "time" => ContentType::Time,
197            "event" => ContentType::Event(String::from("")),
198            _ => ContentType::Primitive,
199        }
200    }
201}
202
203////////////////////////////////////////////////////////////////////////////////
204// TRAIT FUNCTIONS
205////////////////////////////////////////////////////////////////////////////////
206
207impl PartialOrd for Literal {
208    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
209        self.primitive.partial_cmp(&other.primitive)
210    }
211}
212
213impl PartialEq for Literal {
214    fn eq(&self, other: &Self) -> bool {
215        (*self).primitive.is_eq(&(*other.primitive))
216    }
217}
218
219impl Add for Literal {
220    type Output = Result<std::boxed::Box<(dyn Primitive + 'static)>, String>;
221
222    fn add(self, rhs: Literal) -> Result<std::boxed::Box<(dyn Primitive + 'static)>, String> {
223        self.primitive + rhs.primitive
224    }
225}