<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 rustless;
use serde;
use serde_json;
use rustless::server::{status, header};
use rustless::{Api, Nesting};
use valico::json_dsl;
use super::query;
use model::v1::*;
use model;
use params::{dataset_builder, paginate_builder, shape_builder, types_builder, coord_builder};

const DEFAULT_LIMIT: u64 = 10u64;
const DEFAULT_OFFSET: u64 = 0u64;

fn render<T>(mut client: rustless::Client,
             obj: T)
             -> Result<rustless::Client, rustless::ErrorResponse>
    where T: serde::Serialize
{
    client.set_json_content_type();
    client.set_header(header::AccessControlAllowOrigin::Any);
    client.text(serde_json::to_string(&obj).unwrap())
}

pub struct ApiEndPoint {
    pub es_cnx_string: String,
}

impl ApiEndPoint {
    pub fn root(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("", |endpoint| {
                endpoint.handle(|client, _params| {
                    let desc = EndPoint { description: "autocomplete service".to_string() };
                    render(client, desc)
                })
            });

            api.error_formatter(|error, _media| {
                let err = if error.is::<rustless::errors::Validation>() {
                    let val_err = error.downcast::<rustless::errors::Validation>().unwrap();
                    // TODO better message, we shouldn't use {:?} but access the `path`
                    // and `detail` of all errrors in val_err.reason
                    CustomError {
                        short: "validation error".to_string(),
                        long: format!("invalid arguments {:?}", val_err.reason),
                    }
                } else {
                    CustomError {
                        short: "bad_request".to_string(),
                        long: format!("bad request, error: {}", error),
                    }
                };
                let mut resp = rustless::Response::from(status::StatusCode::BadRequest,
                                                        Box::new(serde_json::to_string(&err)
                                                            .unwrap()));
                resp.set_json_content_type();
                Some(resp)
            });
            api.mount(self.v1());
        })
    }

    fn v1(&self) -> rustless::Api {
        Api::build(|api| {
            api.mount(self.status());
            api.mount(self.autocomplete());
            api.mount(self.feature());
        })
    }

    fn status(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("status", |endpoint| {
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, _params| {
                    let status = Status {
                        version: env!("CARGO_PKG_VERSION").to_string(),
                        es: cnx.to_string(),
                        status: "good".to_string(),
                    };
                    render(client, status)
                })
            });
        })
    }

    fn feature(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("feature", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("id", json_dsl::string());
                    dataset_builder(params);
                });
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let id = params.find("id");
                    let pt_dataset = params.find("pt_dataset")
                        .and_then(|val| val.as_str());
                    let all_data =
                        params.find("_all_data").and_then(|val| val.as_bool()).unwrap_or(false);

                    let fearture = query::feature(&pt_dataset, all_data, &cnx, &id);

                    let response = model::v1::AutocompleteResponse::from(fearture);
                    render(client, response)
                })
            });
        })
    }

    fn autocomplete(&self) -> rustless::Api {
        Api::build(|api| {
            api.post("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("q", json_dsl::string());
                    dataset_builder(params);
                    paginate_builder(params);
                    shape_builder(params);
                    types_builder(params);
                });

                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let q = params.find("q").and_then(|val| val.as_str()).unwrap_or("").to_string();
                    let pt_dataset = params.find("pt_dataset")
                        .and_then(|val| val.as_str());
                    let all_data =
                        params.find("_all_data").and_then(|val| val.as_bool()).unwrap_or(false);
                    let offset = params.find("offset")
                        .and_then(|val| val.as_u64())
                        .unwrap_or(DEFAULT_OFFSET);
                    let limit =
                        params.find("limit").and_then(|val| val.as_u64()).unwrap_or(DEFAULT_LIMIT);
                    let geometry = params.find_path(&["shape", "geometry"]).unwrap();
                    let coordinates =
                        geometry.find_path(&["coordinates"]).unwrap().as_array().unwrap();
                    let mut shape = Vec::new();
                    for ar in coordinates[0].as_array().unwrap() {
                        // (Lat, Lon)
                        shape.push((ar.as_array().unwrap()[1].as_f64().unwrap(),
                                    ar.as_array().unwrap()[0].as_f64().unwrap()));
                    }
                    let types = params.find("type")
                        .and_then(|val| val.as_array())
                        .map(|val| val.iter().map(|val| val.as_str().unwrap()).collect());
                    let model_autocomplete = query::autocomplete(&q,
                                                                 &pt_dataset,
                                                                 all_data,
                                                                 offset,
                                                                 limit,
                                                                 None,
                                                                 &cnx,
                                                                 Some(shape),
                                                                 types);

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
            api.get("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("q", json_dsl::string());
                    dataset_builder(params);
                    paginate_builder(params);
                    coord_builder(params);
                    types_builder(params);

                    params.validate_with(|val, path| {
                        // if we have a lat we should have a lon (and the opposite)
                        if let Some(obj) = val.as_object() {
                            let has_lon = obj.get("lon").is_some();
                            let has_lat = obj.get("lat").is_some();
                            if has_lon ^ has_lat {
                                Err(vec![Box::new(json_dsl::errors::WrongValue {
                                             path: path.to_string(),
                                             detail: Some("you need to provide a lon AND a lat \
                                                           if you provide one of them"
                                                 .to_string()),
                                         })])
                            } else {
                                Ok(())
                            }
                        } else {
                            unreachable!("should never happen, already checked");
                        }
                    });
                });
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let q = params.find("q").and_then(|val| val.as_str()).unwrap_or("").to_string();
                    let pt_dataset = params.find("pt_dataset")
                        .and_then(|val| val.as_str());
                    let all_data =
                        params.find("_all_data").and_then(|val| val.as_bool()).unwrap_or(false);
                    let offset = params.find("offset")
                        .and_then(|val| val.as_u64())
                        .unwrap_or(DEFAULT_OFFSET);
                    let limit =
                        params.find("limit").and_then(|val| val.as_u64()).unwrap_or(DEFAULT_LIMIT);
                    let lon = params.find("lon").and_then(|p| p.as_f64());
                    let lat = params.find("lat").and_then(|p| p.as_f64());
                    // we have already checked that if there is a lon, lat
                    // is not None so we can unwrap
                    let coord = lon.and_then(|lon| {
                        Some(model::Coord {
                            lon: lon,
                            lat: lat.unwrap(),
                        })
                    });

                    let types = params.find("type")
                        .and_then(|val| val.as_array())
                        .map(|val| val.iter().map(|val| val.as_str().unwrap()).collect());

                    let model_autocomplete = query::autocomplete(&q,
                                                                 &pt_dataset,
                                                                 all_data,
                                                                 offset,
                                                                 limit,
                                                                 coord,
                                                                 &cnx,
                                                                 None,
                                                                 types);

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
        })
    }
}
<commit_msg>correction<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 rustless;
use serde;
use serde_json;
use rustless::server::{status, header};
use rustless::{Api, Nesting};
use valico::json_dsl;
use super::query;
use model::v1::*;
use model;
use params::{dataset_builder, paginate_builder, shape_builder, types_builder, coord_builder};

