<commit_before>//! Tree structure implementations and common traits for manipulating them.

// Basic use cases:
//  - Fixed tree (built once). Handled by Zipper, Tree, Nav.
//  - Fixed-topology tree (data mutates). Handled by Zipper, Tree, Nav.
//  - Shared-data tree (topology fixed). Handled by Zipper, Tree, Nav with
//    RefCell<T> or Mutex<T> for data.
//  - Shared-topology tree (data fixed).
//  - Shared-data, shared-topology tree.

// For std::rc::try_unwrap.
#![feature(rc_unique)]

/// Fixed-layout trees with good memory locality guarantees.
pub mod fixed;
/// Single-ownership trees wherein a parent owns its children.
pub mod owned;
/// Heap-allocated, reference-counted trees that can be shared freely.
pub mod shared;
/// Tree traversal methods and interfaces.
pub mod traversal;
/// Internal utilities.
mod util;

/// Navigable, focus-based view of a tree.
///
/// This trait defines a view of a tree that is focused on a node and can be
/// navigated to that node's parent, a sibling, or a child.
///
/// If you have worked with
/// [zippers](http://en.wikipedia.org/wiki/Zipper_(data_structure)), this should
/// seem familiar.
///
/// For access to data at tree nodes, implementing types should also implement
/// `std::borrow::Borrow` or `std::borrow::BorrowMut`.
///
/// This trait does not expose methods for mutating the tree, but this does not
/// guarantee immutability or thread safety. Implementing types may permit
/// mutation of tree data (whether by implementing `std::borrow::BorrowMut`,
/// implementing `std::borrow::Borrow` and having `RefCell` data, or otherwise),
/// which may in turn cause arbitrary modififixcations in the underlying
/// representation of the tree structure, such as reallocations. The `Editor`
/// trait, which extends this one, permits modification of the tree topology.
///
/// This trait is usually implemented for borrows of some underlying tree
/// structure.
///
/// To make it convenient to navigate through a tree and retain pointers along
/// the way, it is recommended that implementors also provide an implementation
/// of `std::clone::Clone` when this is possible. For mutable types that also
/// implement `std::borrow::BorrowMut`, which may require a read-write borrow of
/// an underlying structure, this may not be possible.
pub trait Nav {
    /// Returns the number of children of the current node.
    fn child_count(&self) -> usize;

    /// Returns `true` iff the current node is a leaf (i.e., it has no
    /// children).
    fn at_leaf(&self) -> bool {
        self.child_count() == 0
    }

    /// Returns `true` iff the current node is the tree root (i.e., it has no
    /// parent).
    fn at_root(&self) -> bool;

    /// Navigates to the sibling at `offset`, for which negative values indicate
    /// navigating to the left of this node's location and positive value to the
    /// right. (An offset of 0 is a no-op.) Panics if this is the tree root or
    /// `offset` resolves to a nonexistant sibling.
    fn seek_sibling(&mut self, offset: isize);

    /// Navigates to the child at at the given index. Panics if there are no
    /// children to navigate to or `index` resolves to a nonexistant child.
    fn seek_child(&mut self, index: usize);

    /// Navigates to this node's parent. Panics if this is the root.
    fn to_parent(&mut self);

    /// Navigates to the tree's root. If this navigator is already pointing at
    /// the tree root, this is a no-op.
    ///
    /// The default implementation of this method repeatedly calls
    /// `to_parent`. Implementors may wish to provide a more efficient method.
    fn to_root(&mut self) {
        while ! self.at_root() {
            self.to_parent();
        }
    }
}

/// Navigable view of a tree, with support for modifying the tree's topology.
///
/// This trait extends [Nav](trait.Nav.html) with support for tree modification
/// operations.
pub trait Editor: Nav {
    /// The type of tree node data, usually the `T` of some `Tree<T>`.
    type Data;

    /// The tree type that is associated with operations that insert or remove
    /// subtrees. This is typically the implementing tree type that the `Editor`
    /// provides a view of.
    type Tree;

    /// Creates a new leaf with the given data at the logical end of the
    /// children of the current focus and focuses on it.
    fn push_leaf(&mut self, data: <Self as Editor>::Data);

    /// Adds `child` to the logical end of the children of the current focus and
    /// focuses on it.
    fn push_child(&mut self, child: <Self as Editor>::Tree);

    /// Inserts a new leaf with the given data at the given position in the
    /// current focus's children and focuses on it.
    fn insert_leaf(&mut self, index: usize, data: <Self as Editor>::Data);

    /// Inserts `child` at the given position in the current focus's children
    /// and focuses on it.
    fn insert_child(
        &mut self, index: usize, child: <Self as Editor>::Tree);

    /// Inserts a new leaf with the given data at the position an offset by the
    /// given amount from the current focus and focuses on it. Panics if the
    /// offset is invalid.
    fn insert_sibling_leaf(
        &mut self, offset: isize, data: <Self as Editor>::Data);

    /// Inserts `sibling` at the given offset relative to the current focus and
    /// focuses on it. Panics if the offset is invalid.
    fn insert_sibling(
        &mut self, offset: isize, sibling: <Self as Editor>::Tree);

    /// Removes the focus node and returns the subtree rooted at it. Focus
    /// changes to (in order of preference) the focus's left sibling, its right
    /// sibling (if there is no left sibling), or its parent (if there are no
    /// siblings).
    fn remove(&mut self) -> <Self as Editor>::Tree;

    /// Removes the child at the given index and returns the subtree rooted at
    /// it.
    fn remove_child(&mut self, index: usize) -> <Self as Editor>::Tree;

    /// Removes the sibling at the given offset and returns the subtree rooted
    /// at it.
    fn remove_sibling(&mut self, offset: isize) -> <Self as Editor>::Tree;

    /// Swaps the focus node and `other`.
    fn swap(&mut self, other: &mut <Self as Editor>::Tree);

    /// Swaps the children at the given indices. If the indices are equal, this
    /// is a no-op. If either index corresponds to the focus, focus follows it
    /// after the swap.
    fn swap_children(&mut self, index_a: usize, index_b: usize);

    /// Swaps the sibling nodes at the given offsets. If the offsets are equal,
    /// this is a no-op. If either offset is 0 (corresponding to the focus),
    /// focus follows it after the swap.
    fn swap_siblings(&mut self, offset_a: isize, offset_b: isize);
}

// impl<'a, T: Debug + 'a, G: Guard<'a, T>> Debug for Nav<'a, Data=T, DataGuard=G> {
//     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
//         enum Walk<T> { Down(T), Up, };
//         let mut stack = Vec::new();
//         try![write!(f, "({:?}", self.data().deref())];
//         stack.push(Walk::Up);
//         for c in self.children.iter().rev() {
//             stack.push(Walk::Down(c));
//         }
//         loop {
//             match stack.pop() {
//                 None => return Ok(()),
//                 Some(Walk::Up) => try![write!(f, ")")],
//                 Some(Walk::Down(t)) => {
//                     try![write!(f, " ({:?}", *t.data().deref())];
//                     stack.push(Walk::Up);
//                     for c in t.children.iter().rev() {
//                         stack.push(Walk::Down(c));
//                     }
//                 },
//             }
//         }
//     }
// }

// #[cfg(test)]
// mod test {
//     use ::Tree;

//     #[test]
//     fn test_leaf() {
//         assert![Tree::leaf("hi") == tree!["hi"]];
//         assert![Tree { data: "hi", children: Vec::new(), } == tree!["hi"]];
//         let leaf = tree!["hi"];
//         assert![leaf.data() == &"hi"];
//         assert![leaf.children().len() == 0];
//     }

