<commit_before>//! Create or redefine SQL functions
use std::ffi::CStr;
use std::mem;
use std::slice;
use std::str;
use libc::{c_int, c_double, c_char, c_void};

use ffi;
pub use ffi::sqlite3_context;
pub use ffi::sqlite3_value;
pub use ffi::sqlite3_value_type;
pub use ffi::sqlite3_value_numeric_type;

use types::Null;

use {SqliteResult, SqliteError, SqliteConnection, str_to_cstring, InnerSqliteConnection};

/// A trait for types that can be converted into the result of an SQL function.
pub trait ToResult {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context);
}

macro_rules! raw_to_impl(
    ($t:ty, $f:ident) => (
        impl ToResult for $t {
            unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
                ffi::$f(ctx, *self)
            }
        }
    )
);

raw_to_impl!(c_int, sqlite3_result_int);
raw_to_impl!(i64, sqlite3_result_int64);
raw_to_impl!(c_double, sqlite3_result_double);

impl<'a> ToResult for bool {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            true => ffi::sqlite3_result_int(ctx, 1),
            _ => ffi::sqlite3_result_int(ctx, 0),
        }
    }
}

impl<'a> ToResult for &'a str {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        let length = self.len();
        if length > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return;
        }
        match str_to_cstring(self) {
            Ok(c_str) => {
                ffi::sqlite3_result_text(ctx,
                                         c_str.as_ptr(),
                                         length as c_int,
                                         ffi::SQLITE_TRANSIENT())
            }
            Err(_) => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), // TODO sqlite3_result_error
        }
    }
}

impl ToResult for String {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<'a> ToResult for &'a [u8] {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        if self.len() > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return;
        }
        ffi::sqlite3_result_blob(ctx,
                                 mem::transmute(self.as_ptr()),
                                 self.len() as c_int,
                                 ffi::SQLITE_TRANSIENT())
    }
}

impl ToResult for Vec<u8> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<T: ToResult> ToResult for Option<T> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            None => ffi::sqlite3_result_null(ctx),
            Some(ref t) => t.set_result(ctx),
        }
    }
}

impl ToResult for Null {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        ffi::sqlite3_result_null(ctx)
    }
}

// sqlite3_result_error_code, c_int
// sqlite3_result_error_nomem
// sqlite3_result_error_toobig
// sqlite3_result_error, *const c_char, c_int
// sqlite3_result_zeroblob
// sqlite3_result_value

/// A trait for types that can be created from a SQLite function parameter value.
pub trait FromValue: Sized {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Self>;

    /// FromValue types can implement this method and use sqlite3_value_type to check that
    /// the type reported by SQLite matches a type suitable for Self. This method is used
    /// by `???` to confirm that the parameter contains a valid type before
    /// attempting to retrieve the value.
    unsafe fn parameter_has_valid_sqlite_type(_: *mut sqlite3_value) -> bool {
        true
    }
}

macro_rules! raw_from_impl(
    ($t:ty, $f:ident, $c:expr) => (
        impl FromValue for $t {
            unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<$t> {
                Ok(ffi::$f(v))
            }

            unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
                sqlite3_value_numeric_type(v) == $c
            }
        }
    )
);

raw_from_impl!(c_int, sqlite3_value_int, ffi::SQLITE_INTEGER);
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);

impl FromValue for bool {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<bool> {
        match ffi::sqlite3_value_int(v) {
            0 => Ok(false),
            _ => Ok(true),
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for c_double {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<c_double> {
        Ok(ffi::sqlite3_value_double(v))
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_FLOAT ||
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for String {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<String> {
        let c_text = ffi::sqlite3_value_text(v);
        if c_text.is_null() {
            Ok("".to_string())
        } else {
            let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
            let utf8_str = str::from_utf8(c_slice);
            utf8_str.map(|s| s.to_string())
                    .map_err(|e| {
                        SqliteError {
                            code: 0,
                            message: e.to_string(),
                        }
                    })
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_TEXT
    }
}

impl FromValue for Vec<u8> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Vec<u8>> {
        use std::slice::from_raw_parts;
        let c_blob = ffi::sqlite3_value_blob(v);
        let len = ffi::sqlite3_value_bytes(v);

        assert!(len >= 0,
                "unexpected negative return from sqlite3_value_bytes");
        let len = len as usize;

        Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_BLOB
    }
}

impl<T: FromValue> FromValue for Option<T> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Option<T>> {
        if sqlite3_value_type(v) == ffi::SQLITE_NULL {
            Ok(None)
        } else {
            FromValue::parameter_value(v).map(|t| Some(t))
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_NULL || T::parameter_has_valid_sqlite_type(v)
    }
}

// sqlite3_user_data
// sqlite3_get_auxdata
// sqlite3_set_auxdata

unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
    let _: Box<T> = Box::from_raw(mem::transmute(p));
}

pub struct Context<'a> {
    pub ctx: *mut sqlite3_context,
    args: &'a [*mut sqlite3_value],
}

impl<'a> Context<'a> {
    pub fn len(&self) -> usize {
        self.args.len()
    }

    pub fn get<T: FromValue>(&self, idx: usize) -> SqliteResult<T> {
        let arg = self.args[idx];
        unsafe {
            if T::parameter_has_valid_sqlite_type(arg) {
                T::parameter_value(arg)
            } else {
                Err(SqliteError {
                    code: ffi::SQLITE_MISMATCH,
                    message: "Invalid value type".to_string(),
                })
            }
        }
    }

    pub fn set_aux<T>(&self, arg: c_int, value: T) {
        let boxed = Box::into_raw(Box::new(value));
        unsafe {
            ffi::sqlite3_set_auxdata(self.ctx,
                                     arg,
                                     mem::transmute(boxed),
                                     Some(mem::transmute(free_boxed_value::<T>)))
        };
    }

    pub unsafe fn get_aux<T>(&self, arg: c_int) -> Option<&T> {
        let p = ffi::sqlite3_get_auxdata(self.ctx, arg) as *mut T;
        if p.is_null() {
            None
        } else {
            Some(&*p)
        }
    }
}

impl SqliteConnection {
    pub fn create_scalar_function<F>(&self,
                                     fn_name: &str,
                                     n_arg: c_int,
                                     deterministic: bool,
                                     x_func: F)
                                     -> SqliteResult<()>
        where F: FnMut(&Context)
    {
        self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
    }
}

impl InnerSqliteConnection {
    fn create_scalar_function<F>(&mut self,
                                 fn_name: &str,
                                 n_arg: c_int,
                                 deterministic: bool,
                                 x_func: F)
                                 -> SqliteResult<()>
        where F: FnMut(&Context)
    {
        extern "C" fn call_boxed_closure<F>(ctx: *mut sqlite3_context,
                                            argc: c_int,
                                            argv: *mut *mut sqlite3_value)
            where F: FnMut(&Context)
        {
            unsafe {
                let ctx = Context {
                    ctx: ctx,
                    args: slice::from_raw_parts(argv, argc as usize),
                };
                let boxed_f: *mut F = mem::transmute(ffi::sqlite3_user_data(ctx.ctx));
                assert!(!boxed_f.is_null(), "Internal error - null function pointer");
                (*boxed_f)(&ctx);
            }
        }

        let boxed_f: *mut F = Box::into_raw(Box::new(x_func));
        let c_name = try!(str_to_cstring(fn_name));
        let mut flags = ffi::SQLITE_UTF8;
        if deterministic {
            flags |= ffi::SQLITE_DETERMINISTIC;
        }
        let r = unsafe {
            ffi::sqlite3_create_function_v2(self.db(),
                                            c_name.as_ptr(),
                                            n_arg,
                                            flags,
                                            mem::transmute(boxed_f),
                                            Some(call_boxed_closure::<F>),
                                            None,
                                            None,
                                            Some(mem::transmute(free_boxed_value::<F>)))
        };
        self.decode_result(r)
    }
}

#[cfg(test)]
mod test {
    extern crate regex;

    use std::ffi::CString;
    use libc::c_double;
    use self::regex::Regex;

    use SqliteConnection;
    use ffi;
    use functions::{Context, ToResult};

    fn half(ctx: &Context) {
        assert!(ctx.len() == 1, "called with unexpected number of arguments");
        match ctx.get::<c_double>(0) {
            Ok(value) => unsafe { (value / 2f64).set_result(ctx.ctx) },
            Err(err) => unsafe { ffi::sqlite3_result_error_code(ctx.ctx, err.code) },
        }
    }

    #[test]
    fn test_function_half() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("half", 1, true, half).unwrap();
        let result = db.query_row("SELECT half(6)", &[], |r| r.get::<f64>(0));

        assert_eq!(3f64, result.unwrap());
    }

    fn regexp(ctx: &Context) {
        assert!(ctx.len() == 2, "called with unexpected number of arguments");

        let saved_re: Option<&Regex> = unsafe { ctx.get_aux(0) };
        let new_re = match saved_re {
            None => unsafe {
                let raw = ctx.get::<String>(0);
                if raw.is_err() {
                    let msg = CString::new(format!("{}", raw.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx.ctx, msg.as_ptr(), -1);
                    return;
                }
                let comp = Regex::new(raw.unwrap().as_ref());
                if comp.is_err() {
                    let msg = CString::new(format!("{}", comp.unwrap_err())).unwrap();
                    ffi::sqlite3_result_error(ctx.ctx, msg.as_ptr(), -1);
                    return;
                }
                Some(comp.unwrap())
            },
            Some(_) => None,
        };

        {
            let re = saved_re.unwrap_or_else(|| new_re.as_ref().unwrap());

            let text = ctx.get::<String>(1);
            if text.is_ok() {
                let text = text.unwrap();
                unsafe {
                    re.is_match(text.as_ref()).set_result(ctx.ctx);
                }
            } else {
                let msg = CString::new(format!("{}", text.unwrap_err())).unwrap();
                unsafe {
                    ffi::sqlite3_result_error(ctx.ctx, msg.as_ptr(), -1);
                }
                return;
            }
        }

        if let Some(re) = new_re {
            ctx.set_aux(0, re);
        }
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_function_regexp() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.execute_batch("BEGIN;
                         CREATE TABLE foo (x string);
                         INSERT INTO foo VALUES ('lisa');
                         INSERT INTO foo VALUES ('lXsi');
                         INSERT INTO foo VALUES ('lisX');
                         END;").unwrap();
        db.create_scalar_function("regexp", 2, true, regexp).unwrap();

        let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
                                  &[],
                                  |r| r.get::<bool>(0));

        assert_eq!(true, result.unwrap());

        let result = db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1",
                                  &[],
                                  |r| r.get::<i64>(0));

        assert_eq!(2, result.unwrap());
    }
}
<commit_msg>Allow user scalar functions to return results.<commit_after>//! Create or redefine SQL functions
use std::ffi::CStr;
use std::mem;
use std::slice;
use std::str;
use libc::{c_int, c_double, c_char, c_void};

use ffi;
pub use ffi::sqlite3_context;
pub use ffi::sqlite3_value;
pub use ffi::sqlite3_value_type;
pub use ffi::sqlite3_value_numeric_type;

use types::Null;

use {SqliteResult, SqliteError, SqliteConnection, str_to_cstring, InnerSqliteConnection};

/// A trait for types that can be converted into the result of an SQL function.
pub trait ToResult {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context);
}

macro_rules! raw_to_impl(
    ($t:ty, $f:ident) => (
        impl ToResult for $t {
            unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
                ffi::$f(ctx, *self)
            }
        }
    )
);

