pml 0.6.1

A parser for PML, just another format to specify your configs in
Documentation
use std::{collections::HashMap, io::Error as IoError, num::{ParseFloatError, ParseIntError}};

mod impls;
pub mod parse;

mod elem {
    use crate::PmlStruct;

    #[derive(Debug, Clone)]
    pub enum Element {
        PmlArray(ArrayElement),
        PmlBool(bool),
        PmlString(String),
        PmlStruct(Box<PmlStruct>),
        PmlF32(f32),
        PmlF64(f64),
        PmlI8(i8),
        PmlI16(i16),
        PmlI32(i32),
        PmlI64(i64),
        PmlI128(i128),
        PmlU8(u8),
        PmlU16(u16),
        PmlU32(u32),
        PmlU64(u64),
        PmlU128(u128),
    }

    #[derive(Debug, Clone)]
    pub enum ArrayElement {
        PmlBool(Vec<bool>),
        PmlStruct(Vec<PmlStruct>),
        PmlString(Vec<String>),
        PmlF32(Vec<f32>),
        PmlF64(Vec<f64>),
        PmlI8(Vec<i8>),
        PmlI16(Vec<i16>),
        PmlI32(Vec<i32>),
        PmlI64(Vec<i64>),
        PmlI128(Vec<i128>),
        PmlU8(Vec<u8>),
        PmlU16(Vec<u16>),
        PmlU32(Vec<u32>),
        PmlU64(Vec<u64>),
        PmlU128(Vec<u128>),
    }
}
use elem::Element;

#[derive(Clone, Debug)]
pub struct PmlStruct {
    elements: HashMap<String, Element>,
}

#[derive(Debug)]
pub enum ParseNumberError {
    Int(ParseIntError),
    Float(ParseFloatError)
}

#[derive(Debug)]
pub enum Error {
    AlreadyExists {
        key: String,
    },
    CircularDependency(Vec<String>),
    FileAccess(IoError),
    InvalidKey,
    IllegalCharacter{
        char: char,
        line: u32,
        col: u32
    },
    IllegalDependency,
    NotAnExistingStruct(String),
    ParseNumberError{
        line: u32,
        value: String,
        error: ParseNumberError
    },
    UnexpectedEOF,
    UnfulfilledDependency{
        key: String,
        dependency: String
    },
    UnknownForcedType{
        key: String,
        type_name: String
    }
}

pub enum GetError {
    DoesNotExits,
    InvalidType
}

impl<'a> PmlStruct {
    pub fn get<T>(&'a self, key: &str) -> Result<T, GetError>
        where
        T: TryFrom<&'a Element, Error = GetError>
        {
            match key.split_once('.') {
                None => match self.elements.get(key).map(|elem| T::try_from(elem)) {
                    None => Err(GetError::DoesNotExits),
                    Some(res) => res
                }
                Some((first, rest)) => match self.elements.get(first) {
                    Some(Element::PmlStruct(s)) => s.get::<T>(rest),
                    Some(_) => Err(GetError::InvalidType),
                    None => Err(GetError::DoesNotExits)
                }
            }
        }

    pub fn add<T>(&mut self, key: String, elem: T) -> Result<(), Error>
        where
        T: Into<Element>
        {
            if key.starts_with('.') || key.ends_with('.') || key.is_empty() {
                return Err(Error::InvalidKey);
            }
            match key.split_once('.') {
                None => {
                    match self.elements.insert(key.clone(), elem.into()) {
                        Some(_) => Err(Error::AlreadyExists{key}),
                        None => Ok(())
                    }
                }
                Some((first, rest)) => match self.elements.get_mut(first) {
                    Some(Element::PmlStruct(s)) => s.add(String::from(rest), elem),
                    _ => Err(Error::NotAnExistingStruct(String::from(first)))
                }
            }
        }
}