const DEFAULT_LIMIT: u64 = 10u64;
const DEFAULT_OFFSET: u64 = 0u64;

fn render<T>(mut client: rustless::Client,
             obj: T)
             -> Result<rustless::Client, rustless::ErrorResponse>
    where T: serde::Serialize
{
    client.set_json_content_type();
    client.set_header(header::AccessControlAllowOrigin::Any);
    client.text(serde_json::to_string(&obj).unwrap())
}

pub struct ApiEndPoint {
    pub es_cnx_string: String,
}

impl ApiEndPoint {
    pub fn root(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("", |endpoint| {
                endpoint.handle(|client, _params| {
                    let desc = EndPoint { description: "autocomplete service".to_string() };
                    render(client, desc)
                })
            });

            api.error_formatter(|error, _media| {
                let err = if error.is::<rustless::errors::Validation>() {
                    let val_err = error.downcast::<rustless::errors::Validation>().unwrap();
                    // TODO better message, we shouldn't use {:?} but access the `path`
                    // and `detail` of all errrors in val_err.reason
                    CustomError {
                        short: "validation error".to_string(),
                        long: format!("invalid arguments {:?}", val_err.reason),
                    }
                } else {
                    CustomError {
                        short: "bad_request".to_string(),
                        long: format!("bad request, error: {}", error),
                    }
                };
                let mut resp = rustless::Response::from(status::StatusCode::BadRequest,
                                                        Box::new(serde_json::to_string(&err)
                                                            .unwrap()));
                resp.set_json_content_type();
                Some(resp)
            });
            api.mount(self.v1());
        })
    }

    fn v1(&self) -> rustless::Api {
        Api::build(|api| {
            api.mount(self.status());
            api.mount(self.autocomplete());
            api.mount(self.feature());
        })
    }

    fn status(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("status", |endpoint| {
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, _params| {
                    let status = Status {
                        version: env!("CARGO_PKG_VERSION").to_string(),
                        es: cnx.to_string(),
                        status: "good".to_string(),
                    };
                    render(client, status)
                })
            });
        })
    }

    fn feature(&self) -> rustless::Api {
        Api::build(|api| {
            api.get("feature", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("id", json_dsl::string());
                    dataset_builder(params);
                });
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let id = params.find("id");
                    let pt_dataset = params.find("pt_dataset")
                        .and_then(|val| val.as_str());
                    let all_data =
                        params.find("_all_data").and_then(|val| val.as_bool()).unwrap_or(false);

                    let feature = query::feature(&pt_dataset, all_data, &cnx, &id);

                    let response = model::v1::AutocompleteResponse::from(feature);
                    render(client, response)
                })
            });
        })
    }

    fn autocomplete(&self) -> rustless::Api {
        Api::build(|api| {
            api.post("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("q", json_dsl::string());
                    dataset_builder(params);
                    paginate_builder(params);
                    shape_builder(params);
                    types_builder(params);
                });

                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let q = params.find("q").and_then(|val| val.as_str()).unwrap_or("").to_string();
                    let pt_dataset = params.find("pt_dataset")
                        .and_then(|val| val.as_str());
                    let all_data =
                        params.find("_all_data").and_then(|val| val.as_bool()).unwrap_or(false);
                    let offset = params.find("offset")
                        .and_then(|val| val.as_u64())
                        .unwrap_or(DEFAULT_OFFSET);
                    let limit =
                        params.find("limit").and_then(|val| val.as_u64()).unwrap_or(DEFAULT_LIMIT);
                    let geometry = params.find_path(&["shape", "geometry"]).unwrap();
                    let coordinates =
                        geometry.find_path(&["coordinates"]).unwrap().as_array().unwrap();
                    let mut shape = Vec::new();
                    for ar in coordinates[0].as_array().unwrap() {
                        // (Lat, Lon)
                        shape.push((ar.as_array().unwrap()[1].as_f64().unwrap(),
                                    ar.as_array().unwrap()[0].as_f64().unwrap()));
                    }
                    let types = params.find("type")
                        .and_then(|val| val.as_array())
                        .map(|val| val.iter().map(|val| val.as_str().unwrap()).collect());
                    let model_autocomplete = query::autocomplete(&q,
                                                                 &pt_dataset,
                                                                 all_data,
                                                                 offset,
                                                                 limit,
                                                                 None,
                                                                 &cnx,
                                                                 Some(shape),
                                                                 types);

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
            api.get("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("q", json_dsl::string());
                    dataset_builder(params);
                    paginate_builder(params);
                    coord_builder(params);
                    types_builder(params);

                    params.validate_with(|val, path| {
                        // if we have a lat we should have a lon (and the opposite)
                        if let Some(obj) = val.as_object() {
                            let has_lon = obj.get("lon").is_some();
                            let has_lat = obj.get("lat").is_some();
                            if has_lon ^ has_lat {
                                Err(vec![Box::new(json_dsl::errors::WrongValue {
                                             path: path.to_string(),
                                             detail: Some("you need to provide a lon AND a lat \
                                                           if you provide one of them"
                                                 .to_string()),
                                         })])
                            } else {
                                Ok(())
                            }
                        } else {
                            unreachable!("should never happen, already checked");
                        }
                    });
                });
                let cnx = self.es_cnx_string.clone();
                endpoint.handle(move |client, params| {
                    let q = params.find("q").and_then(|val| val.as_str()).unwrap_or("").to_string();
                    let pt_dataset = params.find("pt_dataset")
                        .and_then(|val| val.as_str());
                    let all_data =
                        params.find("_all_data").and_then(|val| val.as_bool()).unwrap_or(false);
                    let offset = params.find("offset")
                        .and_then(|val| val.as_u64())
                        .unwrap_or(DEFAULT_OFFSET);
                    let limit =
                        params.find("limit").and_then(|val| val.as_u64()).unwrap_or(DEFAULT_LIMIT);
                    let lon = params.find("lon").and_then(|p| p.as_f64());
                    let lat = params.find("lat").and_then(|p| p.as_f64());
                    // we have already checked that if there is a lon, lat
                    // is not None so we can unwrap
                    let coord = lon.and_then(|lon| {
                        Some(model::Coord {
                            lon: lon,
                            lat: lat.unwrap(),
                        })
                    });

                    let types = params.find("type")
                        .and_then(|val| val.as_array())
                        .map(|val| val.iter().map(|val| val.as_str().unwrap()).collect());

                    let model_autocomplete = query::autocomplete(&q,
                                                                 &pt_dataset,
                                                                 all_data,
                                                                 offset,
                                                                 limit,
                                                                 coord,
                                                                 &cnx,
                                                                 None,
                                                                 types);

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
        })
    }
}
<|endoftext|>


