<commit_before>use UndoCmd;

/// `UndoStack` maintains a stack of `UndoCmd`s that can be undone and redone by using methods
/// on the `UndoStack`.
///
/// `UndoStack` will notice when it's state changes to either dirty or clean, and the user can
/// set methods that should be called for either state change. This is useful for example if
/// you want to automatically enable or disable undo or redo buttons based on there are any
/// more actions that can be undone or redone.
pub struct UndoStack<'a> {
    // All commands on the stack.
    stack: Vec<Box<UndoCmd + 'a>>,
    // Current position in the stack.
    len: usize,
    // Called when the state changes from dirty to clean.
    on_clean: Option<Box<FnMut() + 'a>>,
    // Called when the state changes from clean to dirty.
    on_dirty: Option<Box<FnMut() + 'a>>,
}

impl<'a> UndoStack<'a> {
    /// Creates a new `UndoStack`.
    #[inline]
    pub fn new() -> Self {
        UndoStack {
            stack: Vec::new(),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Creates a new `UndoStack` with the specified capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        UndoStack {
            stack: Vec::with_capacity(capacity),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Returns the capacity of the `UndoStack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.stack.capacity()
    }

    /// Reserves capacity for at least `additional` more commands to be inserted in the given stack.
    /// The stack may reserve more space to avoid frequent reallocations.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.stack.reserve(additional);
    }

    /// Shrinks the capacity of the `UndoStack` as much as possible.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.stack.shrink_to_fit();
    }

    /// Sets what should happen if the state changes from dirty to clean.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// Note: An empty stack is clean, so the first push will not trigger this method.
    ///
    /// # Examples
    /// ```
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_clean(|| x += 1);
    /// ```
    #[inline]
    pub fn on_clean<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_clean = Some(Box::new(f));
        self
    }

    /// Sets what should happen if the state changes from clean to dirty.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_dirty(|| x += 1);
    /// ```
    #[inline]
    pub fn on_dirty<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_dirty = Some(Box::new(f));
        self
    }

    /// Returns `true` if the state of the stack is clean, `false` otherwise.
    #[inline]
    pub fn is_clean(&self) -> bool {
        self.len == self.stack.len()
    }

    /// Returns `true` if the state of the stack is dirty, `false` otherwise.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        !self.is_clean()
    }

    /// Pushes a `UndoCmd` to the top of the `UndoStack` and executes its [`redo`] method.
    /// This pops off all `UndoCmd`s that is above the active command from the `UndoStack`.
    ///
    /// If `cmd`s id is equal to the current top command, the two commands are merged.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn push<T>(&mut self, mut cmd: T)
        where T: UndoCmd + 'a,
    {
        let is_dirty = self.is_dirty();
        let len = self.len;
        // Pop off all elements after len from stack.
        self.stack.truncate(len);
        cmd.redo();

        // Check if we should merge cmd with the top command on stack.
        let id = cmd.id();
        if len > 0 && id.is_some() && id == unsafe { self.stack.get_unchecked(len - 1).id() } {

            // MergeCmd is the result of the merging.
            struct MergeCmd<'a> {
                cmd1: Box<UndoCmd + 'a>,
                cmd2: Box<UndoCmd + 'a>,
            }

            impl<'a> UndoCmd for MergeCmd<'a> {
                fn redo(&mut self) {
                    self.cmd1.redo();
                    self.cmd2.redo();
                }

                fn undo(&mut self) {
                    self.cmd2.undo();
                    self.cmd1.undo();
                }

                fn id(&self) -> Option<u64> {
                    self.cmd1.id()
                }
            }

            // Merge the command with the one on the top of the stack.
            let cmd = MergeCmd {
                cmd1: unsafe {
                    // Unchecked pop.
                    self.stack.set_len(len - 1);
                    ::std::ptr::read(self.stack.get_unchecked(self.stack.len()))
                },
                cmd2: Box::new(cmd),
            };
            self.stack.push(Box::new(cmd));
        } else {
            self.stack.push(Box::new(cmd));
            self.len += 1;
        }

        // State is always clean after a push, check if it was dirty before.
        if is_dirty {
            if let Some(ref mut f) = self.on_clean {
                f();
            }
        }
    }

    /// Calls the [`redo`] method for the active `UndoCmd` and sets the next `UndoCmd` as the new
    /// active one.
    ///
    /// Calling this method when there are no more commands to redo does nothing.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn redo(&mut self) {
        if self.len < self.stack.len() {
            let is_dirty = self.is_dirty();
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.redo();
            }
            self.len += 1;
            // Check if stack went from dirty to clean.
            if is_dirty && self.is_clean() {
                if let Some(ref mut f) = self.on_clean {
                    f();
                }
            }
        }
    }

    /// Calls the [`undo`] method for the active `UndoCmd` and sets the previous `UndoCmd` as the
    /// new active one.
    ///
    /// Calling this method when there are no more commands to undo does nothing.
    ///
    /// [`undo`]: trait.UndoCmd.html#tymethod.undo
    pub fn undo(&mut self) {
        if self.len > 0 {
            let is_clean = self.is_clean();
            self.len -= 1;
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.undo();
            }
            // Check if stack went from clean to dirty.
            if is_clean && self.is_dirty() {
                if let Some(ref mut f) = self.on_dirty {
                    f();
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use {UndoStack, UndoCmd};

    #[test]
    fn pop() {
        use std::rc::Rc;
        use std::cell::{Cell, RefCell};

        /// Pops an element from a vector.
        #[derive(Clone)]
        struct PopCmd {
            vec: Rc<RefCell<Vec<i32>>>,
            e: Option<i32>,
        }

        impl UndoCmd for PopCmd {
            fn redo(&mut self) {
                self.e = self.vec.borrow_mut().pop();
            }

            fn undo(&mut self) {
                self.vec.borrow_mut().push(self.e.unwrap());
                self.e = None;
            }
        }

        let a = Cell::new(0);
        let b = Cell::new(0);
        // We need to use Rc<RefCell> since all commands are going to mutate the vec.
        let vec = Rc::new(RefCell::new(vec![1, 2, 3]));
        let mut undo_stack = UndoStack::with_capacity(3)
            .on_clean(|| a.set(1))
            .on_dirty(|| b.set(1));

        let cmd = PopCmd { vec: vec.clone(), e: None };
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());

        assert!(vec.borrow().is_empty());

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        undo_stack.undo();
        undo_stack.undo();

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.push(cmd.clone());
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.redo();
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));
    }
}
<commit_msg>Add inline tag to MergeCmd<commit_after>use UndoCmd;

/// `UndoStack` maintains a stack of `UndoCmd`s that can be undone and redone by using methods
/// on the `UndoStack`.
///
/// `UndoStack` will notice when it's state changes to either dirty or clean, and the user can
/// set methods that should be called for either state change. This is useful for example if
/// you want to automatically enable or disable undo or redo buttons based on there are any
/// more actions that can be undone or redone.
pub struct UndoStack<'a> {
    // All commands on the stack.
    stack: Vec<Box<UndoCmd + 'a>>,
    // Current position in the stack.
    len: usize,
    // Called when the state changes from dirty to clean.
    on_clean: Option<Box<FnMut() + 'a>>,
    // Called when the state changes from clean to dirty.
    on_dirty: Option<Box<FnMut() + 'a>>,
}

impl<'a> UndoStack<'a> {
    /// Creates a new `UndoStack`.
    #[inline]
    pub fn new() -> Self {
        UndoStack {
            stack: Vec::new(),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Creates a new `UndoStack` with the specified capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        UndoStack {
            stack: Vec::with_capacity(capacity),
            len: 0,
            on_clean: None,
            on_dirty: None,
        }
    }

    /// Returns the capacity of the `UndoStack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.stack.capacity()
    }

