<commit_before>use super::ByteSize;

impl std::str::FromStr for ByteSize {
    type Err = String;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        if let Ok(v) = value.parse::<u64>() {
            return Ok(Self(v));
        }
        let number: String = value
            .chars()
            .take_while(|c| c.is_digit(10) || c == &'.')
            .collect();
        match number.parse::<f64>() {
            Ok(v) => {
                let suffix: String = value
                    .chars()
                    .skip_while(|c| c.is_whitespace() || c.is_digit(10) || c == &'.')
                    .collect();
                match suffix.parse::<Unit>() {
                    Ok(u) => Ok(Self((v * u.factor() as f64) as u64)),
                    Err(error) => Err(format!(
                        "couldn't parse {:?} into a known SI unit, {}",
                        suffix, error
                    )),
                }
            }
            Err(error) => Err(format!(
                "couldn't parse {:?} into a ByteSize, {}",
                value, error
            )),
        }
    }
}

enum Unit {
    Byte,
    // power of tens
    KiloByte,
    MegaByte,
    GigaByte,
    TeraByte,
    PetaByte,
    // power of twos
    KibiByte,
    MebiByte,
    GibiByte,
    TebiByte,
    PebiByte,
}

impl Unit {
    fn factor(&self) -> u64 {
        match self {
            Self::Byte => super::B,
            // power of tens
            Self::KiloByte => super::KB,
            Self::MegaByte => super::MB,
            Self::GigaByte => super::GB,
            Self::TeraByte => super::TB,
            Self::PetaByte => super::PB,
            // power of twos
            Self::KibiByte => super::KIB,
            Self::MebiByte => super::MIB,
            Self::GibiByte => super::GIB,
            Self::TebiByte => super::TIB,
            Self::PebiByte => super::PIB,
        }
    }
}

impl std::str::FromStr for Unit {
    type Err = String;

    fn from_str(unit: &str) -> Result<Self, Self::Err> {
        match unit.to_lowercase().as_str() {
            "b" => Ok(Self::Byte),
            // power of tens
            "k" | "kb" => Ok(Self::KiloByte),
            "m" | "mb" => Ok(Self::MegaByte),
            "g" | "gb" => Ok(Self::GigaByte),
            "t" | "tb" => Ok(Self::TeraByte),
            "p" | "pb" => Ok(Self::PetaByte),
            // power of twos
            "ki" | "kib" => Ok(Self::KibiByte),
            "mi" | "mib" => Ok(Self::MebiByte),
            "gi" | "gib" => Ok(Self::GibiByte),
            "ti" | "tib" => Ok(Self::TebiByte),
            "pi" | "pib" => Ok(Self::PebiByte),
            _ => Err(format!("couldn't parse unit of {:?}", unit)),
        }
    }
}

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

    #[test]
    fn when_ok() {
        // shortcut for writing test cases
        fn parse(s: &str) -> u64 {
            s.parse::<ByteSize>().unwrap().0
        }

        assert_eq!("0".parse::<ByteSize>().unwrap().0, 0);
        assert_eq!(parse("0"), 0);
        assert_eq!(parse("500"), 500);
        assert_eq!(parse("1K"), 1 * crate::KB);
        assert_eq!(parse("1Ki"), 1 * crate::KIB);
        assert_eq!(parse("1.5Ki"), (1.5 * crate::KIB as f64) as u64);
        assert_eq!(parse("1KiB"), 1 * crate::KIB);
        assert_eq!(parse("1.5KiB"), (1.5 * crate::KIB as f64) as u64);
        assert_eq!(parse("3 MB"), 3 * crate::MB);
        assert_eq!(parse("4 MiB"), 4 * crate::MIB);
        assert_eq!(parse("6 GB"), 6 * crate::GB);
        assert_eq!(parse("4 GiB"), 4 * crate::GIB);
        assert_eq!(parse("88TB"), 88 * crate::TB);
        assert_eq!(parse("521TiB"), 521 * crate::TIB);
        assert_eq!(parse("8 PB"), 8 * crate::PB);
        assert_eq!(parse("8P"), 8 * crate::PB);
        assert_eq!(parse("12 PiB"), 12 * crate::PIB);
    }

    #[test]
    fn when_err() {
        // shortcut for writing test cases
        fn parse(s: &str) -> Result<ByteSize, String> {
            s.parse::<ByteSize>()
        }

        assert!(parse("").is_err());
        assert!(parse("a124GB").is_err());
    }

    #[test]
    fn to_and_from_str() {
        // shortcut for writing test cases
        fn parse(s: &str) -> u64 {
            s.parse::<ByteSize>().unwrap().0
        }

        assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * crate::GB);
        assert_eq!(
            parse(&crate::to_string(parse("128.000 GiB"), true)),
            128 * crate::GIB
        );
    }
}
<commit_msg>impl ops<commit_after>use super::ByteSize;

impl std::str::FromStr for ByteSize {
    type Err = String;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        if let Ok(v) = value.parse::<u64>() {
            return Ok(Self(v));
        }
        let number: String = value
            .chars()
            .take_while(|c| c.is_digit(10) || c == &'.')
            .collect();
        match number.parse::<f64>() {
            Ok(v) => {
                let suffix: String = value
                    .chars()
                    .skip_while(|c| c.is_whitespace() || c.is_digit(10) || c == &'.')
                    .collect();
                match suffix.parse::<Unit>() {
                    Ok(u) => Ok(Self((v * u) as u64)),
                    Err(error) => Err(format!(
                        "couldn't parse {:?} into a known SI unit, {}",
                        suffix, error
                    )),
                }
            }
            Err(error) => Err(format!(
                "couldn't parse {:?} into a ByteSize, {}",
                value, error
            )),
        }
    }
}

enum Unit {
    Byte,
    // power of tens
    KiloByte,
    MegaByte,
    GigaByte,
    TeraByte,
    PetaByte,
    // power of twos
    KibiByte,
    MebiByte,
    GibiByte,
    TebiByte,
    PebiByte,
}

impl Unit {
    fn factor(&self) -> u64 {
        match self {
            Self::Byte => super::B,
            // power of tens
            Self::KiloByte => super::KB,
            Self::MegaByte => super::MB,
            Self::GigaByte => super::GB,
            Self::TeraByte => super::TB,
            Self::PetaByte => super::PB,
            // power of twos
            Self::KibiByte => super::KIB,
            Self::MebiByte => super::MIB,
            Self::GibiByte => super::GIB,
            Self::TebiByte => super::TIB,
            Self::PebiByte => super::PIB,
        }
    }
}

mod impl_ops {
    use super::Unit;
    use std::ops;

    impl ops::Add<u64> for Unit {
        type Output = u64;

        fn add(self, other: u64) -> Self::Output {
            self.factor() + other
        }
    }

    impl ops::Add<Unit> for u64 {
        type Output = u64;

        fn add(self, other: Unit) -> Self::Output {
            self + other.factor()
        }
    }

    impl ops::Mul<u64> for Unit {
        type Output = u64;

        fn mul(self, other: u64) -> Self::Output {
            self.factor() * other
        }
    }

    impl ops::Mul<Unit> for u64 {
        type Output = u64;

        fn mul(self, other: Unit) -> Self::Output {
            self * other.factor()
        }
    }

    impl ops::Add<f64> for Unit {
        type Output = f64;

        fn add(self, other: f64) -> Self::Output {
            self.factor() as f64 + other
        }
    }

    impl ops::Add<Unit> for f64 {
        type Output = f64;

        fn add(self, other: Unit) -> Self::Output {
            other.factor() as f64 + self
        }
    }

    impl ops::Mul<f64> for Unit {
        type Output = f64;

        fn mul(self, other: f64) -> Self::Output {
            self.factor() as f64 * other
        }
    }

    impl ops::Mul<Unit> for f64 {
        type Output = f64;

        fn mul(self, other: Unit) -> Self::Output {
            other.factor() as f64 * self
        }
    }
}

impl std::str::FromStr for Unit {
    type Err = String;

