<commit_before>//
//    Stachanov
//    Copyright (C) 2017 Stachanov Developer Collective
//
//    This file is part of Stachanov.
//
//    This program is free software: you can redistribute it and/or
//    modify it under the terms of the GNU Affero General Public
//    License, version 3, as published by the Free Software Foundation.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the
//               GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

use blockchain::block::Block;
use blockchain::block::BlockId;
use blockchain::errors::IdCollisionError;
use blockchain::transactions::TxId;
use blockchain::transactions::TxLinkMap;
use blockchain::transactions::Transaction;

pub trait Hashable {
    fn to_sha3_hash(&self) -> [u8; 32];
}

/// The `ChainStorage` trait must be implemented by all storage backends.
/// We allow for different backends (redis, postgres, etc) as not
/// every storage type fits for every service built around the core.

pub trait ChainStorage{

    /// Fetches a block identified by its unique block id
    /// * `block_id`: The block identifier (equivalent to the
    ///               the sha3 hash of the block header)

    fn get_block(&self, block_id: BlockId) -> Option<Block>;

    /// Fetches the block *after* the supplied block id. This
    /// is mainly an interface for block iteration.
    /// * `block_id`: The block identifier (equivalent to the
    ///               the sha3 hash of the block header)

    fn get_after(&self, block_id: BlockId) -> Option<Block>;

    /// Fetches the block that has a timestamp greater or
    /// equal to the specified timestamp.
    /// * `timestamp`: A unix timestamp

    // NOTE: This is a difference to the bitcoin timestamp
    // implementation. In stachanov a block header must have a
    // timestamp greater than the timestamp of its predecessor

    fn get_after_timestamp(&self, timestamp: u64) -> Option<Block>;

    /// Fetches the last block in the whole chain

    fn get_tail_block(&self) -> Option<Block>;

    /// Append a block to the chain *without* checking its
    /// validity. Will return an IdCollisionError if there
    /// already is a block with the same block id.
    /// * `block`: The verified block

    fn append_verified_block(&mut self, block: Block) -> Result<(), IdCollisionError>;

    /// Fetches a transaction identifier by its id
    /// * `tx_id`: the transaction id

    fn get_transaction(&self, tx_id: TxId) -> Option<Transaction>;

    /// Fetches the link map of a transaction
    /// * `tx_id`: the transaction id

    fn get_linkmap(&self, tx_id: TxId) -> Option<TxLinkMap>;

    /// Updates the TxLinkMap of a transaction
    /// * `tx_id`: the transaction id
    /// * `map`: the appropriate link map

    fn set_linkmap(&mut self, tx_id: TxId, map: TxLinkMap);

}
<commit_msg>ADD Reset function for ChainStorage<commit_after>//
//    Stachanov
//    Copyright (C) 2017 Stachanov Developer Collective
//
//    This file is part of Stachanov.
//
//    This program is free software: you can redistribute it and/or
//    modify it under the terms of the GNU Affero General Public
//    License, version 3, as published by the Free Software Foundation.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the
//               GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

use blockchain::block::Block;
use blockchain::block::BlockId;
use blockchain::errors::IdCollisionError;
use blockchain::transactions::TxId;
use blockchain::transactions::TxLinkMap;
use blockchain::transactions::Transaction;

pub trait Hashable {
    fn to_sha3_hash(&self) -> [u8; 32];
}

/// The `ChainStorage` trait must be implemented by all storage backends.
/// We allow for different backends (redis, postgres, etc) as not
/// every storage type fits for every service built around the core.

pub trait ChainStorage{

    /// Fetches a block identified by its unique block id
    /// * `block_id`: The block identifier (equivalent to the
    ///               the sha3 hash of the block header)

    fn get_block(&self, block_id: BlockId) -> Option<Block>;

    /// Fetches the block *after* the supplied block id. This
    /// is mainly an interface for block iteration.
    /// * `block_id`: The block identifier (equivalent to the
    ///               the sha3 hash of the block header)

    fn get_after(&self, block_id: BlockId) -> Option<Block>;

    /// Fetches the block that has a timestamp greater or
    /// equal to the specified timestamp.
    /// * `timestamp`: A unix timestamp

    // NOTE: This is a difference to the bitcoin timestamp
    // implementation. In stachanov a block header must have a
    // timestamp greater than the timestamp of its predecessor

    fn get_after_timestamp(&self, timestamp: u64) -> Option<Block>;

    /// Fetches the last block in the whole chain

    fn get_tail_block(&self) -> Option<Block>;

    /// Append a block to the chain *without* checking its
    /// validity. Will return an IdCollisionError if there
    /// already is a block with the same block id.
    /// * `block`: The verified block

    fn append_verified_block(&mut self, block: Block) -> Result<(), IdCollisionError>;

    /// Fetches a transaction identifier by its id
    /// * `tx_id`: the transaction id

    fn get_transaction(&self, tx_id: TxId) -> Option<Transaction>;

    /// Fetches the link map of a transaction
    /// * `tx_id`: the transaction id

    fn get_linkmap(&self, tx_id: TxId) -> Option<TxLinkMap>;

    /// Updates the TxLinkMap of a transaction
    /// * `tx_id`: the transaction id
    /// * `map`: the appropriate link map

    fn set_linkmap(&mut self, tx_id: TxId, map: TxLinkMap);

    /// Removes all data from the storage

    fn reset(&mut self);

}
<|endoftext|>


<commit_before>use super::Position;
use super::Range;
use std::str::from_utf8;

/// A UTF-8 string buffer designed to minimize reallocations,
/// maintaining performance amid frequent modifications.
pub struct GapBuffer {
    data: Vec<u8>,
    gap_start: usize,
    gap_length: usize,
}

/// Initializes a gap buffer with the specified data as its contents.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::gap_buffer::new("scribe".to_string());
/// assert_eq!(buffer.to_string(), "scribe");
/// ```
pub fn new(mut data: String) -> GapBuffer {
    let mut bytes = data.into_bytes();
    let capacity = bytes.capacity();
    let gap_start = bytes.len();
    let gap_length = capacity - gap_start;
    unsafe {
        bytes.set_len(capacity);
    }
    GapBuffer{ data: bytes, gap_start: gap_start, gap_length: gap_length }
}

