<commit_before>use std::io::Read;

use errors::{Result, ErrorKind};
use message::Message;

use byteorder::ReadBytesExt;
use byteorder::LittleEndian as LE;

const WIRE_TYPE_VARINT: u8 = 0;
const WIRE_TYPE_FIXED64: u8 = 1;
const WIRE_TYPE_LENGTH_DELIMITED: u8 = 2;
const WIRE_TYPE_START_GROUP: u8 = 3;
const WIRE_TYPE_END_GROUP: u8 = 4;
const WIRE_TYPE_FIXED32: u8 = 5;

/// A struct to read protocol binary files
pub struct Reader<R> {
    inner: R,
    len: usize,
}

impl<R: Read> Reader<R> {

    /// Creates a new protocol buffer reader with the maximum len of bytes to read
    pub fn from_reader(r: R, len: usize) -> Reader<R> {
        Reader { inner: r, len: len }
    }

    /// Reads next tag, `None` if all bytes have been read
    pub fn next_tag_value(&mut self) -> Option<Result<u32>> {
        if self.len == 0 {
            None
        } else {
            Some(self.read_varint().map(|i| (i as u32)))
        }
    }

    fn read_varint(&mut self) -> Result<u64> {
        let mut r: u64 = 0;
        let mut i = 0;
        for _ in 0..9 {
            self.len -= 1;
            let b = self.inner.read_u8()?;
            r |= ((b & 0x7f) as u64) << i;
            if b < 0x80 {
                return Ok(r);
            }
            i += 7;
        }
        self.len -= 1;
        match self.inner.read_u8()? {
            0 => Ok(r),
            1 => {
                r |= 1 << 63;
                Ok(r)
            }
            _ => Err(ErrorKind::Varint.into()), // we have only one spare bit to fit into
        }
    }

    pub fn read_int32(&mut self) -> Result<i32> {
        self.read_varint().map(|i| i as i32)
    }

    pub fn read_int64(&mut self) -> Result<i64> {
        self.read_varint().map(|i| i as i64)
    }

    pub fn read_uint32(&mut self) -> Result<u32> {
        self.read_varint().map(|i| i as u32)
    }

    pub fn read_uint64(&mut self) -> Result<u64> {
        self.read_varint()
    }

    pub fn read_sint32(&mut self) -> Result<i32> {
        // zigzag
        let n = self.read_varint()? as u32;
        Ok(((n >> 1) as i32) ^ (-((n & 1) as i32)))
    }

    pub fn read_sint64(&mut self) -> Result<i64> {
        // zigzag
        let n = self.read_varint()?;
        Ok(((n >> 1) as i64) ^ (-((n & 1) as i64)))
    }

    pub fn read_fixed64(&mut self) -> Result<u64> {
        self.len -= 8;
        self.inner.read_u64::<LE>().map_err(|e| e.into())
    }

    pub fn read_fixed32(&mut self) -> Result<u32> {
        self.len -= 4;
        self.inner.read_u32::<LE>().map_err(|e| e.into())
    }

    pub fn read_sfixed64(&mut self) -> Result<i64> {
        self.len -= 8;
        self.inner.read_i64::<LE>().map_err(|e| e.into())
    }

    pub fn read_sfixed32(&mut self) -> Result<i32> {
        self.len -= 4;
        self.inner.read_i32::<LE>().map_err(|e| e.into())
    }

    pub fn read_float(&mut self) -> Result<f32> {
        self.len -= 4;
        self.inner.read_f32::<LE>().map_err(|e| e.into())
    }

    pub fn read_double(&mut self) -> Result<f64> {
        self.len -= 8;
        self.inner.read_f64::<LE>().map_err(|e| e.into())
    }

    pub fn read_bool(&mut self) -> Result<bool> {
        self.read_varint().map(|i| i != 0)
    }

    pub fn read_enum<E: From<u64>>(&mut self) -> Result<E> {
        self.read_varint().map(|i| i.into())
    }

    pub fn read_bytes(&mut self) -> Result<Vec<u8>> {
        let len = self.read_varint()? as usize;
        self.len -= len;
        let mut vec = Vec::with_capacity(len);
        unsafe { vec.set_len(len); }
        self.inner.read_exact(&mut vec[..])?;
        Ok(vec)
    }

    pub fn read_string(&mut self) -> Result<String> {
        let vec = self.read_bytes()?;
        String::from_utf8(vec).map_err(|e| e.into())
    }

    pub fn read_packed_repeated_field<M, F: FnMut(&mut Self) -> Result<M>>(&mut self, mut read: F) -> Result<Vec<M>> {
        let len = self.read_varint()? as usize;
        let mut v = Vec::with_capacity(len);
        for _ in 0..len {
            v.push(read(self)?);
        }
        Ok(v)
    }

    pub fn read_message<M: Message>(&mut self) -> Result<M> {
        let len = self.read_varint()? as usize;
        let cur_len = self.len;
        self.len = len;
        let msg = M::from_reader(self)?;
        self.len = cur_len - len;
        Ok(msg)
    }

    pub fn read_unknown(&mut self, tag_value: u32) -> Result<()> {
        match (tag_value & 0x7) as u8 {
            WIRE_TYPE_VARINT => { self.read_varint()?; },
            WIRE_TYPE_FIXED64 => {
                self.len -= 8;
                self.inner.read_exact(&mut [0; 8])?;
            }
            WIRE_TYPE_FIXED32 => {
                self.len -= 4;
                self.inner.read_exact(&mut [0; 4])?;
            }
            WIRE_TYPE_LENGTH_DELIMITED => {
                let len = self.read_varint()? as usize;
                if len == 0 { return Ok(()); }
                self.len -= len;
                let mut buf = Vec::with_capacity(len);
                unsafe { buf.set_len(len); }
                self.inner.read_exact(&mut buf)?;
            },
            WIRE_TYPE_START_GROUP |
                WIRE_TYPE_END_GROUP => { return Err(ErrorKind::Deprecated("group").into()); },
            t => { return Err(ErrorKind::UnknownWireType(t).into()); },
        }
        Ok(())
    }

    pub fn len(&self) -> usize {
        self.len
    }
}

#[test]
fn test_varint() {
    let data: &[u8] = &[0x96, 0x01];
    let mut r = Reader::from_reader(data, data.len());
    assert_eq!(150, r.read_varint().unwrap());
    assert!(r.next_tag().is_none());
}

#[test]
fn test_next_field() {
    let data: &[u8] = &[0x08, 0x96, 0x01];
    let mut r = Reader::from_reader(data, data.len());
    let tag = r.next_tag().unwrap().unwrap();
    assert_eq!((1, WireType::Varint), tag.unpack());
    assert_eq!(150, r.read_varint().unwrap());
    assert!(r.next_tag().is_none());
}
<commit_msg>fix packed<commit_after>use std::io::Read;

use errors::{Result, ErrorKind};
use message::Message;

use byteorder::ReadBytesExt;
use byteorder::LittleEndian as LE;

const WIRE_TYPE_VARINT: u8 = 0;
const WIRE_TYPE_FIXED64: u8 = 1;
const WIRE_TYPE_LENGTH_DELIMITED: u8 = 2;
const WIRE_TYPE_START_GROUP: u8 = 3;
const WIRE_TYPE_END_GROUP: u8 = 4;
const WIRE_TYPE_FIXED32: u8 = 5;

/// A struct to read protocol binary files
pub struct Reader<R> {
    inner: R,
    len: usize,
}

impl<R: Read> Reader<R> {

    /// Creates a new protocol buffer reader with the maximum len of bytes to read
    pub fn from_reader(r: R, len: usize) -> Reader<R> {
        Reader { inner: r, len: len }
    }

    /// Reads next tag, `None` if all bytes have been read
    pub fn next_tag_value(&mut self) -> Option<Result<u32>> {
        if self.len == 0 {
            None
        } else {
            Some(self.read_varint().map(|i| (i as u32)))
        }
    }

    fn read_varint(&mut self) -> Result<u64> {
        let mut r: u64 = 0;
        let mut i = 0;
        for _ in 0..9 {
            self.len -= 1;
            let b = self.inner.read_u8()?;
            r |= ((b & 0x7f) as u64) << i;
            if b < 0x80 {
                return Ok(r);
            }
            i += 7;
        }
        self.len -= 1;
        match self.inner.read_u8()? {
            0 => Ok(r),
            1 => {
                r |= 1 << 63;
                Ok(r)
            }
            _ => Err(ErrorKind::Varint.into()), // we have only one spare bit to fit into
        }
    }