//     #[test]
//     fn test_nested_01() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree::leaf("a"),
//                                               Tree::leaf("b")] };
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_02() {
//         let mut reference = Tree::leaf("hi");
//         reference.push_child(Tree::leaf("a"));
//         reference.push_child(Tree::leaf("b"));
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_03() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree { data: "a",
//                                                      children: vec![Tree::leaf("b"),
//                                                                     Tree::leaf("c")] },
//                                               Tree { data: "d",
//                                                      children: vec![Tree {
//                                                          data: "e",
//                                                          children: vec![Tree::leaf("f"), Tree::leaf("g")]
//                                                      }],
//                                               }],
//         };
//         assert![reference == tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]];
//     }

//     #[test]
//     fn test_debug_format() {
//         assert![format!("{:?}", tree!["a"]) == "(\"a\")"];
//         assert![format!("{:?}", tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]) == "(\"hi\" (\"a\" (\"b\") (\"c\")) (\"d\" (\"e\" (\"f\") (\"g\"))))"];
//         assert![format!("{:?}", tree!["a", ["b"], ["c"], ["d"], ["e"]]) == "(\"a\" (\"b\") (\"c\") (\"d\") (\"e\"))"];
//     }

//     #[test]
//     fn test_recursive_mutating_bfs() {
//         fn mutable_bfs(t: &mut Tree<&str>) {
//             if t.children.len() == 0 {
//                 t.data = "leaf";
//             } else {
//                 for child in &mut t.children {
//                     mutable_bfs(child);
//                 }
//             }
//         }

//         let mut t = tree!["a", ["b", ["c"], ["d"], ["e"]], ["f"]];
//         mutable_bfs(&mut t);
//         assert_eq![format!["{:?}", t],
//                    "(\"a\" (\"b\" (\"leaf\") (\"leaf\") (\"leaf\")) (\"leaf\"))"];
//     }
// }
<commit_msg>Minor documentation fix.<commit_after>//! Tree structure implementations and common traits for manipulating them.

// Basic use cases:
//  - Fixed tree (built once). Handled by Zipper, Tree, Nav.
//  - Fixed-topology tree (data mutates). Handled by Zipper, Tree, Nav.
//  - Shared-data tree (topology fixed). Handled by Zipper, Tree, Nav with
//    RefCell<T> or Mutex<T> for data.
//  - Shared-topology tree (data fixed).
//  - Shared-data, shared-topology tree.

// For std::rc::try_unwrap.
#![feature(rc_unique)]

/// Fixed-layout trees with good memory locality guarantees.
pub mod fixed;
/// Single-ownership trees wherein a parent owns its children.
pub mod owned;
/// Heap-allocated, reference-counted trees that can be shared freely.
pub mod shared;
/// Tree traversal methods and interfaces.
pub mod traversal;
/// Internal utilities.
mod util;

/// Navigable, focus-based view of a tree.
///
/// This trait defines a view of a tree that is focused on a node and can be
/// navigated to that node's parent, a sibling, or a child.
///
/// If you have worked with
/// [zippers](http://en.wikipedia.org/wiki/Zipper_(data_structure)), this should
/// seem familiar.
///
/// For access to data at tree nodes, implementing types should also implement
/// `std::borrow::Borrow` or `std::borrow::BorrowMut`.
///
/// This trait does not expose methods for mutating the tree, but this does not
/// guarantee immutability or thread safety. Implementing types may permit
/// mutation of tree data (whether by implementing `std::borrow::BorrowMut`,
/// implementing `std::borrow::Borrow` and having `RefCell` data, or otherwise),
/// which may in turn cause arbitrary modifications in the underlying
/// representation of the tree structure (such as reallocations). The `Editor`
/// trait, which extends this one, has explicit methods for modification of tree
/// topology.
///
/// This trait is usually implemented for borrows of some underlying tree
/// structure.
///
/// To make it convenient to navigate through a tree and retain pointers along
/// the way, it is recommended that implementors also provide an implementation
/// of `std::clone::Clone` when this is possible. For mutable types that also
/// implement `std::borrow::BorrowMut`, which may require a read-write borrow of
/// an underlying structure, this may not be possible.
pub trait Nav {
    /// Returns the number of children of the current node.
    fn child_count(&self) -> usize;

    /// Returns `true` iff the current node is a leaf (i.e., it has no
    /// children).
    fn at_leaf(&self) -> bool {
        self.child_count() == 0
    }

    /// Returns `true` iff the current node is the tree root (i.e., it has no
    /// parent).
    fn at_root(&self) -> bool;

    /// Navigates to the sibling at `offset`, for which negative values indicate
    /// navigating to the left of this node's location and positive value to the
    /// right. (An offset of 0 is a no-op.) Panics if this is the tree root or
    /// `offset` resolves to a nonexistant sibling.
    fn seek_sibling(&mut self, offset: isize);

    /// Navigates to the child at at the given index. Panics if there are no
    /// children to navigate to or `index` resolves to a nonexistant child.
    fn seek_child(&mut self, index: usize);

    /// Navigates to this node's parent. Panics if this is the root.
    fn to_parent(&mut self);

    /// Navigates to the tree's root. If this navigator is already pointing at
    /// the tree root, this is a no-op.
    ///
    /// The default implementation of this method repeatedly calls
    /// `to_parent`. Implementors may wish to provide a more efficient method.
    fn to_root(&mut self) {
        while ! self.at_root() {
            self.to_parent();
        }
    }
}

/// Navigable view of a tree, with support for modifying the tree's topology.
///
/// This trait extends [Nav](trait.Nav.html) with support for tree modification
/// operations.
pub trait Editor: Nav {
    /// The type of tree node data, usually the `T` of some `Tree<T>`.
    type Data;

    /// The tree type that is associated with operations that insert or remove
    /// subtrees. This is typically the implementing tree type that the `Editor`
    /// provides a view of.
    type Tree;

    /// Creates a new leaf with the given data at the logical end of the
    /// children of the current focus and focuses on it.
    fn push_leaf(&mut self, data: <Self as Editor>::Data);

    /// Adds `child` to the logical end of the children of the current focus and
    /// focuses on it.
    fn push_child(&mut self, child: <Self as Editor>::Tree);

    /// Inserts a new leaf with the given data at the given position in the
    /// current focus's children and focuses on it.
    fn insert_leaf(&mut self, index: usize, data: <Self as Editor>::Data);

    /// Inserts `child` at the given position in the current focus's children
    /// and focuses on it.
    fn insert_child(
        &mut self, index: usize, child: <Self as Editor>::Tree);

    /// Inserts a new leaf with the given data at the position an offset by the
    /// given amount from the current focus and focuses on it. Panics if the
    /// offset is invalid.
    fn insert_sibling_leaf(
        &mut self, offset: isize, data: <Self as Editor>::Data);

    /// Inserts `sibling` at the given offset relative to the current focus and
    /// focuses on it. Panics if the offset is invalid.
    fn insert_sibling(
        &mut self, offset: isize, sibling: <Self as Editor>::Tree);

    /// Removes the focus node and returns the subtree rooted at it. Focus
    /// changes to (in order of preference) the focus's left sibling, its right
    /// sibling (if there is no left sibling), or its parent (if there are no
    /// siblings).
    fn remove(&mut self) -> <Self as Editor>::Tree;

    /// Removes the child at the given index and returns the subtree rooted at
    /// it.
    fn remove_child(&mut self, index: usize) -> <Self as Editor>::Tree;

    /// Removes the sibling at the given offset and returns the subtree rooted
    /// at it.
    fn remove_sibling(&mut self, offset: isize) -> <Self as Editor>::Tree;

    /// Swaps the focus node and `other`.
    fn swap(&mut self, other: &mut <Self as Editor>::Tree);

    /// Swaps the children at the given indices. If the indices are equal, this
    /// is a no-op. If either index corresponds to the focus, focus follows it
    /// after the swap.
    fn swap_children(&mut self, index_a: usize, index_b: usize);

    /// Swaps the sibling nodes at the given offsets. If the offsets are equal,
    /// this is a no-op. If either offset is 0 (corresponding to the focus),
    /// focus follows it after the swap.
    fn swap_siblings(&mut self, offset_a: isize, offset_b: isize);
}

// impl<'a, T: Debug + 'a, G: Guard<'a, T>> Debug for Nav<'a, Data=T, DataGuard=G> {
//     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
//         enum Walk<T> { Down(T), Up, };
//         let mut stack = Vec::new();
//         try![write!(f, "({:?}", self.data().deref())];
//         stack.push(Walk::Up);
//         for c in self.children.iter().rev() {
//             stack.push(Walk::Down(c));
//         }
//         loop {
//             match stack.pop() {
//                 None => return Ok(()),
//                 Some(Walk::Up) => try![write!(f, ")")],
//                 Some(Walk::Down(t)) => {
//                     try![write!(f, " ({:?}", *t.data().deref())];
//                     stack.push(Walk::Up);
//                     for c in t.children.iter().rev() {
//                         stack.push(Walk::Down(c));
//                     }
//                 },
//             }
//         }
//     }
// }

// #[cfg(test)]
// mod test {
//     use ::Tree;

//     #[test]
//     fn test_leaf() {
//         assert![Tree::leaf("hi") == tree!["hi"]];
//         assert![Tree { data: "hi", children: Vec::new(), } == tree!["hi"]];
//         let leaf = tree!["hi"];
//         assert![leaf.data() == &"hi"];
//         assert![leaf.children().len() == 0];
//     }

//     #[test]
//     fn test_nested_01() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree::leaf("a"),
//                                               Tree::leaf("b")] };
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_02() {
//         let mut reference = Tree::leaf("hi");
//         reference.push_child(Tree::leaf("a"));
//         reference.push_child(Tree::leaf("b"));
//         assert![reference == tree!["hi", ["a"], ["b"]]];
//     }

//     #[test]
//     fn test_nested_03() {
//         let reference = Tree { data: "hi",
//                                children: vec![Tree { data: "a",
//                                                      children: vec![Tree::leaf("b"),
//                                                                     Tree::leaf("c")] },
//                                               Tree { data: "d",
//                                                      children: vec![Tree {
//                                                          data: "e",
//                                                          children: vec![Tree::leaf("f"), Tree::leaf("g")]
//                                                      }],
//                                               }],
//         };
//         assert![reference == tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]];
//     }

//     #[test]
//     fn test_debug_format() {
//         assert![format!("{:?}", tree!["a"]) == "(\"a\")"];
//         assert![format!("{:?}", tree!["hi", ["a", ["b"], ["c"]], ["d", ["e", ["f"], ["g"]]]]) == "(\"hi\" (\"a\" (\"b\") (\"c\")) (\"d\" (\"e\" (\"f\") (\"g\"))))"];
//         assert![format!("{:?}", tree!["a", ["b"], ["c"], ["d"], ["e"]]) == "(\"a\" (\"b\") (\"c\") (\"d\") (\"e\"))"];
//     }

//     #[test]
//     fn test_recursive_mutating_bfs() {
//         fn mutable_bfs(t: &mut Tree<&str>) {
//             if t.children.len() == 0 {
//                 t.data = "leaf";
//             } else {
//                 for child in &mut t.children {
//                     mutable_bfs(child);
//                 }
//             }
//         }

//         let mut t = tree!["a", ["b", ["c"], ["d"], ["e"]], ["f"]];
//         mutable_bfs(&mut t);
//         assert_eq![format!["{:?}", t],
//                    "(\"a\" (\"b\" (\"leaf\") (\"leaf\") (\"leaf\")) (\"leaf\"))"];
//     }
// }
<|endoftext|>


<commit_before>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::result;

use byteorder::{LittleEndian, ReadBytesExt};

// MARK: Error types

/// Represents an error that occurred while reading a wave file.
#[derive(Debug)]
pub enum ReadError {
    /// The file format is incorrect or unsupported.
    Format(FormatErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type ReadResult<T> = result::Result<T, ReadError>;

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            ReadError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when the wave file is incorrect or unsupported.
#[derive(Debug)]
pub enum FormatErrorKind {
    /// The file does not start with a "RIFF" tag and chunk size.
    NotARiffFile,
    /// The file doesn't continue with "WAVE" after the RIFF chunk header.
    NotAWaveFile,
    /// This file is not an uncompressed PCM wave file. Only uncompressed files are supported.
    NotAnUncompressedPcmWaveFile(u16),
    /// This file is missing header data and can't be parsed.
    FmtChunkTooShort,
}

impl FormatErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            FormatErrorKind::NotARiffFile => "not a RIFF file",
            FormatErrorKind::NotAWaveFile => "not a WAVE file",
            FormatErrorKind::NotAnUncompressedPcmWaveFile(_) => "Not an uncompressed wave file",
            FormatErrorKind::FmtChunkTooShort => "fmt_ chunk is too short",
        }
    }
}

impl fmt::Display for FormatErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for ReadError {
    fn description(&self) -> &str {
        match *self {
            ReadError::Format(ref kind) => kind.to_string(),
            ReadError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ReadError::Format(_) => None,
            ReadError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError {
        ReadError::Io(err)
    }
}

// MARK: Validation and parsing functions

const FORMAT_UNCOMPRESSED_PCM: u16 = 1;
const FORMAT_EXTENDED: u16 = 65534;

#[derive(Debug)]
enum Format {
    UncompressedPcm,
    Extended,
}

fn validate_pcm_format(format: u16) -> ReadResult<Format> {
    match format {
        FORMAT_UNCOMPRESSED_PCM => Ok(Format::UncompressedPcm),
        FORMAT_EXTENDED => Ok(Format::Extended),
        _ => Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(format))),
    }
}

fn validate_pcm_subformat(sub_format: u16) -> ReadResult<()> {
    match sub_format {
        FORMAT_UNCOMPRESSED_PCM => Ok(()),
        _ => Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(sub_format))),
    }
}

