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}