    fn from_str(unit: &str) -> Result<Self, Self::Err> {
        match unit.to_lowercase().as_str() {
            "b" => Ok(Self::Byte),
            // power of tens
            "k" | "kb" => Ok(Self::KiloByte),
            "m" | "mb" => Ok(Self::MegaByte),
            "g" | "gb" => Ok(Self::GigaByte),
            "t" | "tb" => Ok(Self::TeraByte),
            "p" | "pb" => Ok(Self::PetaByte),
            // power of twos
            "ki" | "kib" => Ok(Self::KibiByte),
            "mi" | "mib" => Ok(Self::MebiByte),
            "gi" | "gib" => Ok(Self::GibiByte),
            "ti" | "tib" => Ok(Self::TebiByte),
            "pi" | "pib" => Ok(Self::PebiByte),
            _ => Err(format!("couldn't parse unit of {:?}", unit)),
        }
    }
}

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

    #[test]
    fn when_ok() {
        // shortcut for writing test cases
        fn parse(s: &str) -> u64 {
            s.parse::<ByteSize>().unwrap().0
        }

        assert_eq!("0".parse::<ByteSize>().unwrap().0, 0);
        assert_eq!(parse("0"), 0);
        assert_eq!(parse("500"), 500);
        assert_eq!(parse("1K"), Unit::KiloByte * 1);
        assert_eq!(parse("1Ki"), Unit::KibiByte * 1);
        assert_eq!(parse("1.5Ki"), (1.5 * Unit::KibiByte) as u64);
        assert_eq!(parse("1KiB"), 1 * Unit::KibiByte);
        assert_eq!(parse("1.5KiB"), (1.5 * Unit::KibiByte) as u64);
        assert_eq!(parse("3 MB"), Unit::MegaByte * 3);
        assert_eq!(parse("4 MiB"), Unit::MebiByte * 4);
        assert_eq!(parse("6 GB"), 6 * Unit::GigaByte);
        assert_eq!(parse("4 GiB"), 4 * Unit::GibiByte);
        assert_eq!(parse("88TB"), 88 * Unit::TeraByte);
        assert_eq!(parse("521TiB"), 521 * Unit::TebiByte);
        assert_eq!(parse("8 PB"), 8 * Unit::PetaByte);
        assert_eq!(parse("8P"), 8 * Unit::PetaByte);
        assert_eq!(parse("12 PiB"), 12 * Unit::PebiByte);
    }

    #[test]
    fn when_err() {
        // shortcut for writing test cases
        fn parse(s: &str) -> Result<ByteSize, String> {
            s.parse::<ByteSize>()
        }

        assert!(parse("").is_err());
        assert!(parse("a124GB").is_err());
    }

    #[test]
    fn to_and_from_str() {
        // shortcut for writing test cases
        fn parse(s: &str) -> u64 {
            s.parse::<ByteSize>().unwrap().0
        }

        assert_eq!(parse(&format!("{}", parse("128GB"))), 128 * Unit::GigaByte);
        assert_eq!(
            parse(&crate::to_string(parse("128.000 GiB"), true)),
            128 * Unit::GibiByte
        );
    }
}
<|endoftext|>


<commit_before>use std::num;
use std::collections::PriorityQueue;

fn is_palindrome(num: uint) -> bool {
    let s = num.to_string();
    let b = s.as_bytes();
    for i in range(0, b.len() / 2) {
        if b[i] != b[b.len() - i - 1] {
            return false;
        }
    }
    true
}

fn largest_palindrome_product(digits: uint) -> uint {
    let max = num::pow(10u, digits);
    let min = 0u;
    let mut results = PriorityQueue::new();

    for i in range(max/2, max).rev() {
        for j in range(0, max).rev() {
            let k = i * j;
            if is_palindrome(k) {
                results.push(k);
            }
        }
    }

    *results.top().unwrap()
}

#[cfg(test)]
mod test {
    use super::{is_palindrome, largest_palindrome_product};

    #[test]
    fn test_is_palindrome() {
        assert!(is_palindrome(9009));
        assert!(is_palindrome(90909));
        assert!(!is_palindrome(9000));
        assert!(!is_palindrome(90900));
    }

    #[test]
    fn provided_example() {
        assert_eq!(largest_palindrome_product(2), 906609);
    }

    #[test]
    fn expected_result() {
        assert_eq!(largest_palindrome_product(3), 90909);
    }
}

<commit_msg>Fix problem 4 tests, remove unused variable.<commit_after>use std::num;
use std::collections::PriorityQueue;

fn is_palindrome(num: uint) -> bool {
    let s = num.to_string();
    let b = s.as_bytes();
    for i in range(0, b.len() / 2) {
        if b[i] != b[b.len() - i - 1] {
            return false;
        }
    }
    true
}

fn largest_palindrome_product(digits: uint) -> uint {
    let max = num::pow(10u, digits);
    let mut results = PriorityQueue::new();

    for i in range(max/2, max).rev() {
        for j in range(0, max).rev() {
            let k = i * j;
            if is_palindrome(k) {
                results.push(k);
            }
        }
    }

    *results.top().unwrap()
}

#[cfg(test)]
mod test {
    use super::{is_palindrome, largest_palindrome_product};

    #[test]
    fn test_is_palindrome() {
        assert!(is_palindrome(9009));
        assert!(is_palindrome(90909));
        assert!(!is_palindrome(9000));
        assert!(!is_palindrome(90900));
    }

    #[test]
    fn provided_example() {
        assert_eq!(largest_palindrome_product(2), 9009);
    }

    #[test]
    fn expected_result() {
        assert_eq!(largest_palindrome_product(3), 906609);
    }
}

<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use gstr;
use gstr::GStr;
use types::gchar;
use util::escape_bytestring;

use glib as ffi;

use std::fmt;
use std::sync::atomic;

#[derive(Copy, Eq, PartialEq)]
pub struct Quark(ffi::GQuark);

pub struct StaticQuark(pub &'static [u8], pub atomic::AtomicUint);

impl Quark {

    #[inline]
    pub unsafe fn from_raw(raw: ffi::GQuark) -> Quark {
        Quark(raw)
    }

    pub fn from_static_str(s: &'static str) -> Quark {
        if !s.ends_with("\0") {
            panic!("static string is not null-terminated: \"{}\"", s);
        }
        unsafe { Quark::from_static_internal(s.as_bytes()) }
    }

    pub fn from_static_bytes(bytes: &'static [u8]) -> Quark {
        assert!(!bytes.is_empty());
        if bytes[bytes.len() - 1] != 0 {
            panic!("static byte string is not null-terminated: \"{}\"",
                   escape_bytestring(bytes));
        }
        unsafe { Quark::from_static_internal(bytes) }
    }

    unsafe fn from_static_internal(s: &'static [u8]) -> Quark {
        let p = s.as_ptr() as *const gchar;
        let q = ffi::g_quark_from_static_string(p);
        Quark(q)
    }

    pub fn as_g_str(&self) -> &'static GStr {
        let Quark(raw) = *self;
        unsafe {
            let s = ffi::g_quark_to_string(raw);
            GStr::from_raw(s, "")
        }
    }

    pub fn as_bytes(&self) -> &'static [u8] {
        let Quark(raw) = *self;
        unsafe {
            let s = ffi::g_quark_to_string(raw);
            gstr::parse_as_bytes(s, "")
        }
    }

    pub fn to_raw(&self) -> ffi::GQuark {
        self.0
    }
}

impl fmt::Display for Quark {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", String::from_utf8_lossy(self.as_bytes()))
    }
}

impl fmt::Debug for Quark {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\"{}\"", escape_bytestring(self.as_bytes()))
    }
}

impl StaticQuark {

    pub fn get(&self) -> Quark {
        let StaticQuark(s, ref cached) = *self;
        let mut q = cached.load(atomic::Ordering::Relaxed) as ffi::GQuark;
        if q == 0 {
            unsafe {
                let p = s.as_ptr() as *const gchar;
                q = ffi::g_quark_from_static_string(p);
            }
            cached.store(q as usize, atomic::Ordering::Relaxed);
        }
        Quark(q)
    }
}
<commit_msg>quark: check for null-terminated strings in StaticQuark::get()<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use gstr;
use gstr::GStr;
use types::gchar;
use util::escape_bytestring;

use glib as ffi;

use std::fmt;
use std::sync::atomic;

#[derive(Copy, Eq, PartialEq)]
pub struct Quark(ffi::GQuark);

pub struct StaticQuark(pub &'static [u8], pub atomic::AtomicUint);

impl Quark {

    #[inline]
    pub unsafe fn from_raw(raw: ffi::GQuark) -> Quark {
        Quark(raw)
    }

    pub fn from_static_str(s: &'static str) -> Quark {
        if !s.ends_with("\0") {
            panic!("static string is not null-terminated: \"{}\"", s);
        }
        unsafe { Quark::from_static_internal(s.as_bytes()) }
    }

    pub fn from_static_bytes(bytes: &'static [u8]) -> Quark {
        assert!(!bytes.is_empty());
        if bytes[bytes.len() - 1] != 0 {
            panic!("static byte string is not null-terminated: \"{}\"",
                   escape_bytestring(bytes));
        }
        unsafe { Quark::from_static_internal(bytes) }
    }

    unsafe fn from_static_internal(s: &'static [u8]) -> Quark {
        let p = s.as_ptr() as *const gchar;
        let q = ffi::g_quark_from_static_string(p);
        Quark(q)
    }

    pub fn as_g_str(&self) -> &'static GStr {
        let Quark(raw) = *self;
        unsafe {
            let s = ffi::g_quark_to_string(raw);
            GStr::from_raw(s, "")
        }
    }

    pub fn as_bytes(&self) -> &'static [u8] {
        let Quark(raw) = *self;
        unsafe {
            let s = ffi::g_quark_to_string(raw);
            gstr::parse_as_bytes(s, "")
        }
    }

    pub fn to_raw(&self) -> ffi::GQuark {
        self.0
    }
}

