<commit_before>//! `feature = "hooks"` Commit, Data Change and Rollback Notification Callbacks
#![allow(non_camel_case_types)]

use std::os::raw::{c_char, c_int, c_void};
use std::panic::{catch_unwind, RefUnwindSafe};
use std::ptr;

use crate::ffi;

use crate::{Connection, InnerConnection};

/// `feature = "hooks"` Action Codes
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(i32)]
#[non_exhaustive]
pub enum Action {
    /// Unsupported / unexpected action
    UNKNOWN = -1,
    /// DELETE command
    SQLITE_DELETE = ffi::SQLITE_DELETE,
    /// INSERT command
    SQLITE_INSERT = ffi::SQLITE_INSERT,
    /// UPDATE command
    SQLITE_UPDATE = ffi::SQLITE_UPDATE,
}

impl From<i32> for Action {
    fn from(code: i32) -> Action {
        match code {
            ffi::SQLITE_DELETE => Action::SQLITE_DELETE,
            ffi::SQLITE_INSERT => Action::SQLITE_INSERT,
            ffi::SQLITE_UPDATE => Action::SQLITE_UPDATE,
            _ => Action::UNKNOWN,
        }
    }
}

impl Connection {
    /// `feature = "hooks"` Register a callback function to be invoked whenever
    /// a transaction is committed.
    ///
    /// The callback returns `true` to rollback.
    pub fn commit_hook<F>(&self, hook: Option<F>)
    where
        F: FnMut() -> bool + Send + 'static,
    {
        self.db.borrow_mut().commit_hook(hook);
    }

    /// `feature = "hooks"` Register a callback function to be invoked whenever
    /// a transaction is committed.
    ///
    /// The callback returns `true` to rollback.
    pub fn rollback_hook<F>(&self, hook: Option<F>)
    where
        F: FnMut() + Send + 'static,
    {
        self.db.borrow_mut().rollback_hook(hook);
    }

    /// `feature = "hooks"` Register a callback function to be invoked whenever
    /// a row is updated, inserted or deleted in a rowid table.
    ///
    /// The callback parameters are:
    ///
    /// - the type of database update (SQLITE_INSERT, SQLITE_UPDATE or
    /// SQLITE_DELETE),
    /// - the name of the database ("main", "temp", ...),
    /// - the name of the table that is updated,
    /// - the ROWID of the row that is updated.
    pub fn update_hook<F>(&self, hook: Option<F>)
    where
        F: FnMut(Action, &str, &str, i64) + Send + 'static,
    {
        self.db.borrow_mut().update_hook(hook);
    }

    /// `feature = "hooks"` Register a query progress callback.
    ///
    /// The parameter `num_ops` is the approximate number of virtual machine instructions that are evaluated between successive invocations of the `handler`.
    /// If `num_ops` is less than one then the progress handler is disabled.
    ///
    /// If the progress callback returns `true`, the operation is interrupted.
    pub fn progress_handler<F>(&self, num_ops: c_int, handler: Option<F>)
    where
        F: FnMut() -> bool + Send + RefUnwindSafe + 'static,
    {
        self.db.borrow_mut().progress_handler(num_ops, handler);
    }
}

impl InnerConnection {
    pub fn remove_hooks(&mut self) {
        self.update_hook(None::<fn(Action, &str, &str, i64)>);
        self.commit_hook(None::<fn() -> bool>);
        self.rollback_hook(None::<fn()>);
        self.progress_handler(0, None::<fn() -> bool>);
    }

    fn commit_hook<F>(&mut self, hook: Option<F>)
    where
        F: FnMut() -> bool + Send + 'static,
    {
        unsafe extern "C" fn call_boxed_closure<F>(p_arg: *mut c_void) -> c_int
        where
            F: FnMut() -> bool,
        {
            let r = catch_unwind(|| {
                let boxed_hook: *mut F = p_arg as *mut F;
                (*boxed_hook)()
            });
            if let Ok(true) = r {
                1
            } else {
                0
            }
        }

        // unlike `sqlite3_create_function_v2`, we cannot specify a `xDestroy` with
        // `sqlite3_commit_hook`. so we keep the `xDestroy` function in
        // `InnerConnection.free_boxed_hook`.
        let free_commit_hook = if hook.is_some() {
            Some(free_boxed_hook::<F> as unsafe fn(*mut c_void))
        } else {
            None
        };

        let previous_hook = match hook {
            Some(hook) => {
                let boxed_hook: *mut F = Box::into_raw(Box::new(hook));
                unsafe {
                    ffi::sqlite3_commit_hook(
                        self.db(),
                        Some(call_boxed_closure::<F>),
                        boxed_hook as *mut _,
                    )
                }
            }
            _ => unsafe { ffi::sqlite3_commit_hook(self.db(), None, ptr::null_mut()) },
        };
        if !previous_hook.is_null() {
            if let Some(free_boxed_hook) = self.free_commit_hook {
                unsafe { free_boxed_hook(previous_hook) };
            }
        }
        self.free_commit_hook = free_commit_hook;
    }

    fn rollback_hook<F>(&mut self, hook: Option<F>)
    where
        F: FnMut() + Send + 'static,
    {
        unsafe extern "C" fn call_boxed_closure<F>(p_arg: *mut c_void)
        where
            F: FnMut(),
        {
            let _ = catch_unwind(|| {
                let boxed_hook: *mut F = p_arg as *mut F;
                (*boxed_hook)();
            });
        }

        let free_rollback_hook = if hook.is_some() {
            Some(free_boxed_hook::<F> as unsafe fn(*mut c_void))
        } else {
            None
        };

        let previous_hook = match hook {
            Some(hook) => {
                let boxed_hook: *mut F = Box::into_raw(Box::new(hook));
                unsafe {
                    ffi::sqlite3_rollback_hook(
                        self.db(),
                        Some(call_boxed_closure::<F>),
                        boxed_hook as *mut _,
                    )
                }
            }
            _ => unsafe { ffi::sqlite3_rollback_hook(self.db(), None, ptr::null_mut()) },
        };
        if !previous_hook.is_null() {
            if let Some(free_boxed_hook) = self.free_rollback_hook {
                unsafe { free_boxed_hook(previous_hook) };
            }
        }
        self.free_rollback_hook = free_rollback_hook;
    }

    fn update_hook<F>(&mut self, hook: Option<F>)
    where
        F: FnMut(Action, &str, &str, i64) + Send + 'static,
    {
        unsafe extern "C" fn call_boxed_closure<F>(
            p_arg: *mut c_void,
            action_code: c_int,
            db_str: *const c_char,
            tbl_str: *const c_char,
            row_id: i64,
        ) where
            F: FnMut(Action, &str, &str, i64),
        {
            use std::ffi::CStr;
            use std::str;

            let action = Action::from(action_code);
            let db_name = {
                let c_slice = CStr::from_ptr(db_str).to_bytes();
                str::from_utf8(c_slice)
            };
            let tbl_name = {
                let c_slice = CStr::from_ptr(tbl_str).to_bytes();
                str::from_utf8(c_slice)
            };

            let _ = catch_unwind(|| {
                let boxed_hook: *mut F = p_arg as *mut F;
                (*boxed_hook)(
                    action,
                    db_name.expect("illegal db name"),
                    tbl_name.expect("illegal table name"),
                    row_id,
                );
            });
        }

        let free_update_hook = if hook.is_some() {
            Some(free_boxed_hook::<F> as unsafe fn(*mut c_void))
        } else {
            None
        };

        let previous_hook = match hook {
            Some(hook) => {
                let boxed_hook: *mut F = Box::into_raw(Box::new(hook));
                unsafe {
                    ffi::sqlite3_update_hook(
                        self.db(),
                        Some(call_boxed_closure::<F>),
                        boxed_hook as *mut _,
                    )
                }
            }
            _ => unsafe { ffi::sqlite3_update_hook(self.db(), None, ptr::null_mut()) },
        };
        if !previous_hook.is_null() {
            if let Some(free_boxed_hook) = self.free_update_hook {
                unsafe { free_boxed_hook(previous_hook) };
            }
        }
        self.free_update_hook = free_update_hook;
    }

    fn progress_handler<F>(&mut self, num_ops: c_int, handler: Option<F>)
    where
        F: FnMut() -> bool + Send + RefUnwindSafe + 'static,
    {
        unsafe extern "C" fn call_boxed_closure<F>(p_arg: *mut c_void) -> c_int
        where
            F: FnMut() -> bool,
        {
            let r = catch_unwind(|| {
                let boxed_handler: *mut F = p_arg as *mut F;
                (*boxed_handler)()
            });
            if let Ok(true) = r {
                1
            } else {
                0
            }
        }

        match handler {
            Some(handler) => {
                let boxed_handler = Box::new(handler);
                unsafe {
                    ffi::sqlite3_progress_handler(
                        self.db(),
                        num_ops,
                        Some(call_boxed_closure::<F>),
                        &*boxed_handler as *const F as *mut _,
                    )
                }
                self.progress_handler = Some(boxed_handler);
            }
            _ => {
                unsafe { ffi::sqlite3_progress_handler(self.db(), num_ops, None, ptr::null_mut()) }
                self.progress_handler = None;
            }
        };
    }
}

unsafe fn free_boxed_hook<F>(p: *mut c_void) {
    drop(Box::from_raw(p as *mut F));
}

#[cfg(test)]
mod test {
    use super::Action;
    use crate::Connection;
    use lazy_static::lazy_static;
    use std::sync::atomic::{AtomicBool, Ordering};

    #[test]
    fn test_commit_hook() {
        let db = Connection::open_in_memory().unwrap();

        lazy_static! {
            static ref CALLED: AtomicBool = AtomicBool::new(false);
        }
        db.commit_hook(Some(|| {
            CALLED.store(true, Ordering::Relaxed);
            false
        }));
        db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
            .unwrap();
        assert!(CALLED.load(Ordering::Relaxed));
    }

    #[test]
    fn test_fn_commit_hook() {
        let db = Connection::open_in_memory().unwrap();

        fn hook() -> bool {
            true
        }

        db.commit_hook(Some(hook));
        db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
            .unwrap_err();
    }

    #[test]
    fn test_rollback_hook() {
        let db = Connection::open_in_memory().unwrap();

        lazy_static! {
            static ref CALLED: AtomicBool = AtomicBool::new(false);
        }
        db.rollback_hook(Some(|| {
            CALLED.store(true, Ordering::Relaxed);
        }));
        db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); ROLLBACK;")
            .unwrap();
        assert!(CALLED.load(Ordering::Relaxed));
    }

    #[test]
    fn test_update_hook() {
        let db = Connection::open_in_memory().unwrap();

        lazy_static! {
            static ref CALLED: AtomicBool = AtomicBool::new(false);
        }
        db.update_hook(Some(|action, db: &str, tbl: &str, row_id| {
            assert_eq!(Action::SQLITE_INSERT, action);
            assert_eq!("main", db);
            assert_eq!("foo", tbl);
            assert_eq!(1, row_id);
            CALLED.store(true, Ordering::Relaxed);
        }));
        db.execute_batch("CREATE TABLE foo (t TEXT)").unwrap();
        db.execute_batch("INSERT INTO foo VALUES ('lisa')").unwrap();
        assert!(CALLED.load(Ordering::Relaxed));
    }
}
<commit_msg>Expose query progress information<commit_after>//! `feature = "hooks"` Commit, Data Change and Rollback Notification Callbacks
#![allow(non_camel_case_types)]

