<commit_before>//! This reader composes frames of bytes started with a 4 byte frame header indicating the size of
//! the buffer. An exact size buffer will be allocated once the 4 byte frame header is received.

use std::io::{self, Read};
use std::collections::VecDeque;
use std::mem;

#[derive(Debug)]
pub struct FrameReader {
    frames: Frames
}

impl FrameReader {
    pub fn new(max_frame_size: u32) -> FrameReader {
        FrameReader {
            frames: Frames::new(max_frame_size)
        }
    }

    pub fn read<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        self.frames.read(reader)
    }

    pub fn iter_mut(&mut self) -> Iter {
        Iter {
            frames: &mut self.frames
        }
    }
}

pub struct Iter<'a> {
    frames: &'a mut Frames
}

impl<'a> Iterator for Iter<'a> {
    type Item = Vec<u8>;

    fn next(&mut self) -> Option<Vec<u8>> {
        self.frames.completed_frames.pop_front()
    }
}

#[derive(Debug)]
struct Frames {
    max_frame_size: u32,
    bytes_read: usize,
    header: [u8; 4],
    reading_header: bool,
    current: Vec<u8>,
    completed_frames: VecDeque<Vec<u8>>
}

impl Frames {
    pub fn new(max_frame_size: u32) -> Frames {
        Frames {
            max_frame_size: max_frame_size,
            bytes_read: 0,
            header: [0; 4],
            reading_header: true,
            current: Vec::with_capacity(0),
            completed_frames: VecDeque::new()
        }
    }

    /// Will read as much data as possible and build up frames to be retrieved from the iterator.
    ///
    /// Will stop reading when 0 bytes are retrieved from the latest call to `do_read` or the error
    /// kind is io::ErrorKind::WouldBlock.
    ///
    /// Returns an error or the total amount of bytes read.
    fn read<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        let mut total_bytes_read = 0;
        loop {
            match self.do_read(reader) {
                Ok(0) => return Ok(total_bytes_read),
                Ok(bytes_read) => {
                    total_bytes_read += bytes_read;
                },
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return Ok(total_bytes_read),
                Err(e) => return Err(e)
            }
        }
    }

    fn do_read<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        if self.reading_header {
            self.read_header(reader)
        } else {
            self.read_value(reader)
        }
    }

    // TODO: Return an error if size is greater than max_frame_size
    fn read_header<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        let bytes_read = try!(reader.read(&mut self.header[self.bytes_read..]));
        self.bytes_read += bytes_read;
        if self.bytes_read == 4 {
           let len = unsafe { u32::from_be(mem::transmute(self.header)) };
           self.bytes_read = 0;
           self.reading_header = false;
           self.current = Vec::with_capacity(len as usize);
           unsafe { self.current.set_len(len as usize); }
        }
        Ok(bytes_read)
    }

    fn read_value<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        let bytes_read = try!(reader.read(&mut self.current[self.bytes_read..]));
        self.bytes_read += bytes_read;
        if self.bytes_read == self.current.len() {
           self.completed_frames.push_back(mem::replace(&mut self.current, Vec::new()));
           self.bytes_read = 0;
           self.reading_header = true;
        }
        Ok(bytes_read)
    }
}

#[cfg(test)]
mod tests {
    use std::{mem, thread};
    use std::io::Cursor;
    use std::io::Write;
    use std::net::{TcpListener, TcpStream};
    use super::FrameReader;

    #[test]
    fn partial_and_complete_reads() {
        let buf1 = String::from("Hello World").into_bytes();
        let buf2 = String::from("Hi.").into_bytes();
        let header1: [u8; 4] = unsafe { mem::transmute((buf1.len() as u32).to_be()) };
        let header2: [u8; 4] = unsafe { mem::transmute((buf2.len() as u32).to_be()) };

        let mut reader = FrameReader::new(1024);

        // Write a partial header
        let mut header = Cursor::new(&header1[0..2]);
        let bytes_read = reader.read(&mut header).unwrap();
        assert_eq!(2, bytes_read);
        assert_eq!(None, reader.iter_mut().next());

        // Complete writing just the header
        let mut header = Cursor::new(&header1[2..]);
        let bytes_read = reader.read(&mut header).unwrap();
        assert_eq!(2, bytes_read);
        assert_eq!(None, reader.iter_mut().next());

        // Write a partial value
        let mut data = Cursor::new(&buf1[0..5]);
        let bytes_read = reader.read(&mut data).unwrap();
        assert_eq!(5, bytes_read);
        assert_eq!(None, reader.iter_mut().next());

        // Complete writing the first value
        let mut data = Cursor::new(&buf1[5..]);
        let bytes_read = reader.read(&mut data).unwrap();
        assert_eq!(6, bytes_read);
        let val = reader.iter_mut().next().unwrap();
        assert_eq!(buf1, val);

        // Write an entire header and value
        let mut data = Cursor::new(Vec::with_capacity(7));
        assert_eq!(4, data.write(&header2).unwrap());
        assert_eq!(3, data.write(&buf2).unwrap());
        data.set_position(0);
        let bytes_read = reader.read(&mut data).unwrap();
        assert_eq!(7, bytes_read);
        assert_eq!(buf2, reader.iter_mut().next().unwrap());
    }

    const IP: &'static str = "127.0.0.1:5003";
    /// Test that we never get an io error, but instead get Ok(0) when the call to read would block
    #[test]
    fn would_block() {
        let listener = TcpListener::bind(IP).unwrap();
        let h = thread::spawn(move || {
            for stream in listener.incoming() {
                if let Ok(mut conn) = stream {
                    conn.set_nonblocking(true).unwrap();
                    let mut reader = FrameReader::new(1024);
                    let result = reader.read(&mut conn);
                    assert_matches!(result, Ok(0));
                    return;
                }
            }
        });

        let _ = TcpStream::connect(IP).unwrap();
        h.join().unwrap();
    }
}
<commit_msg>Fix mindless error that removed eof check<commit_after>//! This reader composes frames of bytes started with a 4 byte frame header indicating the size of
//! the buffer. An exact size buffer will be allocated once the 4 byte frame header is received.

use std::io::{self, Read, Error, ErrorKind};
use std::collections::VecDeque;
use std::mem;

#[derive(Debug)]
pub struct FrameReader {
    frames: Frames
}

impl FrameReader {
    pub fn new(max_frame_size: u32) -> FrameReader {
        FrameReader {
            frames: Frames::new(max_frame_size)
        }
    }

    pub fn read<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        self.frames.read(reader)
    }

    pub fn iter_mut(&mut self) -> Iter {
        Iter {
            frames: &mut self.frames
        }
    }
}

pub struct Iter<'a> {
    frames: &'a mut Frames
}

impl<'a> Iterator for Iter<'a> {
    type Item = Vec<u8>;

    fn next(&mut self) -> Option<Vec<u8>> {
        self.frames.completed_frames.pop_front()
    }
}

#[derive(Debug)]
struct Frames {
    max_frame_size: u32,
    bytes_read: usize,
    header: [u8; 4],
    reading_header: bool,
    current: Vec<u8>,
    completed_frames: VecDeque<Vec<u8>>
}

impl Frames {
    pub fn new(max_frame_size: u32) -> Frames {
        Frames {
            max_frame_size: max_frame_size,
            bytes_read: 0,
            header: [0; 4],
            reading_header: true,
            current: Vec::with_capacity(0),
            completed_frames: VecDeque::new()
        }
    }

    /// Will read as much data as possible and build up frames to be retrieved from the iterator.
    ///
    /// Will stop reading when 0 bytes are retrieved from the latest call to `do_read` or the error
    /// kind is io::ErrorKind::WouldBlock.
    ///
    /// Returns an error or the total amount of bytes read.
    fn read<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        let mut total_bytes_read = 0;
        loop {
            match self.do_read(reader) {
                Ok(0) => {
                    if total_bytes_read == 0 {
                        return Err(Error::new(ErrorKind::UnexpectedEof, "Read 0 bytes"));
                    }
                    return Ok(total_bytes_read);
                },
                Ok(bytes_read) => {
                    total_bytes_read += bytes_read;
                },
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return Ok(total_bytes_read),
                Err(e) => return Err(e)
            }
        }
    }

    fn do_read<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        if self.reading_header {
            self.read_header(reader)
        } else {
            self.read_value(reader)
        }
    }

    // TODO: Return an error if size is greater than max_frame_size
    fn read_header<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        let bytes_read = try!(reader.read(&mut self.header[self.bytes_read..]));
        self.bytes_read += bytes_read;
        if self.bytes_read == 4 {
           let len = unsafe { u32::from_be(mem::transmute(self.header)) };
           self.bytes_read = 0;
           self.reading_header = false;
           self.current = Vec::with_capacity(len as usize);
           unsafe { self.current.set_len(len as usize); }
        }
        Ok(bytes_read)
    }

    fn read_value<T: Read>(&mut self, reader: &mut T) -> io::Result<usize> {
        let bytes_read = try!(reader.read(&mut self.current[self.bytes_read..]));
        self.bytes_read += bytes_read;
        if self.bytes_read == self.current.len() {
           self.completed_frames.push_back(mem::replace(&mut self.current, Vec::new()));
           self.bytes_read = 0;
           self.reading_header = true;
        }
        Ok(bytes_read)
    }
}

#[cfg(test)]
mod tests {
    use std::{mem, thread};
    use std::io::Cursor;
    use std::io::Write;
    use std::net::{TcpListener, TcpStream};
    use super::FrameReader;