impl GapBuffer {
    /// Inserts the specified data into the buffer at the specified position.
    /// The buffer will reallocate if there is insufficient space. If the
    /// position is out of bounds, the buffer contents will remain unchanged.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::gap_buffer::new("my buffer data".to_string());
    /// buffer.insert(" changed", &scribe::buffer::Position{ line: 0, offset: 2});
    /// assert_eq!("my changed buffer data", buffer.to_string());
    /// ```
    pub fn insert(&mut self, data: &str, position: &Position) {
        // Ensure we have the capacity to insert this data.
        if data.len() > self.gap_length {
            // TODO: Move gap to the end before resizing buffer.
            self.data.reserve(data.len());
            let capacity = self.data.capacity();
            self.gap_length = capacity - self.gap_start;
            unsafe {
                self.data.set_len(capacity);
            }
        }

        let offset = match self.find_offset(position) {
            Some(o) => o,
            None => return,
        };

        self.move_gap(offset);
        self.write_to_gap(data);
    }

    /// Returns a string representation of the buffer data (without gap).
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::gap_buffer::new("my data".to_string());
    /// assert_eq!(buffer.to_string(), "my data");
    /// ```
    pub fn to_string(&self) -> String {
        from_utf8(&self.data[..self.gap_start]).unwrap().to_string() + from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap()
    }

    /// Removes the specified range of data from the buffer.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::gap_buffer::new("my data".to_string());
    /// let range = scribe::buffer::Range{ start: scribe::buffer::Position{ line: 0, offset: 0 },
    ///   end: scribe::buffer::Position{ line: 0, offset: 3} };
    /// buffer.remove(&range);
    /// assert_eq!(buffer.to_string(), "data");
    /// ```
    pub fn remove(&mut self, range: &Range) {
        let start_offset = match self.find_offset(&range.start) {
            Some(o) => o,
            None => return,
        };
        self.move_gap(start_offset);

        let end_offset = match self.find_offset(&range.end) {
            Some(o) => o,
            None => return,
        };
        self.gap_length=end_offset-start_offset;
    }

    // Maps a position to its offset equivalent in the data.
    fn find_offset(&self, position: &Position) -> Option<usize> {
        let first_half = from_utf8(&self.data[..self.gap_start]).unwrap();
        let mut line = 0;
        let mut line_offset = 0;

        for char_index in first_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We didn't find the position *within* the first half, but it could
        // be right after it, which means it's right at the start of the gap.
        if line == position.line && line_offset == position.offset {
            return Some(self.gap_start);
        }

        // We haven't reached the position yet, so we'll move on to the other half.
        let second_half = from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap();
        for char_index in second_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(self.gap_start + self.gap_length + offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We didn't find the position *within* the second half, but it could
        // be right after it, which means it's at the end of the buffer.
        if line == position.line && line_offset == position.offset {
            return Some(self.data.len());
        }

        None
    }

    fn move_gap(&mut self, offset: usize) {
        // We don't need to move any data if the buffer is at capacity.
        if self.gap_length == 0 {
            self.gap_start = offset;
            return;
        }

        if offset < self.gap_start {
            // Shift the gap to the left one byte at a time.
            for index in (offset..self.gap_start) {
                self.data[index + self.gap_length] = self.data[index];
                self.data[index] = 0;
            }

            self.gap_start = offset;
        } else if offset > self.gap_start {
            // Shift the gap to the right one byte at a time.
            for index in (self.gap_start+self.gap_length..offset) {
                self.data[index-self.gap_length] = self.data[index];
                self.data[index] = 0;
            }

            // Because the offset was after the gap, its value included the
            // gap length. We must remove it to determine the starting point.
            self.gap_start = offset - self.gap_length;
        }
    }

    fn write_to_gap(&mut self, data: &str) {
        for byte in data.bytes() {
            self.data[self.gap_start] = byte;
            self.gap_start+=1;
            self.gap_length-=1;
        }
    }
}

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

    #[test]
    fn move_gap_works() {
        let mut gb = new("This is a test.".to_string());
        gb.move_gap(0);
        assert_eq!(gb.to_string(), "This is a test.");
    }

    #[test]
    fn inserting_at_the_start_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert("Hi. ", &Position { line: 0, offset: 0 });
        assert_eq!(gb.to_string(), "Hi. This is a test.");
    }

    #[test]
    fn inserting_in_the_middle_works() {
        let mut gb = new("This is a test.\nPlease be gentle.".to_string());
        gb.insert(" very", &Position { line: 1, offset: 9 });
        assert_eq!(gb.to_string(), "This is a test.\nPlease be very gentle.");
    }

    #[test]
    fn inserting_at_the_end_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert(" Seriously.", &Position { line: 0, offset: 15 });
        assert_eq!(gb.to_string(), "This is a test. Seriously.");
    }

    #[test]
    fn inserting_in_different_spots_twice_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert("Hi. ", &Position { line: 0, offset: 0 });
        gb.insert(" Thank you.", &Position { line: 0, offset: 19 });
        assert_eq!(gb.to_string(), "Hi. This is a test. Thank you.");
    }

    #[test]
    fn inserting_at_an_invalid_position_does_nothing() {
        let mut gb = new("This is a test.".to_string());
        gb.insert(" Seriously.", &Position { line: 0, offset: 35 });
        assert_eq!(gb.to_string(), "This is a test.");
    }

    #[test]
    fn removing_works() {
        let mut gb = new("This is a test.\nSee what happens.".to_string());
        let start = Position{ line: 0, offset: 8 };
        let end = Position{ line: 1, offset: 4 };
        gb.remove(&Range{ start: start, end: end });
        assert_eq!(gb.to_string(), "This is what happens.");
    }
}
<commit_msg>Implement gap buffer in_bounds method.<commit_after>use super::Position;
use super::Range;
use std::str::from_utf8;

/// A UTF-8 string buffer designed to minimize reallocations,
/// maintaining performance amid frequent modifications.
pub struct GapBuffer {
    data: Vec<u8>,
    gap_start: usize,
    gap_length: usize,
}

