<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use mimir;
use mimir::Members;
use std::path::Path;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let osm2mimir = Path::new(env!("OUT_DIR"))
        .join("../../../osm2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-way".into(),
            "--import-admin".into(),
            "--import-poi".into(),
            "--level=8".into(),
            "--level=7".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    check_results(es_wrapper, "btreemap backend");
}

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test_sqlite(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let osm2mimir = Path::new(env!("OUT_DIR"))
        .join("../../../osm2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-way".into(),
            "--import-admin".into(),
            "--import-poi".into(),
            "--level=8".into(),
            "--level=7".into(),
            "--db-file=test-db.sqlite3".into(),
            "--db-buffer-size=1".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    check_results(es_wrapper, "sqlite backend");
}

fn check_results(es_wrapper: crate::ElasticSearchWrapper<'_>, test_name: &str) {
    // Test: Import of Admin
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Livry-sur-Seine", |_| true)
        .collect();
    assert_eq!(res.len(), 5, "{}", test_name);

    let has_boundary = |res: &Vec<mimir::Place>, is_admin: bool| {
        res.iter()
            .filter(|place| place.is_admin() == is_admin)
            .flat_map(|a| a.admins())
            .all(|a| a.boundary.clone().map_or(false, |b| !b.0.is_empty()))
    };
    // Admins have boundaries
    assert!(has_boundary(&res, true), "{}", test_name);

    // Others places than Admin don't
    assert!(!has_boundary(&res, false), "{}", test_name);

    assert!(res.iter().any(|r| r.is_admin()), "{}", test_name);

    // Test that Créteil (admin_level 7) is not treated as a city (level 8)
    let admin_regions: Vec<_> = es_wrapper
        .search_and_filter("label:Créteil", |_| true)
        .collect();
    assert!(!admin_regions.is_empty(), "{}", test_name);
    if let mimir::Place::Admin(ref creteil) = admin_regions[0] {
        assert_eq!(creteil.name, "Créteil", "{}", test_name);
        assert_eq!(creteil.level, 7, "{}", test_name);
        assert!(creteil.zone_type.is_none(), "{}", test_name);
    } else {
        panic!("creteil should be an admin");
    }

    // Test: search for "Rue des Près"
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Rue des Près", |_| true)
        .collect();
    assert!(!res.is_empty(), "{}", test_name);
    assert!(res[0].is_street(), "{}", test_name);
    // The first hit should be "Rue des Près"
    assert_eq!(
        res[0].label(),
        "Rue des Près (Livry-sur-Seine)",
        "{}",
        test_name
    );

    // And there should be only ONE "Rue des Près"
    assert_eq!(
        res.iter()
            .filter(|place| place.is_street() && place.label() == "Rue des Près (Livry-sur-Seine)")
            .count(),
        1,
        "{}",
        test_name
    );

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let place_filter = |place: &mimir::Place| {
        place.is_street()
            && place.label() == "Rue du Four à Chaux (Livry-sur-Seine)"
            && place
                .admins()
                .first()
                .map(|admin| admin.label() == "Livry-sur-Seine (77000)")
                .unwrap_or(false)
    };
    // As we merge all ways with same name and of the same admin(level=city_level)
    // Here we have only one way
    let four_a_chaux_street: Vec<mimir::Place> = es_wrapper
        .search_and_filter("label:Rue du Four à Chaux (Livry-sur-Seine)", place_filter)
        .collect();

    let nb = four_a_chaux_street.len();
    assert_eq!(nb, 1, "{}", test_name);

    // Test the id is the min(=40812939) of all the ways composing the street
    assert!(
        four_a_chaux_street[0].address().map_or(false, |a| {
            if let mimir::Address::Street(s) = a {
                s.id == "street:osm:way:40812939"
            } else {
                false
            }
        }),
        "{}",
        test_name
    );

    // Test: Streets having the same label in different cities
    let place_filter = |place: &mimir::Place| {
        place.is_street()
            && place.label() == "Rue du Port (Melun)"
            && place
                .admins()
                .first()
                .map(|admin| admin.label() == "Melun (77000-CP77001)")
                .unwrap_or(false)
    };
    let nb = es_wrapper
        .search_and_filter("label:Rue du Port (Melun)", place_filter)
        .count();
    assert_eq!(nb, 1, "{}", test_name);

    // Test: Street admin is based on a middle node
    // (instead of the first node which is located outside Melun)
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Rue Marcel Houdet", |_| true)
        .collect();
    assert!(!res.len() != 0, "{}", test_name);
    assert_eq!(res[0].label(), "Rue Marcel Houdet (Melun)", "{}", test_name);
    assert!(res[0]
        .admins()
        .iter()
        .filter(|a| a.is_city())
        .any(|a| a.name == "Melun"));

    // Test: search Pois by label
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Le-Mée-sur-Seine Courtilleraies", |_| true)
        .collect();
    assert!(!res.is_empty(), "{}", test_name);

    let poi_type_post_office = "poi_type:amenity:post_office";
    assert!(
        res.iter().any(|r| r
            .poi()
            .map_or(false, |poi| poi.poi_type.id == poi_type_post_office)),
        "{}",
        test_name
    );

    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Melun Rp", |_| true)
        .collect();
    assert!(!res.is_empty(), "{}", test_name);
    assert!(
        res.iter().any(|r| r
            .poi()
            .map_or(false, |poi| poi.poi_type.id == poi_type_post_office)),
        "{}",
        test_name
    );

    // Test: Certain kind of highways should not be indexed.
    // node id 451237947 is a 'bus_stop', and should not be found.
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Grand Châtelet", |_| true)
        .collect();
    assert!(res.is_empty(), "{}", test_name);
}
<commit_msg>Fix osm2mimir test<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use mimir;
use mimir::Members;
use std::path::Path;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let osm2mimir = Path::new(env!("OUT_DIR"))
        .join("../../../osm2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-way".into(),
            "--import-admin".into(),
            "--import-poi".into(),
            "--level=8".into(),
            "--level=7".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    check_results(es_wrapper, "btreemap backend");
}

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test_sqlite(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let osm2mimir = Path::new(env!("OUT_DIR"))
        .join("../../../osm2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-way".into(),
            "--import-admin".into(),
            "--import-poi".into(),
            "--level=8".into(),
            "--level=7".into(),
            #[cfg(feature = "db-storage")]
            "--db-file=test-db.sqlite3".into(),
            "--db-buffer-size=1".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    check_results(es_wrapper, "sqlite backend");
}

fn check_results(es_wrapper: crate::ElasticSearchWrapper<'_>, test_name: &str) {
    // Test: Import of Admin
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Livry-sur-Seine", |_| true)
        .collect();
    assert_eq!(res.len(), 5, "{}", test_name);

    let has_boundary = |res: &Vec<mimir::Place>, is_admin: bool| {
        res.iter()
            .filter(|place| place.is_admin() == is_admin)
            .flat_map(|a| a.admins())
            .all(|a| a.boundary.clone().map_or(false, |b| !b.0.is_empty()))
    };
    // Admins have boundaries
    assert!(has_boundary(&res, true), "{}", test_name);

    // Others places than Admin don't
    assert!(!has_boundary(&res, false), "{}", test_name);

    assert!(res.iter().any(|r| r.is_admin()), "{}", test_name);

    // Test that Créteil (admin_level 7) is not treated as a city (level 8)
    let admin_regions: Vec<_> = es_wrapper
        .search_and_filter("label:Créteil", |_| true)
        .collect();
    assert!(!admin_regions.is_empty(), "{}", test_name);
    if let mimir::Place::Admin(ref creteil) = admin_regions[0] {
        assert_eq!(creteil.name, "Créteil", "{}", test_name);
        assert_eq!(creteil.level, 7, "{}", test_name);
        assert!(creteil.zone_type.is_none(), "{}", test_name);
    } else {
        panic!("creteil should be an admin");
    }

    // Test: search for "Rue des Près"
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Rue des Près", |_| true)
        .collect();
    assert!(!res.is_empty(), "{}", test_name);
    assert!(res[0].is_street(), "{}", test_name);
    // The first hit should be "Rue des Près"
    assert_eq!(
        res[0].label(),
        "Rue des Près (Livry-sur-Seine)",
        "{}",
        test_name
    );

    // And there should be only ONE "Rue des Près"
    assert_eq!(
        res.iter()
            .filter(|place| place.is_street() && place.label() == "Rue des Près (Livry-sur-Seine)")
            .count(),
        1,
        "{}",
        test_name
    );

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let place_filter = |place: &mimir::Place| {
        place.is_street()
            && place.label() == "Rue du Four à Chaux (Livry-sur-Seine)"
            && place
                .admins()
                .first()
                .map(|admin| admin.label() == "Livry-sur-Seine (77000)")
                .unwrap_or(false)
    };
    // As we merge all ways with same name and of the same admin(level=city_level)
    // Here we have only one way
    let four_a_chaux_street: Vec<mimir::Place> = es_wrapper
        .search_and_filter("label:Rue du Four à Chaux (Livry-sur-Seine)", place_filter)
        .collect();

    let nb = four_a_chaux_street.len();
    assert_eq!(nb, 1, "{}", test_name);

    // Test the id is the min(=40812939) of all the ways composing the street
    assert!(
        four_a_chaux_street[0].address().map_or(false, |a| {
            if let mimir::Address::Street(s) = a {
                s.id == "street:osm:way:40812939"
            } else {
                false
            }
        }),
        "{}",
        test_name
    );

    // Test: Streets having the same label in different cities
    let place_filter = |place: &mimir::Place| {
        place.is_street()
            && place.label() == "Rue du Port (Melun)"
            && place
                .admins()
                .first()
                .map(|admin| admin.label() == "Melun (77000-CP77001)")
                .unwrap_or(false)
    };
    let nb = es_wrapper
        .search_and_filter("label:Rue du Port (Melun)", place_filter)
        .count();
    assert_eq!(nb, 1, "{}", test_name);

    // Test: Street admin is based on a middle node
    // (instead of the first node which is located outside Melun)
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Rue Marcel Houdet", |_| true)
        .collect();
    assert!(!res.len() != 0, "{}", test_name);
    assert_eq!(res[0].label(), "Rue Marcel Houdet (Melun)", "{}", test_name);
    assert!(res[0]
        .admins()
        .iter()
        .filter(|a| a.is_city())
        .any(|a| a.name == "Melun"));

    // Test: search Pois by label
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Le-Mée-sur-Seine Courtilleraies", |_| true)
        .collect();
    assert!(!res.is_empty(), "{}", test_name);

    let poi_type_post_office = "poi_type:amenity:post_office";
    assert!(
        res.iter().any(|r| r
            .poi()
            .map_or(false, |poi| poi.poi_type.id == poi_type_post_office)),
        "{}",
        test_name
    );

    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Melun Rp", |_| true)
        .collect();
    assert!(!res.is_empty(), "{}", test_name);
    assert!(
        res.iter().any(|r| r
            .poi()
            .map_or(false, |poi| poi.poi_type.id == poi_type_post_office)),
        "{}",
        test_name
    );

    // Test: Certain kind of highways should not be indexed.
    // node id 451237947 is a 'bus_stop', and should not be found.
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Grand Châtelet", |_| true)
        .collect();
    assert!(res.is_empty(), "{}", test_name);
}
<|endoftext|>


<commit_before>use std::collections;
use std::vec;

use protobuf;
use serde;

use descriptor;
use error;
use value;

pub struct Deserializer<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::MessageDescriptor,
    input: &'a mut protobuf::CodedInputStream<'a>,
}

struct MessageVisitor<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::MessageDescriptor,
    fields: collections::btree_map::IntoIter<i32, value::Field>,
    field: Option<(&'a descriptor::FieldDescriptor, value::Field)>,
}

struct MessageKeyDeserializer<'a> {
    descriptor: &'a descriptor::FieldDescriptor,
}