impl fmt::Display for Quark {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", String::from_utf8_lossy(self.as_bytes()))
    }
}

impl fmt::Debug for Quark {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\"{}\"", escape_bytestring(self.as_bytes()))
    }
}

impl StaticQuark {

    pub fn get(&self) -> Quark {
        let StaticQuark(s, ref cached) = *self;
        let q = cached.load(atomic::Ordering::Relaxed) as ffi::GQuark;
        if q != 0 {
            Quark(q)
        } else {
            let quark = Quark::from_static_bytes(s);
            cached.store(quark.to_raw() as usize, atomic::Ordering::Relaxed);
            quark
        }
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug, PartialEq)]
pub enum QuerySyntaxError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownQueryType(String),
    NoQuery,
    FilteredNoFilter,
    FilteredNoQuery,
    MissingQueryString,
    MultiMatchMissingFields,
}

#[derive(Debug, PartialEq)]
pub enum Filter {
    Term(String, Json),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

#[derive(Debug, PartialEq)]
pub enum Query {
    MatchAll,
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    return field_value == value;
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Filter {
    let filter_json = json.as_object().unwrap();
    let first_key = filter_json.keys().nth(0).unwrap();

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        Filter::Term(first_key.clone(), filter_json.get(first_key).unwrap().clone())
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Filter::Prefix(first_key.clone(), value.to_owned())
    } else if first_key == "and" {
        Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "or" {
        Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "not" {
        Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap())))
    } else {
        Filter::Term("not".to_owned(), Json::String("implemented".to_owned()))
    }
}

impl Query {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Query::MatchAll => true,
            Query::Match{ref field, ref query} => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    let mut field_value = field_value.as_string().unwrap().to_lowercase();
                    let mut query = query.to_lowercase();

                    return field_value.contains(&query);
                }

                false
            }
            Query::MultiMatch{ref fields, ref query} => {
                // TODO
                false
            }
            Query::Filtered{ref query, ref filter} => {
                if filter.matches(doc) {
                    query.matches(doc)
                } else {
                    false
                }
            }
        }
    }
}

pub fn parse_match_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QuerySyntaxError::NoQuery));

    Ok(Query::Match {
        field: first_key.clone(),
        query: json_object.get(first_key).unwrap().as_string().unwrap().to_owned(),
    })
}

pub fn parse_multi_match_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));

    // Convert "fields" into a Vec<String>
    let fields_json = try!(json_object.get("fields").ok_or(QuerySyntaxError::MultiMatchMissingFields));
    let fields = try!(fields_json.as_array().ok_or(QuerySyntaxError::ExpectedArray))
                      .iter().map(|s| s.as_string().unwrap().to_owned())
                      .collect::<Vec<_>>();

    let query_json = try!(json_object.get("query").ok_or(QuerySyntaxError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QuerySyntaxError::ExpectedString)).to_owned();

    Ok(Query::MultiMatch {
        fields: fields,
        query: query,
    })
}

pub fn parse_filtered_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));

    let filter_json = try!(json_object.get("filter").ok_or(QuerySyntaxError::FilteredNoFilter));
    let filter = parse_filter(filter_json);

    let query_json = try!(json_object.get("query").ok_or(QuerySyntaxError::FilteredNoQuery));
    let query = try!(parse_query(query_json));

    Ok(Query::Filtered {
        filter: Box::new(filter),
        query: Box::new(query),
    })
}

pub fn parse_query(json: &Json) -> Result<Query, QuerySyntaxError> {
    let json_object = try!(json.as_object().ok_or(QuerySyntaxError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QuerySyntaxError::NoQuery));

    if first_key == "match_all" {
        Ok(Query::MatchAll)
    } else if first_key == "match" {
        let inner_query = json_object.get("match").unwrap();
        Ok(try!(parse_match_query(inner_query)))
    } else if first_key == "multi_match" {
        let inner_query = json_object.get("multi_match").unwrap();
        Ok(try!(parse_multi_match_query(inner_query)))
    } else if first_key == "filtered" {
        let inner_query = json_object.get("filtered").unwrap();
        Ok(try!(parse_filtered_query(inner_query)))
    } else {
        Err(QuerySyntaxError::UnknownQueryType(first_key.clone()))
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;
    use super::{Query, Filter, QuerySyntaxError, parse_query};

    #[test]
    fn test_match_all_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match_all\": {}
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchAll))
    }

    #[test]
    fn test_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {
                    \"title\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Match{
            field: "title".to_owned(),
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_match_query_without_field() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {}
            }
        ").unwrap());

        assert_eq!(query, Err(QuerySyntaxError::NoQuery))
    }

    #[test]
    fn test_multi_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"],
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MultiMatch{
            fields: vec!["title".to_owned(), "body".to_owned()],
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_multi_match_query_without_fields() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QuerySyntaxError::MultiMatchMissingFields))
    }

    #[test]
    fn test_multi_match_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"]
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QuerySyntaxError::MissingQueryString))
    }

    #[test]
    fn test_filtered_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    },
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Filtered{
            query: Box::new(Query::Match{
                field: "title".to_owned(),
                query: "Hello world!".to_owned(),
            }),
            filter: Box::new(Filter::Term(
                "date".to_owned(),
                Json::from_str("\"2016-01-25\"").unwrap(),
            ))
        }))
    }

    #[test]
    fn test_filtered_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QuerySyntaxError::FilteredNoQuery))
    }

    #[test]
    fn test_filtered_query_without_filter() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QuerySyntaxError::FilteredNoFilter))
    }
}
<commit_msg>Rename QueryParseError to QuerySyntaxError<commit_after>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug, PartialEq)]
pub enum Filter {
    Term(String, Json),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

#[derive(Debug, PartialEq)]
pub enum QueryParseError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownQueryType(String),
    NoQuery,
    FilteredNoFilter,
    FilteredNoQuery,
    MissingQueryString,
    MultiMatchMissingFields,
}

#[derive(Debug, PartialEq)]
pub enum Query {
    MatchAll,
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    return field_value == value;
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Filter {
    let filter_json = json.as_object().unwrap();
    let first_key = filter_json.keys().nth(0).unwrap();

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        Filter::Term(first_key.clone(), filter_json.get(first_key).unwrap().clone())
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Filter::Prefix(first_key.clone(), value.to_owned())
    } else if first_key == "and" {
        Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "or" {
        Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "not" {
        Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap())))
    } else {
        Filter::Term("not".to_owned(), Json::String("implemented".to_owned()))
    }
}

impl Query {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Query::MatchAll => true,
            Query::Match{ref field, ref query} => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    let mut field_value = field_value.as_string().unwrap().to_lowercase();
                    let mut query = query.to_lowercase();

                    return field_value.contains(&query);
                }

                false
            }
            Query::MultiMatch{ref fields, ref query} => {
                // TODO
                false
            }
            Query::Filtered{ref query, ref filter} => {
                if filter.matches(doc) {
                    query.matches(doc)
                } else {
                    false
                }
            }
        }
    }
}

pub fn parse_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    Ok(Query::Match {
        field: first_key.clone(),
        query: json_object.get(first_key).unwrap().as_string().unwrap().to_owned(),
    })
}

pub fn parse_multi_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    // Convert "fields" into a Vec<String>
    let fields_json = try!(json_object.get("fields").ok_or(QueryParseError::MultiMatchMissingFields));
    let fields = try!(fields_json.as_array().ok_or(QueryParseError::ExpectedArray))
                      .iter().map(|s| s.as_string().unwrap().to_owned())
                      .collect::<Vec<_>>();

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QueryParseError::ExpectedString)).to_owned();

    Ok(Query::MultiMatch {
        fields: fields,
        query: query,
    })
}

pub fn parse_filtered_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    let filter_json = try!(json_object.get("filter").ok_or(QueryParseError::FilteredNoFilter));
    let filter = parse_filter(filter_json);

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::FilteredNoQuery));
    let query = try!(parse_query(query_json));

    Ok(Query::Filtered {
        filter: Box::new(filter),
        query: Box::new(query),
    })
}