<commit_before>use crate::execstate::ExecState;
use crate::object::{Obj, Ref};

pub use self::param::*;
pub use self::reg::*;

pub mod asm;
pub mod param;
pub mod reg;
pub mod trap;

pub fn flush_icache(start: *const u8, len: usize) {
    let start = start as usize;
    let end = start + len;

    let (icacheline_size, dcacheline_size) = cacheline_sizes();

    let istart = start & !(icacheline_size - 1);
    let dstart = start & !(dcacheline_size - 1);

    let mut ptr = dstart;

    while ptr < end {
        unsafe {
            asm!("dc civac, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += dcacheline_size;
    }

    unsafe {
        asm!("dsb ish" ::: "memory" : "volatile");
    }

    ptr = istart;

    while ptr < end {
        unsafe {
            asm!("ic ivau, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += icacheline_size;
    }

    unsafe {
        asm!("dsb ish
              isb" ::: "memory" : "volatile");
    }
}

pub fn cacheline_sizes() -> (usize, usize) {
    let value: usize;

    unsafe {
        asm!("mrs $0, ctr_el0": "=r"(value)::: "volatile");
    }

    let insn = 4 << (value & 0xF);
    let data = 4 << ((value >> 16) & 0xF);

    (insn, data)
}

pub fn fp_from_execstate(es: &ExecState) -> usize {
    es.regs[REG_FP.asm() as usize]
}

pub fn get_exception_object(es: &ExecState) -> Ref<Obj> {
    let obj: Ref<Obj> = es.regs[REG_RESULT.asm() as usize].into();

    obj
}

pub fn ra_from_execstate(es: &ExecState) -> usize {
    es.regs[REG_LR.asm() as usize]
}
<commit_msg>fix formatting<commit_after>use crate::execstate::ExecState;
use crate::object::{Obj, Ref};

pub use self::param::*;
pub use self::reg::*;

pub mod asm;
pub mod param;
pub mod reg;

pub fn flush_icache(start: *const u8, len: usize) {
    let start = start as usize;
    let end = start + len;

    let (icacheline_size, dcacheline_size) = cacheline_sizes();

    let istart = start & !(icacheline_size - 1);
    let dstart = start & !(dcacheline_size - 1);

    let mut ptr = dstart;

    while ptr < end {
        unsafe {
            asm!("dc civac, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += dcacheline_size;
    }

    unsafe {
        asm!("dsb ish" ::: "memory" : "volatile");
    }

    ptr = istart;

    while ptr < end {
        unsafe {
            asm!("ic ivau, $0":: "r"(ptr) : "memory" : "volatile");
        }

        ptr += icacheline_size;
    }

    unsafe {
        asm!("dsb ish
              isb" ::: "memory" : "volatile");
    }
}

pub fn cacheline_sizes() -> (usize, usize) {
    let value: usize;

    unsafe {
        asm!("mrs $0, ctr_el0": "=r"(value)::: "volatile");
    }

    let insn = 4 << (value & 0xF);
    let data = 4 << ((value >> 16) & 0xF);

    (insn, data)
}

pub fn fp_from_execstate(es: &ExecState) -> usize {
    es.regs[REG_FP.asm() as usize]
}

pub fn get_exception_object(es: &ExecState) -> Ref<Obj> {
    let obj: Ref<Obj> = es.regs[REG_RESULT.asm() as usize].into();

    obj
}

pub fn ra_from_execstate(es: &ExecState) -> usize {
    es.regs[REG_LR.asm() as usize]
}
<|endoftext|>


<commit_before>use std::mem;

use rustc::ty::{self, layout::{self, Size}};
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};

use crate::*;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Gets an instance for a path.
    fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> {
        let this = self.eval_context_ref();
        this.tcx
            .crates()
            .iter()
            .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0])
            .and_then(|krate| {
                let krate = DefId {
                    krate: *krate,
                    index: CRATE_DEF_INDEX,
                };
                let mut items = this.tcx.item_children(krate);
                let mut path_it = path.iter().skip(1).peekable();

                while let Some(segment) = path_it.next() {
                    for item in mem::replace(&mut items, Default::default()).iter() {
                        if item.ident.name.as_str() == *segment {
                            if path_it.peek().is_none() {
                                return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id()));
                            }

                            items = this.tcx.item_children(item.res.def_id());
                            break;
                        }
                    }
                }
                None
            })
            .ok_or_else(|| {
                let path = path.iter().map(|&s| s.to_owned()).collect();
                InterpError::PathNotFound(path).into()
            })
    }

    /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter
    /// will be true if this is frozen, false if this is in an `UnsafeCell`.
    fn visit_freeze_sensitive(
        &self,
        place: MPlaceTy<'tcx, Tag>,
        size: Size,
        mut action: impl FnMut(Pointer<Tag>, Size, bool) -> InterpResult<'tcx>,
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_ref();
        trace!("visit_frozen(place={:?}, size={:?})", *place, size);
        debug_assert_eq!(size,
            this.size_and_align_of_mplace(place)?
            .map(|(size, _)| size)
            .unwrap_or_else(|| place.layout.size)
        );
        // Store how far we proceeded into the place so far. Everything to the left of
        // this offset has already been handled, in the sense that the frozen parts
        // have had `action` called on them.
        let mut end_ptr = place.ptr;
        // Called when we detected an `UnsafeCell` at the given offset and size.
        // Calls `action` and advances `end_ptr`.
        let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar<Tag>, unsafe_cell_size: Size| {
            if unsafe_cell_size != Size::ZERO {
                debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().alloc_id,
                    end_ptr.to_ptr().unwrap().alloc_id);
                debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().tag,
                    end_ptr.to_ptr().unwrap().tag);
            }
            // We assume that we are given the fields in increasing offset order,
            // and nothing else changes.
            let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(this);
            let end_offset = end_ptr.get_ptr_offset(this);
            assert!(unsafe_cell_offset >= end_offset);
            let frozen_size = unsafe_cell_offset - end_offset;
            // Everything between the end_ptr and this `UnsafeCell` is frozen.
            if frozen_size != Size::ZERO {
                action(end_ptr.to_ptr()?, frozen_size, /*frozen*/true)?;
            }
            // This `UnsafeCell` is NOT frozen.
            if unsafe_cell_size != Size::ZERO {
                action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?;
            }
            // Update end end_ptr.
            end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, this);
            // Done
            Ok(())
        };
        // Run a visitor
        {
            let mut visitor = UnsafeCellVisitor {
                ecx: this,
                unsafe_cell_action: |place| {
                    trace!("unsafe_cell_action on {:?}", place.ptr);
                    // We need a size to go on.
                    let unsafe_cell_size = this.size_and_align_of_mplace(place)?
                        .map(|(size, _)| size)
                        // for extern types, just cover what we can
                        .unwrap_or_else(|| place.layout.size);
                    // Now handle this `UnsafeCell`, unless it is empty.
                    if unsafe_cell_size != Size::ZERO {
                        unsafe_cell_action(place.ptr, unsafe_cell_size)
                    } else {
                        Ok(())
                    }
                },
            };
            visitor.visit_value(place)?;
        }
        // The part between the end_ptr and the end of the place is also frozen.
        // So pretend there is a 0-sized `UnsafeCell` at the end.
        unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?;
        // Done!
        return Ok(());

        /// Visiting the memory covered by a `MemPlace`, being aware of
        /// whether we are inside an `UnsafeCell` or not.
        struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
            where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            ecx: &'ecx MiriEvalContext<'mir, 'tcx>,
            unsafe_cell_action: F,
        }

        impl<'ecx, 'mir, 'tcx, F>
            ValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
        for
            UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
        where
            F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            type V = MPlaceTy<'tcx, Tag>;

            #[inline(always)]
            fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> {
                &self.ecx
            }

            // Hook to detect `UnsafeCell`.
            fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
                let is_unsafe_cell = match v.layout.ty.sty {
                    ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(),
                    _ => false,
                };
                if is_unsafe_cell {
                    // We do not have to recurse further, this is an `UnsafeCell`.
                    (self.unsafe_cell_action)(v)
                } else if self.ecx.type_is_freeze(v.layout.ty) {
                    // This is `Freeze`, there cannot be an `UnsafeCell`
                    Ok(())
                } else {
                    // Proceed further
                    self.walk_value(v)
                }
            }

            // Make sure we visit aggregrates in increasing offset order.
            fn visit_aggregate(
                &mut self,
                place: MPlaceTy<'tcx, Tag>,
                fields: impl Iterator<Item=InterpResult<'tcx, MPlaceTy<'tcx, Tag>>>,
            ) -> InterpResult<'tcx> {
                match place.layout.fields {
                    layout::FieldPlacement::Array { .. } => {
                        // For the array layout, we know the iterator will yield sorted elements so
                        // we can avoid the allocation.
                        self.walk_aggregate(place, fields)
                    }
                    layout::FieldPlacement::Arbitrary { .. } => {
                        // Gather the subplaces and sort them before visiting.
                        let mut places = fields.collect::<InterpResult<'tcx, Vec<MPlaceTy<'tcx, Tag>>>>()?;
                        places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx()));
                        self.walk_aggregate(place, places.into_iter().map(Ok))
                    }
                    layout::FieldPlacement::Union { .. } => {
                        // Uh, what?
                        bug!("a union is not an aggregate we should ever visit")
                    }
                }
            }

            // We have to do *something* for unions.
            fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                // With unions, we fall back to whatever the type says, to hopefully be consistent
                // with LLVM IR.
                // FIXME: are we consistent, and is this really the behavior we want?
                let frozen = self.ecx.type_is_freeze(v.layout.ty);
                if frozen {
                    Ok(())
                } else {
                    (self.unsafe_cell_action)(v)
                }
            }

            // We should never get to a primitive, but always short-circuit somewhere above.
            fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                bug!("we should always short-circuit before coming to a primitive")
            }
        }
    }
}
<commit_msg>we don't need zero-sized freeze-sensitive visiting<commit_after>use std::mem;

