dotproperties 0.1.0

Parser for the Java .properties file format
Documentation
//! A crate to parse the Java Properties file format.
//!
//! The Properties file format is simple key/value text format that can be read
//! and written by the standard library of Java. It is often used for
//! configuration files, and also for translation files (Bundles).
//!
//! The Java class that supports this format is `java.util.Properties`, with
//! its methods `load` and `store`. Note that the Java class also provides the
//! methods `loadFromXML` and `storeToXML`, but this crate does not support
//! the XML format.
//!
//! Starting from Java 9, the Properties files used as Resource Bundles are
//! allowed to be utf-8, instead of only latin1 with unicode escapes ([JEP
//! 226](http://openjdk.java.net/jeps/226)). This crate does not support JEP
//! 226.
//!
//! This crate was written based on the [Java 8 API
//! reference](https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader-).
//! As far as the author knows, this crate supports reading the full Properties
//! format with no exception. There is no support to write Properties files,
//! yet.

#[macro_use]
extern crate nom;

#[macro_use]
#[cfg(test)]
mod test_helpers;

mod parsers;

use std::path::Path;
use std::fs::File;
use std::io;
use std::io::Read;

/// A parsing error
#[derive(Debug)]
pub struct Error;

impl From<io::Error> for Error {
    fn from(_: io::Error) -> Error {
        Error
    }
}

/// Parse the bytes and return a vec of key/value pairs. The order of the
/// elements in the parsed content is preserved.
///
/// Keys are not guaranteed to be unique.
///
/// # Examples
///
/// ```
/// let parsed = dotproperties::parse_from_slice(b"knowledge = power\n1+1 = 2").unwrap();
/// assert_eq!(parsed, vec![("knowledge".to_string(), "power".to_string()),
///                         ("1+1".to_string(), "2".to_string())]);
/// ```
///
/// It is often more convenient to work with a map, instead of a vec of pairs.
/// The conversion can be done using the tools from std.
///
/// ```
/// use std::collections::HashMap;
///
/// let parsed = dotproperties::parse_from_slice(b"a:b\nc:d").unwrap();
/// let mapped : HashMap<_,_> = parsed.into_iter().collect();
///
/// ```
///
/// Note that if you use `collect` to create a map from a vec containing
/// duplicate keys, only the value of the last one is retained.
///
/// ```
/// use std::collections::HashMap;
///
/// let parsed = dotproperties::parse_from_slice(b"a:x\na:y").unwrap();
/// let mapped : HashMap<_,_> = parsed.into_iter().collect();
/// assert_eq!(mapped.len(), 1);
/// // The `map` converts the `Option<&String>` to an `Option<&str>`
/// assert_eq!(mapped.get("a").map(|v| &**v), Some("y"));
///
/// ```
///
/// # Failures
///
/// There is no fine-grained error reporting, yet. If the function encounters
/// a parse error, then an empty struct `Error` is returned.
///
pub fn parse_from_slice(input: &[u8]) -> Result<Vec<(String, String)>, Error> {
    parsers::full_parser(input).to_result().map_err(|_| Error)
}

/// Parse the file and return a vec of key/value pairs. The order of the
/// elements in the parsed content is preserved.
///
/// Keys are not guaranteed to be unique.
///
/// # Examples
///
/// ```
/// # std::fs::File::create("config.properties").unwrap();
/// let parsed = dotproperties::parse_from_file("config.properties").unwrap();
/// # std::fs::remove_file("config.properties").unwrap();
/// ```
///
/// It is often more convenient to work with a map, instead of a vec of pairs.
/// The conversion can be done using the tools from std.
///
/// ```
/// use std::collections::HashMap;
///
/// # std::fs::File::create("config.properties").unwrap();
/// let parsed = dotproperties::parse_from_file("config.properties").unwrap();
/// let mapped : HashMap<_,_> = parsed.into_iter().collect();
/// # std::fs::remove_file("config.properties").unwrap();
///
/// ```
///
/// Note that if you use `collect` to create a map from a vec containing
/// duplicate keys, only the value of the last one is retained.
///
/// # Failures
///
/// There is no fine-grained error reporting, yet. If the function encounters
/// a parse error or an IO error, then an empty struct `Error` is returned.
///
pub fn parse_from_file<P: AsRef<Path>>(path: P) -> Result<Vec<(String, String)>, Error> {
    let mut file = File::open(path)?;
    let mut contents = vec![];
    file.read_to_end(&mut contents)?;
    parse_from_slice(&*contents)
}