rsjson/
lib.rs

1//! Json file parser library
2//!
3//! # Installation
4//! ```toml
5//! ...
6//! [dependencies]
7//! rsjson = "0.6.0";
8//! ```
9//! or run
10//! ```bash
11//! cargo add rsjson
12//! ```
13//!
14//! # Importation
15//! ```rust
16//! use rsjson;
17//! ```
18//!
19//! # Code example
20//! - read and parse a json file
21//! ```rust
22//! let json: Result<rsjson::Json, String> = rsjson::Json::fromFile("/path/to/file.json");
23//! ```
24//!
25//! - read and parse a json structure from a string
26//! - the string can be both "normal" and raw
27//! ```rust
28//! let json: Result<rsjson::Json, String> = rsjson::json!(
29//!     r#"{
30//!         "key" : "value",
31//!         "second_key" : ["one", "two"]
32//!     }"#
33//! );
34//! ```
35//! - in both previous cases, remeber to handle the eventual error (e.g. using `match`) or to call `unwrap()`
36//!
37//!
38//! - create an empty json instance
39//! ```rust
40//! let json = rsjson::Json::new();
41//! ```
42//!
43//! - add a node
44//! ```rust
45//! json.addNode(
46//!     rsjson::Node::new(
47//!         "nodeLabel",
48//!         rsjson::NodeContent::Int(32)
49//!     )
50//! );
51//! ```
52//!
53//! - edit a node's content
54//! ```rust
55//! json.setContent(
56//!     "nodeLabel",
57//!     rsjson::NodeContent::Bool(true)
58//! );
59//! ```
60//!
61//! - remove a node
62//! ```rust
63//! json.remove(
64//!     "nodeLabel"
65//! );
66//! ```
67//!
68//! - check the existance of a label
69//! ```rust
70//! let exists: bool = json.has("nodeLabel");
71//! ```
72
73#![allow(non_snake_case, unused_assignments)]
74
75use std::{fs, path};
76use std::collections::HashSet;
77
78const DIGITS: [&str; 11] = [
79    "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "."
80];
81
82#[derive(Debug, PartialEq)]
83enum Token {
84    String(String),
85    Int(usize),
86    Float(f32),
87    OpenBrace,
88    CloseBrace,
89    OpenBracket,
90    CloseBracket,
91    Colon,
92    Comma,
93    Bool(bool),
94    Null
95}
96
97impl Token {
98    fn toString(&self) -> String {
99        match self {
100            Token::String(string) => string.clone(),
101            _ => String::new()
102        }
103    }
104}
105
106struct Parser {
107    tokens: Vec<Token>,
108    index: usize,
109    text: String ,
110    len: usize
111}
112
113impl Parser {
114    fn new(text: String) -> Parser {
115        return Parser {
116            tokens: Vec::<Token>::new(),
117            index: 0_usize,
118            len: (&text).len(),
119            text: text
120        }
121    }
122
123    fn get(&mut self) -> String {
124        match self.text.get(self.index..self.index+1) {
125            Some(c) => c.to_string(),
126            None => {
127                panic!("Non utf8 character found, which is not accepted")
128            }
129        }
130    }
131
132    fn checkNotEnd(&self) -> bool {
133        self.index != self.len
134    }
135
136    fn parse(&mut self) -> bool {
137        self.skipNull();
138        while self.checkNotEnd() {
139            let mut current = self.get();
140
141            if current == "\"" {
142                self.index += 1;
143
144                let mut value = String::new();
145
146                while self.checkNotEnd() {
147                    current = self.get();
148
149                    if current.as_str() == "\"" && (&self.text[self.index-1..self.index] != "\\") {
150                        break
151
152                    } else if current.as_str() == "\"" && (&self.text[self.index-1..self.index] == "\\" && &self.text[self.index-2..self.index-1] == "\\") {
153                        break
154                    }
155
156                    value += current.as_str();
157                    self.index += 1;
158                }
159
160                if ! self.checkNotEnd() {
161                    return true;
162                }
163                self.index += 1;
164
165                self.tokens.push(Token::String(value));
166
167            } else if self.get() == ":" {
168                self.tokens.push(Token::Colon);
169                self.index += 1;
170
171            } else if self.get() == "," {
172                self.tokens.push(Token::Comma);
173                self.index += 1;
174
175            } else if self.get() == "{" {
176                self.tokens.push(Token::OpenBrace);
177                self.index += 1;
178
179            } else if self.get() == "}" {
180                self.tokens.push(Token::CloseBrace);
181                self.index += 1;
182
183            } else if self.get() == "[" {
184                self.tokens.push(Token::OpenBracket);
185                self.index += 1;
186
187            } else if self.get() == "]" {
188                self.tokens.push(Token::CloseBracket);
189                self.index += 1;
190
191            } else if DIGITS.contains(&self.get().as_str()) {
192                let mut value = String::new();
193
194                while self.checkNotEnd() && DIGITS.contains(&self.get().as_str()) {
195                    value += self.get().as_str();
196                    self.index += 1;
197                }
198
199                if ! self.checkNotEnd() {
200                    return true;
201                }
202
203                if value.contains(".") {
204                    self.tokens.push(Token::Float(value.parse::<f32>().unwrap()))
205
206                } else {
207                    self.tokens.push(Token::Int(value.parse::<usize>().unwrap()))
208                }
209
210            } else if self.get() == "t" || self.get() == "f" || self.get() == "n" {
211                if self.len - self.index - 4 > 0 && &self.text[self.index..self.index + 4] == "true" {
212                    self.tokens.push(Token::Bool(true));
213                    self.index += 4;
214
215                } else if self.len - self.index - 4 > 0 && &self.text[self.index..self.index + 4] == "null" {
216                    self.tokens.push(Token::Null);
217                    self.index += 4;
218
219                } else if self.len - self.index - 5 > 0 && &self.text[self.index..self.index + 5] == "false" {
220                    self.tokens.push(Token::Bool(false));
221                    self.index += 5;
222
223                } else {
224                    return true
225                }
226            }
227            self.skipNull();
228        }
229
230        false
231    }
232
233    fn skipNull(&mut self) {
234        let skip = [" ", "\t", "\n"];
235
236        while self.index < self.len && skip.contains(&&self.text[self.index..self.index + 1]) {
237            self.index += 1;
238        }
239    }
240}
241
242#[derive(Debug, Clone, PartialEq)]
243pub enum NodeContent {
244    String(String),
245    Int(usize),
246    Float(f32),
247    Bool(bool),
248    List(Vec<NodeContent>),
249    Json(Json),
250    Null
251}
252
253impl NodeContent {
254    pub fn toString(&self) -> Option<String> {
255        match self {
256            NodeContent::String(value) => Some(value.to_string().replace("\"", "\\\"")),
257            _ => None
258        }
259    }
260
261    pub fn toUsize(&self) -> Option<usize> {
262        match self {
263            NodeContent::Int(value) => Some(value.to_owned()),
264            _ => None
265        }
266    }
267
268    pub fn toBool(&self) -> Option<bool> {
269        match self {
270            NodeContent::Bool(value) => Some(value.to_owned()),
271            _ => None
272        }
273    }
274
275    pub fn toFloat(&self) -> Option<f32> {
276        match self {
277            NodeContent::Float(value) => Some(value.to_owned()),
278            _ => None
279        }
280    }
281
282    pub fn toJson(&self) -> Option<Json> {
283        match self {
284            NodeContent::Json(value) => Some(value.clone()),
285            _ => None
286        }
287    }
288
289    pub fn toList(&self) -> Option<Vec<NodeContent>> {
290        match self {
291            NodeContent::List(value) => Some(value.clone()),
292            _ => None
293        }
294    }
295
296    pub fn toNull(&self) -> Option<Node> {
297        return None;
298    }
299}
300
301/// Node struct represents a pair of label (String) and content (rsjson::NodeContent)
302/// implements a getter for both label and content
303#[derive(Debug, Clone, PartialEq)]
304pub struct Node {
305    label: String,
306    content: NodeContent
307}
308
309impl Node {
310    pub fn new<T: ToString>(label: T, content: NodeContent) -> Node {
311        Node {
312            label: label.to_string().replace("\"", "\\\""),
313            content: content
314        }
315    }
316
317    pub fn getLabel(&self) -> String {
318        return self.label.clone();
319    }
320
321    pub fn getContent(&self) -> NodeContent {
322        return self.content.clone();
323    }
324}
325
326#[derive(Debug, Clone, PartialEq)]
327pub struct Json {
328    nodes: Vec<Node>,
329    labels: HashSet<String>
330}
331
332impl Json {
333    pub fn new() -> Json {
334        return Json {
335            nodes: Vec::<Node>::new(),
336            labels: HashSet::<String>::new()
337        }
338    }
339
340    /// Reads the file at `filePath` and returns a Json struct corresponding to its content
341    pub fn fromFile<T: ToString>(filePath: T) -> Result<Json, String> {
342        match std::fs::read_to_string(filePath.to_string()) {
343            Err(why) => Err(format!("Failed because: {why}")),
344            Ok(content) => Json::fromString(content)
345        }
346    }
347
348    pub fn fromString<T: ToString>(text: T) -> Result<Json, String> {
349        let mut parser = Parser::new(text.to_string());
350        let error = parser.parse();
351
352        if error {
353            return Err(String::from("Json format error"));
354        }
355
356        let tokens = parser.tokens;
357
358        if tokens.get(0).unwrap() != &Token::OpenBrace {
359            return Err(String::from("Json format error: missing opening curly bracket"));
360        }
361
362        let index = 1_usize;
363
364        let (_, json, error) = Self::json(&tokens, index);
365        if error {
366            return Err(String::from("Json format error"));
367        }
368
369        return Ok(json.unwrap())
370    }
371
372    fn json(tokens: &Vec<Token>, startIndex: usize) -> (usize, Option<Json>, bool) {
373        let mut index = startIndex;
374        let mut nodes = Vec::<Node>::new();
375        let mut labels = HashSet::<String>::new();
376
377        while index < tokens.len() {
378            match tokens.get(index).unwrap() {
379                Token::String(_) => {
380                    let (newIndex, node, error) = Self::node(&tokens, index);
381
382                    if error {
383                        return (index, None, true)
384                    }
385
386                    index = newIndex;
387                    if tokens.get(index).unwrap() != &Token::CloseBrace && tokens.get(index).unwrap() != &Token::Comma {
388                        return (index, None, true)
389
390                    } else if tokens.get(index).unwrap() == &Token::Comma {
391                        index += 1;
392                    }
393
394                    match node {
395                        Some(node) => {
396                            labels.insert(node.label.clone());
397                            nodes.push(node);
398                        },
399                        None => {}
400                    }
401                },
402                Token::CloseBrace => {
403                    break
404                }
405                _ => return (index, None, true)
406            }
407        }
408        (index, Some(Json{nodes: nodes, labels}), false)
409    }
410
411    fn list(tokens: &Vec<Token>, startIndex: usize) -> (usize, Option<NodeContent>, bool) {
412        let mut index = startIndex;
413        let mut content = Vec::<NodeContent>::new();
414
415        while tokens.get(index).unwrap() != &Token::CloseBracket {
416            match tokens.get(index).unwrap() {
417                Token::String(string) => {
418                    content.push(NodeContent::String(string.to_owned()));
419                    index += 1;
420                },
421
422                Token::Int(int) => {
423                    content.push(NodeContent::Int(int.to_owned()));
424                    index += 1;
425                },
426
427                Token::Float(float) => {
428                    content.push(NodeContent::Float(float.to_owned()));
429                    index += 1;
430                },
431
432                Token::Null => {
433                    content.push(NodeContent::Null);
434                    index += 1;
435                },
436
437                Token::Bool(bool) => {
438                    content.push(NodeContent::Bool(bool.to_owned()));
439                    index += 1;
440                },
441
442                Token::OpenBrace => {
443                    let (newIndex, json, error) = Self::json(tokens, index + 1);
444
445                    if error {
446                        return (index, None, true)
447                    }
448
449                    index = newIndex + 1;
450                    content.push(NodeContent::Json(json.unwrap()));
451                },
452
453                Token::OpenBracket => {
454                    let (newIndex, list, error) = Self::list(tokens, index);
455
456                    if error {
457                        return (index, None, true)
458                    }
459
460                    index = newIndex;
461                    content.push(list.unwrap())
462                },
463
464                Token::Comma => {
465                    index += 1;
466                },
467
468                _ => {
469                    return (index, None, true)
470                }
471
472
473            }
474        }
475        if tokens.get(index-1).unwrap() == &Token::Comma {
476            return (index, None, true);
477        }
478
479        (index, Some(NodeContent::List(content)), false)
480    }
481
482    fn node(tokens: &Vec<Token>, startIndex: usize) -> (usize, Option<Node>, bool) {
483        let mut index = startIndex;
484        let label = tokens.get(index).unwrap().toString();
485
486        index += 1;
487        if tokens.get(index).unwrap() != &Token::Colon {
488            return (index, None, true)
489        }
490        index += 1;
491
492        let mut content = NodeContent::Null;
493        match tokens.get(index).unwrap() {
494            Token::Null => {
495                content = NodeContent::Null;
496                index += 1;
497            },
498
499            Token::Int(int) => {
500                content = NodeContent::Int(int.to_owned());
501                index += 1;
502            },
503
504            Token::Float(float) => {
505                content = NodeContent::Float(float.to_owned());
506                index += 1;
507            },
508
509            Token::Bool(bool) => {
510                content = NodeContent::Bool(bool.to_owned());
511                index += 1;
512            },
513
514            Token::String(string) => {
515                content = NodeContent::String(string.to_owned());
516                index += 1;
517            },
518
519            Token::OpenBrace => {
520                index += 1;
521                let (newIndex, nodeContent, error) = Self::json(tokens, index);
522                if error {
523                    return (index, None, true)
524                }
525                index = newIndex + 1;
526                content = NodeContent::Json(nodeContent.unwrap());
527            },
528
529            Token::OpenBracket => {
530                index += 1;
531                let (newIndex, list, error) = Self::list(tokens, index);
532
533                if error {
534                    return (index, None, true);
535                }
536
537                index = newIndex + 1;
538                content = list.unwrap();
539            }
540
541            _ => {
542                return (index, None, true)
543            }
544        }
545
546        (index, Some(Node{label: label, content: content}), false)
547    }
548
549    /// Returns a vector containing all nodes in the Json object
550    pub fn getAllNodes(&self) -> Vec<Node> {
551        return self.nodes.clone();
552    }
553
554    /// Returns the content of the requested node
555    pub fn get<T: ToString>(&self, label: T) -> Option<&NodeContent> {
556        for node in &self.nodes {
557            if node.label == label.to_string() {
558                return Some(&node.content)
559            }
560        }
561
562        return None;
563    }
564
565    /// Returns the requested node
566    pub fn getNode<T: ToString>(&self, label: T) -> Option<&Node> {
567        for node in &self.nodes {
568            if node.label == label.to_string() {
569                return Some(node);
570            }
571        }
572        return None;
573    }
574
575    fn renderJson(json: &Json) -> String {
576        let mut content = String::from("{");
577
578        for node in &json.nodes {
579            let mut label = (&node.label).to_owned();
580            label = label.replace("\\", "\\\\").replace("\"", "\\\"");
581            
582            content = format!("{}\"{}\":{},", content, &node.label, Self::renderContent(&node.content));
583        }
584
585        if content.len() > 2 {
586            format!("{}{}", content[0..content.len()-1].to_string(), "}")
587
588        } else {
589            format!("{}{}", content, "}")
590        }
591    }
592
593    fn renderList(list: &Vec<NodeContent>, ) -> String {
594        let mut content = String::from("[");
595
596        for node in list {
597            content = format!("{}{},", content, Self::renderContent(&node))
598        }
599
600        if content.len() > 1 {
601            format!("{}{}", content[0..content.len()-1].to_string(), "]")
602        } else {
603            String::from("[]")
604        }
605    }
606
607    pub fn renderContent(object: &NodeContent) -> String {
608        match object {
609            NodeContent::Bool(bool) => if *bool { String::from("true") } else { String::from("false") },
610            NodeContent::Float(float) => format!("{}", float),
611            NodeContent::Int(int) => format!("{}", int),
612            NodeContent::Null => String::from("null"),
613            NodeContent::String(string) => format!("\"{}\"", string.replace("\\", "\\\\").replace("\"", "\\\"")),
614            NodeContent::List(list) => Self::renderList(&list),
615            NodeContent::Json(json) => Self::renderJson(&json),
616        }
617    }
618
619    /// Exports the Json struct into a Json file and writes it into `fileName`
620    pub fn writeToFile<T: ToString>(&self, fileName: T) -> bool {
621        let content = Json::renderJson(self);
622
623        return match fs::write(path::Path::new(&fileName.to_string()), content) {
624            Err(_) => false,
625            Ok(_) => true
626        }
627    }
628
629    /// Exports the Json struct into a json-formatted string
630    pub fn toString(&self) -> String {
631        return Json::renderJson(self);
632    }
633
634    /// Adds a node to the Json struct
635    pub fn addNode(&mut self, node: Node) {
636        self.nodes.push(node);
637    }
638
639    /// Changes the content of a node, returns a bool representing the status of the change
640    pub fn setContent<T: ToString>(&mut self, label: T, content: NodeContent) -> bool {
641        for node in &mut self.nodes {
642            if node.label == label.to_string() {
643
644                node.content = content;
645                return true;
646            }
647        }
648
649        return false;
650    }
651
652    /// Removes a node basing on its label
653    pub fn remove<T: ToString>(&mut self, label: T) -> bool {
654        let mut index: usize = 0;
655
656        for node in &self.nodes {
657            if node.label == label.to_string() {
658                self.nodes.remove(index);
659
660                return true;
661            }
662            index += 1;
663        }
664        return false;
665    }
666
667    /// Converts json to bytes
668    pub fn bytes(&self) -> Vec<u8> {
669        Json::renderJson(self).bytes().collect::<Vec<u8>>()
670    }
671
672    /// Checks if exists a node with provided label
673    pub fn has<T: ToString>(&self, label: T) -> bool{
674        self.labels.contains(&label.to_string())
675    }
676}
677
678#[macro_export]
679macro_rules! json {
680    ( $string:expr ) => {
681        Json::fromString($string)
682    };
683}
684
685#[cfg(test)]
686mod tests {
687    use super::*;
688
689    #[test]
690    fn test() {
691        let content = std::fs::read_to_string("./map.json");
692        let j = Json::fromString(content.unwrap()).unwrap();
693
694        println!("{:?}", j);
695        return;
696    }
697}