use rustc::ty::{self, layout::{self, Size}};
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};

use crate::*;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    /// Gets an instance for a path.
    fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> {
        let this = self.eval_context_ref();
        this.tcx
            .crates()
            .iter()
            .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0])
            .and_then(|krate| {
                let krate = DefId {
                    krate: *krate,
                    index: CRATE_DEF_INDEX,
                };
                let mut items = this.tcx.item_children(krate);
                let mut path_it = path.iter().skip(1).peekable();

                while let Some(segment) = path_it.next() {
                    for item in mem::replace(&mut items, Default::default()).iter() {
                        if item.ident.name.as_str() == *segment {
                            if path_it.peek().is_none() {
                                return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id()));
                            }

                            items = this.tcx.item_children(item.res.def_id());
                            break;
                        }
                    }
                }
                None
            })
            .ok_or_else(|| {
                let path = path.iter().map(|&s| s.to_owned()).collect();
                InterpError::PathNotFound(path).into()
            })
    }

    /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter
    /// will be true if this is frozen, false if this is in an `UnsafeCell`.
    fn visit_freeze_sensitive(
        &self,
        place: MPlaceTy<'tcx, Tag>,
        size: Size,
        mut action: impl FnMut(Pointer<Tag>, Size, bool) -> InterpResult<'tcx>,
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_ref();
        trace!("visit_frozen(place={:?}, size={:?})", *place, size);
        debug_assert_eq!(size,
            this.size_and_align_of_mplace(place)?
            .map(|(size, _)| size)
            .unwrap_or_else(|| place.layout.size)
        );
        assert!(size.bytes() > 0);
        // Store how far we proceeded into the place so far. Everything to the left of
        // this offset has already been handled, in the sense that the frozen parts
        // have had `action` called on them.
        let mut end_ptr = place.ptr;
        // Called when we detected an `UnsafeCell` at the given offset and size.
        // Calls `action` and advances `end_ptr`.
        let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar<Tag>, unsafe_cell_size: Size| {
            if unsafe_cell_size != Size::ZERO {
                debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().alloc_id,
                    end_ptr.to_ptr().unwrap().alloc_id);
                debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().tag,
                    end_ptr.to_ptr().unwrap().tag);
            }
            // We assume that we are given the fields in increasing offset order,
            // and nothing else changes.
            let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(this);
            let end_offset = end_ptr.get_ptr_offset(this);
            assert!(unsafe_cell_offset >= end_offset);
            let frozen_size = unsafe_cell_offset - end_offset;
            // Everything between the end_ptr and this `UnsafeCell` is frozen.
            if frozen_size != Size::ZERO {
                action(end_ptr.to_ptr()?, frozen_size, /*frozen*/true)?;
            }
            // This `UnsafeCell` is NOT frozen.
            if unsafe_cell_size != Size::ZERO {
                action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?;
            }
            // Update end end_ptr.
            end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, this);
            // Done
            Ok(())
        };
        // Run a visitor
        {
            let mut visitor = UnsafeCellVisitor {
                ecx: this,
                unsafe_cell_action: |place| {
                    trace!("unsafe_cell_action on {:?}", place.ptr);
                    // We need a size to go on.
                    let unsafe_cell_size = this.size_and_align_of_mplace(place)?
                        .map(|(size, _)| size)
                        // for extern types, just cover what we can
                        .unwrap_or_else(|| place.layout.size);
                    // Now handle this `UnsafeCell`, unless it is empty.
                    if unsafe_cell_size != Size::ZERO {
                        unsafe_cell_action(place.ptr, unsafe_cell_size)
                    } else {
                        Ok(())
                    }
                },
            };
            visitor.visit_value(place)?;
        }
        // The part between the end_ptr and the end of the place is also frozen.
        // So pretend there is a 0-sized `UnsafeCell` at the end.
        unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?;
        // Done!
        return Ok(());

        /// Visiting the memory covered by a `MemPlace`, being aware of
        /// whether we are inside an `UnsafeCell` or not.
        struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
            where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            ecx: &'ecx MiriEvalContext<'mir, 'tcx>,
            unsafe_cell_action: F,
        }

        impl<'ecx, 'mir, 'tcx, F>
            ValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
        for
            UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
        where
            F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
        {
            type V = MPlaceTy<'tcx, Tag>;

            #[inline(always)]
            fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> {
                &self.ecx
            }

            // Hook to detect `UnsafeCell`.
            fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
                let is_unsafe_cell = match v.layout.ty.sty {
                    ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(),
                    _ => false,
                };
                if is_unsafe_cell {
                    // We do not have to recurse further, this is an `UnsafeCell`.
                    (self.unsafe_cell_action)(v)
                } else if self.ecx.type_is_freeze(v.layout.ty) {
                    // This is `Freeze`, there cannot be an `UnsafeCell`
                    Ok(())
                } else {
                    // Proceed further
                    self.walk_value(v)
                }
            }

            // Make sure we visit aggregrates in increasing offset order.
            fn visit_aggregate(
                &mut self,
                place: MPlaceTy<'tcx, Tag>,
                fields: impl Iterator<Item=InterpResult<'tcx, MPlaceTy<'tcx, Tag>>>,
            ) -> InterpResult<'tcx> {
                match place.layout.fields {
                    layout::FieldPlacement::Array { .. } => {
                        // For the array layout, we know the iterator will yield sorted elements so
                        // we can avoid the allocation.
                        self.walk_aggregate(place, fields)
                    }
                    layout::FieldPlacement::Arbitrary { .. } => {
                        // Gather the subplaces and sort them before visiting.
                        let mut places = fields.collect::<InterpResult<'tcx, Vec<MPlaceTy<'tcx, Tag>>>>()?;
                        places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx()));
                        self.walk_aggregate(place, places.into_iter().map(Ok))
                    }
                    layout::FieldPlacement::Union { .. } => {
                        // Uh, what?
                        bug!("a union is not an aggregate we should ever visit")
                    }
                }
            }

            // We have to do *something* for unions.
            fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                // With unions, we fall back to whatever the type says, to hopefully be consistent
                // with LLVM IR.
                // FIXME: are we consistent, and is this really the behavior we want?
                let frozen = self.ecx.type_is_freeze(v.layout.ty);
                if frozen {
                    Ok(())
                } else {
                    (self.unsafe_cell_action)(v)
                }
            }

            // We should never get to a primitive, but always short-circuit somewhere above.
            fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>
            {
                bug!("we should always short-circuit before coming to a primitive")
            }
        }
    }
}
<|endoftext|>