    #[test]
    fn partial_and_complete_reads() {
        let buf1 = String::from("Hello World").into_bytes();
        let buf2 = String::from("Hi.").into_bytes();
        let header1: [u8; 4] = unsafe { mem::transmute((buf1.len() as u32).to_be()) };
        let header2: [u8; 4] = unsafe { mem::transmute((buf2.len() as u32).to_be()) };

        let mut reader = FrameReader::new(1024);

        // Write a partial header
        let mut header = Cursor::new(&header1[0..2]);
        let bytes_read = reader.read(&mut header).unwrap();
        assert_eq!(2, bytes_read);
        assert_eq!(None, reader.iter_mut().next());

        // Complete writing just the header
        let mut header = Cursor::new(&header1[2..]);
        let bytes_read = reader.read(&mut header).unwrap();
        assert_eq!(2, bytes_read);
        assert_eq!(None, reader.iter_mut().next());

        // Write a partial value
        let mut data = Cursor::new(&buf1[0..5]);
        let bytes_read = reader.read(&mut data).unwrap();
        assert_eq!(5, bytes_read);
        assert_eq!(None, reader.iter_mut().next());

        // Complete writing the first value
        let mut data = Cursor::new(&buf1[5..]);
        let bytes_read = reader.read(&mut data).unwrap();
        assert_eq!(6, bytes_read);
        let val = reader.iter_mut().next().unwrap();
        assert_eq!(buf1, val);

        // Write an entire header and value
        let mut data = Cursor::new(Vec::with_capacity(7));
        assert_eq!(4, data.write(&header2).unwrap());
        assert_eq!(3, data.write(&buf2).unwrap());
        data.set_position(0);
        let bytes_read = reader.read(&mut data).unwrap();
        assert_eq!(7, bytes_read);
        assert_eq!(buf2, reader.iter_mut().next().unwrap());
    }