pub fn parse_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    if first_key == "match_all" {
        Ok(Query::MatchAll)
    } else if first_key == "match" {
        let inner_query = json_object.get("match").unwrap();
        Ok(try!(parse_match_query(inner_query)))
    } else if first_key == "multi_match" {
        let inner_query = json_object.get("multi_match").unwrap();
        Ok(try!(parse_multi_match_query(inner_query)))
    } else if first_key == "filtered" {
        let inner_query = json_object.get("filtered").unwrap();
        Ok(try!(parse_filtered_query(inner_query)))
    } else {
        Err(QueryParseError::UnknownQueryType(first_key.clone()))
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;
    use super::{Query, Filter, QueryParseError, parse_query};

    #[test]
    fn test_match_all_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match_all\": {}
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchAll))
    }

    #[test]
    fn test_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {
                    \"title\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Match{
            field: "title".to_owned(),
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_match_query_without_field() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {}
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::NoQuery))
    }

    #[test]
    fn test_multi_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"],
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MultiMatch{
            fields: vec!["title".to_owned(), "body".to_owned()],
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_multi_match_query_without_fields() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MultiMatchMissingFields))
    }

    #[test]
    fn test_multi_match_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"]
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MissingQueryString))
    }

    #[test]
    fn test_filtered_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    },
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Filtered{
            query: Box::new(Query::Match{
                field: "title".to_owned(),
                query: "Hello world!".to_owned(),
            }),
            filter: Box::new(Filter::Term(
                "date".to_owned(),
                Json::from_str("\"2016-01-25\"").unwrap(),
            ))
        }))
    }

    #[test]
    fn test_filtered_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoQuery))
    }

    #[test]
    fn test_filtered_query_without_filter() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoFilter))
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::fmt;
use std::ops::Range as RangeOp;

use super::bound::{BoundType, Bound};

// Unpack Bound into scope to reduce verbosity
use super::bound::Bound::*;

#[derive(Clone, Debug, PartialEq)]
pub struct Range<T> {
    lower: Bound<T>,
    upper: Bound<T>,
}

impl<T> Range<T> {
    pub fn new(lower: Bound<T>, upper: Bound<T>) -> Range<T> {
        Range {
            lower: lower,
            upper: upper,
        }
    }

    pub fn lower_inf(&self) -> bool {
        match self.lower {
            Bound::Unbounded => true,
            _ => false,
        }
    }

    pub fn upper_inf(&self) -> bool {
        match self.upper {
            Bound::Unbounded => true,
            _ => false,
        }
    }

    pub fn is_bounded(&self) -> bool {
        self.lower.is_bounded() && self.upper.is_bounded()
    }
}

impl<T: PartialOrd> Range<T> {
    pub fn contains(&self, item: &T) -> bool {
        let within_lower = match self.lower {
            Inclusive(ref lower) => item >= lower,
            Exclusive(ref lower) => item > lower,
            Unbounded => true,
        };

        let within_upper = match self.upper {
            Inclusive(ref upper) => item <= upper,
            Exclusive(ref upper) => item < upper,
            Unbounded => true,
        };

        within_lower && within_upper
    }
}

impl<T> From<RangeOp<Bound<T>>> for Range<T> {
    fn from(range: RangeOp<Bound<T>>) -> Range<T> {
        Range {
            lower: range.start,
            upper: range.end,
        }
    }
}

// Add shorthands for common range types such as Range::from(1..10). The lower
// end is always inclusive and the upper end is always exclusive.
macro_rules! from_rangeop_impl_for_range {
    ($($t:ty)*) => ($(
        impl From<RangeOp<$t>> for Range<$t> {
            fn from(range: RangeOp<$t>) -> Range<$t> {
                Range::from(Inclusive(range.start) .. Exclusive(range.end))
            }
        }
    )*)
}

from_rangeop_impl_for_range! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }

impl<T: Clone> Range<T> {
    pub fn lower(&self) -> Bound<T> {
        self.lower.clone()
    }

    pub fn upper(&self) -> Bound<T> {
        self.upper.clone()
    }
}

impl<T: fmt::Display> fmt::Display for Range<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.lower {
            Bound::Inclusive(ref x) => write!(f, "[{}", x),
            Bound::Exclusive(ref x) => write!(f, "({}", x),
            Bound::Unbounded => write!(f, "("),
        }?;

        write!(f, ",")?;

        match self.upper {
            Bound::Inclusive(ref x) => write!(f, "{}]", x),
            Bound::Exclusive(ref x) => write!(f, "{})", x),
            Bound::Unbounded => write!(f, ")"),
        }
    }
}

impl<T: PartialOrd> PartialOrd for Range<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match Bound::compare_bounds(BoundType::Lower, &self.lower, &other.lower) {
            Some(Ordering::Equal) => {
                Bound::compare_bounds(BoundType::Upper, &self.upper, &other.upper)
            },
            cmp => cmp,
        }
    }
}
<commit_msg>Added support for empty ranges<commit_after>use std::cmp::Ordering;
use std::fmt;
use std::ops::Range as RangeOp;

use super::bound::{BoundType, Bound};

// Unpack Bound and Range into scope to reduce verbosity
use super::bound::Bound::*;
use self::Range::*;

#[derive(Clone, Debug, PartialEq)]
pub struct Interval<T> {
    lower: Bound<T>,
    upper: Bound<T>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Range<T> {
    Inhabited(Interval<T>),
    Empty,
}

impl<T> Range<T> {
    pub fn new(lower: Bound<T>, upper: Bound<T>) -> Range<T> {
        Inhabited(Interval {
            lower: lower,
            upper: upper,
        })
    }

    pub fn lower_inf(&self) -> bool {
        match *self {
            Inhabited(ref range) => match range.lower {
                Bound::Unbounded => true,
                _ => false,
            },
            Empty => false,
        }
    }

    pub fn upper_inf(&self) -> bool {
        match *self {
            Inhabited(ref range) => match range.upper {
                Bound::Unbounded => true,
                _ => false,
            },
            Empty => false,
        }
    }

    pub fn is_bounded(&self) -> bool {
        match *self {
            Inhabited(ref range) => {
                range.lower.is_bounded() && range.upper.is_bounded()
            },
            Empty => true,
        }
    }
}

impl<T: PartialOrd> Range<T> {
    pub fn contains(&self, item: &T) -> bool {
        match *self {
            Inhabited(ref range) => {
                let within_lower = match range.lower {
                    Inclusive(ref lower) => item >= lower,
                    Exclusive(ref lower) => item > lower,
                    Unbounded => true,
                };

                let within_upper = match range.upper {
                    Inclusive(ref upper) => item <= upper,
                    Exclusive(ref upper) => item < upper,
                    Unbounded => true,
                };

                within_lower && within_upper
            },
            Empty => false,
        }
    }
}

impl<T> From<RangeOp<Bound<T>>> for Range<T> {
    fn from(range: RangeOp<Bound<T>>) -> Range<T> {
        Range::new(range.start, range.end)
    }
}

// Add shorthands for common range types such as Range::from(1..10). The lower
// end is always inclusive and the upper end is always exclusive.
macro_rules! from_rangeop_impl_for_range {
    ($($t:ty)*) => ($(
        impl From<RangeOp<$t>> for Range<$t> {
            fn from(range: RangeOp<$t>) -> Range<$t> {
                Range::from(Inclusive(range.start) .. Exclusive(range.end))
            }
        }
    )*)
}

from_rangeop_impl_for_range! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }

impl<T: Clone> Range<T> {
    pub fn lower(&self) -> Option<Bound<T>> {
        match *self {
            Inhabited(ref range) => Some(range.lower.clone()),
            Empty => None,
        }
    }

    pub fn upper(&self) -> Option<Bound<T>> {
        match *self {
            Inhabited(ref range) => Some(range.upper.clone()),
            Empty => None,
        }
    }
}

impl<T: fmt::Display> fmt::Display for Range<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Inhabited(ref range) => {
                match range.lower {
                    Bound::Inclusive(ref x) => write!(f, "[{}", x),
                    Bound::Exclusive(ref x) => write!(f, "({}", x),
                    Bound::Unbounded => write!(f, "("),
                }?;

                write!(f, ",")?;

                match range.upper {
                    Bound::Inclusive(ref x) => write!(f, "{}]", x),
                    Bound::Exclusive(ref x) => write!(f, "{})", x),
                    Bound::Unbounded => write!(f, ")"),
                }
            },
            Empty => write!(f, "(empty)"),
        }
    }
}