use std::os::raw::{c_char, c_int, c_void};
use std::panic::{catch_unwind, RefUnwindSafe};
use std::ptr;

use crate::ffi;

use crate::{Connection, InnerConnection};

/// `feature = "hooks"` Action Codes
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(i32)]
#[non_exhaustive]
pub enum Action {
    /// Unsupported / unexpected action
    UNKNOWN = -1,
    /// DELETE command
    SQLITE_DELETE = ffi::SQLITE_DELETE,
    /// INSERT command
    SQLITE_INSERT = ffi::SQLITE_INSERT,
    /// UPDATE command
    SQLITE_UPDATE = ffi::SQLITE_UPDATE,
}

impl From<i32> for Action {
    fn from(code: i32) -> Action {
        match code {
            ffi::SQLITE_DELETE => Action::SQLITE_DELETE,
            ffi::SQLITE_INSERT => Action::SQLITE_INSERT,
            ffi::SQLITE_UPDATE => Action::SQLITE_UPDATE,
            _ => Action::UNKNOWN,
        }
    }
}

impl Connection {
    /// `feature = "hooks"` Register a callback function to be invoked whenever
    /// a transaction is committed.
    ///
    /// The callback returns `true` to rollback.
    pub fn commit_hook<F>(&self, hook: Option<F>)
    where
        F: FnMut() -> bool + Send + 'static,
    {
        self.db.borrow_mut().commit_hook(hook);
    }

    /// `feature = "hooks"` Register a callback function to be invoked whenever
    /// a transaction is committed.
    ///
    /// The callback returns `true` to rollback.
    pub fn rollback_hook<F>(&self, hook: Option<F>)
    where
        F: FnMut() + Send + 'static,
    {
        self.db.borrow_mut().rollback_hook(hook);
    }

    /// `feature = "hooks"` Register a callback function to be invoked whenever
    /// a row is updated, inserted or deleted in a rowid table.
    ///
    /// The callback parameters are:
    ///
    /// - the type of database update (SQLITE_INSERT, SQLITE_UPDATE or
    /// SQLITE_DELETE),
    /// - the name of the database ("main", "temp", ...),
    /// - the name of the table that is updated,
    /// - the ROWID of the row that is updated.
    pub fn update_hook<F>(&self, hook: Option<F>)
    where
        F: FnMut(Action, &str, &str, i64) + Send + 'static,
    {
        self.db.borrow_mut().update_hook(hook);
    }

    /// `feature = "hooks"` Register a query progress callback.
    ///
    /// The parameter `num_ops` is the approximate number of virtual machine instructions that are evaluated between successive invocations of the `handler`.
    /// If `num_ops` is less than one then the progress handler is disabled.
    ///
    /// If the progress callback returns `true`, the operation is interrupted.
    pub fn progress_handler<F>(&self, num_ops: c_int, handler: Option<F>)
    where
        F: FnMut() -> bool + Send + RefUnwindSafe + 'static,
    {
        self.db.borrow_mut().progress_handler(num_ops, handler);
    }
}

impl InnerConnection {
    pub fn remove_hooks(&mut self) {
        self.update_hook(None::<fn(Action, &str, &str, i64)>);
        self.commit_hook(None::<fn() -> bool>);
        self.rollback_hook(None::<fn()>);
        self.progress_handler(0, None::<fn() -> bool>);
    }

    fn commit_hook<F>(&mut self, hook: Option<F>)
    where
        F: FnMut() -> bool + Send + 'static,
    {
        unsafe extern "C" fn call_boxed_closure<F>(p_arg: *mut c_void) -> c_int
        where
            F: FnMut() -> bool,
        {
            let r = catch_unwind(|| {
                let boxed_hook: *mut F = p_arg as *mut F;
                (*boxed_hook)()
            });
            if let Ok(true) = r {
                1
            } else {
                0
            }
        }

        // unlike `sqlite3_create_function_v2`, we cannot specify a `xDestroy` with
        // `sqlite3_commit_hook`. so we keep the `xDestroy` function in
        // `InnerConnection.free_boxed_hook`.
        let free_commit_hook = if hook.is_some() {
            Some(free_boxed_hook::<F> as unsafe fn(*mut c_void))
        } else {
            None
        };

        let previous_hook = match hook {
            Some(hook) => {
                let boxed_hook: *mut F = Box::into_raw(Box::new(hook));
                unsafe {
                    ffi::sqlite3_commit_hook(
                        self.db(),
                        Some(call_boxed_closure::<F>),
                        boxed_hook as *mut _,
                    )
                }
            }
            _ => unsafe { ffi::sqlite3_commit_hook(self.db(), None, ptr::null_mut()) },
        };
        if !previous_hook.is_null() {
            if let Some(free_boxed_hook) = self.free_commit_hook {
                unsafe { free_boxed_hook(previous_hook) };
            }
        }
        self.free_commit_hook = free_commit_hook;
    }

    fn rollback_hook<F>(&mut self, hook: Option<F>)
    where
        F: FnMut() + Send + 'static,
    {
        unsafe extern "C" fn call_boxed_closure<F>(p_arg: *mut c_void)
        where
            F: FnMut(),
        {
            let _ = catch_unwind(|| {
                let boxed_hook: *mut F = p_arg as *mut F;
                (*boxed_hook)();
            });
        }

        let free_rollback_hook = if hook.is_some() {
            Some(free_boxed_hook::<F> as unsafe fn(*mut c_void))
        } else {
            None
        };

        let previous_hook = match hook {
            Some(hook) => {
                let boxed_hook: *mut F = Box::into_raw(Box::new(hook));
                unsafe {
                    ffi::sqlite3_rollback_hook(
                        self.db(),
                        Some(call_boxed_closure::<F>),
                        boxed_hook as *mut _,
                    )
                }
            }
            _ => unsafe { ffi::sqlite3_rollback_hook(self.db(), None, ptr::null_mut()) },
        };
        if !previous_hook.is_null() {
            if let Some(free_boxed_hook) = self.free_rollback_hook {
                unsafe { free_boxed_hook(previous_hook) };
            }
        }
        self.free_rollback_hook = free_rollback_hook;
    }

    fn update_hook<F>(&mut self, hook: Option<F>)
    where
        F: FnMut(Action, &str, &str, i64) + Send + 'static,
    {
        unsafe extern "C" fn call_boxed_closure<F>(
            p_arg: *mut c_void,
            action_code: c_int,
            db_str: *const c_char,
            tbl_str: *const c_char,
            row_id: i64,
        ) where
            F: FnMut(Action, &str, &str, i64),
        {
            use std::ffi::CStr;
            use std::str;

            let action = Action::from(action_code);
            let db_name = {
                let c_slice = CStr::from_ptr(db_str).to_bytes();
                str::from_utf8(c_slice)
            };
            let tbl_name = {
                let c_slice = CStr::from_ptr(tbl_str).to_bytes();
                str::from_utf8(c_slice)
            };

            let _ = catch_unwind(|| {
                let boxed_hook: *mut F = p_arg as *mut F;
                (*boxed_hook)(
                    action,
                    db_name.expect("illegal db name"),
                    tbl_name.expect("illegal table name"),
                    row_id,
                );
            });
        }

        let free_update_hook = if hook.is_some() {
            Some(free_boxed_hook::<F> as unsafe fn(*mut c_void))
        } else {
            None
        };

        let previous_hook = match hook {
            Some(hook) => {
                let boxed_hook: *mut F = Box::into_raw(Box::new(hook));
                unsafe {
                    ffi::sqlite3_update_hook(
                        self.db(),
                        Some(call_boxed_closure::<F>),
                        boxed_hook as *mut _,
                    )
                }
            }
            _ => unsafe { ffi::sqlite3_update_hook(self.db(), None, ptr::null_mut()) },
        };
        if !previous_hook.is_null() {
            if let Some(free_boxed_hook) = self.free_update_hook {
                unsafe { free_boxed_hook(previous_hook) };
            }
        }
        self.free_update_hook = free_update_hook;
    }

    fn progress_handler<F>(&mut self, num_ops: c_int, handler: Option<F>)
    where
        F: FnMut() -> bool + Send + RefUnwindSafe + 'static,
    {
        unsafe extern "C" fn call_boxed_closure<F>(p_arg: *mut c_void) -> c_int
        where
            F: FnMut() -> bool,
        {
            let r = catch_unwind(|| {
                let boxed_handler: *mut F = p_arg as *mut F;
                (*boxed_handler)()
            });
            if let Ok(true) = r {
                1
            } else {
                0
            }
        }

        match handler {
            Some(handler) => {
                let boxed_handler = Box::new(handler);
                unsafe {
                    ffi::sqlite3_progress_handler(
                        self.db(),
                        num_ops,
                        Some(call_boxed_closure::<F>),
                        &*boxed_handler as *const F as *mut _,
                    )
                }
                self.progress_handler = Some(boxed_handler);
            }
            _ => {
                unsafe { ffi::sqlite3_progress_handler(self.db(), num_ops, None, ptr::null_mut()) }
                self.progress_handler = None;
            }
        };
    }
}

unsafe fn free_boxed_hook<F>(p: *mut c_void) {
    drop(Box::from_raw(p as *mut F));
}

#[cfg(test)]
mod test {
    use super::Action;
    use crate::Connection;
    use lazy_static::lazy_static;
    use std::sync::atomic::{AtomicBool, Ordering};

    #[test]
    fn test_commit_hook() {
        let db = Connection::open_in_memory().unwrap();

        lazy_static! {
            static ref CALLED: AtomicBool = AtomicBool::new(false);
        }
        db.commit_hook(Some(|| {
            CALLED.store(true, Ordering::Relaxed);
            false
        }));
        db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
            .unwrap();
        assert!(CALLED.load(Ordering::Relaxed));
    }

    #[test]
    fn test_fn_commit_hook() {
        let db = Connection::open_in_memory().unwrap();

        fn hook() -> bool {
            true
        }

        db.commit_hook(Some(hook));
        db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
            .unwrap_err();
    }

    #[test]
    fn test_rollback_hook() {
        let db = Connection::open_in_memory().unwrap();

        lazy_static! {
            static ref CALLED: AtomicBool = AtomicBool::new(false);
        }
        db.rollback_hook(Some(|| {
            CALLED.store(true, Ordering::Relaxed);
        }));
        db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); ROLLBACK;")
            .unwrap();
        assert!(CALLED.load(Ordering::Relaxed));
    }

    #[test]
    fn test_update_hook() {
        let db = Connection::open_in_memory().unwrap();

        lazy_static! {
            static ref CALLED: AtomicBool = AtomicBool::new(false);
        }
        db.update_hook(Some(|action, db: &str, tbl: &str, row_id| {
            assert_eq!(Action::SQLITE_INSERT, action);
            assert_eq!("main", db);
            assert_eq!("foo", tbl);
            assert_eq!(1, row_id);
            CALLED.store(true, Ordering::Relaxed);
        }));
        db.execute_batch("CREATE TABLE foo (t TEXT)").unwrap();
        db.execute_batch("INSERT INTO foo VALUES ('lisa')").unwrap();
        assert!(CALLED.load(Ordering::Relaxed));
    }

    #[test]
    fn test_progress_handler() {
        let db = Connection::open_in_memory().unwrap();

        lazy_static! {
            static ref CALLED: AtomicBool = AtomicBool::new(false);
        }
        db.progress_handler(1, Some(|| {
            CALLED.store(true, Ordering::Relaxed);
            false
        }));
        db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
            .unwrap();
        assert!(CALLED.load(Ordering::Relaxed));
    }

    #[test]
    fn test_progress_handler_interrupt() {
        let db = Connection::open_in_memory().unwrap();

        fn handler() -> bool {
            true
        }

        db.progress_handler(1, Some(handler));
        db.execute_batch("BEGIN; CREATE TABLE foo (t TEXT); COMMIT;")
            .unwrap_err();
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};

