<commit_before>use regex::{Regex, Captures};

static PARAMS: Regex = regex!(r":([a-zA-Z0-9_-]*)");

pub fn deglob(glob: String) -> Regex {
    // Replace glob patterns with corresponding regexs.
    let deglobbed = glob
        // Have to do this because the ** regex contains *
        .replace("**", "___DOUBLE_WILDCARD___")
        // Now only __DOUBLE_WILDCARD___ remains.
        .replace("*", "[a-zA-Z0-9_-]*")
        // Replace ** with its associated regex.
        .replace("___DOUBLE_WILDCARD___", "[/a-zA-Z0-9_-]*");
    // Replace :param patterns with corresponding regexs.
    let debound = PARAMS
        .replace_all(deglobbed.as_slice(), |cap: &Captures| {
            "(?P<".to_string().append(cap.at(1)).append(">[a-zA-Z0-9_-]*)")
        });
    Regex::new("^".to_string().append(debound.as_slice()).append("$").as_slice()).unwrap()
}

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

    #[test]
    fn test_segment_match() {
        // Do literal matches work?
        let glob_regex = deglob("/users/nested/groups".to_string());
        assert!(glob_regex.is_match("/users/nested/groups"));
        assert!(!glob_regex.is_match("/notusers/hello"))
    }

    #[test]
    fn test_wildcard_match() {
        // Do wilcard matches work?
        let glob_regex = deglob("/users/*/groups".to_string());
        assert!(glob_regex.is_match("/users/nested/groups"));
        assert!(glob_regex.is_match("/users//groups"));
        assert!(!glob_regex.is_match("/users/deeply/nested/groups"));
    }

    #[test]
    fn test_double_wildcard_match() {
        // Do double wildcard matches work?
        let glob_regex = deglob("/users/**/groups".to_string());
        assert!(glob_regex.is_match("/users/deeply/nested/groups"));
        assert!(glob_regex.is_match("/users//groups"));
        assert!(!glob_regex.is_match("/notusers/groups/"))
    }

    #[test]
    fn test_params_match() {
        // Does param matching work?
        let glob_regex = deglob("/users/:groupid/:userid".to_string());
        assert!(glob_regex.is_match("/users/73564/87684"));
        assert!(!glob_regex.is_match("/users/234/groups/2343"));
    }

    #[test]
    fn test_params_value() {
        // Do params have the correct value?
        let glob_regex = deglob("/users/:groupid/:userid".to_string());
        assert_eq!(glob_regex.captures("/users/7374/234").unwrap().name("userid"), "234");
        assert_eq!(glob_regex.captures("/users/7374/234").unwrap().name("groupid"), "7374");
    }
}

<commit_msg>(test) Added benchmarks for glob matching.<commit_after>use regex::{Regex, Captures};

static PARAMS: Regex = regex!(r":([a-zA-Z0-9_-]*)");

pub fn deglob(glob: String) -> Regex {
    // Replace glob patterns with corresponding regexs.
    let deglobbed = glob
        // Have to do this because the ** regex contains *
        .replace("**", "___DOUBLE_WILDCARD___")
        // Now only __DOUBLE_WILDCARD___ remains.
        .replace("*", "[a-zA-Z0-9_-]*")
        // Replace ** with its associated regex.
        .replace("___DOUBLE_WILDCARD___", "[/a-zA-Z0-9_-]*");
    // Replace :param patterns with corresponding regexs.
    let debound = PARAMS
        .replace_all(deglobbed.as_slice(), |cap: &Captures| {
            "(?P<".to_string().append(cap.at(1)).append(">[a-zA-Z0-9_-]*)")
        });
    Regex::new("^".to_string().append(debound.as_slice()).append("$").as_slice()).unwrap()
}

#[cfg(test)]
mod test {
    use super::*;
    use test::{Bencher, black_box};

    #[test]
    fn test_segment_match() {
        // Do literal matches work?
        let glob_regex = deglob("/users/nested/groups".to_string());
        assert!(glob_regex.is_match("/users/nested/groups"));
        assert!(!glob_regex.is_match("/notusers/hello"))
    }

    #[test]
    fn test_wildcard_match() {
        // Do wilcard matches work?
        let glob_regex = deglob("/users/*/groups".to_string());
        assert!(glob_regex.is_match("/users/nested/groups"));
        assert!(glob_regex.is_match("/users//groups"));
        assert!(!glob_regex.is_match("/users/deeply/nested/groups"));
    }

    #[test]
    fn test_double_wildcard_match() {
        // Do double wildcard matches work?
        let glob_regex = deglob("/users/**/groups".to_string());
        assert!(glob_regex.is_match("/users/deeply/nested/groups"));
        assert!(glob_regex.is_match("/users//groups"));
        assert!(!glob_regex.is_match("/notusers/groups/"))
    }

    #[test]
    fn test_params_match() {
        // Does param matching work?
        let glob_regex = deglob("/users/:groupid/:userid".to_string());
        assert!(glob_regex.is_match("/users/73564/87684"));
        assert!(!glob_regex.is_match("/users/234/groups/2343"));
    }

    #[test]
    fn test_params_value() {
        // Do params have the correct value?
        let glob_regex = deglob("/users/:groupid/:userid".to_string());
        assert_eq!(glob_regex.captures("/users/7374/234").unwrap().name("userid"), "234");
        assert_eq!(glob_regex.captures("/users/7374/234").unwrap().name("groupid"), "7374");
    }

    #[bench]
    fn bench_explicit_match(b: &mut Bencher) {
        let glob_regex = deglob("/users/get".to_string());
        b.iter(|| {
                glob_regex.is_match("/users/get");
        })
    }

    #[bench]
    fn bench_explicit_match_native(b: &mut Bencher) {
        let glob_regex = regex!(r"/users/get");
        b.iter(|| {
                glob_regex.is_match("/users/get");
        })
    }

    #[bench]
    fn bench_easy_match(b: &mut Bencher) {
        let glob_regex = deglob("/users/*".to_string());
        b.iter(|| {
            black_box({
                glob_regex.is_match("/users/jonathan");
            })
        })
    }

    #[bench]
    fn bench_hard_match(b: &mut Bencher) {
        let glob_regex = deglob("/users/**/:userid/*/groups".to_string());
        b.iter(|| {
            black_box({
                glob_regex.is_match("/users/jonathan/reem/768/random/groups");
            })
        })
    }

    #[bench]
    fn bench_hard_match_native(b: &mut Bencher) {
        let glob_regex = regex!(r"/users/[/a-zA-Z0-9_-]*/(?P<userid>[a-zA-Z0-9_-]*)/[a-zA-Z0-9_-]*/groups");
        b.iter(|| {
            black_box({
                glob_regex.is_match("/users/jonathan/reem/768/random/groups");
            })
        })
    }
}

<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io::BufReader;
use std::io::SeekFrom;
use std::fs::File;
use std::cmp::Ordering;
use std::mem;
use utils;
use errors::Word2VecError;

/// Representation of a word vector space
///
/// Each word of a vocabulary is represented by a vector. All words span a vector space. This data
/// structure manages this vector space of words.
pub struct WordVector {
    vocabulary: Vec<(String, Vec<f32>)>,
    vector_size: usize
}

impl WordVector{
	/// Load a word vector space from file
	///
	/// Word2vec is able to store the word vectors in a binary file. This function parses the file
	/// and loads the vectors into RAM.
	pub fn load_from_binary(file_name: &str) -> Result<WordVector, Word2VecError>
	{
		let file = try!(File::open(file_name));
		let mut reader = BufReader::new(file);
		let mut header = String::new();
		try!(reader.read_line(&mut header));
		let header_info = header.split_whitespace().filter_map(|x| x.parse::<usize>().ok()).take(2).collect::<Vec<usize>>();
		if header_info.len() != 2{
			return Err(Word2VecError::WrongHeader)
		}
		let vocabulary_size = header_info[0];
		let vector_size = header_info[1];
		let mut vocabulary: Vec<(String, Vec<f32>)> = Vec::with_capacity(vocabulary_size);
		for _ in 0..vocabulary_size{
			let mut word_bytes: Vec<u8> = Vec::new();
			try!(reader.read_until(b' ', &mut word_bytes));
			word_bytes.pop();
			let word = try!(String::from_utf8(word_bytes));
			let mut current_vector: Vec<f32> = Vec::with_capacity(vector_size);
			for _ in 0..vector_size{
				let mut buf: [u8; 4] = [0; 4];
				try!(reader.read(&mut buf));
				let vec = unsafe{ mem::transmute::<[u8; 4], f32>(buf) };
				current_vector.push(vec);
			}
			current_vector = utils::vector_norm(current_vector);
			vocabulary.push((word, current_vector));
			try!(reader.seek(SeekFrom::Current(1)));
		}
		Ok(WordVector{
			vocabulary: vocabulary,
			vector_size: vector_size,
		})
	}