    const IP: &'static str = "127.0.0.1:5003";
    /// Test that we never get an io error, but instead get Ok(0) when the call to read would block
    #[test]
    fn would_block() {
        let listener = TcpListener::bind(IP).unwrap();
        let h = thread::spawn(move || {
            for stream in listener.incoming() {
                if let Ok(mut conn) = stream {
                    conn.set_nonblocking(true).unwrap();
                    let mut reader = FrameReader::new(1024);
                    let result = reader.read(&mut conn);
                    assert_matches!(result, Ok(0));
                    return;
                }
            }
        });

        let _ = TcpStream::connect(IP).unwrap();
        h.join().unwrap();
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

#[doc(hidden)]
/// A wrapper to allow for an easy [`into_grouping_map_by`](../trait.Itertools.html#method.into_grouping_map_by)
pub struct MapForGrouping<I, F>(I, F);

impl<I, F> MapForGrouping<I, F> {
    pub(crate) fn new(iter: I, key_mapper: F) -> Self {
        Self(iter, key_mapper)
    }
}

impl<K, V, I, F> Iterator for MapForGrouping<I, F>
    where I: Iterator<Item = V>,
          K: Hash + Eq,
          F: FnMut(&V) -> K,
{
    type Item = (K, V);
    fn next(&mut self) -> Option<Self::Item> {
        let val = self.0.next()?;
        Some(((self.1)(&val), val))
    }
}

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
    where I: Iterator<Item = (K, V)>,
          K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
#[must_use = "GroupingMap is lazy and do nothing unless consumed"]
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
    where I: Iterator<Item = (K, V)>,
          K: Hash + Eq,
{
    /// This is the generic way to perform any operations on a `GroupingMap`.
    /// It's suggested to use this method only to implement custom operations
    /// when the already provided ones are not enough.
    ///
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let data = vec![2, 8, 5, 7, 9, 0, 4, 10];
    /// let lookup = data.into_iter()
    ///     .into_grouping_map_by(|&n| n % 4)
    ///     .aggregate(|acc, _, val| {
    ///         if val == 0 || val == 10 {
    ///             None
    ///         } else {
    ///             Some(acc.unwrap_or(0) + val)
    ///         }
    ///     });
    ///
    /// assert_eq!(lookup[&0], 4);        // 0 resets the accumulator so only 4 is summed
    /// assert_eq!(lookup[&1], 14);       // 5 + 9
    /// assert_eq!(lookup.get(&2), None); // 10 resets the accumulator and nothing is summed afterward
    /// assert_eq!(lookup[&3], 7);        // 7
    /// assert_eq!(lookup.len(), 3);      // The final keys are only 0, 1 and 2
    /// ```
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
        where FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let lookup = (1..=7)
    ///     .into_grouping_map_by(|&n| n % 3)
    ///     .fold(0, |acc, _, val| acc + val);
    ///
    /// assert_eq!(lookup[&0], 9);   // 3 + 6
    /// assert_eq!(lookup[&1], 12);  // 1 + 4 + 7
    /// assert_eq!(lookup[&2], 7);   // 2 + 5
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
        where R: Clone,
              FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let lookup = (1..=7)
    ///     .into_grouping_map_by(|&n| n % 3)
    ///     .fold_first(|acc, _, val| acc + val);
    ///
    /// assert_eq!(lookup[&0], 9);   // 3 + 6
    /// assert_eq!(lookup[&1], 12);  // 1 + 4 + 7
    /// assert_eq!(lookup[&2], 7);   // 2 + 5
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
        where FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
    /// an instance of `C`. The iteration order is preserved when inserting elements.
    ///
    /// Return a `HashMap` associating the key of each group with the collection containing the elements of that group.
    ///
    /// ```
    /// use itertools::Itertools;
    /// use std::collections::HashSet;
    ///
    /// let lookup = vec![0, 1, 2, 3, 4, 5, 6, 2, 3, 6].into_iter()
    ///     .into_grouping_map_by(|&n| n % 3)
    ///     .collect::<HashSet<_>>();
    ///
    /// assert_eq!(lookup[&0], vec![0, 3, 6].into_iter().collect());
    /// assert_eq!(lookup[&1], vec![1, 4].into_iter().collect());
    /// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect());
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn collect<C>(self) -> HashMap<K, C>
        where C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    /// Groups elements from the `GroupingMap` source by key and counts them.
    ///
    /// Return a `HashMap` associating the key of each group with the number of elements in that group.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let lookup = "This is a string".chars()
    ///     .into_grouping_map_by(|&c| c)
    ///     .count();
    ///
    /// assert_eq!(lookup[&'T'], 1);
    /// assert_eq!(lookup[&'h'], 1);
    /// assert_eq!(lookup[&'i'], 3);
    /// assert_eq!(lookup[&'s'], 3);
    /// assert_eq!(lookup[&' '], 3);
    /// assert_eq!(lookup[&'a'], 1);
    /// assert_eq!(lookup[&'t'], 1);
    /// assert_eq!(lookup[&'r'], 1);
    /// assert_eq!(lookup[&'n'], 1);
    /// assert_eq!(lookup[&'g'], 1);
    /// assert_eq!(lookup.len(), 10);
    /// ```
    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<commit_msg>Removed unwanted doc(hidden)<commit_after>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// A wrapper to allow for an easy [`into_grouping_map_by`](../trait.Itertools.html#method.into_grouping_map_by)
pub struct MapForGrouping<I, F>(I, F);

impl<I, F> MapForGrouping<I, F> {
    pub(crate) fn new(iter: I, key_mapper: F) -> Self {
        Self(iter, key_mapper)
    }
}

impl<K, V, I, F> Iterator for MapForGrouping<I, F>
    where I: Iterator<Item = V>,
          K: Hash + Eq,
          F: FnMut(&V) -> K,
{
    type Item = (K, V);
    fn next(&mut self) -> Option<Self::Item> {
        let val = self.0.next()?;
        Some(((self.1)(&val), val))
    }
}

/// Creates a new `GroupingMap` from `iter`
pub fn new<I, K, V>(iter: I) -> GroupingMap<I>
    where I: Iterator<Item = (K, V)>,
          K: Hash + Eq,
{
    GroupingMap { iter }
}

/// `GroupingMap` is an intermediate struct for efficient group-and-fold operations.
/// It groups elements by their key and at the same time fold each group
/// using some aggregating operation.
///
/// No method on this struct performs temporary allocations.
#[must_use = "GroupingMap is lazy and do nothing unless consumed"]
pub struct GroupingMap<I> {
    iter: I,
}

impl<I, K, V> GroupingMap<I>
    where I: Iterator<Item = (K, V)>,
          K: Hash + Eq,
{
    /// This is the generic way to perform any operations on a `GroupingMap`.
    /// It's suggested to use this method only to implement custom operations
    /// when the already provided ones are not enough.
    ///
    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in an `HashMap`.
    ///
    /// The `operation` function is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group if there is currently one;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being aggregated;
    /// If `operation` returns `Some(element)` then the accumulator is updated with `element`,
    /// otherwise the previous accumulation is discarded.
    ///
    /// Return a `HashMap` associating the key of each group with the result of aggregation of the group elements.
    /// If there's no result then there won't be an entry associated to that key.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let data = vec![2, 8, 5, 7, 9, 0, 4, 10];
    /// let lookup = data.into_iter()
    ///     .into_grouping_map_by(|&n| n % 4)
    ///     .aggregate(|acc, _, val| {
    ///         if val == 0 || val == 10 {
    ///             None
    ///         } else {
    ///             Some(acc.unwrap_or(0) + val)
    ///         }
    ///     });
    ///
    /// assert_eq!(lookup[&0], 4);        // 0 resets the accumulator so only 4 is summed
    /// assert_eq!(lookup[&1], 14);       // 5 + 9
    /// assert_eq!(lookup.get(&2), None); // 10 resets the accumulator and nothing is summed afterward
    /// assert_eq!(lookup[&3], 7);        // 7
    /// assert_eq!(lookup.len(), 3);      // The final keys are only 0, 1 and 2
    /// ```
    pub fn aggregate<FO, R>(self, mut operation: FO) -> HashMap<K, R>
        where FO: FnMut(Option<R>, &K, V) -> Option<R>,
    {
        let mut destination_map = HashMap::new();

        for (key, val) in self.iter {
            let acc = destination_map.remove(&key);
            if let Some(op_res) = operation(acc, &key, val) {
                destination_map.insert(key, op_res);
            }
        }

        destination_map
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// `init` is the value from which will be cloned the initial value of each accumulator.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let lookup = (1..=7)
    ///     .into_grouping_map_by(|&n| n % 3)
    ///     .fold(0, |acc, _, val| acc + val);
    ///
    /// assert_eq!(lookup[&0], 9);   // 3 + 6
    /// assert_eq!(lookup[&1], 12);  // 1 + 4 + 7
    /// assert_eq!(lookup[&2], 7);   // 2 + 5
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn fold<FO, R>(self, init: R, mut operation: FO) -> HashMap<K, R>
        where R: Clone,
              FO: FnMut(R, &K, V) -> R,
    {
        self.aggregate(|acc, key, val| {
            let acc = acc.unwrap_or_else(|| init.clone());
            Some(operation(acc, key, val))
        })
    }

    /// Groups elements from the `GroupingMap` source by key and applies `operation` to the elements
    /// of each group sequentially, passing the previously accumulated value, a reference to the key
    /// and the current element as arguments, and stores the results in a new map.
    ///
    /// This is similar to [`fold`] but the initial value of the accumulator is the first element of the group.
    ///
    /// `operation` is a function that is invoked on each element with the following parameters:
    ///  - the current value of the accumulator of the group;
    ///  - a reference to the key of the group this element belongs to;
    ///  - the element from the source being accumulated.
    ///
    /// Return a `HashMap` associating the key of each group with the result of folding the group elements.
    ///
    /// [`fold`]: #tymethod.fold
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let lookup = (1..=7)
    ///     .into_grouping_map_by(|&n| n % 3)
    ///     .fold_first(|acc, _, val| acc + val);
    ///
    /// assert_eq!(lookup[&0], 9);   // 3 + 6
    /// assert_eq!(lookup[&1], 12);  // 1 + 4 + 7
    /// assert_eq!(lookup[&2], 7);   // 2 + 5
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn fold_first<FO>(self, mut operation: FO) -> HashMap<K, V>
        where FO: FnMut(V, &K, V) -> V,
    {
        self.aggregate(|acc, key, val| {
            Some(match acc {
                Some(acc) => operation(acc, key, val),
                None => val,
            })
        })
    }

    /// Groups elements from the `GroupingMap` source by key and collects the elements of each group in
    /// an instance of `C`. The iteration order is preserved when inserting elements.
    ///
    /// Return a `HashMap` associating the key of each group with the collection containing the elements of that group.
    ///
    /// ```
    /// use itertools::Itertools;
    /// use std::collections::HashSet;
    ///
    /// let lookup = vec![0, 1, 2, 3, 4, 5, 6, 2, 3, 6].into_iter()
    ///     .into_grouping_map_by(|&n| n % 3)
    ///     .collect::<HashSet<_>>();
    ///
    /// assert_eq!(lookup[&0], vec![0, 3, 6].into_iter().collect());
    /// assert_eq!(lookup[&1], vec![1, 4].into_iter().collect());
    /// assert_eq!(lookup[&2], vec![2, 5].into_iter().collect());
    /// assert_eq!(lookup.len(), 3);
    /// ```
    pub fn collect<C>(self) -> HashMap<K, C>
        where C: Default + Extend<V>,
    {
        self.aggregate(|acc, _, v| {
            let mut acc = acc.unwrap_or_else(C::default);
            acc.extend(Some(v));
            Some(acc)
        })
    }

    /// Groups elements from the `GroupingMap` source by key and counts them.
    ///
    /// Return a `HashMap` associating the key of each group with the number of elements in that group.
    ///
    /// ```
    /// use itertools::Itertools;
    ///
    /// let lookup = "This is a string".chars()
    ///     .into_grouping_map_by(|&c| c)
    ///     .count();
    ///
    /// assert_eq!(lookup[&'T'], 1);
    /// assert_eq!(lookup[&'h'], 1);
    /// assert_eq!(lookup[&'i'], 3);
    /// assert_eq!(lookup[&'s'], 3);
    /// assert_eq!(lookup[&' '], 3);
    /// assert_eq!(lookup[&'a'], 1);
    /// assert_eq!(lookup[&'t'], 1);
    /// assert_eq!(lookup[&'r'], 1);
    /// assert_eq!(lookup[&'n'], 1);
    /// assert_eq!(lookup[&'g'], 1);
    /// assert_eq!(lookup.len(), 10);
    /// ```
    pub fn count(self) -> HashMap<K, usize> {
        self.fold(0, |acc, _, _| acc + 1)
    }
}
<|endoftext|>


<commit_before>extern crate android_glue;

use libc;
use std::sync::mpsc::{Receiver, channel};
use {CreationError, Event, WindowBuilder};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::Event::{MouseInput, MouseMoved};
use events::MouseButton::LeftMouseButton;

use std::collections::RingBuf;

use BuilderAttribs;

pub struct Window {
    display: ffi::egl::types::EGLDisplay,
    context: ffi::egl::types::EGLContext,
    surface: ffi::egl::types::EGLSurface,
    event_rx: Receiver<android_glue::Event>,
}

pub struct MonitorID;

mod ffi;

pub fn get_available_monitors() -> RingBuf <MonitorID> {
    let mut rb = RingBuf::new();
    rb.push_back(MonitorID);
    rb
}

pub fn get_primary_monitor() -> MonitorID {
    MonitorID
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    pub fn get_dimensions(&self) -> (uint, uint) {
        unimplemented!()
    }
}

#[cfg(feature = "headless")]
pub struct HeadlessContext(int);

#[cfg(feature = "headless")]
impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub unsafe fn make_current(&self) {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        unimplemented!()
    }
}

#[cfg(feature = "headless")]
unsafe impl Send for HeadlessContext {}
#[cfg(feature = "headless")]
unsafe impl Sync for HeadlessContext {}

impl Window {
    pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
        use std::{mem, ptr};

        if builder.sharing.is_some() {
            unimplemented!()
        }

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let display = unsafe {
            let display = ffi::egl::GetDisplay(mem::transmute(ffi::egl::DEFAULT_DISPLAY));
            if display.is_null() {
                return Err(OsError("No EGL display connection available".to_string()));
            }
            display
        };

        android_glue::write_log("eglGetDisplay succeeded");

        let (_major, _minor) = unsafe {
            let mut major: ffi::egl::types::EGLint = mem::uninitialized();
            let mut minor: ffi::egl::types::EGLint = mem::uninitialized();

            if ffi::egl::Initialize(display, &mut major, &mut minor) == 0 {
                return Err(OsError(format!("eglInitialize failed")))
            }

            (major, minor)
        };

        android_glue::write_log("eglInitialize succeeded");

        let use_gles2 = match builder.gl_version {
            Some((2, 0)) => true,
            _ => false,
        };

        let config = unsafe {
            let mut attribute_list = vec!();
            if use_gles2 {
                attribute_list.push_all(&[ffi::egl::RENDERABLE_TYPE as i32,
                                         ffi::egl::OPENGL_ES2_BIT as i32]);
            }
            attribute_list.push_all(&[ffi::egl::RED_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::GREEN_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::BLUE_SIZE as i32, 1]);
            attribute_list.push(ffi::egl::NONE as i32);

            let mut num_config: ffi::egl::types::EGLint = mem::uninitialized();
            let mut config: ffi::egl::types::EGLConfig = mem::uninitialized();
            if ffi::egl::ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1,
                &mut num_config) == 0
            {
                return Err(OsError(format!("eglChooseConfig failed")))
            }

            if num_config <= 0 {
                return Err(OsError(format!("eglChooseConfig returned no available config")))
            }

            config
        };

        android_glue::write_log("eglChooseConfig succeeded");

        let context = unsafe {
            let mut context_attributes = vec!();
            if use_gles2 {
                context_attributes.push_all(&[ffi::egl::CONTEXT_CLIENT_VERSION as i32, 2]);
            }
            context_attributes.push(ffi::egl::NONE as i32);

            let context = ffi::egl::CreateContext(display, config, ptr::null(),
                                                  context_attributes.as_ptr());
            if context.is_null() {
                return Err(OsError(format!("eglCreateContext failed")))
            }
            context
        };

        android_glue::write_log("eglCreateContext succeeded");

        let surface = unsafe {
            let surface = ffi::egl::CreateWindowSurface(display, config, native_window, ptr::null());
            if surface.is_null() {
                return Err(OsError(format!("eglCreateWindowSurface failed")))
            }
            surface
        };

        android_glue::write_log("eglCreateWindowSurface succeeded");

        let (tx, rx) = channel();
        android_glue::add_sender(tx);

        Ok(Window {
            display: display,
            context: context,
            surface: surface,
            event_rx: rx,
        })
    }

    pub fn is_closed(&self) -> bool {
        false
    }

    pub fn set_title(&self, _: &str) {
    }

    pub fn show(&self) {
    }

    pub fn hide(&self) {
    }

    pub fn get_position(&self) -> Option<(int, int)> {
        None
    }

    pub fn set_position(&self, _x: int, _y: int) {
    }

    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window) } as uint,
                unsafe { ffi::ANativeWindow_getHeight(native_window) } as uint
            ))
        }
    }

    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        self.get_inner_size()
    }

    pub fn set_inner_size(&self, _x: uint, _y: uint) {
    }

    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    pub fn poll_events(&self) -> RingBuf<Event> {
        let mut events = RingBuf::new();
        loop {
            match self.event_rx.try_recv() {
                Ok(event) => match event {
                    android_glue::Event::EventDown => {
                        events.push_back(MouseInput(Pressed, LeftMouseButton));
                    },
                    android_glue::Event::EventUp => {
                        events.push_back(MouseInput(Released, LeftMouseButton));
                    },
                    android_glue::Event::EventMove(x, y) => {
                        events.push_back(MouseMoved((x as int, y as int)));
                    },
                },
                Err(_) => {
                    break;
                },
            }
        }
        events
    }

    pub fn wait_events(&self) -> RingBuf<Event> {
        use std::time::Duration;
        use std::io::timer;
        timer::sleep(Duration::milliseconds(16));
        self.poll_events()
    }

    pub fn make_current(&self) {
        unsafe {
            ffi::egl::MakeCurrent(self.display, self.surface, self.surface, self.context);
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const () {
        use std::c_str::ToCStr;

        unsafe {
            addr.with_c_str(|s| {
                ffi::egl::GetProcAddress(s) as *const ()
            })
        }
    }

    pub fn swap_buffers(&self) {
        unsafe {
            ffi::egl::SwapBuffers(self.display, self.surface);
        }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        self.display as *mut libc::c_void
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }

    pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) {
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

#[cfg(feature = "window")]
#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;

        unsafe {
            android_glue::write_log("Destroying gl-init window");
            ffi::egl::MakeCurrent(self.display, ptr::null(), ptr::null(), ptr::null());
            ffi::egl::DestroySurface(self.display, self.surface);
            ffi::egl::DestroyContext(self.display, self.context);
            ffi::egl::Terminate(self.display);
        }
    }
}
<commit_msg>android: Updated for Rust ea6f65c5f 2015-01-06<commit_after>extern crate android_glue;