fn validate_fmt_header_is_large_enough(size: u32, min_size: u32) -> ReadResult<()> {
    if size < min_size {
        Err(ReadError::Format(FormatErrorKind::FmtChunkTooShort))
    } else {
        Ok(())
    }
}

trait WaveReader: Read + Seek {
    fn validate_is_riff_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"RIFF", FormatErrorKind::NotARiffFile));
        // The next four bytes represent the chunk size. We're not going to
        // validate it, so that we can still try to read files that might have
        // an incorrect chunk size, so let's skip over it.
        let _ = try!(self.read_chunk_size());
        Ok(())
    }

    fn validate_is_wave_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"WAVE", FormatErrorKind::NotAWaveFile));
        Ok(())
    }

    fn validate_tag(&mut self,
                    expected_tag: &[u8; 4],
                    err_kind: FormatErrorKind)
                    -> ReadResult<()> {
        let tag = try!(self.read_tag());
        if &tag != expected_tag {
            return Err(ReadError::Format(err_kind));
        }
        Ok(())
    }

    fn skip_until_subchunk(&mut self, matching_tag: &[u8; 4]) -> ReadResult<u32> {
        loop {
            let tag = try!(self.read_tag());
            let subchunk_size = try!(self.read_chunk_size());

            if &tag == matching_tag {
                return Ok(subchunk_size);
            } else {
                try!(self.seek(SeekFrom::Current(subchunk_size.into())));
            }
        }
    }

    fn read_tag(&mut self) -> ReadResult<[u8; 4]> {
        let mut tag: [u8; 4] = [0; 4];
        try!(self.read_exact(&mut tag));
        Ok(tag)
    }

    fn read_chunk_size(&mut self) -> ReadResult<u32> {
        Ok(try!(self.read_u32::<LittleEndian>()))
    }
}

impl<T> WaveReader for T where T: Read + Seek {}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use {FORMAT_UNCOMPRESSED_PCM, FORMAT_EXTENDED};
    use {Format, FormatErrorKind, ReadError, WaveReader};
    use {validate_fmt_header_is_large_enough, validate_pcm_format, validate_pcm_subformat};

    // This is a helper macro that helps us validate results in our tests.
    // Thank you bluss and durka42!
    macro_rules! assert_matches {
        ($expected:pat $(if $guard:expr)*, $value:expr) => {
            match $value {
                $expected $(if $guard)* => {},
                ref actual => {
                    panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                        stringify!($expected), actual);
                },
            }
        };
    }

    // RIFF header tests

    #[test]
    fn test_validate_is_riff_file_ok() {
        let mut data = Cursor::new(b"RIFF    ");
        assert_matches!(Ok(()), data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_incomplete() {
        let mut data = Cursor::new(b"RIF     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    // Wave tag tests

    #[test]
    fn test_validate_is_wave_file_ok() {
        let mut data = Cursor::new(b"WAVE");
        assert_matches!(Ok(()), data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_incomplete() {
        let mut data = Cursor::new(b"WAV ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    // Skipping to subchunk tests
    // After reading in the file header, we also need to read in the "fmt " subchunk.
    // The file might contain other subchunks that we don't currently support, so
    // we'll need to skip over them.

    #[test]
    fn test_skip_until_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let size = data.skip_until_subchunk(b"fmt ");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    fn test_skip_until_second_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00data\x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    #[should_panic]
    fn test_cant_read_first_subchunk_after_second() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEdata\x00\x00\x00\x00fmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    // Wave format validation tests. We only support uncompressed PCM files,
    // which can be in the "canonical" format or an "extended" format.

    #[test]
    fn test_validate_pcm_format_ok_uncompressed() {
        assert_matches!(Ok(Format::UncompressedPcm),
                        validate_pcm_format(FORMAT_UNCOMPRESSED_PCM));
    }

    #[test]
    fn test_validate_pcm_format_ok_extended() {
        assert_matches!(Ok(Format::Extended), validate_pcm_format(FORMAT_EXTENDED));
    }

    #[test]
    fn test_validate_pcm_format_err_not_uncompressed() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
        				validate_pcm_format(12345));
    }

    // Wave subformat validation tests. We only support uncompressed PCM files.

    #[test]
    fn test_validate_pcm_subformat_ok_uncompressed() {
        assert_matches!(Ok(()), validate_pcm_subformat(FORMAT_UNCOMPRESSED_PCM));
    }

    #[test]
    fn test_validate_pcm_subformat_err_extended_format_value_not_valid_for_subformat() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
            			validate_pcm_subformat(FORMAT_EXTENDED));
    }

    #[test]
    fn test_validate_pcm_subformat_err_not_uncompressed() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
						validate_pcm_subformat(12345));
    }

    // Validation tests for ensuring the header is large enough to read in the data we need.

    #[test]
    fn test_validate_fmt_header_is_large_enough_matches() {
        assert_matches!(Ok(()), validate_fmt_header_is_large_enough(16, 16));
    }

    #[test]
    fn test_validate_fmt_header_is_large_enough_more_than_we_need() {
        assert_matches!(Ok(()), validate_fmt_header_is_large_enough(22, 16));
    }

    #[test]
    fn test_validate_fmt_header_is_large_enough_too_small() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::FmtChunkTooShort)),
                        validate_fmt_header_is_large_enough(14, 16));
    }
}
<commit_msg>Add code to read the PCM format and validate the fmt_ chunk size and format.<commit_after>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::result;

use byteorder::{LittleEndian, ReadBytesExt};

// MARK: Error types

/// Represents an error that occurred while reading a wave file.
#[derive(Debug)]
pub enum ReadError {
    /// The file format is incorrect or unsupported.
    Format(FormatErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type ReadResult<T> = result::Result<T, ReadError>;

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            ReadError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when the wave file is incorrect or unsupported.
#[derive(Debug)]
pub enum FormatErrorKind {
    /// The file does not start with a "RIFF" tag and chunk size.
    NotARiffFile,
    /// The file doesn't continue with "WAVE" after the RIFF chunk header.
    NotAWaveFile,
    /// This file is not an uncompressed PCM wave file. Only uncompressed files are supported.
    NotAnUncompressedPcmWaveFile(u16),
    /// This file is missing header data and can't be parsed.
    FmtChunkTooShort,
}

impl FormatErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            FormatErrorKind::NotARiffFile => "not a RIFF file",
            FormatErrorKind::NotAWaveFile => "not a WAVE file",
            FormatErrorKind::NotAnUncompressedPcmWaveFile(_) => "Not an uncompressed wave file",
            FormatErrorKind::FmtChunkTooShort => "fmt_ chunk is too short",
        }
    }
}

impl fmt::Display for FormatErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for ReadError {
    fn description(&self) -> &str {
        match *self {
            ReadError::Format(ref kind) => kind.to_string(),
            ReadError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ReadError::Format(_) => None,
            ReadError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError {
        ReadError::Io(err)
    }
}

// MARK: Validation and parsing functions

const FORMAT_UNCOMPRESSED_PCM: u16 = 1;
const FORMAT_EXTENDED: u16 = 65534;

#[derive(Debug)]
enum Format {
    UncompressedPcm,
    Extended,
}

#[derive(Debug)]
struct PcmFormat {
    num_channels: u16,
    sample_rate: u32,
    bits_per_sample: u16,
}

fn validate_pcm_format(format: u16) -> ReadResult<Format> {
    match format {
        FORMAT_UNCOMPRESSED_PCM => Ok(Format::UncompressedPcm),
        FORMAT_EXTENDED => Ok(Format::Extended),
        _ => Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(format))),
    }
}

fn validate_pcm_subformat(sub_format: u16) -> ReadResult<()> {
    match sub_format {
        FORMAT_UNCOMPRESSED_PCM => Ok(()),
        _ => Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(sub_format))),
    }
}