raw_to_impl!(c_int, sqlite3_result_int);
raw_to_impl!(i64, sqlite3_result_int64);
raw_to_impl!(c_double, sqlite3_result_double);

impl<'a> ToResult for bool {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            true => ffi::sqlite3_result_int(ctx, 1),
            _ => ffi::sqlite3_result_int(ctx, 0),
        }
    }
}

impl<'a> ToResult for &'a str {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        let length = self.len();
        if length > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return;
        }
        match str_to_cstring(self) {
            Ok(c_str) => {
                ffi::sqlite3_result_text(ctx,
                                         c_str.as_ptr(),
                                         length as c_int,
                                         ffi::SQLITE_TRANSIENT())
            }
            Err(_) => ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_MISUSE), // TODO sqlite3_result_error
        }
    }
}

impl ToResult for String {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<'a> ToResult for &'a [u8] {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        if self.len() > ::std::i32::MAX as usize {
            ffi::sqlite3_result_error_toobig(ctx);
            return;
        }
        ffi::sqlite3_result_blob(ctx,
                                 mem::transmute(self.as_ptr()),
                                 self.len() as c_int,
                                 ffi::SQLITE_TRANSIENT())
    }
}

impl ToResult for Vec<u8> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        (&self[..]).set_result(ctx)
    }
}

impl<T: ToResult> ToResult for Option<T> {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        match *self {
            None => ffi::sqlite3_result_null(ctx),
            Some(ref t) => t.set_result(ctx),
        }
    }
}

impl ToResult for Null {
    unsafe fn set_result(&self, ctx: *mut sqlite3_context) {
        ffi::sqlite3_result_null(ctx)
    }
}

// sqlite3_result_error_code, c_int
// sqlite3_result_error_nomem
// sqlite3_result_error_toobig
// sqlite3_result_error, *const c_char, c_int
// sqlite3_result_zeroblob
// sqlite3_result_value

/// A trait for types that can be created from a SQLite function parameter value.
pub trait FromValue: Sized {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Self>;

    /// FromValue types can implement this method and use sqlite3_value_type to check that
    /// the type reported by SQLite matches a type suitable for Self. This method is used
    /// by `???` to confirm that the parameter contains a valid type before
    /// attempting to retrieve the value.
    unsafe fn parameter_has_valid_sqlite_type(_: *mut sqlite3_value) -> bool {
        true
    }
}

macro_rules! raw_from_impl(
    ($t:ty, $f:ident, $c:expr) => (
        impl FromValue for $t {
            unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<$t> {
                Ok(ffi::$f(v))
            }

            unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
                sqlite3_value_numeric_type(v) == $c
            }
        }
    )
);

raw_from_impl!(c_int, sqlite3_value_int, ffi::SQLITE_INTEGER);
raw_from_impl!(i64, sqlite3_value_int64, ffi::SQLITE_INTEGER);

impl FromValue for bool {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<bool> {
        match ffi::sqlite3_value_int(v) {
            0 => Ok(false),
            _ => Ok(true),
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for c_double {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<c_double> {
        Ok(ffi::sqlite3_value_double(v))
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_numeric_type(v) == ffi::SQLITE_FLOAT ||
        sqlite3_value_numeric_type(v) == ffi::SQLITE_INTEGER
    }
}

impl FromValue for String {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<String> {
        let c_text = ffi::sqlite3_value_text(v);
        if c_text.is_null() {
            Ok("".to_string())
        } else {
            let c_slice = CStr::from_ptr(c_text as *const c_char).to_bytes();
            let utf8_str = str::from_utf8(c_slice);
            utf8_str.map(|s| s.to_string())
                    .map_err(|e| {
                        SqliteError {
                            code: 0,
                            message: e.to_string(),
                        }
                    })
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_TEXT
    }
}

impl FromValue for Vec<u8> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Vec<u8>> {
        use std::slice::from_raw_parts;
        let c_blob = ffi::sqlite3_value_blob(v);
        let len = ffi::sqlite3_value_bytes(v);

        assert!(len >= 0,
                "unexpected negative return from sqlite3_value_bytes");
        let len = len as usize;

        Ok(from_raw_parts(mem::transmute(c_blob), len).to_vec())
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_BLOB
    }
}

impl<T: FromValue> FromValue for Option<T> {
    unsafe fn parameter_value(v: *mut sqlite3_value) -> SqliteResult<Option<T>> {
        if sqlite3_value_type(v) == ffi::SQLITE_NULL {
            Ok(None)
        } else {
            FromValue::parameter_value(v).map(|t| Some(t))
        }
    }

    unsafe fn parameter_has_valid_sqlite_type(v: *mut sqlite3_value) -> bool {
        sqlite3_value_type(v) == ffi::SQLITE_NULL || T::parameter_has_valid_sqlite_type(v)
    }
}

unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
    let _: Box<T> = Box::from_raw(mem::transmute(p));
}

pub struct Context<'a> {
    ctx: *mut sqlite3_context,
    args: &'a [*mut sqlite3_value],
}

impl<'a> Context<'a> {
    pub fn len(&self) -> usize {
        self.args.len()
    }

    pub fn get<T: FromValue>(&self, idx: usize) -> SqliteResult<T> {
        let arg = self.args[idx];
        unsafe {
            if T::parameter_has_valid_sqlite_type(arg) {
                T::parameter_value(arg)
            } else {
                Err(SqliteError {
                    code: ffi::SQLITE_MISMATCH,
                    message: "Invalid value type".to_string(),
                })
            }
        }
    }

    pub fn set_aux<T>(&self, arg: c_int, value: T) {
        let boxed = Box::into_raw(Box::new(value));
        unsafe {
            ffi::sqlite3_set_auxdata(self.ctx,
                                     arg,
                                     mem::transmute(boxed),
                                     Some(mem::transmute(free_boxed_value::<T>)))
        };
    }