	fn get_index(&self, word: &str) -> Option<usize>
	{
		self.vocabulary.iter().position(|x| x.0 == word)
	}

	/// Get word vector for the given word.
	pub fn get_vector(&self, word: &str) -> Option<&Vec<f32>>
	{
		let index = self.get_index(word);
		match index {
		    Some(val) => {
		    	return Some(&self.vocabulary[val].1)
		    },
		    None => None,
		}
	}

	/// Compute consine distance to similar words.
	///
	/// The words in the vector space are characterized through the position and angle to each
	/// other. This method calculates the `n` closest words via the cosine of the requested word to
	/// all other words.
	pub fn cosine(&self, word: &str, n: usize) -> Option<Vec<(String, f32)>>
	{
		let word_vector = self.get_vector(word);
		match word_vector {
		    Some(val) => {
		        let mut metrics: Vec<(String, f32)> = Vec::with_capacity(self.vocabulary.len());
		        for word in self.vocabulary.iter(){
		    	    metrics.push((word.0.clone(), utils::dot_product(&word.1, val)));
		        }
		        metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
		        metrics.remove(0);
		        metrics.truncate(n);
		        return Some(metrics)
	        },
		    None => None,
		}
	}

	pub fn analogy(&self, pos: Vec<&str>, neg: Vec<&str>, n: usize) -> Option<Vec<(String, f32)>>
	{
		let mut vectors: Vec<Vec<f32>> = Vec::new();
		let mut exclude: Vec<String> = Vec::new();
		for word in pos {
			exclude.push(word.to_string());
			match self.get_vector(word){
				Some(val) => vectors.push(val.clone()),
				None => {}
			}
		}
		for word in neg.iter(){
			exclude.push(word.to_string());
			match self.get_vector(word) {
			    Some(val) => vectors.push(val.iter().map(|x| -x).collect::<Vec<f32>>()),
			    None => {},
			}
		}
		if exclude.is_empty(){
			return None
		}
		let mut mean: Vec<f32> = Vec::with_capacity(self.vector_size);
		for i in 0..self.vector_size{
			mean.push(utils::mean(vectors.iter().map(|v| v[i])));
		}
		let mut metrics: Vec<(String, f32)> = Vec::new();
		for word in self.vocabulary.iter(){
		    metrics.push((word.0.clone(), utils::dot_product(&word.1, &mean)));
		}
		metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
		metrics.retain(|x| exclude.contains(&x.0) == false);
		metrics.truncate(n);
		Some(metrics)
	}

	/// Get the count of all known words from the vocabulary.
	pub fn word_count(&self) -> usize {
	    self.vocabulary.len()
    }
}

<commit_msg>Add get_words method<commit_after>use std::io::prelude::*;
use std::io::BufReader;
use std::io::SeekFrom;
use std::fs::File;
use std::cmp::Ordering;
use std::mem;
use utils;
use errors::Word2VecError;

/// Representation of a word vector space
///
/// Each word of a vocabulary is represented by a vector. All words span a vector space. This data
/// structure manages this vector space of words.
pub struct WordVector {
	vocabulary: Vec<(String, Vec<f32>)>,
	vector_size: usize
}

impl WordVector{
	/// Load a word vector space from file
	///
	/// Word2vec is able to store the word vectors in a binary file. This function parses the file
	/// and loads the vectors into RAM.
	pub fn load_from_binary(file_name: &str) -> Result<WordVector, Word2VecError>
	{
		let file = try!(File::open(file_name));
		let mut reader = BufReader::new(file);
		let mut header = String::new();
		try!(reader.read_line(&mut header));
		let header_info = header.split_whitespace().filter_map(|x| x.parse::<usize>().ok()).take(2).collect::<Vec<usize>>();
		if header_info.len() != 2{
			return Err(Word2VecError::WrongHeader)
		}
		let vocabulary_size = header_info[0];
		let vector_size = header_info[1];
		let mut vocabulary: Vec<(String, Vec<f32>)> = Vec::with_capacity(vocabulary_size);
		for _ in 0..vocabulary_size{
			let mut word_bytes: Vec<u8> = Vec::new();
			try!(reader.read_until(b' ', &mut word_bytes));
			word_bytes.pop();
			let word = try!(String::from_utf8(word_bytes));
			let mut current_vector: Vec<f32> = Vec::with_capacity(vector_size);
			for _ in 0..vector_size{
				let mut buf: [u8; 4] = [0; 4];
				try!(reader.read(&mut buf));
				let vec = unsafe{ mem::transmute::<[u8; 4], f32>(buf) };
				current_vector.push(vec);
			}
			current_vector = utils::vector_norm(current_vector);
			vocabulary.push((word, current_vector));
			try!(reader.seek(SeekFrom::Current(1)));
		}
		Ok(WordVector{
			vocabulary: vocabulary,
			vector_size: vector_size,
		})
	}

	fn get_index(&self, word: &str) -> Option<usize>
	{
		self.vocabulary.iter().position(|x| x.0 == word)
	}

	/// Get word vector for the given word.
	pub fn get_vector(&self, word: &str) -> Option<&Vec<f32>>
	{
		let index = self.get_index(word);
		match index {
			Some(val) => {
				Some(&self.vocabulary[val].1)
			},
			None => None,
		}
	}

	/// Compute consine distance to similar words.
	///
	/// The words in the vector space are characterized through the position and angle to each
	/// other. This method calculates the `n` closest words via the cosine of the requested word to
	/// all other words.
	pub fn cosine(&self, word: &str, n: usize) -> Option<Vec<(String, f32)>>
	{
		let word_vector = self.get_vector(word);
		match word_vector {
		    Some(val) => {
		        let mut metrics: Vec<(String, f32)> = Vec::with_capacity(self.vocabulary.len());
		        for word in self.vocabulary.iter(){
		    	    metrics.push((word.0.clone(), utils::dot_product(&word.1, val)));
		        }
		        metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
		        metrics.remove(0);
		        metrics.truncate(n);
		        return Some(metrics)
	        },
		    None => None,
		}
	}

	pub fn analogy(&self, pos: Vec<&str>, neg: Vec<&str>, n: usize) -> Option<Vec<(String, f32)>>
	{
		let mut vectors: Vec<Vec<f32>> = Vec::new();
		let mut exclude: Vec<String> = Vec::new();
		for word in pos {
			exclude.push(word.to_string());
			match self.get_vector(word){
				Some(val) => vectors.push(val.clone()),
				None => {}
			}
		}
		for word in neg.iter(){
			exclude.push(word.to_string());
			match self.get_vector(word) {
			    Some(val) => vectors.push(val.iter().map(|x| -x).collect::<Vec<f32>>()),
			    None => {},
			}
		}
		if exclude.is_empty(){
			return None
		}
		let mut mean: Vec<f32> = Vec::with_capacity(self.vector_size);
		for i in 0..self.vector_size{
			mean.push(utils::mean(vectors.iter().map(|v| v[i])));
		}
		let mut metrics: Vec<(String, f32)> = Vec::new();
		for word in self.vocabulary.iter(){
		    metrics.push((word.0.clone(), utils::dot_product(&word.1, &mean)));
		}
		metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
		metrics.retain(|x| exclude.contains(&x.0) == false);
		metrics.truncate(n);
		Some(metrics)
	}

	/// Get the count of all known words from the vocabulary.
	pub fn word_count(&self) -> usize
	{
	    self.vocabulary.len()
    }

    pub fn get_words<'a>(&'a self) -> Words<'a> {
    	Words::new(&self.vocabulary)
	}
}

pub struct Words<'parent> {
	words: &'parent Vec<(String, Vec<f32>)>,
	index: usize,
}

impl<'a> Words<'a> {
	fn new(x: &'a Vec<(String, Vec<f32>)>) -> Words<'a> {
		Words { words: x, index: 0 }
	}
}

impl<'a> Iterator for Words<'a> {
	type Item = String;