/// Initializes a gap buffer with the specified data as its contents.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::gap_buffer::new("scribe".to_string());
/// assert_eq!(buffer.to_string(), "scribe");
/// ```
pub fn new(mut data: String) -> GapBuffer {
    let mut bytes = data.into_bytes();
    let capacity = bytes.capacity();
    let gap_start = bytes.len();
    let gap_length = capacity - gap_start;
    unsafe {
        bytes.set_len(capacity);
    }
    GapBuffer{ data: bytes, gap_start: gap_start, gap_length: gap_length }
}

impl GapBuffer {
    /// Inserts the specified data into the buffer at the specified position.
    /// The buffer will reallocate if there is insufficient space. If the
    /// position is out of bounds, the buffer contents will remain unchanged.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::gap_buffer::new("my buffer data".to_string());
    /// buffer.insert(" changed", &scribe::buffer::Position{ line: 0, offset: 2});
    /// assert_eq!("my changed buffer data", buffer.to_string());
    /// ```
    pub fn insert(&mut self, data: &str, position: &Position) {
        // Ensure we have the capacity to insert this data.
        if data.len() > self.gap_length {
            // TODO: Move gap to the end before resizing buffer.
            self.data.reserve(data.len());
            let capacity = self.data.capacity();
            self.gap_length = capacity - self.gap_start;
            unsafe {
                self.data.set_len(capacity);
            }
        }

        let offset = match self.find_offset(position) {
            Some(o) => o,
            None => return,
        };

        self.move_gap(offset);
        self.write_to_gap(data);
    }

    /// Returns a string representation of the buffer data (without gap).
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::gap_buffer::new("my data".to_string());
    /// assert_eq!(buffer.to_string(), "my data");
    /// ```
    pub fn to_string(&self) -> String {
        from_utf8(&self.data[..self.gap_start]).unwrap().to_string() + from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap()
    }

    /// Removes the specified range of data from the buffer.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::gap_buffer::new("my data".to_string());
    /// let range = scribe::buffer::Range{ start: scribe::buffer::Position{ line: 0, offset: 0 },
    ///   end: scribe::buffer::Position{ line: 0, offset: 3} };
    /// buffer.remove(&range);
    /// assert_eq!(buffer.to_string(), "data");
    /// ```
    pub fn remove(&mut self, range: &Range) {
        let start_offset = match self.find_offset(&range.start) {
            Some(o) => o,
            None => return,
        };
        self.move_gap(start_offset);

        let end_offset = match self.find_offset(&range.end) {
            Some(o) => o,
            None => return,
        };
        self.gap_length=end_offset-start_offset;
    }

    /// Checks whether or not the specified position is in bounds of the buffer data.
    ///
    /// # Examples
    ///
    /// ```
    /// let buffer = scribe::buffer::gap_buffer::new("scribe".to_string());
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 0 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 1, offset: 3 };
    ///
    /// assert_eq!(buffer.in_bounds(&in_bounds), true);
    /// assert_eq!(buffer.in_bounds(&out_of_bounds), false);
    /// ```
    pub fn in_bounds(&self, position: &Position) -> bool {
        self.find_offset(position) != None
    }

    // Maps a position to its offset equivalent in the data.
    fn find_offset(&self, position: &Position) -> Option<usize> {
        let first_half = from_utf8(&self.data[..self.gap_start]).unwrap();
        let mut line = 0;
        let mut line_offset = 0;

        for char_index in first_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We didn't find the position *within* the first half, but it could
        // be right after it, which means it's right at the start of the gap.
        if line == position.line && line_offset == position.offset {
            return Some(self.gap_start);
        }

        // We haven't reached the position yet, so we'll move on to the other half.
        let second_half = from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap();
        for char_index in second_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(self.gap_start + self.gap_length + offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We didn't find the position *within* the second half, but it could
        // be right after it, which means it's at the end of the buffer.
        if line == position.line && line_offset == position.offset {
            return Some(self.data.len());
        }

        None
    }

    fn move_gap(&mut self, offset: usize) {
        // We don't need to move any data if the buffer is at capacity.
        if self.gap_length == 0 {
            self.gap_start = offset;
            return;
        }

        if offset < self.gap_start {
            // Shift the gap to the left one byte at a time.
            for index in (offset..self.gap_start) {
                self.data[index + self.gap_length] = self.data[index];
                self.data[index] = 0;
            }

            self.gap_start = offset;
        } else if offset > self.gap_start {
            // Shift the gap to the right one byte at a time.
            for index in (self.gap_start+self.gap_length..offset) {
                self.data[index-self.gap_length] = self.data[index];
                self.data[index] = 0;
            }

            // Because the offset was after the gap, its value included the
            // gap length. We must remove it to determine the starting point.
            self.gap_start = offset - self.gap_length;
        }
    }

    fn write_to_gap(&mut self, data: &str) {
        for byte in data.bytes() {
            self.data[self.gap_start] = byte;
            self.gap_start+=1;
            self.gap_length-=1;
        }
    }
}

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

    #[test]
    fn move_gap_works() {
        let mut gb = new("This is a test.".to_string());
        gb.move_gap(0);
        assert_eq!(gb.to_string(), "This is a test.");
    }

    #[test]
    fn inserting_at_the_start_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert("Hi. ", &Position { line: 0, offset: 0 });
        assert_eq!(gb.to_string(), "Hi. This is a test.");
    }

    #[test]
    fn inserting_in_the_middle_works() {
        let mut gb = new("This is a test.\nPlease be gentle.".to_string());
        gb.insert(" very", &Position { line: 1, offset: 9 });
        assert_eq!(gb.to_string(), "This is a test.\nPlease be very gentle.");
    }

    #[test]
    fn inserting_at_the_end_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert(" Seriously.", &Position { line: 0, offset: 15 });
        assert_eq!(gb.to_string(), "This is a test. Seriously.");
    }

    #[test]
    fn inserting_in_different_spots_twice_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert("Hi. ", &Position { line: 0, offset: 0 });
        gb.insert(" Thank you.", &Position { line: 0, offset: 19 });
        assert_eq!(gb.to_string(), "Hi. This is a test. Thank you.");
    }

    #[test]
    fn inserting_at_an_invalid_position_does_nothing() {
        let mut gb = new("This is a test.".to_string());
        gb.insert(" Seriously.", &Position { line: 0, offset: 35 });
        assert_eq!(gb.to_string(), "This is a test.");
    }

    #[test]
    fn removing_works() {
        let mut gb = new("This is a test.\nSee what happens.".to_string());
        let start = Position{ line: 0, offset: 8 };
        let end = Position{ line: 1, offset: 4 };
        gb.remove(&Range{ start: start, end: end });
        assert_eq!(gb.to_string(), "This is what happens.");
    }
}
<|endoftext|>