impl<T: PartialOrd> PartialOrd for Range<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match (self, other) {
            (&Inhabited(ref a), &Inhabited(ref b)) => {
                match Bound::compare_bounds(
                    BoundType::Lower, &a.lower, &b.lower)
                {
                    Some(Ordering::Equal) => {
                        Bound::compare_bounds(
                            BoundType::Upper, &a.upper, &b.upper)
                    },
                    cmp => cmp,
                }
            },
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "rustyredis"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;
use std::int::parse_bytes;

// TODO: might need custom parse_bytes
// TODO: need custom readline for bulk items
// TODO: redo format and args, not quite right
//       can't just assume every space is an arg

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(int),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String, //this probably needs to be changed somehow
  reply: RedisObject,
  pos: uint, //might be needed in future, with dealing with multiple replies
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int, // async flag?
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &str> {
    match parse_bytes(s.as_bytes(), 10) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn create_string(&self, mut buf: BufReader, len: uint) -> Result<RedisObject, &str> {
    match buf.read_to_str() {
      Ok(s) => {
        if len + 2 != s.len() { // include \r\n
          return Err("Invalid string for create_string: lengths do not matchup");
        }
        let ns = s.as_slice().trim();
        Ok(RedisString(ns.to_str()))
      },
      Err(_) => Err("Invalid string for create_string") // would be nice to not ignore this error
    }
  }

  fn process_line_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => self.reply = RedisStatus(nns.to_str()),
          RedisReplyError => self.reply = RedisError(nns.to_str()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => self.reply = n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();
        let mut len: int;
        match parse_bytes(nns.as_bytes(), 10){
          Some(n) => {
            if n == -1{
              len = -1;
              self.rstack[self.ridx as uint].kind = RedisReplyNil;
            }
            else{
              len = n;
            }
          },
          None => { return Err("Invalid length in reply for process_bulk_item") }
        };

        match self.rstack[self.ridx as uint].kind {
          RedisReplyString => match self.create_string(reader, len as uint) {
            Ok(s) => self.reply = s,
            Err(e) => return Err(e)
          },
          RedisReplyNil => self.reply = RedisNil,
          _ => return Err("Invalid type for process_bulk_item")
        }
        Ok(())
      }
      Err(e) => Err(e.desc)
    }
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    match slice.char_at(0) {
      '-' => kind = RedisReplyError,
      '+' => kind = RedisReplyStatus,
      ':' => kind = RedisReplyInteger,
      '$' => kind = RedisReplyString,
      '*' => kind = RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    }

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }
    self.buf.truncate(0);
    self.len = 0;
    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_str();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, format: &str) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    for arg in format.split(' '){
      let arglen = arg.len();
      c = c.append("$");
      c = c.append(arglen.to_str().as_slice());
      c = c.append("\r\n");
      c = c.append(arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_str().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_str();
  }

  fn check_error(&self) -> bool {
    match self.err {
      RedisNoError => false,
      _ => true
    }
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); }
      _ => ()
    }
  }

  fn buffer_read(&mut self) {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); },
      Err(e) => { self.set_error(RedisIoError, e.desc); }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();

        if self.check_error() {
          return Err("Error. Check error members.");
        }
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found. Check error members.")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, command: &str) -> Result<Option<RedisObject>, &str> {
    self.obuf = self.format_command(command);
    self.block_for_reply()
  }
}

#[cfg(test)]
mod test {
  #[test]
  fn test_connect(){
    let c = ::RedisContext::connect("127.0.0.1", 6379);
  }

  #[test]
  fn test_command(){
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("PING");

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisStatus(s) => assert!(s.eq(&"PONG".to_str())),
          _ => fail!("Didn't return correct reply type.")
        },
        None => fail!("Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }
  }

  #[test]
  fn test_reply_types() {
    // Integer
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("APPEND mykey test");

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 4),
          _ => fail!("INTEGER: Didn't return correct reply type.")
        },
        None => fail!("INTEGER: Didn't return anything.")
      },
      Err(e) => fail!("INTEGER: {}", e)
    }

    // String
    let r = c.command("GET mykey");

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisString(s) => assert!(s.eq(&"test".to_str())),
          _ => fail!("STRING: Didn't return correct reply type.")
        },
        None => fail!("STRING: Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }

    // cleanup
    let r = c.command("DEL mykey");

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 1),
          _ => fail!("DELETE FAILED for test_process_bulk_item")
        },
        None => fail!("DELETE FAILED for test_procoess_bulk_item")
      },
      Err(_) => fail!("DELETE FAILED for test_process_bulk_item")
    }
  }
}

<commit_msg>slice of args instead of just string<commit_after>#![crate_name = "rustyredis"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;
use std::int::parse_bytes;

// TODO: might need custom parse_bytes
// TODO: need custom readline for bulk items

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(int),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String, //this probably needs to be changed somehow
  reply: RedisObject,
  pos: uint, //might be needed in future, with dealing with multiple replies
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int, // async flag?
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &str> {
    match parse_bytes(s.as_bytes(), 10) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn create_string(&self, mut buf: BufReader, len: uint) -> Result<RedisObject, &str> {
    match buf.read_to_str() {
      Ok(s) => {
        if len + 2 != s.len() { // include \r\n
          return Err("Invalid string for create_string: lengths do not matchup");
        }
        let ns = s.as_slice().trim();
        Ok(RedisString(ns.to_str()))
      },
      Err(_) => Err("Invalid string for create_string") // would be nice to not ignore this error
    }
  }

  fn process_line_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => self.reply = RedisStatus(nns.to_str()),
          RedisReplyError => self.reply = RedisError(nns.to_str()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => self.reply = n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();
        let mut len: int;
        match parse_bytes(nns.as_bytes(), 10){
          Some(n) => {
            if n == -1{
              len = -1;
              self.rstack[self.ridx as uint].kind = RedisReplyNil;
            }
            else{
              len = n;
            }
          },
          None => { return Err("Invalid length in reply for process_bulk_item") }
        };

        match self.rstack[self.ridx as uint].kind {
          RedisReplyString => match self.create_string(reader, len as uint) {
            Ok(s) => self.reply = s,
            Err(e) => return Err(e)
          },
          RedisReplyNil => self.reply = RedisNil,
          _ => return Err("Invalid type for process_bulk_item")
        }
        Ok(())
      }
      Err(e) => Err(e.desc)
    }
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    match slice.char_at(0) {
      '-' => kind = RedisReplyError,
      '+' => kind = RedisReplyStatus,
      ':' => kind = RedisReplyInteger,
      '$' => kind = RedisReplyString,
      '*' => kind = RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    }

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }
    self.buf.truncate(0);
    self.len = 0;
    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_str();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, cmd: &str, args: &[&str]) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    let mut len = cmd.len();
    c = c.append("$");
    c = c.append(len.to_str().as_slice());
    c = c.append("\r\n");
    c = c.append(cmd);
    c = c.append("\r\n");
    argc = argc + 1;

    for arg in args.iter(){
      len = arg.len();
      c = c.append("$");
      c = c.append(len.to_str().as_slice());
      c = c.append("\r\n");
      c = c.append(*arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_str().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_str();
  }

  fn check_error(&self) -> bool {
    match self.err {
      RedisNoError => false,
      _ => true
    }
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); }
      _ => ()
    }
  }

  fn buffer_read(&mut self) {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); },
      Err(e) => { self.set_error(RedisIoError, e.desc); }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();

        if self.check_error() {
          return Err("Error. Check error members.");
        }
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found. Check error members.")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, cmd: &str, args: &[&str]) -> Result<Option<RedisObject>, &str> {
    self.obuf = self.format_command(cmd, args);
    self.block_for_reply()
  }
}

#[cfg(test)]
mod test {
  #[test]
  fn test_connect(){
    let _ = ::RedisContext::connect("127.0.0.1", 6379);
  }

  #[test]
  fn test_command(){
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("PING", []);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisStatus(s) => assert!(s.eq(&"PONG".to_str())),
          _ => fail!("Didn't return correct reply type.")
        },
        None => fail!("Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }
  }

  #[test]
  fn test_reply_types() {
    // Integer
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("APPEND", ["mykey", "test"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 4),
          _ => fail!("INTEGER: Didn't return correct reply type.")
        },
        None => fail!("INTEGER: Didn't return anything.")
      },
      Err(e) => fail!("INTEGER: {}", e)
    }

    // String
    let r = c.command("GET", ["mykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisString(s) => assert!(s.eq(&"test".to_str())),
          _ => fail!("STRING: Didn't return correct reply type.")
        },
        None => fail!("STRING: Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }

    // cleanup
    let r = c.command("DEL", ["mykey"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 1),
          _ => fail!("DELETE FAILED for test_process_bulk_item")
        },
        None => fail!("DELETE FAILED for test_procoess_bulk_item")
      },
      Err(_) => fail!("DELETE FAILED for test_process_bulk_item")
    }
  }
}