    pub unsafe fn get_aux<T>(&self, arg: c_int) -> Option<&T> {
        let p = ffi::sqlite3_get_auxdata(self.ctx, arg) as *mut T;
        if p.is_null() {
            None
        } else {
            Some(&*p)
        }
    }
}

impl SqliteConnection {
    pub fn create_scalar_function<F, T>(&self,
                                        fn_name: &str,
                                        n_arg: c_int,
                                        deterministic: bool,
                                        x_func: F)
                                        -> SqliteResult<()>
        where F: FnMut(&Context) -> SqliteResult<T>,
              T: ToResult
    {
        self.db.borrow_mut().create_scalar_function(fn_name, n_arg, deterministic, x_func)
    }
}

impl InnerSqliteConnection {
    fn create_scalar_function<F, T>(&mut self,
                                    fn_name: &str,
                                    n_arg: c_int,
                                    deterministic: bool,
                                    x_func: F)
                                    -> SqliteResult<()>
        where F: FnMut(&Context) -> SqliteResult<T>,
              T: ToResult
    {
        extern "C" fn call_boxed_closure<F, T>(ctx: *mut sqlite3_context,
                                               argc: c_int,
                                               argv: *mut *mut sqlite3_value)
            where F: FnMut(&Context) -> SqliteResult<T>,
                  T: ToResult
        {
            unsafe {
                let ctx = Context {
                    ctx: ctx,
                    args: slice::from_raw_parts(argv, argc as usize),
                };
                let boxed_f: *mut F = mem::transmute(ffi::sqlite3_user_data(ctx.ctx));
                assert!(!boxed_f.is_null(), "Internal error - null function pointer");
                match (*boxed_f)(&ctx) {
                    Ok(r) => r.set_result(ctx.ctx),
                    Err(e) => {
                        ffi::sqlite3_result_error_code(ctx.ctx, e.code);
                        if let Ok(cstr) = str_to_cstring(&e.message) {
                            ffi::sqlite3_result_error(ctx.ctx, cstr.as_ptr(), -1);
                        }
                    },
                }
            }
        }

        let boxed_f: *mut F = Box::into_raw(Box::new(x_func));
        let c_name = try!(str_to_cstring(fn_name));
        let mut flags = ffi::SQLITE_UTF8;
        if deterministic {
            flags |= ffi::SQLITE_DETERMINISTIC;
        }
        let r = unsafe {
            ffi::sqlite3_create_function_v2(self.db(),
                                            c_name.as_ptr(),
                                            n_arg,
                                            flags,
                                            mem::transmute(boxed_f),
                                            Some(call_boxed_closure::<F, T>),
                                            None,
                                            None,
                                            Some(mem::transmute(free_boxed_value::<F>)))
        };
        self.decode_result(r)
    }
}

#[cfg(test)]
mod test {
    extern crate regex;

    use libc::c_double;
    use self::regex::Regex;

    use {SqliteConnection, SqliteError, SqliteResult};
    use ffi;
    use functions::Context;

    fn half(ctx: &Context) -> SqliteResult<c_double> {
        assert!(ctx.len() == 1, "called with unexpected number of arguments");
        let value = try!(ctx.get::<c_double>(0));
        Ok(value / 2f64)
    }

    #[test]
    fn test_function_half() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.create_scalar_function("half", 1, true, half).unwrap();
        let result = db.query_row("SELECT half(6)", &[], |r| r.get::<f64>(0));

        assert_eq!(3f64, result.unwrap());
    }

    fn regexp(ctx: &Context) -> SqliteResult<bool> {
        assert!(ctx.len() == 2, "called with unexpected number of arguments");

        let saved_re: Option<&Regex> = unsafe { ctx.get_aux(0) };
        let new_re = match saved_re {
            None => {
                let s = try!(ctx.get::<String>(0));
                let r = try!(Regex::new(&s).map_err(|e| SqliteError {
                    code: ffi::SQLITE_ERROR,
                    message: format!("Invalid regular expression: {}", e),
                }));
                Some(r)
            },
            Some(_) => None,
        };

        let is_match = {
            let re = saved_re.unwrap_or_else(|| new_re.as_ref().unwrap());

            let text = try!(ctx.get::<String>(1));
            re.is_match(&text)
        };

        if let Some(re) = new_re {
            ctx.set_aux(0, re);
        }

        Ok(is_match)
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_function_regexp() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.execute_batch("BEGIN;
                         CREATE TABLE foo (x string);
                         INSERT INTO foo VALUES ('lisa');
                         INSERT INTO foo VALUES ('lXsi');
                         INSERT INTO foo VALUES ('lisX');
                         END;").unwrap();
        db.create_scalar_function("regexp", 2, true, regexp).unwrap();

        let result = db.query_row("SELECT regexp('l.s[aeiouy]', 'lisa')",
                                  &[],
                                  |r| r.get::<bool>(0));

        assert_eq!(true, result.unwrap());

        let result = db.query_row("SELECT COUNT(*) FROM foo WHERE regexp('l.s[aeiouy]', x) == 1",
                                  &[],
                                  |r| r.get::<i64>(0));

        assert_eq!(2, result.unwrap());
    }
}
<|endoftext|>


<commit_before>extern crate varlink_parser;

use std::env;
use std::path::{Path, PathBuf};
use std::process::exit;
use std::io::Error as IOError;
use std::error::Error;
use std::io::{Read, Write};
use std::result::Result;
use std::fmt;
use std::collections::HashMap;
use std::iter::FromIterator;
use std::io;
use std::fs::File;

use varlink_parser::{Interface, VStructOrEnum, VType, VTypeExt, Varlink};

type EnumHash<'a> = HashMap<String, Vec<String>>;

trait ToRust {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError>;
}

#[derive(Debug)]
pub enum ToRustError {
    IoError(IOError),
}

impl Error for ToRustError {
    fn description(&self) -> &str {
        match *self {
            ToRustError::IoError(_) => "an I/O error occurred",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ToRustError::IoError(ref err) => Some(&*err as &Error),
        }
    }
}

impl From<IOError> for ToRustError {
    fn from(err: IOError) -> ToRustError {
        ToRustError::IoError(err)
    }
}

impl fmt::Display for ToRustError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())?;
        Ok(())
    }
}

impl<'a> ToRust for VType<'a> {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError> {
        match *self {
            VType::Bool(_) => Ok("bool".into()),
            VType::Int(_) => Ok("i64".into()),
            VType::Float(_) => Ok("f64".into()),
            VType::VString(_) => Ok("String".into()),
            VType::VData(_) => Ok("String".into()),
            VType::VTypename(v) => Ok(v.into()),
            VType::VEnum(ref v) => {
                enumhash.insert(
                    parent.into(),
                    Vec::from_iter(v.elts.iter().map(|s| String::from(*s))),
                );
                Ok(format!("{}", parent).into())
            }
            VType::VStruct(_) => Ok(format!("{}", parent).into()),
        }
    }
}

impl<'a> ToRust for VTypeExt<'a> {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError> {
        let v = self.vtype.to_rust(parent, enumhash)?;

        if self.isarray {
            Ok(format!("Vec<{}>", v).into())
        } else {
            Ok(v.into())
        }
    }
}

fn camel_case_to_underscore(s: &str) -> String {
    let mut out = String::from("");
    for g in s.chars() {
        match g {
            c @ 'A'...'Z' => {
                out += "_";
                out += c.to_lowercase().to_string().as_ref();
            }
            c => out += c.to_string().as_ref(),
        }
    }
    out
}

trait InterfaceToRust {
    fn to_rust(&self, description: &String) -> Result<String, ToRustError>;
}