#[derive(Debug, Clone, Eq, Hash)]
pub struct Ident(String);

impl Ident {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        t.into()
    }
}

impl<'a> From<&'a str> for Ident {
    fn from(s: &str) -> Self {
        Ident(s.to_owned())
    }
}

impl From<String> for Ident {
    fn from(s: String) -> Self {
        Ident(s)
    }
}

impl From<usize> for Ident {
    fn from(u: usize) -> Self {
        Ident(u.to_string())
    }
}

impl AsRef<str> for Ident {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl Display for Ident {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(formatter)
    }
}

impl<T: ?Sized> PartialEq<T> for Ident
    where T: AsRef<str>
{
    fn eq(&self, other: &T) -> bool {
        self.0 == other.as_ref()
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use nom::IResult;
    use space::skip_whitespace;
    use unicode_xid::UnicodeXID;

    pub fn ident(input: &str) -> IResult<&str, Ident> {
        let (rest, id) = match word(input) {
            IResult::Done(rest, id) => (rest, id),
            IResult::Error => return IResult::Error,
        };

        match id.as_ref() {
            // From https://doc.rust-lang.org/grammar.html#keywords
            "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" |
            "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" |
            "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" |
            "mut" | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
            "return" | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" |
            "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
            "while" | "yield" => IResult::Error,
            _ => IResult::Done(rest, id),
        }
    }

    pub fn word(mut input: &str) -> IResult<&str, Ident> {
        input = skip_whitespace(input);

        let mut chars = input.char_indices();
        match chars.next() {
            Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
            _ => return IResult::Error,
        }

        while let Some((i, ch)) = chars.next() {
            if !UnicodeXID::is_xid_continue(ch) {
                return IResult::Done(&input[i..], input[..i].into());
            }
        }

        IResult::Done("", input.into())
    }

    #[cfg(feature = "full")]
    pub fn wordlike(mut input: &str) -> IResult<&str, Ident> {
        input = skip_whitespace(input);

        for (i, ch) in input.char_indices() {
            if !UnicodeXID::is_xid_start(ch) && !UnicodeXID::is_xid_continue(ch) {
                return if i == 0 {
                    IResult::Error
                } else {
                    IResult::Done(&input[i..], input[..i].into())
                };
            }
        }

        IResult::Done("", input.into())
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Ident {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append(self.as_ref())
        }
    }
}
<commit_msg>From<Cow<str>> for Ident<commit_after>use std::borrow::Cow;
use std::fmt::{self, Display};

#[derive(Debug, Clone, Eq, Hash)]
pub struct Ident(String);

impl Ident {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        t.into()
    }
}

impl<'a> From<&'a str> for Ident {
    fn from(s: &str) -> Self {
        Ident(s.to_owned())
    }
}

impl<'a> From<Cow<'a, str>> for Ident {
    fn from(s: Cow<'a, str>) -> Self {
        Ident(s.into_owned())
    }
}

impl From<String> for Ident {
    fn from(s: String) -> Self {
        Ident(s)
    }
}

impl From<usize> for Ident {
    fn from(u: usize) -> Self {
        Ident(u.to_string())
    }
}

impl AsRef<str> for Ident {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl Display for Ident {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(formatter)
    }
}

impl<T: ?Sized> PartialEq<T> for Ident
    where T: AsRef<str>
{
    fn eq(&self, other: &T) -> bool {
        self.0 == other.as_ref()
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use nom::IResult;
    use space::skip_whitespace;
    use unicode_xid::UnicodeXID;

    pub fn ident(input: &str) -> IResult<&str, Ident> {
        let (rest, id) = match word(input) {
            IResult::Done(rest, id) => (rest, id),
            IResult::Error => return IResult::Error,
        };

        match id.as_ref() {
            // From https://doc.rust-lang.org/grammar.html#keywords
            "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" |
            "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" |
            "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" |
            "mut" | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
            "return" | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" |
            "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
            "while" | "yield" => IResult::Error,
            _ => IResult::Done(rest, id),
        }
    }

    pub fn word(mut input: &str) -> IResult<&str, Ident> {
        input = skip_whitespace(input);

        let mut chars = input.char_indices();
        match chars.next() {
            Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
            _ => return IResult::Error,
        }

        while let Some((i, ch)) = chars.next() {
            if !UnicodeXID::is_xid_continue(ch) {
                return IResult::Done(&input[i..], input[..i].into());
            }
        }

        IResult::Done("", input.into())
    }

    #[cfg(feature = "full")]
    pub fn wordlike(mut input: &str) -> IResult<&str, Ident> {
        input = skip_whitespace(input);

        for (i, ch) in input.char_indices() {
            if !UnicodeXID::is_xid_start(ch) && !UnicodeXID::is_xid_continue(ch) {
                return if i == 0 {
                    IResult::Error
                } else {
                    IResult::Done(&input[i..], input[..i].into())
                };
            }
        }

        IResult::Done("", input.into())
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Ident {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append(self.as_ref())
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::io::Read;
use std::io::BufRead;
use std::io::BufReader;
use std::mem;
use std::u64;

#[cfg(feature = "bytes")]
use bytes::Bytes;
#[cfg(feature = "bytes")]
use bytes::BytesMut;
#[cfg(feature = "bytes")]
use bytes::BufMut;

use ProtobufResult;
use ProtobufError;
use error::WireError;

// If an input stream is constructed with a `Read`, we create a
// `BufReader` with an internal buffer of this size.
const INPUT_STREAM_BUFFER_SIZE: usize = 4096;

const USE_UNSAFE_FOR_SPEED: bool = true;

const NO_LIMIT: u64 = u64::MAX;

/// Hold all possible combinations of input source
enum InputSource<'a> {
    BufRead(&'a mut BufRead),
    Read(BufReader<&'a mut Read>),
    Slice(&'a [u8]),
    #[cfg(feature = "bytes")]
    Bytes(&'a Bytes),
}

/// Dangerous implementation of `BufRead`.
///
/// Unsafe wrapper around BufRead which assumes that `BufRead` buf is
/// not moved when `BufRead` is moved.
///
/// This assumption is generally incorrect, however, in practice
/// `BufReadIter` is created either from `BufRead` reference (which
/// cannot  be moved, because it is locked by `CodedInputStream`) or from
/// `BufReader` which does not move its buffer (we know that from
/// inspecting rust standard library).
///
/// It is important for `CodedInputStream` performance that small reads
/// (e. g. 4 bytes reads) do not involve virtual calls or switches.
/// This is achievable with `BufReadIter`.
pub struct BufReadIter<'a> {
    input_source: InputSource<'a>,
    buf: &'a [u8],
    pos_within_buf: usize,
    limit_within_buf: usize,
    pos_of_buf_start: u64,
    limit: u64,
}

impl<'a> Drop for BufReadIter<'a> {
    fn drop(&mut self) {
        match self.input_source {
            InputSource::BufRead(ref mut buf_read) => buf_read.consume(self.pos_within_buf),
            InputSource::Read(_) => {
                // Nothing to flush, because we own BufReader
            }
            _ => {},
        }
    }
}

impl<'ignore> BufReadIter<'ignore> {
    pub fn from_read<'a>(read: &'a mut Read) -> BufReadIter<'a> {
        BufReadIter {
            input_source: InputSource::Read(
                BufReader::with_capacity(INPUT_STREAM_BUFFER_SIZE, read)),
            buf: &[],
            pos_within_buf: 0,
            limit_within_buf: 0,
            pos_of_buf_start: 0,
            limit: NO_LIMIT,
        }
    }

    pub fn from_buf_read<'a>(buf_read: &'a mut BufRead) -> BufReadIter<'a> {
        BufReadIter {
            input_source: InputSource::BufRead(buf_read),
            buf: &[],
            pos_within_buf: 0,
            limit_within_buf: 0,
            pos_of_buf_start: 0,
            limit: NO_LIMIT,
        }
    }

    pub fn from_byte_slice<'a>(bytes: &'a [u8]) -> BufReadIter<'a> {
        BufReadIter {
            input_source: InputSource::Slice(bytes),
            buf: bytes,
            pos_within_buf: 0,
            limit_within_buf: bytes.len(),
            pos_of_buf_start: 0,
            limit: NO_LIMIT,
        }
    }

    #[cfg(feature = "bytes")]
    pub fn from_bytes<'a>(bytes: &'a Bytes) -> BufReadIter<'a> {
        BufReadIter {
            input_source: InputSource::Bytes(bytes),
            buf: &bytes,
            pos_within_buf: 0,
            limit_within_buf: bytes.len(),
            pos_of_buf_start: 0,
            limit: NO_LIMIT,
        }
    }

    #[inline]
    fn assertions(&self) {
        debug_assert!(self.pos_within_buf <= self.limit_within_buf);
        debug_assert!(self.limit_within_buf <= self.buf.len());
        debug_assert!(self.pos_of_buf_start + self.pos_within_buf as u64 <= self.limit);
    }

    pub fn pos(&self) -> u64 {
        self.pos_of_buf_start + self.pos_within_buf as u64
    }

    /// Recompute `limit_within_buf` after update of `limit`
    #[inline]
    fn update_limit_within_buf(&mut self) {
        if self.pos_of_buf_start + (self.buf.len() as u64) <= self.limit {
            self.limit_within_buf = self.buf.len();
        } else {
            self.limit_within_buf = (self.limit - self.pos_of_buf_start) as usize;
        }

        self.assertions();
    }

    pub fn push_limit(&mut self, limit: u64) -> ProtobufResult<u64> {
        // TODO: return error instead of panic
        let new_limit = match self.pos().checked_add(limit) {
            Some(new_limit) => new_limit,
            None => return Err(ProtobufError::WireError(WireError::Other)),
        };

        if new_limit > self.limit {
            return Err(ProtobufError::WireError(WireError::Other));
        }

        let prev_limit = mem::replace(&mut self.limit, new_limit);

        self.update_limit_within_buf();

        Ok(prev_limit)
    }

    #[inline]
    pub fn pop_limit(&mut self, limit: u64) {
        assert!(limit >= self.limit);

        self.limit = limit;

        self.update_limit_within_buf();
    }

    #[inline]
    pub fn remaining_in_buf(&self) -> &[u8] {
        if USE_UNSAFE_FOR_SPEED {
            unsafe { &self.buf.get_unchecked(self.pos_within_buf..self.limit_within_buf) }
        } else {
            &self.buf[self.pos_within_buf..self.limit_within_buf]
        }
    }

    #[inline]
    pub fn remaining_in_buf_len(&self) -> usize {
        self.limit_within_buf - self.pos_within_buf
    }

    pub fn bytes_until_limit(&self) -> u64 {
        if self.limit == NO_LIMIT {
            NO_LIMIT
        } else {
            self.limit - (self.pos_of_buf_start + self.pos_within_buf as u64)
        }
    }

    #[inline(always)]
    pub fn eof(&mut self) -> ProtobufResult<bool> {
        if self.pos_within_buf == self.limit_within_buf {
            Ok(self.fill_buf()?.is_empty())
        } else {
            Ok(false)
        }
    }

    #[inline(always)]
    pub fn read_byte(&mut self) -> ProtobufResult<u8> {
        if self.pos_within_buf == self.limit_within_buf {
            if self.fill_buf()?.is_empty() {
                return Err(ProtobufError::WireError(WireError::UnexpectedEof));
            }
        }

        let r = if USE_UNSAFE_FOR_SPEED {
            unsafe { *self.buf.get_unchecked(self.pos_within_buf) }
        } else {
            self.buf[self.pos_within_buf]
        };
        self.pos_within_buf += 1;
        Ok(r)
    }

    #[cfg(feature = "bytes")]
    pub fn read_exact_bytes(&mut self, len: usize) -> ProtobufResult<Bytes> {
        if let InputSource::Bytes(bytes) = self.input_source {
            if self.pos_within_buf + len > self.limit_within_buf {
                return Err(ProtobufError::WireError(WireError::UnexpectedEof));
            }
            let r = bytes.slice(self.pos_within_buf, self.pos_within_buf + len);
            self.pos_within_buf += len;
            Ok(r)
        } else {
            let mut r = BytesMut::with_capacity(len);
            unsafe {
                {
                    let mut buf = &mut r.bytes_mut()[..len];
                    self.read_exact(buf)?;
                }
                r.advance_mut(len);
            }
            Ok(r.freeze())
        }
    }

    fn _read(&mut self, buf: &mut [u8]) -> ProtobufResult<usize> {
        self.fill_buf()?;

        let rem = &self.buf[self.pos_within_buf..self.limit_within_buf];

        let len = cmp::min(rem.len(), buf.len());
        &mut buf[..len].copy_from_slice(&rem[..len]);
        self.pos_within_buf += len;
        Ok((len))
    }

    pub fn read_exact(&mut self, mut buf: &mut [u8]) -> ProtobufResult<()> {
        if self.remaining_in_buf_len() >= buf.len() {
            let buf_len = buf.len();
            buf.copy_from_slice(&self.buf[self.pos_within_buf.. self.pos_within_buf + buf_len]);
            self.pos_within_buf += buf_len;
            return Ok(());
        }

        if self.bytes_until_limit() < buf.len() as u64 {
            return Err(ProtobufError::WireError(WireError::UnexpectedEof));
        }

        let consume = self.pos_within_buf;
        self.pos_of_buf_start += self.pos_within_buf as u64;
        self.pos_within_buf = 0;
        self.buf = &[];
        self.limit_within_buf = 0;

        match self.input_source {
            InputSource::Read(ref mut buf_read) => {
                buf_read.consume(consume);
                buf_read.read_exact(buf)?;
            }
            InputSource::BufRead(ref mut buf_read) => {
                buf_read.consume(consume);
                buf_read.read_exact(buf)?;
            }
            _ => {
                return Err(ProtobufError::WireError(WireError::UnexpectedEof));
            }
        }

        self.pos_of_buf_start += buf.len() as u64;

        self.assertions();

        Ok(())
    }

    fn do_fill_buf(&mut self) -> ProtobufResult<()> {
        debug_assert!(self.pos_within_buf == self.limit_within_buf);

        // Limit is reached, so EOF is reached
        if self.limit_within_buf != self.buf.len() {
            return Ok(());
        }

        let consume = self.buf.len();
        self.pos_of_buf_start += self.buf.len() as u64;
        self.buf = &[];
        self.pos_within_buf = 0;
        self.limit_within_buf = 0;

        match self.input_source {
            InputSource::Read(ref mut buf_read) => {
                buf_read.consume(consume);
                self.buf = unsafe { mem::transmute(buf_read.fill_buf()?) };
            }
            InputSource::BufRead(ref mut buf_read) => {
                buf_read.consume(consume);
                self.buf = unsafe { mem::transmute(buf_read.fill_buf()?) };
            }
            _ => {
                return Ok(());
            }
        }

        self.update_limit_within_buf();

        Ok(())
    }

    #[inline(always)]
    pub fn fill_buf(&mut self) -> ProtobufResult<&[u8]> {
        if self.pos_within_buf == self.limit_within_buf {
            self.do_fill_buf()?;
        }

        Ok(if USE_UNSAFE_FOR_SPEED {
            unsafe { self.buf.get_unchecked(self.pos_within_buf..self.limit_within_buf) }
        } else {
            &self.buf[self.pos_within_buf..self.limit_within_buf]
        })
    }

    #[inline(always)]
    pub fn consume(&mut self, amt: usize) {
        assert!(amt <= self.limit_within_buf - self.pos_within_buf);
        self.pos_within_buf += amt;
    }
}