<commit_before>use std::io::{BufRead, BufReader};
use std::net::{TcpListener, ToSocketAddrs};
use std::sync::mpsc::{channel, Sender};
use std::thread;

use super::super::SharedStore;
use super::super::parsers::statsd::parse_metrics;

pub struct StatsdTcpListener {
    store: SharedStore,
}

impl StatsdTcpListener {
    pub fn new(store: SharedStore) -> StatsdTcpListener {
        StatsdTcpListener {
            store: store,
        }
    }

    pub fn listen<A>(&self, addr: A)
        where A: ToSocketAddrs {
        let (send, recv) = channel();

        let listener = TcpListener::bind(addr).unwrap();
        thread::spawn(move || {
            accept_on_listener(listener, send)
        });

        for line in recv {
            self.handle_line(line)
        }
    }

    fn handle_line(&self, line: String) {
        let line_trimmed = line.trim_right();
        let result = parse_metrics(line_trimmed.as_bytes());

        match result {
            Ok(metrics) => {
                let metrics = metrics.iter().map(|m| m.to_standard_metric()).collect();
                self.store.record(metrics)
            },
            _ => (),
        }
    }
}

fn accept_on_listener(listener: TcpListener, send: Sender<String>) {
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                let mut reader = BufReader::new(stream);
                let mut line = String::new();

                reader.read_line(&mut line).unwrap();
                send.send(line).unwrap();
            },
            Err(e) => panic!("Failed to listen on TCP socket: {}", e),
        }
    }
}
<commit_msg>Make StatsD TCP server handle multiple clients and failures<commit_after>use std::io::{BufRead, BufReader};
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::Duration;

use super::super::SharedStore;
use super::super::parsers::statsd::parse_metrics;

/// Listens on a TCP socket for StatsD messages.
pub struct StatsdTcpListener {
    store: SharedStore,
}

impl StatsdTcpListener {
    pub fn new(store: SharedStore) -> StatsdTcpListener {
        StatsdTcpListener {
            store: store,
        }
    }

    pub fn listen<A>(&self, addr: A)
        where A: ToSocketAddrs {
        let (send, recv) = channel();

        let listener = TcpListener::bind(addr).unwrap();
        thread::spawn(move || {
            StatsdTcpListener::accept_on_listener(listener, send)
        });

        for line in recv {
            self.handle_line(line)
        }
    }

    fn handle_line(&self, line: String) {
        let line_trimmed = line.trim_right();
        let result = parse_metrics(line_trimmed.as_bytes());

        match result {
            Ok(metrics) => {
                let metrics = metrics.iter().map(|m| m.to_standard_metric()).collect();
                self.store.record(metrics)
            },
            Err(err) => {
                println!("{:?}", err)
            },
        }
    }

    fn accept_on_listener(listener: TcpListener, send: Sender<String>) {
        for stream in listener.incoming() {
            match stream {
                Ok(stream) => {
                    // Clients have 30 seconds to send us data before we'll drop.
                    let _ = stream.set_read_timeout(Some(Duration::from_secs(30)));

                    let send = send.clone();

                    thread::spawn(move || {
                        StatsdTcpListener::handle_client(stream, send)
                    });
                },
                Err(e) => panic!("Failed to listen on TCP socket: {}", e),
            }
        }
    }

    fn handle_client(stream: TcpStream, send: Sender<String>) {
        let mut reader = BufReader::new(stream);

        loop {
            let mut line = String::new();

            match reader.read_line(&mut line) {
                Err(err) => {
                    println!("Error reading StatsD line: {:?}", err);
                    break
                },
                Ok(0) => {
                    // Close if there are no more bytes.
                    break
                },
                Ok(_) => {
                    send.send(line).unwrap()
                },
            }
        }
    }

}
<|endoftext|>


<commit_before>//! Implements a command for managing releases.
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::collections::HashSet;

use clap::{App, AppSettings, Arg, ArgMatches};
use walkdir::WalkDir;

use prelude::*;
use api::{Api, NewRelease};
use config::Config;
use utils::make_subcommand;
use sourcemaps::SourceMapValidator;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("manage releases on Sentry")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .subcommand(make_subcommand("new")
            .about("Create a new release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version identifier for this release"))
            .arg(Arg::with_name("ref")
                 .long("ref")
                 .value_name("REF")
                 .help("Optional commit reference (commit hash)"))
            .arg(Arg::with_name("url")
                 .long("url")
                 .value_name("URL")
                 .help("Optional URL to the release for information purposes")))
        .subcommand(make_subcommand("delete")
            .about("Delete a release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version to delete")))
        .subcommand(make_subcommand("list")
            .about("list the most recent releases"))
        .subcommand(make_subcommand("files")
            .about("manage release artifact files")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The release to manage the files of"))
            .subcommand(make_subcommand("list")
                .about("List all release files"))
            .subcommand(make_subcommand("delete")
                .about("Delete a release file")
                .arg(Arg::with_name("all")
                     .short("A")
                     .long("all")
                     .help("deletes all files"))
                .arg(Arg::with_name("names")
                     .value_name("NAMES")
                     .index(1)
                     .multiple(true)
                     .help("a list of filenames to delete.")))
            .subcommand(make_subcommand("upload")
                .about("Uploads a file for a given release")
                .arg(Arg::with_name("path")
                     .value_name("PATH")
                     .index(1)
                     .required(true)
                     .help("The file to upload"))
                .arg(Arg::with_name("name")
                     .index(2)
                     .value_name("NAME")
                     .help("The name of the file on the server.")))
            .subcommand(make_subcommand("upload-sourcemaps")
                .about("Uploads sourcemap information for a given release")
                .arg(Arg::with_name("paths")
                     .value_name("PATHS")
                     .index(1)
                     .required(true)
                     .multiple(true)
                     .help("The files to upload"))
                .arg(Arg::with_name("url_prefix")
                     .short("u")
                     .long("url-prefix")
                     .value_name("PREFIX")
                     .help("The URL prefix to prepend to all filenames"))
                .arg(Arg::with_name("validate")
                     .long("validate")
                     .help("Enable basic sourcemap validation"))
                .arg(Arg::with_name("verbose")
                     .long("verbose")
                     .short("verbose")
                     .help("Enable verbose mode"))
                .arg(Arg::with_name("extensions")
                     .long("ext")
                     .short("x")
                     .value_name("EXT")
                     .multiple(true)
                     .help("Add a file extension to the list of files to upload."))))
}