fn validate_fmt_header_is_large_enough(size: u32, min_size: u32) -> ReadResult<()> {
    if size < min_size {
        Err(ReadError::Format(FormatErrorKind::FmtChunkTooShort))
    } else {
        Ok(())
    }
}

trait WaveReader: Read + Seek {
    fn read_wave_header(&mut self) -> ReadResult<PcmFormat> {
        // Validate the beginning of the file
        try!(self.validate_is_riff_file());
        try!(self.validate_is_wave_file());

        // Scan for the "fmt " chunk, and validate the format. Check the header
        // size before and after the format check so we can present the
        // appropriate error types.
        let fmt_subchunk_size = try!(self.skip_until_subchunk(b"fmt "));
        // We need at least 14 bytes for wave files.
        try!(validate_fmt_header_is_large_enough(fmt_subchunk_size, 14));
        let format = try!(validate_pcm_format(try!(self.read_u16::<LittleEndian>())));
        // Now that we've validated the PCM format so that we know this is an
        // uncompressed PCM file, we also need to be able to read the bits per sample.
        try!(validate_fmt_header_is_large_enough(fmt_subchunk_size, 16));

        // Bogus until we complete our validation checks
        Err(ReadError::Format(FormatErrorKind::NotARiffFile))
    }

    fn validate_is_riff_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"RIFF", FormatErrorKind::NotARiffFile));
        // The next four bytes represent the chunk size. We're not going to
        // validate it, so that we can still try to read files that might have
        // an incorrect chunk size, so let's skip over it.
        let _ = try!(self.read_chunk_size());
        Ok(())
    }

    fn validate_is_wave_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"WAVE", FormatErrorKind::NotAWaveFile));
        Ok(())
    }

    fn validate_tag(&mut self,
                    expected_tag: &[u8; 4],
                    err_kind: FormatErrorKind)
                    -> ReadResult<()> {
        let tag = try!(self.read_tag());
        if &tag != expected_tag {
            return Err(ReadError::Format(err_kind));
        }
        Ok(())
    }

    fn skip_until_subchunk(&mut self, matching_tag: &[u8; 4]) -> ReadResult<u32> {
        loop {
            let tag = try!(self.read_tag());
            let subchunk_size = try!(self.read_chunk_size());

            if &tag == matching_tag {
                return Ok(subchunk_size);
            } else {
                try!(self.seek(SeekFrom::Current(subchunk_size.into())));
            }
        }
    }

    fn read_tag(&mut self) -> ReadResult<[u8; 4]> {
        let mut tag: [u8; 4] = [0; 4];
        try!(self.read_exact(&mut tag));
        Ok(tag)
    }

    fn read_chunk_size(&mut self) -> ReadResult<u32> {
        Ok(try!(self.read_u32::<LittleEndian>()))
    }
}

impl<T> WaveReader for T where T: Read + Seek {}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::Cursor;

    use {FORMAT_UNCOMPRESSED_PCM, FORMAT_EXTENDED};
    use {Format, FormatErrorKind, ReadError, WaveReader};
    use {validate_fmt_header_is_large_enough, validate_pcm_format, validate_pcm_subformat};

    // This is a helper macro that helps us validate results in our tests.
    // Thank you bluss and durka42!
    macro_rules! assert_matches {
        ($expected:pat $(if $guard:expr)*, $value:expr) => {
            match $value {
                $expected $(if $guard)* => {},
                ref actual => {
                    panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                        stringify!($expected), actual);
                },
            }
        };
    }

    // RIFF header tests

    #[test]
    fn test_validate_is_riff_file_ok() {
        let mut data = Cursor::new(b"RIFF    ");
        assert_matches!(Ok(()), data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_incomplete() {
        let mut data = Cursor::new(b"RIF     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    // Wave tag tests

    #[test]
    fn test_validate_is_wave_file_ok() {
        let mut data = Cursor::new(b"WAVE");
        assert_matches!(Ok(()), data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_incomplete() {
        let mut data = Cursor::new(b"WAV ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    // Skipping to subchunk tests
    // After reading in the file header, we also need to read in the "fmt " subchunk.
    // The file might contain other subchunks that we don't currently support, so
    // we'll need to skip over them.

    #[test]
    fn test_skip_until_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let size = data.skip_until_subchunk(b"fmt ");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    fn test_skip_until_second_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00data\x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    #[should_panic]
    fn test_cant_read_first_subchunk_after_second() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEdata\x00\x00\x00\x00fmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    // Wave format validation tests. We only support uncompressed PCM files,
    // which can be in the "canonical" format or an "extended" format.

    #[test]
    fn test_validate_pcm_format_ok_uncompressed() {
        assert_matches!(Ok(Format::UncompressedPcm),
                        validate_pcm_format(FORMAT_UNCOMPRESSED_PCM));
    }

    #[test]
    fn test_validate_pcm_format_ok_extended() {
        assert_matches!(Ok(Format::Extended), validate_pcm_format(FORMAT_EXTENDED));
    }

    #[test]
    fn test_validate_pcm_format_err_not_uncompressed() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
        				validate_pcm_format(12345));
    }

    // Wave subformat validation tests. We only support uncompressed PCM files.

    #[test]
    fn test_validate_pcm_subformat_ok_uncompressed() {
        assert_matches!(Ok(()), validate_pcm_subformat(FORMAT_UNCOMPRESSED_PCM));
    }

    #[test]
    fn test_validate_pcm_subformat_err_extended_format_value_not_valid_for_subformat() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
            			validate_pcm_subformat(FORMAT_EXTENDED));
    }

    #[test]
    fn test_validate_pcm_subformat_err_not_uncompressed() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
						validate_pcm_subformat(12345));
    }

    // Validation tests for ensuring the header is large enough to read in the data we need.

    #[test]
    fn test_validate_fmt_header_is_large_enough_matches() {
        assert_matches!(Ok(()), validate_fmt_header_is_large_enough(16, 16));
    }

    #[test]
    fn test_validate_fmt_header_is_large_enough_more_than_we_need() {
        assert_matches!(Ok(()), validate_fmt_header_is_large_enough(22, 16));
    }

    #[test]
    fn test_validate_fmt_header_is_large_enough_too_small() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::FmtChunkTooShort)),
                        validate_fmt_header_is_large_enough(14, 16));
    }

    // Wave header validation tests.

    #[test]
    fn test_validate_pcm_header_missing_fmt_chunk() {
        let mut data = Cursor::new(b"RIFF    WAVE");
        assert_matches!(Err(ReadError::Io(ref err)) if err.kind() == io::ErrorKind::UnexpectedEof,
            			data.read_wave_header());
    }

    #[test]
    fn test_validate_pcm_header_fmt_chunk_too_small() {
        let mut data = Cursor::new(b"RIFF    WAVE\
                                     fmt \x0C\x00\x00\x00");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::FmtChunkTooShort)),
                        data.read_wave_header());
    }

    #[test]
    fn test_validate_pcm_header_fmt_chunk_too_small_pcm() {
        let mut data = Cursor::new(b"RIFF    WAVE\
                                     fmt \x0E\x00\x00\x00\
                                     \x01\x00");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::FmtChunkTooShort)),
                        data.read_wave_header());
    }

    #[test]
    fn test_validate_pcm_header_not_pcm_format() {
        let mut data = Cursor::new(b"RIFF    WAVE\
                                     fmt \x0E\x00\x00\x00\
                                     \x02\x00");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
            			data.read_wave_header());

    }
}
<|endoftext|>


<commit_before>extern crate graphics;

use graphics::{ Context, Graphics };

pub struct Timeline {
    pub frames: u32,
    pub current_frame: u32,
    pub bounds: [u32; 4],
}

impl Timeline {
    pub fn new_frames_bounds(frames: u32, bounds: [u32; 4]) -> Timeline {
        Timeline {
            frames: frames,
            current_frame: 0,
            bounds: bounds,
        }
    }

    pub fn draw_timeline<G: Graphics>(&self, c: &Context, g: &mut G) {
        let left_to_frame: f64 = 20.0;
        let right_to_frame: f64 = 20.0;
        let top_to_frame: f64 = 15.0;
        let frame_width: f64 = 10.0;
        let frame_height: f64 = 10.0;
        let frame_offset_x: f64 = 5.0;
        let slide_offset: f64 = 0.0;
        let left_to_goto_beginning: f64 = 15.0;
        let right_to_goto_end: f64 = 15.0;
        let width_for_frames = self.bounds[2] as f64
            - left_to_frame - right_to_frame;
        let max_visible_frames: u32 =
            if width_for_frames < frame_width {
                0
            } else {
                1
                + (
                    (width_for_frames - frame_width)
                    / (frame_width + frame_offset_x)
                ) as u32
            };

        // Draw bounds to see where the control is.
        {
            use graphics::Rectangle;

            let bounds = [
                    self.bounds[0] as f64,
                    self.bounds[1] as f64,
                    self.bounds[2] as f64,
                    self.bounds[3] as f64
                ];
            Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5)
                .draw(bounds, &c.draw_state, c.transform, g);
        }