<commit_before>use elements::{Way, Tag};

struct Rule {
    key: &'static str,
    polygon: RuleType,
    values: [&'static str; 6],
}

enum RuleType {
    All,
    Blacklist,
    Whitelist,
}

static RULES: [Rule; 26] =
    [Rule {
         key: "building",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "highway",
         polygon: RuleType::Whitelist,
         values: ["services", "rest_area", "escape", "elevator", "", ""],
     },
     Rule {
         key: "natural",
         polygon: RuleType::Blacklist,
         values: ["coastline", "cliff", "ridge", "arete", "tree_row", ""],
     },
     Rule {
         key: "landuse",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "waterway",
         polygon: RuleType::Whitelist,
         values: ["riverbank", "dock", "boatyard", "dam", "", ""],
     },
     Rule {
         key: "amenity",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "leisure",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "barrier",
         polygon: RuleType::Whitelist,
         values: ["city_wall", "ditch", "hedge", "retaining_wall", "wall", "spikes"],
     },
     Rule {
         key: "railway",
         polygon: RuleType::Whitelist,
         values: ["station", "turntable", "roundhouse", "platform", "", ""],
     },
     Rule {
         key: "area",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "boundary",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "man_made",
         polygon: RuleType::Blacklist,
         values: ["cutline", "embankment", "pipeline", "", "", ""],
     },
     Rule {
         key: "power",
         polygon: RuleType::Whitelist,
         values: ["plant", "substation", "generator", "transformer", "", ""],
     },
     Rule {
         key: "place",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "shop",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "aeroway",
         polygon: RuleType::Blacklist,
         values: ["taxiway", "", "", "", "", ""],
     },
     Rule {
         key: "tourism",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "historic",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "public_transport",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "office",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "building:part",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "military",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "ruins",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "area:highway",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "craft",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "golf",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     }];

pub fn is_polygon(way: &Way) -> bool {
    way.tags.iter().any(|tag| {
        RULES.iter().any(|rule| rule.key == tag.key && has_matching_rule_value(rule, tag))
    })
}

fn has_matching_rule_value(rule: &Rule, tag: &Tag) -> bool {
    match rule.polygon {
        RuleType::All => true,
        RuleType::Whitelist => rule.values.iter().any(|val| *val != "" && *val == tag.val),
        RuleType::Blacklist => !rule.values.iter().any(|val| *val == tag.val),
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use elements::{Way, Tag};

    #[test]
    fn tagless_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: Vec::new(),
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn detect_ruletype_all_with_tag_val() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("building"),
                           val: String::from("this_is_not_valid"),
                       }],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn detect_ruletype_all_without_tag_val() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("building"),
                           val: String::from(""),
                       }],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn whitelist_val_included_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("highway"),
                           val: String::from("escape"),
                       }],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn whitelist_val_not_included_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("highway"),
                           val: String::from("footway"),
                       }],
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn whitelist_with_empty_val_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("highway"),
                           val: String::from(""),
                       }],
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn whitelist_with_matching_and_nonmatching_tags_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![
                Tag { key: String::from("highway"), val: String::from("footway") },
                Tag { key: String::from("highway"), val: String::from("escape") },
            ],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn blacklist_val_included_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("natural"),
                           val: String::from("cliff"),
                       }],
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn blacklist_val_not_included_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("natural"),
                           val: String::from("tree"),
                       }],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn blacklist_with_empty_val_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("natural"),
                           val: String::from(""),
                       }],
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn blacklist_with_matching_and_nonmatching_tags_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![
                Tag { key: String::from("natural"), val: String::from("cliff") },
                Tag { key: String::from("natural"), val: String::from("tree") },
            ],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }
}
<commit_msg>Closed loop ways are polygons<commit_after>use elements::{Way, Tag};