    pub fn read_int32(&mut self) -> Result<i32> {
        self.read_varint().map(|i| i as i32)
    }

    pub fn read_int64(&mut self) -> Result<i64> {
        self.read_varint().map(|i| i as i64)
    }

    pub fn read_uint32(&mut self) -> Result<u32> {
        self.read_varint().map(|i| i as u32)
    }

    pub fn read_uint64(&mut self) -> Result<u64> {
        self.read_varint()
    }

    pub fn read_sint32(&mut self) -> Result<i32> {
        // zigzag
        let n = self.read_varint()? as u32;
        Ok(((n >> 1) as i32) ^ (-((n & 1) as i32)))
    }

    pub fn read_sint64(&mut self) -> Result<i64> {
        // zigzag
        let n = self.read_varint()?;
        Ok(((n >> 1) as i64) ^ (-((n & 1) as i64)))
    }

    pub fn read_fixed64(&mut self) -> Result<u64> {
        self.len -= 8;
        self.inner.read_u64::<LE>().map_err(|e| e.into())
    }

    pub fn read_fixed32(&mut self) -> Result<u32> {
        self.len -= 4;
        self.inner.read_u32::<LE>().map_err(|e| e.into())
    }

    pub fn read_sfixed64(&mut self) -> Result<i64> {
        self.len -= 8;
        self.inner.read_i64::<LE>().map_err(|e| e.into())
    }

    pub fn read_sfixed32(&mut self) -> Result<i32> {
        self.len -= 4;
        self.inner.read_i32::<LE>().map_err(|e| e.into())
    }

    pub fn read_float(&mut self) -> Result<f32> {
        self.len -= 4;
        self.inner.read_f32::<LE>().map_err(|e| e.into())
    }

    pub fn read_double(&mut self) -> Result<f64> {
        self.len -= 8;
        self.inner.read_f64::<LE>().map_err(|e| e.into())
    }

    pub fn read_bool(&mut self) -> Result<bool> {
        self.read_varint().map(|i| i != 0)
    }

    pub fn read_enum<E: From<u64>>(&mut self) -> Result<E> {
        self.read_varint().map(|i| i.into())
    }

    pub fn read_bytes(&mut self) -> Result<Vec<u8>> {
        let len = self.read_varint()? as usize;
        self.len -= len;
        let mut vec = Vec::with_capacity(len);
        unsafe { vec.set_len(len); }
        self.inner.read_exact(&mut vec[..])?;
        Ok(vec)
    }

    pub fn read_string(&mut self) -> Result<String> {
        let vec = self.read_bytes()?;
        String::from_utf8(vec).map_err(|e| e.into())
    }

    pub fn read_packed_repeated_field<M, F: FnMut(&mut Self) -> Result<M>>(&mut self, mut read: F) -> Result<Vec<M>> {
        let len = self.read_varint()? as usize;
        let cur_len = self.len;
        self.len = len;
        let mut v = Vec::new();
        while self.len > 0 {
            v.push(read(self)?);
        }
        self.len = cur_len - len;
        Ok(v)
    }

    pub fn read_message<M: Message>(&mut self) -> Result<M> {
        let len = self.read_varint()? as usize;
        let cur_len = self.len;
        self.len = len;
        let msg = M::from_reader(self)?;
        self.len = cur_len - len;
        Ok(msg)
    }

    pub fn read_unknown(&mut self, tag_value: u32) -> Result<()> {
        match (tag_value & 0x7) as u8 {
            WIRE_TYPE_VARINT => { self.read_varint()?; },
            WIRE_TYPE_FIXED64 => {
                self.len -= 8;
                self.inner.read_exact(&mut [0; 8])?;
            }
            WIRE_TYPE_FIXED32 => {
                self.len -= 4;
                self.inner.read_exact(&mut [0; 4])?;
            }
            WIRE_TYPE_LENGTH_DELIMITED => {
                let len = self.read_varint()? as usize;
                if len == 0 { return Ok(()); }
                self.len -= len;
                let mut buf = Vec::with_capacity(len);
                unsafe { buf.set_len(len); }
                self.inner.read_exact(&mut buf)?;
            },
            WIRE_TYPE_START_GROUP |
                WIRE_TYPE_END_GROUP => { return Err(ErrorKind::Deprecated("group").into()); },
            t => { return Err(ErrorKind::UnknownWireType(t).into()); },
        }
        Ok(())
    }

    pub fn len(&self) -> usize {
        self.len
    }
}

#[test]
fn test_varint() {
    let data: &[u8] = &[0x96, 0x01];
    let mut r = Reader::from_reader(data, data.len());
    assert_eq!(150, r.read_varint().unwrap());
    assert!(r.next_tag().is_none());
}

#[test]
fn test_next_field() {
    let data: &[u8] = &[0x08, 0x96, 0x01];
    let mut r = Reader::from_reader(data, data.len());
    let tag = r.next_tag().unwrap().unwrap();
    assert_eq!((1, WireType::Varint), tag.unpack());
    assert_eq!(150, r.read_varint().unwrap());
    assert!(r.next_tag().is_none());
}
<|endoftext|>


<commit_before>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::min;
use score::Score;
use sorted_result_set::SortedResultSet;
use std::ascii::AsciiExt;

#[derive(Debug)]
pub struct Search<'s> {
    pub config: &'s Configuration,
    pub current: usize,
    pub query: String,
    pub result: Vec<String>,
    choice_stack: Vec<Vec<&'s String>>,
    done: bool,
}

impl<'s> Search<'s> {
    pub fn blank(config: &'s Configuration) -> Search<'s> {
        let query = config.initial_search.clone();

        let mut choice_stack: Vec<Vec<&'s String>> = Vec::new();
        let mut result = Vec::new();
        let mut first_stack_frame = Vec::new();

        for choice in config.choices.iter().take(config.visible_limit) {
            result.push(choice.clone());
        }

        for choice in config.choices.iter() {
            first_stack_frame.push(choice);
        }

        choice_stack.push(first_stack_frame);

        Search::new(config, query, choice_stack, result, 0, false)
    }

    fn new(config: &'s Configuration, query: String, choice_stack: Vec<Vec<&'s String>>, result: Vec<String>, index: usize, done: bool) -> Search<'s> {
        Search { config: config,
                 current: index,
                 query: query,
                 result: result,
                 choice_stack: choice_stack,
                 done: done}
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn done(self) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, self.current, true)
    }

    pub fn selection(&self) -> Option<String> {
        if self.result.len() > 0 {
            Some(self.result[self.current].to_string())
        } else {
            None
        }
    }

    fn new_for_index(self, index: usize) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, index, self.done)
    }

    pub fn iter_matches<F: FnMut(&'s String, f32)>(query: &str, choices: &Vec<&'s String>, mut f: F) {
        let lower_query = query.to_ascii_lowercase();

        for choice in choices.iter() {
            let lower_choice = choice.to_ascii_lowercase();

            match Score::score(&lower_choice, &lower_query) {
                0.0     => continue,
                quality => f(choice, quality),
            };
        }
    }

    pub fn down(self) -> Search<'s> {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    pub fn up(self) -> Search<'s> {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(mut self, input: &str) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        let mut results = SortedResultSet::new(self.config.visible_limit);
        let mut filtered_choices: Vec<&String> = Vec::new();
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.last().unwrap(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                               filtered_choices.push(match_str)
                                             });

        self.choice_stack.push(filtered_choices);
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    pub fn backspace(mut self) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.pop();

        if self.choice_stack.len() > 1 {
            self.choice_stack.pop();
        }

        let mut results = SortedResultSet::new(self.config.visible_limit);
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.last().unwrap(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                             });
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.actual_limit() {
            0
        } else {
            next_index
        }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 {
            self.actual_limit() - 1
        } else {
            self.current - 1
        }
    }

    fn actual_limit(&self) -> usize {
        min(self.config.visible_limit, self.num_matches())
    }

    pub fn num_matches(&self) -> usize {
        self.choice_stack.last().unwrap().len()
    }
}

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

    fn one_two_three() -> Vec<String> {
        vec!["one".to_string(),
             "two".to_string(),
             "three".to_string()]
    }

    fn input_times(n: usize) ->Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for thing in one_two_three().iter().cycle().take(n) {
            result.push(thing.clone());
        }
        result
    }

    fn basic_configuration() -> Configuration {
        let input = one_two_three();
        Configuration::from_inputs(input, None, None)
    }

    #[test]
    fn it_selects_the_first_choice_by_default() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn it_selets_the_second_when_down_is_called() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_end_of_list() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_top_of_list() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.up().up().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_visible_limit() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").down().selection(), Some("three".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results_twice() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").append_to_search("w").selection(), Some("two".to_string()));
    }

    #[test]
    fn it_handles_not_matching_anything() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("x").selection(), None);
    }

    #[test]
    fn up_match_nothing_after_filtering_all_out() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.up().selection(), None);
    }

    #[test]
    fn down_match_nothing_after_filtering_all_out() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.down().selection(), None);
    }

    #[test]
    fn backspaces_over_characters() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.query, "e");
        assert_eq!(search.backspace().query, "");
    }

    #[test]
    fn resets_the_index_when_removing_char_from_search() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.down().backspace().current, 0);
    }

    #[test]
    fn resets_the_index_when_adding_char_to_seach() {
        let config = basic_configuration();
        let search = Search::blank(&config).down();

        assert_eq!(search.append_to_search("o").current, 0);
    }

    #[test]
    fn previous_results_appear_after_backspace() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("t");

        assert_eq!(search.backspace().num_matches(), 3);
    }

    #[test]
    fn initial_search_is_not_done() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert!(!search.is_done());
    }

    #[test]
    fn backspace_over_initial_doesnt_crash() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        search.backspace();
    }

    #[test]
    fn done_search_is_done() {
        let config = basic_configuration();
        let search = Search::blank(&config).done();

        assert!(search.is_done());
    }

    #[test]
    fn done_search_has_selection() {
        let config = basic_configuration();
        let search = Search::blank(&config).done();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_bottom_of_choices() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("n").down();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_top_of_choices() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("n").up();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn search_is_case_insensitive() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 2);
    }

    #[test]
    fn uses_configs_visible_limit_as_result_size() {
        let input = input_times(30);

        let mut bar = Vec::new();
        for f in input.iter() {
            bar.push((*f).clone());
        }

        let config = Configuration::from_inputs(bar, None, Some(20));
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 20);
    }

}
<commit_msg>Rough drop in implementation of a ChoicesStack<commit_after>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::min;
use score::Score;
use sorted_result_set::SortedResultSet;
use std::ascii::AsciiExt;