impl<'a> InterfaceToRust for Interface<'a> {
    fn to_rust(&self, description: &String) -> Result<String, ToRustError> {
        let mut out: String = "".to_owned();
        let mut enumhash = EnumHash::new();

        for t in self.typedefs.values() {
            out += "#[derive(Serialize, Deserialize, Debug)]\n";
            match t.elt {
                VStructOrEnum::VStruct(ref v) => {
                    out += format!("pub struct {} {{\n", t.name).as_ref();
                    for e in &v.elts {
                        out += format!(
                            "    pub {}: Option<{}>,\n",
                            e.name,
                            e.vtype
                                .to_rust(format!("{}_{}", t.name, e.name).as_ref(), &mut enumhash)?
                        ).as_ref();
                    }
                }
                VStructOrEnum::VEnum(ref v) => {
                    out += format!("pub enum {} {{\n", t.name).as_ref();
                    let mut iter = v.elts.iter();
                    if let Some(fst) = iter.next() {
                        out += format!("    {}", fst).as_ref();
                        for elt in iter {
                            out += format!(",\n    {}", elt).as_ref();
                        }
                    }
                    out += "\n";
                }
            }
            out += "}\n\n";
        }

        for t in self.methods.values() {
            if t.output.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Reply {{\n", t.name).as_ref();
                for e in &t.output.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n";
                out += format!("impl varlink::VarlinkReply for _{}Reply {{}}\n\n", t.name).as_ref();
            }

            if t.input.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Args {{\n", t.name).as_ref();
                for e in &t.input.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n\n";
            }
        }

        for t in self.errors.values() {
            if t.parm.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Args {{\n", t.name).as_ref();
                for e in &t.parm.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n\n";
            }
        }

        out += "pub trait _CallErr: varlink::CallTrait {\n";
        if self.errors.len() > 0 {
            for t in self.errors.values() {
                let mut inparms: String = "".to_owned();
                let mut innames: String = "".to_owned();
                if t.parm.elts.len() > 0 {
                    for e in &t.parm.elts {
                        inparms += format!(
                            ", {}: Option<{}>",
                            e.name,
                            e.vtype.to_rust(self.name, &mut enumhash)?
                        ).as_ref();
                        innames += format!("{}, ", e.name).as_ref();
                        innames.pop();
                        innames.pop();
                    }
                }

                out += format!(
                    r#"    fn reply{}(&mut self{}) -> io::Result<()> {{
        self.reply_struct(varlink::Reply::error(
            "{}.{}".into(),
"#,
                    camel_case_to_underscore(t.name),
                    inparms,
                    self.name,
                    t.name,
                ).as_ref();

                out += format!(
                    "            Some(serde_json::to_value(_{}Args {{ {} }}).unwrap()),",
                    t.name, innames
                ).as_ref();

                out += r#"
        ))
    }
"#;
            }
        }
        out += "}\nimpl<'a> _CallErr for varlink::Call<'a> {}\n\n";

        for (name, v) in &enumhash {
            out += format!("pub enum {} {{\n", name).as_ref();
            let mut iter = v.iter();
            if let Some(fst) = iter.next() {
                out += format!("    {}", fst).as_ref();
                for elt in iter {
                    out += format!(",\n    {}", elt).as_ref();
                }
            }
            out += "\n}\n\n";
        }

        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            let mut innames: String = "".to_owned();
            if t.output.elts.len() > 0 {
                for e in &t.output.elts {
                    inparms += format!(
                        ", {}: Option<{}>",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                    innames += format!("{}, ", e.name).as_ref();
                    innames.pop();
                    innames.pop();
                }
            }
            out += format!("pub trait _Call{}: _CallErr {{\n", t.name).as_ref();
            out += format!("    fn reply(&mut self{}) -> io::Result<()> {{\n", inparms).as_ref();
            out += format!(
                "        self.reply_struct(_{}Reply {{ {} }}.into())\n",
                t.name, innames
            ).as_ref();
            out += format!(
                "    }}\n}}\nimpl<'a> _Call{} for varlink::Call<'a> {{}}\n\n",
                t.name
            ).as_ref();
        }

        out += "pub trait VarlinkInterface {\n";
        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            if t.input.elts.len() > 0 {
                for e in &t.input.elts {
                    inparms += format!(
                        ", {}: Option<{}>",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
            }
            let mut c = t.name.chars();
            let fname = match c.next() {
                None => String::from(t.name),
                Some(f) => f.to_lowercase().chain(c).collect(),
            };

            out += format!(
                "    fn {}(&self, &mut _Call{}{}) -> io::Result<()>;\n",
                fname, t.name, inparms
            ).as_ref();
        }
        out += r#"    fn call_upgraded(&self, &mut varlink::Call) -> io::Result<()> {
        Ok(())
    }
}
"#;

        out += format!(
            r####"
pub struct _InterfaceProxy {{
    inner: Box<VarlinkInterface + Send + Sync>,
}}

pub fn new(inner: Box<VarlinkInterface + Send + Sync>) -> _InterfaceProxy {{
    _InterfaceProxy {{ inner }}
}}

impl varlink::Interface for _InterfaceProxy {{
    fn get_description(&self) -> &'static str {{
        r#"
{}
"#
    }}

    fn get_name(&self) -> &'static str {{
        "{}"
    }}

"####,
            description, self.name
        ).as_ref();

        out += r#"    fn call_upgraded(&self, call: &mut varlink::Call) -> io::Result<()> {
        self.inner.call_upgraded(call)
    }

    fn call(&self, call: &mut varlink::Call) -> io::Result<()> {
        let req = call.request.unwrap();
        let method = req.method.clone();
        match method.as_ref() {
"#;

        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            if t.input.elts.len() > 0 {
                let ref e = t.input.elts[0];
                inparms += format!("args.{}", e.name).as_ref();
                for e in &t.input.elts[1..] {
                    inparms += format!(", args.{}, ", e.name).as_ref();
                }
            }
            let mut c = t.name.chars();
            let fname = match c.next() {
                None => String::from(t.name),
                Some(f) => f.to_lowercase().chain(c).collect(),
            };

            out += format!("            \"{}.{}\" => {{", self.name, t.name).as_ref();
            if t.input.elts.len() > 0 {
                out +=
                    format!(
                        concat!("\n                if let Some(args) = req.parameters.clone() {{\n",
"                    let args: _{}Args = serde_json::from_value(args)?;\n",
"                    return self.inner.{}(call as &mut _Call{}, {});\n",
"                }} else {{\n",
"                    return call.reply_invalid_parameter(None);\n",
"                }}\n",
"            }}\n"),
                        t.name,
                        fname, t.name,
                        inparms
                    ).as_ref();
            } else {
                out += format!(
                    "\n                return self.inner.{}(call as &mut _Call{});\n            }}\n",
                    fname, t.name
                ).as_ref();
            }
        }
        out += concat!(
            "\n",
            "            m => {\n",
            "                let method: String = m.clone().into();\n",
            "                return call.reply_method_not_found(Some(method));\n",
            "            }\n",
            "        }\n",
            "    }\n",
            "}"
        );

        Ok(out)
    }
}

pub fn generate(mut reader: Box<Read>, mut writer: Box<Write>) -> io::Result<()> {
    let mut buffer = String::new();

    reader.read_to_string(&mut buffer)?;

    let vr = Varlink::from_string(&buffer);

    if let Err(e) = vr {
        eprintln!("{}", e);
        exit(1);
    }

    match vr.unwrap().interface.to_rust(&buffer) {
        Ok(out) => {
            writeln!(
                writer,
                r#"// This file is automatically generated by the varlink rust generator
use std::io;

use varlink;
use serde_json;

{}"#,
                out
            )?;
        }
        Err(e) => {
            eprintln!("{}", e);
            exit(1);
        }
    }

    Ok(())
}

/// Errors are emitted to stderr and terminate the process.
pub fn cargo_build<T: AsRef<Path> + ?Sized>(input_path: &T) {
    let mut stderr = io::stderr();
    let input_path = input_path.as_ref();

    let reader: Box<Read>;

    let out_dir: PathBuf = env::var_os("OUT_DIR").unwrap().into();
    let rust_path = out_dir
        .join(input_path.file_name().unwrap())
        .with_extension("rs");

    let writer: Box<Write> = Box::new(File::create(&rust_path).unwrap());

    match File::open(input_path) {
        Ok(r) => reader = Box::new(r),
        Err(e) => {
            writeln!(
                stderr,
                "Could not read varlink input file `{}`: {}",
                input_path.display(),
                e
            ).unwrap();
            exit(1);
        }
    }
    if let Err(e) = generate(reader, writer) {
        writeln!(
            stderr,
            "Could not generate rust code from varlink file `{}`: {}",
            input_path.display(),
            e
        ).unwrap();
        exit(1);
    }

    println!("cargo:rerun-if-changed={}", input_path.display());
}
<commit_msg>generator: convert methods to snake case<commit_after>extern crate varlink_parser;

use std::env;
use std::path::{Path, PathBuf};
use std::process::exit;
use std::io::Error as IOError;
use std::error::Error;
use std::io::{Read, Write};
use std::result::Result;
use std::fmt;
use std::collections::HashMap;
use std::iter::FromIterator;
use std::io;
use std::fs::File;

use varlink_parser::{Interface, VStructOrEnum, VType, VTypeExt, Varlink};

type EnumHash<'a> = HashMap<String, Vec<String>>;

trait ToRust {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError>;
}

#[derive(Debug)]
pub enum ToRustError {
    IoError(IOError),
}

impl Error for ToRustError {
    fn description(&self) -> &str {
        match *self {
            ToRustError::IoError(_) => "an I/O error occurred",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ToRustError::IoError(ref err) => Some(&*err as &Error),
        }
    }
}

impl From<IOError> for ToRustError {
    fn from(err: IOError) -> ToRustError {
        ToRustError::IoError(err)
    }
}

impl fmt::Display for ToRustError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())?;
        Ok(())
    }
}

impl<'a> ToRust for VType<'a> {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError> {
        match *self {
            VType::Bool(_) => Ok("bool".into()),
            VType::Int(_) => Ok("i64".into()),
            VType::Float(_) => Ok("f64".into()),
            VType::VString(_) => Ok("String".into()),
            VType::VData(_) => Ok("String".into()),
            VType::VTypename(v) => Ok(v.into()),
            VType::VEnum(ref v) => {
                enumhash.insert(
                    parent.into(),
                    Vec::from_iter(v.elts.iter().map(|s| String::from(*s))),
                );
                Ok(format!("{}", parent).into())
            }
            VType::VStruct(_) => Ok(format!("{}", parent).into()),
        }
    }
}

