conf_json/lib.rs
1//! # A JSON compatable configure file parser
2//!
3//! It's mainly for `read` not `write` from a human editable configure file in JSON.
4//! Most of the configure key accessing methods are immutable.
5//!
6//! Besides standard JSON, following features are supported:
7//! - Comments begin with '#' which can take a whole line or trailing part of a line
8//! - Both single and double quotation marks strings are allowed
9//! - For JSON Arry and Object, trailing comma is allowed
10//!
11//! # Examples
12//! Parse from `str`
13//!
14//! ```
15//! use conf_json::value;
16//! let s = r##"
17//! ## this is a json conf file
18//! ##
19//! {
20//! ## comment line
21//! "null_key": null,
22//! "i64_key": 1,
23//! "i64_sci_key": 123E+4,
24//! "i64_0x_key": 0xAf,
25//! "f64_key": 3.14,
26//! "f64_sci_key": 3.14e-2,
27//! "true_key": true,
28//! "false_key": false, # comment in line
29//! 'single_quote_key': 'a single quote value',
30//! "object_key": {
31//! "inner_key1": "abc",
32//! "inner_key2": 3.14E3,
33//! },
34//! "array_key": [1, "abc", ],
35//! }
36//! "##;
37//! println!("data source:");
38//! println!("{}", s);
39//! let v = s.parse::<value::Value>().unwrap();
40//!
41//! // basic accessing
42//! println!("\nbasic accessing assertion begin ...");
43//! assert!(v.is_object());
44//! assert!(!v.is_null());
45//! assert!(v.has("i64_key"));
46//! assert!(!v["null_key"].as_bool());
47//! assert!(v["i64_key"].as_bool());
48//! assert_eq!(v["i64_key"].as_i64(), 1);
49//! assert_eq!(v["f64_key"].as_f64(), 3.14);
50//! assert_eq!(v["object_key"]["inner_key1"].as_str(), "abc");
51//! assert_eq!(v["array_key"][1].as_str(), "abc");
52//! println!("basic accessing assertion pass");
53//!
54//! // iter over JSON Array
55//! println!("\niter over JSON Array:");
56//! v["array_key"].iter_array().for_each(|v| {println!("{:?}", v); });
57//!
58//! // iter over JSON Object
59//! println!("\niter over JSON Object:");
60//! v.iter_object().for_each(|(k, v)| { println!("{}: {:?}", k, v); });
61//! ```
62//!
63//! Load from `str`
64//!
65//! ```
66//! use conf_json;
67//! let v: conf_json::value::Value = "\"abc\"".as_bytes().into();
68//! assert_eq!(v.as_str(), "abc");
69//! ```
70//!
71//! Load from file
72//!
73//! ```
74//! use conf_json;
75//! let v = conf_json::load_from_file("sample.conf").unwrap();
76//! assert!(v.is_object());
77//! assert_eq!(v["f64_key"].as_f64(), 3.14);
78//! ```
79//!
80//! Load from any type T t that implements std::io::Read trait
81//! ```
82//! use conf_json;
83//! let t = b"123";
84//! let v: conf_json::value::Value = t.as_slice().into();
85//! assert_eq!(v.as_i64(), 123);
86//! ```
87//!
88
89use std::fs;
90use std::path::Path;
91use std::fmt::Display;
92use std::error::Error;
93
94use crate::value::Value;
95use crate::parser::Parser;
96
97pub mod value;
98pub mod parser;
99
100pub fn load_from_file<P: AsRef<Path> + Display>(path: P) -> Result<Value, Box<dyn Error>> {
101 Ok(Parser::new(fs::File::open(path)?).parse()?)
102}
103
104#[cfg(test)]
105mod tests {
106 use crate::value;
107
108 #[test]
109 fn test_empty_object_and_array() {
110 let empty_obj: value::Value = b"{}".as_slice().into();
111 assert!(empty_obj .is_object());
112 assert!(!empty_obj.as_bool());
113
114 let empty_array: value::Value = "[]".as_bytes().into();
115 assert!(empty_array.is_array());
116 assert!(!empty_array.as_bool());
117 }
118
119 #[test]
120 fn test_weird_numbers() {
121 let mut v :value::Value = "0.0".as_bytes().into();
122 assert_eq!(v.as_i64(), 0);
123
124 v = "0E0".as_bytes().into();
125 assert_eq!(v.as_i64(), 0);
126
127 v = "0e-0".as_bytes().into();
128 assert_eq!(v.as_i64(), 0);
129 }
130
131 #[test]
132 fn test_string() {
133 let mut v :value::Value = "\"abc\"".as_bytes().into();
134 assert_eq!(v.as_str(), "abc");
135
136 v = "'ABC'".as_bytes().into();
137 assert_eq!(v.as_str(), "ABC");
138
139 v = "'\\r\\n\\t'".as_bytes().into();
140 assert_eq!(v.as_str(), "\r\n\t");
141 }
142
143 #[test]
144 fn all() {
145 let s = r##"
146 # this is a json conf file
147 #
148 {
149 "null_key": null,
150 "i64_key": 1,
151 "i64_sci_key": 123E+4,
152 "i64_0x_key": 0xAf,
153 "f64_key": 3.14,
154 "f64_sci_key": 3.14e-2,
155 "true_key": true,
156 "false_key": false, # comment in line
157 'single_quote_key': 'a single quote value',
158 "object_key": {
159 "inner_key1": "abc",
160 "inner_key2": 3.14E3,
161 },
162 "array_key": [1, "abc", ],
163 }
164 "##;
165 let v = s.parse::<value::Value>().unwrap();
166
167 // basic accessing
168 assert!(v.is_object());
169 assert!(!v.is_null());
170 assert!(v.has("i64_key"));
171 assert!(!v["null_key"].as_bool());
172 assert!(v["i64_key"].as_bool());
173 assert_eq!(v["i64_key"].as_i64(), 1);
174 assert_eq!(v["f64_key"].as_f64(), 3.14);
175 assert_eq!(v["object_key"]["inner_key1"].as_str(), "abc");
176 assert_eq!(v["array_key"][1].as_str(), "abc");
177
178 // iter over JSON Array
179 v["array_key"].iter_array().for_each(|v| {println!("{:?}", v); });
180
181 // iter over JSON Object
182 v.iter_object().for_each(|(k, v)| { println!("{}: {:?}", k, v); });
183 }
184}