#[derive(Debug)]
pub struct Search<'s> {
    pub config: &'s Configuration,
    pub current: usize,
    pub query: String,
    pub result: Vec<String>,
    choice_stack: Vec<Vec<&'s String>>,
    done: bool,
}

struct ChoiceStack<'s> {
    content: Vec<Vec<&'s String>>,
}

impl <'s>ChoiceStack<'s> {
    pub fn new(input: &'s Vec<String>) -> ChoiceStack<'s> {
        let mut first_stack_frame = Vec::new();
        for choice in input.iter() {
            first_stack_frame.push(choice);
        }

        ChoiceStack { content: vec![first_stack_frame] }
    }

    pub fn push(&mut self, frame: Vec<&'s String>) {
        self.content.push(frame);
    }

    pub fn pop(&mut self) {
        if self.content.len() > 1 {
            self.content.pop();
        }
    }

    pub fn peek(&self) -> &Vec<&'s String> {
        self.content.last().unwrap()
    }

    pub fn last_size(&self) -> uint {
        self.peek().len()
    }
}

impl<'s> Search<'s> {
    pub fn blank(config: &'s Configuration) -> Search<'s> {
        let query = config.initial_search.clone();

        let mut choice_stack: Vec<Vec<&'s String>> = Vec::new();
        let mut result = Vec::new();
        let mut first_stack_frame = Vec::new();

        let f = ChoiceStack::new(&config.choices);

        for choice in config.choices.iter().take(config.visible_limit) {
            result.push(choice.clone());
        }

        for choice in config.choices.iter() {
            first_stack_frame.push(choice);
        }

        choice_stack.push(first_stack_frame);

        Search::new(config, query, choice_stack, result, 0, false)
    }

    fn new(config: &'s Configuration, query: String, choice_stack: Vec<Vec<&'s String>>, result: Vec<String>, index: usize, done: bool) -> Search<'s> {
        Search { config: config,
                 current: index,
                 query: query,
                 result: result,
                 choice_stack: choice_stack,
                 done: done}
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn done(self) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, self.current, true)
    }

    pub fn selection(&self) -> Option<String> {
        if self.result.len() > 0 {
            Some(self.result[self.current].to_string())
        } else {
            None
        }
    }

    fn new_for_index(self, index: usize) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, index, self.done)
    }

    pub fn iter_matches<F: FnMut(&'s String, f32)>(query: &str, choices: &Vec<&'s String>, mut f: F) {
        let lower_query = query.to_ascii_lowercase();

        for choice in choices.iter() {
            let lower_choice = choice.to_ascii_lowercase();

            match Score::score(&lower_choice, &lower_query) {
                0.0     => continue,
                quality => f(choice, quality),
            };
        }
    }

    pub fn down(self) -> Search<'s> {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    pub fn up(self) -> Search<'s> {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(mut self, input: &str) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        let mut results = SortedResultSet::new(self.config.visible_limit);
        let mut filtered_choices: Vec<&String> = Vec::new();
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.last().unwrap(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                               filtered_choices.push(match_str)
                                             });

        self.choice_stack.push(filtered_choices);
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    pub fn backspace(mut self) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.pop();

        if self.choice_stack.len() > 1 {
            self.choice_stack.pop();
        }

        let mut results = SortedResultSet::new(self.config.visible_limit);
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.last().unwrap(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                             });
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.actual_limit() {
            0
        } else {
            next_index
        }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 {
            self.actual_limit() - 1
        } else {
            self.current - 1
        }
    }

    fn actual_limit(&self) -> usize {
        min(self.config.visible_limit, self.num_matches())
    }

    pub fn num_matches(&self) -> usize {
        self.choice_stack.last().unwrap().len()
    }
}

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

    fn one_two_three() -> Vec<String> {
        vec!["one".to_string(),
             "two".to_string(),
             "three".to_string()]
    }

    fn input_times(n: usize) ->Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for thing in one_two_three().iter().cycle().take(n) {
            result.push(thing.clone());
        }
        result
    }

    fn basic_configuration() -> Configuration {
        let input = one_two_three();
        Configuration::from_inputs(input, None, None)
    }

    #[test]
    fn it_selects_the_first_choice_by_default() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn it_selets_the_second_when_down_is_called() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_end_of_list() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_top_of_list() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.up().up().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_visible_limit() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").down().selection(), Some("three".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results_twice() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").append_to_search("w").selection(), Some("two".to_string()));
    }

    #[test]
    fn it_handles_not_matching_anything() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("x").selection(), None);
    }

    #[test]
    fn up_match_nothing_after_filtering_all_out() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.up().selection(), None);
    }

    #[test]
    fn down_match_nothing_after_filtering_all_out() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.down().selection(), None);
    }

    #[test]
    fn backspaces_over_characters() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.query, "e");
        assert_eq!(search.backspace().query, "");
    }

    #[test]
    fn resets_the_index_when_removing_char_from_search() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.down().backspace().current, 0);
    }

    #[test]
    fn resets_the_index_when_adding_char_to_seach() {
        let config = basic_configuration();
        let search = Search::blank(&config).down();

        assert_eq!(search.append_to_search("o").current, 0);
    }

    #[test]
    fn previous_results_appear_after_backspace() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("t");

        assert_eq!(search.backspace().num_matches(), 3);
    }

    #[test]
    fn initial_search_is_not_done() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert!(!search.is_done());
    }

    #[test]
    fn backspace_over_initial_doesnt_crash() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        search.backspace();
    }

    #[test]
    fn done_search_is_done() {
        let config = basic_configuration();
        let search = Search::blank(&config).done();

        assert!(search.is_done());
    }

    #[test]
    fn done_search_has_selection() {
        let config = basic_configuration();
        let search = Search::blank(&config).done();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_bottom_of_choices() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("n").down();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_top_of_choices() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("n").up();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn search_is_case_insensitive() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 2);
    }

    #[test]
    fn uses_configs_visible_limit_as_result_size() {
        let input = input_times(30);

        let mut bar = Vec::new();
        for f in input.iter() {
            bar.push((*f).clone());
        }

        let config = Configuration::from_inputs(bar, None, Some(20));
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 20);
    }

}
<|endoftext|>