use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use {CreationError, Event, WindowBuilder};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::Event::{MouseInput, MouseMoved};
use events::MouseButton::LeftMouseButton;

use std::collections::RingBuf;

use BuilderAttribs;

pub struct Window {
    display: ffi::egl::types::EGLDisplay,
    context: ffi::egl::types::EGLContext,
    surface: ffi::egl::types::EGLSurface,
    event_rx: Receiver<android_glue::Event>,
}

pub struct MonitorID;

mod ffi;

pub fn get_available_monitors() -> RingBuf <MonitorID> {
    let mut rb = RingBuf::new();
    rb.push_back(MonitorID);
    rb
}

pub fn get_primary_monitor() -> MonitorID {
    MonitorID
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    pub fn get_dimensions(&self) -> (uint, uint) {
        unimplemented!()
    }
}

#[cfg(feature = "headless")]
pub struct HeadlessContext(int);

#[cfg(feature = "headless")]
impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub unsafe fn make_current(&self) {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        unimplemented!()
    }
}

#[cfg(feature = "headless")]
unsafe impl Send for HeadlessContext {}
#[cfg(feature = "headless")]
unsafe impl Sync for HeadlessContext {}

impl Window {
    pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
        use std::{mem, ptr};

        if builder.sharing.is_some() {
            unimplemented!()
        }

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let display = unsafe {
            let display = ffi::egl::GetDisplay(mem::transmute(ffi::egl::DEFAULT_DISPLAY));
            if display.is_null() {
                return Err(OsError("No EGL display connection available".to_string()));
            }
            display
        };

        android_glue::write_log("eglGetDisplay succeeded");

        let (_major, _minor) = unsafe {
            let mut major: ffi::egl::types::EGLint = mem::uninitialized();
            let mut minor: ffi::egl::types::EGLint = mem::uninitialized();

            if ffi::egl::Initialize(display, &mut major, &mut minor) == 0 {
                return Err(OsError(format!("eglInitialize failed")))
            }

            (major, minor)
        };

        android_glue::write_log("eglInitialize succeeded");

        let use_gles2 = match builder.gl_version {
            Some((2, 0)) => true,
            _ => false,
        };

        let config = unsafe {
            let mut attribute_list = vec!();
            if use_gles2 {
                attribute_list.push_all(&[ffi::egl::RENDERABLE_TYPE as i32,
                                         ffi::egl::OPENGL_ES2_BIT as i32]);
            }
            attribute_list.push_all(&[ffi::egl::RED_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::GREEN_SIZE as i32, 1]);
            attribute_list.push_all(&[ffi::egl::BLUE_SIZE as i32, 1]);
            attribute_list.push(ffi::egl::NONE as i32);

            let mut num_config: ffi::egl::types::EGLint = mem::uninitialized();
            let mut config: ffi::egl::types::EGLConfig = mem::uninitialized();
            if ffi::egl::ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1,
                &mut num_config) == 0
            {
                return Err(OsError(format!("eglChooseConfig failed")))
            }

            if num_config <= 0 {
                return Err(OsError(format!("eglChooseConfig returned no available config")))
            }

            config
        };

        android_glue::write_log("eglChooseConfig succeeded");

        let context = unsafe {
            let mut context_attributes = vec!();
            if use_gles2 {
                context_attributes.push_all(&[ffi::egl::CONTEXT_CLIENT_VERSION as i32, 2]);
            }
            context_attributes.push(ffi::egl::NONE as i32);

            let context = ffi::egl::CreateContext(display, config, ptr::null(),
                                                  context_attributes.as_ptr());
            if context.is_null() {
                return Err(OsError(format!("eglCreateContext failed")))
            }
            context
        };

        android_glue::write_log("eglCreateContext succeeded");

        let surface = unsafe {
            let surface = ffi::egl::CreateWindowSurface(display, config, native_window, ptr::null());
            if surface.is_null() {
                return Err(OsError(format!("eglCreateWindowSurface failed")))
            }
            surface
        };

        android_glue::write_log("eglCreateWindowSurface succeeded");

        let (tx, rx) = channel();
        android_glue::add_sender(tx);

        Ok(Window {
            display: display,
            context: context,
            surface: surface,
            event_rx: rx,
        })
    }

    pub fn is_closed(&self) -> bool {
        false
    }

    pub fn set_title(&self, _: &str) {
    }

    pub fn show(&self) {
    }

    pub fn hide(&self) {
    }

    pub fn get_position(&self) -> Option<(int, int)> {
        None
    }

    pub fn set_position(&self, _x: int, _y: int) {
    }

    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window) } as uint,
                unsafe { ffi::ANativeWindow_getHeight(native_window) } as uint
            ))
        }
    }

    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        self.get_inner_size()
    }

    pub fn set_inner_size(&self, _x: uint, _y: uint) {
    }

    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    pub fn poll_events(&self) -> RingBuf<Event> {
        let mut events = RingBuf::new();
        loop {
            match self.event_rx.try_recv() {
                Ok(event) => match event {
                    android_glue::Event::EventDown => {
                        events.push_back(MouseInput(Pressed, LeftMouseButton));
                    },
                    android_glue::Event::EventUp => {
                        events.push_back(MouseInput(Released, LeftMouseButton));
                    },
                    android_glue::Event::EventMove(x, y) => {
                        events.push_back(MouseMoved((x as int, y as int)));
                    },
                },
                Err(_) => {
                    break;
                },
            }
        }
        events
    }

    pub fn wait_events(&self) -> RingBuf<Event> {
        use std::time::Duration;
        use std::io::timer;
        timer::sleep(Duration::milliseconds(16));
        self.poll_events()
    }

    pub fn make_current(&self) {
        unsafe {
            ffi::egl::MakeCurrent(self.display, self.surface, self.surface, self.context);
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const () {
        let addr = CString::from_slice(addr.as_bytes()).as_slice_with_nul().as_ptr();
        unsafe {
            ffi::egl::GetProcAddress(addr) as *const ()
        }
    }

    pub fn swap_buffers(&self) {
        unsafe {
            ffi::egl::SwapBuffers(self.display, self.surface);
        }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        self.display as *mut libc::c_void
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }

    pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) {
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

#[cfg(feature = "window")]
#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;

        unsafe {
            android_glue::write_log("Destroying gl-init window");
            ffi::egl::MakeCurrent(self.display, ptr::null(), ptr::null(), ptr::null());
            ffi::egl::DestroySurface(self.display, self.surface);
            ffi::egl::DestroyContext(self.display, self.context);
            ffi::egl::Terminate(self.display);
        }
    }
}
<|endoftext|>


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

//! Bstream module.
//! This is a blocking stream designed to block on read/write until

use std::result::Result;
use std::net::TcpStream;
use std::io::{Read, Write, Error};

use super::readbuffer::ReadBuffer;

/// Represents the result of attempting a read on the underlying file descriptor
pub type ReadResult = Result<Vec<u8>, Error>;

/// Represents the result attempting a write on the underlying fild descriptor
pub type WriteResult = Result<(), Error>;

/// States the current stream can be in
#[derive(PartialEq, Clone)]
enum ReadState {
    /// Currently reading the payload length
    PayloadLen,
    /// Currently reading the payload
    Payload
}

pub struct Bstream {
    /// Current state
    state: ReadState,
    /// Underlying std::net::TcpStream
    stream: TcpStream,
    /// Message buffer
    buffer: ReadBuffer
}

impl Bstream {

    /// Returns a new Bstream
    pub fn new(stream: TcpStream) -> Bstream {
        Bstream {
            state: ReadState::PayloadLen,
            stream: stream,
            buffer: ReadBuffer::new()
        }
    }

    /// Performs a blocking read and returns when a complete message
    /// has been returned, or an error has occured
    pub fn read(&mut self) -> ReadResult {

        println!("simple stream read loop =============");

        loop {
            // Create a buffer for this specific read iteration
            let count = self.buffer.remaining();
            let mut buffer = Vec::<u8>::with_capacity(count as usize);
            unsafe { buffer.set_len(count as usize); }

            let result = self.stream.read(&mut buffer[..]);
            if result.is_err() {
                return Err(result.unwrap_err());
            }

            let num_read = result.unwrap();
            for x in 0..num_read {
                self.buffer.push(buffer[x]);
            }

            if self.buffer.remaining() == 0 {
                if self.state == ReadState::PayloadLen {

                    println!("Payload length read complete");
                    println!("Printing buffer...");
                    let mut index = 0;
                    for byte in self.buffer.current_buffer().iter() {
                        println!("byte {}: {}", index, byte);
                        index += 1;
                    }

                    self.buffer.calc_payload_len();
                    let p_len = self.buffer.payload_len();

                    println!("Payload length: {}", p_len);

                    self.buffer.set_capacity(p_len);
                    self.state = ReadState::Payload;
                } else { // Payload completely read

                    println!("Payload read complete");
                    println!("Printing buffer...");
                    let mut index = 0;
                    for byte in self.buffer.current_buffer().iter() {
                        println!("byte {}: {}", index, byte);
                        index += 1;
                    }

                    self.buffer.reset();
                    self.state = ReadState::PayloadLen;
                    break;
                }
            }
        }

        println!("simple stream read loop finished =============");

        let mut buffer = self.buffer.drain_queue();

        println!("Queue drained");
        println!("buffer.len: {}", buffer.len());

        // This should always be .len() of 1
        // if it isn't - we're doing some bad stuff in here
        if buffer.len() != 1 {
            panic!("Error - Bstream.read() - Internal buffer was not equal to one...?")
        }

        match buffer.pop() {
            Some(buf) => Ok(buf),
            None => unimplemented!()
        }
    }