fn execute_new<'a>(matches: &ArgMatches<'a>, config: &Config,
                   org: &str, project: &str) -> Result<()> {
    let info_rv = Api::new(config).new_release(org, project, &NewRelease {
        version: matches.value_of("version").unwrap().to_owned(),
        reference: matches.value_of("ref").map(|x| x.to_owned()),
        url: matches.value_of("url").map(|x| x.to_owned()),
    })?;
    println!("Created release {}.", info_rv.version);
    Ok(())
}

fn execute_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                      org: &str, project: &str) -> Result<()> {
    let version = matches.value_of("version").unwrap();
    if Api::new(config).delete_release(org, project, version)? {
        println!("Deleted release {}!", version);
    } else {
        println!("Did nothing. Release with this version ({}) does not exist.", version);
    }
    Ok(())
}

fn execute_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                    org: &str, project: &str) -> Result<()> {
    for info in Api::new(config).list_releases(org, project)? {
        println!("[{}] {}: {} ({} new groups)",
                 info.date_released.unwrap_or("              unreleased".into()),
                 info.version,
                 info.reference.unwrap_or("-".into()),
                 info.new_groups);
    }
    Ok(())
}

fn execute_files_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                          org: &str, project: &str, release: &str) -> Result<()> {
    for artifact in Api::new(config).list_release_files(org, project, release)? {
        println!("{}  ({} bytes)", artifact.name, artifact.size);
    }
    Ok(())
}

fn execute_files_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                            org: &str, project: &str, release: &str) -> Result<()> {
    let files : HashSet<String> = match matches.values_of("names") {
        Some(paths) => paths.map(|x| x.into()).collect(),
        None => HashSet::new(),
    };
    let api = Api::new(config);
    for file in api.list_release_files(org, project, release)? {
        if !(matches.is_present("all") || files.contains(&file.name)) {
            continue;
        }
        if api.delete_release_file(org, project, release, &file.id)? {
            println!("D {}", file.name);
        }
    }
    Ok(())
}

fn execute_files_upload<'a>(matches: &ArgMatches<'a>, config: &Config,
                            org: &str, project: &str, version: &str) -> Result<()> {
    let path = Path::new(matches.value_of("path").unwrap());
    let name = match matches.value_of("name") {
        Some(name) => name,
        None => Path::new(path).file_name()
            .and_then(|x| x.to_str()).ok_or("No filename provided.")?,
    };
    if let Some(artifact) = Api::new(config).upload_release_file(
        org, project, &version, &path, &name)? {
        println!("A {}  ({} bytes)", artifact.sha1, artifact.size);
    } else {
        fail!("File already present!");
    }
    Ok(())
}

fn execute_files_upload_sourcemaps<'a>(matches: &ArgMatches<'a>, config: &Config,
                                       org: &str, project: &str, version: &str) -> Result<()> {
    let api = Api::new(config);
    let release = api.get_release(org, project, version)?.ok_or("release not found")?;
    let url_prefix = matches.value_of("url_prefix").unwrap_or("~").trim_right_matches("/");
    let paths = matches.values_of("paths").unwrap();
    let extensions = match matches.values_of("extensions") {
        Some(matches) => matches.map(|ext| OsStr::new(ext.trim_left_matches("."))).collect(),
        None => vec![OsStr::new("js"), OsStr::new("map")],
    };

    let mut to_process = vec![];

    for path in paths {
        // if we start walking over something that is an actual file then
        // the directory iterator yields that path and terminates.  We
        // handle that case here specifically to figure out what the path is
        // we should strip off.
        let walk_path = PathBuf::from(&path);
        let (base_path, skip_ext_test) = if walk_path.is_file() {
            (walk_path.parent().unwrap(), true)
        } else {
            (walk_path.as_path(), false)
        };

        for dent in WalkDir::new(&walk_path) {
            let dent = dent?;
            if !skip_ext_test {
                let extension = dent.path().extension();
                if !extensions.iter().any(|ext| Some(*ext) == extension) {
                    continue;
                }
            }
            let local_path = dent.path().strip_prefix(&base_path).unwrap();
            let url = format!("{}/{}", url_prefix, local_path.display());
            to_process.push((url, local_path.to_path_buf(),
                             dent.path().to_path_buf()));
        }
    }

    if matches.is_present("validate") {
        println!("Running with sourcemap validation");
        let mut validator = SourceMapValidator::new(matches.is_present("verbose"));
        for &(ref url, _, ref path) in to_process.iter() {
            validator.consider_file(path, url);
        }
        validator.validate_sources()?;
    }

    println!("Uploading sourcemaps for release {}", release.version);
    for (url, local_path, path) in to_process {
        println!("{} -> {}", local_path.display(), url);
        if let Some(artifact) = api.upload_release_file(
            org, project, &release.version, &path, &url)? {
            println!("  {}  ({} bytes)", artifact.sha1, artifact.size);
        } else {
            println!("  already present");
        }
    }

    Ok(())
}

