valid_toml 0.0.2

Provides the ability to load a TOML file with validation.
Documentation
/* Copyright 2016 Joshua Gentry
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */
use std::collections::{BTreeMap, LinkedList};

use item_value::ItemValue;
use enums::Warning;

//*************************************************************************************************
/// Contains the verified results from a TOML file.  Only the data elements defined are stored from
/// the TOML file. This object is not created unless the TOML data matches the definition so it is
/// safe to assume required values are present and valid.
pub struct TomlData
{
    //---------------------------------------------------------------------------------------------
    /// The list of warnings that were generated when reading in the TOML file.
    pub warnings : LinkedList<Warning>,

    //---------------------------------------------------------------------------------------------
    /// The data loaded from the TOML file.
    data : BTreeMap<String, ItemValue>
}

impl TomlData
{
    //*********************************************************************************************
    /// Construct a new instance of the object.
    pub fn new(
        data     : BTreeMap<String, ItemValue>,
        warnings : LinkedList<Warning>
        ) -> TomlData
    {
        TomlData {
            warnings : warnings,
            data     : data
        }
    }

    //*********************************************************************************************
    /// Returns a duration (in milliseconds) from the TOML file.  If the value is optional and not
    /// defined then None is returned.
    ///
    /// # Panics
    ///
    /// If the value is defined but not a duration this method will panic since that indicates a
    /// disconnect between the definition and the code reading the values.
    pub fn optional_duration<T:AsRef<str>>(
        &self,
        name : T
        ) -> Option<i64>
    {
        let name = name.as_ref();

        if let Some(val) = self.data.get(&String::from(name))
        {
            if val.is_duration()
            {
                let val = val.get_i64();

                info!("{} => {}", name, val);
                Some(val)
            }
            else
            {
                panic!("Item {} is not an duration element.", name);
            }
        }
        else
        {
            info!("{} => None", name);
            None
        }
    }

    //*********************************************************************************************
    /// Returns an i64 value from the TOML file.  If the value is optional and not defined then
    /// None is returned.
    ///
    /// # Panics
    ///
    /// If the value is defined but not an i64 value this method will panic since that indicates a
    /// disconnect between the definition and the code reading the values.
    pub fn optional_i64<T:AsRef<str>>(
        &self,
        name : T
        ) -> Option<i64>
    {
        let name = name.as_ref();

        if let Some(val) = self.data.get(&String::from(name))
        {
            if val.is_i64()
            {
                let val = val.get_i64();

                info!("{} => {}", name, val);
                Some(val)
            }
            else
            {
                panic!("Item {} is not an i64 element.", name);
            }
        }
        else
        {
            info!("{} => None", name);
            None
        }
    }

    //*********************************************************************************************
    /// Returns an u16 value from the TOML file.  If the value is optional and not defined then
    /// None is returned.
    ///
    /// # Panics
    ///
    /// If the value is defined but not an u16 value this method will panic since that indicates a
    /// disconnect between the definition and the code reading the values.
    pub fn optional_u16<T:AsRef<str>>(
        &self,
        name : T
        ) -> Option<u16>
    {
        let name = name.as_ref();

        if let Some(val) = self.data.get(&String::from(name))
        {
            if val.is_u16()
            {
                let val = val.get_u16();

                info!("{} => {}", name, val);
                Some(val)
            }
            else
            {
                panic!("Item {} is not an u16 element.", name);
            }
        }
        else
        {
            info!("{} => None", name);
            None
        }
    }

    //*********************************************************************************************
    /// Returns an usize value from the TOML file.  If the value is optional and not defined then
    /// None is returned.
    ///
    /// # Panics
    ///
    /// If the value is defined but not an usize value this method will panic since that indicates
    /// a disconnect between the definition and the code reading the values.
    pub fn optional_usize<T:AsRef<str>>(
        &self,
        name : T
        ) -> Option<usize>
    {
        let name = name.as_ref();

        if let Some(val) = self.data.get(&String::from(name))
        {
            if val.is_usize()
            {
                let val = val.get_usize();

                info!("{} => {}", name, val);
                Some(val)
            }
            else
            {
                panic!("Item {} is not an usize element.", name);
            }
        }
        else
        {
            info!("{} => None", name);
            None
        }
    }