        // Draw a sequence of squares for each frame.
        {
            use graphics::Rectangle;

            let rect = Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5);
            for i in 0..self.frames {
                let bounds = [
                    self.bounds[0] as f64 + left_to_frame
                        + i as f64 * (frame_width + frame_offset_x)
                        - slide_offset,
                    self.bounds[1] as f64 + top_to_frame,
                    frame_width,
                    frame_height
                ];
                rect.draw(bounds, &c.draw_state, c.transform, g);
            }
        }

        // Draw navigate to beginning button.
        {
            fn draw_triangle<G: Graphics>(
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                use graphics::math::*;

                let triangle = [
                    [0.0, 0.0],
                    [1.0, 0.5],
                    [0.0, 1.0]
                ];
                let transform_triangle = multiply(
                    translate(offset),
                    scale(scale_up[0], scale_up[1])
                );
                let p = [
                    transform_pos(transform_triangle, triangle[0]),
                    transform_pos(transform_triangle, triangle[1]),
                    transform_pos(transform_triangle, triangle[2])
                ];
                for i in 0..3 {
                    let j = (i + 1) % 3;
                    line.draw([p[i][0], p[i][1], p[j][0], p[j][1]], &c.draw_state, c.transform, g);
                }
            }

            fn draw_double_arrow<G: Graphics>(
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                draw_triangle(offset, scale_up, line, c, g);
                let offset = [offset[0] + scale_up[0], offset[1]];
                draw_triangle(offset, scale_up, line, c, g);
            }

            fn draw_goto_end<G: Graphics>(
                at_end: bool,
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                if !at_end {
                    draw_triangle(offset, scale_up, line, c, g);
                }

                line.draw([
                    offset[0] + scale_up[0], offset[1],
                    offset[0] + scale_up[0], offset[1] + scale_up[1]
                ], &c.draw_state, c.transform, g);
            }

            use graphics::Line;
            use graphics::math::*;

            let line = Line::new([0.0, 0.0, 1.0, 1.0], 0.5);

            let at_beginning: bool = false;
            draw_goto_end(
                at_beginning,
                [
                    self.bounds[0] as f64 + left_to_goto_beginning,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    -frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );

            let at_end: bool = true;
            draw_goto_end(
                at_end,
                [
                    self.bounds[0] as f64 + self.bounds[2] as f64
                        - right_to_goto_end,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );
        }
    }

    pub fn draw_drag<G: Graphics>(&self, c: &Context, g: &mut G) {

    }
}
<commit_msg>Compute end frame<commit_after>extern crate graphics;

use graphics::{ Context, Graphics };

pub struct Timeline {
    pub frames: u32,
    pub current_frame: u32,
    pub start_frame: u32,
    pub bounds: [u32; 4],
}

impl Timeline {
    pub fn new_frames_bounds(frames: u32, bounds: [u32; 4]) -> Timeline {
        Timeline {
            frames: frames,
            current_frame: 0,
            start_frame: 0,
            bounds: bounds,
        }
    }

    pub fn draw_timeline<G: Graphics>(&self, c: &Context, g: &mut G) {
        use std::cmp::min;

        let left_to_frame: f64 = 20.0;
        let right_to_frame: f64 = 20.0;
        let top_to_frame: f64 = 15.0;
        let frame_width: f64 = 10.0;
        let frame_height: f64 = 10.0;
        let frame_offset_x: f64 = 5.0;
        let slide_offset: f64 = 0.0;
        let left_to_goto_beginning: f64 = 15.0;
        let right_to_goto_end: f64 = 15.0;
        let width_for_frames = self.bounds[2] as f64
            - left_to_frame - right_to_frame;
        let max_visible_frames: u32 =
            if width_for_frames < frame_width {
                0
            } else {
                1
                + (
                    (width_for_frames - frame_width)
                    / (frame_width + frame_offset_x)
                ) as u32
            };
        let end_frame = min(
            self.frames,
            self.start_frame + max_visible_frames
        );

        // Draw bounds to see where the control is.
        {
            use graphics::Rectangle;

            let bounds = [
                    self.bounds[0] as f64,
                    self.bounds[1] as f64,
                    self.bounds[2] as f64,
                    self.bounds[3] as f64
                ];
            Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5)
                .draw(bounds, &c.draw_state, c.transform, g);
        }

        // Draw a sequence of squares for each frame.
        {
            use graphics::Rectangle;

            let rect = Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5);
            for i in 0..self.frames {
                let bounds = [
                    self.bounds[0] as f64 + left_to_frame
                        + i as f64 * (frame_width + frame_offset_x)
                        - slide_offset,
                    self.bounds[1] as f64 + top_to_frame,
                    frame_width,
                    frame_height
                ];
                rect.draw(bounds, &c.draw_state, c.transform, g);
            }
        }

        // Draw navigate to beginning button.
        {
            fn draw_triangle<G: Graphics>(
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                use graphics::math::*;

                let triangle = [
                    [0.0, 0.0],
                    [1.0, 0.5],
                    [0.0, 1.0]
                ];
                let transform_triangle = multiply(
                    translate(offset),
                    scale(scale_up[0], scale_up[1])
                );
                let p = [
                    transform_pos(transform_triangle, triangle[0]),
                    transform_pos(transform_triangle, triangle[1]),
                    transform_pos(transform_triangle, triangle[2])
                ];
                for i in 0..3 {
                    let j = (i + 1) % 3;
                    line.draw([p[i][0], p[i][1], p[j][0], p[j][1]], &c.draw_state, c.transform, g);
                }
            }

            fn draw_double_arrow<G: Graphics>(
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                draw_triangle(offset, scale_up, line, c, g);
                let offset = [offset[0] + scale_up[0], offset[1]];
                draw_triangle(offset, scale_up, line, c, g);
            }

            fn draw_goto_end<G: Graphics>(
                at_end: bool,
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                if !at_end {
                    draw_triangle(offset, scale_up, line, c, g);
                }

                line.draw([
                    offset[0] + scale_up[0], offset[1],
                    offset[0] + scale_up[0], offset[1] + scale_up[1]
                ], &c.draw_state, c.transform, g);
            }

            use graphics::Line;
            use graphics::math::*;

            let line = Line::new([0.0, 0.0, 1.0, 1.0], 0.5);

            let at_beginning: bool = false;
            draw_goto_end(
                at_beginning,
                [
                    self.bounds[0] as f64 + left_to_goto_beginning,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    -frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );

            let at_end: bool = true;
            draw_goto_end(
                at_end,
                [
                    self.bounds[0] as f64 + self.bounds[2] as f64
                        - right_to_goto_end,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );
        }
    }

    pub fn draw_drag<G: Graphics>(&self, c: &Context, g: &mut G) {

    }
}
<|endoftext|>


<commit_before>//! indicatif is a library for Rust that helps you build command line
//! interfaces that report progress to users.  It comes with various
//! tools and utilities for formatting anything that indicates progress.
//!
//! # Progress Bars and Spinners
//!
//! indicatif comes with a `ProgressBar` type that support both bounded
//! progress bar uses as well as unbounded "spinner" type progress reports.
//! Progress bars are `Sync` and `Send` objects which means that they are
//! internally locked and can be passed from thread to thread.
//!
//! Additionally a `MultiProgress` utility is provided that can manage
//! rendering multiple progress bars at once (eg: for instance from
//! multiple threads).
//!
//! Progress bars are manually advanced and by default draw to stdout.
//! When you are done the progress bar can be finished either visibly
//! (eg: the progress bar stays on the screen) or cleared (the progress
//! bar will be removed).
//!
//! ```rust
//! use indicatif::ProgressBar;
//!
//! let bar = ProgressBar::new(1000);
//! for _ in 0..1000 {
//!     bar.inc();
//!     // ...
//! }
//! bar.finish();
//! ```
//!
//! # Templates
//!
//! Progress bars can be styled with simple format strings similar to the
//! ones in Rust itself.  The format for a placeholder is `{key:options}`
//! where the `options` part is optional.  If provided the format is this:
//!
//! ```
//! [<^>]           for an optional alignment specification
//! WIDTH           an optional width as positive integer
//! !               an optional exclamation mark to enable truncation
//! .STYLE          an optional dot separated style string
//! /STYLE          an optional dot separated alternative style string
//! ```
//!
//! For the style component see `Styled::from_dotted_str` for more
//! information.
//!
//! Some examples for templates:
//!
//! ```text
//! [{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}
//! ```
//!
//! This sets a progress bar that is 40 characters wide and has cyan
//! as primary style color and blue as alternative style color.
//! Alternative styles are currently only used for progress bars.
//!
//! The following keys exist:
//!
//! * `bar`: renders a progress bar. By default 20 characters wide.  The
//!   style string is used to color the elapsed part, the alternative
//!   style is used for the bar that is yet to render.
//! * `wide_bar`: like `bar` but always fills the remaining space.
//! * `spinner`: renders the spinner (current tick char)
//! * `msg`: renders the currently set message on the progress bar.
//! * `pos`: renders the current position of the bar as integer
//! * `len`: renders the total length of the bar as integer
//! * `bytes`: renders the current position of the bar as bytes.
//! * `total_bytes`: renders the total length of the bar as bytes.
//! * `elapsed_precise`: renders the elapsed time as `HH:MM:SS`.
//! * `elapased`: renders the elapsed time as `42s`, `1m` etc.
//! * `eta_precise`: the remaining time (like `elapsed_precise`).
//! * `eta`: the remaining time (like `elapsed`).
//!
//! The design of the progress bar can be altered with the integrated
//! template functionality.  The template can be set by changing a
//! `ProgressStyle` and attaching it to the progress bar.
//!
//! # Terminal Access
//!
//! The library provides a basic abstraction over working with terminals
//! through the `Term` object.  For instance you can use it to move
//! cursors or clear contents.
//!
//! # Colors and Styles
//!
//! `indicatif` uses `clicolors-control` to control colors.  It also
//! provides higher level wrappers for styling text and other things
//! that can be displayed with the `style` function.
//!
//! Example usage:
//!
//! ```
//! use indicatif::style;
//!
//! println!("This is {} neat", style("fo").cyan());
//! ```
//!
//! # Human Readable Formatting
//!
//! There are some formatting wrappers for showing elapsed time and
//! file sizes for human users:
//!
//! ```ignore
//! use std::time::Instant;
//! use indicatif::{HumanDuration, HumanBytes};
//!
//! let started = Instant::now();
//! println!("The file is {} large", HumanBytes(file.size));
//! println!("The script took {}", HumanDuration(started.elapsed()));
//! ```
#[cfg(unix)] extern crate libc;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate kernel32;
extern crate parking_lot;
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate unicode_width;
extern crate clicolors_control;