    /// Reserves capacity for at least `additional` more commands to be inserted in the given stack.
    /// The stack may reserve more space to avoid frequent reallocations.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.stack.reserve(additional);
    }

    /// Shrinks the capacity of the `UndoStack` as much as possible.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.stack.shrink_to_fit();
    }

    /// Sets what should happen if the state changes from dirty to clean.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// Note: An empty stack is clean, so the first push will not trigger this method.
    ///
    /// # Examples
    /// ```
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_clean(|| x += 1);
    /// ```
    #[inline]
    pub fn on_clean<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_clean = Some(Box::new(f));
        self
    }

    /// Sets what should happen if the state changes from clean to dirty.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_dirty(|| x += 1);
    /// ```
    #[inline]
    pub fn on_dirty<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_dirty = Some(Box::new(f));
        self
    }

    /// Returns `true` if the state of the stack is clean, `false` otherwise.
    #[inline]
    pub fn is_clean(&self) -> bool {
        self.len == self.stack.len()
    }

    /// Returns `true` if the state of the stack is dirty, `false` otherwise.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        !self.is_clean()
    }

    /// Pushes a `UndoCmd` to the top of the `UndoStack` and executes its [`redo`] method.
    /// This pops off all `UndoCmd`s that is above the active command from the `UndoStack`.
    ///
    /// If `cmd`s id is equal to the current top command, the two commands are merged.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn push<T>(&mut self, mut cmd: T)
        where T: UndoCmd + 'a,
    {
        let is_dirty = self.is_dirty();
        let len = self.len;
        // Pop off all elements after len from stack.
        self.stack.truncate(len);
        cmd.redo();

        // Check if we should merge cmd with the top command on stack.
        let id = cmd.id();
        if len > 0 && id.is_some() && id == unsafe { self.stack.get_unchecked(len - 1).id() } {

            // MergeCmd is the result of the merging.
            struct MergeCmd<'a> {
                cmd1: Box<UndoCmd + 'a>,
                cmd2: Box<UndoCmd + 'a>,
            }

            impl<'a> UndoCmd for MergeCmd<'a> {
                #[inline]
                fn redo(&mut self) {
                    self.cmd1.redo();
                    self.cmd2.redo();
                }

                #[inline]
                fn undo(&mut self) {
                    self.cmd2.undo();
                    self.cmd1.undo();
                }

                #[inline]
                fn id(&self) -> Option<u64> {
                    self.cmd1.id()
                }
            }

            // Merge the command with the one on the top of the stack.
            let cmd = MergeCmd {
                cmd1: unsafe {
                    // Unchecked pop.
                    self.stack.set_len(len - 1);
                    ::std::ptr::read(self.stack.get_unchecked(self.stack.len()))
                },
                cmd2: Box::new(cmd),
            };
            self.stack.push(Box::new(cmd));
        } else {
            self.stack.push(Box::new(cmd));
            self.len += 1;
        }

        // State is always clean after a push, check if it was dirty before.
        if is_dirty {
            if let Some(ref mut f) = self.on_clean {
                f();
            }
        }
    }

    /// Calls the [`redo`] method for the active `UndoCmd` and sets the next `UndoCmd` as the new
    /// active one.
    ///
    /// Calling this method when there are no more commands to redo does nothing.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn redo(&mut self) {
        if self.len < self.stack.len() {
            let is_dirty = self.is_dirty();
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.redo();
            }
            self.len += 1;
            // Check if stack went from dirty to clean.
            if is_dirty && self.is_clean() {
                if let Some(ref mut f) = self.on_clean {
                    f();
                }
            }
        }
    }

    /// Calls the [`undo`] method for the active `UndoCmd` and sets the previous `UndoCmd` as the
    /// new active one.
    ///
    /// Calling this method when there are no more commands to undo does nothing.
    ///
    /// [`undo`]: trait.UndoCmd.html#tymethod.undo
    pub fn undo(&mut self) {
        if self.len > 0 {
            let is_clean = self.is_clean();
            self.len -= 1;
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.len);
                cmd.undo();
            }
            // Check if stack went from clean to dirty.
            if is_clean && self.is_dirty() {
                if let Some(ref mut f) = self.on_dirty {
                    f();
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use {UndoStack, UndoCmd};

    #[test]
    fn pop() {
        use std::rc::Rc;
        use std::cell::{Cell, RefCell};

        /// Pops an element from a vector.
        #[derive(Clone)]
        struct PopCmd {
            vec: Rc<RefCell<Vec<i32>>>,
            e: Option<i32>,
        }

        impl UndoCmd for PopCmd {
            fn redo(&mut self) {
                self.e = self.vec.borrow_mut().pop();
            }

            fn undo(&mut self) {
                self.vec.borrow_mut().push(self.e.unwrap());
                self.e = None;
            }
        }

        let a = Cell::new(0);
        let b = Cell::new(0);
        // We need to use Rc<RefCell> since all commands are going to mutate the vec.
        let vec = Rc::new(RefCell::new(vec![1, 2, 3]));
        let mut undo_stack = UndoStack::with_capacity(3)
            .on_clean(|| a.set(1))
            .on_dirty(|| b.set(1));

        let cmd = PopCmd { vec: vec.clone(), e: None };
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());
        undo_stack.push(cmd.clone());

        assert!(vec.borrow().is_empty());

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        undo_stack.undo();
        undo_stack.undo();

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.push(cmd.clone());
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));

        assert_eq!(b.get(), 0);
        undo_stack.undo();
        assert_eq!(b.get(), 1);
        b.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2, 3])));

        assert_eq!(a.get(), 0);
        undo_stack.redo();
        assert_eq!(a.get(), 1);
        a.set(0);

        assert_eq!(vec, Rc::new(RefCell::new(vec![1, 2])));
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 TiKV Project Authors. Licensed under Apache-2.0.

use collections::HashMap;
use parking_lot::Mutex;
use std::cell::RefCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use tikv_util::sys::thread::{self, Pid};

thread_local! {
    static CURRENT_LOAD: RefCell<Option<Arc<AtomicUsize>>> = RefCell::new(None);
}

/// A load metric for all threads.
pub struct ThreadLoadPool {
    stats: Mutex<HashMap<Pid, Arc<AtomicUsize>>>,
    threshold: usize,
    total_load: AtomicUsize,
}

impl ThreadLoadPool {
    pub fn with_threshold(threshold: usize) -> ThreadLoadPool {
        ThreadLoadPool {
            stats: Mutex::default(),
            threshold,
            total_load: AtomicUsize::new(0),
        }
    }

    /// Check if current thread is in heavy load.
    pub fn current_thread_in_heavy_load(&self) -> bool {
        CURRENT_LOAD.with(|l| {
            let mut l = l.borrow_mut();
            if l.is_none() {
                let mut loads = self.stats.lock();
                *l = Some(loads.entry(thread::thread_id()).or_default().clone());
            }
            l.as_ref().unwrap().load(Ordering::Relaxed) >= self.threshold
        })
    }

    /// Gets the current load. For example, 200 means the threads consuming 200% of the CPU resources.
    pub fn total_load(&self) -> usize {
        self.total_load.load(Ordering::Relaxed)
    }
}

#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
pub use self::linux::ThreadLoadStatistics;

#[cfg(not(target_os = "linux"))]
mod other_os {
    use super::ThreadLoad;
    use std::sync::Arc;
    use std::time::Instant;

    /// A dummy `ThreadLoadStatistics` implementation for non-Linux platforms
    pub struct ThreadLoadStatistics {}