<commit_before>use configuration::Configuration;
use score::Score;
use sorted_result_set::SortedResultSet;
use std::slice::SliceExt;
use std::cmp::min;
use std::ascii::AsciiExt;

#[derive(Debug)]
pub struct Search<'s> {
    pub config: &'s Configuration,
    pub current: usize,
    pub query: String,
    pub result: Vec<String>,
    choice_stack: ChoiceStack<'s>,
    done: bool,
}

#[derive(Debug)]
struct ChoiceStack<'s> {
    content: Vec<Vec<&'s String>>,
}

impl <'s>ChoiceStack<'s> {
    pub fn new(input: &'s Vec<String>) -> ChoiceStack<'s> {
        let first_stack_frame = input.iter().map(|x| x).collect();

        ChoiceStack { content: vec![first_stack_frame] }
    }

    pub fn push(&mut self, frame: Vec<&'s String>) {
        self.content.push(frame);
    }

    pub fn pop(&mut self) {
        if self.content.len() > 1 {
            self.content.pop();
        }
    }

    pub fn peek(&self) -> &Vec<&'s String> {
        self.content.last().unwrap()
    }

    pub fn last_size(&self) -> usize {
        self.peek().len()
    }
}

impl<'s> Search<'s> {
    pub fn blank(config: &'s Configuration) -> Search<'s> {
        let query = config.initial_search.clone();

        let choice_stack = ChoiceStack::new(&config.choices);
        let result = Search::copy_items(&config.choices, config.visible_limit);

        Search::new(config, query, choice_stack, result, 0, false)
    }

    fn copy_items(input: &Vec<String>, size: usize) -> Vec<String> {
        input.iter().take(size).map(|x| x.clone() ).collect()
    }

    fn new(config: &'s Configuration, query: String, choice_stack: ChoiceStack<'s>, result: Vec<String>, index: usize, done: bool) -> Search<'s> {
        Search { config: config,
                 current: index,
                 query: query,
                 result: result,
                 choice_stack: choice_stack,
                 done: done}
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn done(self) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, self.current, true)
    }

    pub fn selection(&self) -> Option<String> {
        if self.result.len() > 0 {
            Some(self.result[self.current].to_string())
        } else {
            None
        }
    }

    fn new_for_index(self, index: usize) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, index, self.done)
    }

    pub fn iter_matches<F: FnMut(&'s String, f32)>(query: &str, choices: &Vec<&'s String>, mut f: F) {
        let lower_query = query.to_ascii_lowercase();

        for choice in choices.iter() {
            let lower_choice = choice.to_ascii_lowercase();

            match Score::score(&lower_choice, &lower_query) {
                0.0     => continue,
                quality => f(choice, quality),
            };
        }
    }

    pub fn down(self) -> Search<'s> {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    pub fn up(self) -> Search<'s> {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(mut self, input: &str) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        let mut results = SortedResultSet::new(self.config.visible_limit);
        let mut filtered_choices: Vec<&String> = Vec::new();
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.peek(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                               filtered_choices.push(match_str)
                                             });

        self.choice_stack.push(filtered_choices);
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    pub fn backspace(mut self) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.pop();

        self.choice_stack.pop();

        let mut results = SortedResultSet::new(self.config.visible_limit);
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.peek(), |match_str, quality| results.push(match_str, quality) );

        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.actual_limit() {
            0
        } else {
            next_index
        }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 {
            self.actual_limit() - 1
        } else {
            self.current - 1
        }
    }

    fn actual_limit(&self) -> usize {
        min(self.config.visible_limit, self.num_matches())
    }

    pub fn num_matches(&self) -> usize {
        self.choice_stack.last_size()
    }
}

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

    fn one_two_three() -> Vec<String> {
        vec!["one".to_string(),
             "two".to_string(),
             "three".to_string()]
    }

    fn input_times(n: usize) ->Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for thing in one_two_three().iter().cycle().take(n) {
            result.push(thing.clone());
        }
        result
    }

    fn basic_configuration() -> Configuration {
        let input = one_two_three();
        Configuration::from_inputs(input, None, None)
    }

    #[test]
    fn it_selects_the_first_choice_by_default() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn it_selets_the_second_when_down_is_called() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_end_of_list() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_top_of_list() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.up().up().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_visible_limit() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").down().selection(), Some("three".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results_twice() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").append_to_search("w").selection(), Some("two".to_string()));
    }

    #[test]
    fn it_handles_not_matching_anything() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("x").selection(), None);
    }

    #[test]
    fn up_match_nothing_after_filtering_all_out() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.up().selection(), None);
    }

    #[test]
    fn down_match_nothing_after_filtering_all_out() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.down().selection(), None);
    }

    #[test]
    fn backspaces_over_characters() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.query, "e");
        assert_eq!(search.backspace().query, "");
    }

    #[test]
    fn resets_the_index_when_removing_char_from_search() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.down().backspace().current, 0);
    }

    #[test]
    fn resets_the_index_when_adding_char_to_seach() {
        let config = basic_configuration();
        let search = Search::blank(&config).down();

        assert_eq!(search.append_to_search("o").current, 0);
    }

    #[test]
    fn previous_results_appear_after_backspace() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("t");

        assert_eq!(search.backspace().num_matches(), 3);
    }

    #[test]
    fn initial_search_is_not_done() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert!(!search.is_done());
    }

    #[test]
    fn backspace_over_initial_doesnt_crash() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        search.backspace();
    }

    #[test]
    fn done_search_is_done() {
        let config = basic_configuration();
        let search = Search::blank(&config).done();

        assert!(search.is_done());
    }

    #[test]
    fn done_search_has_selection() {
        let config = basic_configuration();
        let search = Search::blank(&config).done();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_bottom_of_choices() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("n").down();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_top_of_choices() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("n").up();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn search_is_case_insensitive() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 2);
    }

    #[test]
    fn uses_configs_visible_limit_as_result_size() {
        let input = input_times(30);

        let mut bar = Vec::new();
        for f in input.iter() {
            bar.push((*f).clone());
        }

        let config = Configuration::from_inputs(bar, None, Some(20));
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 20);
    }
}
<commit_msg>Renames first_stack_frame to initial_choices<commit_after>use configuration::Configuration;
use score::Score;
use sorted_result_set::SortedResultSet;
use std::slice::SliceExt;
use std::cmp::min;
use std::ascii::AsciiExt;

#[derive(Debug)]
pub struct Search<'s> {
    pub config: &'s Configuration,
    pub current: usize,
    pub query: String,
    pub result: Vec<String>,
    choice_stack: ChoiceStack<'s>,
    done: bool,
}

#[derive(Debug)]
struct ChoiceStack<'s> {
    content: Vec<Vec<&'s String>>,
}

impl <'s>ChoiceStack<'s> {
    pub fn new(input: &'s Vec<String>) -> ChoiceStack<'s> {
        let initial_choices = input.iter().map(|x| x).collect();

        ChoiceStack { content: vec![initial_choices] }
    }

    pub fn push(&mut self, frame: Vec<&'s String>) {
        self.content.push(frame);
    }

    pub fn pop(&mut self) {
        if self.content.len() > 1 {
            self.content.pop();
        }
    }

    pub fn peek(&self) -> &Vec<&'s String> {
        self.content.last().unwrap()
    }

    pub fn last_size(&self) -> usize {
        self.peek().len()
    }
}