impl<'a> ToRust for VTypeExt<'a> {
    fn to_rust(&self, parent: &str, enumhash: &mut EnumHash) -> Result<String, ToRustError> {
        let v = self.vtype.to_rust(parent, enumhash)?;

        if self.isarray {
            Ok(format!("Vec<{}>", v).into())
        } else {
            Ok(v.into())
        }
    }
}
fn to_snake_case(mut str: &str) -> String {
    let mut words = vec![];
    // Preserve leading underscores
    str = str.trim_left_matches(|c: char| {
        if c == '_' {
            words.push(String::new());
            true
        } else {
            false
        }
    });
    for s in str.split('_') {
        let mut last_upper = false;
        let mut buf = String::new();
        if s.is_empty() {
            continue;
        }
        for ch in s.chars() {
            if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
                words.push(buf);
                buf = String::new();
            }
            last_upper = ch.is_uppercase();
            buf.extend(ch.to_lowercase());
        }
        words.push(buf);
    }
    words.join("_")
}

trait InterfaceToRust {
    fn to_rust(&self, description: &String) -> Result<String, ToRustError>;
}

impl<'a> InterfaceToRust for Interface<'a> {
    fn to_rust(&self, description: &String) -> Result<String, ToRustError> {
        let mut out: String = "".to_owned();
        let mut enumhash = EnumHash::new();

        for t in self.typedefs.values() {
            out += "#[derive(Serialize, Deserialize, Debug)]\n";
            match t.elt {
                VStructOrEnum::VStruct(ref v) => {
                    out += format!("pub struct {} {{\n", t.name).as_ref();
                    for e in &v.elts {
                        out += format!(
                            "    pub {}: Option<{}>,\n",
                            e.name,
                            e.vtype
                                .to_rust(format!("{}_{}", t.name, e.name).as_ref(), &mut enumhash)?
                        ).as_ref();
                    }
                }
                VStructOrEnum::VEnum(ref v) => {
                    out += format!("pub enum {} {{\n", t.name).as_ref();
                    let mut iter = v.elts.iter();
                    if let Some(fst) = iter.next() {
                        out += format!("    {}", fst).as_ref();
                        for elt in iter {
                            out += format!(",\n    {}", elt).as_ref();
                        }
                    }
                    out += "\n";
                }
            }
            out += "}\n\n";
        }

        for t in self.methods.values() {
            if t.output.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Reply {{\n", t.name).as_ref();
                for e in &t.output.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n";
                out += format!("impl varlink::VarlinkReply for _{}Reply {{}}\n\n", t.name).as_ref();
            }

            if t.input.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Args {{\n", t.name).as_ref();
                for e in &t.input.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n\n";
            }
        }

        for t in self.errors.values() {
            if t.parm.elts.len() > 0 {
                out += "#[allow(non_camel_case_types)]\n#[derive(Serialize, Deserialize, Debug)]\n";
                out += format!("struct _{}Args {{\n", t.name).as_ref();
                for e in &t.parm.elts {
                    out += format!(
                        "    {}: Option<{}>,\n",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
                out += "}\n\n";
            }
        }

        out += "pub trait _CallErr: varlink::CallTrait {\n";
        if self.errors.len() > 0 {
            for t in self.errors.values() {
                let mut inparms: String = "".to_owned();
                let mut innames: String = "".to_owned();
                if t.parm.elts.len() > 0 {
                    for e in &t.parm.elts {
                        inparms += format!(
                            ", {}: Option<{}>",
                            e.name,
                            e.vtype.to_rust(self.name, &mut enumhash)?
                        ).as_ref();
                        innames += format!("{}, ", e.name).as_ref();
                    }
                    innames.pop();
                    innames.pop();
                }

                out += format!(
                    r#"    fn reply_{}(&mut self{}) -> io::Result<()> {{
        self.reply_struct(varlink::Reply::error(
            "{}.{}".into(),
"#,
                    to_snake_case(t.name),
                    inparms,
                    self.name,
                    t.name,
                ).as_ref();

                out += format!(
                    "            Some(serde_json::to_value(_{}Args {{ {} }}).unwrap()),",
                    t.name, innames
                ).as_ref();

                out += r#"
        ))
    }
"#;
            }
        }
        out += "}\nimpl<'a> _CallErr for varlink::Call<'a> {}\n\n";

        for (name, v) in &enumhash {
            out += format!("pub enum {} {{\n", name).as_ref();
            let mut iter = v.iter();
            if let Some(fst) = iter.next() {
                out += format!("    {}", fst).as_ref();
                for elt in iter {
                    out += format!(",\n    {}", elt).as_ref();
                }
            }
            out += "\n}\n\n";
        }

        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            let mut innames: String = "".to_owned();
            if t.output.elts.len() > 0 {
                for e in &t.output.elts {
                    inparms += format!(
                        ", {}: Option<{}>",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                    innames += format!("{}, ", e.name).as_ref();
                }
                innames.pop();
                innames.pop();
            }
            out += format!("pub trait _Call{}: _CallErr {{\n", t.name).as_ref();
            out += format!("    fn reply(&mut self{}) -> io::Result<()> {{\n", inparms).as_ref();
            out += format!(
                "        self.reply_struct(_{}Reply {{ {} }}.into())\n",
                t.name, innames
            ).as_ref();
            out += format!(
                "    }}\n}}\nimpl<'a> _Call{} for varlink::Call<'a> {{}}\n\n",
                t.name
            ).as_ref();
        }

        out += "pub trait VarlinkInterface {\n";
        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            if t.input.elts.len() > 0 {
                for e in &t.input.elts {
                    inparms += format!(
                        ", {}: Option<{}>",
                        e.name,
                        e.vtype.to_rust(self.name, &mut enumhash)?
                    ).as_ref();
                }
            }

            out += format!(
                "    fn {}(&self, call: &mut _Call{}{}) -> io::Result<()>;\n",
                to_snake_case(t.name),
                t.name,
                inparms
            ).as_ref();
        }
        out += r#"    fn call_upgraded(&self, _call: &mut varlink::Call) -> io::Result<()> {
        Ok(())
    }
}
"#;

        out += format!(
            r####"
pub struct _InterfaceProxy {{
    inner: Box<VarlinkInterface + Send + Sync>,
}}

pub fn new(inner: Box<VarlinkInterface + Send + Sync>) -> _InterfaceProxy {{
    _InterfaceProxy {{ inner }}
}}

impl varlink::Interface for _InterfaceProxy {{
    fn get_description(&self) -> &'static str {{
        r#"
{}
"#
    }}

    fn get_name(&self) -> &'static str {{
        "{}"
    }}

"####,
            description, self.name
        ).as_ref();

        out += r#"    fn call_upgraded(&self, call: &mut varlink::Call) -> io::Result<()> {
        self.inner.call_upgraded(call)
    }

    fn call(&self, call: &mut varlink::Call) -> io::Result<()> {
        let req = call.request.unwrap();
        let method = req.method.clone();
        match method.as_ref() {
"#;

        for t in self.methods.values() {
            let mut inparms: String = "".to_owned();
            if t.input.elts.len() > 0 {
                let ref e = t.input.elts[0];
                inparms += format!("args.{}", e.name).as_ref();
                for e in &t.input.elts[1..] {
                    inparms += format!(", args.{}, ", e.name).as_ref();
                }
            }

            out += format!("            \"{}.{}\" => {{", self.name, t.name).as_ref();
            if t.input.elts.len() > 0 {
                out +=
                    format!(
                        concat!("\n                if let Some(args) = req.parameters.clone() {{\n",
"                    let args: _{}Args = serde_json::from_value(args)?;\n",
"                    return self.inner.{}(call as &mut _Call{}, {});\n",
"                }} else {{\n",
"                    return call.reply_invalid_parameter(None);\n",
"                }}\n",
"            }}\n"),
                        t.name,
                        to_snake_case(t.name), t.name,
                        inparms
                    ).as_ref();
            } else {
                out += format!(
                    "\n                return self.inner.{}(call as &mut _Call{});\n            }}\n",
                    to_snake_case(t.name), t.name
                ).as_ref();
            }
        }
        out += concat!(
            "\n",
            "            m => {\n",
            "                let method: String = m.clone().into();\n",
            "                return call.reply_method_not_found(Some(method));\n",
            "            }\n",
            "        }\n",
            "    }\n",
            "}"
        );

        Ok(out)
    }
}