#[cfg(all(test, feature = "bytes"))]
mod test_bytes {
    use super::*;
    use std::io::Write;

    fn make_long_string(len: usize) -> Vec<u8> {
        let mut s = Vec::new();
        while s.len() < len {
            let len = s.len();
            write!(&mut s, "{}", len).expect("unexpected");
        }
        s.truncate(len);
        s
    }

    #[test]
    fn read_exact_bytes_from_slice() {
        let bytes = make_long_string(100);
        let mut bri = BufReadIter::from_byte_slice(&bytes[..]);
        assert_eq!(&bytes[..90], &bri.read_exact_bytes(90).unwrap()[..]);
        assert_eq!(bytes[90], bri.read_byte().expect("read_byte"));
    }

    #[test]
    fn read_exact_bytes_from_bytes() {
        let bytes = Bytes::from(make_long_string(100));
        let mut bri = BufReadIter::from_bytes(&bytes);
        let read = bri.read_exact_bytes(90).unwrap();
        assert_eq!(&bytes[..90], &read[..]);
        assert_eq!(&bytes[..90].as_ptr(), &read.as_ptr());
        assert_eq!(bytes[90], bri.read_byte().expect("read_byte"));
    }

}
<commit_msg>Optimize read byte slightly<commit_after>use std::cmp;
use std::io::Read;
use std::io::BufRead;
use std::io::BufReader;
use std::mem;
use std::u64;

#[cfg(feature = "bytes")]
use bytes::Bytes;
#[cfg(feature = "bytes")]
use bytes::BytesMut;
#[cfg(feature = "bytes")]
use bytes::BufMut;

use ProtobufResult;
use ProtobufError;
use error::WireError;

// If an input stream is constructed with a `Read`, we create a
// `BufReader` with an internal buffer of this size.
const INPUT_STREAM_BUFFER_SIZE: usize = 4096;

const USE_UNSAFE_FOR_SPEED: bool = true;

const NO_LIMIT: u64 = u64::MAX;