    //*********************************************************************************************
    /// Returns an string value from the TOML file.  If the value is optional and not defined then
    /// None is returned.
    ///
    /// # Panics
    ///
    /// If the value is defined but not a string value this method will panic since that indicates
    /// a disconnect between the definition and the code reading the values.
    pub fn optional_str<'a, T:AsRef<str>>(
        &'a self,
        name : T
        ) -> Option<&'a str>
    {
        let name = name.as_ref();

        if let Some(val) = self.data.get(&String::from(name))
        {
            if val.is_str()
            {
                let val = val.get_str();

                info!("{} => [{}]", name, val);
                Some(val)
            }
            else
            {
                panic!("Item {} is not an string element.", name);
            }
        }
        else
        {
            info!("{} => None", name);
            None
        }
    }

    //*********************************************************************************************
    /// Returns a required duration.
    ///
    /// # Panics
    ///
    /// If the value is defined but not a duration this method will panic since that indicates
    /// a disconnect between the definition and the code reading the values.
    ///
    /// If the value doesn't exist then this method will panic since that means the value is not
    /// actually required.
    pub fn get_duration<T:AsRef<str>>(
        &self,
        name : T
        ) -> i64
    {
        let name = name.as_ref();

        if let Some(val) = self.optional_duration(name)
        {
            val
        }
        else
        {
            panic!("Item {} does not exist.", name);
        }
    }

    //*********************************************************************************************
    /// Returns a required i64 value.
    ///
    /// # Panics
    ///
    /// If the value is defined but not an i64 value this method will panic since that indicates
    /// a disconnect between the definition and the code reading the values.
    ///
    /// If the value doesn't exist then this method will panic since that means the value is not
    /// actually required.
    pub fn get_i64<T:AsRef<str>>(
        &self,
        name : T
        ) -> i64
    {
        let name = name.as_ref();

        if let Some(val) = self.optional_i64(name)
        {
            val
        }
        else
        {
            panic!("Item {} does not exist.", name);
        }
    }

    //*********************************************************************************************
    /// Returns a required u16 value.
    ///
    /// # Panics
    ///
    /// If the value is defined but not an u16 value this method will panic since that indicates
    /// a disconnect between the definition and the code reading the values.
    ///
    /// If the value doesn't exist then this method will panic since that means the value is not
    /// actually required.
    pub fn get_u16<T:AsRef<str>>(
        &self,
        name : T
        ) -> u16
    {
        let name = name.as_ref();

        if let Some(val) = self.optional_u16(name)
        {
            val
        }
        else
        {
            panic!("Item {} does not exist.", name);
        }
    }

    //*********************************************************************************************
    /// Returns a required usize value.
    ///
    /// # Panics
    ///
    /// If the value is defined but not an usize value this method will panic since that indicates
    /// a disconnect between the definition and the code reading the values.
    ///
    /// If the value doesn't exist then this method will panic since that means the value is not
    /// actually required.
    pub fn get_usize<T:AsRef<str>>(
        &self,
        name : T
        ) -> usize
    {
        let name = name.as_ref();

        if let Some(val) = self.optional_usize(name)
        {
            val
        }
        else
        {
            panic!("Item {} does not exist.", name);
        }
    }

    //*********************************************************************************************
    /// Returns a required string value.
    ///
    /// # Panics
    ///
    /// If the value is defined but not a string value this method will panic since that indicates
    /// a disconnect between the definition and the code reading the values.
    ///
    /// If the value doesn't exist then this method will panic since that means the value is not
    /// actually required.
    pub fn get_str<'a, T:AsRef<str>>(
        &'a self,
        name : T
        ) -> &'a str
    {
        let name = name.as_ref();

        if let Some(val) = self.optional_str(name)
        {
            val
        }
        else
        {
            panic!("Item {} does not exist.", name);
        }
    }
}