struct MessageFieldDeserializer<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::FieldDescriptor,
    field: Option<value::Field>,
}

struct RepeatedValueVisitor<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::FieldDescriptor,
    values: vec::IntoIter<value::Value>,
}

struct ValueDeserializer<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::FieldDescriptor,
    value: Option<value::Value>,
}

impl<'a> Deserializer<'a> {
    pub fn new(descriptors: &'a descriptor::Descriptors,
               descriptor: &'a descriptor::MessageDescriptor,
               input: &'a mut protobuf::CodedInputStream<'a>)
               -> Deserializer<'a> {
        Deserializer {
            descriptors: descriptors,
            descriptor: descriptor,
            input: input,
        }
    }

    pub fn for_named_message(descriptors: &'a descriptor::Descriptors,
                             message_name: &str,
                             input: &'a mut protobuf::CodedInputStream<'a>)
                             -> error::Result<Deserializer<'a>> {
        if let Some(message) = descriptors.message_by_name(message_name) {
            Ok(Deserializer::new(descriptors, message, input))
        } else {
            Err(error::Error::UnknownMessage(message_name.to_owned()))
        }
    }
}

impl<'a> serde::Deserializer for Deserializer<'a> {
    type Error = error::Error;

    #[inline]
    fn deserialize<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error>
        where V: serde::de::Visitor
    {
        let mut message = value::Message::new(self.descriptor);
        try!(message.merge_from(self.descriptors, self.descriptor, self.input));
        visitor.visit_map(MessageVisitor::new(self.descriptors, self.descriptor, message))
    }
}

impl<'a> MessageVisitor<'a> {
    fn new(descriptors: &'a descriptor::Descriptors,
           descriptor: &'a descriptor::MessageDescriptor,
           value: value::Message)
           -> MessageVisitor<'a> {
        MessageVisitor {
            descriptors: descriptors,
            descriptor: descriptor,
            fields: value.fields.into_iter(),
            field: None,
        }
    }
}

impl<'a> serde::de::MapVisitor for MessageVisitor<'a> {
    type Error = error::Error;

    fn visit_key<K>(&mut self) -> error::Result<Option<K>>
        where K: serde::Deserialize
    {
        if let Some((k, v)) = self.fields.next() {
            let descriptor = self.descriptor.field_by_number(k).expect("Lost track of field");
            let key = try!(K::deserialize(&mut MessageKeyDeserializer::new(descriptor)));
            self.field = Some((descriptor, v));
            Ok(Some(key))
        } else {
            Ok(None)
        }
    }

    fn visit_value<V>(&mut self) -> error::Result<V>
        where V: serde::Deserialize
    {
        let (descriptor, field) = self.field
                                      .take()
                                      .expect("visit_value was called before visit_key");

        Ok(try!(V::deserialize(&mut MessageFieldDeserializer::new(self.descriptors,
                                                                  descriptor,
                                                                  field))))
    }

    fn end(&mut self) -> error::Result<()> {
        Ok(())
    }
}

impl<'a> MessageKeyDeserializer<'a> {
    fn new(descriptor: &'a descriptor::FieldDescriptor) -> MessageKeyDeserializer<'a> {
        MessageKeyDeserializer { descriptor: descriptor }
    }
}

impl<'a> serde::Deserializer for MessageKeyDeserializer<'a> {
    type Error = error::Error;

    fn deserialize<V>(&mut self, mut visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        visitor.visit_str(self.descriptor.name())
    }

    fn deserialize_i64<V>(&mut self, mut visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        visitor.visit_i32(self.descriptor.number())
    }

    fn deserialize_u64<V>(&mut self, mut visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        visitor.visit_u32(self.descriptor.number() as u32)
    }
}

impl<'a> MessageFieldDeserializer<'a> {
    fn new(descriptors: &'a descriptor::Descriptors,
           descriptor: &'a descriptor::FieldDescriptor,
           field: value::Field)
           -> MessageFieldDeserializer<'a> {
        MessageFieldDeserializer {
            descriptors: descriptors,
            descriptor: descriptor,
            field: Some(field),
        }
    }
}

impl<'a> serde::Deserializer for MessageFieldDeserializer<'a> {
    type Error = error::Error;

    fn deserialize<V>(&mut self, mut visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        let ds = self.descriptors;
        let d = self.descriptor;
        match self.field.take() {
            Some(value::Field::Singular(None)) => {
                if d.field_label() == descriptor::FieldLabel::Optional {
                    visitor.visit_none()
                } else {
                    visitor.visit_unit()
                }
            },
            Some(value::Field::Singular(Some(v))) => {
                if d.field_label() == descriptor::FieldLabel::Optional {
                    visitor.visit_some(&mut ValueDeserializer::new(ds, d, v))
                } else {
                    visit_value(ds, d, v, visitor)
                }
            },
            Some(value::Field::Repeated(vs)) => {
                visitor.visit_seq(&mut RepeatedValueVisitor::new(ds, d, vs.into_iter()))
            },
            None => Err(serde::de::Error::end_of_stream()),
        }
    }
}

impl<'a> RepeatedValueVisitor<'a> {
    fn new(descriptors: &'a descriptor::Descriptors,
           descriptor: &'a descriptor::FieldDescriptor,
           values: vec::IntoIter<value::Value>)
           -> RepeatedValueVisitor<'a> {
        RepeatedValueVisitor {
            descriptors: descriptors,
            descriptor: descriptor,
            values: values,
        }
    }
}

impl<'a> serde::de::SeqVisitor for RepeatedValueVisitor<'a> {
    type Error = error::Error;

    fn visit<A>(&mut self) -> error::Result<Option<A>>
        where A: serde::de::Deserialize
    {
        let ds = self.descriptors;
        let d = self.descriptor;
        match self.values.next() {
            Some(v) => Ok(Some(try!(A::deserialize(&mut ValueDeserializer::new(ds, d, v))))),
            None => Ok(None),
        }
    }

    fn end(&mut self) -> error::Result<()> {
        let len = self.values.size_hint().0;
        if len == 0 { Ok(()) } else { Err(serde::de::Error::invalid_length(len)) }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.values.size_hint()
    }
}

impl<'a> ValueDeserializer<'a> {
    fn new(descriptors: &'a descriptor::Descriptors,
           descriptor: &'a descriptor::FieldDescriptor,
           value: value::Value)
           -> ValueDeserializer<'a> {
        ValueDeserializer {
            descriptors: descriptors,
            descriptor: descriptor,
            value: Some(value),
        }
    }
}

impl<'a> serde::Deserializer for ValueDeserializer<'a> {
    type Error = error::Error;

    fn deserialize<V>(&mut self, visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        match self.value.take() {
            Some(value) => visit_value(self.descriptors, self.descriptor, value, visitor),
            None => Err(serde::de::Error::end_of_stream()),
        }
    }
}