<|endoftext|>


<commit_before>use std::cmp::min;
use std::ascii::AsciiExt;

#[derive(Clone, Debug,PartialEq)]
pub struct Quality(pub f32);

impl Quality {
    pub fn to_f32(&self) -> f32 {
        let Quality(q) = *self;
        q
    }
}

#[derive(Clone, Debug,PartialEq)]
pub struct Substring(pub usize,pub usize);

impl Substring {
    pub fn slice(&self, input: &String) -> (String, String, String) {
       let Substring(start, end) = *self;
       (input[0..start].to_string(),
        input[start..end].to_string(),
        input[end..].to_string())
    }
}

#[derive(Clone, Debug,PartialEq)]
pub struct Match<'a> {
    pub quality: Quality,
    pub range: Substring,
    pub original: &'a String,

}

impl <'a>Match<'a>{
    pub fn new(quality: Quality, range: Substring, original: &'a String) -> Match<'a> {
        Match { quality: quality, range: range, original: original }
    }

    pub fn origin_only(original: &'a String) -> Match<'a> {
        Match::new(Quality(1.0), Substring(0,0), original)
    }
}

pub fn score<'a>(choice: &'a String, query: &String) -> Option<Match<'a>> {
    let choice_length = choice.len() as f32;
    let query_length = query.len() as f32;

    if query_length == 0.0 { return Some(Match::new(Quality(1.0), Substring(0,0), choice)) }
    let lower_choice = choice.to_ascii_lowercase();

    match compute_match_length(&lower_choice, query) {
        Some((start, match_length)) => {
            let quality = Quality( (query_length / match_length as f32) / choice_length);
            let substring = Substring(start, start+match_length);
            Some(Match::new(quality, substring, choice))
        },
        None => None,
    }
}

fn compute_match_length(choice: &String, query: &String) -> Option<(usize, usize)> {
    if query.len() == 0 {
        return None;
    }
    let (first, rest) = query.slice_shift_char().unwrap();

    let impossible_match = choice.len() + 1;
    let mut shortest_match = impossible_match;
    let mut shortest_start = impossible_match;

    for_each_beginning(choice, first, |beginning| {
        match match_length_from(choice, rest, beginning) {
            Some(length) => {
                             shortest_match = min(length, shortest_match);
                             shortest_start = beginning;
            },
            None => {},
        };
    });

    if shortest_match == impossible_match {None} else {Some((shortest_start, shortest_match))}
}

fn for_each_beginning<F: FnMut(usize)>(choice: &String, beginning: char, mut f: F) {
    for (idx, character) in choice.chars().enumerate() {
        if character == beginning {
            f(idx);
        }
    }
}

fn match_length_from(choice: &String, query: &str, beginning: usize) -> Option<usize> {
    let mut match_index = beginning;

    for query_char in query.chars() {
       match find_first_after(choice, query_char, match_index + 1) {
           Some(n) => match_index = n,
           None => return None,
       };
    }
    Some(match_index - beginning + 1)
}

fn find_first_after(choice: &String, query: char, offset: usize) -> Option<usize> {
    choice[offset..]
        .find(query)
        .map(|index| index + offset)
}
<commit_msg>Use simpler constructor for match<commit_after>use std::cmp::min;
use std::ascii::AsciiExt;

#[derive(Clone, Debug,PartialEq)]
pub struct Quality(pub f32);

impl Quality {
    pub fn to_f32(&self) -> f32 {
        let Quality(q) = *self;
        q
    }
}

#[derive(Clone, Debug,PartialEq)]
pub struct Substring(pub usize,pub usize);

impl Substring {
    pub fn slice(&self, input: &String) -> (String, String, String) {
       let Substring(start, end) = *self;
       (input[0..start].to_string(),
        input[start..end].to_string(),
        input[end..].to_string())
    }
}

#[derive(Clone, Debug,PartialEq)]
pub struct Match<'a> {
    pub quality: Quality,
    pub range: Substring,
    pub original: &'a String,

}

impl <'a>Match<'a>{
    pub fn new(quality: Quality, range: Substring, original: &'a String) -> Match<'a> {
        Match { quality: quality, range: range, original: original }
    }

    pub fn origin_only(original: &'a String) -> Match<'a> {
        Match::new(Quality(1.0), Substring(0,0), original)
    }
}

pub fn score<'a>(choice: &'a String, query: &String) -> Option<Match<'a>> {
    let choice_length = choice.len() as f32;
    let query_length = query.len() as f32;

    if query_length == 0.0 { return Some(Match::origin_only(choice)) }
    let lower_choice = choice.to_ascii_lowercase();

    match compute_match_length(&lower_choice, query) {
        Some((start, match_length)) => {
            let quality = Quality( (query_length / match_length as f32) / choice_length);
            let substring = Substring(start, start+match_length);
            Some(Match::new(quality, substring, choice))
        },
        None => None,
    }
}

fn compute_match_length(choice: &String, query: &String) -> Option<(usize, usize)> {
    if query.len() == 0 {
        return None;
    }
    let (first, rest) = query.slice_shift_char().unwrap();

    let impossible_match = choice.len() + 1;
    let mut shortest_match = impossible_match;
    let mut shortest_start = impossible_match;

    for_each_beginning(choice, first, |beginning| {
        match match_length_from(choice, rest, beginning) {
            Some(length) => {
                             shortest_match = min(length, shortest_match);
                             shortest_start = beginning;
            },
            None => {},
        };
    });

    if shortest_match == impossible_match {None} else {Some((shortest_start, shortest_match))}
}

fn for_each_beginning<F: FnMut(usize)>(choice: &String, beginning: char, mut f: F) {
    for (idx, character) in choice.chars().enumerate() {
        if character == beginning {
            f(idx);
        }
    }
}

fn match_length_from(choice: &String, query: &str, beginning: usize) -> Option<usize> {
    let mut match_index = beginning;

    for query_char in query.chars() {
       match find_first_after(choice, query_char, match_index + 1) {
           Some(n) => match_index = n,
           None => return None,
       };
    }
    Some(match_index - beginning + 1)
}

fn find_first_after(choice: &String, query: char, offset: usize) -> Option<usize> {
    choice[offset..]
        .find(query)
        .map(|index| index + offset)
}
<|endoftext|>


<commit_before>use super::core::str::as_bytes;
use super::core::slice::iter;
use super::core::iter::Iterator;
use super::core::option::{Some, None};

static VGA_ADDRESS: uint = 0xb8000;

static VGA_WIDTH  : u16 = 80;
static VGA_HEIGHT : u16 = 24;

static mut curr_x: u16 = 0;
static mut curr_y: u16 = 0;

static mut fg_color: Color = Green;
static mut bg_color: Color = Black;

pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

fn range(lo: uint, hi: uint, it: |uint| ) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

pub fn clear_screen() {
    unsafe {
        range(0, 80*25, |i| {
            *((VGA_ADDRESS + i * 2) as *mut u16) = make_vgaentry(0, fg_color, bg_color);

        });
    }
}

pub fn backspace() {
    unsafe {
        if (curr_x == 0) {
            curr_y -= 1;
            curr_x = VGA_WIDTH - 1;
        } else {
            curr_x -= 1;
        }
        putchar(curr_x, curr_y, 0);
    }
}

pub fn putc(c: u8) {
    unsafe {
        putchar(curr_x, curr_y, c);
        curr_x += 1;
        if (curr_x > VGA_WIDTH) {
            curr_x -= VGA_WIDTH;
            curr_y += 1;
        }
    }
}

pub fn newline() {
    unsafe {
        curr_x = 0;
        curr_y += 1;
    }
}

pub fn putchar(x: u16, y: u16, c: u8) {
    if (x >= VGA_WIDTH || y >= VGA_HEIGHT) {
        return;
    }
    let idx : uint =  (y * VGA_WIDTH * 2 + x * 2) as uint;
    unsafe {
        *((VGA_ADDRESS + idx) as *mut u16) = make_vgaentry(c, fg_color, bg_color);
    }
}

fn make_vgaentry(c: u8, fg: Color, bg: Color) -> u16 {
    let color = fg as u16 | (bg as u16 << 4);
    return c as u16 | (color << 8);
}

pub fn write(x: u16, y: u16, s: &str) {
    let bytes : &[u8] = as_bytes(s);
    let mut ix = x;
    let mut iy = y;
    for b in super::core::slice::iter(bytes) {
        putchar(ix, iy, *b);
        if (ix > VGA_WIDTH * 2) {
            ix = ix - VGA_WIDTH * 2;
            iy += 1;
        }
        ix += 1;
    }
}
<commit_msg>Refactor write() function to use putc()<commit_after>use super::core::str::as_bytes;
use super::core::slice::iter;
use super::core::iter::Iterator;
use super::core::option::{Some, None};