impl<'s> Search<'s> {
    pub fn blank(config: &'s Configuration) -> Search<'s> {
        let query = config.initial_search.clone();

        let choice_stack = ChoiceStack::new(&config.choices);
        let result = Search::copy_items(&config.choices, config.visible_limit);

        Search::new(config, query, choice_stack, result, 0, false)
    }

    fn copy_items(input: &Vec<String>, size: usize) -> Vec<String> {
        input.iter().take(size).map(|x| x.clone() ).collect()
    }

    fn new(config: &'s Configuration, query: String, choice_stack: ChoiceStack<'s>, result: Vec<String>, index: usize, done: bool) -> Search<'s> {
        Search { config: config,
                 current: index,
                 query: query,
                 result: result,
                 choice_stack: choice_stack,
                 done: done}
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn done(self) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, self.current, true)
    }

    pub fn selection(&self) -> Option<String> {
        if self.result.len() > 0 {
            Some(self.result[self.current].to_string())
        } else {
            None
        }
    }

    fn new_for_index(self, index: usize) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, index, self.done)
    }

    pub fn iter_matches<F: FnMut(&'s String, f32)>(query: &str, choices: &Vec<&'s String>, mut f: F) {
        let lower_query = query.to_ascii_lowercase();

        for choice in choices.iter() {
            let lower_choice = choice.to_ascii_lowercase();

            match Score::score(&lower_choice, &lower_query) {
                0.0     => continue,
                quality => f(choice, quality),
            };
        }
    }

    pub fn down(self) -> Search<'s> {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    pub fn up(self) -> Search<'s> {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(mut self, input: &str) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        let mut results = SortedResultSet::new(self.config.visible_limit);
        let mut filtered_choices: Vec<&String> = Vec::new();
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.peek(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                               filtered_choices.push(match_str)
                                             });

        self.choice_stack.push(filtered_choices);
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    pub fn backspace(mut self) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.pop();

        self.choice_stack.pop();

        let mut results = SortedResultSet::new(self.config.visible_limit);
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.peek(), |match_str, quality| results.push(match_str, quality) );

        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.actual_limit() {
            0
        } else {
            next_index
        }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 {
            self.actual_limit() - 1
        } else {
            self.current - 1
        }
    }

    fn actual_limit(&self) -> usize {
        min(self.config.visible_limit, self.num_matches())
    }

    pub fn num_matches(&self) -> usize {
        self.choice_stack.last_size()
    }
}

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

    fn one_two_three() -> Vec<String> {
        vec!["one".to_string(),
             "two".to_string(),
             "three".to_string()]
    }

    fn input_times(n: usize) ->Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for thing in one_two_three().iter().cycle().take(n) {
            result.push(thing.clone());
        }
        result
    }

    fn basic_configuration() -> Configuration {
        let input = one_two_three();
        Configuration::from_inputs(input, None, None)
    }

    #[test]
    fn it_selects_the_first_choice_by_default() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn it_selets_the_second_when_down_is_called() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_end_of_list() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_top_of_list() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.up().up().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_visible_limit() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection(), Some("two".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").down().selection(), Some("three".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results_twice() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").append_to_search("w").selection(), Some("two".to_string()));
    }

    #[test]
    fn it_handles_not_matching_anything() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("x").selection(), None);
    }

    #[test]
    fn up_match_nothing_after_filtering_all_out() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.up().selection(), None);
    }

    #[test]
    fn down_match_nothing_after_filtering_all_out() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.down().selection(), None);
    }

    #[test]
    fn backspaces_over_characters() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.query, "e");
        assert_eq!(search.backspace().query, "");
    }

    #[test]
    fn resets_the_index_when_removing_char_from_search() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.down().backspace().current, 0);
    }

    #[test]
    fn resets_the_index_when_adding_char_to_seach() {
        let config = basic_configuration();
        let search = Search::blank(&config).down();

        assert_eq!(search.append_to_search("o").current, 0);
    }

    #[test]
    fn previous_results_appear_after_backspace() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("t");

        assert_eq!(search.backspace().num_matches(), 3);
    }

    #[test]
    fn initial_search_is_not_done() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        assert!(!search.is_done());
    }

    #[test]
    fn backspace_over_initial_doesnt_crash() {
        let config = basic_configuration();
        let search = Search::blank(&config);

        search.backspace();
    }

    #[test]
    fn done_search_is_done() {
        let config = basic_configuration();
        let search = Search::blank(&config).done();

        assert!(search.is_done());
    }

    #[test]
    fn done_search_has_selection() {
        let config = basic_configuration();
        let search = Search::blank(&config).done();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_bottom_of_choices() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("n").down();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_top_of_choices() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("n").up();

        assert_eq!(search.selection(), Some("one".to_string()));
    }

    #[test]
    fn search_is_case_insensitive() {
        let config = basic_configuration();
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 2);
    }

    #[test]
    fn uses_configs_visible_limit_as_result_size() {
        let input = input_times(30);

        let mut bar = Vec::new();
        for f in input.iter() {
            bar.push((*f).clone());
        }

        let config = Configuration::from_inputs(bar, None, Some(20));
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 20);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::net::UdpSocket;
use std::str;

// Content of the request.
const SEARCH_REQUEST: &'static str =
"M-SEARCH * HTTP/1.1\r
Host:239.255.255.250:1900\r
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r
Man:\"ssdp:discover\"\r
MX:3\r\n\r\n";

// Error type this module emits.
#[derive(Debug)]
pub enum SearchError {
    IoError(io::Error),
    InvalidResponse,
}

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

// Try to find the gateway on the local network.
// Bind to the given interface.
pub fn search_gateway_from(local_addr: SocketAddrV4) -> Result<SocketAddrV4, SearchError> {
    let socket = try!(UdpSocket::bind(local_addr));

    // send the request on the broadcast address
    try!(socket.send_to(SEARCH_REQUEST.as_bytes(), "239.255.255.250:1900"));

    let mut buf = [0u8; 1024];
    let (read, _) = try!(socket.recv_from(&mut buf));
    let text = str::from_utf8(&buf[..read]).unwrap();
    match parse_result(text) {
        None => Err(SearchError::InvalidResponse),
        Some(socketaddr) => Ok(socketaddr),
    }
}

// Try to find the gateway on the local network.
// Bind to all interfaces.
pub fn search_gateway() -> Result<SocketAddrV4, SearchError> {
    search_gateway_from(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 1900))
}

// Parse the result.
fn parse_result(text: &str) -> Option<SocketAddrV4> {
    let re = regex!(r"LOCATION:\s*http://(\d+\.\d+\.\d+\.\d+):(\d+)/.+");
    for line in text.lines() {
        match re.captures(line) {
            None => continue,
            Some(cap) => {
                // these shouldn't fail if the regex matched.
                let addr = cap.at(1).unwrap();
                let port = cap.at(2).unwrap();
                return Some(SocketAddrV4::new(
                    addr.parse::<Ipv4Addr>().unwrap(),
                    port.parse::<u16>().unwrap()
                ));
            },
        }
    }
    None
}
<commit_msg>Use Ipv4Addr instead of SocketAddrV4<commit_after>use std::io;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::net::UdpSocket;
use std::str;

// Content of the request.
const SEARCH_REQUEST: &'static str =
"M-SEARCH * HTTP/1.1\r
Host:239.255.255.250:1900\r
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r
Man:\"ssdp:discover\"\r
MX:3\r\n\r\n";

// Error type this module emits.
#[derive(Debug)]
pub enum SearchError {
    IoError(io::Error),
    InvalidResponse,
}

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

// Try to find the gateway on the local network.
// Bind to the given interface.
pub fn search_gateway_from(ip: Ipv4Addr) -> Result<SocketAddrV4, SearchError> {
    let addr = SocketAddrV4::new(ip, 1900);
    let socket = try!(UdpSocket::bind(addr));

    // send the request on the broadcast address
    try!(socket.send_to(SEARCH_REQUEST.as_bytes(), "239.255.255.250:1900"));

    let mut buf = [0u8; 1024];
    let (read, _) = try!(socket.recv_from(&mut buf));
    let text = str::from_utf8(&buf[..read]).unwrap();
    match parse_result(text) {
        None => Err(SearchError::InvalidResponse),
        Some(socketaddr) => Ok(socketaddr),
    }
}

// Try to find the gateway on the local network.
// Bind to all interfaces.
pub fn search_gateway() -> Result<SocketAddrV4, SearchError> {
    search_gateway_from(Ipv4Addr::new(0, 0, 0, 0))
}

// Parse the result.
fn parse_result(text: &str) -> Option<SocketAddrV4> {
    let re = regex!(r"LOCATION:\s*http://(\d+\.\d+\.\d+\.\d+):(\d+)/.+");
    for line in text.lines() {
        match re.captures(line) {
            None => continue,
            Some(cap) => {
                // these shouldn't fail if the regex matched.
                let addr = cap.at(1).unwrap();
                let port = cap.at(2).unwrap();
                return Some(SocketAddrV4::new(
                    addr.parse::<Ipv4Addr>().unwrap(),
                    port.parse::<u16>().unwrap()
                ));
            },
        }
    }
    None
}
<|endoftext|>


<commit_before>use std::ptr;
use gl;
use gl::types::*;
use context::ContextOf;
use types::GLError;

pub struct Shader {
    gl_id: GLuint
}

impl Shader {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteShader(self.gl_id);
        }
    }
}