/// Hold all possible combinations of input source
enum InputSource<'a> {
    BufRead(&'a mut BufRead),
    Read(BufReader<&'a mut Read>),
    Slice(&'a [u8]),
    #[cfg(feature = "bytes")]
    Bytes(&'a Bytes),
}

/// Dangerous implementation of `BufRead`.
///
/// Unsafe wrapper around BufRead which assumes that `BufRead` buf is
/// not moved when `BufRead` is moved.
///
/// This assumption is generally incorrect, however, in practice
/// `BufReadIter` is created either from `BufRead` reference (which
/// cannot  be moved, because it is locked by `CodedInputStream`) or from
/// `BufReader` which does not move its buffer (we know that from
/// inspecting rust standard library).
///
/// It is important for `CodedInputStream` performance that small reads
/// (e. g. 4 bytes reads) do not involve virtual calls or switches.
/// This is achievable with `BufReadIter`.
pub struct BufReadIter<'a> {
    input_source: InputSource<'a>,
    buf: &'a [u8],
    pos_within_buf: usize,
    limit_within_buf: usize,
    pos_of_buf_start: u64,
    limit: u64,
}

impl<'a> Drop for BufReadIter<'a> {
    fn drop(&mut self) {
        match self.input_source {
            InputSource::BufRead(ref mut buf_read) => buf_read.consume(self.pos_within_buf),
            InputSource::Read(_) => {
                // Nothing to flush, because we own BufReader
            }
            _ => {},
        }
    }
}

impl<'ignore> BufReadIter<'ignore> {
    pub fn from_read<'a>(read: &'a mut Read) -> BufReadIter<'a> {
        BufReadIter {
            input_source: InputSource::Read(
                BufReader::with_capacity(INPUT_STREAM_BUFFER_SIZE, read)),
            buf: &[],
            pos_within_buf: 0,
            limit_within_buf: 0,
            pos_of_buf_start: 0,
            limit: NO_LIMIT,
        }
    }

    pub fn from_buf_read<'a>(buf_read: &'a mut BufRead) -> BufReadIter<'a> {
        BufReadIter {
            input_source: InputSource::BufRead(buf_read),
            buf: &[],
            pos_within_buf: 0,
            limit_within_buf: 0,
            pos_of_buf_start: 0,
            limit: NO_LIMIT,
        }
    }

    pub fn from_byte_slice<'a>(bytes: &'a [u8]) -> BufReadIter<'a> {
        BufReadIter {
            input_source: InputSource::Slice(bytes),
            buf: bytes,
            pos_within_buf: 0,
            limit_within_buf: bytes.len(),
            pos_of_buf_start: 0,
            limit: NO_LIMIT,
        }
    }

    #[cfg(feature = "bytes")]
    pub fn from_bytes<'a>(bytes: &'a Bytes) -> BufReadIter<'a> {
        BufReadIter {
            input_source: InputSource::Bytes(bytes),
            buf: &bytes,
            pos_within_buf: 0,
            limit_within_buf: bytes.len(),
            pos_of_buf_start: 0,
            limit: NO_LIMIT,
        }
    }

    #[inline]
    fn assertions(&self) {
        debug_assert!(self.pos_within_buf <= self.limit_within_buf);
        debug_assert!(self.limit_within_buf <= self.buf.len());
        debug_assert!(self.pos_of_buf_start + self.pos_within_buf as u64 <= self.limit);
    }

    pub fn pos(&self) -> u64 {
        self.pos_of_buf_start + self.pos_within_buf as u64
    }

    /// Recompute `limit_within_buf` after update of `limit`
    #[inline]
    fn update_limit_within_buf(&mut self) {
        if self.pos_of_buf_start + (self.buf.len() as u64) <= self.limit {
            self.limit_within_buf = self.buf.len();
        } else {
            self.limit_within_buf = (self.limit - self.pos_of_buf_start) as usize;
        }

        self.assertions();
    }

    pub fn push_limit(&mut self, limit: u64) -> ProtobufResult<u64> {
        // TODO: return error instead of panic
        let new_limit = match self.pos().checked_add(limit) {
            Some(new_limit) => new_limit,
            None => return Err(ProtobufError::WireError(WireError::Other)),
        };

        if new_limit > self.limit {
            return Err(ProtobufError::WireError(WireError::Other));
        }

        let prev_limit = mem::replace(&mut self.limit, new_limit);

        self.update_limit_within_buf();

        Ok(prev_limit)
    }

    #[inline]
    pub fn pop_limit(&mut self, limit: u64) {
        assert!(limit >= self.limit);

        self.limit = limit;

        self.update_limit_within_buf();
    }

    #[inline]
    pub fn remaining_in_buf(&self) -> &[u8] {
        if USE_UNSAFE_FOR_SPEED {
            unsafe { &self.buf.get_unchecked(self.pos_within_buf..self.limit_within_buf) }
        } else {
            &self.buf[self.pos_within_buf..self.limit_within_buf]
        }
    }

    #[inline(always)]
    pub fn remaining_in_buf_len(&self) -> usize {
        self.limit_within_buf - self.pos_within_buf
    }

    pub fn bytes_until_limit(&self) -> u64 {
        if self.limit == NO_LIMIT {
            NO_LIMIT
        } else {
            self.limit - (self.pos_of_buf_start + self.pos_within_buf as u64)
        }
    }

    #[inline(always)]
    pub fn eof(&mut self) -> ProtobufResult<bool> {
        if self.pos_within_buf == self.limit_within_buf {
            Ok(self.fill_buf()?.is_empty())
        } else {
            Ok(false)
        }
    }

    #[inline(always)]
    pub fn read_byte(&mut self) -> ProtobufResult<u8> {
        if self.pos_within_buf == self.limit_within_buf {
            self.do_fill_buf()?;
            if self.remaining_in_buf_len() == 0 {
                return Err(ProtobufError::WireError(WireError::UnexpectedEof));
            }
        }

        let r = if USE_UNSAFE_FOR_SPEED {
            unsafe { *self.buf.get_unchecked(self.pos_within_buf) }
        } else {
            self.buf[self.pos_within_buf]
        };
        self.pos_within_buf += 1;
        Ok(r)
    }

    #[cfg(feature = "bytes")]
    pub fn read_exact_bytes(&mut self, len: usize) -> ProtobufResult<Bytes> {
        if let InputSource::Bytes(bytes) = self.input_source {
            if self.pos_within_buf + len > self.limit_within_buf {
                return Err(ProtobufError::WireError(WireError::UnexpectedEof));
            }
            let r = bytes.slice(self.pos_within_buf, self.pos_within_buf + len);
            self.pos_within_buf += len;
            Ok(r)
        } else {
            let mut r = BytesMut::with_capacity(len);
            unsafe {
                {
                    let mut buf = &mut r.bytes_mut()[..len];
                    self.read_exact(buf)?;
                }
                r.advance_mut(len);
            }
            Ok(r.freeze())
        }
    }

    fn _read(&mut self, buf: &mut [u8]) -> ProtobufResult<usize> {
        self.fill_buf()?;

        let rem = &self.buf[self.pos_within_buf..self.limit_within_buf];

        let len = cmp::min(rem.len(), buf.len());
        &mut buf[..len].copy_from_slice(&rem[..len]);
        self.pos_within_buf += len;
        Ok((len))
    }

    pub fn read_exact(&mut self, mut buf: &mut [u8]) -> ProtobufResult<()> {
        if self.remaining_in_buf_len() >= buf.len() {
            let buf_len = buf.len();
            buf.copy_from_slice(&self.buf[self.pos_within_buf.. self.pos_within_buf + buf_len]);
            self.pos_within_buf += buf_len;
            return Ok(());
        }

        if self.bytes_until_limit() < buf.len() as u64 {
            return Err(ProtobufError::WireError(WireError::UnexpectedEof));
        }

        let consume = self.pos_within_buf;
        self.pos_of_buf_start += self.pos_within_buf as u64;
        self.pos_within_buf = 0;
        self.buf = &[];
        self.limit_within_buf = 0;

        match self.input_source {
            InputSource::Read(ref mut buf_read) => {
                buf_read.consume(consume);
                buf_read.read_exact(buf)?;
            }
            InputSource::BufRead(ref mut buf_read) => {
                buf_read.consume(consume);
                buf_read.read_exact(buf)?;
            }
            _ => {
                return Err(ProtobufError::WireError(WireError::UnexpectedEof));
            }
        }

        self.pos_of_buf_start += buf.len() as u64;

        self.assertions();

        Ok(())
    }

    fn do_fill_buf(&mut self) -> ProtobufResult<()> {
        debug_assert!(self.pos_within_buf == self.limit_within_buf);

        // Limit is reached, so EOF is reached
        if self.limit_within_buf != self.buf.len() {
            return Ok(());
        }

        let consume = self.buf.len();
        self.pos_of_buf_start += self.buf.len() as u64;
        self.buf = &[];
        self.pos_within_buf = 0;
        self.limit_within_buf = 0;

        match self.input_source {
            InputSource::Read(ref mut buf_read) => {
                buf_read.consume(consume);
                self.buf = unsafe { mem::transmute(buf_read.fill_buf()?) };
            }
            InputSource::BufRead(ref mut buf_read) => {
                buf_read.consume(consume);
                self.buf = unsafe { mem::transmute(buf_read.fill_buf()?) };
            }
            _ => {
                return Ok(());
            }
        }

        self.update_limit_within_buf();

        Ok(())
    }

    #[inline(always)]
    pub fn fill_buf(&mut self) -> ProtobufResult<&[u8]> {
        if self.pos_within_buf == self.limit_within_buf {
            self.do_fill_buf()?;
        }

        Ok(if USE_UNSAFE_FOR_SPEED {
            unsafe { self.buf.get_unchecked(self.pos_within_buf..self.limit_within_buf) }
        } else {
            &self.buf[self.pos_within_buf..self.limit_within_buf]
        })
    }

    #[inline(always)]
    pub fn consume(&mut self, amt: usize) {
        assert!(amt <= self.limit_within_buf - self.pos_within_buf);
        self.pos_within_buf += amt;
    }
}

#[cfg(all(test, feature = "bytes"))]
mod test_bytes {
    use super::*;
    use std::io::Write;

    fn make_long_string(len: usize) -> Vec<u8> {
        let mut s = Vec::new();
        while s.len() < len {
            let len = s.len();
            write!(&mut s, "{}", len).expect("unexpected");
        }
        s.truncate(len);
        s
    }

    #[test]
    fn read_exact_bytes_from_slice() {
        let bytes = make_long_string(100);
        let mut bri = BufReadIter::from_byte_slice(&bytes[..]);
        assert_eq!(&bytes[..90], &bri.read_exact_bytes(90).unwrap()[..]);
        assert_eq!(bytes[90], bri.read_byte().expect("read_byte"));
    }

    #[test]
    fn read_exact_bytes_from_bytes() {
        let bytes = Bytes::from(make_long_string(100));
        let mut bri = BufReadIter::from_bytes(&bytes);
        let read = bri.read_exact_bytes(90).unwrap();
        assert_eq!(&bytes[..90], &read[..]);
        assert_eq!(&bytes[..90].as_ptr(), &read.as_ptr());
        assert_eq!(bytes[90], bri.read_byte().expect("read_byte"));
    }

}
<|endoftext|>


<commit_before>use luminance_gl::gl33::Tessellation;
use std::collections::BTreeMap;
//use std::fs::File;
//use std::io::Read;
use std::path::{Path, PathBuf};
use wavefront_obj::{self, obj};

// FIXME: implement materials
pub type Material = ();

pub type Vertex = (VertexPos, VertexNor, VertexTexCoord);
pub type VertexPos = [f32; 3];
pub type VertexNor = [f32; 3];
pub type VertexTexCoord = [f32; 2];

pub struct Model<'a> {
  parts: Vec<Part<'a>>
}

impl<'a> Model<'a> {
  pub fn from_parts(parts: Vec<Part<'a>>) -> Self {
    Model {
      parts: parts
    }
  }
}

pub struct Part<'a> {
  tess: Tessellation,
  mat: Option<&'a Material>
}

impl<'a> Part<'a> {
  pub fn new(tess: Tessellation, mat: Option<&'a Material>) -> Self {
    Part {
      tess: tess,
      mat: mat
    }
  }

  pub fn tessellation(&self) -> &Tessellation {
    &self.tess
  }

  pub fn material(&self) -> Option<&Material> {
    self.mat.clone()
  }
}

// FIXME: review all the code bellow
////pub fn load<P>(path: P, mode: tessellation::Mode) -> Result<gl33::Tessellation, TessellationError> where P: AsRef<Path> {
////  let path = path.as_ref();
////
////  info!("loading tessellation: \x1b[35m{:?}", path);
////
////  let mut input = String::new();
////
////  // load the data directly into memory; no buffering nor streaming
////  {
////    let mut file = try!(File::open(path).map_err(|e| TessellationError::FileNotFound(path.to_path_buf(), format!("{:?}", e))));
////    let _ = file.read_to_string(&mut input);
////  }
////
////  // parse the obj file and convert it
////  let obj_set = try!(obj::parse(input).map_err(TessellationError::ParseFailed));
////
////  convert_obj(obj_set, mode)
////}
////
////// Turn a loaded wavefront obj object into a `Model`
////fn convert_obj(obj_set: obj::ObjSet, mode: tessellation::Mode) -> Result<gl33::Tessellation, TessellationError> {
////  if obj_set.objects.len() != 1 {
////    return Err(TessellationError::MultiObjects);
////  }
////
////  let obj = &obj_set.objects[0];
////  info!("  found object \x1b[35m{}", obj.name);
////
////  // interleave the vertices
////  let interleaved_vertices = interleave_vertices(&obj.vertices, &obj.normals, &obj.tex_vertices);
////
////  Err(TessellationError::Error)
////}

// Convert wavefront_obj’s Geometry into a pair of vertices and indices.
//
// This function will regenerate the indices on the fly based on which are used in the shapes in the
// geometry. It’s used to create independent tessellation.
fn convert_geometry(geo: &obj::Geometry, positions: &[obj::Vertex], normals: &[obj::Normal], tvertices: &[obj::TVertex]) -> Result<(Vec<Vertex>, Vec<u32>), ModelError> {
  let mut vertices = Vec::new(); // FIXME: better allocation scheme?
  let mut indices = Vec::new();
  let mut index_map = BTreeMap::new();

  for prim in geo.shapes.iter().map(|s| s.primitive) {
    let keys = try!(create_keys_from_primitive(prim));

    for key in keys {
      match index_map.get(&key).map(|&i| i) {
        Some(index) => {
          // that triplet already exists; just append the index in the indices buffer
          indices.push(index);
        },
        None => {
          // this is a new, not yet discovered triplet; create the corresponding vertex and add it
          // to the vertices buffer, and map the triplet to the index in the indices buffer
          let vertex = interleave_vertex(&positions[key.0], &normals[key.1], &tvertices[key.2]);
          let index = vertices.len() as u32;

          vertices.push(vertex);
          indices.push(index);
          index_map.insert(key, index);
        }
      }
    }
  }

  Ok((vertices, indices))
}

// Create triplet keys from wavefront_obj primitives. If any primitive doesn’t have all the triplet
// information (position, normal, tex), a ModelError::UnsupportedVertex error is returned instead.
fn create_keys_from_primitive(prim: obj::Primitive) -> Result<Vec<(usize, usize, usize)>, ModelError> {
  match prim {
    obj::Primitive::Point(i) => {
      let a = try!(vtnindex_to_key(i));
      Ok(vec![a])
    },
    obj::Primitive::Line(i, j) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      Ok(vec![a, b])
    },
    obj::Primitive::Triangle(i, j, k) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      let c = try!(vtnindex_to_key(k));
      Ok(vec![a, b, c])
    }
  }
}

// Convert from a wavefront_obj VTNIndex into our triplet, raising error if not possible.
fn vtnindex_to_key(i: obj::VTNIndex) -> Result<(usize, usize, usize), ModelError> {
  match i {
    (pi, Some(ti), Some(ni)) => Ok((pi, ni, ti)),
    _ => Err(ModelError::UnsupportedVertex)
  }
}