mod term;
mod progress;
mod utils;
mod ansistyle;
mod format;

pub use progress::{ProgressBar, MultiProgress, ProgressState, DrawState,
                   DrawTarget, ProgressStyle};
pub use term::Term;
pub use ansistyle::{style, Styled, Color, Style,
                    strip_ansi_codes, measure_text_width,
                    colors_enabled, set_colors_enabled};
pub use format::{HumanDuration, FormattedDuration, HumanBytes};
<commit_msg>Added platform notes<commit_after>//! indicatif is a library for Rust that helps you build command line
//! interfaces that report progress to users.  It comes with various
//! tools and utilities for formatting anything that indicates progress.
//!
//! Platform support:
//!
//! * Linux
//! * OS X
//! * Windows (colors require Windows 10)
//!
//! # Progress Bars and Spinners
//!
//! indicatif comes with a `ProgressBar` type that support both bounded
//! progress bar uses as well as unbounded "spinner" type progress reports.
//! Progress bars are `Sync` and `Send` objects which means that they are
//! internally locked and can be passed from thread to thread.
//!
//! Additionally a `MultiProgress` utility is provided that can manage
//! rendering multiple progress bars at once (eg: for instance from
//! multiple threads).
//!
//! Progress bars are manually advanced and by default draw to stdout.
//! When you are done the progress bar can be finished either visibly
//! (eg: the progress bar stays on the screen) or cleared (the progress
//! bar will be removed).
//!
//! ```rust
//! use indicatif::ProgressBar;
//!
//! let bar = ProgressBar::new(1000);
//! for _ in 0..1000 {
//!     bar.inc();
//!     // ...
//! }
//! bar.finish();
//! ```
//!
//! # Templates
//!
//! Progress bars can be styled with simple format strings similar to the
//! ones in Rust itself.  The format for a placeholder is `{key:options}`
//! where the `options` part is optional.  If provided the format is this:
//!
//! ```
//! [<^>]           for an optional alignment specification
//! WIDTH           an optional width as positive integer
//! !               an optional exclamation mark to enable truncation
//! .STYLE          an optional dot separated style string
//! /STYLE          an optional dot separated alternative style string
//! ```
//!
//! For the style component see `Styled::from_dotted_str` for more
//! information.
//!
//! Some examples for templates:
//!
//! ```text
//! [{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}
//! ```
//!
//! This sets a progress bar that is 40 characters wide and has cyan
//! as primary style color and blue as alternative style color.
//! Alternative styles are currently only used for progress bars.
//!
//! The following keys exist:
//!
//! * `bar`: renders a progress bar. By default 20 characters wide.  The
//!   style string is used to color the elapsed part, the alternative
//!   style is used for the bar that is yet to render.
//! * `wide_bar`: like `bar` but always fills the remaining space.
//! * `spinner`: renders the spinner (current tick char)
//! * `msg`: renders the currently set message on the progress bar.
//! * `pos`: renders the current position of the bar as integer
//! * `len`: renders the total length of the bar as integer
//! * `bytes`: renders the current position of the bar as bytes.
//! * `total_bytes`: renders the total length of the bar as bytes.
//! * `elapsed_precise`: renders the elapsed time as `HH:MM:SS`.
//! * `elapased`: renders the elapsed time as `42s`, `1m` etc.
//! * `eta_precise`: the remaining time (like `elapsed_precise`).
//! * `eta`: the remaining time (like `elapsed`).
//!
//! The design of the progress bar can be altered with the integrated
//! template functionality.  The template can be set by changing a
//! `ProgressStyle` and attaching it to the progress bar.
//!
//! # Terminal Access
//!
//! The library provides a basic abstraction over working with terminals
//! through the `Term` object.  For instance you can use it to move
//! cursors or clear contents.
//!
//! # Colors and Styles
//!
//! `indicatif` uses `clicolors-control` to control colors.  It also
//! provides higher level wrappers for styling text and other things
//! that can be displayed with the `style` function.
//!
//! Example usage:
//!
//! ```
//! use indicatif::style;
//!
//! println!("This is {} neat", style("fo").cyan());
//! ```
//!
//! # Human Readable Formatting
//!
//! There are some formatting wrappers for showing elapsed time and
//! file sizes for human users:
//!
//! ```ignore
//! use std::time::Instant;
//! use indicatif::{HumanDuration, HumanBytes};
//!
//! let started = Instant::now();
//! println!("The file is {} large", HumanBytes(file.size));
//! println!("The script took {}", HumanDuration(started.elapsed()));
//! ```
#[cfg(unix)] extern crate libc;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate kernel32;
extern crate parking_lot;
extern crate regex;
#[macro_use] extern crate lazy_static;
extern crate unicode_width;
extern crate clicolors_control;

mod term;
mod progress;
mod utils;
mod ansistyle;
mod format;

pub use progress::{ProgressBar, MultiProgress, ProgressState, DrawState,
                   DrawTarget, ProgressStyle};
pub use term::Term;
pub use ansistyle::{style, Styled, Color, Style,
                    strip_ansi_codes, measure_text_width,
                    colors_enabled, set_colors_enabled};
pub use format::{HumanDuration, FormattedDuration, HumanBytes};
<|endoftext|>


<commit_before>// Copyright 2017 Dario Domizioli ("hhexo").
//
// 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.

//! Mecha is yet another actor model implementation written in Rust.
//!
//! There are already Rust crates implementing such model. I'll give a shout out
//! to [RobotS](https://github.com/gamazeps/RobotS) and
//! [acto-rs](https://github.com/dbeck/acto-rs), but I suspect there are others,
//! and some building blocks are there in other libraries.
//!
//! The main reason why I am writing this library is as a learning exercise, and
//! it should not be expected to be feature-complete (I wish!) or stable.
//!
//! Do not use this in production code.
//!
//! # Using mecha
//!
//! If you really want to use mecha, feel free to add a git dependency. I
//! haven't gone through the effort of uploading a crate to crates.io yet.
//!
//! `mecha = { git = "https://github.com/hhexo/mecha.git" }`
//!
//! # Actors and messages
//!
//! Here is a quick example of how to spawn an actor and send a message to it.
//!
//! ```
//! extern crate mecha;
//!
//! struct ActorImplementation;
//!
//! impl mecha::Actor for ActorImplementation {
//!     fn process_message(&mut self,
//!                        message: mecha::Message,
//!                        myself: &mecha::ActorAddress) {
//!         println!("I received a message! It was of type...");
//!         println!("    {:?}", message.get_type());
//!         println!("...with datum...");
//!         println!("    {:?}", message.get_datum());
//!     }
//! }
//!
//! let actor = mecha::spawn(ActorImplementation);
//!
//! mecha::Message::custom("MyMessage")
//!     .with_datum(mecha::MessageDatum::from("blah"))
//!     .send_to(&actor);
//!
//! // Or, more simply:
//!
//! mecha::Message::custom("MyMessage").with_str("blah").send_to(&actor);
//!
//! // Be clean and don't forget to stop the actor at the end!
//!
//! mecha::Message::stop().send_to(&actor);
//!
//! // Wait some time if you want to see the output printed by the other thread
//! use std::thread;
//! use std::time::Duration;
//! thread::sleep(Duration::from_millis(500));
//! ```
//!

use std::thread;
use std::sync::mpsc;
use std::collections::HashMap;

/// An ActorAddress structure is used, essentially, just as the identifier of an
/// actor for sending messages to it. ActorAddresses can be cheaply cloned and
/// passed around.
#[derive(Clone, Debug)]
pub struct ActorAddress {
    endpoint: mpsc::Sender<Message>
}