    impl ThreadLoadStatistics {
        /// Constructs a new `ThreadLoadStatistics`.
        pub fn new(_slots: usize, _prefix: &str, _thread_load: Arc<ThreadLoad>) -> Self {
            ThreadLoadStatistics {}
        }
        /// Designate target thread count of this collector.
        pub fn set_thread_target(&mut self, _target: usize) {}
        /// Records current thread load statistics.
        pub fn record(&mut self, _instant: Instant) {}
    }
}
#[cfg(not(target_os = "linux"))]
pub use self::other_os::ThreadLoadStatistics;
<commit_msg>load_statis: fix compilation on macos (#11851)<commit_after>// Copyright 2018 TiKV Project Authors. Licensed under Apache-2.0.

use collections::HashMap;
use parking_lot::Mutex;
use std::cell::RefCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use tikv_util::sys::thread::{self, Pid};

thread_local! {
    static CURRENT_LOAD: RefCell<Option<Arc<AtomicUsize>>> = RefCell::new(None);
}

/// A load metric for all threads.
pub struct ThreadLoadPool {
    stats: Mutex<HashMap<Pid, Arc<AtomicUsize>>>,
    threshold: usize,
    total_load: AtomicUsize,
}

impl ThreadLoadPool {
    pub fn with_threshold(threshold: usize) -> ThreadLoadPool {
        ThreadLoadPool {
            stats: Mutex::default(),
            threshold,
            total_load: AtomicUsize::new(0),
        }
    }

    /// Check if current thread is in heavy load.
    pub fn current_thread_in_heavy_load(&self) -> bool {
        CURRENT_LOAD.with(|l| {
            let mut l = l.borrow_mut();
            if l.is_none() {
                let mut loads = self.stats.lock();
                *l = Some(loads.entry(thread::thread_id()).or_default().clone());
            }
            l.as_ref().unwrap().load(Ordering::Relaxed) >= self.threshold
        })
    }

    /// Gets the current load. For example, 200 means the threads consuming 200% of the CPU resources.
    pub fn total_load(&self) -> usize {
        self.total_load.load(Ordering::Relaxed)
    }
}

#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
pub use self::linux::ThreadLoadStatistics;

#[cfg(not(target_os = "linux"))]
mod other_os {
    use super::ThreadLoadPool;
    use std::sync::Arc;
    use std::time::Instant;

    /// A dummy `ThreadLoadStatistics` implementation for non-Linux platforms
    pub struct ThreadLoadStatistics;

    impl ThreadLoadStatistics {
        /// Constructs a new `ThreadLoadStatistics`.
        pub fn new(_slots: usize, _prefix: &str, _thread_load: Arc<ThreadLoadPool>) -> Self {
            ThreadLoadStatistics
        }
        /// Designate target thread count of this collector.
        pub fn set_thread_target(&mut self, _target: usize) {}
        /// Records current thread load statistics.
        pub fn record(&mut self, _instant: Instant) {}
    }
}
#[cfg(not(target_os = "linux"))]
pub use self::other_os::ThreadLoadStatistics;
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parsing interface for parsing a token stream into a syntax tree node.
//!
//! Parsing in Syn is built on parser functions that take in a [`Cursor`] and
//! produce a [`PResult<T>`] where `T` is some syntax tree node. `Cursor` is a
//! cheaply copyable cursor over a range of tokens in a token stream, and
//! `PResult` is a result that packages together a parsed syntax tree node `T`
//! with a stream of remaining unparsed tokens after `T` represented as another
//! `Cursor`, or a [`ParseError`] if parsing failed.
//!
//! [`Cursor`]: ../buffer/index.html
//! [`PResult<T>`]: type.PResult.html
//! [`ParseError`]: struct.ParseError.html
//!
//! This `Cursor`- and `PResult`-based interface is convenient for parser
//! combinators and parser implementations, but not necessarily when you just
//! have some tokens that you want to parse. For that we expose the following
//! two entry points.
//!
//! ## The `syn::parse*` functions
//!
//! The [`syn::parse`], [`syn::parse2`], and [`syn::parse_str`] functions serve
//! as an entry point for parsing syntax tree nodes that can be parsed in an
//! obvious default way. These functions can return any syntax tree node that
//! implements the [`Synom`] trait, which includes most types in Syn.
//!
//! [`syn::parse`]: ../fn.parse.html
//! [`syn::parse2`]: ../fn.parse2.html
//! [`syn::parse_str`]: ../fn.parse_str.html
//! [`Synom`]: trait.Synom.html
//!
//! ```
//! use syn::Type;
//!
//! # fn run_parser() -> Result<(), syn::synom::ParseError> {
//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?;
//! #     Ok(())
//! # }
//! #
//! # fn main() {
//! #     run_parser().unwrap();
//! # }
//! ```
//!
//! The [`parse_quote!`] macro also uses this approach.
//!
//! [`parse_quote!`]: ../macro.parse_quote.html
//!
//! ## The `Parser` trait
//!
//! Some types can be parsed in several ways depending on context. For example
//! an [`Attribute`] can be either "outer" like `#[...]` or "inner" like
//! `#![...]` and parsing the wrong one would be a bug. Similarly [`Punctuated`]
//! may or may not allow trailing punctuation, and parsing it the wrong way
//! would either reject valid input or accept invalid input.
//!
//! [`Attribute`]: ../struct.Attribute.html
//! [`Punctuated`]: ../punctuated/index.html
//!
//! The `Synom` trait is not implemented in these cases because there is no good
//! behavior to consider the default.
//!
//! ```ignore
//! // Can't parse `Punctuated` without knowing whether trailing punctuation
//! // should be allowed in this context.
//! let path: Punctuated<PathSegment, Token![::]> = syn::parse(tokens)?;
//! ```
//!
//! In these cases the types provide a choice of parser functions rather than a
//! single `Synom` implementation, and those parser functions can be invoked
//! through the [`Parser`] trait.
//!
//! [`Parser`]: trait.Parser.html
//!
//! ```
//! # #[macro_use]
//! # extern crate syn;
//! #
//! # extern crate proc_macro2;
//! # use proc_macro2::TokenStream;
//! #
//! use syn::synom::Parser;
//! use syn::punctuated::Punctuated;
//! use syn::{PathSegment, Expr, Attribute};
//!
//! # fn run_parsers() -> Result<(), syn::synom::ParseError> {
//! #     let tokens = TokenStream::empty().into();
//! // Parse a nonempty sequence of path segments separated by `::` punctuation
//! // with no trailing punctuation.
//! let parser = Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty;
//! let path = parser.parse(tokens)?;
//!
//! #     let tokens = TokenStream::empty().into();
//! // Parse a possibly empty sequence of expressions terminated by commas with
//! // an optional trailing punctuation.
//! let parser = Punctuated::<Expr, Token![,]>::parse_terminated;
//! let args = parser.parse(tokens)?;
//!
//! #     let tokens = TokenStream::empty().into();
//! // Parse zero or more outer attributes but not inner attributes.
//! named!(outer_attrs -> Vec<Attribute>, many0!(Attribute::parse_outer));
//! let attrs = outer_attrs.parse(tokens)?;
//! #
//! #     Ok(())
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! # Implementing a parser function
//!
//! Parser functions are usually implemented using the [`nom`]-style parser
//! combinator macros provided by Syn, but may also be implemented without
//! macros be using the low-level [`Cursor`] API directly.
//!
//! [`nom`]: https://github.com/Geal/nom
//!
//! The following parser combinator macros are available and a `Synom` parsing
//! example is provided for each one.
//!
//! - [`alt!`](../macro.alt.html)
//! - [`braces!`](../macro.braces.html)
//! - [`brackets!`](../macro.brackets.html)
//! - [`call!`](../macro.call.html)
//! - [`cond!`](../macro.cond.html)
//! - [`cond_reduce!`](../macro.cond_reduce.html)
//! - [`do_parse!`](../macro.do_parse.html)
//! - [`epsilon!`](../macro.epsilon.html)
//! - [`input_end!`](../macro.input_end.html)
//! - [`keyword!`](../macro.keyword.html)
//! - [`many0!`](../macro.many0.html)
//! - [`map!`](../macro.map.html)
//! - [`not!`](../macro.not.html)
//! - [`option!`](../macro.option.html)
//! - [`parens!`](../macro.parens.html)
//! - [`punct!`](../macro.punct.html)
//! - [`reject!`](../macro.reject.html)
//! - [`switch!`](../macro.switch.html)
//! - [`syn!`](../macro.syn.html)
//! - [`tuple!`](../macro.tuple.html)
//! - [`value!`](../macro.value.html)
//!
//! *This module is available if Syn is built with the `"parsing"` feature.*

use proc_macro;
use proc_macro2;

pub use error::{PResult, ParseError};

use buffer::{Cursor, TokenBuffer};

/// Parsing interface implemented by all types that can be parsed in a default
/// way from a token stream.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This trait is available if Syn is built with the `"parsing"` feature.*
pub trait Synom: Sized {
    fn parse(input: Cursor) -> PResult<Self>;

    fn description() -> Option<&'static str> {
        None
    }
}

impl Synom for proc_macro2::TokenStream {
    fn parse(input: Cursor) -> PResult<Self> {
        Ok((input.token_stream(), Cursor::empty()))
    }

    fn description() -> Option<&'static str> {
        Some("arbitrary token stream")
    }
}

/// Parser that can parse Rust tokens into a particular syntax tree node.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This trait is available if Syn is built with the `"parsing"` feature.*
pub trait Parser: Sized {
    type Output;

    fn parse2(self, tokens: proc_macro2::TokenStream) -> Result<Self::Output, ParseError>;

    fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output, ParseError> {
        self.parse2(tokens.into())
    }

    fn parse_str(self, s: &str) -> Result<Self::Output, ParseError> {
        match s.parse() {
            Ok(tts) => self.parse2(tts),
            Err(_) => Err(ParseError::new("error while lexing input string")),
        }
    }
}

impl<F, T> Parser for F where F: FnOnce(Cursor) -> PResult<T> {
    type Output = T;