pub fn generate(mut reader: Box<Read>, mut writer: Box<Write>) -> io::Result<()> {
    let mut buffer = String::new();

    reader.read_to_string(&mut buffer)?;

    let vr = Varlink::from_string(&buffer);

    if let Err(e) = vr {
        eprintln!("{}", e);
        exit(1);
    }

    match vr.unwrap().interface.to_rust(&buffer) {
        Ok(out) => {
            writeln!(
                writer,
                r#"// This file is automatically generated by the varlink rust generator
use std::io;

use varlink;
use serde_json;

{}"#,
                out
            )?;
        }
        Err(e) => {
            eprintln!("{}", e);
            exit(1);
        }
    }

    Ok(())
}

/// Errors are emitted to stderr and terminate the process.
pub fn cargo_build<T: AsRef<Path> + ?Sized>(input_path: &T) {
    let mut stderr = io::stderr();
    let input_path = input_path.as_ref();

    let reader: Box<Read>;

    let out_dir: PathBuf = env::var_os("OUT_DIR").unwrap().into();
    let rust_path = out_dir
        .join(input_path.file_name().unwrap())
        .with_extension("rs");

    let writer: Box<Write> = Box::new(File::create(&rust_path).unwrap());

    match File::open(input_path) {
        Ok(r) => reader = Box::new(r),
        Err(e) => {
            writeln!(
                stderr,
                "Could not read varlink input file `{}`: {}",
                input_path.display(),
                e
            ).unwrap();
            exit(1);
        }
    }
    if let Err(e) = generate(reader, writer) {
        writeln!(
            stderr,
            "Could not generate rust code from varlink file `{}`: {}",
            input_path.display(),
            e
        ).unwrap();
        exit(1);
    }

    println!("cargo:rerun-if-changed={}", input_path.display());
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use self::Cell::*;
use std::default::Default;
use std::ops::Not;

/// An enum representing the state of a cell.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Cell {
    /// Stands for `0`.
    Zero,
    /// Stands for `1`.
    One,
    /// Empty cell.
    Empty,
}

impl Default for Cell {
    fn default() -> Self {
        Empty
    }
}

impl Not for Cell {
    type Output = Self;

    fn not(self) -> Self {
        match self {
            Zero  => One,
            One   => Zero,
            Empty => panic!("called `Not` on an `Empty` cell"),
        }
    }
}

impl Cell {
    /// Returns `true` if a cell is `Empty`.
    pub fn is_empty(self) -> bool {
        match self {
            Empty => true,
            _     => false,
        }
    }

    /// Returns `true` if a cell is `Zero` or `One`.
    pub fn is_filled(self) -> bool {
        match self {
            Empty => false,
            _     => true,
        }
    }
}
<commit_msg>don't panic on !Empty<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use self::Cell::*;
use std::default::Default;
use std::ops::Not;

/// An enum representing the state of a cell.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Cell {
    /// Stands for `0`.
    Zero,
    /// Stands for `1`.
    One,
    /// Empty cell.
    Empty,
}

impl Default for Cell {
    fn default() -> Self {
        Empty
    }
}

impl Not for Cell {
    type Output = Self;

    fn not(self) -> Self {
        match self {
            Zero  => One,
            One   => Zero,
            Empty => Empty,
        }
    }
}

impl Cell {
    /// Returns `true` if a cell is `Empty`.
    pub fn is_empty(self) -> bool {
        match self {
            Empty => true,
            _     => false,
        }
    }

    /// Returns `true` if a cell is `Zero` or `One`.
    pub fn is_filled(self) -> bool {
        match self {
            Empty => false,
            _     => true,
        }
    }
}
<|endoftext|>


<commit_before>/* hil::timer -- Traits and structures for software timers.
 *
 * Support for virtualized software timers on top of a single hardware
 * alarm (counter interrupt). Currently traits do not specify the time
 * units of the timers; a future version will.
 *
 * The four relevant types are:
 *   - Timer: the trait that provides virtualized timers
 *   - TimerMux: the struct that implements Timer on top of Alarm
 *   - TimerRequest: the structure a caller must pass in when requesting
 *                   a timer
 *   - TimerCB: the trait which has the callback for when the timer fires
 *
 * The TimerRequest structure contains a reference to a TimerCB. So
 * to invoke a timer, an application defines a structure that implements
 * TimerCB, creates a TimerRequest whose callback field is the TimerCB
 * (either through new() or initialization), then passes TimerRequest to
 * calls to Timer.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: 7/16/15
 */
#![allow(dead_code)]

use core::prelude::*;
use alarm;

// If a timer is late (was supposed to fire in the past), LATE_DELAY
// specifies how far in the future to fire it. This number needs to be
// > 1 in case the counter ticks between reading it and setting the
// overflow value. Set it to 5 just to be safe.
const LATE_DELAY: u32 = 5;

pub trait TimerCB {
    fn fired(&'static mut self, &'static mut TimerRequest, now: u32);
}

pub trait Timer {
    fn now(&'static mut self) -> u32;
    fn cancel(&'static mut self, &'static mut TimerRequest);
    fn oneshot(&'static mut self, interval: u32, &'static mut TimerRequest);
    fn repeat(&'static mut self, interval: u32, &'static mut TimerRequest);
}

pub struct TimerRequest {
    pub next: Option<&'static mut TimerRequest>,
    pub is_active: bool,
    pub is_repeat: bool,
    pub when: u32,
    pub interval: u32,
    pub callback: Option<&'static mut TimerCB>
}

impl TimerRequest {
    pub fn new(cb: &'static mut TimerCB) -> TimerRequest {
        TimerRequest {
            next:      None,
            is_active: false,
            is_repeat: false,
            when:      0,
            interval:  0,
            callback:  Some(cb)
        }
    }
}

pub struct TimerMux {
    request: Option<&'static mut TimerRequest>,
    internal: Option<&'static mut alarm::Alarm>
}

impl TimerMux {
    pub fn new(internal: &'static mut alarm::Alarm) -> TimerMux {
        TimerMux {
            request: None,
            internal: Some(internal)
        }
  }

    /*
     * There are two pairs of functions for manipulating the ordered
     * linked list of outstanding timers
     *
     *  insert/delete: operate on list, inserting or deleting an entry
     *  add/remove: operate on list, and reconfigure underlying hardware
     *              alarm if first element of list changes
     *
     * add/remove are wrappers around insert/delete.
     */

    /* Insert a TimerRequest into the linked list, reconfiguring the
     * hardware alarm if it is inserted as the first element. */
    fn add(&'static mut self, request: &'static mut TimerRequest) -> bool {
        let changed = self.insert(request);
        if changed {
            self.start_request();
        }
        changed
    }

    /* Remove a TimerRequest into the linked list, reconfiguring the
     * hardware alarm if it was the first element. */
    fn remove(&'static mut self, request: &'static mut TimerRequest) -> bool {
        let changed = self.delete(request);
        if changed {
            self.start_request();
        }
        changed
    }

    /* Insert a TimerRequest into the linked list. Returns whether hardware
    * clock has to be recalculated (inserted timer is now first timer) */
    fn insert(&'static mut self, request: &'static mut TimerRequest) -> bool {
        if request.next.is_some() { // Already on a list, this is an error!
            false
        } else if self.request.is_none() {
            self.request = Some(request);
            true
        } else {
            let mut first = true;
            let mut done = false;
            let mut copt = &mut self.request;
            while !done {
                let mycopt = copt.take();
                let mut curr = mycopt.unwrap();
                // 'request' is earlier than current element, insert here by making
                // the current Option point to 'request' and have 'request''s next
                // Option point to the element the current Option held.
                if request.when < curr.when {
                   request.next = Some(curr);
                   *copt = Some(request);
                   done = true;
                } else {
                   // We need to insert later. We therefore are not inserting in
                   // the first element. There are two cases:
                   //   1. last element and we need to insert at the end, or
                   //   2. we need to traverse the next hop.
                   first = false;
                   if curr.next.is_none() {
                     // Reached end of list, insert here
                     curr.next = Some(request);
                     *copt = Some(curr);
                     done = true;
                   } else {
                     let mut nopt = &mut curr.next;
                     *copt = Some(curr);
                     copt = nopt;
                   }

                }
            }
            first
        }
    }

    /* Delete a TimerRequest from the linked list. Returns whether hardware
     * clock has to be recalculated (removed first timer) */
    fn delete(&'static mut self, request: &'static mut TimerRequest) -> bool {
        if self.request.is_none() {return false;}

        let mut done = false;
        let mut copt = &mut self.request;
        let mut first = true;
        while !done {
            let mycopt = copt.take();
            let mut curr = mycopt.unwrap();
            let cptr: *const TimerRequest = curr;
            let rptr: *const TimerRequest = request;
            if cptr == rptr {
                *copt = curr.next.take();
                done = true;
            } else if curr.next.is_none() {
                *copt = Some(curr);
                first = false;
                done = true;
            } else {
                let mut nopt = &mut curr.next;
                *copt = Some(curr);
                copt = nopt;
                first = false;
            }
        }
        first
    }

