cog-idl 0.1.1

Parser and validator for Cog IDL.
Documentation
mod parser;

pub use parser::ParseError;

use std::{
    fs::{read_dir, read_to_string},
    path::Path,
};

use parser::parse_module;

pub fn load_api_from_dir<P: AsRef<Path>>(path: P) -> Result<Api, ParseError> {
    let mut api = Api {
        modules: Vec::new(),
    };

    for path in read_dir(path).unwrap() {
        let path = path.unwrap().path();

        let module_name = path.file_stem().unwrap().to_str().unwrap();

        let module_str = read_to_string(&path).unwrap();
        let module = load_module_from_str(module_name, &module_str)?;

        api.modules.push(module);
    }

    Ok(api)
}

pub fn load_module_from_str<S: ToString>(name: S, cog: &str) -> Result<Module, ParseError> {
    parse_module(name.to_string(), cog)
}

#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Api {
    pub modules: Vec<Module>,
}

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Module {
    pub name: String,
    pub documentation: Option<String>,
    pub interfaces: Vec<Interface>,
}

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Interface {
    pub name: String,
    pub documentation: Option<String>,
    pub functions: Vec<Function>,
}

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Function {
    pub name: String,
    pub documentation: Option<String>,
    pub parameters: Vec<Parameter>,
    pub return_type: Option<Type>,
}

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Parameter {
    pub name: String,
    pub type_: Type,
}

#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Type {
    pub modifier: TypeModifier,
    pub type_name: TypeName,
}

#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TypeModifier {
    None,
    Pointer,
    Reference,
}

#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TypeName {
    CString,
    Any,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn single_interface() {
        let code = "interface foo { fn bar(); }";
        let result = load_module_from_str("test", &code);

        assert!(result.is_ok());

        let module = result.unwrap();

        assert_eq!(module.interfaces.len(), 1);

        let interface = &module.interfaces[0];
        assert_eq!(interface.name, "foo");
        assert_eq!(interface.functions.len(), 1);

        let function = &interface.functions[0];
        assert_eq!(function.name, "bar");
    }

    #[test]
    fn comment_at_end_of_file() {
        let code = "// comment";
        let result = load_module_from_str("test", &code);

        assert!(result.is_ok());
    }
}