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
10use 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 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
39pub 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 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
91impl 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
203impl 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}