struct Rule {
    key: &'static str,
    polygon: RuleType,
    values: [&'static str; 6],
}

enum RuleType {
    All,
    Blacklist,
    Whitelist,
}

static RULES: [Rule; 26] =
    [Rule {
         key: "building",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "highway",
         polygon: RuleType::Whitelist,
         values: ["services", "rest_area", "escape", "elevator", "", ""],
     },
     Rule {
         key: "natural",
         polygon: RuleType::Blacklist,
         values: ["coastline", "cliff", "ridge", "arete", "tree_row", ""],
     },
     Rule {
         key: "landuse",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "waterway",
         polygon: RuleType::Whitelist,
         values: ["riverbank", "dock", "boatyard", "dam", "", ""],
     },
     Rule {
         key: "amenity",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "leisure",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "barrier",
         polygon: RuleType::Whitelist,
         values: ["city_wall", "ditch", "hedge", "retaining_wall", "wall", "spikes"],
     },
     Rule {
         key: "railway",
         polygon: RuleType::Whitelist,
         values: ["station", "turntable", "roundhouse", "platform", "", ""],
     },
     Rule {
         key: "area",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "boundary",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "man_made",
         polygon: RuleType::Blacklist,
         values: ["cutline", "embankment", "pipeline", "", "", ""],
     },
     Rule {
         key: "power",
         polygon: RuleType::Whitelist,
         values: ["plant", "substation", "generator", "transformer", "", ""],
     },
     Rule {
         key: "place",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "shop",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "aeroway",
         polygon: RuleType::Blacklist,
         values: ["taxiway", "", "", "", "", ""],
     },
     Rule {
         key: "tourism",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "historic",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "public_transport",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "office",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "building:part",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "military",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "ruins",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "area:highway",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "craft",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     },
     Rule {
         key: "golf",
         polygon: RuleType::All,
         values: ["", "", "", "", "", ""],
     }];

pub fn is_polygon(way: &Way) -> bool {
    if is_closed_loop(way) {
        return true;
    }

    way.tags.iter().any(|tag| {
        RULES.iter().any(|rule| rule.key == tag.key && has_matching_rule_value(rule, tag))
    })
}

fn is_closed_loop(way: &Way) -> bool {
    let first = way.nodes.first();
    let last = way.nodes.last();

    if let None = first.and(last) {
        return false;
    }

    first.unwrap() == last.unwrap()
}

fn has_matching_rule_value(rule: &Rule, tag: &Tag) -> bool {
    match rule.polygon {
        RuleType::All => true,
        RuleType::Whitelist => rule.values.iter().any(|val| *val != "" && *val == tag.val),
        RuleType::Blacklist => !rule.values.iter().any(|val| *val == tag.val),
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use elements::{Way, Tag, UnresolvedReference};

    #[test]
    fn tagless_and_nonloop_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: Vec::new(),
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn closed_loop_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: Vec::new(),
            nodes: vec![
                UnresolvedReference::Node(1),
                UnresolvedReference::Node(2),
                UnresolvedReference::Node(3),
                UnresolvedReference::Node(26),
                UnresolvedReference::Node(1),
                ],
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn detect_ruletype_all_with_tag_val() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("building"),
                           val: String::from("this_is_not_valid"),
                       }],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn detect_ruletype_all_without_tag_val() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("building"),
                           val: String::from(""),
                       }],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn whitelist_val_included_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("highway"),
                           val: String::from("escape"),
                       }],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn whitelist_val_not_included_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("highway"),
                           val: String::from("footway"),
                       }],
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn whitelist_with_empty_val_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("highway"),
                           val: String::from(""),
                       }],
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn whitelist_with_matching_and_nonmatching_tags_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![
                Tag { key: String::from("highway"), val: String::from("footway") },
                Tag { key: String::from("highway"), val: String::from("escape") },
                ],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn nonloop_and_whitelist_match_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("highway"),
                           val: String::from("escape"),
                       }],
            nodes: vec![
                UnresolvedReference::Node(1),
                UnresolvedReference::Node(2),
                UnresolvedReference::Node(3),
                ],
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn blacklist_val_included_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("natural"),
                           val: String::from("cliff"),
                       }],
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn blacklist_val_not_included_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("natural"),
                           val: String::from("tree"),
                       }],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn blacklist_with_empty_val_is_not_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("natural"),
                           val: String::from(""),
                       }],
            nodes: Vec::new(),
        };

        assert!(!is_polygon(&way));
    }

    #[test]
    fn blacklist_with_matching_and_nonmatching_tags_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![
                Tag { key: String::from("natural"), val: String::from("cliff") },
                Tag { key: String::from("natural"), val: String::from("tree") },
                ],
            nodes: Vec::new(),
        };

        assert!(is_polygon(&way));
    }

    #[test]
    fn nonloop_and_blacklist_cleared_is_polygon() {
        let way = Way {
            id: 1234567,
            tags: vec![Tag {
                           key: String::from("natural"),
                           val: String::from("tree"),
                       }],
            nodes: vec![
                UnresolvedReference::Node(1),
                UnresolvedReference::Node(2),
                UnresolvedReference::Node(3),
                ],
        };

        assert!(is_polygon(&way));
    }
}
<|endoftext|>