    /* Schedule the hardware alarm based on the first TimerRequest.
     * Assumes that timers are at most 2^31 in the future. If the
     * duration until a timer is > 2^31, assumes this means the
     * timer has passed (is late) and so fires immediately (in LATE_DELAY
     * ticks).
     */
    fn start_request(&'static mut self) {
        if self.request.is_none() {return;}

        let aopt: Option<&'static mut alarm::Alarm> = self.internal.take();
        let alarm: &'static mut alarm::Alarm = aopt.unwrap();
        let ropt = self.request.take();
        let request: &'static mut TimerRequest = ropt.unwrap();
        let mut when = request.when;

        let curr = alarm.now();
        let delay = request.when - curr;
        if delay > (0x80000000) {
            when = curr + LATE_DELAY;
            request.when = when;
        }
        alarm.set_alarm(when, self);

        self.internal = Some(alarm);
        self.request = Some(request);
    }

}

impl alarm::Request for TimerMux {

    // The hardware alarm fired. If its firing matches the expected
    // firing time, invoke the next software timer and schedule the
    // following one.
    fn fired(&'static mut self) {
        if self.request.is_none() {return;}
        let curr = self.now();
        let ropt = self.request.take();
        let request: &'static mut TimerRequest = ropt.unwrap();
        // The timer did not fire early
        if (request.when - curr) < 20 {
            self.request = request.next.take();

            // Note this implementation is inefficient: if the repeat timer
            // would be at the head of the queue again, we recalculate the
            // timer, then re-insert so recalculate a second time.
            // A better implementation would check this and conditionally
            // remove/insert. -pal 7/22/15
            let cbopt = request.callback.take();
            let cb: &'static mut TimerCB = cbopt.unwrap();
            request.callback = Some(cb);
            if request.is_repeat {
                request.when = request.when + request.interval;
                self.add(request);
            } else {
                request.is_active = false;
            }
            self.start_request();
            cb.fired(request, curr);
        } else {
            // Timer fired early. Not sure why this happens,
            // But it does -pal 7/28/15
            self.request = Some(request);
            self.start_request();
        }
    }
}

impl Timer for TimerMux {
    fn now(&'static mut self) -> u32 {
        let alarm = self.internal.as_mut().unwrap();
        let val = alarm.now();
        self.internal = Some(*alarm);
        val
    }

    fn cancel(&'static mut self, request: &'static mut TimerRequest) {
        if !request.is_active {return;}

        request.is_active = false;
        self.remove(request);
    }

    fn oneshot(&'static mut self, interval: u32, request: &'static mut TimerRequest) {
        request.interval = interval;
        request.is_active = true;
        request.when = self.now() + interval;
        request.is_repeat = false;
        self.add(request);
    }

    fn repeat(&'static mut self, interval: u32, request: &'static mut TimerRequest) {
        request.interval = interval;
        request.is_active = true;
        request.when = self.now() + interval;
        request.is_repeat = true;
        self.add(request);
    }
}

<commit_msg>Does TimerMux#internal need to an Option?<commit_after>/* hil::timer -- Traits and structures for software timers.
 *
 * Support for virtualized software timers on top of a single hardware
 * alarm (counter interrupt). Currently traits do not specify the time
 * units of the timers; a future version will.
 *
 * The four relevant types are:
 *   - Timer: the trait that provides virtualized timers
 *   - TimerMux: the struct that implements Timer on top of Alarm
 *   - TimerRequest: the structure a caller must pass in when requesting
 *                   a timer
 *   - TimerCB: the trait which has the callback for when the timer fires
 *
 * The TimerRequest structure contains a reference to a TimerCB. So
 * to invoke a timer, an application defines a structure that implements
 * TimerCB, creates a TimerRequest whose callback field is the TimerCB
 * (either through new() or initialization), then passes TimerRequest to
 * calls to Timer.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: 7/16/15
 */
#![allow(dead_code)]

use core::prelude::*;
use alarm;

// If a timer is late (was supposed to fire in the past), LATE_DELAY
// specifies how far in the future to fire it. This number needs to be
// > 1 in case the counter ticks between reading it and setting the
// overflow value. Set it to 5 just to be safe.
const LATE_DELAY: u32 = 5;

pub trait TimerCB {
    fn fired(&'static mut self, &'static mut TimerRequest, now: u32);
}

pub trait Timer {
    fn now(&'static mut self) -> u32;
    fn cancel(&'static mut self, &'static mut TimerRequest);
    fn oneshot(&'static mut self, interval: u32, &'static mut TimerRequest);
    fn repeat(&'static mut self, interval: u32, &'static mut TimerRequest);
}

pub struct TimerRequest {
    pub next: Option<&'static mut TimerRequest>,
    pub is_active: bool,
    pub is_repeat: bool,
    pub when: u32,
    pub interval: u32,
    pub callback: Option<&'static mut TimerCB>
}

impl TimerRequest {
    pub fn new(cb: &'static mut TimerCB) -> TimerRequest {
        TimerRequest {
            next:      None,
            is_active: false,
            is_repeat: false,
            when:      0,
            interval:  0,
            callback:  Some(cb)
        }
    }
}

pub struct TimerMux {
    request: Option<&'static mut TimerRequest>,
    internal: &'static mut alarm::Alarm
}

impl TimerMux {
    pub fn new(internal: &'static mut alarm::Alarm) -> TimerMux {
        TimerMux {
            request: None,
            internal: internal
        }
    }

    /*
     * There are two pairs of functions for manipulating the ordered
     * linked list of outstanding timers
     *
     *  insert/delete: operate on list, inserting or deleting an entry
     *  add/remove: operate on list, and reconfigure underlying hardware
     *              alarm if first element of list changes
     *
     * add/remove are wrappers around insert/delete.
     */

    /* Insert a TimerRequest into the linked list, reconfiguring the
     * hardware alarm if it is inserted as the first element. */
    fn add(&'static mut self, request: &'static mut TimerRequest) -> bool {
        let changed = self.insert(request);
        if changed {
            self.start_request();
        }
        changed
    }

    /* Remove a TimerRequest into the linked list, reconfiguring the
     * hardware alarm if it was the first element. */
    fn remove(&'static mut self, request: &'static mut TimerRequest) -> bool {
        let changed = self.delete(request);
        if changed {
            self.start_request();
        }
        changed
    }

    /* Insert a TimerRequest into the linked list. Returns whether hardware
    * clock has to be recalculated (inserted timer is now first timer) */
    fn insert(&'static mut self, request: &'static mut TimerRequest) -> bool {
        if request.next.is_some() { // Already on a list, this is an error!
            false
        } else if self.request.is_none() {
            self.request = Some(request);
            true
        } else {
            let mut first = true;
            let mut done = false;
            let mut copt = &mut self.request;
            while !done {
                let mycopt = copt.take();
                let mut curr = mycopt.unwrap();
                // 'request' is earlier than current element, insert here by making
                // the current Option point to 'request' and have 'request''s next
                // Option point to the element the current Option held.
                if request.when < curr.when {
                   request.next = Some(curr);
                   *copt = Some(request);
                   done = true;
                } else {
                   // We need to insert later. We therefore are not inserting in
                   // the first element. There are two cases:
                   //   1. last element and we need to insert at the end, or
                   //   2. we need to traverse the next hop.
                   first = false;
                   if curr.next.is_none() {
                     // Reached end of list, insert here
                     curr.next = Some(request);
                     *copt = Some(curr);
                     done = true;
                   } else {
                     let mut nopt = &mut curr.next;
                     *copt = Some(curr);
                     copt = nopt;
                   }

                }
            }
            first
        }
    }

    /* Delete a TimerRequest from the linked list. Returns whether hardware
     * clock has to be recalculated (removed first timer) */
    fn delete(&'static mut self, request: &'static mut TimerRequest) -> bool {
        if self.request.is_none() {return false;}

        let mut done = false;
        let mut copt = &mut self.request;
        let mut first = true;
        while !done {
            let mycopt = copt.take();
            let mut curr = mycopt.unwrap();
            let cptr: *const TimerRequest = curr;
            let rptr: *const TimerRequest = request;
            if cptr == rptr {
                *copt = curr.next.take();
                done = true;
            } else if curr.next.is_none() {
                *copt = Some(curr);
                first = false;
                done = true;
            } else {
                let mut nopt = &mut curr.next;
                *copt = Some(curr);
                copt = nopt;
                first = false;
            }
        }
        first
    }

    /* Schedule the hardware alarm based on the first TimerRequest.
     * Assumes that timers are at most 2^31 in the future. If the
     * duration until a timer is > 2^31, assumes this means the
     * timer has passed (is late) and so fires immediately (in LATE_DELAY
     * ticks).
     */
    fn start_request(&'static mut self) {
        if self.request.is_none() { return }

        let request = self.request.as_mut().unwrap();
        let mut when = request.when;
        let curr = self.internal.now();
        let delay = request.when - curr;
        if delay > (0x80000000) {
            when = curr + LATE_DELAY;
            request.when = when;
        }
        self.internal.set_alarm(when, self);
    }

}

impl alarm::Request for TimerMux {