    fn parse2(self, tokens: proc_macro2::TokenStream) -> Result<T, ParseError> {
        let buf = TokenBuffer::new2(tokens);
        let (t, rest) = self(buf.begin())?;
        if rest.eof() {
            Ok(t)
        } else if rest == buf.begin() {
            // parsed nothing
            Err(ParseError::new("failed to parse anything"))
        } else {
            Err(ParseError::new("failed to parse all tokens"))
        }
    }
}
<commit_msg>Copy syn::parse* documentation to Parser methods<commit_after>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parsing interface for parsing a token stream into a syntax tree node.
//!
//! Parsing in Syn is built on parser functions that take in a [`Cursor`] and
//! produce a [`PResult<T>`] where `T` is some syntax tree node. `Cursor` is a
//! cheaply copyable cursor over a range of tokens in a token stream, and
//! `PResult` is a result that packages together a parsed syntax tree node `T`
//! with a stream of remaining unparsed tokens after `T` represented as another
//! `Cursor`, or a [`ParseError`] if parsing failed.
//!
//! [`Cursor`]: ../buffer/index.html
//! [`PResult<T>`]: type.PResult.html
//! [`ParseError`]: struct.ParseError.html
//!
//! This `Cursor`- and `PResult`-based interface is convenient for parser
//! combinators and parser implementations, but not necessarily when you just
//! have some tokens that you want to parse. For that we expose the following
//! two entry points.
//!
//! ## The `syn::parse*` functions
//!
//! The [`syn::parse`], [`syn::parse2`], and [`syn::parse_str`] functions serve
//! as an entry point for parsing syntax tree nodes that can be parsed in an
//! obvious default way. These functions can return any syntax tree node that
//! implements the [`Synom`] trait, which includes most types in Syn.
//!
//! [`syn::parse`]: ../fn.parse.html
//! [`syn::parse2`]: ../fn.parse2.html
//! [`syn::parse_str`]: ../fn.parse_str.html
//! [`Synom`]: trait.Synom.html
//!
//! ```
//! use syn::Type;
//!
//! # fn run_parser() -> Result<(), syn::synom::ParseError> {
//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?;
//! #     Ok(())
//! # }
//! #
//! # fn main() {
//! #     run_parser().unwrap();
//! # }
//! ```
//!
//! The [`parse_quote!`] macro also uses this approach.
//!
//! [`parse_quote!`]: ../macro.parse_quote.html
//!
//! ## The `Parser` trait
//!
//! Some types can be parsed in several ways depending on context. For example
//! an [`Attribute`] can be either "outer" like `#[...]` or "inner" like
//! `#![...]` and parsing the wrong one would be a bug. Similarly [`Punctuated`]
//! may or may not allow trailing punctuation, and parsing it the wrong way
//! would either reject valid input or accept invalid input.
//!
//! [`Attribute`]: ../struct.Attribute.html
//! [`Punctuated`]: ../punctuated/index.html
//!
//! The `Synom` trait is not implemented in these cases because there is no good
//! behavior to consider the default.
//!
//! ```ignore
//! // Can't parse `Punctuated` without knowing whether trailing punctuation
//! // should be allowed in this context.
//! let path: Punctuated<PathSegment, Token![::]> = syn::parse(tokens)?;
//! ```
//!
//! In these cases the types provide a choice of parser functions rather than a
//! single `Synom` implementation, and those parser functions can be invoked
//! through the [`Parser`] trait.
//!
//! [`Parser`]: trait.Parser.html
//!
//! ```
//! # #[macro_use]
//! # extern crate syn;
//! #
//! # extern crate proc_macro2;
//! # use proc_macro2::TokenStream;
//! #
//! use syn::synom::Parser;
//! use syn::punctuated::Punctuated;
//! use syn::{PathSegment, Expr, Attribute};
//!
//! # fn run_parsers() -> Result<(), syn::synom::ParseError> {
//! #     let tokens = TokenStream::empty().into();
//! // Parse a nonempty sequence of path segments separated by `::` punctuation
//! // with no trailing punctuation.
//! let parser = Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty;
//! let path = parser.parse(tokens)?;
//!
//! #     let tokens = TokenStream::empty().into();
//! // Parse a possibly empty sequence of expressions terminated by commas with
//! // an optional trailing punctuation.
//! let parser = Punctuated::<Expr, Token![,]>::parse_terminated;
//! let args = parser.parse(tokens)?;
//!
//! #     let tokens = TokenStream::empty().into();
//! // Parse zero or more outer attributes but not inner attributes.
//! named!(outer_attrs -> Vec<Attribute>, many0!(Attribute::parse_outer));
//! let attrs = outer_attrs.parse(tokens)?;
//! #
//! #     Ok(())
//! # }
//! #
//! # fn main() {}
//! ```
//!
//! # Implementing a parser function
//!
//! Parser functions are usually implemented using the [`nom`]-style parser
//! combinator macros provided by Syn, but may also be implemented without
//! macros be using the low-level [`Cursor`] API directly.
//!
//! [`nom`]: https://github.com/Geal/nom
//!
//! The following parser combinator macros are available and a `Synom` parsing
//! example is provided for each one.
//!
//! - [`alt!`](../macro.alt.html)
//! - [`braces!`](../macro.braces.html)
//! - [`brackets!`](../macro.brackets.html)
//! - [`call!`](../macro.call.html)
//! - [`cond!`](../macro.cond.html)
//! - [`cond_reduce!`](../macro.cond_reduce.html)
//! - [`do_parse!`](../macro.do_parse.html)
//! - [`epsilon!`](../macro.epsilon.html)
//! - [`input_end!`](../macro.input_end.html)
//! - [`keyword!`](../macro.keyword.html)
//! - [`many0!`](../macro.many0.html)
//! - [`map!`](../macro.map.html)
//! - [`not!`](../macro.not.html)
//! - [`option!`](../macro.option.html)
//! - [`parens!`](../macro.parens.html)
//! - [`punct!`](../macro.punct.html)
//! - [`reject!`](../macro.reject.html)
//! - [`switch!`](../macro.switch.html)
//! - [`syn!`](../macro.syn.html)
//! - [`tuple!`](../macro.tuple.html)
//! - [`value!`](../macro.value.html)
//!
//! *This module is available if Syn is built with the `"parsing"` feature.*

use proc_macro;
use proc_macro2;

pub use error::{PResult, ParseError};

use buffer::{Cursor, TokenBuffer};

/// Parsing interface implemented by all types that can be parsed in a default
/// way from a token stream.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This trait is available if Syn is built with the `"parsing"` feature.*
pub trait Synom: Sized {
    fn parse(input: Cursor) -> PResult<Self>;

    fn description() -> Option<&'static str> {
        None
    }
}

impl Synom for proc_macro2::TokenStream {
    fn parse(input: Cursor) -> PResult<Self> {
        Ok((input.token_stream(), Cursor::empty()))
    }

    fn description() -> Option<&'static str> {
        Some("arbitrary token stream")
    }
}

/// Parser that can parse Rust tokens into a particular syntax tree node.
///
/// Refer to the [module documentation] for details about parsing in Syn.
///
/// [module documentation]: index.html
///
/// *This trait is available if Syn is built with the `"parsing"` feature.*
pub trait Parser: Sized {
    type Output;

    /// Parse a proc-macro2 token stream into the chosen syntax tree node.
    fn parse2(self, tokens: proc_macro2::TokenStream) -> Result<Self::Output, ParseError>;

    /// Parse tokens of source code into the chosen syntax tree node.
    fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output, ParseError> {
        self.parse2(tokens.into())
    }

    /// Parse a string of Rust code into the chosen syntax tree node.
    ///
    /// # Hygiene
    ///
    /// Every span in the resulting syntax tree will be set to resolve at the
    /// macro call site.
    fn parse_str(self, s: &str) -> Result<Self::Output, ParseError> {
        match s.parse() {
            Ok(tts) => self.parse2(tts),
            Err(_) => Err(ParseError::new("error while lexing input string")),
        }
    }
}

impl<F, T> Parser for F where F: FnOnce(Cursor) -> PResult<T> {
    type Output = T;

    fn parse2(self, tokens: proc_macro2::TokenStream) -> Result<T, ParseError> {
        let buf = TokenBuffer::new2(tokens);
        let (t, rest) = self(buf.begin())?;
        if rest.eof() {
            Ok(t)
        } else if rest == buf.begin() {
            // parsed nothing
            Err(ParseError::new("failed to parse anything"))
        } else {
            Err(ParseError::new("failed to parse all tokens"))
        }
    }
}
<|endoftext|>


<commit_before>// run-rustfix

#![allow(warnings)]

struct A;
struct B;

fn foo() -> Result<A, B> {
    Ok(A)
}

fn bar() -> Result<A, B> {
    foo()?
    //~^ ERROR try expression alternatives have incompatible types [E0308]
}

fn main() {}
<commit_msg>Disable issue-59756 test for now<commit_after>// run-rustfix
// ignore-test
//
// FIXME: Re-enable this test once we support choosing
// between multiple mutually exclusive suggestions for the same span

#![allow(warnings)]

struct A;
struct B;

fn foo() -> Result<A, B> {
    Ok(A)
}

fn bar() -> Result<A, B> {
    foo()?
    //~^ ERROR try expression alternatives have incompatible types [E0308]
}

fn main() {}
<|endoftext|>


<commit_before>//! Untyped safe interface for NumPy ndarray

use ndarray::*;
use npyffi;
use pyo3::*;

use std::os::raw::c_void;
use std::ptr::null_mut;

use super::error::ArrayCastError;
use super::*;

/// Untyped safe interface for NumPy ndarray.
pub struct PyArray(PyObject);
pyobject_native_type!(PyArray, *npyffi::PyArray_Type_Ptr, npyffi::PyArray_Check);

impl IntoPyObject for PyArray {
    fn into_object(self, _py: Python) -> PyObject {
        self.0
    }
}

impl PyArray {
    /// Get raw pointer for PyArrayObject
    pub fn as_array_ptr(&self) -> *mut npyffi::PyArrayObject {
        self.as_ptr() as _
    }

    /// Construct one-dimension PyArray from Vec.
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let pyarray = PyArray::from_vec::<u32>(gil.python(), &np, vec![1, 2, 3, 4, 5]);
    /// assert_eq!(pyarray.as_slice::<u32>().unwrap(), &[1, 2, 3, 4, 5]);
    /// # }
    /// ```
    pub fn from_vec<T: TypeNum>(py: Python, np: &PyArrayModule, v: Vec<T>) -> PyArray {
        IntoPyArray::into_pyarray(v, py, np)
    }

    /// Construct two-dimension PyArray from `Vec<Vec<T>>`.
    ///
    /// This function checks all dimension of inner vec, and if there's any vec
    /// where its dimension differs from others, it returns `ArrayCastError`.
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; #[macro_use] extern crate ndarray; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let vec2 = vec![vec![1, 2, 3]; 2];
    /// let pyarray = PyArray::from_vec2::<u32>(gil.python(), &np, vec2).unwrap();
    /// assert_eq!(pyarray.as_array::<u32>().unwrap(), array![[1, 2, 3], [1, 2, 3]].into_dyn());
    /// assert!(PyArray::from_vec2::<u32>(gil.python(), &np, vec![vec![1], vec![2, 3]]).is_err());
    /// # }
    /// ```
    pub fn from_vec2<T: TypeNum>(
        py: Python,
        np: &PyArrayModule,
        v: Vec<Vec<T>>,
    ) -> Result<PyArray, ArrayCastError>
    {
        let last_len = v.last().map_or(0, |v| v.len());
        if v.iter().any(|v| v.len() != last_len) {
            return Err(ArrayCastError::FromVec);
        }
        let dims = [v.len(), last_len];
        let flattend: Vec<_> = v.into_iter().flatten().collect();
        unsafe {
            let data = convert::into_raw(flattend);
            Ok(PyArray::new_::<T>(py, np, &dims, null_mut(), data))
        }
    }