    /// Performs a blocking write operation and returns the complete buffer has
    /// been written, or an error has occured
    pub fn write(&mut self, buffer: &Vec<u8>) -> WriteResult {
        let mut plen_buf = [0u8; 2];
        plen_buf[0] = (buffer.len() as u16 & 0b1111_1111u16 << 8) as u8;
        plen_buf[1] = (buffer.len() as u16 & 0b1111_1111u16) as u8;

        let mut n_buffer = Vec::<u8>::with_capacity(buffer.len() + 2);
        n_buffer.push(plen_buf[0]);
        n_buffer.push(plen_buf[1]);

        for x in 0..buffer.len() {
            n_buffer.push(buffer[x]);
        }

        match self.stream.write_all(&n_buffer[..]) {
            Ok(()) => {
                let _ = self.stream.flush();
                Ok(())
            }
            Err(e) => Err(e)
        }
    }
}

impl Clone for Bstream {
    fn clone(&self) -> Bstream {
        Bstream {
            state: self.state.clone(),
            stream: self.stream.try_clone().unwrap(),
            buffer: self.buffer.clone()
        }
    }
}
<commit_msg>Updating bitshifting<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.

//! Bstream module.
//! This is a blocking stream designed to block on read/write until

use std::result::Result;
use std::net::TcpStream;
use std::io::{Read, Write, Error};

use super::readbuffer::ReadBuffer;

/// Represents the result of attempting a read on the underlying file descriptor
pub type ReadResult = Result<Vec<u8>, Error>;

/// Represents the result attempting a write on the underlying fild descriptor
pub type WriteResult = Result<(), Error>;

/// States the current stream can be in
#[derive(PartialEq, Clone)]
enum ReadState {
    /// Currently reading the payload length
    PayloadLen,
    /// Currently reading the payload
    Payload
}

pub struct Bstream {
    /// Current state
    state: ReadState,
    /// Underlying std::net::TcpStream
    stream: TcpStream,
    /// Message buffer
    buffer: ReadBuffer
}

impl Bstream {

    /// Returns a new Bstream
    pub fn new(stream: TcpStream) -> Bstream {
        Bstream {
            state: ReadState::PayloadLen,
            stream: stream,
            buffer: ReadBuffer::new()
        }
    }

    /// Performs a blocking read and returns when a complete message
    /// has been returned, or an error has occured
    pub fn read(&mut self) -> ReadResult {

        println!("simple stream read loop =============");

        loop {
            // Create a buffer for this specific read iteration
            let count = self.buffer.remaining();
            let mut buffer = Vec::<u8>::with_capacity(count as usize);
            unsafe { buffer.set_len(count as usize); }

            let result = self.stream.read(&mut buffer[..]);
            if result.is_err() {
                return Err(result.unwrap_err());
            }

            let num_read = result.unwrap();
            for x in 0..num_read {
                self.buffer.push(buffer[x]);
            }

            if self.buffer.remaining() == 0 {
                if self.state == ReadState::PayloadLen {

                    println!("Payload length read complete");
                    println!("Printing buffer...");
                    let mut index = 0;
                    for byte in self.buffer.current_buffer().iter() {
                        println!("byte {}: {}", index, byte);
                        index += 1;
                    }

                    self.buffer.calc_payload_len();
                    let p_len = self.buffer.payload_len();

                    println!("Payload length: {}", p_len);

                    self.buffer.set_capacity(p_len);
                    self.state = ReadState::Payload;
                } else { // Payload completely read

                    println!("Payload read complete");
                    println!("Printing buffer...");
                    let mut index = 0;
                    for byte in self.buffer.current_buffer().iter() {
                        println!("byte {}: {}", index, byte);
                        index += 1;
                    }

                    self.buffer.reset();
                    self.state = ReadState::PayloadLen;
                    break;
                }
            }
        }

        println!("simple stream read loop finished =============");

        let mut buffer = self.buffer.drain_queue();

        println!("Queue drained");
        println!("buffer.len: {}", buffer.len());

        // This should always be .len() of 1
        // if it isn't - we're doing some bad stuff in here
        if buffer.len() != 1 {
            panic!("Error - Bstream.read() - Internal buffer was not equal to one...?")
        }

        match buffer.pop() {
            Some(buf) => Ok(buf),
            None => unimplemented!()
        }
    }

    /// Performs a blocking write operation and returns the complete buffer has
    /// been written, or an error has occured
    pub fn write(&mut self, buffer: &Vec<u8>) -> WriteResult {
        let mut plen_buf = [0u8; 2];
        plen_buf[0] = (buffer.len() as u16 >> 8) as u8;
        plen_buf[1] = (buffer.len() as u16 & 0b1111_1111u16) as u8;

        let mut n_buffer = Vec::<u8>::with_capacity(buffer.len() + 2);
        n_buffer.push(plen_buf[0]);
        n_buffer.push(plen_buf[1]);

        for x in 0..buffer.len() {
            n_buffer.push(buffer[x]);
        }

        match self.stream.write_all(&n_buffer[..]) {
            Ok(()) => {
                let _ = self.stream.flush();
                Ok(())
            }
            Err(e) => Err(e)
        }
    }
}

impl Clone for Bstream {
    fn clone(&self) -> Bstream {
        Bstream {
            state: self.state.clone(),
            stream: self.stream.try_clone().unwrap(),
            buffer: self.buffer.clone()
        }
    }
}
<|endoftext|>


<commit_before>use std::io::ALL_PERMISSIONS;
use std::io::fs::{mkdir_recursive};

use config::builders as B;

use super::context::BuildContext;
use super::commands::debian;
use super::commands::generic;
use super::download::download_file;
use super::tarcmd::unpack_file;
use container::util::clean_dir;
use container::mount::{bind_mount, unmount};

pub trait BuildCommand {
    fn build(&self, ctx: &mut BuildContext) -> Result<(), String>;
}

impl BuildCommand for B::Builder {
    fn build(&self, ctx: &mut BuildContext) -> Result<(), String> {
        match self {
            &B::UbuntuCore(ref name) => {
                debian::fetch_ubuntu_core(ctx, name)
            }
            &B::Sh(ref text) => {
                generic::run_command(ctx,
                    &["/bin/sh".to_string(),
                      "-c".to_string(),
                      text.to_string()])
            }
            &B::Cmd(ref cmd) => {
                generic::run_command(ctx, cmd.as_slice())
            }
            &B::Env(ref pairs) => {
                for (k, v) in pairs.iter() {
                    ctx.environ.insert(k.clone(), v.clone());
                }
                Ok(())
            }
            &B::Remove(ref path) => {
                try!(clean_dir(path, true));
                ctx.add_remove_dir(path.clone());
                Ok(())
            }
            &B::EmptyDir(ref path) => {
                try!(clean_dir(path, false));
                ctx.add_empty_dir(path.clone());
                Ok(())
            }
            &B::EnsureDir(ref path) => {
                let fpath = path.path_relative_from(&Path::new("/")).unwrap();
                try!(mkdir_recursive(
                    &Path::new("/vagga/root").join(fpath), ALL_PERMISSIONS)
                    .map_err(|e| format!("Error creating dir: {}", e)));
                ctx.add_ensure_dir(path.clone());
                Ok(())
            }
            &B::Depends(_) => {
                Ok(())
            }
            &B::Tar(ref tar) => {
                let fpath = Path::new("/vagga/root").join(
                    tar.path.path_relative_from(&Path::new("/")).unwrap());
                let filename = try!(download_file(ctx, &tar.url));
                // TODO(tailhook) check sha256 sum
                if tar.subdir == Path::new(".") {
                    try!(unpack_file(ctx, &filename, &fpath, &[], &[]));
                } else {
                    let tmppath = Path::new("/vagga/root/tmp")
                        .join(filename.filename_str().unwrap());
                    let tmpsub = tmppath.join(&tar.subdir);
                    try!(mkdir_recursive(&tmpsub, ALL_PERMISSIONS)
                         .map_err(|e| format!("Error making dir: {}", e)));
                    try!(bind_mount(&fpath, &tmpsub));
                    let res = unpack_file(ctx, &filename, &tmppath,
                        &[tar.subdir.clone()], &[]);
                    try!(unmount(&tmpsub));
                    try!(res);
                }
                Ok(())
            }
        }
    }
}
<commit_msg>Implement mkdir for `!Tar.subdir`<commit_after>use std::io::ALL_PERMISSIONS;
use std::io::fs::{mkdir_recursive};
use std::io::fs::PathExtensions;

use config::builders as B;

use super::context::BuildContext;
use super::commands::debian;
use super::commands::generic;
use super::download::download_file;
use super::tarcmd::unpack_file;
use container::util::clean_dir;
use container::mount::{bind_mount, unmount};

pub trait BuildCommand {
    fn build(&self, ctx: &mut BuildContext) -> Result<(), String>;
}