fn interleave_vertex(p: &obj::Vertex, n: &obj::Normal, t: &obj::TVertex) -> Vertex {
  (convert_vertex(p), convert_nor(n), convert_tvertex(t))
}

fn convert_vertex(v: &obj::Vertex) -> VertexPos {
  [v.x as f32, v.y as f32, v.z as f32]
}

fn convert_nor(n: &obj::Normal) -> VertexNor {
  convert_vertex(n)
}

fn convert_tvertex(t: &obj::TVertex) -> VertexTexCoord {
  [t.x as f32, t.y as f32]
}

////mod hot {
////  use super::{TessellationError, Vertex};
////
////  use luminance::tessellation;
////  use luminance_gl::gl33;
////  use resource::ResourceManager;
////  use std::ops::Deref;
////  use std::path::{Path, PathBuf};
////
////  pub struct Tessellation {
////    path: PathBuf,
////    mode: tessellation::Mode,
////    tess: gl33::Tessellation
////  }
////
////  impl Tessellation {
////    fn load<P>(manager: &mut ResourceManager, path: P, mode: tessellation::Mode) -> Result<Self, TessellationError> where P: AsRef<Path> {
////      Err(TessellationError::Error)
////    }
////  }
////
////  impl Deref for Tessellation {
////    type Target = gl33::Tessellation;
////
////    fn deref(&self) -> &Self::Target {
////      &self.tess
////    }
////  }
////}
////
pub enum ModelError {
  FileNotFound(PathBuf, String),
  ParseFailed(wavefront_obj::ParseError),
  MultiObjects,
  UnsupportedVertex
}
<commit_msg>Guessing the tessellation mode to use. (#3, #9)<commit_after>use luminance::tessellation;
use luminance_gl::gl33::Tessellation;
use std::collections::BTreeMap;
//use std::fs::File;
//use std::io::Read;
use std::path::{Path, PathBuf};
use wavefront_obj::{self, obj};

// FIXME: implement materials
pub type Material = ();

pub type Vertex = (VertexPos, VertexNor, VertexTexCoord);
pub type VertexPos = [f32; 3];
pub type VertexNor = [f32; 3];
pub type VertexTexCoord = [f32; 2];

pub struct Model<'a> {
  parts: Vec<Part<'a>>
}

impl<'a> Model<'a> {
  pub fn from_parts(parts: Vec<Part<'a>>) -> Self {
    Model {
      parts: parts
    }
  }
}

pub struct Part<'a> {
  tess: Tessellation,
  mat: Option<&'a Material>
}

impl<'a> Part<'a> {
  pub fn new(tess: Tessellation, mat: Option<&'a Material>) -> Self {
    Part {
      tess: tess,
      mat: mat
    }
  }

  pub fn tessellation(&self) -> &Tessellation {
    &self.tess
  }

  pub fn material(&self) -> Option<&Material> {
    self.mat.clone()
  }
}

// FIXME: review all the code bellow
////pub fn load<P>(path: P, mode: tessellation::Mode) -> Result<gl33::Tessellation, TessellationError> where P: AsRef<Path> {
////  let path = path.as_ref();
////
////  info!("loading model: \x1b[35m{:?}", path);
////
////  let mut input = String::new();
////
////  // load the data directly into memory; no buffering nor streaming
////  {
////    let mut file = try!(File::open(path).map_err(|e| TessellationError::FileNotFound(path.to_path_buf(), format!("{:?}", e))));
////    let _ = file.read_to_string(&mut input);
////  }
////
////  // parse the obj file and convert it
////  let obj_set = try!(obj::parse(input).map_err(TessellationError::ParseFailed));
////
////  convert_obj(obj_set, mode)
////}
////
// Turn a loaded wavefront obj object into a `Model`
//fn convert_obj(obj_set: obj::ObjSet) -> Result<Model, ModelError> {
//  if obj_set.objects.len() != 1 {
//    return Err(ModelError::MultiObjects);
//  }
//
//  let obj = &obj_set.objects[0];
//  info!("  converting object \x1b[35m{}", obj.name);
//
//  // convert all the geometries
//  let parts = Vec::with_capacity(obj.geometries.len());
//
//  Err(TessellationError::Error)
//}

// Convert wavefront_obj’s Geometry into a pair of vertices and indices.
//
// This function will regenerate the indices on the fly based on which are used in the shapes in the
// geometry. It’s used to create independent tessellation.
fn convert_geometry(geo: &obj::Geometry, positions: &[obj::Vertex], normals: &[obj::Normal], tvertices: &[obj::TVertex]) -> Result<(Vec<Vertex>, Vec<u32>, tessellation::Mode), ModelError> {
  let mut vertices = Vec::new(); // FIXME: better allocation scheme?
  let mut indices = Vec::new();
  let mut index_map = BTreeMap::new();

  info!("    converting geometry");

  // TODO: error if no shapes?

  let mode = guess_mode(geo.shapes[0].primitive);

  for prim in geo.shapes.iter().map(|s| s.primitive) {
    let keys = try!(create_keys_from_primitive(prim));

    for key in keys {
      match index_map.get(&key).map(|&i| i) {
        Some(index) => {
          // that triplet already exists; just append the index in the indices buffer
          indices.push(index);
        },
        None => {
          // this is a new, not yet discovered triplet; create the corresponding vertex and add it
          // to the vertices buffer, and map the triplet to the index in the indices buffer
          let vertex = interleave_vertex(&positions[key.0], &normals[key.1], &tvertices[key.2]);
          let index = vertices.len() as u32;

          vertices.push(vertex);
          indices.push(index);
          index_map.insert(key, index);
        }
      }
    }
  }

  Ok((vertices, indices, mode))
}

// Create triplet keys from wavefront_obj primitives. If any primitive doesn’t have all the triplet
// information (position, normal, tex), a ModelError::UnsupportedVertex error is returned instead.
fn create_keys_from_primitive(prim: obj::Primitive) -> Result<Vec<(usize, usize, usize)>, ModelError> {
  match prim {
    obj::Primitive::Point(i) => {
      let a = try!(vtnindex_to_key(i));
      Ok(vec![a])
    },
    obj::Primitive::Line(i, j) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      Ok(vec![a, b])
    },
    obj::Primitive::Triangle(i, j, k) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      let c = try!(vtnindex_to_key(k));
      Ok(vec![a, b, c])
    }
  }
}

// Convert from a wavefront_obj VTNIndex into our triplet, raising error if not possible.
fn vtnindex_to_key(i: obj::VTNIndex) -> Result<(usize, usize, usize), ModelError> {
  match i {
    (pi, Some(ti), Some(ni)) => Ok((pi, ni, ti)),
    _ => Err(ModelError::UnsupportedVertex)
  }
}

fn interleave_vertex(p: &obj::Vertex, n: &obj::Normal, t: &obj::TVertex) -> Vertex {
  (convert_vertex(p), convert_nor(n), convert_tvertex(t))
}

fn convert_vertex(v: &obj::Vertex) -> VertexPos {
  [v.x as f32, v.y as f32, v.z as f32]
}

fn convert_nor(n: &obj::Normal) -> VertexNor {
  convert_vertex(n)
}

fn convert_tvertex(t: &obj::TVertex) -> VertexTexCoord {
  [t.x as f32, t.y as f32]
}

fn guess_mode(prim: obj::Primitive) -> tessellation::Mode {
  match prim {
    obj::Primitive::Point(_) => tessellation::Mode::Point,
    obj::Primitive::Line(_, _) => tessellation::Mode::Line,
    obj::Primitive::Triangle(_, _, _) => tessellation::Mode::Triangle
  }
}

////mod hot {
////  use super::{TessellationError, Vertex};
////
////  use luminance::tessellation;
////  use luminance_gl::gl33;
////  use resource::ResourceManager;
////  use std::ops::Deref;
////  use std::path::{Path, PathBuf};
////
////  pub struct Tessellation {
////    path: PathBuf,
////    mode: tessellation::Mode,
////    tess: gl33::Tessellation
////  }
////
////  impl Tessellation {
////    fn load<P>(manager: &mut ResourceManager, path: P, mode: tessellation::Mode) -> Result<Self, TessellationError> where P: AsRef<Path> {
////      Err(TessellationError::Error)
////    }
////  }
////
////  impl Deref for Tessellation {
////    type Target = gl33::Tessellation;
////
////    fn deref(&self) -> &Self::Target {
////      &self.tess
////    }
////  }
////}
////
pub enum ModelError {
  FileNotFound(PathBuf, String),
  ParseFailed(wavefront_obj::ParseError),
  MultiObjects,
  UnsupportedVertex
}
<|endoftext|>


<commit_before>
use core::ops::Not;
use hardware::peripherals::digital_io::DigitalOutput;
use hardware::peripherals::digital_io::DigitalValue;
use hardware::peripherals::time::Time;

#[derive(Clone, Copy, Debug)]
pub enum Direction {
    Forward = 1,
    Backward = -1,
}

impl Not for Direction {
    type Output = Direction;

    fn not(self) -> Direction {
        match self {
            Direction::Forward => Direction::Backward,
            Direction::Backward => Direction::Forward,
        }
    }
}

pub trait Motor {
    fn set_velocity(&mut self, velocity: f32);
    fn set_direction(&mut self, direction: Direction);
    fn get_position(&self) -> f32;
    fn get_velocity(&self) -> f32;
    fn update(&mut self);
}

#[derive(Debug, Clone, Copy)]
pub struct StepperMotorConfig {
    min_travel: f32,
    max_travel: f32,

    steps_per_millimeter: i32,

    pulse_length: u32,
}

pub struct StepperMotor<'a> {
    step_output: &'a mut DigitalOutput,
    dir_output: &'a mut DigitalOutput,

    time: &'a Time,

    config: StepperMotorConfig,

    /// The current step that the motor is at
    current_step: i32,

    /// The current direction
    current_direction: Direction,

    /// The current traveling velocity in microseconds per step
    microseconds_per_step: u32,

    /// The minimum number of steps that can be stepped
    min_steps: i32,

    /// The maxmimum number of steps that can be stepped
    max_steps: i32,

    /// The last time we stepped
    last_step: u32,

    /// If we are in the middle of a pulse
    mid_pulse: bool,
}

impl<'a> StepperMotor<'a> {
    fn new(
        step_output: &'a mut DigitalOutput,
        dir_output: &'a mut DigitalOutput,
        time: &'a Time,
        config: StepperMotorConfig,
    ) -> StepperMotor<'a> {
        StepperMotor {
            step_output: step_output,
            dir_output: dir_output,
            time: time,
            config: config,
            current_step: 0,
            current_direction: Direction::Backward,
            microseconds_per_step: 0,
            min_steps: (config.min_travel * config.steps_per_millimeter as f32) as i32,
            max_steps: (config.max_travel * config.steps_per_millimeter as f32) as i32,
            last_step: 0,
            mid_pulse: false,
        }
    }
}

impl<'a> Motor for StepperMotor<'a> {
    fn set_velocity(&mut self, velocity: f32) {

        if velocity > 0.0 {
            self.set_direction(Direction::Forward);
            let microseconds_per_step =
                (60000000.0 / (velocity * self.config.steps_per_millimeter as f32)) as u32;

            self.microseconds_per_step = microseconds_per_step;

        } else if velocity < 0.0 {
            self.set_direction(Direction::Backward);
            let microseconds_per_step =
                (60000000.0 / (-velocity * self.config.steps_per_millimeter as f32)) as u32;

            self.microseconds_per_step = microseconds_per_step;

        } else {
            self.microseconds_per_step = 0;
        }
    }