    /// Construct PyArray from ndarray::Array.
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; #[macro_use] extern crate ndarray; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let pyarray = PyArray::from_ndarray::<u32, _>(gil.python(), &np, array![[1, 2], [3, 4]]);
    /// assert_eq!(pyarray.as_array::<u32>().unwrap(), array![[1, 2], [3, 4]].into_dyn());
    /// # }
    /// ```
    pub fn from_ndarray<A, D>(py: Python, np: &PyArrayModule, arr: Array<A, D>) -> PyArray
    where
        A: TypeNum,
        D: Dimension,
    {
        IntoPyArray::into_pyarray(arr, py, np)
    }

    pub unsafe fn from_owned_ptr(py: Python, ptr: *mut pyo3::ffi::PyObject) -> Self {
        let obj = PyObject::from_owned_ptr(py, ptr);
        PyArray(obj)
    }

    pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut pyo3::ffi::PyObject) -> Self {
        let obj = PyObject::from_borrowed_ptr(py, ptr);
        PyArray(obj)
    }

    /// Returns the number of dimensions in the array.
    ///
    /// Same as [numpy.ndarray.ndim](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.ndim.html)
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let arr = PyArray::new::<f64>(gil.python(), &np, &[4, 5, 6]);
    /// assert_eq!(arr.ndim(), 3);
    /// # }
    /// ```
    // C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_NDIM
    pub fn ndim(&self) -> usize {
        let ptr = self.as_array_ptr();
        unsafe { (*ptr).nd as usize }
    }

    /// Same as [shape](./struct.PyArray.html#method.shape)
    ///
    /// Reserved for backward compatibility.
    #[inline]
    pub fn dims(&self) -> &[usize] {
        self.shape()
    }

    pub fn len(&self) -> usize {
        self.shape().iter().fold(1, |a, b| a * b)
    }

    /// Returns a slice which contains dimmensions of the array.
    ///
    /// Same as [numpy.ndarray.shape](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.shape.html)
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let arr = PyArray::new::<f64>(gil.python(), &np, &[4, 5, 6]);
    /// assert_eq!(arr.shape(), &[4, 5, 6]);
    /// # }
    /// ```
    // C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_DIMS
    pub fn shape(&self) -> &[usize] {
        let n = self.ndim();
        let ptr = self.as_array_ptr();
        unsafe {
            let p = (*ptr).dimensions as *mut usize;
            ::std::slice::from_raw_parts(p, n)
        }
    }

    /// Returns a slice which contains how many bytes you need to jump to the next row.
    ///
    /// Same as [numpy.ndarray.strides](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.strides.html)
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let arr = PyArray::new::<f64>(gil.python(), &np, &[4, 5, 6]);
    /// assert_eq!(arr.strides(), &[240, 48, 8]);
    /// # }
    /// ```
    // C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_STRIDES
    pub fn strides(&self) -> &[isize] {
        let n = self.ndim();
        let ptr = self.as_array_ptr();
        unsafe {
            let p = (*ptr).strides;
            ::std::slice::from_raw_parts(p, n)
        }
    }

    unsafe fn data<T>(&self) -> *mut T {
        let ptr = self.as_array_ptr();
        (*ptr).data as *mut T
    }

    fn ndarray_shape<A>(&self) -> StrideShape<IxDyn> {
        // FIXME may be done more simply
        let shape: Shape<_> = Dim(self.shape()).into();
        let st: Vec<usize> = self
            .strides()
            .iter()
            .map(|&x| x as usize / ::std::mem::size_of::<A>())
            .collect();
        shape.strides(Dim(st))
    }

    pub fn typenum(&self) -> i32 {
        unsafe {
            let descr = (*self.as_array_ptr()).descr;
            (*descr).type_num
        }
    }

    fn type_check<A: types::TypeNum>(&self) -> Result<(), ArrayCastError> {
        let test = A::typenum();
        let truth = self.typenum();
        if A::typenum() == self.typenum() {
            Ok(())
        } else {
            Err(ArrayCastError::to_rust(test, truth))
        }
    }

    /// Get data as a ndarray::ArrayView
    pub fn as_array<A: types::TypeNum>(&self) -> Result<ArrayViewD<A>, ArrayCastError> {
        self.type_check::<A>()?;
        unsafe {
            Ok(ArrayView::from_shape_ptr(
                self.ndarray_shape::<A>(),
                self.data(),
            ))
        }
    }

    /// Get data as a ndarray::ArrayViewMut
    pub fn as_array_mut<A: types::TypeNum>(&self) -> Result<ArrayViewMutD<A>, ArrayCastError> {
        self.type_check::<A>()?;
        unsafe {
            Ok(ArrayViewMut::from_shape_ptr(
                self.ndarray_shape::<A>(),
                self.data(),
            ))
        }
    }

    /// Get data as a Rust immutable slice
    pub fn as_slice<A: types::TypeNum>(&self) -> Result<&[A], ArrayCastError> {
        self.type_check::<A>()?;
        unsafe { Ok(::std::slice::from_raw_parts(self.data(), self.len())) }
    }

    /// Get data as a Rust mutable slice
    pub fn as_slice_mut<A: types::TypeNum>(&self) -> Result<&mut [A], ArrayCastError> {
        self.type_check::<A>()?;
        unsafe { Ok(::std::slice::from_raw_parts_mut(self.data(), self.len())) }
    }

    pub unsafe fn new_<T: types::TypeNum>(
        py: Python,
        np: &PyArrayModule,
        dims: &[usize],
        strides: *mut npy_intp,
        data: *mut c_void,
    ) -> Self {
        let dims: Vec<_> = dims.iter().map(|d| *d as npy_intp).collect();
        let ptr = np.PyArray_New(
            np.get_type_object(npyffi::ArrayType::PyArray_Type),
            dims.len() as i32,
            dims.as_ptr() as *mut npy_intp,
            T::typenum(),
            strides,
            data,
            0,                      // itemsize
            0,                      // flag
            ::std::ptr::null_mut(), //obj
        );
        Self::from_owned_ptr(py, ptr)
    }

    /// a wrapper of [PyArray_SimpleNew](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_SimpleNew)
    pub fn new<T: TypeNum>(py: Python, np: &PyArrayModule, dims: &[usize]) -> Self {
        unsafe { Self::new_::<T>(py, np, dims, null_mut(), null_mut()) }
    }

    /// a wrapper of [PyArray_ZEROS](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_ZEROS)
    pub fn zeros<T: TypeNum>(
        py: Python,
        np: &PyArrayModule,
        dims: &[usize],
        order: NPY_ORDER,
    ) -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let descr = np.PyArray_DescrFromType(T::typenum());
            let ptr = np.PyArray_Zeros(
                dims.len() as i32,
                dims.as_ptr() as *mut npy_intp,
                descr,
                order as i32,
            );
            Self::from_owned_ptr(py, ptr)
        }
    }

    /// a wrapper of [PyArray_Arange](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_Arange)
    pub fn arange<T: TypeNum>(
        py: Python,
        np: &PyArrayModule,
        start: f64,
        stop: f64,
        step: f64,
    ) -> Self {
        unsafe {
            let ptr = np.PyArray_Arange(start, stop, step, T::typenum());
            Self::from_owned_ptr(py, ptr)
        }
    }
}
<commit_msg>Add from_vec3 and from_boxed_slice<commit_after>//! Untyped safe interface for NumPy ndarray

use ndarray::*;
use npyffi;
use pyo3::*;

use std::os::raw::c_void;
use std::ptr::null_mut;

use super::error::ArrayCastError;
use super::*;

/// Untyped safe interface for NumPy ndarray.
pub struct PyArray(PyObject);
pyobject_native_type!(PyArray, *npyffi::PyArray_Type_Ptr, npyffi::PyArray_Check);

impl IntoPyObject for PyArray {
    fn into_object(self, _py: Python) -> PyObject {
        self.0
    }
}

impl PyArray {
    /// Get raw pointer for PyArrayObject
    pub fn as_array_ptr(&self) -> *mut npyffi::PyArrayObject {
        self.as_ptr() as _
    }

    /// Construct one-dimension PyArray from boxed slice.
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let slice = vec![1, 2, 3, 4, 5].into_boxed_slice();
    /// let pyarray = PyArray::from_boxed_slice::<u32>(gil.python(), &np, slice);
    /// assert_eq!(pyarray.as_slice::<u32>().unwrap(), &[1, 2, 3, 4, 5]);
    /// # }
    /// ```
    pub fn from_boxed_slice<T: TypeNum>(py: Python, np: &PyArrayModule, v: Box<[T]>) -> PyArray {
        IntoPyArray::into_pyarray(v, py, np)
    }