static VGA_ADDRESS: uint = 0xb8000;

static VGA_WIDTH  : u16 = 80;
static VGA_HEIGHT : u16 = 24;

static mut curr_x: u16 = 0;
static mut curr_y: u16 = 0;

static mut fg_color: Color = Green;
static mut bg_color: Color = Black;

pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

fn range(lo: uint, hi: uint, it: |uint| ) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

pub fn clear_screen() {
    unsafe {
        range(0, 80*25, |i| {
            *((VGA_ADDRESS + i * 2) as *mut u16) = make_vgaentry(0, fg_color, bg_color);

        });
    }
}

pub fn backspace() {
    unsafe {
        if (curr_x == 0) {
            curr_y -= 1;
            curr_x = VGA_WIDTH - 1;
        } else {
            curr_x -= 1;
        }
        putchar(curr_x, curr_y, 0);
    }
}

pub fn putc(c: u8) {
    unsafe {
        putchar(curr_x, curr_y, c);
        curr_x += 1;
        if (curr_x > VGA_WIDTH) {
            curr_x -= VGA_WIDTH;
            curr_y += 1;
        }
    }
}

pub fn newline() {
    unsafe {
        curr_x = 0;
        curr_y += 1;
    }
}

pub fn putchar(x: u16, y: u16, c: u8) {
    if (x >= VGA_WIDTH || y >= VGA_HEIGHT) {
        return;
    }
    let idx : uint =  (y * VGA_WIDTH * 2 + x * 2) as uint;
    unsafe {
        *((VGA_ADDRESS + idx) as *mut u16) = make_vgaentry(c, fg_color, bg_color);
    }
}

fn make_vgaentry(c: u8, fg: Color, bg: Color) -> u16 {
    let color = fg as u16 | (bg as u16 << 4);
    return c as u16 | (color << 8);
}

pub fn write(s: &str) {
    let bytes : &[u8] = as_bytes(s);
    for b in super::core::slice::iter(bytes) {
        putc(*b);
    }
}
<|endoftext|>


<commit_before>/// A style is a collection of properties that can format a string
/// using ANSI escape codes.
#[derive(PartialEq, Clone, Copy)]
pub struct Style {

    /// The style's foreground colour, if it has one.
    pub foreground: Option<Colour>,

    /// The style's background colour, if it has one.
    pub background: Option<Colour>,

    /// Whether this style is bold.
    pub is_bold: bool,

    /// Whether this style is dimmed.
    pub is_dimmed: bool,

    /// Whether this style is italic.
    pub is_italic: bool,

    /// Whether this style is underlined.
    pub is_underline: bool,

    /// Whether this style is blinking.
    pub is_blink: bool,

    /// Whether this style has reverse colours.
    pub is_reverse: bool,

    /// Whether this style is hidden.
    pub is_hidden: bool,

    /// Whether this style is struckthrough.
    pub is_strikethrough: bool
}

impl Style {
    /// Creates a new Style with no differences.
    pub fn new() -> Style {
        Style::default()
    }

    /// Returns a Style with the bold property set.
    pub fn bold(&self) -> Style {
        Style { is_bold: true, .. *self }
    }

    /// Returns a Style with the dimmed property set.
    pub fn dimmed(&self) -> Style {
        Style { is_dimmed: true, .. *self }
    }

    /// Returns a Style with the italic property set.
    pub fn italic(&self) -> Style {
        Style { is_italic: true, .. *self }
    }

    /// Returns a Style with the underline property set.
    pub fn underline(&self) -> Style {
        Style { is_underline: true, .. *self }
    }

    /// Returns a Style with the blink property set.
    pub fn blink(&self) -> Style {
        Style { is_blink: true, .. *self }
    }

    /// Returns a Style with the reverse property set.
    pub fn reverse(&self) -> Style {
        Style { is_reverse: true, .. *self }
    }

    /// Returns a Style with the hidden property set.
    pub fn hidden(&self) -> Style {
        Style { is_hidden: true, .. *self }
    }

    /// Returns a Style with the hidden property set.
    pub fn strikethrough(&self) -> Style {
        Style { is_strikethrough: true, .. *self }
    }

    /// Returns a Style with the foreground colour property set.
    pub fn fg(&self, foreground: Colour) -> Style {
        Style { foreground: Some(foreground), .. *self }
    }

    /// Returns a Style with the background colour property set.
    pub fn on(&self, background: Colour) -> Style {
        Style { background: Some(background), .. *self }
    }

    /// Return true if this `Style` has no actual styles, and can be written
    /// without any control characters.
    pub fn is_plain(self) -> bool {
        self == Style::default()
    }
}

impl Default for Style {

    /// Returns a style with *no* properties set. Formatting text using this
    /// style returns the exact same text.
    ///
    /// ```
    /// use ansi_term::Style;
    /// assert_eq!(None,  Style::default().foreground);
    /// assert_eq!(None,  Style::default().background);
    /// assert_eq!(false, Style::default().is_bold);
    /// assert_eq!("txt", Style::default().paint("txt").to_string());
    /// ```
    fn default() -> Style {
        Style {
            foreground: None,
            background: None,
            is_bold: false,
            is_dimmed: false,
            is_italic: false,
            is_underline: false,
            is_blink: false,
            is_reverse: false,
            is_hidden: false,
            is_strikethrough: false,
        }
    }
}

// ---- colours ----

/// A colour is one specific type of ANSI escape code, and can refer
/// to either the foreground or background colour.
///
/// These use the standard numeric sequences.
/// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum Colour {

    /// Colour #0 (foreground code `30`, background code `40`).
    ///
    /// This is not necessarily the background colour, and using it as one may
    /// render the text hard to read on terminals with dark backgrounds.
    Black,

    /// Colour #1 (foreground code `31`, background code `41`).
    Red,

    /// Colour #2 (foreground code `32`, background code `42`).
    Green,

    /// Colour #3 (foreground code `33`, background code `43`).
    Yellow,

    /// Colour #4 (foreground code `34`, background code `44`).
    Blue,

    /// Colour #5 (foreground code `35`, background code `45`).
    Purple,

    /// Colour #6 (foreground code `36`, background code `46`).
    Cyan,

    /// Colour #7 (foreground code `37`, background code `47`).
    ///
    /// As above, this is not necessarily the foreground colour, and may be
    /// hard to read on terminals with light backgrounds.
    White,

    /// A colour number from 0 to 255, for use in 256-colour terminal
    /// environments.
    ///
    /// - Colours 0 to 7 are the `Black` to `White` variants respectively.
    ///   These colours can usually be changed in the terminal emulator.
    /// - Colours 8 to 15 are brighter versions of the eight colours above.
    ///   These can also usually be changed in the terminal emulator, or it
    ///   could be configured to use the original colours and show the text in
    ///   bold instead. It varies depending on the program.
    /// - Colours 16 to 231 contain several palettes of bright colours,
    ///   arranged in six squares measuring six by six each.
    /// - Colours 232 to 255 are shades of grey from black to white.
    ///
    /// It might make more sense to look at a [colour chart][cc].
    /// [cc]: https://upload.wikimedia.org/wikipedia/en/1/15/Xterm_256color_chart.svg
    Fixed(u8),

    /// A 24-bit RGB color, as specified by ISO-8613-3.
    RGB(u8, u8, u8),
}

impl Colour {
    /// Return a Style with the foreground colour set to this colour.
    pub fn normal(self) -> Style {
        Style { foreground: Some(self), .. Style::default() }
    }

    /// Returns a Style with the bold property set.
    pub fn bold(self) -> Style {
        Style { foreground: Some(self), is_bold: true, .. Style::default() }
    }

    /// Returns a Style with the dimmed property set.
    pub fn dimmed(self) -> Style {
        Style { foreground: Some(self), is_dimmed: true, .. Style::default() }
    }

    /// Returns a Style with the italic property set.
    pub fn italic(self) -> Style {
        Style { foreground: Some(self), is_italic: true, .. Style::default() }
    }

    /// Returns a Style with the underline property set.
    pub fn underline(self) -> Style {
        Style { foreground: Some(self), is_underline: true, .. Style::default() }
    }

    /// Returns a Style with the blink property set.
    pub fn blink(self) -> Style {
        Style { foreground: Some(self), is_blink: true, .. Style::default() }
    }

    /// Returns a Style with the reverse property set.
    pub fn reverse(self) -> Style {
        Style { foreground: Some(self), is_reverse: true, .. Style::default() }
    }

    /// Returns a Style with the hidden property set.
    pub fn hidden(self) -> Style {
        Style { foreground: Some(self), is_hidden: true, .. Style::default() }
    }