fn execute_files<'a>(matches: &ArgMatches<'a>, config: &Config,
                     org: &str, project: &str) -> Result<()> {
    let release = matches.value_of("version").unwrap();
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        return execute_files_list(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        return execute_files_delete(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload") {
        return execute_files_upload(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload-sourcemaps") {
        return execute_files_upload_sourcemaps(sub_matches, config, org, project, release);
    }
    unreachable!();
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    if let Some(sub_matches) = matches.subcommand_matches("new") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_new(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_delete(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_list(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("files") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_files(sub_matches, config, &org, &project);
    }
    unreachable!();
}
<commit_msg>Add debug logging for local files found before uploading<commit_after>//! Implements a command for managing releases.
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::collections::HashSet;

use clap::{App, AppSettings, Arg, ArgMatches};
use walkdir::WalkDir;

use prelude::*;
use api::{Api, NewRelease};
use config::Config;
use utils::make_subcommand;
use sourcemaps::SourceMapValidator;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("manage releases on Sentry")
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .subcommand(make_subcommand("new")
            .about("Create a new release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version identifier for this release"))
            .arg(Arg::with_name("ref")
                 .long("ref")
                 .value_name("REF")
                 .help("Optional commit reference (commit hash)"))
            .arg(Arg::with_name("url")
                 .long("url")
                 .value_name("URL")
                 .help("Optional URL to the release for information purposes")))
        .subcommand(make_subcommand("delete")
            .about("Delete a release")
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The version to delete")))
        .subcommand(make_subcommand("list")
            .about("list the most recent releases"))
        .subcommand(make_subcommand("files")
            .about("manage release artifact files")
            .setting(AppSettings::SubcommandRequiredElseHelp)
            .arg(Arg::with_name("version")
                 .value_name("VERSION")
                 .required(true)
                 .index(1)
                 .help("The release to manage the files of"))
            .subcommand(make_subcommand("list")
                .about("List all release files"))
            .subcommand(make_subcommand("delete")
                .about("Delete a release file")
                .arg(Arg::with_name("all")
                     .short("A")
                     .long("all")
                     .help("deletes all files"))
                .arg(Arg::with_name("names")
                     .value_name("NAMES")
                     .index(1)
                     .multiple(true)
                     .help("a list of filenames to delete.")))
            .subcommand(make_subcommand("upload")
                .about("Uploads a file for a given release")
                .arg(Arg::with_name("path")
                     .value_name("PATH")
                     .index(1)
                     .required(true)
                     .help("The file to upload"))
                .arg(Arg::with_name("name")
                     .index(2)
                     .value_name("NAME")
                     .help("The name of the file on the server.")))
            .subcommand(make_subcommand("upload-sourcemaps")
                .about("Uploads sourcemap information for a given release")
                .arg(Arg::with_name("paths")
                     .value_name("PATHS")
                     .index(1)
                     .required(true)
                     .multiple(true)
                     .help("The files to upload"))
                .arg(Arg::with_name("url_prefix")
                     .short("u")
                     .long("url-prefix")
                     .value_name("PREFIX")
                     .help("The URL prefix to prepend to all filenames"))
                .arg(Arg::with_name("validate")
                     .long("validate")
                     .help("Enable basic sourcemap validation"))
                .arg(Arg::with_name("verbose")
                     .long("verbose")
                     .short("verbose")
                     .help("Enable verbose mode"))
                .arg(Arg::with_name("extensions")
                     .long("ext")
                     .short("x")
                     .value_name("EXT")
                     .multiple(true)
                     .help("Add a file extension to the list of files to upload."))))
}

fn execute_new<'a>(matches: &ArgMatches<'a>, config: &Config,
                   org: &str, project: &str) -> Result<()> {
    let info_rv = Api::new(config).new_release(org, project, &NewRelease {
        version: matches.value_of("version").unwrap().to_owned(),
        reference: matches.value_of("ref").map(|x| x.to_owned()),
        url: matches.value_of("url").map(|x| x.to_owned()),
    })?;
    println!("Created release {}.", info_rv.version);
    Ok(())
}

fn execute_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                      org: &str, project: &str) -> Result<()> {
    let version = matches.value_of("version").unwrap();
    if Api::new(config).delete_release(org, project, version)? {
        println!("Deleted release {}!", version);
    } else {
        println!("Did nothing. Release with this version ({}) does not exist.", version);
    }
    Ok(())
}

fn execute_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                    org: &str, project: &str) -> Result<()> {
    for info in Api::new(config).list_releases(org, project)? {
        println!("[{}] {}: {} ({} new groups)",
                 info.date_released.unwrap_or("              unreleased".into()),
                 info.version,
                 info.reference.unwrap_or("-".into()),
                 info.new_groups);
    }
    Ok(())
}

fn execute_files_list<'a>(_matches: &ArgMatches<'a>, config: &Config,
                          org: &str, project: &str, release: &str) -> Result<()> {
    for artifact in Api::new(config).list_release_files(org, project, release)? {
        println!("{}  ({} bytes)", artifact.name, artifact.size);
    }
    Ok(())
}

fn execute_files_delete<'a>(matches: &ArgMatches<'a>, config: &Config,
                            org: &str, project: &str, release: &str) -> Result<()> {
    let files : HashSet<String> = match matches.values_of("names") {
        Some(paths) => paths.map(|x| x.into()).collect(),
        None => HashSet::new(),
    };
    let api = Api::new(config);
    for file in api.list_release_files(org, project, release)? {
        if !(matches.is_present("all") || files.contains(&file.name)) {
            continue;
        }
        if api.delete_release_file(org, project, release, &file.id)? {
            println!("D {}", file.name);
        }
    }
    Ok(())
}

fn execute_files_upload<'a>(matches: &ArgMatches<'a>, config: &Config,
                            org: &str, project: &str, version: &str) -> Result<()> {
    let path = Path::new(matches.value_of("path").unwrap());
    let name = match matches.value_of("name") {
        Some(name) => name,
        None => Path::new(path).file_name()
            .and_then(|x| x.to_str()).ok_or("No filename provided.")?,
    };
    if let Some(artifact) = Api::new(config).upload_release_file(
        org, project, &version, &path, &name)? {
        println!("A {}  ({} bytes)", artifact.sha1, artifact.size);
    } else {
        fail!("File already present!");
    }
    Ok(())
}