    /// Construct one-dimension PyArray from Vec.
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let pyarray = PyArray::from_vec::<u32>(gil.python(), &np, vec![1, 2, 3, 4, 5]);
    /// assert_eq!(pyarray.as_slice::<u32>().unwrap(), &[1, 2, 3, 4, 5]);
    /// # }
    /// ```
    pub fn from_vec<T: TypeNum>(py: Python, np: &PyArrayModule, v: Vec<T>) -> PyArray {
        IntoPyArray::into_pyarray(v, py, np)
    }

    /// Construct a two-dimension PyArray from `Vec<Vec<T>>`.
    ///
    /// This function checks all dimension of inner vec, and if there's any vec
    /// where its dimension differs from others, it returns `ArrayCastError`.
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; #[macro_use] extern crate ndarray; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let vec2 = vec![vec![1, 2, 3]; 2];
    /// let pyarray = PyArray::from_vec2::<u32>(gil.python(), &np, vec2).unwrap();
    /// assert_eq!(pyarray.as_array::<u32>().unwrap(), array![[1, 2, 3], [1, 2, 3]].into_dyn());
    /// assert!(PyArray::from_vec2::<u32>(gil.python(), &np, vec![vec![1], vec![2, 3]]).is_err());
    /// # }
    /// ```
    pub fn from_vec2<T: TypeNum>(
        py: Python,
        np: &PyArrayModule,
        v: Vec<Vec<T>>,
    ) -> Result<PyArray, ArrayCastError> {
        let last_len = v.last().map_or(0, |v| v.len());
        if v.iter().any(|v| v.len() != last_len) {
            return Err(ArrayCastError::FromVec);
        }
        let dims = [v.len(), last_len];
        let flattend: Vec<_> = v.into_iter().flatten().collect();
        unsafe {
            let data = convert::into_raw(flattend);
            Ok(PyArray::new_::<T>(py, np, &dims, null_mut(), data))
        }
    }

    /// Construct a three-dimension PyArray from `Vec<Vec<Vec<T>>>`.
    ///
    /// This function checks all dimension of inner vec, and if there's any vec
    /// where its dimension differs from others, it returns `ArrayCastError`.
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; #[macro_use] extern crate ndarray; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let vec2 = vec![vec![1, 2, 3]; 3];
    /// let pyarray = PyArray::from_vec2::<u32>(gil.python(), &np, vec2).unwrap();
    /// assert_eq!(
    ///     pyarray.as_array::<u32>().unwrap(),
    ///     array![[1, 2, 3], [1, 2, 3], [1, 2, 3]].into_dyn()
    /// );
    /// assert!(PyArray::from_vec3::<u32>(gil.python(), &np, vec![vec![vec![1], vec![]]]).is_err());
    /// # }
    /// ```
    pub fn from_vec3<T: TypeNum>(
        py: Python,
        np: &PyArrayModule,
        v: Vec<Vec<Vec<T>>>,
    ) -> Result<PyArray, ArrayCastError> {
        let dim2 = v.last().map_or(0, |v| v.len());
        if v.iter().any(|v| v.len() != dim2) {
            return Err(ArrayCastError::FromVec);
        }
        let dim3 = v.last().map_or(0, |v| v.last().map_or(0, |v| v.len()));
        if v.iter().any(|v| v.iter().any(|v| v.len() != dim3)) {
            return Err(ArrayCastError::FromVec);
        }
        let dims = [v.len(), dim2, dim3];
        let flattend: Vec<_> = v.into_iter().flat_map(|v| v.into_iter().flatten()).collect();
        unsafe {
            let data = convert::into_raw(flattend);
            Ok(PyArray::new_::<T>(py, np, &dims, null_mut(), data))
        }
    }

    /// Construct PyArray from ndarray::Array.
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; #[macro_use] extern crate ndarray; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let pyarray = PyArray::from_ndarray::<u32, _>(gil.python(), &np, array![[1, 2], [3, 4]]);
    /// assert_eq!(pyarray.as_array::<u32>().unwrap(), array![[1, 2], [3, 4]].into_dyn());
    /// # }
    /// ```
    pub fn from_ndarray<A, D>(py: Python, np: &PyArrayModule, arr: Array<A, D>) -> PyArray
    where
        A: TypeNum,
        D: Dimension,
    {
        IntoPyArray::into_pyarray(arr, py, np)
    }

    pub unsafe fn from_owned_ptr(py: Python, ptr: *mut pyo3::ffi::PyObject) -> Self {
        let obj = PyObject::from_owned_ptr(py, ptr);
        PyArray(obj)
    }

    pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut pyo3::ffi::PyObject) -> Self {
        let obj = PyObject::from_borrowed_ptr(py, ptr);
        PyArray(obj)
    }

    /// Returns the number of dimensions in the array.
    ///
    /// Same as [numpy.ndarray.ndim](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.ndim.html)
    ///
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let arr = PyArray::new::<f64>(gil.python(), &np, &[4, 5, 6]);
    /// assert_eq!(arr.ndim(), 3);
    /// # }
    /// ```
    // C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_NDIM
    pub fn ndim(&self) -> usize {
        let ptr = self.as_array_ptr();
        unsafe { (*ptr).nd as usize }
    }

    /// Same as [shape](./struct.PyArray.html#method.shape)
    ///
    /// Reserved for backward compatibility.
    #[inline]
    pub fn dims(&self) -> &[usize] {
        self.shape()
    }

    pub fn len(&self) -> usize {
        self.shape().iter().fold(1, |a, b| a * b)
    }

    /// Returns a slice which contains dimmensions of the array.
    ///
    /// Same as [numpy.ndarray.shape](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.shape.html)
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let arr = PyArray::new::<f64>(gil.python(), &np, &[4, 5, 6]);
    /// assert_eq!(arr.shape(), &[4, 5, 6]);
    /// # }
    /// ```
    // C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_DIMS
    pub fn shape(&self) -> &[usize] {
        let n = self.ndim();
        let ptr = self.as_array_ptr();
        unsafe {
            let p = (*ptr).dimensions as *mut usize;
            ::std::slice::from_raw_parts(p, n)
        }
    }

    /// Returns a slice which contains how many bytes you need to jump to the next row.
    ///
    /// Same as [numpy.ndarray.strides](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.strides.html)
    /// # Example
    /// ```
    /// # extern crate pyo3; extern crate numpy; fn main() {
    /// use numpy::{PyArray, PyArrayModule};
    /// let gil = pyo3::Python::acquire_gil();
    /// let np = PyArrayModule::import(gil.python()).unwrap();
    /// let arr = PyArray::new::<f64>(gil.python(), &np, &[4, 5, 6]);
    /// assert_eq!(arr.strides(), &[240, 48, 8]);
    /// # }
    /// ```
    // C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_STRIDES
    pub fn strides(&self) -> &[isize] {
        let n = self.ndim();
        let ptr = self.as_array_ptr();
        unsafe {
            let p = (*ptr).strides;
            ::std::slice::from_raw_parts(p, n)
        }
    }

    unsafe fn data<T>(&self) -> *mut T {
        let ptr = self.as_array_ptr();
        (*ptr).data as *mut T
    }

    fn ndarray_shape<A>(&self) -> StrideShape<IxDyn> {
        // FIXME may be done more simply
        let shape: Shape<_> = Dim(self.shape()).into();
        let st: Vec<usize> = self
            .strides()
            .iter()
            .map(|&x| x as usize / ::std::mem::size_of::<A>())
            .collect();
        shape.strides(Dim(st))
    }

    pub fn typenum(&self) -> i32 {
        unsafe {
            let descr = (*self.as_array_ptr()).descr;
            (*descr).type_num
        }
    }

    fn type_check<A: types::TypeNum>(&self) -> Result<(), ArrayCastError> {
        let test = A::typenum();
        let truth = self.typenum();
        if A::typenum() == self.typenum() {
            Ok(())
        } else {
            Err(ArrayCastError::to_rust(test, truth))
        }
    }

    /// Get data as a ndarray::ArrayView
    pub fn as_array<A: types::TypeNum>(&self) -> Result<ArrayViewD<A>, ArrayCastError> {
        self.type_check::<A>()?;
        unsafe {
            Ok(ArrayView::from_shape_ptr(
                self.ndarray_shape::<A>(),
                self.data(),
            ))
        }
    }

    /// Get data as a ndarray::ArrayViewMut
    pub fn as_array_mut<A: types::TypeNum>(&self) -> Result<ArrayViewMutD<A>, ArrayCastError> {
        self.type_check::<A>()?;
        unsafe {
            Ok(ArrayViewMut::from_shape_ptr(
                self.ndarray_shape::<A>(),
                self.data(),
            ))
        }
    }

    /// Get data as a Rust immutable slice
    pub fn as_slice<A: types::TypeNum>(&self) -> Result<&[A], ArrayCastError> {
        self.type_check::<A>()?;
        unsafe { Ok(::std::slice::from_raw_parts(self.data(), self.len())) }
    }

    /// Get data as a Rust mutable slice
    pub fn as_slice_mut<A: types::TypeNum>(&self) -> Result<&mut [A], ArrayCastError> {
        self.type_check::<A>()?;
        unsafe { Ok(::std::slice::from_raw_parts_mut(self.data(), self.len())) }
    }

    pub unsafe fn new_<T: types::TypeNum>(
        py: Python,
        np: &PyArrayModule,
        dims: &[usize],
        strides: *mut npy_intp,
        data: *mut c_void,
    ) -> Self {
        let dims: Vec<_> = dims.iter().map(|d| *d as npy_intp).collect();
        let ptr = np.PyArray_New(
            np.get_type_object(npyffi::ArrayType::PyArray_Type),
            dims.len() as i32,
            dims.as_ptr() as *mut npy_intp,
            T::typenum(),
            strides,
            data,
            0,                      // itemsize
            0,                      // flag
            ::std::ptr::null_mut(), //obj
        );
        Self::from_owned_ptr(py, ptr)
    }

    /// a wrapper of [PyArray_SimpleNew](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_SimpleNew)
    pub fn new<T: TypeNum>(py: Python, np: &PyArrayModule, dims: &[usize]) -> Self {
        unsafe { Self::new_::<T>(py, np, dims, null_mut(), null_mut()) }
    }

    /// a wrapper of [PyArray_ZEROS](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_ZEROS)
    pub fn zeros<T: TypeNum>(
        py: Python,
        np: &PyArrayModule,
        dims: &[usize],
        order: NPY_ORDER,
    ) -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let descr = np.PyArray_DescrFromType(T::typenum());
            let ptr = np.PyArray_Zeros(
                dims.len() as i32,
                dims.as_ptr() as *mut npy_intp,
                descr,
                order as i32,
            );
            Self::from_owned_ptr(py, ptr)
        }
    }

    /// a wrapper of [PyArray_Arange](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_Arange)
    pub fn arange<T: TypeNum>(
        py: Python,
        np: &PyArrayModule,
        start: f64,
        stop: f64,
        step: f64,
    ) -> Self {
        unsafe {
            let ptr = np.PyArray_Arange(start, stop, step, T::typenum());
            Self::from_owned_ptr(py, ptr)
        }
    }
}
<|endoftext|>