fn visit_value<V>(descriptors: &descriptor::Descriptors,
                  descriptor: &descriptor::FieldDescriptor,
                  value: value::Value,
                  mut visitor: V)
                  -> error::Result<V::Value>
    where V: serde::de::Visitor
{
    match value {
        value::Value::Bool(v) => visitor.visit_bool(v),
        value::Value::I32(v) => visitor.visit_i32(v),
        value::Value::I64(v) => visitor.visit_i64(v),
        value::Value::U32(v) => visitor.visit_u32(v),
        value::Value::U64(v) => visitor.visit_u64(v),
        value::Value::F32(v) => visitor.visit_f32(v),
        value::Value::F64(v) => visitor.visit_f64(v),
        value::Value::Bytes(v) => visitor.visit_byte_buf(v),
        value::Value::String(v) => visitor.visit_string(v),
        value::Value::Message(m) => {
            if let descriptor::FieldType::Message(d) = descriptor.field_type(descriptors) {
                visitor.visit_map(MessageVisitor::new(descriptors, d, m))
            } else {
                panic!("A field with a message value doesn't have a message type!")
            }
        },
        value::Value::Enum(e) => {
            if let descriptor::FieldType::Enum(d) = descriptor.field_type(descriptors) {
                visitor.visit_str(d.value_by_number(e).unwrap().name())
            } else {
                panic!("A field with an enum value doesn't have an enum type!")
            }
        },
    }
}
<commit_msg>Stop parsing protobuf at eof<commit_after>use std::collections;
use std::vec;

use protobuf;
use serde;

use descriptor;
use error;
use value;

pub struct Deserializer<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::MessageDescriptor,
    input: &'a mut protobuf::CodedInputStream<'a>,
}

struct MessageVisitor<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::MessageDescriptor,
    fields: collections::btree_map::IntoIter<i32, value::Field>,
    field: Option<(&'a descriptor::FieldDescriptor, value::Field)>,
}

struct MessageKeyDeserializer<'a> {
    descriptor: &'a descriptor::FieldDescriptor,
}

struct MessageFieldDeserializer<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::FieldDescriptor,
    field: Option<value::Field>,
}

struct RepeatedValueVisitor<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::FieldDescriptor,
    values: vec::IntoIter<value::Value>,
}

struct ValueDeserializer<'a> {
    descriptors: &'a descriptor::Descriptors,
    descriptor: &'a descriptor::FieldDescriptor,
    value: Option<value::Value>,
}

impl<'a> Deserializer<'a> {
    pub fn new(descriptors: &'a descriptor::Descriptors,
               descriptor: &'a descriptor::MessageDescriptor,
               input: &'a mut protobuf::CodedInputStream<'a>)
               -> Deserializer<'a> {
        Deserializer {
            descriptors: descriptors,
            descriptor: descriptor,
            input: input,
        }
    }

    pub fn for_named_message(descriptors: &'a descriptor::Descriptors,
                             message_name: &str,
                             input: &'a mut protobuf::CodedInputStream<'a>)
                             -> error::Result<Deserializer<'a>> {
        if let Some(message) = descriptors.message_by_name(message_name) {
            Ok(Deserializer::new(descriptors, message, input))
        } else {
            Err(error::Error::UnknownMessage(message_name.to_owned()))
        }
    }
}

impl<'a> serde::Deserializer for Deserializer<'a> {
    type Error = error::Error;

    #[inline]
    fn deserialize<V>(&mut self, mut visitor: V) -> Result<V::Value, Self::Error>
        where V: serde::de::Visitor
    {
        if try!(self.input.eof()) {
            Err(serde::de::Error::end_of_stream())
        } else {
            let mut message = value::Message::new(self.descriptor);
            try!(message.merge_from(self.descriptors, self.descriptor, self.input));
            visitor.visit_map(MessageVisitor::new(self.descriptors, self.descriptor, message))
        }
    }
}

impl<'a> MessageVisitor<'a> {
    fn new(descriptors: &'a descriptor::Descriptors,
           descriptor: &'a descriptor::MessageDescriptor,
           value: value::Message)
           -> MessageVisitor<'a> {
        MessageVisitor {
            descriptors: descriptors,
            descriptor: descriptor,
            fields: value.fields.into_iter(),
            field: None,
        }
    }
}

impl<'a> serde::de::MapVisitor for MessageVisitor<'a> {
    type Error = error::Error;

    fn visit_key<K>(&mut self) -> error::Result<Option<K>>
        where K: serde::Deserialize
    {
        if let Some((k, v)) = self.fields.next() {
            let descriptor = self.descriptor.field_by_number(k).expect("Lost track of field");
            let key = try!(K::deserialize(&mut MessageKeyDeserializer::new(descriptor)));
            self.field = Some((descriptor, v));
            Ok(Some(key))
        } else {
            Ok(None)
        }
    }

    fn visit_value<V>(&mut self) -> error::Result<V>
        where V: serde::Deserialize
    {
        let (descriptor, field) = self.field
                                      .take()
                                      .expect("visit_value was called before visit_key");

        Ok(try!(V::deserialize(&mut MessageFieldDeserializer::new(self.descriptors,
                                                                  descriptor,
                                                                  field))))
    }

    fn end(&mut self) -> error::Result<()> {
        Ok(())
    }
}

impl<'a> MessageKeyDeserializer<'a> {
    fn new(descriptor: &'a descriptor::FieldDescriptor) -> MessageKeyDeserializer<'a> {
        MessageKeyDeserializer { descriptor: descriptor }
    }
}

impl<'a> serde::Deserializer for MessageKeyDeserializer<'a> {
    type Error = error::Error;

    fn deserialize<V>(&mut self, mut visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        visitor.visit_str(self.descriptor.name())
    }

    fn deserialize_i64<V>(&mut self, mut visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        visitor.visit_i32(self.descriptor.number())
    }

    fn deserialize_u64<V>(&mut self, mut visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        visitor.visit_u32(self.descriptor.number() as u32)
    }
}

impl<'a> MessageFieldDeserializer<'a> {
    fn new(descriptors: &'a descriptor::Descriptors,
           descriptor: &'a descriptor::FieldDescriptor,
           field: value::Field)
           -> MessageFieldDeserializer<'a> {
        MessageFieldDeserializer {
            descriptors: descriptors,
            descriptor: descriptor,
            field: Some(field),
        }
    }
}

impl<'a> serde::Deserializer for MessageFieldDeserializer<'a> {
    type Error = error::Error;

    fn deserialize<V>(&mut self, mut visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        let ds = self.descriptors;
        let d = self.descriptor;
        match self.field.take() {
            Some(value::Field::Singular(None)) => {
                if d.field_label() == descriptor::FieldLabel::Optional {
                    visitor.visit_none()
                } else {
                    visitor.visit_unit()
                }
            },
            Some(value::Field::Singular(Some(v))) => {
                if d.field_label() == descriptor::FieldLabel::Optional {
                    visitor.visit_some(&mut ValueDeserializer::new(ds, d, v))
                } else {
                    visit_value(ds, d, v, visitor)
                }
            },
            Some(value::Field::Repeated(vs)) => {
                visitor.visit_seq(&mut RepeatedValueVisitor::new(ds, d, vs.into_iter()))
            },
            None => Err(serde::de::Error::end_of_stream()),
        }
    }
}

impl<'a> RepeatedValueVisitor<'a> {
    fn new(descriptors: &'a descriptor::Descriptors,
           descriptor: &'a descriptor::FieldDescriptor,
           values: vec::IntoIter<value::Value>)
           -> RepeatedValueVisitor<'a> {
        RepeatedValueVisitor {
            descriptors: descriptors,
            descriptor: descriptor,
            values: values,
        }
    }
}

impl<'a> serde::de::SeqVisitor for RepeatedValueVisitor<'a> {
    type Error = error::Error;

    fn visit<A>(&mut self) -> error::Result<Option<A>>
        where A: serde::de::Deserialize
    {
        let ds = self.descriptors;
        let d = self.descriptor;
        match self.values.next() {
            Some(v) => Ok(Some(try!(A::deserialize(&mut ValueDeserializer::new(ds, d, v))))),
            None => Ok(None),
        }
    }

    fn end(&mut self) -> error::Result<()> {
        let len = self.values.size_hint().0;
        if len == 0 { Ok(()) } else { Err(serde::de::Error::invalid_length(len)) }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.values.size_hint()
    }
}

impl<'a> ValueDeserializer<'a> {
    fn new(descriptors: &'a descriptor::Descriptors,
           descriptor: &'a descriptor::FieldDescriptor,
           value: value::Value)
           -> ValueDeserializer<'a> {
        ValueDeserializer {
            descriptors: descriptors,
            descriptor: descriptor,
            value: Some(value),
        }
    }
}

impl<'a> serde::Deserializer for ValueDeserializer<'a> {
    type Error = error::Error;

    fn deserialize<V>(&mut self, visitor: V) -> error::Result<V::Value>
        where V: serde::de::Visitor
    {
        match self.value.take() {
            Some(value) => visit_value(self.descriptors, self.descriptor, value, visitor),
            None => Err(serde::de::Error::end_of_stream()),
        }
    }
}