<commit_before>use libc;

extern {
    #[cfg(test)]
    fn highbd_dc_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_dc_left_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_dc_top_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_h_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
}

pub fn pred_dc_128(output: &mut [u16], stride: usize) {
    for y in 0..4 {
        for x in 0..4 {
            output[y*stride+x] = 128;
        }
    }
}

#[cfg(test)]
fn pred_dc_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc_left_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_left_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc_top_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_top_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_h_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_h_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    let edges = left.iter().chain(above.iter());
    let len = (left.len() + above.len()) as u32;
    let bw = above.len();
    let bh = left.len();
    let avg = (edges.fold(0, |acc, &v| acc + v as u32) + (len >> 1)) / len;

    for line in output.chunks_mut(stride).take(bh) {
        for v in &mut line[..bw] {
            *v = avg as u16;
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rand::{ChaChaRng, Rng};

    const MAX_ITER: usize = 1000;

    fn setup_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>, Vec<u16>, Vec<u16>) {
        let output = vec![0u16; 32 * 32];
        let above: Vec<u16> = (0..32).map(|_| ra.gen()).collect();
        let left: Vec<u16> = (0..32).map(|_| ra.gen()).collect();

        let o1 = output.clone();
        let o2 = output.clone();

        (above, left, o1, o2)
    }

    fn do_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>) {
        let (above, left, mut o1, mut o2) = setup_pred(ra);

        pred_dc_4x4(&mut o1, 32, &above[..4], &left[..4]);
        pred_dc(&mut o2, 32, &above[..4], &left[..4]);

        (o1, o2)
    }

    #[test]
    fn pred_matches() {
        let mut ra = ChaChaRng::new_unseeded();
        for _ in 0..MAX_ITER {
            let (o1, o2) = do_pred(&mut ra);

            assert_eq!(o1, o2);
        }
    }

    #[test]
    fn pred_same() {
        let mut ra = ChaChaRng::new_unseeded();
        for _ in 0..MAX_ITER {
            let (_, o2) = do_pred(&mut ra);

            for l in o2.chunks(32).take(4) {
                for v in l[..4].windows(2) {
                    assert_eq!(v[0], v[1]);
                }
            }
        }
    }

    #[test]
    fn pred_max() {
        let max12bit = 4096 - 1;
        let above = [max12bit; 32];
        let left = [max12bit; 32];

        let mut o = vec![0u16; 32 * 32];

        pred_dc(&mut o, 32, &above[..4], &left[..4]);

        for l in o.chunks(32).take(4) {
            for v in l[..4].iter() {
                assert_eq!(*v, max12bit);
            }
        }
    }
}
<commit_msg>Move pred_dc_4x4 to testing namespace<commit_after>use libc;