    /// Returns a Style with the strikethrough property set.
    pub fn strikethrough(self) -> Style {
        Style { foreground: Some(self), is_strikethrough: true, .. Style::default() }
    }

    /// Returns a Style with the background colour property set.
    pub fn on(self, background: Colour) -> Style {
        Style { foreground: Some(self), background: Some(background), .. Style::default() }
    }
}

impl From<Colour> for Style {

    /// You can turn a `Colour` into a `Style` with the foreground colour set
    /// with the `From` trait.
    ///
    /// ```
    /// use ansi_term::{Style, Colour};
    /// let green_foreground = Style::default().fg(Colour::Green);
    /// assert_eq!(green_foreground, Colour::Green.normal());
    /// assert_eq!(green_foreground, Colour::Green.into());
    /// assert_eq!(green_foreground, Style::from(Colour::Green));
    /// ```
    fn from(colour: Colour) -> Style {
        colour.normal()
    }
}
<commit_msg>Fix markdown warning with newer Rust.<commit_after>/// A style is a collection of properties that can format a string
/// using ANSI escape codes.
#[derive(PartialEq, Clone, Copy)]
pub struct Style {

    /// The style's foreground colour, if it has one.
    pub foreground: Option<Colour>,

    /// The style's background colour, if it has one.
    pub background: Option<Colour>,

    /// Whether this style is bold.
    pub is_bold: bool,

    /// Whether this style is dimmed.
    pub is_dimmed: bool,

    /// Whether this style is italic.
    pub is_italic: bool,

    /// Whether this style is underlined.
    pub is_underline: bool,

    /// Whether this style is blinking.
    pub is_blink: bool,

    /// Whether this style has reverse colours.
    pub is_reverse: bool,

    /// Whether this style is hidden.
    pub is_hidden: bool,

    /// Whether this style is struckthrough.
    pub is_strikethrough: bool
}

impl Style {
    /// Creates a new Style with no differences.
    pub fn new() -> Style {
        Style::default()
    }

    /// Returns a Style with the bold property set.
    pub fn bold(&self) -> Style {
        Style { is_bold: true, .. *self }
    }

    /// Returns a Style with the dimmed property set.
    pub fn dimmed(&self) -> Style {
        Style { is_dimmed: true, .. *self }
    }

    /// Returns a Style with the italic property set.
    pub fn italic(&self) -> Style {
        Style { is_italic: true, .. *self }
    }

    /// Returns a Style with the underline property set.
    pub fn underline(&self) -> Style {
        Style { is_underline: true, .. *self }
    }

    /// Returns a Style with the blink property set.
    pub fn blink(&self) -> Style {
        Style { is_blink: true, .. *self }
    }

    /// Returns a Style with the reverse property set.
    pub fn reverse(&self) -> Style {
        Style { is_reverse: true, .. *self }
    }

    /// Returns a Style with the hidden property set.
    pub fn hidden(&self) -> Style {
        Style { is_hidden: true, .. *self }
    }

    /// Returns a Style with the hidden property set.
    pub fn strikethrough(&self) -> Style {
        Style { is_strikethrough: true, .. *self }
    }

    /// Returns a Style with the foreground colour property set.
    pub fn fg(&self, foreground: Colour) -> Style {
        Style { foreground: Some(foreground), .. *self }
    }

    /// Returns a Style with the background colour property set.
    pub fn on(&self, background: Colour) -> Style {
        Style { background: Some(background), .. *self }
    }

    /// Return true if this `Style` has no actual styles, and can be written
    /// without any control characters.
    pub fn is_plain(self) -> bool {
        self == Style::default()
    }
}

impl Default for Style {

    /// Returns a style with *no* properties set. Formatting text using this
    /// style returns the exact same text.
    ///
    /// ```
    /// use ansi_term::Style;
    /// assert_eq!(None,  Style::default().foreground);
    /// assert_eq!(None,  Style::default().background);
    /// assert_eq!(false, Style::default().is_bold);
    /// assert_eq!("txt", Style::default().paint("txt").to_string());
    /// ```
    fn default() -> Style {
        Style {
            foreground: None,
            background: None,
            is_bold: false,
            is_dimmed: false,
            is_italic: false,
            is_underline: false,
            is_blink: false,
            is_reverse: false,
            is_hidden: false,
            is_strikethrough: false,
        }
    }
}

// ---- colours ----

/// A colour is one specific type of ANSI escape code, and can refer
/// to either the foreground or background colour.
///
/// These use the standard numeric sequences.
/// See <http://invisible-island.net/xterm/ctlseqs/ctlseqs.html>
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum Colour {

    /// Colour #0 (foreground code `30`, background code `40`).
    ///
    /// This is not necessarily the background colour, and using it as one may
    /// render the text hard to read on terminals with dark backgrounds.
    Black,

    /// Colour #1 (foreground code `31`, background code `41`).
    Red,

    /// Colour #2 (foreground code `32`, background code `42`).
    Green,

    /// Colour #3 (foreground code `33`, background code `43`).
    Yellow,

    /// Colour #4 (foreground code `34`, background code `44`).
    Blue,

    /// Colour #5 (foreground code `35`, background code `45`).
    Purple,

    /// Colour #6 (foreground code `36`, background code `46`).
    Cyan,

    /// Colour #7 (foreground code `37`, background code `47`).
    ///
    /// As above, this is not necessarily the foreground colour, and may be
    /// hard to read on terminals with light backgrounds.
    White,

    /// A colour number from 0 to 255, for use in 256-colour terminal
    /// environments.
    ///
    /// - Colours 0 to 7 are the `Black` to `White` variants respectively.
    ///   These colours can usually be changed in the terminal emulator.
    /// - Colours 8 to 15 are brighter versions of the eight colours above.
    ///   These can also usually be changed in the terminal emulator, or it
    ///   could be configured to use the original colours and show the text in
    ///   bold instead. It varies depending on the program.
    /// - Colours 16 to 231 contain several palettes of bright colours,
    ///   arranged in six squares measuring six by six each.
    /// - Colours 232 to 255 are shades of grey from black to white.
    ///
    /// It might make more sense to look at a [colour chart][cc].
    ///
    /// [cc]: https://upload.wikimedia.org/wikipedia/en/1/15/Xterm_256color_chart.svg
    Fixed(u8),

    /// A 24-bit RGB color, as specified by ISO-8613-3.
    RGB(u8, u8, u8),
}

impl Colour {
    /// Return a Style with the foreground colour set to this colour.
    pub fn normal(self) -> Style {
        Style { foreground: Some(self), .. Style::default() }
    }

    /// Returns a Style with the bold property set.
    pub fn bold(self) -> Style {
        Style { foreground: Some(self), is_bold: true, .. Style::default() }
    }

    /// Returns a Style with the dimmed property set.
    pub fn dimmed(self) -> Style {
        Style { foreground: Some(self), is_dimmed: true, .. Style::default() }
    }

    /// Returns a Style with the italic property set.
    pub fn italic(self) -> Style {
        Style { foreground: Some(self), is_italic: true, .. Style::default() }
    }

    /// Returns a Style with the underline property set.
    pub fn underline(self) -> Style {
        Style { foreground: Some(self), is_underline: true, .. Style::default() }
    }

    /// Returns a Style with the blink property set.
    pub fn blink(self) -> Style {
        Style { foreground: Some(self), is_blink: true, .. Style::default() }
    }

    /// Returns a Style with the reverse property set.
    pub fn reverse(self) -> Style {
        Style { foreground: Some(self), is_reverse: true, .. Style::default() }
    }

    /// Returns a Style with the hidden property set.
    pub fn hidden(self) -> Style {
        Style { foreground: Some(self), is_hidden: true, .. Style::default() }
    }

    /// Returns a Style with the strikethrough property set.
    pub fn strikethrough(self) -> Style {
        Style { foreground: Some(self), is_strikethrough: true, .. Style::default() }
    }

    /// Returns a Style with the background colour property set.
    pub fn on(self, background: Colour) -> Style {
        Style { foreground: Some(self), background: Some(background), .. Style::default() }
    }
}

impl From<Colour> for Style {

    /// You can turn a `Colour` into a `Style` with the foreground colour set
    /// with the `From` trait.
    ///
    /// ```
    /// use ansi_term::{Style, Colour};
    /// let green_foreground = Style::default().fg(Colour::Green);
    /// assert_eq!(green_foreground, Colour::Green.normal());
    /// assert_eq!(green_foreground, Colour::Green.into());
    /// assert_eq!(green_foreground, Style::from(Colour::Green));
    /// ```
    fn from(colour: Colour) -> Style {
        colour.normal()
    }
}
<|endoftext|>