fn visit_value<V>(descriptors: &descriptor::Descriptors,
                  descriptor: &descriptor::FieldDescriptor,
                  value: value::Value,
                  mut visitor: V)
                  -> error::Result<V::Value>
    where V: serde::de::Visitor
{
    match value {
        value::Value::Bool(v) => visitor.visit_bool(v),
        value::Value::I32(v) => visitor.visit_i32(v),
        value::Value::I64(v) => visitor.visit_i64(v),
        value::Value::U32(v) => visitor.visit_u32(v),
        value::Value::U64(v) => visitor.visit_u64(v),
        value::Value::F32(v) => visitor.visit_f32(v),
        value::Value::F64(v) => visitor.visit_f64(v),
        value::Value::Bytes(v) => visitor.visit_byte_buf(v),
        value::Value::String(v) => visitor.visit_string(v),
        value::Value::Message(m) => {
            if let descriptor::FieldType::Message(d) = descriptor.field_type(descriptors) {
                visitor.visit_map(MessageVisitor::new(descriptors, d, m))
            } else {
                panic!("A field with a message value doesn't have a message type!")
            }
        },
        value::Value::Enum(e) => {
            if let descriptor::FieldType::Enum(d) = descriptor.field_type(descriptors) {
                visitor.visit_str(d.value_by_number(e).unwrap().name())
            } else {
                panic!("A field with an enum value doesn't have an enum type!")
            }
        },
    }
}
<|endoftext|>


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

extern crate app_units;
extern crate cssparser;
extern crate gecko_bindings;
extern crate style;
extern crate style_traits;

mod sanity_checks;
<commit_msg>Fix `test-geckolib`<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate app_units;
extern crate cssparser;
extern crate style;
extern crate style_traits;

mod sanity_checks;
<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};
use std::list;
use std::list::{List, Cons, Nil};

/**
 * A purely functional Pairing Heap [FSST86]
 *
 * Our implementation uses Linked List (cons cells) so may not be the
 * fastest way to implement this in Rust.
 *
 * This implementation is a port of the Standard ML found in Okasaki's
 * Purely Functional Data Structures.
 */
pub enum PairingHeap<E: Copy Eq Ord> {
  Empty_,
  PairingHeap_(
    E,
    @List<PairingHeap<E>>
  )
}

pub trait Heap<E: Copy Eq Ord> {
  // returns true if the Heap is empty.
  pure fn is_empty(&self) -> bool;

  // returns a new Heap with the element inserted.
  pure fn insert(elem: E) -> self;

  // returns the minimum element without a modified heap
  pure fn find_min() -> Option<E>;

  // returns the minimum element and a new Heap without that element.
  pure fn delete_min() -> (Option<E>, self);
}

pure fn Empty<E: Copy Eq Ord>() -> PairingHeap<E> {
  Empty_
}

pure fn PairingHeap<E: Copy Eq Ord>(initial_value: E) -> PairingHeap<E> {
  PairingHeap_(
    initial_value,
    @Nil
  )
}

impl<E: Copy Eq Ord> PairingHeap<E> : Eq {
  pure fn eq(other: &PairingHeap<E>) -> bool {
    match (self, *other) {
      (Empty_, Empty_) => {true}
      (PairingHeap_(headA, restA), PairingHeap_(headB, restB)) => {
        (headA == headB) && (restA == restB)
      }
      //(Empty_, PairingHeap_(_)) => {false} // why are these unreachable?
      //(PairingHeap_(_), Empty) => {false}
      (_, _) => {false}
    }
  }

  pure fn ne(other: &PairingHeap<E>) -> bool { !(self).eq(other) }
}

impl<E: Copy Eq Ord> PairingHeap<E> : Heap<E> {
  pure fn is_empty(&self) -> bool {
    *self == Empty_
  }

  pure fn insert(e: E) -> PairingHeap<E> {
    self.merge(PairingHeap(e))
  }

  pure fn find_min() -> Option<E> {
    match self {
      Empty_ => { None }
      PairingHeap_(head, _) => { Some(head) }
    }
  }

  pure fn delete_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => {(None, self)}
      PairingHeap_(head, rest) => {(Some(head), self.merge_pairs(rest))}
    }
  }

  pure fn merge(other: PairingHeap<E>) -> PairingHeap<E> {
    match (self, other) {
      (Empty_, b) => { b }
      (a, Empty_) => { a }
      (x@PairingHeap_(headA, restA), y@PairingHeap_(headB, restB)) => {
        if (headA.le(&headB)) {
          PairingHeap_(
            headA,
            @Cons(y, restA)
          )
        } else {
          PairingHeap_(
            headB,
            @Cons(x, restB)
          )
        }
      }
    }
  }

  pure fn merge_pairs(heaps: @List<PairingHeap<E>>) -> PairingHeap<E> {
    match heaps {
      // Why are @-signs required for pattern matching here?
      @Cons(a, @Cons(b, xs)) => {a.merge(b).merge(self.merge_pairs(xs))}
      @Cons(elem, @Nil) => {elem}
      @Nil => {Empty()}
    }
  }
}

#[test]
fn test_heap_create() {
  let heap = PairingHeap(1);
  assert(!heap.is_empty());

  // inference fails on this without a type declaration.
  let heap : PairingHeap<()> = Empty();
  assert(heap.is_empty());
}

#[test]
fn test_heap_insert() {
  let v1 = PairingHeap(10);
  let v2 = v1.insert(1);
  let (one, v3) = v2.delete_min();
  let (ten, v4) = v3.delete_min();
  let (e, v5) = v4.delete_min();

  assert(one == Some(1));
  assert(ten == Some(10));
  assert(v4 == Empty_);
  assert(e == None);
  assert(v5 == Empty_);
}

#[test]
fn test_heap_insert_delete_interleved() {
  let v1 = PairingHeap(10);
  let (a, v2) = v1.delete_min();
  assert(a == Some(10));
  assert(v2 == Empty_);

  let v3 = v2.insert(9);
  let v4 = v3.insert(8);
  let v5 = v4.insert(11);

  let (b, v6) = v5.delete_min();
  assert(b == Some(8));

  let v7 = v6.insert(7);
  let v8 = v7.insert(12);

  let x = v8.find_min();
  assert(x == Some(7));

  let (c, v9) = v8.delete_min();
  assert(c == Some(7));

  let (d, v10) = v9.delete_min();
  assert(d == Some(9));

  let (e, v11) = v10.delete_min();
  assert(e == Some(11));

  let (f, v12) = v11.delete_min();
  assert(f == Some(12));

  let (g, v13) = v12.delete_min();
  assert(g == None);
  assert(v13 == Empty_);
}

#[test]
fn test_immutable_heap() {
  let heap = PairingHeap(10);
  let x1 = heap.insert(1);

  assert(x1.find_min() == Some(1));
  assert(heap.find_min() == Some(10));

  let (a, v1) = heap.delete_min();
  assert(a == Some(10));
  assert(v1 == Empty_);

  let (b, x2) = x1.delete_min();
  assert(b == Some(1));
  assert(x2 != Empty_);
}

<commit_msg>PairingHeap_ -> PairingHeapCell<commit_after>use core::cmp::{Eq, Ord};
use std::list;
use std::list::{List, Cons, Nil};

/**
 * A purely functional Pairing Heap [FSST86]
 *
 * Our implementation uses Linked List (cons cells) so may not be the
 * fastest way to implement this in Rust.
 *
 * This implementation is a port of the Standard ML found in Okasaki's
 * Purely Functional Data Structures.
 */
pub enum PairingHeap<E: Copy Eq Ord> {
  Empty_,
  PairingHeapCell(
    E,
    @List<PairingHeap<E>>
  )
}

pub trait Heap<E: Copy Eq Ord> {
  // returns true if the Heap is empty.
  pure fn is_empty(&self) -> bool;

  // returns a new Heap with the element inserted.
  pure fn insert(elem: E) -> self;

  // returns the minimum element without a modified heap
  pure fn find_min() -> Option<E>;

  // returns the minimum element and a new Heap without that element.
  pure fn delete_min() -> (Option<E>, self);
}

pure fn Empty<E: Copy Eq Ord>() -> PairingHeap<E> {
  Empty_
}

pure fn PairingHeap<E: Copy Eq Ord>(initial_value: E) -> PairingHeap<E> {
  PairingHeapCell(
    initial_value,
    @Nil
  )
}

impl<E: Copy Eq Ord> PairingHeap<E> : Eq {
  pure fn eq(other: &PairingHeap<E>) -> bool {
    match (self, *other) {
      (Empty_, Empty_) => {true}
      (PairingHeapCell(headA, restA), PairingHeapCell(headB, restB)) => {
        (headA == headB) && (restA == restB)
      }
      //(Empty_, PairingHeapCell(_)) => {false} // why are these unreachable?
      //(PairingHeapCell(_), Empty) => {false}
      (_, _) => {false}
    }
  }

  pure fn ne(other: &PairingHeap<E>) -> bool { !(self).eq(other) }
}

impl<E: Copy Eq Ord> PairingHeap<E> : Heap<E> {
  pure fn is_empty(&self) -> bool {
    *self == Empty_
  }

  pure fn insert(e: E) -> PairingHeap<E> {
    self.merge(PairingHeap(e))
  }

  pure fn find_min() -> Option<E> {
    match self {
      Empty_ => { None }
      PairingHeapCell(head, _) => { Some(head) }
    }
  }