<commit_before>//! Utilities and parsers for dealing with ASCII data in `u8` format.

use conv::{NoError, ValueFrom};
use conv::errors::UnwrapOk;

use std::ops::{Add, Mul};

use {Input, U8Result};
use parsers::{take_while, take_while1, satisfy};

/// Lowercase ASCII predicate.
#[inline]
pub fn is_lowercase(c: u8) -> bool {
    b'a' <= c && c <= b'z'
}

/// Uppercase ASCII character predicate.
#[inline]
pub fn is_uppercase(c: u8) -> bool {
    b'A' <= c && c <= b'Z'
}

/// ASCII whitespace predicate.
///
/// Includes:
///
/// * Horizontal tab (TAB)
/// * Line feed (LF)
/// * Vertical tab (VT)
/// * Form feed (FF)
/// * Carriage return (CR)
/// * Space
#[inline]
pub fn is_whitespace(c: u8) -> bool {
    9 <= c && c <= 13 || c == b' '
}

/// A predicate which matches either space (' ') or horizontal tab ('\t').
#[inline]
pub fn is_horizontal_space(c: u8) -> bool {
    c == b'\t' || c == b' '
}

/// A predicate matching eithr a newline ('\n') or a carriage return ('\r').
#[inline]
pub fn is_end_of_line(c: u8) -> bool {
    c == b'\n' || c == b'\r'
}

/// ASCII digit predicate.
#[inline]
pub fn is_digit(c: u8) -> bool {
    b'0' <= c && c <= b'9'
}

/// ASCII alphabetic predicate.
#[inline]
pub fn is_alpha(c: u8) -> bool {
    is_lowercase(c) || is_uppercase(c)
}

/// ASCII alphanumeric predicate.
#[inline]
pub fn is_alphanumeric(c: u8) -> bool {
    is_alpha(c) || is_digit(c)
}

/// Skips over whitespace.
///
/// Matches zero-length.
///
/// # Example
///
/// ```
/// use chomp::Input;
/// use chomp::ascii::skip_whitespace;
///
/// let i = Input::new(b" \t ");
///
/// assert_eq!(skip_whitespace(i).unwrap(), ());
/// ```
#[inline]
pub fn skip_whitespace(i: Input<u8>) -> U8Result<()> {
    take_while(i, is_whitespace).map(|_| ())
}

/// Parses a single digit.
///
/// # Note
///
/// The result is the code of the digit, no conversion takes place.
///
/// # Example
///
/// ```
/// use chomp::Input;
/// use chomp::ascii::digit;
///
/// let i = Input::new(b"1");
///
/// let r = digit(i);
///
/// assert_eq!(r.unwrap(), b'1');
/// ```
#[inline]
pub fn digit(i: Input<u8>) -> U8Result<u8> {
    satisfy(i, is_digit)
}

/// Parses a series of digits and converts them to an integer.
///
/// # Note
///
/// The `T` type must be larger than `u8` if it is signed.
///
/// # Example
///
/// ```
/// use chomp::Input;
/// use chomp::ascii::decimal;
///
/// let i = Input::new(b"123");
///
/// let r = decimal::<u8>(i);
///
/// assert_eq!(r.unwrap(), 123u8);
/// ```
#[inline]
pub fn decimal<T: Copy + ValueFrom<u8, Err=NoError> + Add<Output=T> + Mul<Output=T>>(i: Input<u8>) -> U8Result<T> {
    take_while1(i, is_digit).bind(|i, buf| i.ret(to_decimal(buf)))
}

/// Internal function converting a `[u8]` to the given integer type `T`.
///
/// # Notes
///
/// * The slice must not contain any other characters besides 0 to 9.
/// * The `T` type must be larger than `u8` if it is signed.
#[inline]
fn to_decimal<T: Copy + ValueFrom<u8, Err=NoError> + Add<Output=T> + Mul<Output=T>>(buf: &[u8]) -> T {
    buf.iter().fold(T::value_from(0).unwrap_ok(), |a, n| a * T::value_from(10).unwrap_ok() + T::value_from(n - b'0').unwrap_ok())
}

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

    macro_rules! test_to_decimal {
        ( $($n:ty),+ ) => { $(
            assert_eq!(to_decimal::<$n>(b""), 0);
            assert_eq!(to_decimal::<$n>(b"0"), 0);
            assert_eq!(to_decimal::<$n>(b"1"), 1);
            assert_eq!(to_decimal::<$n>(b"2"), 2);
            assert_eq!(to_decimal::<$n>(b"10"), 10);
            assert_eq!(to_decimal::<$n>(b"20"), 20);
            assert_eq!(to_decimal::<$n>(b"25"), 25);
        )+ }
    }

    #[test]
    fn test_to_decimal_u8() {
        test_to_decimal!(u8, u16, u32, u64, i16, i32, i64);
    }
}
<commit_msg>Combinator: ascii::signed<commit_after>//! Utilities and parsers for dealing with ASCII data in `u8` format.

use conv::{NoError, ValueFrom};
use conv::errors::UnwrapOk;

use std::ops::{Add, Mul};

use {Input, U8Result};
use combinators::option;
use parsers::{take_while, take_while1, satisfy};

/// Lowercase ASCII predicate.
#[inline]
pub fn is_lowercase(c: u8) -> bool {
    b'a' <= c && c <= b'z'
}

/// Uppercase ASCII character predicate.
#[inline]
pub fn is_uppercase(c: u8) -> bool {
    b'A' <= c && c <= b'Z'
}

/// ASCII whitespace predicate.
///
/// Includes:
///
/// * Horizontal tab (TAB)
/// * Line feed (LF)
/// * Vertical tab (VT)
/// * Form feed (FF)
/// * Carriage return (CR)
/// * Space
#[inline]
pub fn is_whitespace(c: u8) -> bool {
    9 <= c && c <= 13 || c == b' '
}

/// A predicate which matches either space (' ') or horizontal tab ('\t').
#[inline]
pub fn is_horizontal_space(c: u8) -> bool {
    c == b'\t' || c == b' '
}

/// A predicate matching eithr a newline ('\n') or a carriage return ('\r').
#[inline]
pub fn is_end_of_line(c: u8) -> bool {
    c == b'\n' || c == b'\r'
}

/// ASCII digit predicate.
#[inline]
pub fn is_digit(c: u8) -> bool {
    b'0' <= c && c <= b'9'
}

/// ASCII alphabetic predicate.
#[inline]
pub fn is_alpha(c: u8) -> bool {
    is_lowercase(c) || is_uppercase(c)
}

/// ASCII alphanumeric predicate.
#[inline]
pub fn is_alphanumeric(c: u8) -> bool {
    is_alpha(c) || is_digit(c)
}

/// Skips over whitespace.
///
/// Matches zero-length.
///
/// # Example
///
/// ```
/// use chomp::Input;
/// use chomp::ascii::skip_whitespace;
///
/// let i = Input::new(b" \t ");
///
/// assert_eq!(skip_whitespace(i).unwrap(), ());
/// ```
#[inline]
pub fn skip_whitespace(i: Input<u8>) -> U8Result<()> {
    take_while(i, is_whitespace).map(|_| ())
}