/// A MessageType defines a number of standard messages (such as the one to
/// stop an actor) and a Custom type which can be used to send user-defined
/// messages between actors.
///
/// Custom types contain a static str (so basically they're created from a
/// string literal) which can be matched on.
#[derive(Clone, PartialOrd, PartialEq, Ord, Eq, Debug)]
pub enum MessageType {
    /// A message of this type is automatically sent to any actor upon spawning.
    /// If an actor does not need initialization, it can safely ignore the
    /// message.
    Init,
    /// A message of this type will stop and kill the actor receiving it.
    Stop,
    /// This is a custom message type to use for user-defined messages.
    Custom(&'static str)
}

/// This variant type specifies what kind of data can be passed around in
/// messages; we believe it is better to have a well defined variant type rather
/// than something like an Any. This makes serialization well defined, and
/// the Map variant can serialize complex data structures anyway.
#[derive(Clone, Debug)]
pub enum MessageDatum {
    Void,
    I64(i64),
    U64(u64),
    F64(f64),
    Str(String),
    Map(HashMap<String, MessageDatum>),
    Act(ActorAddress)
}
impl MessageDatum {
    /// Consumes the MessageDatum and converts it to i64 if possible.
    pub fn as_i64(self) -> Option<i64> {
        match self {
            MessageDatum::I64(x) => Some(x),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to u64 if possible.
    pub fn as_u64(self) -> Option<u64> {
        match self {
            MessageDatum::U64(x) => Some(x),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to f64 if possible.
    pub fn as_f64(self) -> Option<f64> {
        match self {
            MessageDatum::F64(x) => Some(x),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to String if possible.
    pub fn as_str(self) -> Option<String> {
        match self {
            MessageDatum::Str(x) => Some(x),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to a map if possible.
    pub fn as_map(self) -> Option<HashMap<String, MessageDatum>> {
        match self {
            MessageDatum::Map(m) => Some(m),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to an ActorAddress if
    /// possible.
    pub fn as_act(self) -> Option<ActorAddress> {
        match self {
            MessageDatum::Act(a) => Some(a),
            _ => None
        }
    }
}
impl From<i64> for MessageDatum {
    fn from(x: i64) -> MessageDatum { MessageDatum::I64(x) }
}
impl From<u64> for MessageDatum {
    fn from(x: u64) -> MessageDatum { MessageDatum::U64(x) }
}
impl From<f64> for MessageDatum {
    fn from(x: f64) -> MessageDatum { MessageDatum::F64(x) }
}
impl From<String> for MessageDatum {
    fn from(x: String) -> MessageDatum { MessageDatum::Str(x) }
}
impl<'a> From<&'a str> for MessageDatum {
    fn from(x: &'a str) -> MessageDatum { MessageDatum::Str(x.to_string()) }
}
impl From<HashMap<String, MessageDatum>> for MessageDatum {
    fn from(x: HashMap<String, MessageDatum>) -> MessageDatum { MessageDatum::Map(x) }
}
impl From<ActorAddress> for MessageDatum {
    fn from(x: ActorAddress) -> MessageDatum { MessageDatum::Act(x) }
}
impl<'a> From<&'a ActorAddress> for MessageDatum {
    fn from(x: &'a ActorAddress) -> MessageDatum { MessageDatum::Act(x.clone()) }
}

/// A Message contains a type, the actor from whom the message comes, and a
/// datum. A Message can be created and sent using a builder pattern.
#[derive(Clone, Debug)]
pub struct Message {
    mt: MessageType,
    sender: ActorAddress,
    datum: MessageDatum
}

/// The builder struct for a Message.
pub struct MessageBuilder {
    mt: MessageType,
    sender: Option<ActorAddress>,
    datum: Option<MessageDatum>
}

impl Message {
    /// Gets the type of the message.
    pub fn get_type(&self) -> &MessageType { &self.mt }
    /// Gets the sender of the message.
    pub fn get_sender(&self) -> &ActorAddress { &self.sender }
    /// Gets the datum of the message.
    pub fn get_datum(&self) -> &MessageDatum { &self.datum }

    /// Initializes a message builder for an Init typed message.
    pub fn init() -> MessageBuilder {
        MessageBuilder {
            mt: MessageType::Init,
            sender: None,
            datum: None,
        }
    }

    /// Initializes a message builder for a Stop typed message.
    pub fn stop() -> MessageBuilder {
        MessageBuilder {
            mt: MessageType::Stop,
            sender: None,
            datum: None,
        }
    }

    /// Initializes a message builder for a Custom typed message.
    pub fn custom(mt: &'static str) -> MessageBuilder {
        MessageBuilder {
            mt: MessageType::Custom(mt),
            sender: None,
            datum: None,
        }
    }
}

impl MessageBuilder {
    /// Specifies the sender of the message.
    pub fn with_sender<'a>(&'a mut self, f: &ActorAddress) -> &'a mut MessageBuilder {
        self.sender = Some(f.clone());
        self
    }

    /// Specifies the datum of the message.
    pub fn with_datum<'a>(&'a mut self, d: MessageDatum) -> &'a mut MessageBuilder {
        self.datum = Some(d);
        self
    }

    /// Specifies an i64 as the datum of the message.
    pub fn with_i64<'a>(&'a mut self, i: i64) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(i))
    }

    /// Specifies an u64 as the datum of the message.
    pub fn with_u64<'a>(&'a mut self, u: u64) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(u))
    }

    /// Specifies an f64 as the datum of the message.
    pub fn with_f64<'a>(&'a mut self, f: f64) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(f))
    }

    /// Specifies a string as the datum of the message.
    pub fn with_str<'a>(&'a mut self, s: &str) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(s.to_string()))
    }

    /// Specifies a map as the datum of the message.
    pub fn with_map<'a>(&'a mut self, m: HashMap<String, MessageDatum>) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(m))
    }

    /// Specifies an actor as the datum of the message.
    pub fn with_act<'a>(&'a mut self, a: &ActorAddress) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(a))
    }

    fn build(&self) -> Message {
        let (fake_tx, _) = std::sync::mpsc::channel();
        Message {
            mt: self.mt.clone(),
            sender: self.sender.clone().unwrap_or(
                ActorAddress { endpoint: fake_tx }), // TODO: FIX. Leaks a broken channel.
            datum: match self.datum {
                None => MessageDatum::Void,
                Some(ref x) => x.clone(),
            }
        }
    }

    /// Builds the Message and sends it to the specified actor.
    ///
    /// This function is in the builder class for stylistic purposes: this
    /// way, it is possible to have nice one-liners.
    ///
    /// `Message::custom("blah").sender(&some_actor).with_i64(123).send_to(&other_actor);`
    ///
    pub fn send_to(&self, to: &ActorAddress) {
        to.endpoint.send(self.build()).unwrap_or(()); // TODO: Error handling.
    }
}

/// This trait represents the interface of any actor implementation.
///
/// Implementing this trait effectively requires to implement the functionality
/// to act upon one single message. The `mecha` library takes care of handling
/// the mailbox and the loop which receives messages.
pub trait Actor {
    /// This function is the meat of the message processing and must be
    /// implemented to implement this trait.
    fn process_message(&mut self, message: Message, myself: &ActorAddress);
}

/// Spawns an actor based on the provided Actor implementor, whose ownership is
/// acquired by the spawned thread. Returns an ActorAddress identifying the
/// spawned actor.
pub fn spawn<T: Actor + Send + 'static>(mut implementor: T) -> ActorAddress {
    let (tx, rx) = mpsc::channel::<Message>();
    let actor = ActorAddress { endpoint: tx.clone() };
    // Put an Init message on the channel immediately.
    Message::init().send_to(&actor);
    // Then spawn another thread.
    thread::spawn(move || {
        let rx_internal = rx;
        let tx_internal = tx;
        let actor_internal = ActorAddress { endpoint: tx_internal };
        loop {
            let rcvd_msg = rx_internal.recv();
            match rcvd_msg {
                Ok(msg) => {
                    let mt = msg.get_type().clone(); // for later
                    // Consume and process the message
                    implementor.process_message(msg, &actor_internal);
                    // Perform extra standard actions
                    match mt {
                        MessageType::Stop => {
                            // Stop this actor.
                            println!("Exiting upon request.");
                            break;
                        },
                        _ => ()
                    }
                },
                Err(_) => {
                    println!("Exiting upon error receiving message!");
                    break;
                }
            }
        }
    });
    actor
}

#[cfg(test)]
mod tests;
<commit_msg>Make build() public, after all MessageBuilder is a builder<commit_after>// Copyright 2017 Dario Domizioli ("hhexo").
//
// 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.

//! Mecha is yet another actor model implementation written in Rust.
//!
//! There are already Rust crates implementing such model. I'll give a shout out
//! to [RobotS](https://github.com/gamazeps/RobotS) and
//! [acto-rs](https://github.com/dbeck/acto-rs), but I suspect there are others,
//! and some building blocks are there in other libraries.
//!
//! The main reason why I am writing this library is as a learning exercise, and
//! it should not be expected to be feature-complete (I wish!) or stable.
//!
//! Do not use this in production code.
//!
//! # Using mecha
//!
//! If you really want to use mecha, feel free to add a git dependency. I
//! haven't gone through the effort of uploading a crate to crates.io yet.
//!
//! `mecha = { git = "https://github.com/hhexo/mecha.git" }`
//!
//! # Actors and messages
//!
//! Here is a quick example of how to spawn an actor and send a message to it.
//!
//! ```
//! extern crate mecha;
//!
//! struct ActorImplementation;
//!
//! impl mecha::Actor for ActorImplementation {
//!     fn process_message(&mut self,
//!                        message: mecha::Message,
//!                        myself: &mecha::ActorAddress) {
//!         println!("I received a message! It was of type...");
//!         println!("    {:?}", message.get_type());
//!         println!("...with datum...");
//!         println!("    {:?}", message.get_datum());
//!     }
//! }
//!
//! let actor = mecha::spawn(ActorImplementation);
//!
//! mecha::Message::custom("MyMessage")
//!     .with_datum(mecha::MessageDatum::from("blah"))
//!     .send_to(&actor);
//!
//! // Or, more simply:
//!
//! mecha::Message::custom("MyMessage").with_str("blah").send_to(&actor);
//!
//! // Be clean and don't forget to stop the actor at the end!
//!
//! mecha::Message::stop().send_to(&actor);
//!
//! // Wait some time if you want to see the output printed by the other thread
//! use std::thread;
//! use std::time::Duration;
//! thread::sleep(Duration::from_millis(500));
//! ```
//!

use std::thread;
use std::sync::mpsc;
use std::collections::HashMap;

/// An ActorAddress structure is used, essentially, just as the identifier of an
/// actor for sending messages to it. ActorAddresses can be cheaply cloned and
/// passed around.
#[derive(Clone, Debug)]
pub struct ActorAddress {
    endpoint: mpsc::Sender<Message>
}