    fn set_direction(&mut self, direction: Direction) {
        self.current_direction = direction;
        match self.current_direction {
            Direction::Forward => self.dir_output.write(DigitalValue::High),
            Direction::Backward => self.dir_output.write(DigitalValue::Low),
        }
    }

    fn get_position(&self) -> f32 {
        self.current_step as f32 / self.config.steps_per_millimeter as f32
    }

    /// Return the current velocity in mm/min
    fn get_velocity(&self) -> f32 {
        self.current_direction as i32 as f32 * 60000000.0 /
            (self.microseconds_per_step as i32 * self.config.steps_per_millimeter) as f32
    }

    fn update(&mut self) {
        //let now = unsafe { bindings::micros() };
        let now = self.time.now();

        // Check if needed to start next step
        if now - self.last_step > self.microseconds_per_step {
            if match self.current_direction {
                Direction::Forward => self.current_step != self.max_steps,
                Direction::Backward => self.current_step != self.min_steps,
            } {
                //self.hardware.digital_write(self.config.step_pin, PinState::High);
                self.step_output.write(DigitalValue::High);

                self.mid_pulse = true;
                self.last_step = now;
            }
        }

        // Check if needed to end step pulse
        if self.mid_pulse && now - self.last_step > self.config.pulse_length {

            //self.hardware.digital_write(self.config.step_pin, PinState::Low);
            self.step_output.write(DigitalValue::High);

            self.current_step += self.current_direction as i32;
            self.mid_pulse = false;
            self.last_step = now;
        }
    }
}
<commit_msg>Make motor stuff pub StepperMotor::new Fields of StepperMotorConfig<commit_after>
use core::ops::Not;
use hardware::peripherals::digital_io::DigitalOutput;
use hardware::peripherals::digital_io::DigitalValue;
use hardware::peripherals::time::Time;

#[derive(Clone, Copy, Debug)]
pub enum Direction {
    Forward = 1,
    Backward = -1,
}

impl Not for Direction {
    type Output = Direction;

    fn not(self) -> Direction {
        match self {
            Direction::Forward => Direction::Backward,
            Direction::Backward => Direction::Forward,
        }
    }
}

pub trait Motor {
    fn set_velocity(&mut self, velocity: f32);
    fn set_direction(&mut self, direction: Direction);
    fn get_position(&self) -> f32;
    fn get_velocity(&self) -> f32;
    fn update(&mut self);
}

#[derive(Debug, Clone, Copy)]
pub struct StepperMotorConfig {
    pub min_travel: f32,
    pub max_travel: f32,

    pub steps_per_millimeter: i32,

    pub pulse_length: u32,
}

pub struct StepperMotor<'a> {
    step_output: &'a mut DigitalOutput,
    dir_output: &'a mut DigitalOutput,

    time: &'a Time,

    config: StepperMotorConfig,

    /// The current step that the motor is at
    current_step: i32,

    /// The current direction
    current_direction: Direction,

    /// The current traveling velocity in microseconds per step
    microseconds_per_step: u32,

    /// The minimum number of steps that can be stepped
    min_steps: i32,

    /// The maxmimum number of steps that can be stepped
    max_steps: i32,

    /// The last time we stepped
    last_step: u32,

    /// If we are in the middle of a pulse
    mid_pulse: bool,
}

impl<'a> StepperMotor<'a> {
    pub fn new(
        step_output: &'a mut DigitalOutput,
        dir_output: &'a mut DigitalOutput,
        time: &'a Time,
        config: StepperMotorConfig,
    ) -> StepperMotor<'a> {
        StepperMotor {
            step_output: step_output,
            dir_output: dir_output,
            time: time,
            config: config,
            current_step: 0,
            current_direction: Direction::Backward,
            microseconds_per_step: 0,
            min_steps: (config.min_travel * config.steps_per_millimeter as f32) as i32,
            max_steps: (config.max_travel * config.steps_per_millimeter as f32) as i32,
            last_step: 0,
            mid_pulse: false,
        }
    }
}

impl<'a> Motor for StepperMotor<'a> {
    fn set_velocity(&mut self, velocity: f32) {

        if velocity > 0.0 {
            self.set_direction(Direction::Forward);
            let microseconds_per_step =
                (60000000.0 / (velocity * self.config.steps_per_millimeter as f32)) as u32;

            self.microseconds_per_step = microseconds_per_step;

        } else if velocity < 0.0 {
            self.set_direction(Direction::Backward);
            let microseconds_per_step =
                (60000000.0 / (-velocity * self.config.steps_per_millimeter as f32)) as u32;

            self.microseconds_per_step = microseconds_per_step;

        } else {
            self.microseconds_per_step = 0;
        }
    }

    fn set_direction(&mut self, direction: Direction) {
        self.current_direction = direction;
        match self.current_direction {
            Direction::Forward => self.dir_output.write(DigitalValue::High),
            Direction::Backward => self.dir_output.write(DigitalValue::Low),
        }
    }

    fn get_position(&self) -> f32 {
        self.current_step as f32 / self.config.steps_per_millimeter as f32
    }

    /// Return the current velocity in mm/min
    fn get_velocity(&self) -> f32 {
        self.current_direction as i32 as f32 * 60000000.0 /
            (self.microseconds_per_step as i32 * self.config.steps_per_millimeter) as f32
    }

    fn update(&mut self) {
        //let now = unsafe { bindings::micros() };
        let now = self.time.now();

        // Check if needed to start next step
        if now - self.last_step > self.microseconds_per_step {
            if match self.current_direction {
                Direction::Forward => self.current_step != self.max_steps,
                Direction::Backward => self.current_step != self.min_steps,
            } {
                //self.hardware.digital_write(self.config.step_pin, PinState::High);
                self.step_output.write(DigitalValue::High);

                self.mid_pulse = true;
                self.last_step = now;
            }
        }

        // Check if needed to end step pulse
        if self.mid_pulse && now - self.last_step > self.config.pulse_length {

            //self.hardware.digital_write(self.config.step_pin, PinState::Low);
            self.step_output.write(DigitalValue::High);

            self.current_step += self.current_direction as i32;
            self.mid_pulse = false;
            self.last_step = now;
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::ops::Index;
use std::path::PathBuf;
use std::str::FromStr;
use std::borrow::Cow;
use smallvec::SmallVec;

use error::{ResponseError, UriSegmentError, ErrorBadRequest};

/// A trait to abstract the idea of creating a new instance of a type from a path parameter.
pub trait FromParam: Sized {
    /// The associated error which can be returned from parsing.
    type Err: ResponseError;

    /// Parses a string `s` to return a value of this type.
    fn from_param(s: &str) -> Result<Self, Self::Err>;
}

/// Route match information
///
/// If resource path contains variable patterns, `Params` stores this variables.
#[derive(Debug)]
pub struct Params<'a>(SmallVec<[(Cow<'a, str>, Cow<'a, str>); 3]>);

impl<'a> Default for Params<'a> {
    fn default() -> Params<'a> {
        Params(SmallVec::new())
    }
}

impl<'a> Params<'a> {

    pub(crate) fn clear(&mut self) {
        self.0.clear();
    }

    pub(crate) fn add<N, V>(&mut self, name: N, value: V)
        where N: Into<Cow<'a, str>>, V: Into<Cow<'a, str>>,
    {
        self.0.push((name.into(), value.into()));
    }

    /// Check if there are any matched patterns
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Get matched parameter by name without type conversion
    pub fn get(&'a self, key: &str) -> Option<&'a str> {
        for item in self.0.iter() {
            if key == item.0 {
                return Some(item.1.as_ref())
            }
        }
        None
    }

    /// Get matched `FromParam` compatible parameter by name.
    ///
    /// If keyed parameter is not available empty string is used as default value.
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// # use actix_web::*;
    /// fn index(req: HttpRequest) -> Result<String> {
    ///    let ivalue: isize = req.match_info().query("val")?;
    ///    Ok(format!("isuze value: {:?}", ivalue))
    /// }
    /// # fn main() {}
    /// ```
    pub fn query<T: FromParam>(&'a self, key: &str) -> Result<T, <T as FromParam>::Err>
    {
        if let Some(s) = self.get(key) {
            T::from_param(s)
        } else {
            T::from_param("")
        }
    }
}

impl<'a, 'b, 'c: 'a> Index<&'b str> for &'c Params<'a> {
    type Output = str;

    fn index(&self, name: &'b str) -> &str {
        self.get(name).expect("Value for parameter is not available")
    }
}

/// Creates a `PathBuf` from a path parameter. The returned `PathBuf` is
/// percent-decoded. If a segment is equal to "..", the previous segment (if
/// any) is skipped.
///
/// For security purposes, if a segment meets any of the following conditions,
/// an `Err` is returned indicating the condition met:
///
///   * Decoded segment starts with any of: `.` (except `..`), `*`
///   * Decoded segment ends with any of: `:`, `>`, `<`
///   * Decoded segment contains any of: `/`
///   * On Windows, decoded segment contains any of: '\'
///   * Percent-encoding results in invalid UTF8.
///
/// As a result of these conditions, a `PathBuf` parsed from request path parameter is
/// safe to interpolate within, or use as a suffix of, a path without additional
/// checks.
impl FromParam for PathBuf {
    type Err = UriSegmentError;

    fn from_param(val: &str) -> Result<PathBuf, UriSegmentError> {
        let mut buf = PathBuf::new();
        for segment in val.split('/') {
            if segment == ".." {
                buf.pop();
            } else if segment.starts_with('.') {
                return Err(UriSegmentError::BadStart('.'))
            } else if segment.starts_with('*') {
                return Err(UriSegmentError::BadStart('*'))
            } else if segment.ends_with(':') {
                return Err(UriSegmentError::BadEnd(':'))
            } else if segment.ends_with('>') {
                return Err(UriSegmentError::BadEnd('>'))
            } else if segment.ends_with('<') {
                return Err(UriSegmentError::BadEnd('<'))
            } else if segment.is_empty() {
                continue
            } else if cfg!(windows) && segment.contains('\\') {
                return Err(UriSegmentError::BadChar('\\'))
            } else {
                buf.push(segment)
            }
        }

        Ok(buf)
    }
}

macro_rules! FROM_STR {
    ($type:ty) => {
        impl FromParam for $type {
            type Err = ErrorBadRequest<<$type as FromStr>::Err>;

            fn from_param(val: &str) -> Result<Self, Self::Err> {
                <$type as FromStr>::from_str(val).map_err(ErrorBadRequest)
            }
        }
    }
}

FROM_STR!(u8);
FROM_STR!(u16);
FROM_STR!(u32);
FROM_STR!(u64);
FROM_STR!(usize);
FROM_STR!(i8);
FROM_STR!(i16);
FROM_STR!(i32);
FROM_STR!(i64);
FROM_STR!(isize);
FROM_STR!(f32);
FROM_STR!(f64);
FROM_STR!(String);
FROM_STR!(std::net::IpAddr);
FROM_STR!(std::net::Ipv4Addr);
FROM_STR!(std::net::Ipv6Addr);
FROM_STR!(std::net::SocketAddr);
FROM_STR!(std::net::SocketAddrV4);
FROM_STR!(std::net::SocketAddrV6);

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

    #[test]
    fn test_path_buf() {
        assert_eq!(PathBuf::from_param("/test/.tt"), Err(UriSegmentError::BadStart('.')));
        assert_eq!(PathBuf::from_param("/test/*tt"), Err(UriSegmentError::BadStart('*')));
        assert_eq!(PathBuf::from_param("/test/tt:"), Err(UriSegmentError::BadEnd(':')));
        assert_eq!(PathBuf::from_param("/test/tt<"), Err(UriSegmentError::BadEnd('<')));
        assert_eq!(PathBuf::from_param("/test/tt>"), Err(UriSegmentError::BadEnd('>')));
        assert_eq!(PathBuf::from_param("/seg1/seg2/"),
                   Ok(PathBuf::from_iter(vec!["seg1", "seg2"])));
        assert_eq!(PathBuf::from_param("/seg1/../seg2/"),
                   Ok(PathBuf::from_iter(vec!["seg2"])));
    }
}
<commit_msg>add parameter container iterator<commit_after>use std;
use std::ops::Index;
use std::path::PathBuf;
use std::str::FromStr;
use std::slice::Iter;
use std::borrow::Cow;
use smallvec::SmallVec;

use error::{ResponseError, UriSegmentError, ErrorBadRequest};

/// A trait to abstract the idea of creating a new instance of a type from a path parameter.
pub trait FromParam: Sized {
    /// The associated error which can be returned from parsing.
    type Err: ResponseError;

    /// Parses a string `s` to return a value of this type.
    fn from_param(s: &str) -> Result<Self, Self::Err>;
}

/// Route match information
///
/// If resource path contains variable patterns, `Params` stores this variables.
#[derive(Debug)]
pub struct Params<'a>(SmallVec<[(Cow<'a, str>, Cow<'a, str>); 3]>);

impl<'a> Default for Params<'a> {
    fn default() -> Params<'a> {
        Params(SmallVec::new())
    }
}

impl<'a> Params<'a> {

