dotproperties/
lib.rs

1//! A crate to parse the Java Properties file format.
2//!
3//! The Properties file format is simple key/value text format that can be read
4//! and written by the standard library of Java. It is often used for
5//! configuration files, and also for translation files (Bundles).
6//!
7//! The Java class that supports this format is `java.util.Properties`, with
8//! its methods `load` and `store`. Note that the Java class also provides the
9//! methods `loadFromXML` and `storeToXML`, but this crate does not support
10//! the XML format.
11//!
12//! Starting from Java 9, the Properties files used as Resource Bundles are
13//! allowed to be utf-8, instead of only latin1 with unicode escapes ([JEP
14//! 226](http://openjdk.java.net/jeps/226)). This crate does not support JEP
15//! 226.
16//!
17//! This crate was written based on the [Java 8 API
18//! reference](https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader-).
19//! As far as the author knows, this crate supports reading the full Properties
20//! format with no exception. There is no support to write Properties files,
21//! yet.
22
23#[macro_use]
24extern crate nom;
25
26#[macro_use]
27#[cfg(test)]
28mod test_helpers;
29
30mod parsers;
31
32use std::path::Path;
33use std::fs::File;
34use std::io;
35use std::io::Read;
36
37/// A parsing error
38#[derive(Debug)]
39pub struct Error;
40
41impl From<io::Error> for Error {
42    fn from(_: io::Error) -> Error {
43        Error
44    }
45}
46
47/// Parse the bytes and return a vec of key/value pairs. The order of the
48/// elements in the parsed content is preserved.
49///
50/// Keys are not guaranteed to be unique.
51///
52/// # Examples
53///
54/// ```
55/// let parsed = dotproperties::parse_from_slice(b"knowledge = power\n1+1 = 2").unwrap();
56/// assert_eq!(parsed, vec![("knowledge".to_string(), "power".to_string()),
57///                         ("1+1".to_string(), "2".to_string())]);
58/// ```
59///
60/// It is often more convenient to work with a map, instead of a vec of pairs.
61/// The conversion can be done using the tools from std.
62///
63/// ```
64/// use std::collections::HashMap;
65///
66/// let parsed = dotproperties::parse_from_slice(b"a:b\nc:d").unwrap();
67/// let mapped : HashMap<_,_> = parsed.into_iter().collect();
68///
69/// ```
70///
71/// Note that if you use `collect` to create a map from a vec containing
72/// duplicate keys, only the value of the last one is retained.
73///
74/// ```
75/// use std::collections::HashMap;
76///
77/// let parsed = dotproperties::parse_from_slice(b"a:x\na:y").unwrap();
78/// let mapped : HashMap<_,_> = parsed.into_iter().collect();
79/// assert_eq!(mapped.len(), 1);
80/// // The `map` converts the `Option<&String>` to an `Option<&str>`
81/// assert_eq!(mapped.get("a").map(|v| &**v), Some("y"));
82///
83/// ```
84///
85/// # Failures
86///
87/// There is no fine-grained error reporting, yet. If the function encounters
88/// a parse error, then an empty struct `Error` is returned.
89///
90pub fn parse_from_slice(input: &[u8]) -> Result<Vec<(String, String)>, Error> {
91    parsers::full_parser(input).to_result().map_err(|_| Error)
92}
93
94/// Parse the file and return a vec of key/value pairs. The order of the
95/// elements in the parsed content is preserved.
96///
97/// Keys are not guaranteed to be unique.
98///
99/// # Examples
100///
101/// ```
102/// # std::fs::File::create("config.properties").unwrap();
103/// let parsed = dotproperties::parse_from_file("config.properties").unwrap();
104/// # std::fs::remove_file("config.properties").unwrap();
105/// ```
106///
107/// It is often more convenient to work with a map, instead of a vec of pairs.
108/// The conversion can be done using the tools from std.
109///
110/// ```
111/// use std::collections::HashMap;
112///
113/// # std::fs::File::create("config.properties").unwrap();
114/// let parsed = dotproperties::parse_from_file("config.properties").unwrap();
115/// let mapped : HashMap<_,_> = parsed.into_iter().collect();
116/// # std::fs::remove_file("config.properties").unwrap();
117///
118/// ```
119///
120/// Note that if you use `collect` to create a map from a vec containing
121/// duplicate keys, only the value of the last one is retained.
122///
123/// # Failures
124///
125/// There is no fine-grained error reporting, yet. If the function encounters
126/// a parse error or an IO error, then an empty struct `Error` is returned.
127///
128pub fn parse_from_file<P: AsRef<Path>>(path: P) -> Result<Vec<(String, String)>, Error> {
129    let mut file = File::open(path)?;
130    let mut contents = vec![];
131    file.read_to_end(&mut contents)?;
132    parse_from_slice(&*contents)
133}