fn execute_files_upload_sourcemaps<'a>(matches: &ArgMatches<'a>, config: &Config,
                                       org: &str, project: &str, version: &str) -> Result<()> {
    let api = Api::new(config);
    let release = api.get_release(org, project, version)?.ok_or("release not found")?;
    let url_prefix = matches.value_of("url_prefix").unwrap_or("~").trim_right_matches("/");
    let paths = matches.values_of("paths").unwrap();
    let extensions = match matches.values_of("extensions") {
        Some(matches) => matches.map(|ext| OsStr::new(ext.trim_left_matches("."))).collect(),
        None => vec![OsStr::new("js"), OsStr::new("map")],
    };

    let mut to_process = vec![];

    for path in paths {
        // if we start walking over something that is an actual file then
        // the directory iterator yields that path and terminates.  We
        // handle that case here specifically to figure out what the path is
        // we should strip off.
        let walk_path = PathBuf::from(&path);
        let (base_path, skip_ext_test) = if walk_path.is_file() {
            (walk_path.parent().unwrap(), true)
        } else {
            (walk_path.as_path(), false)
        };

        for dent in WalkDir::new(&walk_path) {
            let dent = dent?;
            if !skip_ext_test {
                let extension = dent.path().extension();
                if !extensions.iter().any(|ext| Some(*ext) == extension) {
                    continue;
                }
            }
            debug!("found: {} ({} bytes)", dent.path().display(), dent.metadata().unwrap().len());
            let local_path = dent.path().strip_prefix(&base_path).unwrap();
            let url = format!("{}/{}", url_prefix, local_path.display());
            to_process.push((url, local_path.to_path_buf(),
                             dent.path().to_path_buf()));
        }
    }

    if matches.is_present("validate") {
        println!("Running with sourcemap validation");
        let mut validator = SourceMapValidator::new(matches.is_present("verbose"));
        for &(ref url, _, ref path) in to_process.iter() {
            validator.consider_file(path, url);
        }
        validator.validate_sources()?;
    }

    println!("Uploading sourcemaps for release {}", release.version);
    for (url, local_path, path) in to_process {
        println!("{} -> {}", local_path.display(), url);
        if let Some(artifact) = api.upload_release_file(
            org, project, &release.version, &path, &url)? {
            println!("  {}  ({} bytes)", artifact.sha1, artifact.size);
        } else {
            println!("  already present");
        }
    }

    Ok(())
}

fn execute_files<'a>(matches: &ArgMatches<'a>, config: &Config,
                     org: &str, project: &str) -> Result<()> {
    let release = matches.value_of("version").unwrap();
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        return execute_files_list(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        return execute_files_delete(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload") {
        return execute_files_upload(sub_matches, config, org, project, release);
    }
    if let Some(sub_matches) = matches.subcommand_matches("upload-sourcemaps") {
        return execute_files_upload_sourcemaps(sub_matches, config, org, project, release);
    }
    unreachable!();
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    if let Some(sub_matches) = matches.subcommand_matches("new") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_new(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("delete") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_delete(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("list") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_list(sub_matches, config, &org, &project);
    }
    if let Some(sub_matches) = matches.subcommand_matches("files") {
        let (org, project) = config.get_org_and_project(matches)?;
        return execute_files(sub_matches, config, &org, &project);
    }
    unreachable!();
}
<|endoftext|>


<commit_before>// -*- rust -*-

fn main(vec[str] args) -> () {
  let int i = 0;
  for (str filename in args) {
    if (i > 0) {
      auto br = std._io.mk_buf_reader(filename);
      log "opened file: " + filename;
    }
    i += 1;
  }
}
<commit_msg>Clean out rustc so it doesn't give the false impression of doing anything yet.<commit_after>// -*- rust -*-

fn main(vec[str] args) -> () {
  log "This is the rust 'self-hosted' compiler.";
  log "The one written in rust.";
  log "It does nothing yet, it's a placeholder.";
  log "You want rustboot, the compiler next door.";
}
<|endoftext|>


<commit_before>//! Test module for `cripes::util::flex_box`, which provides flexibly-sized
//! reusable boxes.

use std;
use cripes::util::flex_box::*;

#[test]
/// Test that FlexBox works for simple value types.
fn test_simple_value() {
    let mut b = FlexBox::new();

    {
        let x = b.store(3u8);
        println!("{:?}", x);
    }
    {
        let x = b.store(vec![0x55usize;32]);
        println!("{:?}", x);
    }

    {
        let y = b.store("foo");
        println!("{:?}", y);
    }
}

#[test]
/// Test that FlexBox works for values with Drop implementations.
fn test_with_drop() {
    use std::rc::Rc;
    use std::ops::Drop;
    use std::mem::drop;
    use std::cell::RefCell;
    use std::sync::atomic::{AtomicUsize,Ordering};

    let ran_drop = Rc::new(RefCell::new(AtomicUsize::new(0)));

    struct HasDrop(Rc<RefCell<AtomicUsize>>);
    impl Drop for HasDrop {
        fn drop(&mut self) {
            println!("Goodbye, World!");
            self.0.borrow_mut().fetch_add(1, Ordering::SeqCst);
        }
    }

    let mut b = FlexBox::new();
    {
        let x = b.store(HasDrop(ran_drop.clone()));
        assert!( 0 == ran_drop.borrow().load(Ordering::SeqCst) );
        drop(x);
        assert!( 1 == ran_drop.borrow().load(Ordering::SeqCst) );
    }

    ran_drop.borrow().store(0, Ordering::SeqCst);
    {
        let x: Ref<Drop> = b.store(HasDrop(ran_drop.clone()));
        assert!( 0 == ran_drop.borrow().load(Ordering::SeqCst) );
        drop(x);
        assert!( 1 == ran_drop.borrow().load(Ordering::SeqCst) );

    }
}

#[test]
/// Ensure that trait objects work.
fn test_with_trait_object() {
    use std;
    let mut b = FlexBox::new();

    {
        let y: Ref<std::fmt::Debug> = b.store("eeny meeny meiny moe");
        println!("{:?}", y);
    }
}

#[test]
/// Check that the iterator implementations on flex_box::Ref work as expected.
/// This is mostly a compile-time check.
fn test_with_iterator() {
    let mut b = FlexBox::new();

    {
        let u = vec![1, 2, 3, 4];
        let it: Ref<Iterator<Item=_>> = b.store(u.iter());
         for x in it {
            println!("{:?} ", x);
        }
    }
}

#[test]
/// Check that we can store items in a FlexBox indirectly.  This is mostly
/// a compile-time check.
fn test_store_indirect() {
    let mut b = FlexBox::new();

    for x in store_and_return_iterator::<()>(&mut b) {
        println!("{:?}", x);
    }
}

fn store_and_return_iterator<'a,I: 'a>(b: &'a mut FlexBox) -> Ref<'a,Iterator<Item=I>> {
    b.store(std::iter::empty::<I>())
}

#[test]
/// Check that we can implement traits that use FlexBox for storage,
/// potentially via chained calls to subobjects.  This is mostly
/// a compile-time check.
fn test_trait_store_iterator_chained() {
    trait StoresIterator<T> {
        fn give_me_an_iterator<'b>(&self, b: &'b mut FlexBox) -> Ref<'b, Iterator<Item=T>>
            where T: 'b;
    }

    struct LikesIterators<T: Copy> {
        // ...but doesn't own them directly.
        holder: HasIterator<T>
    }
    impl<T: Copy> StoresIterator<T> for LikesIterators<T> {
        fn give_me_an_iterator<'b>(&self, b: &'b mut FlexBox) -> Ref<'b,Iterator<Item=T>>
        where T: 'b {
            self.holder.give_me_an_iterator(b)
        }
    }

    struct HasIterator<T: Copy> { value: T }

    impl<T: Copy> StoresIterator<T> for HasIterator<T> {
        fn give_me_an_iterator<'b>(&self, b: &'b mut FlexBox) -> Ref<'b,Iterator<Item=T>>
        where T: 'b {
            b.store(std::iter::once(self.value))
        }
    }

    let mut b = FlexBox::new();
    let hi = HasIterator{value: 2};
    let likes_iterators = LikesIterators{holder: HasIterator{value: 2}};

    for u in hi.give_me_an_iterator(&mut b) {
        println!("{}", u);
    }

    for v in likes_iterators.give_me_an_iterator(&mut b) {
        println!("{}", v);
    }
}
<commit_msg>test/test_util/test_flex_box: add another `assert_eq`<commit_after>//! Test module for `cripes::util::flex_box`, which provides flexibly-sized
//! reusable boxes.