    // The hardware alarm fired. If its firing matches the expected
    // firing time, invoke the next software timer and schedule the
    // following one.
    fn fired(&'static mut self) {
        if self.request.is_none() {return;}
        let curr = self.now();
        let ropt = self.request.take();
        let request: &'static mut TimerRequest = ropt.unwrap();
        // The timer did not fire early
        if (request.when - curr) < 20 {
            self.request = request.next.take();

            // Note this implementation is inefficient: if the repeat timer
            // would be at the head of the queue again, we recalculate the
            // timer, then re-insert so recalculate a second time.
            // A better implementation would check this and conditionally
            // remove/insert. -pal 7/22/15
            let cbopt = request.callback.take();
            let cb: &'static mut TimerCB = cbopt.unwrap();
            request.callback = Some(cb);
            if request.is_repeat {
                request.when = request.when + request.interval;
                self.add(request);
            } else {
                request.is_active = false;
            }
            self.start_request();
            cb.fired(request, curr);
        } else {
            // Timer fired early. Not sure why this happens,
            // But it does -pal 7/28/15
            self.request = Some(request);
            self.start_request();
        }
    }
}

impl Timer for TimerMux {
    fn now(&'static mut self) -> u32 {
        self.internal.now()
    }

    fn cancel(&'static mut self, request: &'static mut TimerRequest) {
        if !request.is_active {return;}

        request.is_active = false;
        self.remove(request);
    }

    fn oneshot(&'static mut self, interval: u32, request: &'static mut TimerRequest) {
        request.interval = interval;
        request.is_active = true;
        request.when = self.now() + interval;
        request.is_repeat = false;
        self.add(request);
    }

    fn repeat(&'static mut self, interval: u32, request: &'static mut TimerRequest) {
        request.interval = interval;
        request.is_active = true;
        request.when = self.now() + interval;
        request.is_repeat = true;
        self.add(request);
    }
}

<|endoftext|>


<commit_before>pub mod config;
pub mod util;

extern crate clap;

use env;
use std::convert;
use std::fs::File;
use std::io::{self, BufReader, BufRead};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use self::clap::{App, AppSettings, Arg, SubCommand};

/// Reads the arguments given to this program at execution and returns them
pub fn read_arguments<T>() -> config::GlobalConfig<T>
    where T: FromStr,
          T::Err: convert::From<io::Error>,
          Result<Vec<T>, T::Err>: FromIterator<Result<T, io::Error>>,
          Result<Vec<T>, io::Error>: FromIterator<Result<T, T::Err>>
{
    let matches = App::new("rustle my net")
        .subcommand(SubCommand::with_name("learn")
            .arg(Arg::with_name("topology")
                .long("topology")
                .short("t")
                // TODO: proper help
                .help("a list of values representing the number of nodes in each layer")
                .multiple(true)
                .required(true))
            .arg(Arg::with_name("learning_rate")
                .long("eta")
                .takes_value(true)
                .help("The learning rate eta. Should be between 0.0 and 1.0")
                .default_value("0.05"))
            .arg(Arg::with_name("epochs")
                .long("epochs")
                .takes_value(true)
                .help("The number of training epochs")
                .default_value("100"))
            .arg(Arg::with_name("mini_batch_size")
                .long("batchsize")
                .takes_value(true)
                .help("The size of the mini batches for the learning process.")
                .default_value("32"))
            .arg(Arg::with_name("test_data_size")
                .long("testsize")
                .takes_value(true)
                .default_value("20")))
        .subcommand(SubCommand::with_name("classify"))
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("verbosity")
            .long("verbosity")
            .short("v")
            .takes_value(true)
            .possible_values(&["debug", "info", "error", "off"])
            // TODO: change default to warn for production
            .default_value("debug"))
        .arg(Arg::with_name("data")
            .long("data")
            .short("i")
            .takes_value(true)
            .default_value("data/iris_flowers.txt"))
        .arg(Arg::with_name("network_model")
            .long("model")
            .short("m")
            .takes_value(true))
        .arg(Arg::with_name("datatype")
            .long("type")
            .short("d")
            .takes_value(true)
            .possible_values(&["flower", "mnist"])
            .default_value("flower"))
        .get_matches();

    config::GlobalConfig::from_arguments(matches)
}

/// reads content of given file and returns a result with
/// either the Vector of Flowers or Err
pub fn read_data<T>(filename: &Path) -> io::Result<Vec<T>>
    where T: FromStr,
          T::Err: convert::From<io::Error>,
          Result<Vec<T>, T::Err>: FromIterator<Result<T, io::Error>>,
          Result<Vec<T>, io::Error>: FromIterator<Result<T, T::Err>>
{
    let f = File::open(filename)?;
    let reader = BufReader::new(&f);
    reader.lines().map(|l| l?.parse::<T>()).collect()
}

// TODO: DOK
fn parse_data<T>(datafile: &str) -> Result<Vec<T>, io::Error>
    where T: FromStr,
          T::Err: convert::From<io::Error>,
          Result<Vec<T>, T::Err>: FromIterator<Result<T, io::Error>>,
          Result<Vec<T>, io::Error>: FromIterator<Result<T, T::Err>>
{
    let mut data_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    data_path.push(Path::new(datafile));
    read_data(&data_path)
}
<commit_msg>fix bug w/ topology input<commit_after>pub mod config;
pub mod util;

extern crate clap;

use env;
use std::convert;
use std::fs::File;
use std::io::{self, BufReader, BufRead};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use self::clap::{App, AppSettings, Arg, SubCommand};

/// Reads the arguments given to this program at execution and returns them
pub fn read_arguments<T>() -> config::GlobalConfig<T>
    where T: FromStr,
          T::Err: convert::From<io::Error>,
          Result<Vec<T>, T::Err>: FromIterator<Result<T, io::Error>>,
          Result<Vec<T>, io::Error>: FromIterator<Result<T, T::Err>>
{
    let matches = App::new("rustle my net")
        .subcommand(SubCommand::with_name("learn")
            .arg(Arg::with_name("topology")
                .long("topology")
                .short("t")
                // TODO: proper help
                .help("a list of values representing the number of nodes in each layer")
                .multiple(true)
                .value_delimiter(" ")
                .required(true))
            .arg(Arg::with_name("learning_rate")
                .long("eta")
                .takes_value(true)
                .help("The learning rate eta. Should be between 0.0 and 1.0")
                .default_value("0.05"))
            .arg(Arg::with_name("epochs")
                .long("epochs")
                .takes_value(true)
                .help("The number of training epochs")
                .default_value("100"))
            .arg(Arg::with_name("mini_batch_size")
                .long("batchsize")
                .takes_value(true)
                .help("The size of the mini batches for the learning process.")
                .default_value("32"))
            .arg(Arg::with_name("test_data_size")
                .long("testsize")
                .takes_value(true)
                .default_value("20")))
        .subcommand(SubCommand::with_name("classify"))
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("verbosity")
            .long("verbosity")
            .short("v")
            .takes_value(true)
            .possible_values(&["debug", "info", "error", "off"])
            // TODO: change default to warn for production
            .default_value("debug"))
        .arg(Arg::with_name("data")
            .long("data")
            .short("i")
            .takes_value(true)
            .default_value("data/iris_flowers.txt"))
        .arg(Arg::with_name("network_model")
            .long("model")
            .short("m")
            .takes_value(true))
        .arg(Arg::with_name("datatype")
            .long("type")
            .short("d")
            .takes_value(true)
            .possible_values(&["flower", "mnist"])
            .default_value("flower"))
        .get_matches();

    config::GlobalConfig::from_arguments(matches)
}

/// reads content of given file and returns a result with
/// either the Vector of Flowers or Err
pub fn read_data<T>(filename: &Path) -> io::Result<Vec<T>>
    where T: FromStr,
          T::Err: convert::From<io::Error>,
          Result<Vec<T>, T::Err>: FromIterator<Result<T, io::Error>>,
          Result<Vec<T>, io::Error>: FromIterator<Result<T, T::Err>>
{
    let f = File::open(filename)?;
    let reader = BufReader::new(&f);
    reader.lines().map(|l| l?.parse::<T>()).collect()
}

// TODO: DOK
fn parse_data<T>(datafile: &str) -> Result<Vec<T>, io::Error>
    where T: FromStr,
          T::Err: convert::From<io::Error>,
          Result<Vec<T>, T::Err>: FromIterator<Result<T, io::Error>>,
          Result<Vec<T>, io::Error>: FromIterator<Result<T, T::Err>>
{
    let mut data_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    data_path.push(Path::new(datafile));
    read_data(&data_path)
}
<|endoftext|>