unsafe fn _get_shader_iv(shader: &Shader,
                         pname: GLenum,
                         params: *mut GLint)
{
    gl::GetShaderiv(shader.gl_id(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`pname` is not an accepted value",
        GLError::InvalidValue => "`shader` is not a value generated by OpenGL",
        GLError::InvalidOperation => "`shader` is not a shader object, or `pname` is GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH or GL_SHADER_SOURCE_LENGTH but a shader compiler is not supported",
        _ => "Unknown error"
    }
}

pub struct ShaderBuilder<'a, B, F, P, R, T>
    where B: 'a,
          F: 'a,
          P: 'a,
          R: 'a,
          T: 'a
{
    gl: &'a ContextOf<B, F, P, R, T>,
    ty: ShaderType,
    source: &'a str
}

impl<'a, B, F, P, R, T> ShaderBuilder<'a, B, F, P, R, T> {
    fn new(gl: &'a ContextOf<B, F, P, R, T>,
           ty: ShaderType,
           source: &'a str)
        -> Self
    {
        ShaderBuilder { gl: gl, ty: ty, source: source }
    }

    pub fn try_unwrap(self) -> Result<Shader, GLError> {
        unsafe {
            let mut shader = try! {
                self.gl.create_shader(self.ty).or_else(|_| {
                    let msg = "Error creating OpenGL shader";
                    Err(GLError::Message(msg.to_owned()))
                })
            };

            self.gl.shader_source(&mut shader, self.source);
            try!(self.gl.compile_shader(&mut shader));
            Ok(shader)
        }
    }

    pub fn unwrap(self) -> Shader {
        self.try_unwrap().unwrap()
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    // TODO: Move these methods into `ContextShaderExt`
    pub fn build_shader<'a>(&'a self, ty: ShaderType, source: &'a str)
        -> ShaderBuilder<'a, B, F, P, R, T>
    {
        ShaderBuilder::new(self, ty, source)
    }

    pub fn build_fragment_shader<'a>(&'a self, source: &'a str)
        -> ShaderBuilder<'a, B, F, P, R, T>
    {
        ShaderBuilder::new(self, ShaderType::FragmentShader, source)
    }

    pub fn build_vertex_shader<'a>(&'a self, source: &'a str)
        -> ShaderBuilder<'a, B, F, P, R, T>
    {
        ShaderBuilder::new(self, ShaderType::VertexShader, source)
    }
}

pub trait ContextShaderExt {
    unsafe fn create_shader(&self, shader_type: ShaderType)
        -> Result<Shader, ()>;
    fn shader_source(&self, shader: &mut Shader, source: &str);
    fn compile_shader(&self, shader: &mut Shader) -> Result<(), GLError>;
    fn get_shader_info_log(&self, shader: &Shader) -> Option<String>;
}

impl<B, F, P, R, T> ContextShaderExt for ContextOf<B, F, P, R, T> {
    unsafe fn create_shader(&self, shader_type: ShaderType)
        -> Result<Shader, ()>
    {
        let id = gl::CreateShader(shader_type.gl_enum());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`shaderType` is not an accepted value",
            _ => "Unknown error"
        }
        if id > 0 {
            Ok(Shader { gl_id: id })
        }
        else {
            Err(())
        }
    }

    fn shader_source(&self, shader: &mut Shader, source: &str) {
        unsafe {
            let source_ptr = source.as_ptr() as *const GLchar;
            let source_len = source.len() as GLint;

            gl::ShaderSource(shader.gl_id(), 1,
                             &source_ptr as *const *const GLchar,
                             &source_len as *const GLint);
            dbg_gl_error! {
                GLError::InvalidOperation => "`shader` is not a shader object or shader compiler is not supported",
                GLError::InvalidValue => "`shader` is not a value generated by OpenGL or `count` < 0",
                _ => "Unknown error"
            }
        }
    }

    fn compile_shader(&self, shader: &mut Shader) -> Result<(), GLError> {
        let success = unsafe {
            gl::CompileShader(shader.gl_id());
            dbg_gl_error! {
                GLError::InvalidOperation => "`shader` is not a shader object or shader compiler is not supported",
                GLError::InvalidValue => "`shader` is not a value generated by OpenGL",
                _ => "Unknown error"
            }

            let mut compile_status : GLint = 0;
            _get_shader_iv(shader,
                           gl::COMPILE_STATUS,
                           &mut compile_status as *mut GLint);

            compile_status == gl::TRUE as GLint
        };

        if success {
            Ok(())
        }
        else {
            let msg = match self.get_shader_info_log(&shader) {
                Some(s) => { s },
                None => { String::from("[Unknown shader error]") }
            };
            Err(GLError::Message(msg))
        }
    }

    fn get_shader_info_log(&self, shader: &Shader) -> Option<String> {
        unsafe {
            let mut info_length : GLint = 0;
            _get_shader_iv(shader,
                           gl::INFO_LOG_LENGTH,
                           &mut info_length as *mut GLint);

            if info_length > 0 {
                let mut bytes = Vec::<u8>::with_capacity(info_length as usize);

                gl::GetShaderInfoLog(shader.gl_id(),
                                     info_length,
                                     ptr::null_mut(),
                                     bytes.as_mut_ptr() as *mut GLchar);
                dbg_gl_sanity_check! {
                    GLError::InvalidValue => "`shader` is not a value generated by OpenGL, or `maxLength` < 0",
                    GLError::InvalidOperation => "`shader` is not a shader object",
                    _ => "Unknown error"
                }

                bytes.set_len((info_length - 1) as usize);

                String::from_utf8(bytes).ok()
            }
            else {
                None
            }
        }
    }
}

// TODO: Add a macro to reduce this boilerplate
impl<'a, B, F, P, R, T> ContextShaderExt for &'a mut ContextOf<B, F, P, R, T> {
    unsafe fn create_shader(&self, shader_type: ShaderType)
        -> Result<Shader, ()>
    {
        (**self).create_shader(shader_type)
    }

    fn shader_source(&self, shader: &mut Shader, source: &str) {
        (**self).shader_source(shader, source);
    }

    fn compile_shader(&self, shader: &mut Shader) -> Result<(), GLError> {
        (**self).compile_shader(shader)
    }

    fn get_shader_info_log(&self, shader: &Shader) -> Option<String> {
        (**self).get_shader_info_log(shader)
    }
}

gl_enum! {
    pub gl_enum ShaderType {
        VertexShader as VERTEX_SHADER = gl::VERTEX_SHADER,
        FragmentShader as FRAGMENT_SHADER = gl::FRAGMENT_SHADER
    }
}
<commit_msg>Refactor `ShaderBuilder` to have one generic parameter<commit_after>use std::ptr;
use gl;
use gl::types::*;
use context::{AContext, ContextOf};
use types::GLError;

pub struct Shader {
    gl_id: GLuint
}

impl Shader {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteShader(self.gl_id);
        }
    }
}