/// A MessageType defines a number of standard messages (such as the one to
/// stop an actor) and a Custom type which can be used to send user-defined
/// messages between actors.
///
/// Custom types contain a static str (so basically they're created from a
/// string literal) which can be matched on.
#[derive(Clone, PartialOrd, PartialEq, Ord, Eq, Debug)]
pub enum MessageType {
    /// A message of this type is automatically sent to any actor upon spawning.
    /// If an actor does not need initialization, it can safely ignore the
    /// message.
    Init,
    /// A message of this type will stop and kill the actor receiving it.
    Stop,
    /// This is a custom message type to use for user-defined messages.
    Custom(&'static str)
}

/// This variant type specifies what kind of data can be passed around in
/// messages; we believe it is better to have a well defined variant type rather
/// than something like an Any. This makes serialization well defined, and
/// the Map variant can serialize complex data structures anyway.
#[derive(Clone, Debug)]
pub enum MessageDatum {
    Void,
    I64(i64),
    U64(u64),
    F64(f64),
    Str(String),
    Map(HashMap<String, MessageDatum>),
    Act(ActorAddress)
}
impl MessageDatum {
    /// Consumes the MessageDatum and converts it to i64 if possible.
    pub fn as_i64(self) -> Option<i64> {
        match self {
            MessageDatum::I64(x) => Some(x),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to u64 if possible.
    pub fn as_u64(self) -> Option<u64> {
        match self {
            MessageDatum::U64(x) => Some(x),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to f64 if possible.
    pub fn as_f64(self) -> Option<f64> {
        match self {
            MessageDatum::F64(x) => Some(x),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to String if possible.
    pub fn as_str(self) -> Option<String> {
        match self {
            MessageDatum::Str(x) => Some(x),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to a map if possible.
    pub fn as_map(self) -> Option<HashMap<String, MessageDatum>> {
        match self {
            MessageDatum::Map(m) => Some(m),
            _ => None
        }
    }
    /// Consumes the MessageDatum and converts it to an ActorAddress if
    /// possible.
    pub fn as_act(self) -> Option<ActorAddress> {
        match self {
            MessageDatum::Act(a) => Some(a),
            _ => None
        }
    }
}
impl From<i64> for MessageDatum {
    fn from(x: i64) -> MessageDatum { MessageDatum::I64(x) }
}
impl From<u64> for MessageDatum {
    fn from(x: u64) -> MessageDatum { MessageDatum::U64(x) }
}
impl From<f64> for MessageDatum {
    fn from(x: f64) -> MessageDatum { MessageDatum::F64(x) }
}
impl From<String> for MessageDatum {
    fn from(x: String) -> MessageDatum { MessageDatum::Str(x) }
}
impl<'a> From<&'a str> for MessageDatum {
    fn from(x: &'a str) -> MessageDatum { MessageDatum::Str(x.to_string()) }
}
impl From<HashMap<String, MessageDatum>> for MessageDatum {
    fn from(x: HashMap<String, MessageDatum>) -> MessageDatum { MessageDatum::Map(x) }
}
impl From<ActorAddress> for MessageDatum {
    fn from(x: ActorAddress) -> MessageDatum { MessageDatum::Act(x) }
}
impl<'a> From<&'a ActorAddress> for MessageDatum {
    fn from(x: &'a ActorAddress) -> MessageDatum { MessageDatum::Act(x.clone()) }
}

/// A Message contains a type, the actor from whom the message comes, and a
/// datum. A Message can be created and sent using a builder pattern.
#[derive(Clone, Debug)]
pub struct Message {
    mt: MessageType,
    sender: ActorAddress,
    datum: MessageDatum
}

/// The builder struct for a Message.
pub struct MessageBuilder {
    mt: MessageType,
    sender: Option<ActorAddress>,
    datum: Option<MessageDatum>
}

impl Message {
    /// Gets the type of the message.
    pub fn get_type(&self) -> &MessageType { &self.mt }
    /// Gets the sender of the message.
    pub fn get_sender(&self) -> &ActorAddress { &self.sender }
    /// Gets the datum of the message.
    pub fn get_datum(&self) -> &MessageDatum { &self.datum }

    /// Initializes a message builder for an Init typed message.
    pub fn init() -> MessageBuilder {
        MessageBuilder {
            mt: MessageType::Init,
            sender: None,
            datum: None,
        }
    }

    /// Initializes a message builder for a Stop typed message.
    pub fn stop() -> MessageBuilder {
        MessageBuilder {
            mt: MessageType::Stop,
            sender: None,
            datum: None,
        }
    }

    /// Initializes a message builder for a Custom typed message.
    pub fn custom(mt: &'static str) -> MessageBuilder {
        MessageBuilder {
            mt: MessageType::Custom(mt),
            sender: None,
            datum: None,
        }
    }
}

impl MessageBuilder {
    /// Specifies the sender of the message.
    pub fn with_sender<'a>(&'a mut self, f: &ActorAddress) -> &'a mut MessageBuilder {
        self.sender = Some(f.clone());
        self
    }

    /// Specifies the datum of the message.
    pub fn with_datum<'a>(&'a mut self, d: MessageDatum) -> &'a mut MessageBuilder {
        self.datum = Some(d);
        self
    }

    /// Specifies an i64 as the datum of the message.
    pub fn with_i64<'a>(&'a mut self, i: i64) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(i))
    }

    /// Specifies an u64 as the datum of the message.
    pub fn with_u64<'a>(&'a mut self, u: u64) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(u))
    }

    /// Specifies an f64 as the datum of the message.
    pub fn with_f64<'a>(&'a mut self, f: f64) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(f))
    }

    /// Specifies a string as the datum of the message.
    pub fn with_str<'a>(&'a mut self, s: &str) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(s.to_string()))
    }

    /// Specifies a map as the datum of the message.
    pub fn with_map<'a>(&'a mut self, m: HashMap<String, MessageDatum>) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(m))
    }

    /// Specifies an actor as the datum of the message.
    pub fn with_act<'a>(&'a mut self, a: &ActorAddress) -> &'a mut MessageBuilder {
        self.with_datum(MessageDatum::from(a))
    }

    /// Builds the Message, should a user want to store it. Generally this is
    /// not necessary, just use `send_to()` to send it directly.
    pub fn build(&self) -> Message {
        let (fake_tx, _) = std::sync::mpsc::channel();
        Message {
            mt: self.mt.clone(),
            sender: self.sender.clone().unwrap_or(
                ActorAddress { endpoint: fake_tx }), // TODO: FIX. Leaks a broken channel.
            datum: match self.datum {
                None => MessageDatum::Void,
                Some(ref x) => x.clone(),
            }
        }
    }

    /// Builds the Message and sends it to the specified actor.
    ///
    /// This function is in the builder class for stylistic purposes: this
    /// way, it is possible to have nice one-liners.
    ///
    /// `mecha::Message::custom("blah").with_sender(&some_actor).with_i64(123).send_to(&other_actor);`
    ///
    pub fn send_to(&self, to: &ActorAddress) {
        to.endpoint.send(self.build()).unwrap_or(()); // TODO: Error handling.
    }
}

/// This trait represents the interface of any actor implementation.
///
/// Implementing this trait effectively requires to implement the functionality
/// to act upon one single message. The `mecha` library takes care of handling
/// the mailbox and the loop which receives messages.
pub trait Actor {
    /// This function is the meat of the message processing and must be
    /// implemented to implement this trait.
    fn process_message(&mut self, message: Message, myself: &ActorAddress);
}

/// Spawns an actor based on the provided Actor implementor, whose ownership is
/// acquired by the spawned thread. Returns an ActorAddress identifying the
/// spawned actor.
pub fn spawn<T: Actor + Send + 'static>(mut implementor: T) -> ActorAddress {
    let (tx, rx) = mpsc::channel::<Message>();
    let actor = ActorAddress { endpoint: tx.clone() };
    // Put an Init message on the channel immediately.
    Message::init().send_to(&actor);
    // Then spawn another thread.
    thread::spawn(move || {
        let rx_internal = rx;
        let tx_internal = tx;
        let actor_internal = ActorAddress { endpoint: tx_internal };
        loop {
            let rcvd_msg = rx_internal.recv();
            match rcvd_msg {
                Ok(msg) => {
                    let mt = msg.get_type().clone(); // for later
                    // Consume and process the message
                    implementor.process_message(msg, &actor_internal);
                    // Perform extra standard actions
                    match mt {
                        MessageType::Stop => {
                            // Stop this actor.
                            println!("Exiting upon request.");
                            break;
                        },
                        _ => ()
                    }
                },
                Err(_) => {
                    println!("Exiting upon error receiving message!");
                    break;
                }
            }
        }
    });
    actor
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are
//! defined in this crate because they cannot be used in [syn] without "full"
//! feature.
//!
//! # Optional features
//!
//! * **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: ItemFn
//! [`syn_mid::Block`]: Block
//! [syn]: https://github.com/dtolnay/syn

#![doc(test(
    no_crate_inject,
    attr(
        deny(warnings, rust_2018_idioms, single_use_lifetimes),
        allow(dead_code, unused_variables)
    )
))]
#![forbid(unsafe_code)]
#![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(clippy::default_trait_access)]
#![allow(clippy::eval_order_dependence, clippy::large_enum_variant)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod func;
mod pat;
mod path;

pub use crate::{
    func::{Block, FnArg, ItemFn, Receiver, Signature},
    pat::{
        FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
        PatType, PatWild,
    },
};
<commit_msg>Apply clippy::wildcard_imports lint<commit_after>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are
//! defined in this crate because they cannot be used in [syn] without "full"
//! feature.
//!
//! # Optional features
//!
//! * **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: ItemFn
//! [`syn_mid::Block`]: Block
//! [syn]: https://github.com/dtolnay/syn

#![doc(test(
    no_crate_inject,
    attr(
        deny(warnings, rust_2018_idioms, single_use_lifetimes),
        allow(dead_code, unused_variables)
    )
))]
#![forbid(unsafe_code)]
#![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(clippy::default_trait_access, clippy::wildcard_imports)]
#![allow(clippy::eval_order_dependence, clippy::large_enum_variant)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod func;
mod pat;
mod path;

pub use crate::{
    func::{Block, FnArg, ItemFn, Receiver, Signature},
    pat::{
        FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
        PatType, PatWild,
    },
};
<|endoftext|>