/// Parses a single digit.
///
/// # Note
///
/// The result is the code of the digit, no conversion takes place.
///
/// # Example
///
/// ```
/// use chomp::Input;
/// use chomp::ascii::digit;
///
/// let i = Input::new(b"1");
///
/// let r = digit(i);
///
/// assert_eq!(r.unwrap(), b'1');
/// ```
#[inline]
pub fn digit(i: Input<u8>) -> U8Result<u8> {
    satisfy(i, is_digit)
}

/// Parses a number with an optional leading '+' or '-'.
///
/// # Note
///
/// The from `i8` bound here is usually smaller than the number parser requirement for signed
/// integers (usually the smallest possible signed is `i16`).
///
/// # Example
///
/// ```
/// use chomp::{Input, ParseResult};
/// use chomp::ascii::{decimal, signed};
///
/// let i = Input::new(b"-123");
///
/// let r: ParseResult<_, i16, _> = signed(i, decimal);
///
/// assert_eq!(r.unwrap(), -123i16);
/// ```
#[inline]
pub fn signed<T, F>(i: Input<u8>, f: F) -> U8Result<T>
  where T: Copy + ValueFrom<i8, Err=NoError> + Add<Output=T> + Mul<Output=T>,
        F: FnOnce(Input<u8>) -> U8Result<T> {
    option(i,
           |i| satisfy(i, |c| c == b'-' || c == b'+')
               .map(|s| T::value_from(if s == b'+' { 1 } else { -1 }).unwrap_ok()),
           T::value_from(1).unwrap_ok())
        .bind(|i, sign| f(i).map(|num| sign * num))
}

/// Parses a series of digits and converts them to an integer.
///
/// # Note
///
/// The `T` type must be larger than `u8` if it is signed.
///
/// # Example
///
/// ```
/// use chomp::Input;
/// use chomp::ascii::decimal;
///
/// let i = Input::new(b"123");
///
/// let r = decimal::<u8>(i);
///
/// assert_eq!(r.unwrap(), 123u8);
/// ```
#[inline]
pub fn decimal<T: Copy + ValueFrom<u8, Err=NoError> + Add<Output=T> + Mul<Output=T>>(i: Input<u8>) -> U8Result<T> {
    take_while1(i, is_digit).bind(|i, buf| i.ret(to_decimal(buf)))
}

/// Internal function converting a `[u8]` to the given integer type `T`.
///
/// # Notes
///
/// * The slice must not contain any other characters besides 0 to 9.
/// * The `T` type must be larger than `u8` if it is signed.
#[inline]
fn to_decimal<T: Copy + ValueFrom<u8, Err=NoError> + Add<Output=T> + Mul<Output=T>>(buf: &[u8]) -> T {
    buf.iter().fold(T::value_from(0).unwrap_ok(), |a, n| a * T::value_from(10).unwrap_ok() + T::value_from(n - b'0').unwrap_ok())
}

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

    macro_rules! test_to_decimal {
        ( $($n:ty),+ ) => { $(
            assert_eq!(to_decimal::<$n>(b""), 0);
            assert_eq!(to_decimal::<$n>(b"0"), 0);
            assert_eq!(to_decimal::<$n>(b"1"), 1);
            assert_eq!(to_decimal::<$n>(b"2"), 2);
            assert_eq!(to_decimal::<$n>(b"10"), 10);
            assert_eq!(to_decimal::<$n>(b"20"), 20);
            assert_eq!(to_decimal::<$n>(b"25"), 25);
        )+ }
    }

    #[test]
    fn test_to_decimal_u8() {
        test_to_decimal!(u8, u16, u32, u64, i16, i32, i64);
    }
}
<|endoftext|>


<commit_before>//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

// 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 https://mozilla.org/MPL/2.0/.

use std::io::Cursor;
use super::*;
extern crate test_assembler;
use self::test_assembler::*;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
    Auto,
}

fn make_box_raw<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    let mut section = Section::new();
    let box_size = Label::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
        BoxSize::Auto => section.B32(&box_size),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) => {
            if size > 0 {
                assert_eq!(size as u64, section.size())
            }
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        BoxSize::Auto => {
            assert!(section.size() <= u32::max_value() as u64,
              "Tried to use a long box with BoxSize::Auto");
            box_size.set_const(section.size());
        },
        // Skip checking BoxSize::Unchecked* cases.
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_box<F>(size: u32, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, func)
}

fn make_fullbox<F>(size: u32, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, |s| {
        func(s.B8(version)
              .B8(0)
              .B8(0)
              .B8(0))
    })
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box_raw(BoxSize::Short(8), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 8);
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box_raw(BoxSize::Long(16), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 16);
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box_raw(BoxSize::Short(0), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::Unsupported) => (),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedShort(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedLong(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(24, b"ftyp", |s| {
        s.append_bytes(b"mp42")
         .B32(0) // minor version
         .append_bytes(b"isom")
         .append_bytes(b"mp42")
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"ftyp"));
    assert_eq!(parsed.header.size, 24);
    assert_eq!(parsed.major_brand, FourCC(*b"mp42"));
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], FourCC(*b"isom"));
    assert_eq!(parsed.compatible_brands[1], FourCC(*b"mp42"));
}

#[test]
#[should_panic(expected = "expected an error result")]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box_raw(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0) // minor version
            .append_bytes(b"isom")
    });
    let mut context = MediaContext::new();
    match read_mp4(&mut stream, &mut context) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => assert!(false, "expected an error result"),
        _ => assert!(false, "expected a different error result"),
    }
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(28, b"elst", 0, |s| {
        s.B32(1) // list count
          // first entry
         .B32(1234) // duration
         .B32(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 28);
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(56, b"elst", 1, |s| {
        s.B32(2) // list count
         // first entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
         // second entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 56);
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 44);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(::std::u32::MAX) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mdhd(&mut stream, &header, &mut super::Track::new(0));
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 120);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mvhd(&mut stream, &header);
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(::std::u32::MAX)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_vpcc() {
    let data_length = 12u16;
    let box_length = 8 + 4 + 6 + data_length as u32;
    let mut stream = make_fullbox(box_length, b"vpcC", 0, |s| {
        s.B8(2)
         .B8(0)
         .B8(0x82)
         .B8(0)
         .B16(data_length)
         .append_repeated(42, data_length as usize)
    });
    let header = read_box_header(&mut stream).unwrap();
    assert_eq!(header.name.as_bytes(), b"vpcC");
    let r = super::read_vpcc(&mut stream);
    assert!(r.is_ok());
}
<commit_msg>Use BoxSize::Auto for most tests.<commit_after>//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

// 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 https://mozilla.org/MPL/2.0/.

use std::io::Cursor;
use super::*;
extern crate test_assembler;
use self::test_assembler::*;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
    Auto,
}

fn make_box_raw<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    let mut section = Section::new();
    let box_size = Label::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
        BoxSize::Auto => section.B32(&box_size),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) => {
            if size > 0 {
                assert_eq!(size as u64, section.size())
            }
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        BoxSize::Auto => {
            assert!(section.size() <= u32::max_value() as u64,
              "Tried to use a long box with BoxSize::Auto");
            box_size.set_const(section.size());
        },
        // Skip checking BoxSize::Unchecked* cases.
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_box<F>(size: u32, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, func)
}

fn make_fullbox<F>(size: BoxSize, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(size, name, |s| {
        func(s.B8(version)
              .B8(0)
              .B8(0)
              .B8(0))
    })
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box_raw(BoxSize::Short(8), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 8);
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box_raw(BoxSize::Long(16), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 16);
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box_raw(BoxSize::Short(0), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::Unsupported) => (),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedShort(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedLong(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(24, b"ftyp", |s| {
        s.append_bytes(b"mp42")
         .B32(0) // minor version
         .append_bytes(b"isom")
         .append_bytes(b"mp42")
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"ftyp"));
    assert_eq!(parsed.header.size, 24);
    assert_eq!(parsed.major_brand, FourCC(*b"mp42"));
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], FourCC(*b"isom"));
    assert_eq!(parsed.compatible_brands[1], FourCC(*b"mp42"));
}

#[test]
#[should_panic(expected = "expected an error result")]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box_raw(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0) // minor version
            .append_bytes(b"isom")
    });
    let mut context = MediaContext::new();
    match read_mp4(&mut stream, &mut context) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => assert!(false, "expected an error result"),
        _ => assert!(false, "expected a different error result"),
    }
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(BoxSize::Auto, b"elst", 0, |s| {
        s.B32(1) // list count
          // first entry
         .B32(1234) // duration
         .B32(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 28);
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(BoxSize::Auto, b"elst", 1, |s| {
        s.B32(2) // list count
         // first entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
         // second entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 56);
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 44);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(::std::u32::MAX) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mdhd(&mut stream, &header, &mut super::Track::new(0));
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 120);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mvhd(&mut stream, &header);
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(::std::u32::MAX)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_vpcc() {
    let data_length = 12u16;
    let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 0, |s| {
        s.B8(2)
         .B8(0)
         .B8(0x82)
         .B8(0)
         .B16(data_length)
         .append_repeated(42, data_length as usize)
    });
    let header = read_box_header(&mut stream).unwrap();
    assert_eq!(header.name.as_bytes(), b"vpcC");
    let r = super::read_vpcc(&mut stream);
    assert!(r.is_ok());
}
<|endoftext|>