	fn next(&mut self) -> Option<Self::Item>{
		if self.index >= self.words.len() {
			return None
		}
		self.index += 1;
		Some(self.words[self.index - 1].0.clone())
	}
}

<|endoftext|>


<commit_before>#![no_std]

extern crate stm32f0_hal as hal;

use hal::servo;
use hal::pwm;
use hal::rcc;

fn main() {
    rcc::init();
    let servo1 = servo::Servo::init(pwm::Pin::PB4);
    servo1.set_position(0.0);
    loop {
        // increase position of 0.5° each 20 ms
        for i in 0..360 {
            servo1.set_position(i as f32 / 2.0);
            rcc::ms_delay(20);
        }
        // decrease position of 0.5° each 20 ms
        for i in 0..360 {
            servo1.set_position(180.0 - (i as f32 / 2.0));
            rcc::ms_delay(20);
        }
    }
}
<commit_msg>Fix servo examples.<commit_after>#![no_std]

extern crate stm32f0_hal as hal;

use hal::servo;
use hal::pwm;
use hal::rcc;

fn main() {
    rcc::init();
    let servo1 = servo::Servo::init(pwm::Pin::PB4);
    servo1.set_position(0.0);
    loop {
        // increase position of 0.5° each 20 ms
        for i in 0..360 {
            servo1.set_position(i as f64 / 2.0);
            rcc::ms_delay(20);
        }
        // decrease position of 0.5° each 20 ms
        for i in 0..360 {
            servo1.set_position(180.0 - (i as f64 / 2.0));
            rcc::ms_delay(20);
        }
    }
}
<|endoftext|>


<commit_before>mod field;

pub use self::field::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Clue {
    NoClue,
    Empty,
    Up(i32),
    Left(i32),
    Down(i32),
    Right(i32),
}

impl Clue {
    pub fn same_shape(self, other: Clue) -> bool {
        match (self, other) {
            (Clue::Up(_), Clue::Up(_))
            | (Clue::Left(_), Clue::Left(_))
            | (Clue::Down(_), Clue::Down(_))
            | (Clue::Right(_), Clue::Right(_)) => true,
            _ => false,
        }
    }
    pub fn clue_number(self) -> i32 {
        match self {
            Clue::NoClue | Clue::Empty => -1,
            Clue::Up(n) | Clue::Left(n) | Clue::Down(n) | Clue::Right(n) => n,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cell {
    Clue,
    Undecided,
    Line,
    Blocked,
}
<commit_msg>Yajilin: add Cell::is_blocking<commit_after>mod field;

pub use self::field::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Clue {
    NoClue,
    Empty,
    Up(i32),
    Left(i32),
    Down(i32),
    Right(i32),
}

impl Clue {
    pub fn same_shape(self, other: Clue) -> bool {
        match (self, other) {
            (Clue::Up(_), Clue::Up(_))
            | (Clue::Left(_), Clue::Left(_))
            | (Clue::Down(_), Clue::Down(_))
            | (Clue::Right(_), Clue::Right(_)) => true,
            _ => false,
        }
    }
    pub fn clue_number(self) -> i32 {
        match self {
            Clue::NoClue | Clue::Empty => -1,
            Clue::Up(n) | Clue::Left(n) | Clue::Down(n) | Clue::Right(n) => n,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cell {
    Clue,
    Undecided,
    Line,
    Blocked,
}

impl Cell {
    pub fn is_blocking(self) -> bool {
        match self {
            Cell::Clue | Cell::Blocked => true,
            _ => false,
        }
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;
extern crate tokio_service;
extern crate uuid;

#[macro_use]
extern crate clap;
extern crate es_proto;

use std::io;
use std::net::SocketAddr;
use std::process;
use uuid::Uuid;

use futures::Future;
use tokio_core::reactor::Core;
use tokio_service::Service;

use clap::{Arg, App, SubCommand};

use es_proto::{EventStoreClient, Package, Message, Builder, ExpectedVersion, StreamVersion, Direction};

#[derive(Debug)]
enum ReadMode {
    ForwardOnce{ skip: usize, count: usize },
    Backward{ skip: usize, count: usize }
}

impl ReadMode {
    fn into_request(self, stream_id: &str) -> Message {
        use ReadMode::*;
        match self {
            ForwardOnce { skip, count: 1 } | Backward { skip, count: 1 } => {
                let ver = StreamVersion::from_opt(skip as u32).expect("Stream version overflow");
                Builder::read_event()
                    .stream_id(stream_id.to_owned())
                    .event_number(ver)
                    .resolve_link_tos(true)
                    .require_master(false)
                    .build_message()
            },
            ForwardOnce { skip, count } => {
                // TODO: perhaps bad choice of option?
                // TODO: handle at main
                let ver = StreamVersion::from_opt(skip as u32).expect("Stream version overflow");
                Builder::read_stream_events()
                    .direction(Direction::Forward) // TODO: ReadDirection would be more clear?
                    .stream_id(stream_id.to_owned())
                    .from_event_number(ver)
                    .max_count(count as u8) // TODO: restrict at main
                    .build_message()
            },
            Backward { skip, count } => {
                // last is -1, -1; TODO: cannot fit usize
                let ver = StreamVersion::from_opt(skip as u32).expect("Stream version overflow");
                Builder::read_stream_events()
                    .direction(Direction::Forward) // TODO: ReadDirection would be more clear?
                    .stream_id(stream_id.to_owned())
                    .from_event_number(ver)
                    .max_count(count as u8) // TODO: restrict at main
                    .build_message()
            }
        }
    }
}

fn main() {

    let matches = App::new(crate_name!())
        .version(crate_version!())
        .about(crate_description!())
        .author(crate_authors!("\n"))
        .arg(Arg::with_name("hostname")
                .short("h")
                .long("host")
                .value_name("HOST")
                .takes_value(true)
                .help("The name of the host to connect to, default: 127.0.0.1"))
        .arg(Arg::with_name("port")
                .short("p")
                .long("port")
                .value_name("PORT")
                .takes_value(true)
                .help("The port to connect to, default: 1113"))
        .arg(Arg::with_name("verbose")
                 .short("v")
                 .long("verbose")
                 .takes_value(false)
                 .help("Output verbose timings"))
        .subcommand(SubCommand::with_name("ping")
                        .about("Send a ping to the host after possibly authenticating depending on the options"))
        .subcommand(SubCommand::with_name("write")
                        .about("Write single event to a given stream")
                        .arg(Arg::with_name("stream_id")
                                .value_name("STREAM-ID")
                                .required(true)
                                .index(1)
                                .help("Stream id to write to"))
                        .arg(Arg::with_name("expected_version")
                                .value_name("EXPECTED_VERSION")
                                .required(true)
                                .index(2)
                                .help("Acceptable values: any|created|n where n >= -2"))
                        .arg(Arg::with_name("type")
                                .value_name("TYPE")
                                .required(true)
                                .index(3)
                                .help("Type name of the event"))
                        .arg(Arg::with_name("data")
                                .value_name("DATA")
                                .required(true)
                                .index(4)
                                .help("Raw bytes of data."))
                        .arg(Arg::with_name("metadata")
                                .value_name("METADATA")
                                .required(false)
                                .index(5)
                                .help("Raw bytes of metadata, optional"))
                        .arg(Arg::with_name("json")
                                .short("j")
                                .long("json")
                                .takes_value(false)
                                .help("Flags the data and metadata (when given) as json values")))
        .subcommand(SubCommand::with_name("read")
                        .about("Read event(s) of a stream")
                        .arg(Arg::with_name("stream_id")
                                .value_name("STREAM-ID")
                                .required(true)
                                .index(1)
                                .help("Stream id to read from, or $all for every stream"))
                        .arg(Arg::with_name("count")
                             .value_name("N")
                             .short("c")
                             .long("count")
                             .takes_value(true)
                             .help("Number of events to read, 'all' or N > 0, defaults to 1"))
                        .arg(Arg::with_name("skip")
                             .value_name("SKIP")
                             .short("s")
                             .long("skip")
                             .takes_value(true)
                             .help("The event number to start from, defaults to 0"))
                        .arg(Arg::with_name("mode")
                             .value_name("MODE")
                             .short("m")
                             .long("mode")
                             .takes_value(true)
                             .possible_values(&["forward-forever", "forward-once", "backward"])
                             .help("'forward-once' reads up until the current latest,
'forward-forever' stays and awaits for new messages until count has been reached,
'backward' goes to up to first event"))
                        .arg(Arg::with_name("output")
                             .value_name("OUTPUT_MODE")
                             .short("o")
                             .long("output")
                             .takes_value(true)
                             .possible_values(&["debug", "utf8_lossy", "json_oneline", "hex"])
                             .help("'debug' will print the structure with {:?} or {:#?} depending on verbose
'utf8_lossy' will attempt to decode data as utf8
'json_oneline' will parse the json and stringify on one line
'hex' will write data as hexadecimals")))
        .get_matches();

    let addr = {
        let s = format!("{}:{}", matches.value_of("hostname").unwrap_or("127.0.0.1"), matches.value_of("port").unwrap_or("1113"));
        s.parse::<SocketAddr>().expect("Failed to parse host:port as SocketAddr")
    };

    let verbose = matches.is_present("verbose");

    let res = if let Some(_) = matches.subcommand_matches("ping") {
        ping(addr, verbose)
    } else if let Some(w) = matches.subcommand_matches("write") {
        let mut builder = Builder::write_events();
        builder.stream_id(w.value_of("stream_id").unwrap().to_owned())
            .expected_version(match w.value_of("expected_version").unwrap() {
                "any" => ExpectedVersion::Any,
                "created" => ExpectedVersion::NewStream,
                n => ExpectedVersion::Exact(StreamVersion::from_opt(n.parse().unwrap()).expect("Stream version out of bounds"))
            })
            .require_master(w.is_present("require_master"));

        {
            let mut event = builder.new_event();

            event = event.data(w.value_of("data").unwrap().as_bytes().iter().cloned().collect::<Vec<_>>())
                .data_content_type(w.is_present("json"))
                .event_type(w.value_of("type").unwrap().to_owned());

            event = if let Some(x) = w.value_of("metadata") {
                event.metadata(x.as_bytes().iter().cloned().collect::<Vec<_>>())
                    .metadata_content_type(w.is_present("json"))
            } else {
                event
            };

            event.done();
        }

        write(addr, verbose, builder.build_package(None, None))
    } else if let Some(r) = matches.subcommand_matches("read") {
        let stream_id = r.value_of("stream_id").unwrap();
        let count: usize = match r.value_of("count").unwrap_or("1") {
            "all" => usize::max_value(),
            s => s.parse().expect("Parsing count failed"),
        };

        let skip: usize = r.value_of("skip").unwrap_or("0").parse().expect("Parsing skip failed");
        let mode = match r.value_of("mode") {
            None | Some("forward-once") => ReadMode::ForwardOnce{skip, count},
            Some("forward-forever") => unimplemented!(),
            Some("backward") => ReadMode::Backward{skip, count},
            _ => unreachable!(),
        };

        read(addr, verbose, stream_id, mode)
    } else {
        println!("Subcommand is required.\n\n{}", matches.usage());
        process::exit(1);
    };

    if let Err(e) = res {
        println!("Failure: {:?}", e);
        process::exit(1);
    }
}

use std::time::Instant;

fn ping(addr: SocketAddr, verbose: bool) -> Result<(), io::Error> {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let started = Instant::now();

    let job = EventStoreClient::connect(&addr, &handle)
        .map(|client| (client, Instant::now()))
        .and_then(|(client, connected)| {

            let f = client.call(Builder::ping().build_package(None, None));
            let send_began = Instant::now();

            f.map(move |resp| (resp, connected, send_began))
        }).and_then(|(pong, connected, send_began)| {
            let received = Instant::now();
            match pong.message {
                Message::Pong => Ok((connected, send_began, received)),
                msg => Err(io::Error::new(io::ErrorKind::Other, format!("Unexpected response: {:?}", msg)))
            }
        }).and_then(move |(connected, send_began, received)| {
            if verbose {
                print_elapsed("connected in  ", connected - started);
                print_elapsed("ready to send ", send_began - connected);
                print_elapsed("received in   ", received - send_began);
                print_elapsed("total         ", started.elapsed());
            } else {
                print_elapsed("pong received in", started.elapsed());
            }

            Ok(())
        });

    core.run(job)
}

fn write(addr: SocketAddr, verbose: bool, pkg: Package) -> Result<(), io::Error> {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let client = EventStoreClient::connect(&addr, &handle);
    let started = Instant::now();

    let job = client.and_then(|client| {
        client.call(pkg)
    }).and_then(|resp| {
        match resp.message {
            Message::WriteEventsCompleted(Ok(success)) => {
                print_elapsed("Success in", started.elapsed());
                if verbose {
                    println!("{:#?}", success);
                }
                Ok(())
            },
            Message::WriteEventsCompleted(Err(reason)) => {
                Err(io::Error::new(io::ErrorKind::Other, format!("{}", reason)))
            },
            x => {
                Err(io::Error::new(io::ErrorKind::Other, format!("Unexpected response: {:?}", x)))
            }
        }
    });

    core.run(job)
}

fn read(addr: SocketAddr, _: bool, stream_id: &str, mode: ReadMode) -> Result<(), io::Error> {
    /*if stream_id == "$all" {
        unimplemented!();
    }*/

    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let client = EventStoreClient::connect(&addr, &handle);

    let job = client.and_then(|client| {
        client.call(Package {
            authentication: None,
            correlation_id: Uuid::new_v4(),
            message: mode.into_request(stream_id),
        })
    }).and_then(|resp| {
        println!("{:#?}", resp);
        Ok(())
    });

    core.run(job)
}

use std::time::Duration;

fn print_elapsed(subject: &str, d: Duration) {
    println!("{} {}.{:06}ms", subject, d.as_secs() * 1000 + d.subsec_nanos() as u64 / 1_000_000, d.subsec_nanos() % 1_000_000);
}

/*
fn nice(addr: &SocketAddr, handle: &Handle) {
    let client = EventStoreClient::connect(&addr, &handle);
    client.and_then(|client| {

    });
}*/

/*
struct Client {
    tx: mpsc::Sender<(Package, oneshot::Sender<Result<Package, io::Error>>)>,
}

impl Client {
    fn new(addr: &SocketAddr, handle: &Handle) -> Client {
        let (tx, rx) = mpsc::channel::<(Package, oneshot::Sender<Result<Package, io::Error>>)>(4);
        let client = EventStoreClient::connect(addr, handle);
        let task = client.and_then(move |client| {
            rx.for_each(move |(pkg, tx)| {
                client.call(pkg).then(|res| {
                    let ret = match res {
                        Ok(_) => Ok(()),
                        Err(_) => Err(())
                    };
                    tx.complete(res);
                    ret
                })
            }).map_err(|_| io::Error::new(io::ErrorKind::Other, "dunno?"))
        });
        handle.spawn(task.then(|res| match res { Ok(_) => Ok(()), Err(_) => Err(()) }));
        Client { tx: tx }
    }

    fn call(&self, msg: Message) -> MessageFuture {
        let (tx, rx) = oneshot::channel();

        self.tx.send(());
    }
}*/

// connecting
// ready
// heartbeat
// disconnected
<commit_msg>testclient: add output indirection<commit_after>extern crate futures;
extern crate tokio_core;
extern crate tokio_service;
extern crate uuid;

#[macro_use]
extern crate clap;
extern crate es_proto;

use std::io;
use std::net::SocketAddr;
use std::process;
use uuid::Uuid;

use futures::Future;
use tokio_core::reactor::Core;
use tokio_service::Service;

use clap::{Arg, App, SubCommand};

use es_proto::{EventStoreClient, Package, Message, Builder, ExpectedVersion, StreamVersion, Direction};

#[derive(Debug)]
enum ReadMode {
    ForwardOnce{ skip: usize, count: usize },
    Backward{ skip: usize, count: usize }
}

#[derive(Debug, Clone)]
enum OutputMode {
    Debug,
    Utf8Lossy,
    JsonOneline,
    Hex
}

impl Copy for OutputMode {}

impl<'a> From<&'a str> for OutputMode {
    fn from(s: &'a str) -> OutputMode {
        match s {
            "debug" => OutputMode::Debug,
            "utf8_lossy" => OutputMode::Utf8Lossy,
            "json_oneline" => OutputMode::JsonOneline,
            "hex" => OutputMode::Hex,
            _ => panic!("Unsupport mode: {}", s)
        }
    }
}

impl OutputMode {
    fn format<Out: io::Write>(&self, verbose: bool, msg: Message, out: &mut Out) -> io::Result<()> {
        match *self {
            OutputMode::Debug => {
                if verbose {
                    writeln!(out, "{:#?}", msg)
                } else {
                    writeln!(out, "{:?}", msg)
                }
            },
            _ => unimplemented!()
        }
    }
}

impl ReadMode {
    fn into_request(self, stream_id: &str) -> Message {
        use ReadMode::*;
        match self {
            ForwardOnce { skip, count: 1 } | Backward { skip, count: 1 } => {
                let ver = StreamVersion::from_opt(skip as u32).expect("Stream version overflow");
                Builder::read_event()
                    .stream_id(stream_id.to_owned())
                    .event_number(ver)
                    .resolve_link_tos(true)
                    .require_master(false)
                    .build_message()
            },
            ForwardOnce { skip, count } => {
                // TODO: perhaps bad choice of option?
                // TODO: handle at main
                let ver = StreamVersion::from_opt(skip as u32).expect("Stream version overflow");
                Builder::read_stream_events()
                    .direction(Direction::Forward) // TODO: ReadDirection would be more clear?
                    .stream_id(stream_id.to_owned())
                    .from_event_number(ver)
                    .max_count(count as u8) // TODO: restrict at main
                    .build_message()
            },
            Backward { skip, count } => {
                // last is -1, -1; TODO: cannot fit usize
                let ver = StreamVersion::from_opt(skip as u32).expect("Stream version overflow");
                Builder::read_stream_events()
                    .direction(Direction::Forward) // TODO: ReadDirection would be more clear?
                    .stream_id(stream_id.to_owned())
                    .from_event_number(ver)
                    .max_count(count as u8) // TODO: restrict at main
                    .build_message()
            }
        }
    }
}

fn main() {

    let matches = App::new(crate_name!())
        .version(crate_version!())
        .about(crate_description!())
        .author(crate_authors!("\n"))
        .arg(Arg::with_name("hostname")
                .short("h")
                .long("host")
                .value_name("HOST")
                .takes_value(true)
                .help("The name of the host to connect to, default: 127.0.0.1"))
        .arg(Arg::with_name("port")
                .short("p")
                .long("port")
                .value_name("PORT")
                .takes_value(true)
                .help("The port to connect to, default: 1113"))
        .arg(Arg::with_name("verbose")
                 .short("v")
                 .long("verbose")
                 .takes_value(false)
                 .help("Output verbose timings"))
        .subcommand(SubCommand::with_name("ping")
                        .about("Send a ping to the host after possibly authenticating depending on the options"))
        .subcommand(SubCommand::with_name("write")
                        .about("Write single event to a given stream")
                        .arg(Arg::with_name("stream_id")
                                .value_name("STREAM-ID")
                                .required(true)
                                .index(1)
                                .help("Stream id to write to"))
                        .arg(Arg::with_name("expected_version")
                                .value_name("EXPECTED_VERSION")
                                .required(true)
                                .index(2)
                                .help("Acceptable values: any|created|n where n >= -2"))
                        .arg(Arg::with_name("type")
                                .value_name("TYPE")
                                .required(true)
                                .index(3)
                                .help("Type name of the event"))
                        .arg(Arg::with_name("data")
                                .value_name("DATA")
                                .required(true)
                                .index(4)
                                .help("Raw bytes of data."))
                        .arg(Arg::with_name("metadata")
                                .value_name("METADATA")
                                .required(false)
                                .index(5)
                                .help("Raw bytes of metadata, optional"))
                        .arg(Arg::with_name("json")
                                .short("j")
                                .long("json")
                                .takes_value(false)
                                .help("Flags the data and metadata (when given) as json values")))
        .subcommand(SubCommand::with_name("read")
                        .about("Read event(s) of a stream")
                        .arg(Arg::with_name("stream_id")
                                .value_name("STREAM-ID")
                                .required(true)
                                .index(1)
                                .help("Stream id to read from, or $all for every stream"))
                        .arg(Arg::with_name("count")
                             .value_name("N")
                             .short("c")
                             .long("count")
                             .takes_value(true)
                             .help("Number of events to read, 'all' or N > 0, defaults to 1"))
                        .arg(Arg::with_name("skip")
                             .value_name("SKIP")
                             .short("s")
                             .long("skip")
                             .takes_value(true)
                             .help("The event number to start from, defaults to 0"))
                        .arg(Arg::with_name("mode")
                             .value_name("MODE")
                             .short("m")
                             .long("mode")
                             .takes_value(true)
                             .possible_values(&["forward-forever", "forward-once", "backward"])
                             .help("'forward-once' reads up until the current latest,
'forward-forever' stays and awaits for new messages until count has been reached,
'backward' goes to up to first event"))
                        .arg(Arg::with_name("output")
                             .value_name("OUTPUT_MODE")
                             .short("o")
                             .long("output")
                             .takes_value(true)
                             .possible_values(&["debug", "utf8_lossy", "json_oneline", "hex"])
                             .help("'debug' will print the structure with {:?} or {:#?} depending on verbose
'utf8_lossy' will attempt to decode data as utf8
'json_oneline' will parse the json and stringify on one line
'hex' will write data as hexadecimals")))
        .get_matches();

    let addr = {
        let s = format!("{}:{}", matches.value_of("hostname").unwrap_or("127.0.0.1"), matches.value_of("port").unwrap_or("1113"));
        s.parse::<SocketAddr>().expect("Failed to parse host:port as SocketAddr")
    };

    let verbose = matches.is_present("verbose");

    let res = if let Some(_) = matches.subcommand_matches("ping") {
        ping(addr, verbose)
    } else if let Some(w) = matches.subcommand_matches("write") {
        let mut builder = Builder::write_events();
        builder.stream_id(w.value_of("stream_id").unwrap().to_owned())
            .expected_version(match w.value_of("expected_version").unwrap() {
                "any" => ExpectedVersion::Any,
                "created" => ExpectedVersion::NewStream,
                n => ExpectedVersion::Exact(StreamVersion::from_opt(n.parse().unwrap()).expect("Stream version out of bounds"))
            })
            .require_master(w.is_present("require_master"));

        {
            let mut event = builder.new_event();

            event = event.data(w.value_of("data").unwrap().as_bytes().iter().cloned().collect::<Vec<_>>())
                .data_content_type(w.is_present("json"))
                .event_type(w.value_of("type").unwrap().to_owned());

            event = if let Some(x) = w.value_of("metadata") {
                event.metadata(x.as_bytes().iter().cloned().collect::<Vec<_>>())
                    .metadata_content_type(w.is_present("json"))
            } else {
                event
            };

            event.done();
        }

        write(addr, verbose, builder.build_package(None, None))
    } else if let Some(r) = matches.subcommand_matches("read") {
        let stream_id = r.value_of("stream_id").unwrap();
        let count: usize = match r.value_of("count").unwrap_or("1") {
            "all" => usize::max_value(),
            s => s.parse().expect("Parsing count failed"),
        };

        let skip: usize = r.value_of("skip").unwrap_or("0").parse().expect("Parsing skip failed");
        let mode = match r.value_of("mode") {
            None | Some("forward-once") => ReadMode::ForwardOnce{skip, count},
            Some("forward-forever") => unimplemented!(),
            Some("backward") => ReadMode::Backward{skip, count},
            _ => unreachable!(),
        };

        let output = r.value_of("output").map(OutputMode::from).unwrap_or(OutputMode::Debug);

        read(addr, verbose, output, stream_id, mode)
    } else {
        println!("Subcommand is required.\n\n{}", matches.usage());
        process::exit(1);
    };

    if let Err(e) = res {
        println!("Failure: {:?}", e);
        process::exit(1);
    }
}

use std::time::Instant;

fn ping(addr: SocketAddr, verbose: bool) -> Result<(), io::Error> {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let started = Instant::now();

    let job = EventStoreClient::connect(&addr, &handle)
        .map(|client| (client, Instant::now()))
        .and_then(|(client, connected)| {

            let f = client.call(Builder::ping().build_package(None, None));
            let send_began = Instant::now();

            f.map(move |resp| (resp, connected, send_began))
        }).and_then(|(pong, connected, send_began)| {
            let received = Instant::now();
            match pong.message {
                Message::Pong => Ok((connected, send_began, received)),
                msg => Err(io::Error::new(io::ErrorKind::Other, format!("Unexpected response: {:?}", msg)))
            }
        }).and_then(move |(connected, send_began, received)| {
            if verbose {
                print_elapsed("connected in  ", connected - started);
                print_elapsed("ready to send ", send_began - connected);
                print_elapsed("received in   ", received - send_began);
                print_elapsed("total         ", started.elapsed());
            } else {
                print_elapsed("pong received in", started.elapsed());
            }

            Ok(())
        });

    core.run(job)
}

fn write(addr: SocketAddr, verbose: bool, pkg: Package) -> Result<(), io::Error> {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let client = EventStoreClient::connect(&addr, &handle);
    let started = Instant::now();

    let job = client.and_then(|client| {
        client.call(pkg)
    }).and_then(|resp| {
        match resp.message {
            Message::WriteEventsCompleted(Ok(success)) => {
                print_elapsed("Success in", started.elapsed());
                if verbose {
                    println!("{:#?}", success);
                }
                Ok(())
            },
            Message::WriteEventsCompleted(Err(reason)) => {
                Err(io::Error::new(io::ErrorKind::Other, format!("{}", reason)))
            },
            x => {
                Err(io::Error::new(io::ErrorKind::Other, format!("Unexpected response: {:?}", x)))
            }
        }
    });

    core.run(job)
}

fn read(addr: SocketAddr, verbose: bool, output: OutputMode, stream_id: &str, mode: ReadMode) -> Result<(), io::Error> {
    /*if stream_id == "$all" {
        unimplemented!();
    }*/

    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let client = EventStoreClient::connect(&addr, &handle);

    let job = client.and_then(|client| {
        client.call(Package {
            authentication: None,
            correlation_id: Uuid::new_v4(),
            message: mode.into_request(stream_id),
        })
    }).and_then(|resp| {
        let mut stdout = io::stdout();
        output.format(verbose, resp.message, &mut stdout)
    });

    core.run(job)
}

use std::time::Duration;

fn print_elapsed(subject: &str, d: Duration) {
    println!("{} {}.{:06}ms", subject, d.as_secs() * 1000 + d.subsec_nanos() as u64 / 1_000_000, d.subsec_nanos() % 1_000_000);
}

/*
fn nice(addr: &SocketAddr, handle: &Handle) {
    let client = EventStoreClient::connect(&addr, &handle);
    client.and_then(|client| {

    });
}*/

/*
struct Client {
    tx: mpsc::Sender<(Package, oneshot::Sender<Result<Package, io::Error>>)>,
}

impl Client {
    fn new(addr: &SocketAddr, handle: &Handle) -> Client {
        let (tx, rx) = mpsc::channel::<(Package, oneshot::Sender<Result<Package, io::Error>>)>(4);
        let client = EventStoreClient::connect(addr, handle);
        let task = client.and_then(move |client| {
            rx.for_each(move |(pkg, tx)| {
                client.call(pkg).then(|res| {
                    let ret = match res {
                        Ok(_) => Ok(()),
                        Err(_) => Err(())
                    };
                    tx.complete(res);
                    ret
                })
            }).map_err(|_| io::Error::new(io::ErrorKind::Other, "dunno?"))
        });
        handle.spawn(task.then(|res| match res { Ok(_) => Ok(()), Err(_) => Err(()) }));
        Client { tx: tx }
    }

    fn call(&self, msg: Message) -> MessageFuture {
        let (tx, rx) = oneshot::channel();

        self.tx.send(());
    }
}*/

// connecting
// ready
// heartbeat
// disconnected
<|endoftext|>


<commit_before>use files::dump;

pub struct Token<'a>
{
    pub name: &'a str,
    pub range: (usize, usize),
    pub value: String,
}

pub trait Printable
{
    fn print_to(&self, file_path: &str, console_out: bool);

    fn format_for_print(&self, console_out: bool) -> String;
}

impl <'a> Printable for Vec<Token<'a>>
{
    fn print_to(&self, file_path: &str, console_out: bool)
    {
        let lexed_token_string = self.format_for_print(console_out);
        if file_path.len() > 0 { dump(file_path, lexed_token_string); }
    }

    fn format_for_print(&self, console_out: bool) -> String
    {
        let mut lexed_token_string: String = String::new();

        for token in self.iter()
        {
            lexed_token_string.push_str(token.name);
            lexed_token_string.push_str("\t");
            lexed_token_string.push_str(&*token.value);
            lexed_token_string.push_str("\n");

            if console_out { println!("\t{}\t{:?}\t{}", token.name, token.range, token.value); }
        }

        lexed_token_string
    }
}
<commit_msg>Clone implementation for Token<commit_after>use files::dump;

pub struct Token<'a>
{
    pub name: &'a str,
    pub range: (usize, usize),
    pub value: String,
}

impl <'a> Token<'a>
{
    pub fn clone(&self) -> Token<'a>
    {
        Token
        {
            name: self.name.clone(),
            range: self.range.clone(),
            value: self.value.clone(),
        }
    }
}

pub trait Printable
{
    fn print_to(&self, file_path: &str, console_out: bool);

    fn format_for_print(&self, console_out: bool) -> String;
}

impl <'a> Printable for Vec<Token<'a>>
{
    fn print_to(&self, file_path: &str, console_out: bool)
    {
        let lexed_token_string = self.format_for_print(console_out);
        if file_path.len() > 0 { dump(file_path, lexed_token_string); }
    }

    fn format_for_print(&self, console_out: bool) -> String
    {
        let mut lexed_token_string: String = String::new();

        for token in self.iter()
        {
            lexed_token_string.push_str(token.name);
            lexed_token_string.push_str("\t");
            lexed_token_string.push_str(&*token.value);
            lexed_token_string.push_str("\n");

            if console_out { println!("\t{}\t{:?}\t{}", token.name, token.range, token.value); }
        }

        lexed_token_string
    }
}
<|endoftext|>


<commit_before>use clock::Clock;

//
// Clock Creation
//

#[test]
fn test_on_the_hour() {
    assert_eq!(Clock::new(8, 0).to_string(), "08:00");
}

#[test]
#[ignore]
fn test_past_the_hour() {
    assert_eq!(Clock::new(11, 9).to_string(), "11:09");
}

#[test]
#[ignore]
fn test_midnight_is_zero_hours() {
    assert_eq!(Clock::new(24, 0).to_string(), "00:00");
}

#[test]
#[ignore]
fn test_hour_rolls_over() {
    assert_eq!(Clock::new(25, 0).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_hour_rolls_over_continuously() {
    assert_eq!(Clock::new(100, 0).to_string(), "04:00");
}

#[test]
#[ignore]
fn test_sixty_minutes_is_next_hour() {
    assert_eq!(Clock::new(1, 60).to_string(), "02:00");
}

#[test]
#[ignore]
fn test_minutes_roll_over() {
    assert_eq!(Clock::new(0, 160).to_string(), "02:40");
}

#[test]
#[ignore]
fn test_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(0, 1723).to_string(), "04:43");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over() {
    assert_eq!(Clock::new(25, 160).to_string(), "03:40");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(201, 3001).to_string(), "11:01");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over_to_exactly_midnight() {
    assert_eq!(Clock::new(72, 8640).to_string(), "00:00");
}

#[test]
#[ignore]
fn test_negative_hour() {
    assert_eq!(Clock::new(-1, 15).to_string(), "23:15");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over() {
    assert_eq!(Clock::new(-25, 00).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over_continuously() {
    assert_eq!(Clock::new(-91, 00).to_string(), "05:00");
}

#[test]
#[ignore]
fn test_negative_minutes() {
    assert_eq!(Clock::new(1, -40).to_string(), "00:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over() {
    assert_eq!(Clock::new(1, -160).to_string(), "22:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(1, -4820).to_string(), "16:40");
}

#[test]
#[ignore]
fn test_negative_sixty_minutes_is_prev_hour() {
    assert_eq!(Clock::new(2, -60).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over() {
    assert_eq!(Clock::new(-25, -160).to_string(), "20:20");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over_continuously() {
    assert_eq!(Clock::new(-121, -5810).to_string(), "22:10");
}

//
// Clock Math
//

#[test]
#[ignore]
fn test_add_minutes() {
    let clock = Clock::new(10, 0).add_minutes(3);
    assert_eq!(clock.to_string(), "10:03");
}

#[test]
#[ignore]
fn test_add_no_minutes() {
    let clock = Clock::new(6, 41).add_minutes(0);
    assert_eq!(clock.to_string(), "06:41");
}

#[test]
#[ignore]
fn test_add_to_next_hour() {
    let clock = Clock::new(0, 45).add_minutes(40);
    assert_eq!(clock.to_string(), "01:25");
}

#[test]
#[ignore]
fn test_add_more_than_one_hour() {
    let clock = Clock::new(10, 0).add_minutes(61);
    assert_eq!(clock.to_string(), "11:01");
}

#[test]
#[ignore]
fn test_add_more_than_two_hours_with_carry() {
    let clock = Clock::new(0, 45).add_minutes(160);
    assert_eq!(clock.to_string(), "03:25");
}

#[test]
#[ignore]
fn test_add_across_midnight() {
    let clock = Clock::new(23, 59).add_minutes(2);
    assert_eq!(clock.to_string(), "00:01");
}

#[test]
#[ignore]
fn test_add_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(1500);
    assert_eq!(clock.to_string(), "06:32");
}

#[test]
#[ignore]
fn test_add_more_than_two_days() {
    let clock = Clock::new(1, 1).add_minutes(3500);
    assert_eq!(clock.to_string(), "11:21");
}

#[test]
#[ignore]
fn test_subtract_minutes() {
    let clock = Clock::new(10, 3).add_minutes(-3);
    assert_eq!(clock.to_string(), "10:00");
}

#[test]
#[ignore]
fn test_subtract_to_previous_hour() {
    let clock = Clock::new(10, 3).add_minutes(-30);
    assert_eq!(clock.to_string(), "09:33");
}

#[test]
#[ignore]
fn test_subtract_more_than_an_hour() {
    let clock = Clock::new(10, 3).add_minutes(-70);
    assert_eq!(clock.to_string(), "08:53");
}

#[test]
#[ignore]
fn test_subtract_across_midnight() {
    let clock = Clock::new(0, 3).add_minutes(-4);
    assert_eq!(clock.to_string(), "23:59");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours() {
    let clock = Clock::new(0, 0).add_minutes(-160);
    assert_eq!(clock.to_string(), "21:20");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours_with_borrow() {
    let clock = Clock::new(6, 15).add_minutes(-160);
    assert_eq!(clock.to_string(), "03:35");
}

#[test]
#[ignore]
fn test_subtract_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(-1500);
    assert_eq!(clock.to_string(), "04:32");
}

#[test]
#[ignore]
fn test_subtract_mores_than_two_days() {
    let clock = Clock::new(2, 20).add_minutes(-3000);
    assert_eq!(clock.to_string(), "00:20");
}

//
// Test Equality
//

#[test]
#[ignore]
fn test_compare_clocks_for_equality() {
    assert_eq!(Clock::new(15, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_a_minute_apart() {
    assert_ne!(Clock::new(15, 36), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_an_hour_apart() {
    assert_ne!(Clock::new(14, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow() {
    assert_eq!(Clock::new(10, 37), Clock::new(34, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow_by_several_days() {
    assert_eq!(Clock::new(3, 11), Clock::new(99, 11));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour() {
    assert_eq!(Clock::new(22, 40), Clock::new(-2, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps() {
    assert_eq!(Clock::new(17, 3), Clock::new(-31, 3));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() {
    assert_eq!(Clock::new(13, 49), Clock::new(-83, 49));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow() {
    assert_eq!(Clock::new(0, 1), Clock::new(0, 1441));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow_by_several_days() {
    assert_eq!(Clock::new(2, 2), Clock::new(2, 4322));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute() {
    assert_eq!(Clock::new(2, 40), Clock::new(3, -20))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps() {
    assert_eq!(Clock::new(4, 10), Clock::new(5, -1490))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps_multiple() {
    assert_eq!(Clock::new(6, 15), Clock::new(6, -4305))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes() {
    assert_eq!(Clock::new(7, 32), Clock::new(-12, -268))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() {
    assert_eq!(Clock::new(18, 7), Clock::new(-54, -11_513))
}

#[test]
#[ignore]
fn test_compare_full_clock_and_zeroed_clock() {
    assert_eq!(Clock::new(24, 0), Clock::new(0, 0))
}
<commit_msg>clock: Add a test case for some edge case (#952)<commit_after>use clock::Clock;

//
// Clock Creation
//

#[test]
fn test_on_the_hour() {
    assert_eq!(Clock::new(8, 0).to_string(), "08:00");
}

#[test]
#[ignore]
fn test_past_the_hour() {
    assert_eq!(Clock::new(11, 9).to_string(), "11:09");
}

#[test]
#[ignore]
fn test_midnight_is_zero_hours() {
    assert_eq!(Clock::new(24, 0).to_string(), "00:00");
}

#[test]
#[ignore]
fn test_hour_rolls_over() {
    assert_eq!(Clock::new(25, 0).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_hour_rolls_over_continuously() {
    assert_eq!(Clock::new(100, 0).to_string(), "04:00");
}

#[test]
#[ignore]
fn test_sixty_minutes_is_next_hour() {
    assert_eq!(Clock::new(1, 60).to_string(), "02:00");
}

#[test]
#[ignore]
fn test_minutes_roll_over() {
    assert_eq!(Clock::new(0, 160).to_string(), "02:40");
}

#[test]
#[ignore]
fn test_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(0, 1723).to_string(), "04:43");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over() {
    assert_eq!(Clock::new(25, 160).to_string(), "03:40");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(201, 3001).to_string(), "11:01");
}

#[test]
#[ignore]
fn test_hours_and_minutes_roll_over_to_exactly_midnight() {
    assert_eq!(Clock::new(72, 8640).to_string(), "00:00");
}

#[test]
#[ignore]
fn test_negative_hour() {
    assert_eq!(Clock::new(-1, 15).to_string(), "23:15");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over() {
    assert_eq!(Clock::new(-25, 00).to_string(), "23:00");
}

#[test]
#[ignore]
fn test_negative_hour_roll_over_continuously() {
    assert_eq!(Clock::new(-91, 00).to_string(), "05:00");
}

#[test]
#[ignore]
fn test_negative_minutes() {
    assert_eq!(Clock::new(1, -40).to_string(), "00:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over() {
    assert_eq!(Clock::new(1, -160).to_string(), "22:20");
}

#[test]
#[ignore]
fn test_negative_minutes_roll_over_continuously() {
    assert_eq!(Clock::new(1, -4820).to_string(), "16:40");
}

#[test]
#[ignore]
fn test_negative_sixty_minutes_is_prev_hour() {
    assert_eq!(Clock::new(2, -60).to_string(), "01:00");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over() {
    assert_eq!(Clock::new(-25, -160).to_string(), "20:20");
}

#[test]
#[ignore]
fn test_negative_hour_and_minutes_both_roll_over_continuously() {
    assert_eq!(Clock::new(-121, -5810).to_string(), "22:10");
}

#[test]
#[ignore]
fn test_zero_hour_and_negative_minutes() {
    assert_eq!(Clock::new(0, -22).to_string(), "23:38");
}

//
// Clock Math
//

#[test]
#[ignore]
fn test_add_minutes() {
    let clock = Clock::new(10, 0).add_minutes(3);
    assert_eq!(clock.to_string(), "10:03");
}

#[test]
#[ignore]
fn test_add_no_minutes() {
    let clock = Clock::new(6, 41).add_minutes(0);
    assert_eq!(clock.to_string(), "06:41");
}

#[test]
#[ignore]
fn test_add_to_next_hour() {
    let clock = Clock::new(0, 45).add_minutes(40);
    assert_eq!(clock.to_string(), "01:25");
}

#[test]
#[ignore]
fn test_add_more_than_one_hour() {
    let clock = Clock::new(10, 0).add_minutes(61);
    assert_eq!(clock.to_string(), "11:01");
}

#[test]
#[ignore]
fn test_add_more_than_two_hours_with_carry() {
    let clock = Clock::new(0, 45).add_minutes(160);
    assert_eq!(clock.to_string(), "03:25");
}

#[test]
#[ignore]
fn test_add_across_midnight() {
    let clock = Clock::new(23, 59).add_minutes(2);
    assert_eq!(clock.to_string(), "00:01");
}

#[test]
#[ignore]
fn test_add_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(1500);
    assert_eq!(clock.to_string(), "06:32");
}

#[test]
#[ignore]
fn test_add_more_than_two_days() {
    let clock = Clock::new(1, 1).add_minutes(3500);
    assert_eq!(clock.to_string(), "11:21");
}

#[test]
#[ignore]
fn test_subtract_minutes() {
    let clock = Clock::new(10, 3).add_minutes(-3);
    assert_eq!(clock.to_string(), "10:00");
}

#[test]
#[ignore]
fn test_subtract_to_previous_hour() {
    let clock = Clock::new(10, 3).add_minutes(-30);
    assert_eq!(clock.to_string(), "09:33");
}

#[test]
#[ignore]
fn test_subtract_more_than_an_hour() {
    let clock = Clock::new(10, 3).add_minutes(-70);
    assert_eq!(clock.to_string(), "08:53");
}

#[test]
#[ignore]
fn test_subtract_across_midnight() {
    let clock = Clock::new(0, 3).add_minutes(-4);
    assert_eq!(clock.to_string(), "23:59");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours() {
    let clock = Clock::new(0, 0).add_minutes(-160);
    assert_eq!(clock.to_string(), "21:20");
}

#[test]
#[ignore]
fn test_subtract_more_than_two_hours_with_borrow() {
    let clock = Clock::new(6, 15).add_minutes(-160);
    assert_eq!(clock.to_string(), "03:35");
}

#[test]
#[ignore]
fn test_subtract_more_than_one_day() {
    let clock = Clock::new(5, 32).add_minutes(-1500);
    assert_eq!(clock.to_string(), "04:32");
}

#[test]
#[ignore]
fn test_subtract_mores_than_two_days() {
    let clock = Clock::new(2, 20).add_minutes(-3000);
    assert_eq!(clock.to_string(), "00:20");
}

//
// Test Equality
//

#[test]
#[ignore]
fn test_compare_clocks_for_equality() {
    assert_eq!(Clock::new(15, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_a_minute_apart() {
    assert_ne!(Clock::new(15, 36), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_an_hour_apart() {
    assert_ne!(Clock::new(14, 37), Clock::new(15, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow() {
    assert_eq!(Clock::new(10, 37), Clock::new(34, 37));
}

#[test]
#[ignore]
fn test_compare_clocks_with_hour_overflow_by_several_days() {
    assert_eq!(Clock::new(3, 11), Clock::new(99, 11));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour() {
    assert_eq!(Clock::new(22, 40), Clock::new(-2, 40));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps() {
    assert_eq!(Clock::new(17, 3), Clock::new(-31, 3));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hour_that_wraps_multiple_times() {
    assert_eq!(Clock::new(13, 49), Clock::new(-83, 49));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow() {
    assert_eq!(Clock::new(0, 1), Clock::new(0, 1441));
}

#[test]
#[ignore]
fn test_compare_clocks_with_minutes_overflow_by_several_days() {
    assert_eq!(Clock::new(2, 2), Clock::new(2, 4322));
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute() {
    assert_eq!(Clock::new(2, 40), Clock::new(3, -20))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps() {
    assert_eq!(Clock::new(4, 10), Clock::new(5, -1490))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_minute_that_wraps_multiple() {
    assert_eq!(Clock::new(6, 15), Clock::new(6, -4305))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes() {
    assert_eq!(Clock::new(7, 32), Clock::new(-12, -268))
}

#[test]
#[ignore]
fn test_compare_clocks_with_negative_hours_and_minutes_that_wrap() {
    assert_eq!(Clock::new(18, 7), Clock::new(-54, -11_513))
}

#[test]
#[ignore]
fn test_compare_full_clock_and_zeroed_clock() {
    assert_eq!(Clock::new(24, 0), Clock::new(0, 0))
}
<|endoftext|>


<commit_before>extern crate rustbox;
use rustbox::*;
use screen::common::*;
use utility::string::*;
use model::ShowItem;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show { rustbox: &rustbox }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        print_header(&self.rustbox,
                     self.rustbox.width(),
                     &format!("{} - {}", item.title, title));
        print_body(&self.rustbox,
                   self.body_width(),
                   2,
                   self.body_height(),
                   &item);
    }
    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }
}

fn print_header(rustbox: &rustbox::RustBox, width: usize, text: &str) {
    let title_len = jks_len(text);
    let padding = (if width >= title_len {
        width - title_len
    } else {
        0
    }) / 2;

    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    clearline(&rustbox, width, 0, 0);
    rustbox.print(padding,
                  0,
                  rustbox::RB_BOLD,
                  Color::White,
                  Color::Black,
                  text);
    rustbox.print(0,
                  1,
                  rustbox::RB_BOLD,
                  Color::Yellow,
                  Color::Black,
                  &header_bottom);
}

fn print_body(rustbox: &rustbox::RustBox,
              width: usize,
              offset_y: usize,
              rows: usize,
              item: &ShowItem) {

    let mut y = offset_y;
    let replier_max_width = 14;

    let separator_width = if rustbox.width() >= 4 {
        rustbox.width() - 4
    } else {
        0
    };
    let separator_padding_width = if rustbox.width() > separator_width {
        rustbox.width() - separator_width
    } else {
        0
    } / 2;

    let separator_padding = (0..separator_padding_width).map(|_| " ").collect::<Vec<_>>().join("");

    let separator_bottom = make_separator_bottom(separator_width, &separator_padding);

    for (i, reply) in item.replies.iter().take(rows).enumerate() {
        let contents: Vec<&str> = reply.content.split("\n").collect();

        let mut m = 0;

        for (j, content) in contents.iter().enumerate() {
            rustbox.print(0,
                          j + y,
                          rustbox::RB_NORMAL,
                          Color::White,
                          Color::Black,
                          &format!(" {}", content));
            m += 1;
        }
        let replier_name = reply.username.clone();
        let separator_top = make_separator_top(separator_width,
                                               &separator_padding,
                                               replier_max_width,
                                               &replier_name);

        rustbox.print(0,
                      m + y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &separator_top);
        m += 1;

        rustbox.print(0,
                      m + y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &separator_bottom);
        m += 1;
        y += m;
    }
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str)
                      -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = (0..replier_name_left_spacing_width)
                                        .map(|_| "─")
                                        .collect::<Vec<_>>()
                                        .join("");

    let replier_name_right_spacing = (0..replier_name_right_spacing_width)
                                         .map(|_| "─")
                                         .collect::<Vec<_>>()
                                         .join("");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "╮");
    let separator_replier_width = jks_len(&separator_replier);

    let separator_top_middle_width = if separator_width > separator_replier_width {
        separator_width - separator_replier_width
    } else {
        0
    };
    let separator_top_middle = (0..separator_top_middle_width)
                                   .map(|_| " ")
                                   .collect::<Vec<_>>()
                                   .join("");

    let separator_top = format!("{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_padding);
    return separator_top;
}
fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = (0..separator_bottom_middle_width)
                                      .map(|_| "─")
                                      .collect::<Vec<_>>()
                                      .join("");
    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}
<commit_msg>show - extract make function of replier_name<commit_after>extern crate rustbox;
use rustbox::*;
use screen::common::*;
use utility::string::*;
use model::ShowItem;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show { rustbox: &rustbox }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        print_header(&self.rustbox,
                     self.rustbox.width(),
                     &format!("{} - {}", item.title, title));
        print_body(&self.rustbox,
                   self.body_width(),
                   2,
                   self.body_height(),
                   &item);
    }
    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }
}

fn print_header(rustbox: &rustbox::RustBox, width: usize, text: &str) {
    let title_len = jks_len(text);
    let padding = (if width >= title_len {
        width - title_len
    } else {
        0
    }) / 2;

    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    clearline(&rustbox, width, 0, 0);
    rustbox.print(padding,
                  0,
                  rustbox::RB_BOLD,
                  Color::White,
                  Color::Black,
                  text);
    rustbox.print(0,
                  1,
                  rustbox::RB_BOLD,
                  Color::Yellow,
                  Color::Black,
                  &header_bottom);
}

fn print_body(rustbox: &rustbox::RustBox,
              width: usize,
              offset_y: usize,
              rows: usize,
              item: &ShowItem) {

    let mut y = offset_y;
    let replier_max_width = 14;

    let separator_width = if rustbox.width() >= 4 {
        rustbox.width() - 4
    } else {
        0
    };
    let separator_padding_width = if rustbox.width() > separator_width {
        rustbox.width() - separator_width
    } else {
        0
    } / 2;

    let separator_padding = (0..separator_padding_width).map(|_| " ").collect::<Vec<_>>().join("");

    let separator_bottom = make_separator_bottom(separator_width, &separator_padding);

    for (i, reply) in item.replies.iter().take(rows).enumerate() {
        let contents: Vec<&str> = reply.content.split("\n").collect();

        let mut m = 0;

        for (j, content) in contents.iter().enumerate() {
            rustbox.print(0,
                          j + y,
                          rustbox::RB_NORMAL,
                          Color::White,
                          Color::Black,
                          &format!(" {}", content));
            m += 1;
        }
        let replier_name = reply.username.clone();
        let separator_top = make_separator_top(separator_width,
                                               &separator_padding,
                                               replier_max_width,
                                               &replier_name);

        rustbox.print(0,
                      m + y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &separator_top);
        m += 1;

        rustbox.print(0,
                      m + y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &separator_bottom);
        m += 1;
        y += m;
    }
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = (0..replier_name_left_spacing_width)
                                        .map(|_| "─")
                                        .collect::<Vec<_>>()
                                        .join("");

    let replier_name_right_spacing = (0..replier_name_right_spacing_width)
                                         .map(|_| "─")
                                         .collect::<Vec<_>>()
                                         .join("");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "╮");
    return separator_replier;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_top_middle_width = if separator_width > separator_replier_width {
        separator_width - separator_replier_width
    } else {
        0
    };
    let separator_top_middle = (0..separator_top_middle_width)
                                   .map(|_| " ")
                                   .collect::<Vec<_>>()
                                   .join("");

    let separator_top = format!("{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_padding);
    return separator_top;
}
fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = (0..separator_bottom_middle_width)
                                      .map(|_| "─")
                                      .collect::<Vec<_>>()
                                      .join("");
    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}
<|endoftext|>