unsafe fn _get_shader_iv(shader: &Shader,
                         pname: GLenum,
                         params: *mut GLint)
{
    gl::GetShaderiv(shader.gl_id(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`pname` is not an accepted value",
        GLError::InvalidValue => "`shader` is not a value generated by OpenGL",
        GLError::InvalidOperation => "`shader` is not a shader object, or `pname` is GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH or GL_SHADER_SOURCE_LENGTH but a shader compiler is not supported",
        _ => "Unknown error"
    }
}

pub struct ShaderBuilder<'a, C: 'a>
    where C: AContext
{
    gl: &'a C,
    ty: ShaderType,
    source: &'a str
}

impl<'a, C: 'a> ShaderBuilder<'a, C>
    where C: AContext
{
    fn new(gl: &'a C, ty: ShaderType, source: &'a str)
        -> Self
    {
        ShaderBuilder { gl: gl, ty: ty, source: source }
    }

    pub fn try_unwrap(self) -> Result<Shader, GLError> {
        unsafe {
            let mut shader = try! {
                self.gl.create_shader(self.ty).or_else(|_| {
                    let msg = "Error creating OpenGL shader";
                    Err(GLError::Message(msg.to_owned()))
                })
            };

            self.gl.shader_source(&mut shader, self.source);
            try!(self.gl.compile_shader(&mut shader));
            Ok(shader)
        }
    }

    pub fn unwrap(self) -> Shader {
        self.try_unwrap().unwrap()
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    // TODO: Move these methods into `ContextShaderExt`
    pub fn build_shader<'a>(&'a self, ty: ShaderType, source: &'a str)
        -> ShaderBuilder<'a, Self>
    {
        ShaderBuilder::new(self, ty, source)
    }

    pub fn build_fragment_shader<'a>(&'a self, source: &'a str)
        -> ShaderBuilder<'a, Self>
    {
        ShaderBuilder::new(self, ShaderType::FragmentShader, source)
    }

    pub fn build_vertex_shader<'a>(&'a self, source: &'a str)
        -> ShaderBuilder<'a, Self>
    {
        ShaderBuilder::new(self, ShaderType::VertexShader, source)
    }
}

pub trait ContextShaderExt {
    unsafe fn create_shader(&self, shader_type: ShaderType)
        -> Result<Shader, ()>;
    fn shader_source(&self, shader: &mut Shader, source: &str);
    fn compile_shader(&self, shader: &mut Shader) -> Result<(), GLError>;
    fn get_shader_info_log(&self, shader: &Shader) -> Option<String>;
}

impl<B, F, P, R, T> ContextShaderExt for ContextOf<B, F, P, R, T> {
    unsafe fn create_shader(&self, shader_type: ShaderType)
        -> Result<Shader, ()>
    {
        let id = gl::CreateShader(shader_type.gl_enum());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`shaderType` is not an accepted value",
            _ => "Unknown error"
        }
        if id > 0 {
            Ok(Shader { gl_id: id })
        }
        else {
            Err(())
        }
    }

    fn shader_source(&self, shader: &mut Shader, source: &str) {
        unsafe {
            let source_ptr = source.as_ptr() as *const GLchar;
            let source_len = source.len() as GLint;

            gl::ShaderSource(shader.gl_id(), 1,
                             &source_ptr as *const *const GLchar,
                             &source_len as *const GLint);
            dbg_gl_error! {
                GLError::InvalidOperation => "`shader` is not a shader object or shader compiler is not supported",
                GLError::InvalidValue => "`shader` is not a value generated by OpenGL or `count` < 0",
                _ => "Unknown error"
            }
        }
    }

    fn compile_shader(&self, shader: &mut Shader) -> Result<(), GLError> {
        let success = unsafe {
            gl::CompileShader(shader.gl_id());
            dbg_gl_error! {
                GLError::InvalidOperation => "`shader` is not a shader object or shader compiler is not supported",
                GLError::InvalidValue => "`shader` is not a value generated by OpenGL",
                _ => "Unknown error"
            }

            let mut compile_status : GLint = 0;
            _get_shader_iv(shader,
                           gl::COMPILE_STATUS,
                           &mut compile_status as *mut GLint);

            compile_status == gl::TRUE as GLint
        };

        if success {
            Ok(())
        }
        else {
            let msg = match self.get_shader_info_log(&shader) {
                Some(s) => { s },
                None => { String::from("[Unknown shader error]") }
            };
            Err(GLError::Message(msg))
        }
    }

    fn get_shader_info_log(&self, shader: &Shader) -> Option<String> {
        unsafe {
            let mut info_length : GLint = 0;
            _get_shader_iv(shader,
                           gl::INFO_LOG_LENGTH,
                           &mut info_length as *mut GLint);

            if info_length > 0 {
                let mut bytes = Vec::<u8>::with_capacity(info_length as usize);

                gl::GetShaderInfoLog(shader.gl_id(),
                                     info_length,
                                     ptr::null_mut(),
                                     bytes.as_mut_ptr() as *mut GLchar);
                dbg_gl_sanity_check! {
                    GLError::InvalidValue => "`shader` is not a value generated by OpenGL, or `maxLength` < 0",
                    GLError::InvalidOperation => "`shader` is not a shader object",
                    _ => "Unknown error"
                }

                bytes.set_len((info_length - 1) as usize);

                String::from_utf8(bytes).ok()
            }
            else {
                None
            }
        }
    }
}

// TODO: Add a macro to reduce this boilerplate
impl<'a, B, F, P, R, T> ContextShaderExt for &'a mut ContextOf<B, F, P, R, T> {
    unsafe fn create_shader(&self, shader_type: ShaderType)
        -> Result<Shader, ()>
    {
        (**self).create_shader(shader_type)
    }

    fn shader_source(&self, shader: &mut Shader, source: &str) {
        (**self).shader_source(shader, source);
    }

    fn compile_shader(&self, shader: &mut Shader) -> Result<(), GLError> {
        (**self).compile_shader(shader)
    }

    fn get_shader_info_log(&self, shader: &Shader) -> Option<String> {
        (**self).get_shader_info_log(shader)
    }
}

gl_enum! {
    pub gl_enum ShaderType {
        VertexShader as VERTEX_SHADER = gl::VERTEX_SHADER,
        FragmentShader as FRAGMENT_SHADER = gl::FRAGMENT_SHADER
    }
}
<|endoftext|>


<commit_before>use num::{ Float, ToPrimitive, FromPrimitive };
use callback::Callable;
use frame::Frameable;
use color::{ Color, Colorable };
use label::{ FontSize, Labelable };
use dimensions::Dimensions;
use label;
use mouse::Mouse;
use graphics::Graphics;
use graphics::character::CharacterCache;
use point::Point;
use position::Positionable;
use rectangle;
use ui_context::{ UIID, UiContext };
use utils::{
    clamp,
    percentage,
    value_from_perc,
};
use widget::Widget;
use vecmath::vec2_add;

/// Represents the state of the Button widget.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(Slider, State, Widget::Slider(State::Normal));

/// Check the current state of the slider.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _ => Normal,
    }
}

/// A context on which the builder pattern can be implemented.
pub struct Slider<'a, T, F> {
    ui_id: UIID,
    value: T,
    min: T,
    max: T,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl<'a, T, F> Slider<'a, T, F> {
    /// A button builder method to be implemented by the UiContext.
    pub fn new(ui_id: UIID, value: T, min: T, max: T) -> Slider<'a, T, F> {
        Slider {
            ui_id: ui_id,
            value: value,
            min: min,
            max: max,
            pos: [0.0, 0.0],
            dim: [192.0, 48.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, T, F> Colorable for Slider<'a, T, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, T, F> Frameable for Slider<'a, T, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

impl<'a, T, F> Callable<F> for Slider<'a, T, F> {
    fn callback(mut self, cb: F) -> Self {
        self.maybe_callback = Some(cb);
        self
    }
}

impl<'a, T, F> Labelable<'a> for Slider<'a, T, F>
{
    fn label(mut self, text: &'a str) -> Self {
        self.maybe_label = Some(text);
        self
    }

    fn label_color(mut self, color: Color) -> Self {
        self.maybe_label_color = Some(color);
        self
    }

    fn label_font_size(mut self, size: FontSize) -> Self {
        self.maybe_label_font_size = Some(size);
        self
    }
}

impl<'a, T, F> Positionable for Slider<'a, T, F> {
    fn point(mut self, pos: Point) -> Self {
        self.pos = pos;
        self
    }
}

/*
quack! {
    slider: Slider['a, T, F]
    get:
        fn () -> Size [] { Size(slider.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::Slider(State::Normal))
        }
        fn () -> Id [] { Id(slider.ui_id) }
    set:
        fn (val: Size) [] { slider.dim = val.0 }
    action:
}
*/

impl<'a, T, F> ::draw::Drawable for Slider<'a, T, F>
    where
        T: Float + FromPrimitive + ToPrimitive,
        F: FnMut(T) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over = rectangle::is_over(self.pos, mouse.pos, self.dim);
        let new_state = get_new_state(is_over, state, mouse);

        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let frame_color = self.maybe_frame_color.unwrap_or(uic.theme.frame_color);

        let is_horizontal = self.dim[0] > self.dim[1];
        let (new_value, pad_pos, pad_dim) = if is_horizontal {
            // Horizontal.
            let p = vec2_add(self.pos, [frame_w, frame_w]);
            let max_w = self.dim[0] - frame_w2;
            let w = match (is_over, state, new_state) {
                (true, State::Highlighted, State::Clicked) | (_, State::Clicked, State::Clicked)  =>
                     clamp(mouse.pos[0] - p[0], 0f64, max_w),
                _ => clamp(percentage(self.value, self.min, self.max) as f64 * max_w, 0f64, max_w),
            };
            let h = self.dim[1] - frame_w2;
            let new_value = value_from_perc((w / max_w) as f32, self.min, self.max);
            (new_value, p, [w, h])
        } else {
            // Vertical.
            let max_h = self.dim[1] - frame_w2;
            let corner = vec2_add(self.pos, [frame_w, frame_w]);
            let y_max = corner[1] + max_h;
            let (h, p) = match (is_over, state, new_state) {
                (true, State::Highlighted, State::Clicked) | (_, State::Clicked, State::Clicked) => {
                    let p = [corner[0], clamp(mouse.pos[1], corner[1], y_max)];
                    let h = clamp(max_h - (p[1] - corner[1]), 0.0, max_h);
                    (h, p)
                },
                _ => {
                    let h = clamp(percentage(self.value, self.min, self.max) as f64 * max_h, 0.0, max_h);
                    let p = [corner[0], corner[1] + max_h - h];
                    (h, p)
                },
            };
            let w = self.dim[0] - frame_w2;
            let new_value = value_from_perc((h / max_h) as f32, self.min, self.max);
            (new_value, p, [w, h])
        };

        // Callback.
        match self.maybe_callback {
            Some(ref mut callback) => {
                if self.value != new_value || match (state, new_state) {
                    (State::Highlighted, State::Clicked) | (State::Clicked, State::Highlighted) => true,
                    _ => false,
                } { (*callback)(new_value) }
            }, None => (),
        }

        // Draw.
        let rect_state = new_state.as_rectangle_state();
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);

        // Rectangle frame / backdrop.
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state,
                        self.pos, self.dim, None, frame_color);
        // Slider rectangle.
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state,
                        pad_pos, pad_dim, None, color);

        // If there's a label, draw it.
        if let Some(text) = self.maybe_label {
            let text_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
            let size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
            let is_horizontal = self.dim[0] > self.dim[1];
            let l_pos = if is_horizontal {
                let x = pad_pos[0] + (pad_dim[1] - size as f64) / 2.0;
                let y = pad_pos[1] + (pad_dim[1] - size as f64) / 2.0;
                [x, y]
            } else {
                let label_w = label::width(uic, size, &text);
                let x = pad_pos[0] + (pad_dim[0] - label_w) / 2.0;
                let y = pad_pos[1] + pad_dim[1] - pad_dim[0] - frame_w;
                [x, y]
            };
            // Draw the label.
            uic.draw_text(graphics, l_pos, size, text_color, &text);
        }

        set_state(uic, self.ui_id, Widget::Slider(new_state), self.pos, self.dim);

    }
}
<commit_msg>Implemented `Shapeable` for `Slider`<commit_after>use num::{ Float, ToPrimitive, FromPrimitive };
use callback::Callable;
use frame::Frameable;
use color::{ Color, Colorable };
use label::{ FontSize, Labelable };
use dimensions::Dimensions;
use label;
use mouse::Mouse;
use graphics::Graphics;
use graphics::character::CharacterCache;
use point::Point;
use position::Positionable;
use shape::Shapeable;
use rectangle;
use ui_context::{ UIID, UiContext };
use utils::{
    clamp,
    percentage,
    value_from_perc,
};
use widget::Widget;
use vecmath::vec2_add;

