pocketsphinx 0.6.0

Rust wrapper for libpocketsphinx
Documentation
use bindings;

use std;
use std::ptr;
use std::ffi::{CStr, CString, OsStr};

use std::os::unix::ffi::OsStrExt;

use super::{Error, Result};

pub mod internal {
    use std;
    use bindings;
    use libc::c_char;
    use std::ffi::CStr;

    #[derive(Clone)]
    pub struct Tags<'a> {
        node: bindings::glist_t,
        _marker: std::marker::PhantomData<&'a str>,
    }

    impl<'a> Tags<'a> {
        pub fn new(node: bindings::glist_t) -> Self {
            Tags { node: node, _marker: std::marker::PhantomData }
        }
    }

    impl<'a> Iterator for Tags<'a> {
        type Item = &'a str;

        fn next(&mut self) -> Option<Self::Item> {
            if self.node.is_null() {
                return None
            }

            let tag = unsafe { CStr::from_ptr((*self.node).data.as_ptr() as *const c_char) };
            self.node = unsafe { (*self.node).next };
            Some(tag.to_str().unwrap())
        }
    }

    #[derive(Clone)]
    pub struct Atom<'a> {
        raw: *const bindings::internal::jsgf_atom_t,
        _marker: std::marker::PhantomData<&'a str>,
    }

    impl<'a> Atom<'a> {
        pub fn new(raw: *const bindings::internal::jsgf_atom_t) -> Self {
            Atom { raw: raw, _marker: std::marker::PhantomData }
        }

        pub fn name(&self) -> &'a str {
            unsafe { CStr::from_ptr((*self.raw).name).to_str().unwrap() }
        }

        pub fn tags(&self) -> Tags<'a>  {
            Tags::new(unsafe { (*self.raw).tags })
        }
    }

    #[derive(Clone)]
    pub struct Atoms<'a> {
        node: bindings::glist_t,
        _marker: std::marker::PhantomData<&'a str>,
    }

    impl<'a> Atoms<'a> {
        fn new(node: bindings::glist_t) -> Self {
            Atoms { node: node, _marker: std::marker::PhantomData }
        }
    }

    impl<'a> Iterator for Atoms<'a> {
        type Item = Atom<'a>;

        fn next(&mut self) -> Option<Self::Item> {
            if self.node.is_null() {
                return None
            }

            let atom = Atom::new(unsafe {
                (*self.node).data.as_ptr() as *const bindings::internal::jsgf_atom_t
            });
            self.node = unsafe { (*self.node).next };
            Some(atom)
        }
    }

    #[derive(Clone)]
    pub struct Alternatives<'a> {
        node: *const bindings::internal::jsgf_rhs_t,
        _marker: std::marker::PhantomData<&'a str>,
    }

    impl<'a> Alternatives<'a> {
        fn new(node: *const bindings::internal::jsgf_rhs_t) -> Self {
            Alternatives { node: node, _marker: std::marker::PhantomData }
        }
    }

    impl<'a> Iterator for Alternatives<'a> {
        type Item = Atoms<'a>;

        fn next(&mut self) -> Option<Self::Item> {
            if self.node.is_null() {
                return None;
            }

            let atoms = Atoms::new(unsafe { (*self.node).atoms });
            self.node = unsafe { (*self.node).alt };
            Some(atoms)
        }
    }

    #[derive(Clone)]
    pub struct RuleData<'a> {
        raw: *const bindings::internal::jsgf_rule_s,
        _marker: std::marker::PhantomData<&'a super::Jsgf>,
    }

    impl<'a> RuleData<'a> {
        pub fn new(raw: *const bindings::internal::jsgf_rule_s) -> Self {
            RuleData { raw: raw, _marker: std::marker::PhantomData }
        }

        pub fn alternatives(&self) -> Alternatives<'a> {
            Alternatives::new(unsafe { (*self.raw).rhs })
        }
    }
}

#[derive(Clone)]
pub struct Rule<'a> {
    raw: *const bindings::jsgf_rule_t,
    _marker: std::marker::PhantomData<&'a str>,
}

impl<'a> Rule<'a> {
    fn new(raw: *const bindings::jsgf_rule_t) -> Self {
        Rule { raw: raw, _marker: std::marker::PhantomData }
    }

    pub fn name(&self) -> &'a str {
        let name_c = unsafe { bindings::jsgf_rule_name(self.raw) };
        unsafe { CStr::from_ptr(name_c) }.to_str().unwrap()
    }

    pub fn is_public(&self) -> bool {
        let res = unsafe { bindings::jsgf_rule_public(self.raw) };
        res != 0
    }

    pub unsafe fn internal(&self) -> internal::RuleData<'a> {
        internal::RuleData::new(self.raw as *const bindings::internal::jsgf_rule_s)
    }
}

pub struct Rules<'a> {
    raw: *const bindings::jsgf_rule_iter_t,
    _marker: std::marker::PhantomData<&'a str>,
}

impl<'a> Rules<'a> {
    pub fn new(raw: *const bindings::jsgf_rule_iter_t) -> Self {
        Rules { raw: raw, _marker: std::marker::PhantomData }
    }
}

impl<'a> Drop for Rules<'a> {
    fn drop(&mut self) {
        if !self.raw.is_null() {
            unsafe { bindings::jsgf_rule_iter_free(self.raw) };
        }
    }
}

impl<'a> Iterator for Rules<'a> {
    type Item = Rule<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.raw.is_null() {
            None
        } else {
            let item = Rule::new(unsafe { bindings::jsgf_rule_iter_rule(self.raw) });
            self.raw = unsafe { bindings::jsgf_rule_iter_next(self.raw) };
            Some(item)
        }
    }
}

pub struct Jsgf {
    raw: *mut bindings::jsgf_t,
}

impl Jsgf {
    pub fn parse_file(filename: &OsStr) -> Result<Self> {
        let filename_c = CString::new(filename.as_bytes()).unwrap();
        let raw = unsafe { bindings::jsgf_parse_file(filename_c.as_ptr(), ptr::null()) };
        if raw.is_null() {
            Err(Error)
        } else {
            Ok(Jsgf { raw: raw })
        }
    }

    pub fn parse_string(s: &str) -> Result<Self> {
        let s_c = CString::new(s.as_bytes()).unwrap();
        let raw = unsafe { bindings::jsgf_parse_string(s_c.as_ptr(), ptr::null()) };
        if raw.is_null() {
            Err(Error)
        } else {
            Ok(Jsgf { raw: raw })
        }
    }

    pub fn name(&self) -> &str {
        let name_c = unsafe { bindings::jsgf_grammar_name(self.raw) };
        assert!(!name_c.is_null());
        unsafe { CStr::from_ptr(name_c) }.to_str().unwrap()
    }

    pub fn rules(&self) -> Rules {
        let raw_rules_iter = unsafe { bindings::jsgf_rule_iter(self.raw) };
        assert!(!raw_rules_iter.is_null());
        Rules::new(raw_rules_iter)
    }

    pub fn public_rule(&self) -> Rule {
        Rule::new(unsafe { bindings::jsgf_get_public_rule(self.raw) })
    }

    pub fn rule<'a>(&'a self, name: &str) -> Option<Rule<'a>> {
        let name_c = CString::new(name).unwrap();
        let raw_rule = unsafe { bindings::jsgf_get_rule(self.raw, name_c.as_ptr()) };
        if raw_rule.is_null() {
            None
        } else {
            Some(Rule::new(raw_rule))
        }
    }
}

impl Drop for Jsgf {
    fn drop(&mut self) {
        unsafe { bindings::jsgf_grammar_free(self.raw) }
    }
}