impl BuildCommand for B::Builder {
    fn build(&self, ctx: &mut BuildContext) -> Result<(), String> {
        match self {
            &B::UbuntuCore(ref name) => {
                debian::fetch_ubuntu_core(ctx, name)
            }
            &B::Sh(ref text) => {
                generic::run_command(ctx,
                    &["/bin/sh".to_string(),
                      "-c".to_string(),
                      text.to_string()])
            }
            &B::Cmd(ref cmd) => {
                generic::run_command(ctx, cmd.as_slice())
            }
            &B::Env(ref pairs) => {
                for (k, v) in pairs.iter() {
                    ctx.environ.insert(k.clone(), v.clone());
                }
                Ok(())
            }
            &B::Remove(ref path) => {
                try!(clean_dir(path, true));
                ctx.add_remove_dir(path.clone());
                Ok(())
            }
            &B::EmptyDir(ref path) => {
                try!(clean_dir(path, false));
                ctx.add_empty_dir(path.clone());
                Ok(())
            }
            &B::EnsureDir(ref path) => {
                let fpath = path.path_relative_from(&Path::new("/")).unwrap();
                try!(mkdir_recursive(
                    &Path::new("/vagga/root").join(fpath), ALL_PERMISSIONS)
                    .map_err(|e| format!("Error creating dir: {}", e)));
                ctx.add_ensure_dir(path.clone());
                Ok(())
            }
            &B::Depends(_) => {
                Ok(())
            }
            &B::Tar(ref tar) => {
                let fpath = Path::new("/vagga/root").join(
                    tar.path.path_relative_from(&Path::new("/")).unwrap());
                let filename = try!(download_file(ctx, &tar.url));
                // TODO(tailhook) check sha256 sum
                if tar.subdir == Path::new(".") {
                    try!(unpack_file(ctx, &filename, &fpath, &[], &[]));
                } else {
                    let tmppath = Path::new("/vagga/root/tmp")
                        .join(filename.filename_str().unwrap());
                    let tmpsub = tmppath.join(&tar.subdir);
                    try!(mkdir_recursive(&tmpsub, ALL_PERMISSIONS)
                         .map_err(|e| format!("Error making dir: {}", e)));
                    if !fpath.exists() {
                        try!(mkdir_recursive(&fpath, ALL_PERMISSIONS)
                             .map_err(|e| format!("Error making dir: {}", e)));
                    }
                    try!(bind_mount(&fpath, &tmpsub));
                    let res = unpack_file(ctx, &filename, &tmppath,
                        &[tar.subdir.clone()], &[]);
                    try!(unmount(&tmpsub));
                    try!(res);
                }
                Ok(())
            }
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "chmod"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules, phase)]

#![allow(unused_variables)]  // only necessary while the TODOs still exist

extern crate getopts;
extern crate libc;
extern crate native;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;

use std::io::fs;
use std::io::fs::PathExtensions;
use std::io::IoError;
use std::mem;
use std::num::from_str_radix;
use regex::Regex;

#[path = "../common/util.rs"]
mod util;

const NAME: &'static str = "chmod";
const VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].clone();

    let opts = [
        getopts::optflag("c", "changes", "like verbose but report only when a change is made (unimplemented)"),
        getopts::optflag("f", "quiet", "suppress most error messages (unimplemented)"), // TODO: support --silent
        getopts::optflag("v", "verbose", "output a diagnostic for every file processed (unimplemented)"),
        getopts::optflag("", "no-preserve-root", "do not treat '/' specially (the default)"),
        getopts::optflag("", "preserve-root", "fail to operate recursively on '/'"),
        getopts::optflagopt("", "reference", "use RFILE's mode instead of MODE values", "RFILE"),
        getopts::optflag("R", "recursive", "change files and directories recursively"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit")
    ];
    // TODO: sanitize input for - at beginning (e.g. chmod -x testfile).  Solution is to add a to -x, making a-x
    let mut matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => {
            crash!(1, "{}", f)
        }
    };
    if matches.opt_present("help") {
        println!("{name} v{version}

Usage:
  {program} [OPTION]... MODE[,MODE]... FILE...
  {program} [OPTION]... OCTAL-MODE FILE...
  {program} [OPTION]... --reference=RFILE FILE...

{usage}
Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.",
               name = NAME, version = VERSION, program = program,
               usage = getopts::usage("Change the mode of each FILE to MODE. \
                                       With --reference, change the mode of \
                                       each FILE to that of RFILE.", &opts));
    } else if matches.opt_present("version") {
        println!("{} v{}", NAME, VERSION);
    } else if matches.free.is_empty() && matches.opt_present("reference") || matches.free.len() < 2 {
        show_error!("missing an argument");
        show_error!("for help, try '{} --help'", program);
        return 1;
    } else {
        let changes = matches.opt_present("changes");
        let quiet = matches.opt_present("quiet");
        let verbose = matches.opt_present("verbose");
        let preserve_root = matches.opt_present("preserve-root");
        let recursive = matches.opt_present("recursive");
        let fmode = matches.opt_str("reference").and_then(|fref| {
            let mut stat = unsafe { mem::uninitialized() };
            let statres = unsafe { libc::stat(fref.as_slice().as_ptr() as *const i8, &mut stat as *mut libc::stat) };
            if statres == 0 {
                Some(stat.st_mode)
            } else {
                crash!(1, "{}", IoError::last_error())
            }
        });
        let cmode =
            if fmode.is_none() {
                let mode = matches.free.remove(0).unwrap();  // there are at least two elements
                match verify_mode(mode.as_slice()) {
                    Ok(_) => Some(mode),
                    Err(f) => {
                        show_error!("{}", f);
                        return 1;
                    }
                }
            } else {
                None
            };
        match chmod(matches.free, changes, quiet, verbose, preserve_root,
                    recursive, fmode, cmode.as_ref()) {
            Ok(()) => {}
            Err(e) => return e
        }
    }

    0
}

#[cfg(unix)]
#[inline]
fn verify_mode(modes: &str) -> Result<(), String> {
    static REGEXP: regex::Regex = regex!(r"^[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+$");
    for mode in modes.split(',') {
        if !REGEXP.is_match(mode) {
            return Err(format!("invalid mode '{}'", mode));
        }
    }
    Ok(())
}

#[cfg(windows)]
#[inline]
// XXX: THIS IS NOT TESTED!!!
fn verify_mode(mode: &str) -> Result<(), String> {
    static REGEXP: regex::Regex = regex!(r"^[ugoa]*(?:[-+=](?:([rwxXst]*)|[ugo]))+|[-+=]?([0-7]+)$");
    for mode in modes.split(',') {
        match REGEXP.captures(mode) {
            Some(cap) => {
                let symbols = cap.at(1);
                let numbers = cap.at(2);
                if symbols.contains("s") || symbols.contains("t") {
                    return Err("The 's' and 't' modes are not supported on Windows".to_string());
                } else if numbers.len() >= 4 && numbers.slice_to(num_len - 3).find(|ch| ch != '0').is_some() {
                    return Err("Setuid, setgid, and sticky modes are not supported on Windows".to_string());
                }
            }
            None => return Err(format!("invalid mode '{}'", mode))
        }
    }
    Ok(())
}

fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve_root: bool, recursive: bool, fmode: Option<u32>, cmode: Option<&String>) -> Result<(), int> {
    let mut r = Ok(());

    for filename in files.iter() {
        let filename = filename.as_slice();
        let file = Path::new(filename);
        if file.exists() {
            if file.is_dir() {
                if !preserve_root || filename != "/" {
                    if recursive {
                        let walk_dir = match fs::walk_dir(&file) {
                            Ok(m) => m,
                            Err(f) => {
                                crash!(1, "{}", f.to_string());
                            }
                        };
                        r = chmod(walk_dir.map(|x| x.as_str().unwrap().to_string()).collect(), changes, quiet, verbose, preserve_root, recursive, fmode, cmode).and(r);
                        r = chmod_file(&file, filename, changes, quiet, verbose, fmode, cmode).and(r);
                    }
                } else {
                    show_error!("could not change permissions of directory '{}'",
                                filename);
                    r = Err(1);
                }
            } else {
                r = chmod_file(&file, filename.as_slice(), changes, quiet, verbose, fmode, cmode).and(r);
            }
        } else {
            show_error!("no such file or directory '{}'", filename);
            r = Err(1);
        }
    }

    r
}

fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<u32>, cmode: Option<&String>) -> Result<(), int> {
    let path = name.to_c_str();
    match fmode {
        Some(mode) => {
            if unsafe { libc::chmod(path.as_ptr(), mode) } == 0 {
                // TODO: handle changes, quiet, and verbose
            } else {
                show_error!("{}", IoError::last_error());
                return Err(1);
            }
        }
        None => {
            // TODO: make the regex processing occur earlier (i.e. once in the main function)
            static REGEXP: regex::Regex = regex!(r"^(([ugoa]*)((?:[-+=](?:[rwxXst]*|[ugo]))+))|([-+=]?[0-7]+)$");
            let mut stat = unsafe { mem::uninitialized() };
            let statres = unsafe { libc::stat(path.as_ptr(), &mut stat as *mut libc::stat) };
            let mut fperm =
                if statres == 0 {
                    stat.st_mode
                } else {
                    show_error!("{}", IoError::last_error());
                    return Err(1);
                };
            for mode in cmode.unwrap().as_slice().split(',') {  // cmode is guaranteed to be Some in this case
                let cap = REGEXP.captures(mode).unwrap();  // mode was verified earlier, so this is safe
                if cap.at(1) != "" {
                    // symbolic
                    let mut levels = cap.at(2);
                    if levels.len() == 0 {
                        levels = "a";
                    }
                    let change_str = cap.at(3).to_string() + "+";
                    let change = change_str.as_slice();
                    let mut action = change.char_at(0);
                    let mut rwx = 0;
                    let mut special = 0;
                    let mut special_changed = false;
                    for ch in change.slice_from(1).chars() {
                        match ch {
                            '+' | '-' | '=' => {
                                for level in levels.chars() {
                                    let (rwx, mask) = match level {
                                        'u' => (rwx << 6, 0o7077),
                                        'g' => (rwx << 3, 0o7707),
                                        'o' => (rwx, 0o7770),
                                        'a' => ((rwx << 6) | (rwx << 3) | rwx, 0o7000),
                                        _ => unreachable!()
                                    };
                                    match action {
                                        '+' => fperm |= rwx,
                                        '-' => fperm &= !rwx,
                                        '=' => fperm = (fperm & mask) | rwx,
                                        _ => unreachable!()
                                    }
                                }
                                if special_changed {
                                    match action {
                                        '+' => fperm |= special,
                                        '-' => fperm &= !special,
                                        '=' => fperm &= special | 0o0777,
                                        _ => unreachable!()
                                    }
                                }
                                action = ch;
                                rwx = 0;
                                special = 0;
                                special_changed = false;
                            }
                            'r' => rwx |= 0o004,
                            'w' => rwx |= 0o002,
                            'x' => rwx |= 0o001,
                            'X' => {
                                if file.is_dir() || (fperm & 0o0111) != 0 {
                                    rwx |= 0o001;
                                }
                            }
                            's' => {
                                special |= 0o4000 | 0o2000;
                                special_changed = true;
                            }
                            't' => {
                                special |= 0o1000;
                                special_changed = true;
                            }
                            'u' => rwx = (fperm >> 6) & 0o007,
                            'g' => rwx = (fperm >> 3) & 0o007,
                            'o' => rwx = (fperm >> 0) & 0o007,
                            _ => unreachable!()
                        }
                    }
                } else {
                    // numeric
                    let change = cap.at(4);
                    let ch = change.char_at(0);
                    let (action, slice) = match ch {
                        '+' | '-' | '=' => (ch, change.slice_from(1)),
                        _ => ('=', change)
                    };
                    let mode = from_str_radix::<u32>(slice, 8).unwrap();  // already verified
                    match action {
                        '+' => fperm |= mode,
                        '-' => fperm &= !mode,
                        '=' => fperm = mode,
                        _ => unreachable!()
                    }
                }
                if unsafe { libc::chmod(path.as_ptr(), fperm) } == 0 {
                    // TODO: see above
                } else {
                    show_error!("{}", IoError::last_error());
                    return Err(1);
                }
            }
        }
    }

    Ok(())
}
<commit_msg>chmod: fix build on freebsd<commit_after>#![crate_name = "chmod"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules, phase)]