use std;
use cripes::util::flex_box::*;

#[test]
/// Test that FlexBox works for simple value types.
fn test_simple_value() {
    let mut b = FlexBox::new();

    {
        let x = b.store(3u8);
        println!("{:?}", x);
    }
    {
        let x = b.store(vec![0x55usize;32]);
        assert_eq!(*x, &[0x55usize;32]);
        println!("{:?}", x);
    }

    {
        let y = b.store("foo");
        println!("{:?}", y);
    }
}

#[test]
/// Test that FlexBox works for values with Drop implementations.
fn test_with_drop() {
    use std::rc::Rc;
    use std::ops::Drop;
    use std::mem::drop;
    use std::cell::RefCell;
    use std::sync::atomic::{AtomicUsize,Ordering};

    let ran_drop = Rc::new(RefCell::new(AtomicUsize::new(0)));

    struct HasDrop(Rc<RefCell<AtomicUsize>>);
    impl Drop for HasDrop {
        fn drop(&mut self) {
            println!("Goodbye, World!");
            self.0.borrow_mut().fetch_add(1, Ordering::SeqCst);
        }
    }

    let mut b = FlexBox::new();
    {
        let x = b.store(HasDrop(ran_drop.clone()));
        assert!( 0 == ran_drop.borrow().load(Ordering::SeqCst) );
        drop(x);
        assert!( 1 == ran_drop.borrow().load(Ordering::SeqCst) );
    }

    ran_drop.borrow().store(0, Ordering::SeqCst);
    {
        let x: Ref<Drop> = b.store(HasDrop(ran_drop.clone()));
        assert!( 0 == ran_drop.borrow().load(Ordering::SeqCst) );
        drop(x);
        assert!( 1 == ran_drop.borrow().load(Ordering::SeqCst) );

    }
}

#[test]
/// Ensure that trait objects work.
fn test_with_trait_object() {
    use std;
    let mut b = FlexBox::new();

    {
        let y: Ref<std::fmt::Debug> = b.store("eeny meeny meiny moe");
        println!("{:?}", y);
    }
}

#[test]
/// Check that the iterator implementations on flex_box::Ref work as expected.
/// This is mostly a compile-time check.
fn test_with_iterator() {
    let mut b = FlexBox::new();

    {
        let u = vec![1, 2, 3, 4];
        let it: Ref<Iterator<Item=_>> = b.store(u.iter());
         for x in it {
            println!("{:?} ", x);
        }
    }
}

#[test]
/// Check that we can store items in a FlexBox indirectly.  This is mostly
/// a compile-time check.
fn test_store_indirect() {
    let mut b = FlexBox::new();

    for x in store_and_return_iterator::<()>(&mut b) {
        println!("{:?}", x);
    }
}

fn store_and_return_iterator<'a,I: 'a>(b: &'a mut FlexBox) -> Ref<'a,Iterator<Item=I>> {
    b.store(std::iter::empty::<I>())
}

#[test]
/// Check that we can implement traits that use FlexBox for storage,
/// potentially via chained calls to subobjects.  This is mostly
/// a compile-time check.
fn test_trait_store_iterator_chained() {
    trait StoresIterator<T> {
        fn give_me_an_iterator<'b>(&self, b: &'b mut FlexBox) -> Ref<'b, Iterator<Item=T>>
            where T: 'b;
    }

    struct LikesIterators<T: Copy> {
        // ...but doesn't own them directly.
        holder: HasIterator<T>
    }
    impl<T: Copy> StoresIterator<T> for LikesIterators<T> {
        fn give_me_an_iterator<'b>(&self, b: &'b mut FlexBox) -> Ref<'b,Iterator<Item=T>>
        where T: 'b {
            self.holder.give_me_an_iterator(b)
        }
    }

    struct HasIterator<T: Copy> { value: T }

    impl<T: Copy> StoresIterator<T> for HasIterator<T> {
        fn give_me_an_iterator<'b>(&self, b: &'b mut FlexBox) -> Ref<'b,Iterator<Item=T>>
        where T: 'b {
            b.store(std::iter::once(self.value))
        }
    }

    let mut b = FlexBox::new();
    let hi = HasIterator{value: 2};
    let likes_iterators = LikesIterators{holder: HasIterator{value: 2}};

    for u in hi.give_me_an_iterator(&mut b) {
        println!("{}", u);
    }

    for v in likes_iterators.give_me_an_iterator(&mut b) {
        println!("{}", v);
    }
}
<|endoftext|>