    pub(crate) fn clear(&mut self) {
        self.0.clear();
    }

    pub(crate) fn add<N, V>(&mut self, name: N, value: V)
        where N: Into<Cow<'a, str>>, V: Into<Cow<'a, str>>,
    {
        self.0.push((name.into(), value.into()));
    }

    /// Check if there are any matched patterns
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Get matched parameter by name without type conversion
    pub fn get(&'a self, key: &str) -> Option<&'a str> {
        for item in self.0.iter() {
            if key == item.0 {
                return Some(item.1.as_ref())
            }
        }
        None
    }

    /// Get matched `FromParam` compatible parameter by name.
    ///
    /// If keyed parameter is not available empty string is used as default value.
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// # use actix_web::*;
    /// fn index(req: HttpRequest) -> Result<String> {
    ///    let ivalue: isize = req.match_info().query("val")?;
    ///    Ok(format!("isuze value: {:?}", ivalue))
    /// }
    /// # fn main() {}
    /// ```
    pub fn query<T: FromParam>(&'a self, key: &str) -> Result<T, <T as FromParam>::Err>
    {
        if let Some(s) = self.get(key) {
            T::from_param(s)
        } else {
            T::from_param("")
        }
    }

    /// Return iterator to items in paramter container
    pub fn iter(&self) -> Iter<(Cow<'a, str>, Cow<'a, str>)> {
        self.0.iter()
    }
}

impl<'a, 'b, 'c: 'a> Index<&'b str> for &'c Params<'a> {
    type Output = str;

    fn index(&self, name: &'b str) -> &str {
        self.get(name).expect("Value for parameter is not available")
    }
}

/// Creates a `PathBuf` from a path parameter. The returned `PathBuf` is
/// percent-decoded. If a segment is equal to "..", the previous segment (if
/// any) is skipped.
///
/// For security purposes, if a segment meets any of the following conditions,
/// an `Err` is returned indicating the condition met:
///
///   * Decoded segment starts with any of: `.` (except `..`), `*`
///   * Decoded segment ends with any of: `:`, `>`, `<`
///   * Decoded segment contains any of: `/`
///   * On Windows, decoded segment contains any of: '\'
///   * Percent-encoding results in invalid UTF8.
///
/// As a result of these conditions, a `PathBuf` parsed from request path parameter is
/// safe to interpolate within, or use as a suffix of, a path without additional
/// checks.
impl FromParam for PathBuf {
    type Err = UriSegmentError;

    fn from_param(val: &str) -> Result<PathBuf, UriSegmentError> {
        let mut buf = PathBuf::new();
        for segment in val.split('/') {
            if segment == ".." {
                buf.pop();
            } else if segment.starts_with('.') {
                return Err(UriSegmentError::BadStart('.'))
            } else if segment.starts_with('*') {
                return Err(UriSegmentError::BadStart('*'))
            } else if segment.ends_with(':') {
                return Err(UriSegmentError::BadEnd(':'))
            } else if segment.ends_with('>') {
                return Err(UriSegmentError::BadEnd('>'))
            } else if segment.ends_with('<') {
                return Err(UriSegmentError::BadEnd('<'))
            } else if segment.is_empty() {
                continue
            } else if cfg!(windows) && segment.contains('\\') {
                return Err(UriSegmentError::BadChar('\\'))
            } else {
                buf.push(segment)
            }
        }

        Ok(buf)
    }
}

macro_rules! FROM_STR {
    ($type:ty) => {
        impl FromParam for $type {
            type Err = ErrorBadRequest<<$type as FromStr>::Err>;

            fn from_param(val: &str) -> Result<Self, Self::Err> {
                <$type as FromStr>::from_str(val).map_err(ErrorBadRequest)
            }
        }
    }
}

FROM_STR!(u8);
FROM_STR!(u16);
FROM_STR!(u32);
FROM_STR!(u64);
FROM_STR!(usize);
FROM_STR!(i8);
FROM_STR!(i16);
FROM_STR!(i32);
FROM_STR!(i64);
FROM_STR!(isize);
FROM_STR!(f32);
FROM_STR!(f64);
FROM_STR!(String);
FROM_STR!(std::net::IpAddr);
FROM_STR!(std::net::Ipv4Addr);
FROM_STR!(std::net::Ipv6Addr);
FROM_STR!(std::net::SocketAddr);
FROM_STR!(std::net::SocketAddrV4);
FROM_STR!(std::net::SocketAddrV6);

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

    #[test]
    fn test_path_buf() {
        assert_eq!(PathBuf::from_param("/test/.tt"), Err(UriSegmentError::BadStart('.')));
        assert_eq!(PathBuf::from_param("/test/*tt"), Err(UriSegmentError::BadStart('*')));
        assert_eq!(PathBuf::from_param("/test/tt:"), Err(UriSegmentError::BadEnd(':')));
        assert_eq!(PathBuf::from_param("/test/tt<"), Err(UriSegmentError::BadEnd('<')));
        assert_eq!(PathBuf::from_param("/test/tt>"), Err(UriSegmentError::BadEnd('>')));
        assert_eq!(PathBuf::from_param("/seg1/seg2/"),
                   Ok(PathBuf::from_iter(vec!["seg1", "seg2"])));
        assert_eq!(PathBuf::from_param("/seg1/../seg2/"),
                   Ok(PathBuf::from_iter(vec!["seg2"])));
    }
}
<|endoftext|>


<commit_before>use super::ByteSize;

impl std::str::FromStr for ByteSize {
    type Err = String;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value.parse::<u64>() {
            Ok(v) => return Ok(Self(v)), // simple case, bytes
            Err(_) => {},
        };
        todo!()
    }
}

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

    #[test]
    fn when_ok() {
        // shortcut for writing test cases
        fn parse(s: &str) -> u64 {
            s.parse::<ByteSize>().unwrap().0
        }

        assert_eq!("0".parse::<ByteSize>().unwrap().0, 0);
        assert_eq!(parse("0"), 0);
        assert_eq!(parse("500"), 500);
        assert_eq!(parse("1K"), 1 * MB);
        assert_eq!(parse("1Ki"), 1 * KIB);
        assert_eq!(parse("1.5Ki"), (1.5 * KIB as f64) as u64);
        assert_eq!(parse("1KiB"), 1 * KIB);
        assert_eq!(parse("1.5KiB"), (1.5 * KIB as f64) as u64);
        assert_eq!(parse("3 MB"), 3 * MB);
        assert_eq!(parse("4 MiB"), 4 * MIB);
        assert_eq!(parse("6 GB"), 6 * GB);
        assert_eq!(parse("4 GiB"), 4 * GIB);
        assert_eq!(parse("88TB"), 88 * TB);
        assert_eq!(parse("521TiB"), 521 * TIB);
        assert_eq!(parse("8 PB"), 8 * PB);
        assert_eq!(parse("12 PB"), 12 * PIB);
    }
}
<commit_msg>pass the test<commit_after>use super::ByteSize;

impl std::str::FromStr for ByteSize {
    type Err = String;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value.parse::<u64>() {
            Ok(v) => return Ok(Self(v)), // simple case, bytes
            Err(_) => {}
        };
        let number: String = value
            .chars()
            .take_while(|c| c.is_digit(10) || c == &'.')
            .collect();
        match number.parse::<f64>() {
            Ok(v) => {
                let suffix: String = value
                    .chars()
                    .skip_while(|c| c.is_whitespace() || c.is_digit(10) || c == &'.')
                    .collect();
                Ok(Self((v * match_suffix(&suffix) as f64) as u64))
            }
            Err(error) => Err(format!(
                "couldn't parse {:?} into a ByteSize, {}",
                value, error
            )),
        }
    }
}

fn match_suffix(unit: &str) -> u64 {
    match unit.to_lowercase().as_str() {
        "k" | "kb" => super::KB,
        "ki" | "kib" => super::KIB,
        "m" | "mb" => super::MB,
        "mi" | "mib" => super::MIB,
        "g" | "gb" => super::GB,
        "gi" | "gib" => super::GIB,
        "t" | "tb" => super::TB,
        "ti" | "tib" => super::TIB,
        "p" | "pb" => super::PB,
        "pi" | "pib" => super::PIB,
        _ => 1,
    }
}

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

    #[test]
    fn when_ok() {
        // shortcut for writing test cases
        fn parse(s: &str) -> u64 {
            s.parse::<ByteSize>().unwrap().0
        }

        assert_eq!("0".parse::<ByteSize>().unwrap().0, 0);
        assert_eq!(parse("0"), 0);
        assert_eq!(parse("500"), 500);
        assert_eq!(parse("1K"), 1 * KB);
        assert_eq!(parse("1Ki"), 1 * KIB);
        assert_eq!(parse("1.5Ki"), (1.5 * KIB as f64) as u64);
        assert_eq!(parse("1KiB"), 1 * KIB);
        assert_eq!(parse("1.5KiB"), (1.5 * KIB as f64) as u64);
        assert_eq!(parse("3 MB"), 3 * MB);
        assert_eq!(parse("4 MiB"), 4 * MIB);
        assert_eq!(parse("6 GB"), 6 * GB);
        assert_eq!(parse("4 GiB"), 4 * GIB);
        assert_eq!(parse("88TB"), 88 * TB);
        assert_eq!(parse("521TiB"), 521 * TIB);
        assert_eq!(parse("8 PB"), 8 * PB);
        assert_eq!(parse("12 PiB"), 12 * PIB);
    }
}
<|endoftext|>