  pure fn delete_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => {(None, self)}
      PairingHeapCell(head, rest) => {(Some(head), self.merge_pairs(rest))}
    }
  }

  pure fn merge(other: PairingHeap<E>) -> PairingHeap<E> {
    match (self, other) {
      (Empty_, b) => { b }
      (a, Empty_) => { a }
      (x@PairingHeapCell(headA, restA), y@PairingHeapCell(headB, restB)) => {
        if (headA.le(&headB)) {
          PairingHeapCell(
            headA,
            @Cons(y, restA)
          )
        } else {
          PairingHeapCell(
            headB,
            @Cons(x, restB)
          )
        }
      }
    }
  }

  pure fn merge_pairs(heaps: @List<PairingHeap<E>>) -> PairingHeap<E> {
    match heaps {
      // Why are @-signs required for pattern matching here?
      @Cons(a, @Cons(b, xs)) => {a.merge(b).merge(self.merge_pairs(xs))}
      @Cons(elem, @Nil) => {elem}
      @Nil => {Empty()}
    }
  }
}

#[test]
fn test_heap_create() {
  let heap = PairingHeap(1);
  assert(!heap.is_empty());

  // inference fails on this without a type declaration.
  let heap : PairingHeap<()> = Empty();
  assert(heap.is_empty());
}

#[test]
fn test_heap_insert() {
  let v1 = PairingHeap(10);
  let v2 = v1.insert(1);
  let (one, v3) = v2.delete_min();
  let (ten, v4) = v3.delete_min();
  let (e, v5) = v4.delete_min();

  assert(one == Some(1));
  assert(ten == Some(10));
  assert(v4 == Empty_);
  assert(e == None);
  assert(v5 == Empty_);
}

#[test]
fn test_heap_insert_delete_interleved() {
  let v1 = PairingHeap(10);
  let (a, v2) = v1.delete_min();
  assert(a == Some(10));
  assert(v2 == Empty_);

  let v3 = v2.insert(9);
  let v4 = v3.insert(8);
  let v5 = v4.insert(11);

  let (b, v6) = v5.delete_min();
  assert(b == Some(8));

  let v7 = v6.insert(7);
  let v8 = v7.insert(12);

  let x = v8.find_min();
  assert(x == Some(7));

  let (c, v9) = v8.delete_min();
  assert(c == Some(7));

  let (d, v10) = v9.delete_min();
  assert(d == Some(9));

  let (e, v11) = v10.delete_min();
  assert(e == Some(11));

  let (f, v12) = v11.delete_min();
  assert(f == Some(12));

  let (g, v13) = v12.delete_min();
  assert(g == None);
  assert(v13 == Empty_);
}

#[test]
fn test_immutable_heap() {
  let heap = PairingHeap(10);
  let x1 = heap.insert(1);

  assert(x1.find_min() == Some(1));
  assert(heap.find_min() == Some(10));

  let (a, v1) = heap.delete_min();
  assert(a == Some(10));
  assert(v1 == Empty_);

  let (b, x2) = x1.delete_min();
  assert(b == Some(1));
  assert(x2 != Empty_);
}

<|endoftext|>


<commit_before>use support::rustc_host;
use support::{basic_lib_manifest, execs, project, path2url};
use support::hamcrest::assert_that;

#[test]
fn pathless_tools() {
    let target = rustc_host();

    let foo = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{}]
            ar = "nonexistent-ar"
            linker = "nonexistent-linker"
        "#,
                target
            ),
        )
        .build();

    assert_that(
        foo.cargo("build").arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo.url()
        )),
    )
}

#[test]
fn absolute_tools() {
    let target = rustc_host();

    // Escaped as they appear within a TOML config file
    let config = if cfg!(windows) {
        (
            r#"C:\\bogus\\nonexistent-ar"#,
            r#"C:\\bogus\\nonexistent-linker"#,
        )
    } else {
        (r#"/bogus/nonexistent-ar"#, r#"/bogus/nonexistent-linker"#)
    };

    let foo = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{target}]
            ar = "{ar}"
            linker = "{linker}"
        "#,
                target = target,
                ar = config.0,
                linker = config.1
            ),
        )
        .build();

    let output = if cfg!(windows) {
        (
            r#"C:\bogus\nonexistent-ar"#,
            r#"C:\bogus\nonexistent-linker"#,
        )
    } else {
        (r#"/bogus/nonexistent-ar"#, r#"/bogus/nonexistent-linker"#)
    };

    assert_that(
        foo.cargo("build").arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar={ar} -C linker={linker} [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo.url(),
            ar = output.0,
            linker = output.1
        )),
    )
}

#[test]
fn relative_tools() {
    let target = rustc_host();

    // Escaped as they appear within a TOML config file
    let config = if cfg!(windows) {
        (r#".\\nonexistent-ar"#, r#".\\tools\\nonexistent-linker"#)
    } else {
        (r#"./nonexistent-ar"#, r#"./tools/nonexistent-linker"#)
    };

    // Funky directory structure to test that relative tool paths are made absolute
    // by reference to the `.cargo/..` directory and not to (for example) the CWD.
    let p = project()
        .no_manifest()
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{target}]
            ar = "{ar}"
            linker = "{linker}"
        "#,
                target = target,
                ar = config.0,
                linker = config.1
            ),
        )
        .build();

    let foo_path = p.root().join("bar");
    let foo_url = path2url(&foo_path);
    let prefix = p.root().into_os_string().into_string().unwrap();
    let output = if cfg!(windows) {
        (
            format!(r#"{}\.\nonexistent-ar"#, prefix),
            format!(r#"{}\.\tools\nonexistent-linker"#, prefix),
        )
    } else {
        (
            format!(r#"{}/./nonexistent-ar"#, prefix),
            format!(r#"{}/./tools/nonexistent-linker"#, prefix),
        )
    };

    assert_that(
        p.cargo("build").cwd(foo_path).arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] bar v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar={ar} -C linker={linker} [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo_url,
            ar = output.0,
            linker = output.1
        )),
    )
}

#[test]
fn custom_runner() {
    let target = rustc_host();

    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file("tests/test.rs", "")
        .file("benches/bench.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{}]
            runner = "nonexistent-runner -r"
        "#,
                target
            ),
        )
        .build();

    assert_that(
        p.cargo("run -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param`
",
            url = p.url()
        )),
    );

    assert_that(
        p.cargo("test --test test --verbose -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/debug/deps/test-[..][EXE] --param`
",
            url = p.url()
        )),
    );

    assert_that(
        p.cargo("bench --bench bench --verbose -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[RUNNING] `rustc [..]`
[FINISHED] release [optimized] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/release/deps/bench-[..][EXE] --param --bench`
",
            url = p.url()
        )),
    );
}
<commit_msg>Remove backslash management in 2 tool_paths tests<commit_after>use support::rustc_host;
use support::{basic_lib_manifest, execs, project, path2url};
use support::hamcrest::assert_that;

#[test]
fn pathless_tools() {
    let target = rustc_host();

    let foo = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{}]
            ar = "nonexistent-ar"
            linker = "nonexistent-linker"
        "#,
                target
            ),
        )
        .build();

    assert_that(
        foo.cargo("build").arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo.url()
        )),
    )
}

#[test]
fn absolute_tools() {
    let target = rustc_host();
    let root = if cfg!(windows) { r#"C:\\"# } else { "/" };

    // Escaped as they appear within a TOML config file
    let config = if cfg!(windows) {
        (
            r#"C:\\bogus\\nonexistent-ar"#,
            r#"C:\\bogus\\nonexistent-linker"#,
        )
    } else {
        (r#"/bogus/nonexistent-ar"#, r#"/bogus/nonexistent-linker"#)
    };

    let foo = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{target}]
            ar = "{ar}"
            linker = "{linker}"
        "#,
                target = target,
                ar = config.0,
                linker = config.1
            ),
        )
        .build();

    assert_that(
        foo.cargo("build").arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] foo v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar={root}bogus/nonexistent-ar -C linker={root}bogus/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo.url(),
            root = root,
        )),
    )
}

#[test]
fn relative_tools() {
    let target = rustc_host();

    // Escaped as they appear within a TOML config file
    let config = if cfg!(windows) {
        (r#".\\nonexistent-ar"#, r#".\\tools\\nonexistent-linker"#)
    } else {
        (r#"./nonexistent-ar"#, r#"./tools/nonexistent-linker"#)
    };

    // Funky directory structure to test that relative tool paths are made absolute
    // by reference to the `.cargo/..` directory and not to (for example) the CWD.
    let p = project()
        .no_manifest()
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{target}]
            ar = "{ar}"
            linker = "{linker}"
        "#,
                target = target,
                ar = config.0,
                linker = config.1
            ),
        )
        .build();

    let foo_path = p.root().join("bar");
    let foo_url = path2url(&foo_path);
    let prefix = p.root().into_os_string().into_string().unwrap();

    assert_that(
        p.cargo("build").cwd(foo_path).arg("--verbose"),
        execs().with_stderr(&format!(
            "\
[COMPILING] bar v0.5.0 ({url})
[RUNNING] `rustc [..] -C ar={prefix}/./nonexistent-ar -C linker={prefix}/./tools/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
            url = foo_url,
            prefix = prefix,
        )),
    )
}