extern {
    #[cfg(test)]
    fn highbd_dc_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_dc_left_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_dc_top_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_h_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
}

pub fn pred_dc_128(output: &mut [u16], stride: usize) {
    for y in 0..4 {
        for x in 0..4 {
            output[y*stride+x] = 128;
        }
    }
}

pub fn pred_dc_left_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_left_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc_top_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_top_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_h_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_h_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    let edges = left.iter().chain(above.iter());
    let len = (left.len() + above.len()) as u32;
    let bw = above.len();
    let bh = left.len();
    let avg = (edges.fold(0, |acc, &v| acc + v as u32) + (len >> 1)) / len;

    for line in output.chunks_mut(stride).take(bh) {
        for v in &mut line[..bw] {
            *v = avg as u16;
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rand::{ChaChaRng, Rng};

    const MAX_ITER: usize = 1000;

    fn setup_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>, Vec<u16>, Vec<u16>) {
        let output = vec![0u16; 32 * 32];
        let above: Vec<u16> = (0..32).map(|_| ra.gen()).collect();
        let left: Vec<u16> = (0..32).map(|_| ra.gen()).collect();

        let o1 = output.clone();
        let o2 = output.clone();

        (above, left, o1, o2)
    }

    fn pred_dc_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
        unsafe {
            highbd_dc_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
        }
    }

    fn do_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>) {
        let (above, left, mut o1, mut o2) = setup_pred(ra);

        pred_dc_4x4(&mut o1, 32, &above[..4], &left[..4]);
        pred_dc(&mut o2, 32, &above[..4], &left[..4]);

        (o1, o2)
    }

    #[test]
    fn pred_matches() {
        let mut ra = ChaChaRng::new_unseeded();
        for _ in 0..MAX_ITER {
            let (o1, o2) = do_pred(&mut ra);

            assert_eq!(o1, o2);
        }
    }

    #[test]
    fn pred_same() {
        let mut ra = ChaChaRng::new_unseeded();
        for _ in 0..MAX_ITER {
            let (_, o2) = do_pred(&mut ra);

            for l in o2.chunks(32).take(4) {
                for v in l[..4].windows(2) {
                    assert_eq!(v[0], v[1]);
                }
            }
        }
    }

    #[test]
    fn pred_max() {
        let max12bit = 4096 - 1;
        let above = [max12bit; 32];
        let left = [max12bit; 32];

        let mut o = vec![0u16; 32 * 32];

        pred_dc(&mut o, 32, &above[..4], &left[..4]);

        for l in o.chunks(32).take(4) {
            for v in l[..4].iter() {
                assert_eq!(*v, max12bit);
            }
        }
    }
}
<|endoftext|>