1#![no_std]
2extern crate no_std_compat as std;
3
4use std::prelude::v1::*;
5
6pub mod data;
7
8use std::fmt::Formatter;
9
10use crate::data::DataFormat;
11
12#[cfg(any(feature = "networking", feature = "networking_std"))]
13use product_os_net::{ IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs };
14
15#[cfg(feature = "networking_std")]
16use dns_lookup::lookup_host;
17
18#[cfg(feature = "files")]
19use product_os_security::RandomGeneratorTemplate;
20
21#[cfg(feature = "content")]
22use content_inspector::{ContentType, inspect};
23#[cfg(feature = "content")]
24use mime_sniffer::MimeTypeSniffer;
25
26
27#[cfg(feature = "files")]
28use std::sync::Arc;
29
30#[cfg(feature = "files")]
31use parking_lot::Mutex;
32
33
34#[cfg(feature = "json")]
35use regex::Regex;
36#[cfg(feature = "json")]
37use chrono::NaiveDateTime;
38
39#[cfg(any(feature = "json", feature = "yaml", feature = "networking", feature = "networking_std"))]
40use std::str::FromStr;
41
42use serde::{ Serialize, Deserialize };
43
44
45#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
46pub enum ProductOSError {
47 GenericError(String)
48}
49
50impl ProductOSError {
51 pub fn to_string(&self) -> String {
52 match self {
53 ProductOSError::GenericError(e) => e.to_owned(),
54 }
56 }
57}
58
59impl std::fmt::Display for ProductOSError {
60 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61 match self {
62 ProductOSError::GenericError(s) => write!(f, "{}", s)
63 }
64 }
65}
66
67
68pub struct ProductOSUtilities {}
69
70impl ProductOSUtilities {
71 #[cfg(feature = "files")]
72 pub fn get_current_working_dir() -> String {
73 let res = std::env::current_dir();
74 match res {
75 Ok(path) => path.into_os_string().into_string().unwrap(),
76 Err(_) => panic!("Problem getting current working directory")
77 }
78 }
79
80 #[cfg(feature = "files")]
81 pub fn get_base_path(files_path: &str) -> String {
82 let mut files_base_path = String::new();
83
84 if !files_path.starts_with("/") {
85 files_base_path.push_str(ProductOSUtilities::get_current_working_dir().as_str());
86 }
87
88 if !files_path.ends_with("/") {
89 files_base_path.push_str("/");
90 }
91
92 files_base_path.push_str(files_path);
93
94 tracing::info!("File list path used for file list get is: {:?}", files_base_path);
95
96 files_base_path
97 }
98
99 #[cfg(feature = "files")]
100 pub fn get_file_list(files_path: &str) -> Result<Vec<String>, ProductOSError> {
101 let files_base_path = ProductOSUtilities::get_base_path(files_path);
102
103 tracing::info!("File list path used for file list get is: {:?}", files_base_path);
104
105 let entries = walkdir::WalkDir::new(files_base_path.as_str())
106 .min_depth(1)
107 .max_depth(5)
108 .follow_links(true)
109 .into_iter()
110 .filter_entry(|e| ProductOSUtilities::is_not_hidden(e));
111 let mut files_list = Vec::new();
115
116 for entry in entries {
117 match entry {
118 Ok(entry) => {
119 let path = entry.path();
120 match path.to_str() {
121 None => {}
122 Some(s) => {
123 if entry.metadata().unwrap().is_file() {
124 let mut files_path = files_path.to_owned();
127 files_path.push_str(s.to_string().replace(files_base_path.as_str(), "").as_str());
128
129 let mut files_data_path = String::from(files_base_path.as_str());
130 files_data_path.push_str(s.to_string().replace(files_base_path.as_str(), "").as_str());
131
132 files_list.push(files_data_path);
133 }
134 }
135 }
136 }
137 Err(e) => return Err(ProductOSError::GenericError(format!("Failed to read files folder entry: {:?}", e)))
138 }
139 }
140
141 Ok(files_list)
142 }
143
144 #[cfg(feature = "files")]
145 fn is_not_hidden(entry: &walkdir::DirEntry) -> bool {
146 entry
147 .file_name()
148 .to_str()
149 .map(|s| !s.starts_with("."))
150 .unwrap_or(false)
151 }
152
153 #[cfg(feature = "files")]
154 pub fn get_select_file(random_generator: Arc<Mutex<product_os_security::RandomGenerator>>, files_path: &str) -> Result<String, ProductOSError> {
155 let mut generator = random_generator.lock();
156
157 match ProductOSUtilities::get_file_list(files_path) {
158 Ok(files_list) => {
159 let random_value = generator.get_random_usize(0, files_list.len());
160 let value: String = files_list.get(random_value).unwrap().to_string();
161 Ok(value)
162 }
163 Err(e) => Err(e)
164 }
165 }
166
167 #[cfg(feature = "logging_std")]
168 pub fn define_logging(level: tracing::Level) -> tracing_subscriber::FmtSubscriber {
169 tracing_subscriber::FmtSubscriber::builder()
171 .with_max_level(level)
173 .finish()
175 }
176
177 #[cfg(feature = "logging_std")]
178 pub fn set_global_logger(definition: tracing_subscriber::FmtSubscriber) {
179 match tracing::subscriber::set_global_default(definition) {
180 Ok(_) => {}
181 Err(e) => { tracing::warn!("Error setting default subscriber: {}", e) }
182 }
183 }
184
185 #[cfg(feature = "networking_advanced")]
186 pub fn get_all_current_host_ip_addresses() -> Vec<core::net::IpAddr> {
187 let mut ip_list = Vec::new();
188
189 for iface in pnet::datalink::interfaces() {
190 let ips = iface.ips;
191
192 for ip in ips {
193 tracing::info!("Idnentified current host IP address: {:?}", ip);
194 ip_list.push(ip.network())
195 }
196 }
197
198 ip_list
199 }
200
201 #[cfg(feature = "networking_std")]
202 pub fn get_socket_address(host: &str, port: u16, default_all_interfaces: bool) -> SocketAddr {
203 let socket_port = port;
204
205 let default_address = match default_all_interfaces {
206 true => SocketAddr::from((Ipv4Addr::new(0, 0, 0, 0), socket_port)),
207 false => SocketAddr::from((Ipv4Addr::new(127, 0, 0, 1), socket_port))
208 };
209
210 match lookup_host(host) {
211 Ok(addresses) => {
212 for address in addresses {
213 let address_string = address.to_string();
214 match SocketAddr::from_str(address_string.as_str()) {
215 Ok(socket_addr) => return socket_addr,
216 Err(_) => {}
217 }
218 }
219
220 tracing::info!("Hostname did not resolve any meaningful address, using default address");
221 default_address
222 },
223 Err(_) => {
224 match Ipv4Addr::from_str(host) {
225 Ok(address) => {
226 SocketAddr::from((IpAddr::V4(address), socket_port))
227 },
228 Err(_) => {
229 match Ipv6Addr::from_str(host) {
230 Ok(address) => {
231 SocketAddr::from((IpAddr::V6(address), socket_port))
232 },
233 Err(_) => {
234 tracing::error!("Address defined does not meet any allowed formats, using default address");
235 default_address
236 }
237 }
238 }
239 }
240 }
241 }
242 }
243
244 #[cfg(feature = "networking_std")]
245 pub fn get_all_interfaces_socket_address(host: &str, port: u16) -> SocketAddr {
246 let socket_port = port;
247
248 let default_address = SocketAddr::from((Ipv4Addr::new(0, 0, 0, 0), socket_port));
249
250 match Ipv4Addr::from_str(host) {
251 Ok(address) => {
252 SocketAddr::from((IpAddr::V4(address), socket_port))
253 },
254 Err(_) => {
255 match Ipv6Addr::from_str(host) {
256 Ok(address) => {
257 SocketAddr::from((IpAddr::V6(address), socket_port))
258 },
259 Err(_) => {
260 tracing::error!("Address defined does not meet any allowed formats, using default address");
261 default_address
262 }
263 }
264 }
265 }
266 }
267
268 #[cfg(feature = "networking_std")]
269 pub fn get_local_socket_address(host: &str, port: u16) -> SocketAddr {
270 let socket_port = port;
271
272 let default_address = SocketAddr::from((Ipv4Addr::new(127, 0, 0, 1), socket_port));
273
274 match Ipv4Addr::from_str(host) {
275 Ok(address) => {
276 SocketAddr::from((IpAddr::V4(address), socket_port))
277 },
278 Err(_) => {
279 match Ipv6Addr::from_str(host) {
280 Ok(address) => {
281 SocketAddr::from((IpAddr::V6(address), socket_port))
282 },
283 Err(_) => {
284 tracing::error!("Address defined does not meet any allowed formats, using default address");
285 default_address
286 }
287 }
288 }
289 }
290 }
291
292 #[cfg(feature = "json")]
295 pub fn find_json_property(object: &serde_json::Value, property: &str, default_value: &serde_json::Value) -> serde_json::Value {
296 let property_parts = property.split(".").collect::<Vec<&str>>();
297 let property_parts_length = property_parts.len();
298
299 ProductOSUtilities::find_json_property_internal(object, property_parts, default_value, 0, property_parts_length)
300 }
301
302 #[cfg(feature = "json")]
303 fn find_json_property_internal(object: &serde_json::Value, property_parts: Vec<&str>, default_value: &serde_json::Value, depth: usize, property_parts_length: usize) -> serde_json::Value {
304 match object {
305 serde_json::Value::Array(array) => {
306 match usize::from_str(property_parts.get(depth).unwrap()) {
307 Ok(prop) => {
308 match array.get(prop) {
309 None => default_value.to_owned(),
310 Some(value) => {
311 if depth == property_parts_length - 1 {
312 value.to_owned()
313 }
314 else {
315 ProductOSUtilities::find_json_property_internal(value, property_parts.to_owned(), default_value, depth + 1, property_parts_length)
316 }
317 }
318 }
319 }
320 Err(_) => default_value.to_owned()
321 }
322 }
323 serde_json::Value::Object(o) => {
324 #[cfg(feature = "logging")]
325 tracing::info!("Name {:?} in object {:?} for remap", &property_parts.get(depth).unwrap().to_string(), o);
326 match o.get_key_value(&property_parts.get(depth).unwrap().to_string()) {
327 None => default_value.to_owned(),
328 Some((_, value)) => {
329 if depth == property_parts_length - 1 {
330 value.to_owned()
331 }
332 else {
333 ProductOSUtilities::find_json_property_internal(value, property_parts.to_owned(), default_value, depth + 1, property_parts_length)
334 }
335 }
336 }
337 }
338 _ => default_value.to_owned()
339 }
340 }
341
342 #[cfg(feature = "json")]
343 pub fn is_number_json(object: &serde_json::Value) -> bool {
344 match object {
345 serde_json::Value::Number(_) => true,
346 serde_json::Value::String(s) => {
347 let regex = Regex::new("^[-+]?[0-9]+([.][0-9]+)?$").unwrap();
348 regex.is_match(s.as_str())
349 }
350 _ => false
351 }
352 }
353
354 #[cfg(feature = "json")]
355 pub fn is_integer_json(object: &serde_json::Value) -> bool {
356 match object {
357 serde_json::Value::Number(n) => {
358 if n.is_i64() || n.is_u64() { true }
359 else { false }
360 },
361 serde_json::Value::String(s) => {
362 let regex = Regex::new("^[-+]?[0-9]+$").unwrap();
363 regex.is_match(s.as_str())
364 }
365 _ => false
366 }
367 }
368
369 #[cfg(feature = "json")]
370 pub fn is_float_json(object: &serde_json::Value) -> bool {
371 match object {
372 serde_json::Value::Number(n) => {
373 if n.is_f64() { true }
374 else { false }
375 },
376 serde_json::Value::String(s) => {
377 let regex = Regex::new("^[-+]?[0-9]+([.][0-9]+)$").unwrap();
378 regex.is_match(s.as_str())
379 }
380 _ => false
381 }
382 }
383
384 #[cfg(feature = "json")]
385 pub fn is_boolean_json(object: &serde_json::Value) -> bool {
386 match object {
387 serde_json::Value::Bool(_) => true,
388 serde_json::Value::Number(n) => {
389 if n.is_i64() {
390 match n.as_i64().unwrap() {
391 0 | 1 => true,
392 _ => false
393 }
394 }
395 else if n.is_u64() {
396 match n.as_u64().unwrap() {
397 0 | 1 => true,
398 _ => false
399 }
400 }
401 else { false }
402 }
403 serde_json::Value::String(s) => {
404 let regex = Regex::new("^(?i)(none|some|null|true|false|0|1)$").unwrap();
405 regex.is_match(s.as_str())
406 }
407 _ => false
408 }
409 }
410
411 #[cfg(feature = "json")]
412 pub fn is_date_json(object: &serde_json::Value) -> bool {
413 match object {
414 serde_json::Value::String(s) => {
415 match NaiveDateTime::from_str(s.as_str()) {
416 Ok(_) => true,
417 Err(_) => false
418 }
419 }
420 _ => false
421 }
422 }
423
424 #[cfg(feature = "json")]
425 pub fn is_base64_json(object: &serde_json::Value) -> bool {
426 match object {
427 serde_json::Value::String(s) => {
428 let regex = Regex::new("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$").unwrap();
429 regex.is_match(s.as_str())
430 }
431 _ => false
432 }
433 }
434
435 #[cfg(feature = "json")]
436 pub fn is_mime_type_json(object: &serde_json::Value) -> bool {
437 match object {
438 serde_json::Value::String(s) => {
439 let regex = Regex::new("\\w+/[-.\\w]+(?:\\+[-.\\w]+)?").unwrap();
440 regex.is_match(s.as_str())
441 }
442 _ => false
443 }
444 }
445
446 #[cfg(all(feature = "json", feature = "content"))]
447 pub fn is_valid_mime_type_json(object: &serde_json::Value) -> Option<String> {
448 match object {
449 serde_json::Value::String(s) => {
450 match s.as_str().sniff_mime_type() {
451 None => None,
452 Some(s) => Some(s.to_string())
453 }
454 }
455 _ => None
456 }
457 }
458
459 #[cfg(all(feature = "json", feature = "content"))]
460 pub fn is_binary_json(object: &serde_json::Value) -> bool {
461 match object {
462 serde_json::Value::String(s) => {
463 match inspect(s.as_bytes()) {
464 ContentType::BINARY => true,
465 _ => false
466 }
467 }
468 _ => false
469 }
470 }
471
472 #[cfg(all(feature = "json", feature = "xml"))]
473 pub fn is_xml_json(object: &serde_json::Value) -> bool {
474 match object {
475 serde_json::Value::String(s) => {
476 let parser = xml::reader::EventReader::from_str(s.as_str());
477
478 let mut is_valid = false;
479 for e in parser {
480 match e {
481 Ok(_) => { is_valid = true },
482 Err(_) => {}
483 }
484 }
485
486 is_valid
487 }
488 _ => false
489 }
490 }
491
492 #[cfg(feature = "json")]
493 pub fn is_array_json(object: &serde_json::Value) -> bool {
494 match object {
495 serde_json::Value::Array(_) => true,
496 _ => false
497 }
498 }
499
500 #[cfg(feature = "json")]
501 pub fn is_string_json(object: &serde_json::Value) -> bool {
502 match object {
503 serde_json::Value::String(_) => true,
504 _ => false
505 }
506 }
507
508 #[cfg(feature = "json")]
509 pub fn is_option_json(object: &serde_json::Value) -> bool {
510 match object {
511 serde_json::Value::String(_) => true,
512 serde_json::Value::Number(_) => true,
513 serde_json::Value::Bool(_) => true,
514 _ => false
515 }
516 }
517
518 #[cfg(feature = "json")]
519 pub fn is_object_json(object: &serde_json::Value) -> bool {
520 match object {
521 serde_json::Value::Object(_) => true,
522 _ => false
523 }
524 }
525
526 #[cfg(feature = "json")]
527 pub fn is_null_json(object: &serde_json::Value) -> bool {
528 match object {
529 serde_json::Value::Null => true,
530 _ => false
531 }
532 }
533
534 #[cfg(feature = "json")]
535 pub fn data_type_json(object: &serde_json::Value) -> DataFormat {
536 if ProductOSUtilities::is_number_json(object) {
537 return DataFormat::Number
538 }
539
540 if ProductOSUtilities::is_boolean_json(object) {
541 return DataFormat::Boolean
542 }
543
544 if ProductOSUtilities::is_date_json(object) {
545 return DataFormat::Date
546 }
547
548 #[cfg(all(feature = "json", feature = "xml"))] {
549 if ProductOSUtilities::is_xml_json(object) {
550 return DataFormat::XML
551 }
552 }
553
554 if ProductOSUtilities::is_object_json(object) {
555 return DataFormat::JSON
556 }
557
558 if ProductOSUtilities::is_array_json(object) {
559 return DataFormat::List
560 }
561
562 if ProductOSUtilities::is_base64_json(object) {
563 return DataFormat::Base64
564 }
565
566 #[cfg(all(feature = "json", feature = "content"))] {
567 if ProductOSUtilities::is_binary_json(object) {
568 return DataFormat::Binary
569 }
570 }
571
572 #[cfg(all(feature = "json", feature = "content"))] {
573 match ProductOSUtilities::is_valid_mime_type_json(object) {
574 None => {
575 if ProductOSUtilities::is_string_json(object) {
576 return DataFormat::Text
577 }
578 else if ProductOSUtilities::is_option_json(object) {
579 return DataFormat::Option(object.to_string())
580 }
581 }
582 Some(s) => {
583 return DataFormat::Mime(s)
584 }
585 }
586 }
587
588 DataFormat::Unknown
589 }
590
591 #[cfg(feature = "text")]
592 pub fn text_indent(size: usize) -> String {
593 const INDENT: &'static str = " ";
594 (0..size).map(|_| INDENT)
595 .fold(String::with_capacity(size*INDENT.len()), |r, s| r + s)
596 }
597
598 #[cfg(feature = "yaml")]
599 pub fn yaml_to_string(yaml: &serde_yaml::Value, is_document: bool) -> Result<String, ProductOSError> {
600 let depth = 0;
601
602 let mut yaml_string = String::new();
603
604 if is_document {
605 yaml_string.push_str("---\n");
606 }
607
608 match ProductOSUtilities::yaml_to_string_internal(yaml, depth) {
609 Ok(yaml_str) => yaml_string.push_str(yaml_str.as_str()),
610 Err(e) => return Err(e)
611 }
612
613 Ok(yaml_string)
614 }
615
616 #[cfg(feature = "yaml")]
617 pub fn string_to_yaml(yaml_string: &str) -> Result<serde_yaml::Value, ProductOSError> {
618 match serde_yaml::from_str(yaml_string) {
619 Ok(v) => Ok(v),
620 Err(e) => Err(ProductOSError::GenericError(e.to_string()))
621 }
622 }
623
624 #[cfg(feature = "yaml")]
625 fn yaml_to_string_internal(yaml: &serde_yaml::Value, mut depth: usize) -> Result<String, ProductOSError> {
626 let mut yaml_string = String::new();
627
628 match yaml {
629 serde_yaml::Value::Null => {},
630 serde_yaml::Value::Bool(b) => yaml_string.push_str(format!("{}", b).as_str()),
631 serde_yaml::Value::Number(n) => {
632 match n.as_u64() {
633 Some(u) => yaml_string.push_str(format!("{}", u).as_str()),
634 None => {
635 match n.as_f64() {
636 Some(f) => yaml_string.push_str(format!("{}", f).as_str()),
637 None => {
638 match n.as_i64() {
639 Some(i) => yaml_string.push_str(format!("{}", i).as_str()),
640 None => return Err(ProductOSError::GenericError(String::from("Could not convert YAML")))
641 }
642 }
643 }
644 }
645 }
646 }
647 serde_yaml::Value::String(s) => yaml_string.push_str(format!("{}", s).as_str()),
648 serde_yaml::Value::Sequence(a) => {
649 for element in a {
650 match ProductOSUtilities::yaml_to_string_internal(element, depth) {
651 Ok(value) => {
652 yaml_string.push_str(format!("{}- ", ProductOSUtilities::text_indent(depth)).as_str());
653
654 depth = depth + 1;
655 yaml_string.push_str(format!("{}", value).as_str());
656 depth = depth - 1;
657 }
658 Err(e) => return Err(e)
659 };
660
661 yaml_string.push_str("\n");
662 }
663 }
664 serde_yaml::Value::Mapping(m) => {
665 for (key, value) in m {
666 match ProductOSUtilities::yaml_to_string_internal(key, depth) {
667 Ok(key) => {
668 yaml_string.push_str(format!("{}{}: ", ProductOSUtilities::text_indent(depth), key).as_str());
669 }
670 Err(e) => return Err(e)
671 };
672
673 depth = depth + 1;
674 match ProductOSUtilities::yaml_to_string_internal(value, depth) {
675 Ok(value) => {
676 yaml_string.push_str(format!("{}", value).as_str());
677 }
678 Err(e) => return Err(e)
679 };
680 depth = depth - 1;
681
682 yaml_string.push_str("\n");
683 }
684 }
685 serde_yaml::Value::Tagged(t) => {
686 let value = match ProductOSUtilities::yaml_to_string_internal(&t.value, depth + 1) {
687 Ok(v) => v,
688 Err(e) => return Err(e)
689 };
690
691 yaml_string.push_str(format!("{}: {}\n", t.tag.to_string(), value).as_str());
692 }
693 }
694
695 Ok(yaml_string)
696
697 }
770
771
772 #[cfg(all(feature = "json", feature = "yaml"))]
773 pub fn yaml_to_json(yaml: &serde_yaml::Value) -> Result<serde_json::Value, ProductOSError> {
774 ProductOSUtilities::yaml_value_to_json_value(yaml)
775 }
846
847 #[cfg(all(feature = "json", feature = "yaml"))]
848 pub fn json_to_yaml(value: &serde_json::Value, mut depth: usize) -> Result<serde_yaml::Value, ProductOSError> {
849 let mut yaml_string = String::new();
850
851 match value {
852 serde_json::Value::Object(o) => {
853 for (key, value) in o {
854 yaml_string.push_str(format!("{}{}: ", ProductOSUtilities::text_indent(depth), key).as_str());
855
856 match ProductOSUtilities::json_to_yaml(value, depth) {
857 Ok(yaml_value) => {
858 depth = depth + 1;
859 match ProductOSUtilities::yaml_to_string(&yaml_value, false) {
860 Ok(value_string) => yaml_string.push_str(format!("{}", value_string).as_str()),
861 Err(e) => return Err(e)
862 }
863 depth = depth - 1;
864 }
865 Err(e) => return Err(e)
866 };
867
868 yaml_string.push_str("\n");
869 }
870 }
871 serde_json::Value::Array(array) => {
872 for _ in array {
873 match ProductOSUtilities::json_to_yaml(value, depth) {
874 Ok(value) => {
875 yaml_string.push_str(format!("{}- ", ProductOSUtilities::text_indent(depth)).as_str());
876
877 depth = depth + 1;
878 match ProductOSUtilities::yaml_to_string(&value, false) {
879 Ok(value_string) => yaml_string.push_str(format!("{}", value_string).as_str()),
880 Err(e) => return Err(e)
881 }
882 depth = depth - 1;
883 }
884 Err(e) => return Err(e)
885 };
886
887 yaml_string.push_str("\n");
888 }
889 }
890 serde_json::Value::String(s) => {
891 yaml_string.push_str(format!("{}", s).as_str());
892 yaml_string.push_str("\n");
893 }
894 serde_json::Value::Bool(b) => {
895 yaml_string.push_str(format!("{}", b).as_str());
896 yaml_string.push_str("\n");
897 }
898 serde_json::Value::Number(n) => {
899 match n.as_f64() {
900 Some(f) => yaml_string.push_str(format!("{}", f).as_str()),
901 None => {
902 match n.as_i64() {
903 Some(i) => yaml_string.push_str(format!("{}", i).as_str()),
904 None => {
905 match n.as_u64() {
906 Some(u) => yaml_string.push_str(format!("{}", u).as_str()),
907 None => return Err(ProductOSError::GenericError(String::from("Could not convert number value")))
908 }
909 }
910 }
911 }
912 }
913 yaml_string.push_str("\n");
914 }
915 serde_json::Value::Null => {
916 yaml_string.push_str("null");
917 yaml_string.push_str("\n");
918 }
919 }
920
921 ProductOSUtilities::string_to_yaml(yaml_string.as_str())
922 }
923
924 #[cfg(all(feature = "yaml", feature = "json"))]
925 pub fn yaml_value_to_json_value(value: &serde_yaml::Value) -> Result<serde_json::Value, ProductOSError> {
926 match value {
927 serde_yaml::Value::Null => Ok(serde_json::Value::Null),
928 serde_yaml::Value::Bool(b) => Ok(serde_json::Value::Bool(b.to_owned())),
929 serde_yaml::Value::Number(n) => {
930 match n.as_u64() {
931 None => match n.as_i64() {
932 None => match n.as_f64() {
933 None => return Err(ProductOSError::GenericError(String::from("Invalid value returned"))),
934 Some(f) => {
935 match serde_json::Number::from_f64(f.to_owned()) {
936 None => return Err(ProductOSError::GenericError(String::from("Invalid float value returned"))),
937 Some(f) => Ok(serde_json::Value::Number(f))
938 }
939 }
940 }
941 Some(i) => Ok(serde_json::Value::Number(serde_json::Number::from(i.to_owned())))
942 }
943 Some(u) => Ok(serde_json::Value::Number(serde_json::Number::from(u.to_owned())))
944 }
945 }
946 serde_yaml::Value::String(s) => Ok(serde_json::Value::String(s.to_owned())),
947 serde_yaml::Value::Sequence(a) => {
948 let mut val_vec: Vec<serde_json::Value> = vec!();
949
950 for e in a.as_slice() {
951 match ProductOSUtilities::yaml_value_to_json_value(e) {
952 Ok(v) => val_vec.push(v),
953 Err(e) => return Err(e)
954 }
955 }
956
957 Ok(serde_json::Value::Array(val_vec))
958 }
959 serde_yaml::Value::Mapping(m) => {
960 let mut map = serde_json::Map::new();
961
962 for (k, v) in m.iter() {
963 let key = match ProductOSUtilities::yaml_value_to_json_value(k) {
964 Ok(v) => match v {
965 serde_json::Value::String(k) => k,
966 _ => return Err(ProductOSError::GenericError(String::from("Invalid value returned")))
967 },
968 Err(e) => return Err(e)
969 };
970
971 let value = match ProductOSUtilities::yaml_value_to_json_value(v) {
972 Ok(v) => v,
973 Err(e) => return Err(e)
974 };
975
976 map.insert(key, value);
977 }
978
979 Ok(serde_json::Value::Object(map))
980 }
981 serde_yaml::Value::Tagged(t) => {
982 let tag = t.tag.to_string();
983 let value = match ProductOSUtilities::yaml_value_to_json_value(&t.value) {
984 Ok(v) => v,
985 Err(e) => return Err(e)
986 };
987
988 let mut map = serde_json::Map::new();
989 map.insert(tag, value);
990
991 Ok(serde_json::Value::Object(map))
992 }
993 }
994 }
995
996 #[cfg(all(feature = "yaml", feature = "json"))]
997 pub fn json_value_to_yaml_value(value: &serde_json::Value) -> Result<serde_yaml::Value, ProductOSError> {
998 match value {
999 serde_json::Value::Null => Ok(serde_yaml::Value::Null),
1000 serde_json::Value::Bool(b) => Ok(serde_yaml::Value::Bool(b.to_owned())),
1001 serde_json::Value::Number(n) => {
1002 match n.as_u64() {
1003 None => match n.as_i64() {
1004 None => match n.as_f64() {
1005 None => return Err(ProductOSError::GenericError(String::from("Invalid value returned"))),
1006 Some(f) => Ok(serde_yaml::Value::Number(serde_yaml::Number::from(f.to_owned())))
1007 }
1008 Some(i) => Ok(serde_yaml::Value::Number(serde_yaml::Number::from(i.to_owned())))
1009 }
1010 Some(u) => Ok(serde_yaml::Value::Number(serde_yaml::Number::from(u.to_owned())))
1011 }
1012 }
1013 serde_json::Value::String(s) => Ok(serde_yaml::Value::String(s.to_owned())),
1014 serde_json::Value::Array(a) => {
1015 let mut val_vec: Vec<serde_yaml::Value> = vec!();
1016
1017 for e in a.as_slice() {
1018 match ProductOSUtilities::json_value_to_yaml_value(e) {
1019 Ok(v) => val_vec.push(v),
1020 Err(e) => return Err(e)
1021 }
1022 }
1023
1024 Ok(serde_yaml::Value::Sequence(val_vec))
1025 }
1026 serde_json::Value::Object(o) => {
1027 let mut map = serde_yaml::Mapping::new();
1028
1029 for (k, v) in o.iter() {
1030 let key = serde_yaml::Value::String(k.to_owned());
1031
1032 let value = match ProductOSUtilities::json_value_to_yaml_value(v) {
1033 Ok(v) => v,
1034 Err(e) => return Err(e)
1035 };
1036
1037 map.insert(key, value);
1038 }
1039
1040 Ok(serde_yaml::Value::Mapping(map))
1041 }
1042 }
1043 }
1044
1045 #[cfg(feature = "yaml")]
1046 pub fn find_yaml_property(yaml: &serde_yaml::Value, property: &str, default_value: &serde_yaml::Value) -> serde_yaml::Value {
1047 let property_parts = property.split(".").collect::<Vec<&str>>();
1048 let property_parts_length = property_parts.len();
1049
1050 ProductOSUtilities::find_yaml_property_internal(yaml, property_parts, default_value, 0, property_parts_length)
1051 }
1052
1053 #[cfg(feature = "yaml")]
1054 fn find_yaml_property_internal(yaml: &serde_yaml::Value, property_parts: Vec<&str>, default_value: &serde_yaml::Value, depth: usize, property_parts_length: usize) -> serde_yaml::Value {
1055 match yaml {
1056 serde_yaml::Value::Sequence(array) => {
1057 match usize::from_str(property_parts.get(depth).unwrap()) {
1058 Ok(prop) => {
1059 match array.get(prop) {
1060 None => default_value.to_owned(),
1061 Some(value) => {
1062 if depth == property_parts_length - 1 {
1063 value.to_owned()
1064 }
1065 else {
1066 ProductOSUtilities::find_yaml_property_internal(value, property_parts.to_owned(), default_value, depth + 1, property_parts_length)
1067 }
1068 }
1069 }
1070 }
1071 Err(_) => default_value.to_owned()
1072 }
1073 }
1074 serde_yaml::Value::Mapping(map) => {
1075 match map.get(&serde_yaml::Value::String(property_parts.get(depth).unwrap().to_string())) {
1076 None => default_value.to_owned(),
1077 Some(value) => {
1078 if depth == property_parts_length - 1 {
1079 value.to_owned()
1080 }
1081 else {
1082 ProductOSUtilities::find_yaml_property_internal(value, property_parts.to_owned(), default_value, depth + 1, property_parts_length)
1083 }
1084 }
1085 }
1086 }
1087 _ => default_value.to_owned()
1088 }
1089
1090 }
1131}
1132
1133
1134