/// Represents the state of the Button widget.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(Slider, State, Widget::Slider(State::Normal));

/// Check the current state of the slider.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _ => Normal,
    }
}

/// A context on which the builder pattern can be implemented.
pub struct Slider<'a, T, F> {
    ui_id: UIID,
    value: T,
    min: T,
    max: T,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl<'a, T, F> Slider<'a, T, F> {
    /// A button builder method to be implemented by the UiContext.
    pub fn new(ui_id: UIID, value: T, min: T, max: T) -> Slider<'a, T, F> {
        Slider {
            ui_id: ui_id,
            value: value,
            min: min,
            max: max,
            pos: [0.0, 0.0],
            dim: [192.0, 48.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, T, F> Colorable for Slider<'a, T, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, T, F> Frameable for Slider<'a, T, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

impl<'a, T, F> Callable<F> for Slider<'a, T, F> {
    fn callback(mut self, cb: F) -> Self {
        self.maybe_callback = Some(cb);
        self
    }
}

impl<'a, T, F> Labelable<'a> for Slider<'a, T, F>
{
    fn label(mut self, text: &'a str) -> Self {
        self.maybe_label = Some(text);
        self
    }

    fn label_color(mut self, color: Color) -> Self {
        self.maybe_label_color = Some(color);
        self
    }

    fn label_font_size(mut self, size: FontSize) -> Self {
        self.maybe_label_font_size = Some(size);
        self
    }
}

impl<'a, T, F> Positionable for Slider<'a, T, F> {
    fn point(mut self, pos: Point) -> Self {
        self.pos = pos;
        self
    }
}

impl<'a, T, F> Shapeable for Slider<'a, T, F> {
    fn get_dim(&self) -> Dimensions { self.dim }
    fn dim(mut self, dim: Dimensions) -> Self { self.dim = dim; self }
}

/*
quack! {
    slider: Slider['a, T, F]
    get:
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::Slider(State::Normal))
        }
        fn () -> Id [] { Id(slider.ui_id) }
    set:
    action:
}
*/

impl<'a, T, F> ::draw::Drawable for Slider<'a, T, F>
    where
        T: Float + FromPrimitive + ToPrimitive,
        F: FnMut(T) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over = rectangle::is_over(self.pos, mouse.pos, self.dim);
        let new_state = get_new_state(is_over, state, mouse);

        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let frame_color = self.maybe_frame_color.unwrap_or(uic.theme.frame_color);

        let is_horizontal = self.dim[0] > self.dim[1];
        let (new_value, pad_pos, pad_dim) = if is_horizontal {
            // Horizontal.
            let p = vec2_add(self.pos, [frame_w, frame_w]);
            let max_w = self.dim[0] - frame_w2;
            let w = match (is_over, state, new_state) {
                (true, State::Highlighted, State::Clicked) | (_, State::Clicked, State::Clicked)  =>
                     clamp(mouse.pos[0] - p[0], 0f64, max_w),
                _ => clamp(percentage(self.value, self.min, self.max) as f64 * max_w, 0f64, max_w),
            };
            let h = self.dim[1] - frame_w2;
            let new_value = value_from_perc((w / max_w) as f32, self.min, self.max);
            (new_value, p, [w, h])
        } else {
            // Vertical.
            let max_h = self.dim[1] - frame_w2;
            let corner = vec2_add(self.pos, [frame_w, frame_w]);
            let y_max = corner[1] + max_h;
            let (h, p) = match (is_over, state, new_state) {
                (true, State::Highlighted, State::Clicked) | (_, State::Clicked, State::Clicked) => {
                    let p = [corner[0], clamp(mouse.pos[1], corner[1], y_max)];
                    let h = clamp(max_h - (p[1] - corner[1]), 0.0, max_h);
                    (h, p)
                },
                _ => {
                    let h = clamp(percentage(self.value, self.min, self.max) as f64 * max_h, 0.0, max_h);
                    let p = [corner[0], corner[1] + max_h - h];
                    (h, p)
                },
            };
            let w = self.dim[0] - frame_w2;
            let new_value = value_from_perc((h / max_h) as f32, self.min, self.max);
            (new_value, p, [w, h])
        };

        // Callback.
        match self.maybe_callback {
            Some(ref mut callback) => {
                if self.value != new_value || match (state, new_state) {
                    (State::Highlighted, State::Clicked) | (State::Clicked, State::Highlighted) => true,
                    _ => false,
                } { (*callback)(new_value) }
            }, None => (),
        }

        // Draw.
        let rect_state = new_state.as_rectangle_state();
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);

        // Rectangle frame / backdrop.
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state,
                        self.pos, self.dim, None, frame_color);
        // Slider rectangle.
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state,
                        pad_pos, pad_dim, None, color);

        // If there's a label, draw it.
        if let Some(text) = self.maybe_label {
            let text_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
            let size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
            let is_horizontal = self.dim[0] > self.dim[1];
            let l_pos = if is_horizontal {
                let x = pad_pos[0] + (pad_dim[1] - size as f64) / 2.0;
                let y = pad_pos[1] + (pad_dim[1] - size as f64) / 2.0;
                [x, y]
            } else {
                let label_w = label::width(uic, size, &text);
                let x = pad_pos[0] + (pad_dim[0] - label_w) / 2.0;
                let y = pad_pos[1] + pad_dim[1] - pad_dim[0] - frame_w;
                [x, y]
            };
            // Draw the label.
            uic.draw_text(graphics, l_pos, size, text_color, &text);
        }

        set_state(uic, self.ui_id, Widget::Slider(new_state), self.pos, self.dim);

    }
}
<|endoftext|>