#[test]
fn custom_runner() {
    let target = rustc_host();

    let p = project()
        .file("src/main.rs", "fn main() {}")
        .file("tests/test.rs", "")
        .file("benches/bench.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{}]
            runner = "nonexistent-runner -r"
        "#,
                target
            ),
        )
        .build();

    assert_that(
        p.cargo("run -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target/debug/foo[EXE] --param`
",
            url = p.url()
        )),
    );

    assert_that(
        p.cargo("test --test test --verbose -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/debug/deps/test-[..][EXE] --param`
",
            url = p.url()
        )),
    );

    assert_that(
        p.cargo("bench --bench bench --verbose -- --param"),
        execs().with_status(101).with_stderr_contains(&format!(
            "\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[RUNNING] `rustc [..]`
[FINISHED] release [optimized] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..]/target/release/deps/bench-[..][EXE] --param --bench`
",
            url = p.url()
        )),
    );
}
<|endoftext|>


<commit_before>pub mod tokens;

use std::str::CharIndices;
use self::tokens::Token;

#[inline]
fn is_id_start(ch: char) -> bool {
    ch == '_' || ch.is_ascii_alphabetic()
}

#[inline]
fn is_id_continue(ch: char) -> bool {
    ch == '_' || ch.is_ascii_digit()
}

pub type Location = usize;

#[derive(Debug, Fail)]
pub enum LexicalError {
    #[fail(display = "Invalid character '{}' found at {}", ch, location)]
    InvalidCharacter { ch: char, location: Location },

    #[fail(display = "String starting at {} was not terminated", location)]
    UnterminatedString { location: Location },
}

pub type SpanResult<'input> = Result<(Location, Token<'input>, Location), LexicalError>;

pub struct Lexer<'input> {
    source: &'input str,
    chars: CharIndices<'input>,
    lookahead: Option<(usize, char)>,
    lookahead2: Option<(usize, char)>,
}

impl<'input> Lexer<'input> {
    pub fn new(source: &'input str) -> Lexer<'input> {
        let mut chars = source.char_indices();
        let lookahead = chars.next();
        let lookahead2 = chars.next();

        Lexer {
            source,
            chars,
            lookahead,
            lookahead2,
        }
    }

    fn bump(&mut self) -> Option<(usize, char)> {
        let next = self.lookahead;
        self.lookahead = self.lookahead2;
        self.lookahead2 = self.chars.next();
        next
    }

    fn take_until<F>(&mut self, mut terminate: F) -> Option<usize>
    where
        F: FnMut(char) -> bool,
    {
        while let Some((i, ch)) = self.lookahead {
            if terminate(ch) {
                return Some(i);
            } else {
                self.bump();
            }
        }

        None
    }

    fn take_while<F>(&mut self, mut condition: F) -> Option<usize>
    where
        F: FnMut(char) -> bool,
    {
        self.take_until(|ch| !condition(ch))
    }

    fn skip_to_line_end(&mut self) {
        self.take_while(|ch| ch != '\n');
    }

    fn skip_whitespace(&mut self) {
        self.take_while(|ch| ch.is_whitespace());
    }

    fn read_string(&mut self, pos: usize) -> SpanResult<'input> {
        match self.take_until(|ch| ch == '"') {
            Some(i) => {
                self.bump();
                Ok((pos, Token::String(&self.source[pos + 1..i]), i + 1))
            }
            None => Err(LexicalError::UnterminatedString { location: pos }),
        }
    }

    fn read_number(&mut self, pos: usize) -> SpanResult<'input> {
        let mut end = self.take_while(|ch| ch.is_ascii_digit());

        if let Some((_, '.')) = self.lookahead {
            // Check if it's a decimal or a field access
            if let Some((_, next_ch)) = self.lookahead2 {
                if next_ch.is_ascii_digit() {
                    self.bump();
                    end = self.take_while(|ch| ch.is_ascii_digit());
                }
            }
        }

        let end = end.unwrap_or_else(|| self.source.len());

        Ok((
            pos,
            Token::Number(self.source[pos..end].parse().expect("unparsable number")),
            end,
        ))
    }

    fn read_identifier(&mut self, pos: usize) -> SpanResult<'input> {
        let end = self.take_while(|ch| is_id_start(ch) || is_id_continue(ch))
            .unwrap_or_else(|| self.source.len());

        match &self.source[pos..end] {
            "else" => Ok((pos, Token::Else, end)),
            "false" => Ok((pos, Token::False, end)),
            "fn" => Ok((pos, Token::Fn, end)),
            "for" => Ok((pos, Token::For, end)),
            "if" => Ok((pos, Token::If, end)),
            "nil" => Ok((pos, Token::Nil, end)),
            "print" => Ok((pos, Token::Print, end)),
            "return" => Ok((pos, Token::Return, end)),
            "this" => Ok((pos, Token::This, end)),
            "true" => Ok((pos, Token::True, end)),
            "let" => Ok((pos, Token::Let, end)),
            "while" => Ok((pos, Token::While, end)),
            id => Ok((pos, Token::Identifier(id), end)),
        }
    }
}

impl<'input> Iterator for Lexer<'input> {
    type Item = SpanResult<'input>;

    fn next(&mut self) -> Option<SpanResult<'input>> {
        self.skip_whitespace();

        if let Some((i, ch)) = self.bump() {
            match ch {
                '{' => Some(Ok((i, Token::OpenBrace, i + 1))),
                '}' => Some(Ok((i, Token::CloseBrace, i + 1))),
                '(' => Some(Ok((i, Token::OpenParen, i + 1))),
                ')' => Some(Ok((i, Token::CloseParen, i + 1))),
                '[' => Some(Ok((i, Token::OpenBracket, i + 1))),
                ']' => Some(Ok((i, Token::CloseBracket, i + 1))),
                ';' => Some(Ok((i, Token::Semicolon, i + 1))),
                ',' => Some(Ok((i, Token::Comma, i + 1))),
                '.' => Some(Ok((i, Token::Dot, i + 1))),
                '+' => Some(Ok((i, Token::Plus, i + 1))),
                '-' => Some(Ok((i, Token::Minus, i + 1))),
                '*' => Some(Ok((i, Token::Star, i + 1))),

                '/' => {
                    if let Some((_, '/')) = self.lookahead {
                        self.skip_to_line_end();
                        self.next()
                    } else {
                        Some(Ok((i, Token::Slash, i + 1)))
                    }
                }

                '!' => {
                    if let Some((_, '=')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::NotEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Not, i + 1)))
                    }
                }

                '=' => {
                    if let Some((_, '=')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::EqualEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Equal, i + 1)))
                    }
                }

                '>' => {
                    if let Some((_, '=')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::GreaterEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Greater, i + 1)))
                    }
                }

                '<' => {
                    if let Some((_, '=')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::LessEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Less, i + 1)))
                    }
                }

                '&' => {
                    if let Some((_, '&')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::AmpAmp, i + 2)))
                    } else {
                        Some(Err(LexicalError::InvalidCharacter { ch, location: i }))
                    }
                }

                '|' => {
                    if let Some((_, '|')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::PipePipe, i + 2)))
                    } else {
                        Some(Err(LexicalError::InvalidCharacter { ch, location: i }))
                    }
                }

                '"' => Some(self.read_string(i)),
                ch if is_id_start(ch) => Some(self.read_identifier(i)),
                ch if ch.is_ascii_digit() => Some(self.read_number(i)),

                ch => Some(Err(LexicalError::InvalidCharacter { ch, location: i })),
            }
        } else {
            None
        }
    }
}

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

    fn lex(source: &str, expected: Vec<(usize, Token, usize)>) {
        let mut lexer = Lexer::new(source);

        let mut actual_len = 0;
        let expected_len = expected.len();

        for (expected, actual) in expected.into_iter().zip(lexer.by_ref()) {
            actual_len += 1;
            let actual = actual.unwrap();
            assert_eq!(expected, actual);
        }

        assert_eq!(expected_len, actual_len);
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn delimiters() {
        lex(
            "{} [] ()",
            vec![
                (0, Token::OpenBrace, 1),
                (1, Token::CloseBrace, 2),
                (3, Token::OpenBracket, 4),
                (4, Token::CloseBracket, 5),
                (6, Token::OpenParen, 7),
                (7, Token::CloseParen, 8),
            ],
        );
    }

    #[test]
    fn operators() {
        lex(
            ", . + - * / = == ! != > >= < <= && ||",
            vec![
                (0, Token::Comma, 1),
                (2, Token::Dot, 3),
                (4, Token::Plus, 5),
                (6, Token::Minus, 7),
                (8, Token::Star, 9),
                (10, Token::Slash, 11),
                (12, Token::Equal, 13),
                (14, Token::EqualEqual, 16),
                (17, Token::Not, 18),
                (19, Token::NotEqual, 21),
                (22, Token::Greater, 23),
                (24, Token::GreaterEqual, 26),
                (27, Token::Less, 28),
                (29, Token::LessEqual, 31),
                (32, Token::AmpAmp, 34),
                (35, Token::PipePipe, 37),
            ],
        );
    }

    #[test]
    fn line_comment() {
        lex(
            "123; // comment\n 123",
            vec![
                (0, Token::Number(123.0), 3),
                (3, Token::Semicolon, 4),
                (17, Token::Number(123.0), 20),
            ],
        );
    }

    #[test]
    fn string() {
        lex(
            "\"hello, world\"",
            vec![(0, Token::String("hello, world"), 14)],
        );
    }

    #[test]
    fn integer() {
        lex("123", vec![(0, Token::Number(123.0), 3)]);
    }

    #[test]
    fn decimal() {
        lex("123.45", vec![(0, Token::Number(123.45), 6)]);
    }

    #[test]
    fn number_field_access() {
        lex(
            "123.prop",
            vec![
                (0, Token::Number(123.0), 3),
                (3, Token::Dot, 4),
                (4, Token::Identifier("prop"), 8),
            ],
        );
    }

    #[test]
    fn identifiers() {
        lex("id", vec![(0, Token::Identifier("id"), 2)]);
        lex("_id", vec![(0, Token::Identifier("_id"), 3)]);
        lex("id123", vec![(0, Token::Identifier("id123"), 5)]);
    }

    #[test]
    fn keywords() {
        lex("else", vec![(0, Token::Else, 4)]);
        lex("false", vec![(0, Token::False, 5)]);
        lex("fn", vec![(0, Token::Fn, 2)]);
        lex("for", vec![(0, Token::For, 3)]);
        lex("if", vec![(0, Token::If, 2)]);
        lex("nil", vec![(0, Token::Nil, 3)]);
        lex("print", vec![(0, Token::Print, 5)]);
        lex("return", vec![(0, Token::Return, 6)]);
        lex("this", vec![(0, Token::This, 4)]);
        lex("true", vec![(0, Token::True, 4)]);
        lex("let", vec![(0, Token::Let, 3)]);
        lex("while", vec![(0, Token::While, 5)]);
    }
}
<commit_msg>Fix lexer tests (whoops)<commit_after>pub mod tokens;

use std::str::CharIndices;
use self::tokens::Token;

#[inline]
fn is_id_start(ch: char) -> bool {
    ch == '_' || ch.is_ascii_alphabetic()
}

#[inline]
fn is_id_continue(ch: char) -> bool {
    ch == '_' || ch.is_ascii_digit()
}

pub type Location = usize;

#[derive(Debug, Fail, PartialEq)]
pub enum LexicalError {
    #[fail(display = "Invalid character '{}' found at {}", ch, location)]
    InvalidCharacter { ch: char, location: Location },

    #[fail(display = "String starting at {} was not terminated", location)]
    UnterminatedString { location: Location },
}

pub type SpanResult<'input> = Result<(Location, Token<'input>, Location), LexicalError>;

pub struct Lexer<'input> {
    source: &'input str,
    chars: CharIndices<'input>,
    lookahead: Option<(usize, char)>,
    lookahead2: Option<(usize, char)>,
}

impl<'input> Lexer<'input> {
    pub fn new(source: &'input str) -> Lexer<'input> {
        let mut chars = source.char_indices();
        let lookahead = chars.next();
        let lookahead2 = chars.next();

        Lexer {
            source,
            chars,
            lookahead,
            lookahead2,
        }
    }

    fn bump(&mut self) -> Option<(usize, char)> {
        let next = self.lookahead;
        self.lookahead = self.lookahead2;
        self.lookahead2 = self.chars.next();
        next
    }

    fn take_until<F>(&mut self, mut terminate: F) -> Option<usize>
    where
        F: FnMut(char) -> bool,
    {
        while let Some((i, ch)) = self.lookahead {
            if terminate(ch) {
                return Some(i);
            } else {
                self.bump();
            }
        }

        None
    }

    fn take_while<F>(&mut self, mut condition: F) -> Option<usize>
    where
        F: FnMut(char) -> bool,
    {
        self.take_until(|ch| !condition(ch))
    }

    fn skip_to_line_end(&mut self) {
        self.take_while(|ch| ch != '\n');
    }

    fn skip_whitespace(&mut self) {
        self.take_while(|ch| ch.is_whitespace());
    }

    fn read_string(&mut self, pos: usize) -> SpanResult<'input> {
        match self.take_until(|ch| ch == '"') {
            Some(i) => {
                self.bump();
                Ok((pos, Token::String(&self.source[pos + 1..i]), i + 1))
            }
            None => Err(LexicalError::UnterminatedString { location: pos }),
        }
    }

    fn read_number(&mut self, pos: usize) -> SpanResult<'input> {
        let mut end = self.take_while(|ch| ch.is_ascii_digit());

        if let Some((_, '.')) = self.lookahead {
            // Check if it's a decimal or a field access
            if let Some((_, next_ch)) = self.lookahead2 {
                if next_ch.is_ascii_digit() {
                    self.bump();
                    end = self.take_while(|ch| ch.is_ascii_digit());
                }
            }
        }

        let end = end.unwrap_or_else(|| self.source.len());

        Ok((
            pos,
            Token::Number(self.source[pos..end].parse().expect("unparsable number")),
            end,
        ))
    }

    fn read_identifier(&mut self, pos: usize) -> SpanResult<'input> {
        let end = self.take_while(|ch| is_id_start(ch) || is_id_continue(ch))
            .unwrap_or_else(|| self.source.len());

        match &self.source[pos..end] {
            "else" => Ok((pos, Token::Else, end)),
            "false" => Ok((pos, Token::False, end)),
            "fn" => Ok((pos, Token::Fn, end)),
            "for" => Ok((pos, Token::For, end)),
            "if" => Ok((pos, Token::If, end)),
            "nil" => Ok((pos, Token::Nil, end)),
            "print" => Ok((pos, Token::Print, end)),
            "return" => Ok((pos, Token::Return, end)),
            "this" => Ok((pos, Token::This, end)),
            "true" => Ok((pos, Token::True, end)),
            "let" => Ok((pos, Token::Let, end)),
            "while" => Ok((pos, Token::While, end)),
            id => Ok((pos, Token::Identifier(id), end)),
        }
    }
}

impl<'input> Iterator for Lexer<'input> {
    type Item = SpanResult<'input>;

    fn next(&mut self) -> Option<SpanResult<'input>> {
        self.skip_whitespace();

        if let Some((i, ch)) = self.bump() {
            match ch {
                '{' => Some(Ok((i, Token::OpenBrace, i + 1))),
                '}' => Some(Ok((i, Token::CloseBrace, i + 1))),
                '(' => Some(Ok((i, Token::OpenParen, i + 1))),
                ')' => Some(Ok((i, Token::CloseParen, i + 1))),
                '[' => Some(Ok((i, Token::OpenBracket, i + 1))),
                ']' => Some(Ok((i, Token::CloseBracket, i + 1))),
                ';' => Some(Ok((i, Token::Semicolon, i + 1))),
                ',' => Some(Ok((i, Token::Comma, i + 1))),
                '.' => Some(Ok((i, Token::Dot, i + 1))),
                '+' => Some(Ok((i, Token::Plus, i + 1))),
                '-' => Some(Ok((i, Token::Minus, i + 1))),
                '*' => Some(Ok((i, Token::Star, i + 1))),

                '/' => {
                    if let Some((_, '/')) = self.lookahead {
                        self.skip_to_line_end();
                        self.next()
                    } else {
                        Some(Ok((i, Token::Slash, i + 1)))
                    }
                }

                '!' => {
                    if let Some((_, '=')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::NotEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Not, i + 1)))
                    }
                }

                '=' => {
                    if let Some((_, '=')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::EqualEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Equal, i + 1)))
                    }
                }

                '>' => {
                    if let Some((_, '=')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::GreaterEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Greater, i + 1)))
                    }
                }

                '<' => {
                    if let Some((_, '=')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::LessEqual, i + 2)))
                    } else {
                        Some(Ok((i, Token::Less, i + 1)))
                    }
                }

                '&' => {
                    if let Some((_, '&')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::AmpAmp, i + 2)))
                    } else {
                        Some(Err(LexicalError::InvalidCharacter { ch, location: i }))
                    }
                }

                '|' => {
                    if let Some((_, '|')) = self.lookahead {
                        self.bump();
                        Some(Ok((i, Token::PipePipe, i + 2)))
                    } else {
                        Some(Err(LexicalError::InvalidCharacter { ch, location: i }))
                    }
                }

                '"' => Some(self.read_string(i)),
                ch if is_id_start(ch) => Some(self.read_identifier(i)),
                ch if ch.is_ascii_digit() => Some(self.read_number(i)),

                ch => Some(Err(LexicalError::InvalidCharacter { ch, location: i })),
            }
        } else {
            None
        }
    }
}

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

    fn lex(source: &str, expected: Vec<(usize, Token, usize)>) {
        let mut lexer = Lexer::new(source);

        let mut actual_len = 0;
        let expected_len = expected.len();

        for (expected, actual) in expected.into_iter().zip(lexer.by_ref()) {
            actual_len += 1;
            let actual = actual.unwrap();
            assert_eq!(expected, actual);
        }

        assert_eq!(expected_len, actual_len);
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn delimiters() {
        lex(
            "{} [] ()",
            vec![
                (0, Token::OpenBrace, 1),
                (1, Token::CloseBrace, 2),
                (3, Token::OpenBracket, 4),
                (4, Token::CloseBracket, 5),
                (6, Token::OpenParen, 7),
                (7, Token::CloseParen, 8),
            ],
        );
    }

    #[test]
    fn operators() {
        lex(
            ", . + - * / = == ! != > >= < <= && ||",
            vec![
                (0, Token::Comma, 1),
                (2, Token::Dot, 3),
                (4, Token::Plus, 5),
                (6, Token::Minus, 7),
                (8, Token::Star, 9),
                (10, Token::Slash, 11),
                (12, Token::Equal, 13),
                (14, Token::EqualEqual, 16),
                (17, Token::Not, 18),
                (19, Token::NotEqual, 21),
                (22, Token::Greater, 23),
                (24, Token::GreaterEqual, 26),
                (27, Token::Less, 28),
                (29, Token::LessEqual, 31),
                (32, Token::AmpAmp, 34),
                (35, Token::PipePipe, 37),
            ],
        );
    }

    #[test]
    fn line_comment() {
        lex(
            "123; // comment\n 123",
            vec![
                (0, Token::Number(123.0), 3),
                (3, Token::Semicolon, 4),
                (17, Token::Number(123.0), 20),
            ],
        );
    }

    #[test]
    fn string() {
        lex(
            "\"hello, world\"",
            vec![(0, Token::String("hello, world"), 14)],
        );
    }

    #[test]
    fn integer() {
        lex("123", vec![(0, Token::Number(123.0), 3)]);
    }

    #[test]
    fn decimal() {
        lex("123.45", vec![(0, Token::Number(123.45), 6)]);
    }

    #[test]
    fn number_field_access() {
        lex(
            "123.prop",
            vec![
                (0, Token::Number(123.0), 3),
                (3, Token::Dot, 4),
                (4, Token::Identifier("prop"), 8),
            ],
        );
    }

    #[test]
    fn identifiers() {
        lex("id", vec![(0, Token::Identifier("id"), 2)]);
        lex("_id", vec![(0, Token::Identifier("_id"), 3)]);
        lex("id123", vec![(0, Token::Identifier("id123"), 5)]);
    }

    #[test]
    fn keywords() {
        lex("else", vec![(0, Token::Else, 4)]);
        lex("false", vec![(0, Token::False, 5)]);
        lex("fn", vec![(0, Token::Fn, 2)]);
        lex("for", vec![(0, Token::For, 3)]);
        lex("if", vec![(0, Token::If, 2)]);
        lex("nil", vec![(0, Token::Nil, 3)]);
        lex("print", vec![(0, Token::Print, 5)]);
        lex("return", vec![(0, Token::Return, 6)]);
        lex("this", vec![(0, Token::This, 4)]);
        lex("true", vec![(0, Token::True, 4)]);
        lex("let", vec![(0, Token::Let, 3)]);
        lex("while", vec![(0, Token::While, 5)]);
    }
}
<|endoftext|>


<commit_before>use std::{cmp, fmt, ops};

/// Message sent and received from a multiplexed service
pub enum Message<T, B> {
    /// Has no associated streaming body
    WithoutBody(T),
    /// Has associated streaming body
    WithBody(T, B),
}

impl<T, B> Message<T, B> {
    /// If the `Message` value has an associated body stream, return it. The
    /// original `Message` value will then become a `WithoutBody` variant.
    pub fn take_body(&mut self) -> Option<B> {
        use std::ptr;

        // unfortunate that this is unsafe, but I think it is preferable to add
        // a little bit of unsafe code instead of adding a useless variant to
        // Message.
        unsafe {
            match ptr::read(self as *const Message<T, B>) {
                m @ Message::WithoutBody(..) => {
                    ptr::write(self as *mut Message<T, B>, m);
                    None
                }
                Message::WithBody(m, b) => {
                    ptr::write(self as *mut Message<T, B>, Message::WithoutBody(m));
                    Some(b)
                }
            }
        }
    }
}

impl<T, B> cmp::PartialEq<T> for Message<T, B>
    where T: cmp::PartialEq
{
    fn eq(&self, other: &T) -> bool {
        (**self).eq(other)
    }
}

impl<T, B> ops::Deref for Message<T, B> {
    type Target = T;

    fn deref(&self) -> &T {
        match *self {
            Message::WithoutBody(ref v) => v,
            Message::WithBody(ref v, _) => v,
        }
    }
}

impl<T, B> ops::DerefMut for Message<T, B> {
    fn deref_mut(&mut self) -> &mut T {
        match *self {
            Message::WithoutBody(ref mut v) => v,
            Message::WithBody(ref mut v, _) => v,
        }
    }
}

impl<T, B> fmt::Debug for Message<T, B>
    where T: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Message::WithoutBody(ref v) => write!(fmt, "Message::WithoutBody({:?})", v),
            Message::WithBody(ref v, _) => write!(fmt, "Message::WithBody({:?}, ...)", v),
        }
    }
}
<commit_msg>Add some access fns to Message<commit_after>use std::{cmp, fmt, ops};

/// Message sent and received from a multiplexed service
pub enum Message<T, B> {
    /// Has no associated streaming body
    WithoutBody(T),
    /// Has associated streaming body
    WithBody(T, B),
}

impl<T, B> Message<T, B> {
    /// Returns a reference to the inner value
    pub fn get_ref(&self) -> &T {
        match *self {
            Message::WithoutBody(ref v) => v,
            Message::WithBody(ref v, _) => v,
        }
    }

    /// Returns a mutable reference to the inner value
    pub fn get_mut(&mut self) -> &mut T {
        match *self {
            Message::WithoutBody(ref mut v) => v,
            Message::WithBody(ref mut v, _) => v,
        }
    }

    /// Consumes the value and returns the inner value
    pub fn into_inner(self) -> T {
        match self {
            Message::WithoutBody(v) => v,
            Message::WithBody(v, _) => v,
        }
    }

    /// If the `Message` value has an associated body stream, return it. The
    /// original `Message` value will then become a `WithoutBody` variant.
    pub fn take_body(&mut self) -> Option<B> {
        use std::ptr;

        // unfortunate that this is unsafe, but I think it is preferable to add
        // a little bit of unsafe code instead of adding a useless variant to
        // Message.
        unsafe {
            match ptr::read(self as *const Message<T, B>) {
                m @ Message::WithoutBody(..) => {
                    ptr::write(self as *mut Message<T, B>, m);
                    None
                }
                Message::WithBody(m, b) => {
                    ptr::write(self as *mut Message<T, B>, Message::WithoutBody(m));
                    Some(b)
                }
            }
        }
    }
}

impl<T, B> cmp::PartialEq<T> for Message<T, B>
    where T: cmp::PartialEq
{
    fn eq(&self, other: &T) -> bool {
        (**self).eq(other)
    }
}

impl<T, B> ops::Deref for Message<T, B> {
    type Target = T;

    fn deref(&self) -> &T {
        match *self {
            Message::WithoutBody(ref v) => v,
            Message::WithBody(ref v, _) => v,
        }
    }
}

impl<T, B> ops::DerefMut for Message<T, B> {
    fn deref_mut(&mut self) -> &mut T {
        match *self {
            Message::WithoutBody(ref mut v) => v,
            Message::WithBody(ref mut v, _) => v,
        }
    }
}

impl<T, B> fmt::Debug for Message<T, B>
    where T: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Message::WithoutBody(ref v) => write!(fmt, "Message::WithoutBody({:?})", v),
            Message::WithBody(ref v, _) => write!(fmt, "Message::WithBody({:?}, ...)", v),
        }
    }
}
<|endoftext|>


<commit_before>pub type Seconds = u8;

pub use self::Metric::*;

#[derive(Debug, PartialEq)]
pub enum Metric {
    Count(String, u64),
    Measure(String, f64),
    Sample(String, f64),
}
<commit_msg>Implement basic metric aggregation<commit_after>use std::collections::hash_map;
use std::cmp::Ordering::Equal;

pub type Seconds = u8;

pub use self::Metric::*;

#[derive(Debug, PartialEq)]
pub enum Metric {
    Count(String, u64),
    Measure(String, f64),
    Sample(String, f64),
}

/// All the metrics in a given time interval coalesced into a single value for each metric.
pub struct AggregatedMetrics {
    metrics: Vec<(String, f64)>,
}

impl AggregatedMetrics {
    fn aggregate_counts(&mut self, counts: hash_map::Iter<String, u64>) {
        for (name, value) in counts {
            self.metrics.push((name.to_owned(), *value as f64))
        }
    }

    fn aggregate_measures(&mut self, measures: hash_map::Iter<String, Vec<f64>>) {
        for (name, values) in measures {
            let mut sorted = values.clone();
            sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Equal));

            let min          = *sorted.first().unwrap();
            let max          = *sorted.last().unwrap();
            let median       = sorted[(sorted.len() / 2) - 1];
            let average      = sorted.iter().fold(0.0, |sum, val| { sum + val }) / (sorted.len() as f64);
            let percentile95 = sorted[(sorted.len() as f64 * 0.95) as usize];

            self.metrics.push((format!("{}.min",          name.clone()), min));
            self.metrics.push((format!("{}.max",          name.clone()), max));
            self.metrics.push((format!("{}.median",       name.clone()), median));
            self.metrics.push((format!("{}.avg",          name.clone()), average));
            self.metrics.push((format!("{}.95percentile", name.clone()), percentile95));

            self.metrics.push((format!("{}.count", name.clone()), sorted.len() as f64));
        }
    }

    fn aggregate_samples(&mut self, samples: hash_map::Iter<String, f64>) {
        for (name, value) in samples {
            self.metrics.push((name.to_owned(), *value as f64))
        }
    }
}
<|endoftext|>