#![allow(unused_variables)]  // only necessary while the TODOs still exist

extern crate getopts;
extern crate libc;
extern crate native;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;

use std::io::fs;
use std::io::fs::PathExtensions;
use std::io::IoError;
use std::mem;
use std::num::from_str_radix;
use regex::Regex;

#[path = "../common/util.rs"]
mod util;

const NAME: &'static str = "chmod";
const VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].clone();

    let opts = [
        getopts::optflag("c", "changes", "like verbose but report only when a change is made (unimplemented)"),
        getopts::optflag("f", "quiet", "suppress most error messages (unimplemented)"), // TODO: support --silent
        getopts::optflag("v", "verbose", "output a diagnostic for every file processed (unimplemented)"),
        getopts::optflag("", "no-preserve-root", "do not treat '/' specially (the default)"),
        getopts::optflag("", "preserve-root", "fail to operate recursively on '/'"),
        getopts::optflagopt("", "reference", "use RFILE's mode instead of MODE values", "RFILE"),
        getopts::optflag("R", "recursive", "change files and directories recursively"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit")
    ];
    // TODO: sanitize input for - at beginning (e.g. chmod -x testfile).  Solution is to add a to -x, making a-x
    let mut matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => {
            crash!(1, "{}", f)
        }
    };
    if matches.opt_present("help") {
        println!("{name} v{version}

Usage:
  {program} [OPTION]... MODE[,MODE]... FILE...
  {program} [OPTION]... OCTAL-MODE FILE...
  {program} [OPTION]... --reference=RFILE FILE...

{usage}
Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.",
               name = NAME, version = VERSION, program = program,
               usage = getopts::usage("Change the mode of each FILE to MODE. \
                                       With --reference, change the mode of \
                                       each FILE to that of RFILE.", &opts));
    } else if matches.opt_present("version") {
        println!("{} v{}", NAME, VERSION);
    } else if matches.free.is_empty() && matches.opt_present("reference") || matches.free.len() < 2 {
        show_error!("missing an argument");
        show_error!("for help, try '{} --help'", program);
        return 1;
    } else {
        let changes = matches.opt_present("changes");
        let quiet = matches.opt_present("quiet");
        let verbose = matches.opt_present("verbose");
        let preserve_root = matches.opt_present("preserve-root");
        let recursive = matches.opt_present("recursive");
        let fmode = matches.opt_str("reference").and_then(|fref| {
            let mut stat = unsafe { mem::uninitialized() };
            let statres = unsafe { libc::stat(fref.as_slice().as_ptr() as *const i8, &mut stat as *mut libc::stat) };
            if statres == 0 {
                Some(stat.st_mode)
            } else {
                crash!(1, "{}", IoError::last_error())
            }
        });
        let cmode =
            if fmode.is_none() {
                let mode = matches.free.remove(0).unwrap();  // there are at least two elements
                match verify_mode(mode.as_slice()) {
                    Ok(_) => Some(mode),
                    Err(f) => {
                        show_error!("{}", f);
                        return 1;
                    }
                }
            } else {
                None
            };
        match chmod(matches.free, changes, quiet, verbose, preserve_root,
                    recursive, fmode, cmode.as_ref()) {
            Ok(()) => {}
            Err(e) => return e
        }
    }

    0
}

#[cfg(unix)]
#[inline]
fn verify_mode(modes: &str) -> Result<(), String> {
    static REGEXP: regex::Regex = regex!(r"^[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+$");
    for mode in modes.split(',') {
        if !REGEXP.is_match(mode) {
            return Err(format!("invalid mode '{}'", mode));
        }
    }
    Ok(())
}

#[cfg(windows)]
#[inline]
// XXX: THIS IS NOT TESTED!!!
fn verify_mode(mode: &str) -> Result<(), String> {
    static REGEXP: regex::Regex = regex!(r"^[ugoa]*(?:[-+=](?:([rwxXst]*)|[ugo]))+|[-+=]?([0-7]+)$");
    for mode in modes.split(',') {
        match REGEXP.captures(mode) {
            Some(cap) => {
                let symbols = cap.at(1);
                let numbers = cap.at(2);
                if symbols.contains("s") || symbols.contains("t") {
                    return Err("The 's' and 't' modes are not supported on Windows".to_string());
                } else if numbers.len() >= 4 && numbers.slice_to(num_len - 3).find(|ch| ch != '0').is_some() {
                    return Err("Setuid, setgid, and sticky modes are not supported on Windows".to_string());
                }
            }
            None => return Err(format!("invalid mode '{}'", mode))
        }
    }
    Ok(())
}

fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve_root: bool, recursive: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), int> {
    let mut r = Ok(());

    for filename in files.iter() {
        let filename = filename.as_slice();
        let file = Path::new(filename);
        if file.exists() {
            if file.is_dir() {
                if !preserve_root || filename != "/" {
                    if recursive {
                        let walk_dir = match fs::walk_dir(&file) {
                            Ok(m) => m,
                            Err(f) => {
                                crash!(1, "{}", f.to_string());
                            }
                        };
                        r = chmod(walk_dir.map(|x| x.as_str().unwrap().to_string()).collect(), changes, quiet, verbose, preserve_root, recursive, fmode, cmode).and(r);
                        r = chmod_file(&file, filename, changes, quiet, verbose, fmode, cmode).and(r);
                    }
                } else {
                    show_error!("could not change permissions of directory '{}'",
                                filename);
                    r = Err(1);
                }
            } else {
                r = chmod_file(&file, filename.as_slice(), changes, quiet, verbose, fmode, cmode).and(r);
            }
        } else {
            show_error!("no such file or directory '{}'", filename);
            r = Err(1);
        }
    }

    r
}

fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), int> {
    let path = name.to_c_str();
    match fmode {
        Some(mode) => {
            if unsafe { libc::chmod(path.as_ptr(), mode) } == 0 {
                // TODO: handle changes, quiet, and verbose
            } else {
                show_error!("{}", IoError::last_error());
                return Err(1);
            }
        }
        None => {
            // TODO: make the regex processing occur earlier (i.e. once in the main function)
            static REGEXP: regex::Regex = regex!(r"^(([ugoa]*)((?:[-+=](?:[rwxXst]*|[ugo]))+))|([-+=]?[0-7]+)$");
            let mut stat = unsafe { mem::uninitialized() };
            let statres = unsafe { libc::stat(path.as_ptr(), &mut stat as *mut libc::stat) };
            let mut fperm =
                if statres == 0 {
                    stat.st_mode
                } else {
                    show_error!("{}", IoError::last_error());
                    return Err(1);
                };
            for mode in cmode.unwrap().as_slice().split(',') {  // cmode is guaranteed to be Some in this case
                let cap = REGEXP.captures(mode).unwrap();  // mode was verified earlier, so this is safe
                if cap.at(1) != "" {
                    // symbolic
                    let mut levels = cap.at(2);
                    if levels.len() == 0 {
                        levels = "a";
                    }
                    let change_str = cap.at(3).to_string() + "+";
                    let change = change_str.as_slice();
                    let mut action = change.char_at(0);
                    let mut rwx = 0;
                    let mut special = 0;
                    let mut special_changed = false;
                    for ch in change.slice_from(1).chars() {
                        match ch {
                            '+' | '-' | '=' => {
                                for level in levels.chars() {
                                    let (rwx, mask) = match level {
                                        'u' => (rwx << 6, 0o7077),
                                        'g' => (rwx << 3, 0o7707),
                                        'o' => (rwx, 0o7770),
                                        'a' => ((rwx << 6) | (rwx << 3) | rwx, 0o7000),
                                        _ => unreachable!()
                                    };
                                    match action {
                                        '+' => fperm |= rwx,
                                        '-' => fperm &= !rwx,
                                        '=' => fperm = (fperm & mask) | rwx,
                                        _ => unreachable!()
                                    }
                                }
                                if special_changed {
                                    match action {
                                        '+' => fperm |= special,
                                        '-' => fperm &= !special,
                                        '=' => fperm &= special | 0o0777,
                                        _ => unreachable!()
                                    }
                                }
                                action = ch;
                                rwx = 0;
                                special = 0;
                                special_changed = false;
                            }
                            'r' => rwx |= 0o004,
                            'w' => rwx |= 0o002,
                            'x' => rwx |= 0o001,
                            'X' => {
                                if file.is_dir() || (fperm & 0o0111) != 0 {
                                    rwx |= 0o001;
                                }
                            }
                            's' => {
                                special |= 0o4000 | 0o2000;
                                special_changed = true;
                            }
                            't' => {
                                special |= 0o1000;
                                special_changed = true;
                            }
                            'u' => rwx = (fperm >> 6) & 0o007,
                            'g' => rwx = (fperm >> 3) & 0o007,
                            'o' => rwx = (fperm >> 0) & 0o007,
                            _ => unreachable!()
                        }
                    }
                } else {
                    // numeric
                    let change = cap.at(4);
                    let ch = change.char_at(0);
                    let (action, slice) = match ch {
                        '+' | '-' | '=' => (ch, change.slice_from(1)),
                        _ => ('=', change)
                    };
                    let mode = from_str_radix::<u32>(slice, 8).unwrap() as libc::mode_t;  // already verified
                    match action {
                        '+' => fperm |= mode,
                        '-' => fperm &= !mode,
                        '=' => fperm = mode,
                        _ => unreachable!()
                    }
                }
                if unsafe { libc::chmod(path.as_ptr(), fperm) } == 0 {
                    // TODO: see above
                } else {
                    show_error!("{}", IoError::last_error());
                    return Err(1);
                }
            }
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>#[derive(Debug)]
#[derive(Clone)]
pub struct Session {
    pub name: String,
    pub tmp_window_name: String
}

#[derive(Debug)]
#[derive(Clone)]
pub struct Window {
    pub session_name: String,
    pub name: String,
    pub root: Option<String>
}

#[derive(Debug)]
#[derive(Clone)]
pub struct Split {
    pub target: String,
    pub root: Option<String>
}

#[derive(Debug)]
#[derive(Clone)]
pub struct Layout {
    pub target: String,
    pub layout: String,
}

#[derive(Debug)]
#[derive(Clone)]
pub struct SendKeys {
    pub target: String,
    pub exec: String
}

#[derive(Debug)]
#[derive(Clone)]
pub struct Attach {
    pub name: String
}

#[derive(Debug)]
#[derive(Clone)]
pub struct KillWindow {
    pub name: String
}

#[derive(Debug)]
#[derive(Clone)]
pub enum Command {
    Session(Session),
    Window(Window),
    Split(Split),
    Layout(Layout),
    SendKeys(SendKeys),
    Attach(Attach),
    KillWindow(KillWindow)
}
<commit_msg>Document the Command enum and related structs.<commit_after>//! The structures used to manage commands sent over to tmux.

/// The Session command is used to fire up a new daemonized session in tmux.
/// name: The Name of a named tmux session.
/// tmp_window_name: The randomized tmp window name created for the first window
/// of the session. This window is closed before attaching.
#[derive(Debug)]
#[derive(Clone)]
pub struct Session {
    pub name: String,
    pub tmp_window_name: String
}

/// The Window command is used to identify every new window opened in the tmux
/// session.
/// session_name: The name of the session.
/// name: The named window to be opened.
/// root: An `Option<String>` containing a possible root directory passed to the
/// `-c` arguement.
#[derive(Debug)]
#[derive(Clone)]
pub struct Window {
    pub session_name: String,
    pub name: String,
    pub root: Option<String>
}

/// The Split is used to call split-window on a particular window in the
/// session.
/// target: The target window. In the format `{session}:{window}.{paneIndex}`.
/// root: An `Option<String>` containing a possible root directory passed to the
/// `-c` arguement.
#[derive(Debug)]
#[derive(Clone)]
pub struct Split {
    pub target: String,
    pub root: Option<String>
}

/// The Layout command calls select-layout with a specific pre-defined tmux
/// layout option see `tmux select-layout --help` for more options.
/// target: The target window. In the format `{session}:{window}.{paneIndex}`.
/// layout: The type of layout. ex `main-horizontal`.
#[derive(Debug)]
#[derive(Clone)]
pub struct Layout {
    pub target: String,
    pub layout: String,
}

/// A generic SendKeys command used to send "typed" commands to tmux. This is
/// used to initialize processes or tasks in specific window. Such as starting log
/// tails or running servers.
/// target: The target window. In the format `{session}:{window}.{paneIndex}`.
/// exec: The cli command to be run. ex. `tail -f logs/development.log`.
#[derive(Debug)]
#[derive(Clone)]
pub struct SendKeys {
    pub target: String,
    pub exec: String
}

/// Used to attach to the daemonized session.
/// name: The named session to attach too.
#[derive(Debug)]
#[derive(Clone)]
pub struct Attach {
    pub name: String
}

/// Sends the kill-window command. Used to kill off the randomized first pane
/// opened with the new session.
/// name: the name of the window to kill.
#[derive(Debug)]
#[derive(Clone)]
pub struct KillWindow {
    pub name: String
}

/// The Command enum. Commands represent the series of commands sent to the
/// running tmux process to build a users env. This is an enum to support
/// containing all the commands that require running in a single Vec. This
/// allows a simple process of first in, first out command execution.
#[derive(Debug)]
#[derive(Clone)]
pub enum Command {
    Session(Session),
    Window(Window),
    Split(Split),
    Layout(Layout),
    SendKeys(SendKeys),
    Attach(Attach),
    KillWindow(KillWindow)
}
<|endoftext|>


<commit_before>use http::status::Status;
use http::status::Status::{Forbidden, NotFound, InternalServerError};
use nickel::{
    Continue,
    ErrorWithStatusCode,
    Halt,
    MiddlewareResult,
    NickelError,
    Request,
    Response,
};
use nickel::mimes::MediaType;
use rustdoc::html::markdown::Markdown;
use std::collections::HashMap;
use std::io::{
    BufferedReader,
    File
};

use parser;

/// Render the index page.
pub fn root_handler(_request: &Request, response: &mut Response) {
    let mut data = HashMap::<&str, &str>::new();
    data.insert("name", "user");
    response.render("assets/templates/index.tpl", &data);
}

pub fn get_blog_post(request: &Request, response: &mut Response) {
    // Retrieve the post id from the request URL.
    let post_year = request.param("post_year");
    let post_id = request.param("post_id");
    let post_path = Path::new("assets/content/posts/".to_string() +
            post_year.to_string() +
            "/".to_string() +
            post_id.to_string() +
            ".md".to_string());

    // Read the post markdown from the disk.
    let content = File::open(&post_path).read_to_end().unwrap();
    let content = String::from_utf8(content).unwrap();
    let post = match parser::post(content.as_slice()) {
        Ok(post) => post,
        Err(e) => {
            error!("Failed to parse post: {}", e);
            handle_error(InternalServerError, "500", "An internal error has occurred!", response);
            return
        }
    };
    let html_content = format!("{}", Markdown(post.content()));

    let mut data = HashMap::<&str, &str>::new();
    data.insert("content", html_content.as_slice());
    response.render("assets/templates/post.tpl", &data);
}

pub fn custom_errors(err: &NickelError, _req: &Request, response: &mut Response) -> MiddlewareResult {
    match err.kind {
        ErrorWithStatusCode(Forbidden) => {
            handle_error(Forbidden, "403", "You are not authorized to view this page", response);
            Ok(Halt)
        },
        ErrorWithStatusCode(NotFound) => {
            handle_error(NotFound, "404", "That file could not be found.", response);
            Ok(Halt)
        },
        ErrorWithStatusCode(InternalServerError) => {
            handle_error(InternalServerError, "500", "An error has occured!", response);
            Ok(Halt)
        },
        _ => Ok(Continue)
    }
}

fn handle_error(status_code: Status, error_code: &str, error_message: &str, res: &mut Response) {
    let mut data = HashMap::<&str, &str>::new();

    data.insert("site_url", "http://nikitapek.in");
    data.insert("error_code", error_code);
    data.insert("error_message", error_message);

    res.content_type(MediaType::Html)
       .status_code(status_code)
       .render("assets/templates/error.tpl", &data);
}
<commit_msg>Remove unused import<commit_after>use http::status::Status;
use http::status::Status::{Forbidden, NotFound, InternalServerError};
use nickel::{
    Continue,
    ErrorWithStatusCode,
    Halt,
    MiddlewareResult,
    NickelError,
    Request,
    Response,
};
use nickel::mimes::MediaType;
use rustdoc::html::markdown::Markdown;
use std::collections::HashMap;
use std::io::File;

use parser;

/// Render the index page.
pub fn root_handler(_request: &Request, response: &mut Response) {
    let mut data = HashMap::<&str, &str>::new();
    data.insert("name", "user");
    response.render("assets/templates/index.tpl", &data);
}

pub fn get_blog_post(request: &Request, response: &mut Response) {
    // Retrieve the post id from the request URL.
    let post_year = request.param("post_year");
    let post_id = request.param("post_id");
    let post_path = Path::new("assets/content/posts/".to_string() +
            post_year.to_string() +
            "/".to_string() +
            post_id.to_string() +
            ".md".to_string());

    // Read the post markdown from the disk.
    let content = File::open(&post_path).read_to_end().unwrap();
    let content = String::from_utf8(content).unwrap();
    let post = match parser::post(content.as_slice()) {
        Ok(post) => post,
        Err(e) => {
            error!("Failed to parse post: {}", e);
            handle_error(InternalServerError, "500", "An internal error has occurred!", response);
            return
        }
    };
    let html_content = format!("{}", Markdown(post.content()));

    let mut data = HashMap::<&str, &str>::new();
    data.insert("content", html_content.as_slice());
    response.render("assets/templates/post.tpl", &data);
}

pub fn custom_errors(err: &NickelError, _req: &Request, response: &mut Response) -> MiddlewareResult {
    match err.kind {
        ErrorWithStatusCode(Forbidden) => {
            handle_error(Forbidden, "403", "You are not authorized to view this page", response);
            Ok(Halt)
        },
        ErrorWithStatusCode(NotFound) => {
            handle_error(NotFound, "404", "That file could not be found.", response);
            Ok(Halt)
        },
        ErrorWithStatusCode(InternalServerError) => {
            handle_error(InternalServerError, "500", "An error has occured!", response);
            Ok(Halt)
        },
        _ => Ok(Continue)
    }
}

fn handle_error(status_code: Status, error_code: &str, error_message: &str, res: &mut Response) {
    let mut data = HashMap::<&str, &str>::new();

    data.insert("site_url", "http://nikitapek.in");
    data.insert("error_code", error_code);
    data.insert("error_message", error_message);

    res.content_type(MediaType::Html)
       .status_code(status_code)
       .render("assets/templates/error.tpl", &data);
}
<|endoftext|>