<commit_before>use super::guards::*;

use crate::{
    adapters::{self, json},
    core::{
        prelude::*,
        usecases::{self, DuplicateType},
        util::{self, geo},
    },
    infrastructure::{
        db::{sqlite, tantivy},
        error::AppError,
        flows::prelude as flows,
        notify,
    },
};

use csv;
use rocket::{
    self,
    http::{ContentType, Cookie, Cookies, Status},
    request::Form,
    response::{content::Content, Responder, Response},
    Route,
};
use rocket_contrib::json::Json;
use std::result;

mod count;
pub mod events;
pub mod geocoding;
mod ratings;
mod search;
#[cfg(test)]
pub mod tests;
mod users;

type Result<T> = result::Result<Json<T>, AppError>;

pub fn routes() -> Vec<Route> {
    routes![
        login,
        logout,
        confirm_email_address,
        subscribe_to_bbox,
        get_bbox_subscriptions,
        unsubscribe_all_bboxes,
        get_entry,
        post_entry,
        put_entry,
        events::post_event,
        events::post_event_with_token,
        events::get_event,
        events::get_events,
        events::get_events_with_token,
        events::put_event,
        events::put_event_with_token,
        events::delete_event,
        events::delete_event_with_token,
        users::post_request_password_reset,
        users::post_reset_password,
        users::post_user,
        ratings::post_rating,
        ratings::load_rating,
        users::get_user,
        users::delete_user,
        get_categories,
        get_category,
        get_tags,
        search::get_search,
        get_duplicates,
        get_recently_changed_entries,
        count::get_count_entries,
        count::get_count_tags,
        get_version,
        csv_export,
        get_api
    ]
}

#[derive(Deserialize, Debug, Clone)]
struct UserId {
    u_id: String,
}

#[get("/entries/<ids>")]
fn get_entry(db: sqlite::Connections, ids: String) -> Result<Vec<json::Entry>> {
    // TODO: Only lookup and return a single entity
    // TODO: Add a new method for searching multiple ids
    let ids = util::split_ids(&ids);
    if ids.is_empty() {
        return Ok(Json(vec![]));
    }
    let results = {
        let mut results = Vec::with_capacity(ids.len());
        let db = db.shared()?;
        for e in db.get_entries(&ids)?.into_iter() {
            let r = db.load_ratings_of_entry(&e.id)?;
            results.push(json::Entry::from_entry_with_ratings(e, r));
        }
        results
    };
    Ok(Json(results))
}

#[get("/entries/recently-changed?<since>&<with_ratings>&<offset>&<limit>")]
fn get_recently_changed_entries(
    db: sqlite::Connections,
    since: i64,
    with_ratings: Option<bool>,
    offset: Option<u64>,
    limit: Option<u64>,
) -> Result<Vec<json::Entry>> {
    let results = {
        let db = db.shared()?;
        let entries = db.recently_changed_entries(since.into(), offset, limit)?;
        if with_ratings.unwrap_or(false) {
            let mut results = Vec::with_capacity(entries.len());
            for e in entries.into_iter() {
                let r = db.load_ratings_of_entry(&e.id)?;
                results.push(json::Entry::from_entry_with_ratings(e, r));
            }
            results
        } else {
            entries
                .into_iter()
                .map(|e| json::Entry::from_entry_with_ratings(e, vec![]))
                .collect()
        }
    };
    Ok(Json(results))
}

#[get("/duplicates/<ids>")]
fn get_duplicates(
    db: sqlite::Connections,
    ids: String,
) -> Result<Vec<(String, String, DuplicateType)>> {
    let ids = util::split_ids(&ids);
    if ids.is_empty() {
        return Ok(Json(vec![]));
    }
    let (entries, all_entries) = {
        let db = db.shared()?;
        (db.get_entries(&ids)?, db.all_entries()?)
    };
    let results = usecases::find_duplicates(&entries, &all_entries);
    Ok(Json(results))
}

#[get("/server/version")]
fn get_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

#[get("/server/api.yaml")]
fn get_api() -> Content<&'static str> {
    let data = include_str!("../../../../openapi.yaml");
    let c_type = ContentType::new("text", "yaml");
    Content(c_type, data)
}

#[post("/login", format = "application/json", data = "<login>")]
fn login(
    db: sqlite::Connections,
    mut cookies: Cookies,
    login: Json<usecases::Login>,
) -> Result<()> {
    //TODO: login with email
    let username = usecases::login_with_username(&*db.shared()?, &login.into_inner())?;
    cookies.add_private(
        Cookie::build(COOKIE_USER_KEY, username)
            .same_site(rocket::http::SameSite::None)
            .finish(),
    );
    Ok(Json(()))
}

#[post("/logout", format = "application/json")]
fn logout(mut cookies: Cookies) -> Result<()> {
    cookies.remove_private(Cookie::named(COOKIE_USER_KEY));
    Ok(Json(()))
}

#[post("/confirm-email-address", format = "application/json", data = "<user>")]
fn confirm_email_address(db: sqlite::Connections, user: Json<UserId>) -> Result<()> {
    let u_id = user.into_inner().u_id;
    usecases::confirm_email_address(&*db.exclusive()?, &u_id)?;
    Ok(Json(()))
}

#[post(
    "/subscribe-to-bbox",
    format = "application/json",
    data = "<coordinates>"
)]
fn subscribe_to_bbox(
    db: sqlite::Connections,
    user: Login,
    coordinates: Json<Vec<json::Coordinate>>,
) -> Result<()> {
    let sw_ne: Vec<_> = coordinates
        .into_inner()
        .into_iter()
        .map(MapPoint::from)
        .collect();
    if sw_ne.len() != 2 {
        return Err(Error::Parameter(ParameterError::Bbox).into());
    }
    let bbox = geo::MapBbox::new(sw_ne[0], sw_ne[1]);
    let Login(username) = user;
    usecases::subscribe_to_bbox(bbox, &username, &mut *db.exclusive()?)?;
    Ok(Json(()))
}

#[delete("/unsubscribe-all-bboxes")]
fn unsubscribe_all_bboxes(db: sqlite::Connections, user: Login) -> Result<()> {
    let Login(username) = user;
    usecases::unsubscribe_all_bboxes_by_username(&mut *db.exclusive()?, &username)?;
    Ok(Json(()))
}

#[get("/bbox-subscriptions")]
fn get_bbox_subscriptions(
    db: sqlite::Connections,
    user: Login,
) -> Result<Vec<json::BboxSubscription>> {
    let Login(username) = user;
    let user_subscriptions = usecases::get_bbox_subscriptions(&username, &*db.shared()?)?
        .into_iter()
        .map(|s| json::BboxSubscription {
            id: s.id,
            south_west_lat: s.bbox.south_west().lat().to_deg(),
            south_west_lng: s.bbox.south_west().lng().to_deg(),
            north_east_lat: s.bbox.north_east().lat().to_deg(),
            north_east_lng: s.bbox.north_east().lng().to_deg(),
        })
        .collect();
    Ok(Json(user_subscriptions))
}

#[post("/entries", format = "application/json", data = "<body>")]
fn post_entry(
    connections: sqlite::Connections,
    mut search_engine: tantivy::SearchEngine,
    body: Json<usecases::NewEntry>,
) -> Result<String> {
    Ok(Json(flows::create_entry(
        &connections,
        &mut search_engine,
        body.into_inner(),
    )?))
}

#[put("/entries/<id>", format = "application/json", data = "<data>")]
fn put_entry(
    connections: sqlite::Connections,
    mut search_engine: tantivy::SearchEngine,
    id: String,
    data: Json<usecases::UpdateEntry>,
) -> Result<String> {
    Ok(Json(
        flows::update_entry(&connections, &mut search_engine, id, data.into_inner())?.id,
    ))
}

#[get("/tags")]
fn get_tags(connections: sqlite::Connections) -> Result<Vec<String>> {
    let tags = connections.shared()?.all_tags()?;
    Ok(Json(tags.into_iter().map(|t| t.id).collect()))
}

#[get("/categories")]
fn get_categories(connections: sqlite::Connections) -> Result<Vec<Category>> {
    let categories = connections.shared()?.all_categories()?;
    Ok(Json(categories))
}

#[get("/categories/<ids>")]
fn get_category(connections: sqlite::Connections, ids: String) -> Result<Vec<Category>> {
    // TODO: Only lookup and return a single entity
    // TODO: Add a new method for searching multiple ids
    let ids = util::split_ids(&ids);
    if ids.is_empty() {
        return Ok(Json(vec![]));
    }
    let categories = connections
        .shared()?
        .all_categories()?
        .into_iter()
        .filter(|c| ids.iter().any(|id| &c.id == id))
        .collect::<Vec<Category>>();
    Ok(Json(categories))
}

#[derive(FromForm, Clone, Serialize)]
struct CsvExport {
    bbox: String,
}

// TODO: CSV export should only be permitted with a valid API key!
// https://github.com/slowtec/openfairdb/issues/147
#[get("/export/entries.csv?<export..>")]
fn csv_export(
    connections: sqlite::Connections,
    search_engine: tantivy::SearchEngine,
    export: Form<CsvExport>,
) -> result::Result<Content<String>, AppError> {
    let bbox = export
        .bbox
        .parse::<geo::MapBbox>()
        .map_err(|_| ParameterError::Bbox)
        .map_err(Error::Parameter)
        .map_err(AppError::Business)?;

    let req = usecases::SearchRequest {
        bbox,
        ids: vec![],
        categories: vec![],
        hash_tags: vec![],
        text: None,
    };

    let entries_categories_and_ratings = {
        let db = connections.shared()?;
        let all_categories: Vec<_> = db.all_categories()?;
        let limit = db.count_entries()? + 100;
        usecases::search(&search_engine, req, limit)?
            .0
            .into_iter()
            .filter_map(|indexed_entry| {
                let IndexedEntry {
                    ref id,
                    ref ratings,
                    ..
                } = indexed_entry;
                if let Ok(entry) = db.get_entry(id) {
                    let categories = all_categories
                        .iter()
                        .filter(|c1| entry.categories.iter().any(|c2| *c2 == c1.id))
                        .cloned()
                        .collect::<Vec<Category>>();
                    Some((entry, categories, ratings.total()))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>()
    };

    let records: Vec<adapters::csv::CsvRecord> = entries_categories_and_ratings
        .into_iter()
        .map(adapters::csv::CsvRecord::from)
        .collect();

    let buff: Vec<u8> = vec![];
    let mut wtr = csv::Writer::from_writer(buff);

    for r in records {
        wtr.serialize(r)?;
    }
    wtr.flush()?;
    let data = String::from_utf8(wtr.into_inner()?)?;

    Ok(Content(ContentType::CSV, data))
}

impl<'r> Responder<'r> for AppError {
    fn respond_to(self, _: &rocket::Request) -> result::Result<Response<'r>, Status> {
        if let AppError::Business(ref err) = self {
            match *err {
                Error::Parameter(ref err) => {
                    return Err(match *err {
                        ParameterError::Credentials | ParameterError::Unauthorized => {
                            Status::Unauthorized
                        }
                        ParameterError::UserExists => <Status>::new(400, "UserExists"),
                        ParameterError::EmailNotConfirmed => {
                            <Status>::new(403, "EmailNotConfirmed")
                        }
                        ParameterError::Forbidden | ParameterError::OwnedTag => Status::Forbidden,
                        _ => Status::BadRequest,
                    });
                }
                Error::Repo(ref err) => {
                    if let RepoError::NotFound = *err {
                        return Err(Status::NotFound);
                    }
                }
                _ => {}
            }
        }
        error!("Error: {}", self);
        Err(Status::InternalServerError)
    }
}
<commit_msg>Limit the max. number of recently changed entries<commit_after>use super::guards::*;

use crate::{
    adapters::{self, json},
    core::{
        prelude::*,
        usecases::{self, DuplicateType},
        util::{self, geo},
    },
    infrastructure::{
        db::{sqlite, tantivy},
        error::AppError,
        flows::prelude as flows,
        notify,
    },
};

use csv;
use rocket::{
    self,
    http::{ContentType, Cookie, Cookies, Status},
    request::Form,
    response::{content::Content, Responder, Response},
    Route,
};
use rocket_contrib::json::Json;
use std::result;

mod count;
pub mod events;
pub mod geocoding;
mod ratings;
mod search;
#[cfg(test)]
pub mod tests;
mod users;

type Result<T> = result::Result<Json<T>, AppError>;

pub fn routes() -> Vec<Route> {
    routes![
        login,
        logout,
        confirm_email_address,
        subscribe_to_bbox,
        get_bbox_subscriptions,
        unsubscribe_all_bboxes,
        get_entry,
        post_entry,
        put_entry,
        events::post_event,
        events::post_event_with_token,
        events::get_event,
        events::get_events,
        events::get_events_with_token,
        events::put_event,
        events::put_event_with_token,
        events::delete_event,
        events::delete_event_with_token,
        users::post_request_password_reset,
        users::post_reset_password,
        users::post_user,
        ratings::post_rating,
        ratings::load_rating,
        users::get_user,
        users::delete_user,
        get_categories,
        get_category,
        get_tags,
        search::get_search,
        get_duplicates,
        get_recently_changed_entries,
        count::get_count_entries,
        count::get_count_tags,
        get_version,
        csv_export,
        get_api
    ]
}

#[derive(Deserialize, Debug, Clone)]
struct UserId {
    u_id: String,
}

#[get("/entries/<ids>")]
fn get_entry(db: sqlite::Connections, ids: String) -> Result<Vec<json::Entry>> {
    // TODO: Only lookup and return a single entity
    // TODO: Add a new method for searching multiple ids
    let ids = util::split_ids(&ids);
    if ids.is_empty() {
        return Ok(Json(vec![]));
    }
    let results = {
        let mut results = Vec::with_capacity(ids.len());
        let db = db.shared()?;
        for e in db.get_entries(&ids)?.into_iter() {
            let r = db.load_ratings_of_entry(&e.id)?;
            results.push(json::Entry::from_entry_with_ratings(e, r));
        }
        results
    };
    Ok(Json(results))
}

// Limit the total number of recently changed entries to avoid cloning
// the whole database!!
const MAX_ENTRIES_RECECENTLY_CHANGED: u64 = 1000;

#[get("/entries/recently-changed?<since>&<with_ratings>&<offset>&<limit>")]
fn get_recently_changed_entries(
    db: sqlite::Connections,
    since: i64,
    with_ratings: Option<bool>,
    offset: Option<u64>,
    mut limit: Option<u64>,
) -> Result<Vec<json::Entry>> {
    let results = {
        let db = db.shared()?;
        let mut total_count = 0;
        if let Some(offset) = offset {
            total_count += offset;
        }
        if let Some(limit) = limit {
            total_count += limit;
        }
        if total_count > MAX_ENTRIES_RECECENTLY_CHANGED {
            log::warn!("Only the latest {} recently changed entries are available", MAX_ENTRIES_RECECENTLY_CHANGED);
            if let Some(offset) = offset {
                limit = Some(MAX_ENTRIES_RECECENTLY_CHANGED - offset.min(MAX_ENTRIES_RECECENTLY_CHANGED));
            } else {
                limit = Some(MAX_ENTRIES_RECECENTLY_CHANGED);
            }
        }
        let entries = db.recently_changed_entries(since.into(), offset, limit)?;
        if with_ratings.unwrap_or(false) {
            let mut results = Vec::with_capacity(entries.len());
            for e in entries.into_iter() {
                let r = db.load_ratings_of_entry(&e.id)?;
                results.push(json::Entry::from_entry_with_ratings(e, r));
            }
            results
        } else {
            entries
                .into_iter()
                .map(|e| json::Entry::from_entry_with_ratings(e, vec![]))
                .collect()
        }
    };
    Ok(Json(results))
}

#[get("/duplicates/<ids>")]
fn get_duplicates(
    db: sqlite::Connections,
    ids: String,
) -> Result<Vec<(String, String, DuplicateType)>> {
    let ids = util::split_ids(&ids);
    if ids.is_empty() {
        return Ok(Json(vec![]));
    }
    let (entries, all_entries) = {
        let db = db.shared()?;
        (db.get_entries(&ids)?, db.all_entries()?)
    };
    let results = usecases::find_duplicates(&entries, &all_entries);
    Ok(Json(results))
}

#[get("/server/version")]
fn get_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

#[get("/server/api.yaml")]
fn get_api() -> Content<&'static str> {
    let data = include_str!("../../../../openapi.yaml");
    let c_type = ContentType::new("text", "yaml");
    Content(c_type, data)
}

#[post("/login", format = "application/json", data = "<login>")]
fn login(
    db: sqlite::Connections,
    mut cookies: Cookies,
    login: Json<usecases::Login>,
) -> Result<()> {
    //TODO: login with email
    let username = usecases::login_with_username(&*db.shared()?, &login.into_inner())?;
    cookies.add_private(
        Cookie::build(COOKIE_USER_KEY, username)
            .same_site(rocket::http::SameSite::None)
            .finish(),
    );
    Ok(Json(()))
}

#[post("/logout", format = "application/json")]
fn logout(mut cookies: Cookies) -> Result<()> {
    cookies.remove_private(Cookie::named(COOKIE_USER_KEY));
    Ok(Json(()))
}

#[post("/confirm-email-address", format = "application/json", data = "<user>")]
fn confirm_email_address(db: sqlite::Connections, user: Json<UserId>) -> Result<()> {
    let u_id = user.into_inner().u_id;
    usecases::confirm_email_address(&*db.exclusive()?, &u_id)?;
    Ok(Json(()))
}

#[post(
    "/subscribe-to-bbox",
    format = "application/json",
    data = "<coordinates>"
)]
fn subscribe_to_bbox(
    db: sqlite::Connections,
    user: Login,
    coordinates: Json<Vec<json::Coordinate>>,
) -> Result<()> {
    let sw_ne: Vec<_> = coordinates
        .into_inner()
        .into_iter()
        .map(MapPoint::from)
        .collect();
    if sw_ne.len() != 2 {
        return Err(Error::Parameter(ParameterError::Bbox).into());
    }
    let bbox = geo::MapBbox::new(sw_ne[0], sw_ne[1]);
    let Login(username) = user;
    usecases::subscribe_to_bbox(bbox, &username, &mut *db.exclusive()?)?;
    Ok(Json(()))
}

#[delete("/unsubscribe-all-bboxes")]
fn unsubscribe_all_bboxes(db: sqlite::Connections, user: Login) -> Result<()> {
    let Login(username) = user;
    usecases::unsubscribe_all_bboxes_by_username(&mut *db.exclusive()?, &username)?;
    Ok(Json(()))
}

#[get("/bbox-subscriptions")]
fn get_bbox_subscriptions(
    db: sqlite::Connections,
    user: Login,
) -> Result<Vec<json::BboxSubscription>> {
    let Login(username) = user;
    let user_subscriptions = usecases::get_bbox_subscriptions(&username, &*db.shared()?)?
        .into_iter()
        .map(|s| json::BboxSubscription {
            id: s.id,
            south_west_lat: s.bbox.south_west().lat().to_deg(),
            south_west_lng: s.bbox.south_west().lng().to_deg(),
            north_east_lat: s.bbox.north_east().lat().to_deg(),
            north_east_lng: s.bbox.north_east().lng().to_deg(),
        })
        .collect();
    Ok(Json(user_subscriptions))
}

#[post("/entries", format = "application/json", data = "<body>")]
fn post_entry(
    connections: sqlite::Connections,
    mut search_engine: tantivy::SearchEngine,
    body: Json<usecases::NewEntry>,
) -> Result<String> {
    Ok(Json(flows::create_entry(
        &connections,
        &mut search_engine,
        body.into_inner(),
    )?))
}

#[put("/entries/<id>", format = "application/json", data = "<data>")]
fn put_entry(
    connections: sqlite::Connections,
    mut search_engine: tantivy::SearchEngine,
    id: String,
    data: Json<usecases::UpdateEntry>,
) -> Result<String> {
    Ok(Json(
        flows::update_entry(&connections, &mut search_engine, id, data.into_inner())?.id,
    ))
}

#[get("/tags")]
fn get_tags(connections: sqlite::Connections) -> Result<Vec<String>> {
    let tags = connections.shared()?.all_tags()?;
    Ok(Json(tags.into_iter().map(|t| t.id).collect()))
}

#[get("/categories")]
fn get_categories(connections: sqlite::Connections) -> Result<Vec<Category>> {
    let categories = connections.shared()?.all_categories()?;
    Ok(Json(categories))
}

#[get("/categories/<ids>")]
fn get_category(connections: sqlite::Connections, ids: String) -> Result<Vec<Category>> {
    // TODO: Only lookup and return a single entity
    // TODO: Add a new method for searching multiple ids
    let ids = util::split_ids(&ids);
    if ids.is_empty() {
        return Ok(Json(vec![]));
    }
    let categories = connections
        .shared()?
        .all_categories()?
        .into_iter()
        .filter(|c| ids.iter().any(|id| &c.id == id))
        .collect::<Vec<Category>>();
    Ok(Json(categories))
}

#[derive(FromForm, Clone, Serialize)]
struct CsvExport {
    bbox: String,
}

// TODO: CSV export should only be permitted with a valid API key!
// https://github.com/slowtec/openfairdb/issues/147
#[get("/export/entries.csv?<export..>")]
fn csv_export(
    connections: sqlite::Connections,
    search_engine: tantivy::SearchEngine,
    export: Form<CsvExport>,
) -> result::Result<Content<String>, AppError> {
    let bbox = export
        .bbox
        .parse::<geo::MapBbox>()
        .map_err(|_| ParameterError::Bbox)
        .map_err(Error::Parameter)
        .map_err(AppError::Business)?;

    let req = usecases::SearchRequest {
        bbox,
        ids: vec![],
        categories: vec![],
        hash_tags: vec![],
        text: None,
    };

    let entries_categories_and_ratings = {
        let db = connections.shared()?;
        let all_categories: Vec<_> = db.all_categories()?;
        let limit = db.count_entries()? + 100;
        usecases::search(&search_engine, req, limit)?
            .0
            .into_iter()
            .filter_map(|indexed_entry| {
                let IndexedEntry {
                    ref id,
                    ref ratings,
                    ..
                } = indexed_entry;
                if let Ok(entry) = db.get_entry(id) {
                    let categories = all_categories
                        .iter()
                        .filter(|c1| entry.categories.iter().any(|c2| *c2 == c1.id))
                        .cloned()
                        .collect::<Vec<Category>>();
                    Some((entry, categories, ratings.total()))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>()
    };

    let records: Vec<adapters::csv::CsvRecord> = entries_categories_and_ratings
        .into_iter()
        .map(adapters::csv::CsvRecord::from)
        .collect();

    let buff: Vec<u8> = vec![];
    let mut wtr = csv::Writer::from_writer(buff);

    for r in records {
        wtr.serialize(r)?;
    }
    wtr.flush()?;
    let data = String::from_utf8(wtr.into_inner()?)?;

    Ok(Content(ContentType::CSV, data))
}

impl<'r> Responder<'r> for AppError {
    fn respond_to(self, _: &rocket::Request) -> result::Result<Response<'r>, Status> {
        if let AppError::Business(ref err) = self {
            match *err {
                Error::Parameter(ref err) => {
                    return Err(match *err {
                        ParameterError::Credentials | ParameterError::Unauthorized => {
                            Status::Unauthorized
                        }
                        ParameterError::UserExists => <Status>::new(400, "UserExists"),
                        ParameterError::EmailNotConfirmed => {
                            <Status>::new(403, "EmailNotConfirmed")
                        }
                        ParameterError::Forbidden | ParameterError::OwnedTag => Status::Forbidden,
                        _ => Status::BadRequest,
                    });
                }
                Error::Repo(ref err) => {
                    if let RepoError::NotFound = *err {
                        return Err(Status::NotFound);
                    }
                }
                _ => {}
            }
        }
        error!("Error: {}", self);
        Err(Status::InternalServerError)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! google compute engine metadata fetcher

use metadata::Metadata;

use errors::*;

pub fn fetch_metadata() -> Result<Metadata> {
    unimplemented!();
}
<commit_msg>providers/gce: initial implementation<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! google compute engine metadata fetcher

use metadata::Metadata;

use errors::*;

use retry;

header! {(MetadataFlavor, "Metadata-Flavor") => [String]}
const GOOGLE: &str = "Google";

fn url_for_key(key: &str) -> String {
    format!("http://metadata.google.internal/computeMetadata/v1/{}", key)
}

// Google's metadata service returns a 200 success even if there is no resource. If an empty body
// was returned, it means there was no result
fn empty_to_none(s: Option<String>) -> Option<String> {
    match s {
        Some(s) => if &s == "" { None } else { Some(s) },
        x => x,
    }
}

pub fn fetch_metadata() -> Result<Metadata> {
    let client = retry::Client::new()?
        .header(MetadataFlavor(GOOGLE.to_owned()))
        .return_on_404(true);
    let public: Option<String> = client.get(retry::Raw, url_for_key("instance/network-interfaces/0/access-configs/0/external-ip")).send()?;
    let local: Option<String> = client.get(retry::Raw, url_for_key("instance/network-interfaces/0/ip")).send()?;
    let hostname: Option<String> = client.get(retry::Raw, url_for_key("instance/hostname")).send()?;

    let ssh_keys = fetch_all_ssh_keys(&client)?;

    Ok(Metadata::builder()
        .add_attribute_if_exists("GCE_IP_LOCAL_0".to_owned(), empty_to_none(local))
        .add_attribute_if_exists("GCE_IP_EXTERNAL_0".to_owned(), empty_to_none(public))
        .add_attribute_if_exists("GCE_HOSTNAME".to_owned(), empty_to_none(hostname.clone()))
        .set_hostname_if_exists(hostname)
        .add_ssh_keys(ssh_keys)?
        .build())
}

fn fetch_all_ssh_keys(client: &retry::Client) -> Result<Vec<String>> {
    let keys = fetch_ssh_keys(client, "instance/attributes/sshKeys")?;
    if !keys.is_empty() {
        return Ok(keys);
    }
    let mut keys = fetch_ssh_keys(client, "instance/attributes/ssh-keys")?;

    let block_project_keys: Option<String> = client.clone().get(retry::Raw, url_for_key("instance/attributes/block-project-ssh-keys")).send()?;

    if block_project_keys == Some("true".to_owned()) {
        return Ok(keys);
    }

    keys.append(&mut fetch_ssh_keys(client, "project/attributes/sshKeys")?);

    Ok(keys)
}

fn fetch_ssh_keys(client: &retry::Client, key: &str) -> Result<Vec<String>> {
    let key_data: Option<String> = client.get(retry::Raw, url_for_key(key)).send()?;
    if let Some(key_data) = key_data {
        let mut keys = Vec::new();
        for l in key_data.lines() {
            if l.is_empty() {
                continue
            }
            let mut l = l.to_owned();
            let index = l.find(':')
                .ok_or("character ':' not found in line in key data")?;
            keys.push(l.split_off(index+1));
        }
        Ok(keys)
    } else {
        // The user must have not provided any keys
        Ok(Vec::new())
    }

}
<|endoftext|>


<commit_before>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::{c_double, c_int};

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection, here is the resulting area anyways.
    NoIntersection(Area)
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
    pub x: c_int,
    pub y: c_int
}

impl Default for Origin {
    fn default() -> Self {
        Origin { x: 0, y: 0 }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Size {
    pub width: c_int,
    pub height: c_int
}

impl Default for Size {
    fn default() -> Self {
        Size { width: 0,
               height: 0 }
    }
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(origin: Origin, size: Size) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       width: size.width,
                       height: size.height })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: c_double, y: c_double) -> (c_double, c_double) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&self, other_box: &Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty =
                wlr_box_intersection(&self.0, &other_box.0, &mut res.0 as *mut _);
            if is_empty {
                IntersectionResult::NoIntersection(res)
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: c_double, y: c_double) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self, transform: wl_output_transform) -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.x == other.x && self.y == other.y && self.height == other.height
        && self.width == other.width
    }
}

impl Eq for Area {}
<commit_msg>Derive Eq/PartialEq for IntersectionResult<commit_after>//! Wrapper for the `wlr_box` type.
//! Note that we renamed it to `Area` to avoid conflicts with Rust's Box.

use std::ops::{Deref, DerefMut};

use libc::{c_double, c_int};

use wlroots_sys::{wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point,
                  wlr_box_empty, wlr_box_intersection, wlr_box_transform};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Result of applying an intersection of two `Area`s.
pub enum IntersectionResult {
    /// This area is the intersection between the two points.
    Intersection(Area),
    /// There was not an intersection, here is the resulting area anyways.
    NoIntersection(Area)
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Origin {
    pub x: c_int,
    pub y: c_int
}

impl Default for Origin {
    fn default() -> Self {
        Origin { x: 0, y: 0 }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct Size {
    pub width: c_int,
    pub height: c_int
}

impl Default for Size {
    fn default() -> Self {
        Size { width: 0,
               height: 0 }
    }
}

#[derive(Debug, Clone, Copy)]
/// Generic geometry-like struct. Container an origin (x, y) point and bounds
/// (width, height).
pub struct Area(pub wlr_box);

impl Default for Area {
    fn default() -> Area {
        Area(wlr_box { x: 0,
                       y: 0,
                       width: 0,
                       height: 0 })
    }
}

impl Area {
    pub fn new(origin: Origin, size: Size) -> Self {
        Area(wlr_box { x: origin.x,
                       y: origin.y,
                       width: size.width,
                       height: size.height })
    }

    /// Finds the closest point within the box to the given point.
    /// If the (x, y) point lies outside of the box, then it finds the closest
    /// corner and returns that.
    ///
    /// Returned value is in form of (x, y).
    pub fn closest_point(&mut self, x: c_double, y: c_double) -> (c_double, c_double) {
        unsafe {
            let (mut dest_x, mut dest_y) = (0.0, 0.0);
            wlr_box_closest_point(&mut self.0, x, y, &mut dest_x, &mut dest_y);
            (dest_x, dest_y)
        }
    }

    /// Gets the intersection of the two areas.
    pub fn intersection(&self, other_box: &Area) -> IntersectionResult {
        unsafe {
            let mut res = Area::default();
            let is_empty =
                wlr_box_intersection(&self.0, &other_box.0, &mut res.0 as *mut _);
            if is_empty {
                IntersectionResult::NoIntersection(res)
            } else {
                IntersectionResult::Intersection(res)
            }
        }
    }

    /// Determines if the box contains the given point.
    pub fn contains_point(&mut self, x: c_double, y: c_double) -> bool {
        unsafe { wlr_box_contains_point(&mut self.0, x, y) }
    }

    /// Determines if the box is empty (e.g if the bounds give it an area of 0).
    pub fn is_empty(&mut self) -> bool {
        unsafe { wlr_box_empty(&mut self.0) }
    }

    /// Transforms the box coordinates and bounds according to the
    /// output transformation.
    ///
    /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° clockwise.
    pub fn transform(&mut self, transform: wl_output_transform) -> Area {
        unsafe {
            let mut res = Area::default();
            wlr_box_transform(&mut self.0, transform, &mut res.0);
            res
        }
    }
}

impl Deref for Area {
    type Target = wlr_box;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Area {
    fn deref_mut(&mut self) -> &mut wlr_box {
        &mut self.0
    }
}

impl PartialEq for Area {
    fn eq(&self, other: &Area) -> bool {
        self.x == other.x && self.y == other.y && self.height == other.height
        && self.width == other.width
    }
}

impl Eq for Area {}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use proto::raftpb::{Entry, Snapshot};

// unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
#[derive(Debug, PartialEq)]
pub struct Unstable {
    // the incoming unstable snapshot, if any.
    pub snapshot: Option<Box<Snapshot>>,
    // all entries that have not yet been written to storage.
    pub entries: Vec<Entry>,
    pub offset: u64,
}

impl Unstable {
    pub fn new(offset: u64) -> Unstable {
        Unstable {
            offset: offset,
            snapshot: None,
            entries: vec![],
        }
    }
    // maybe_first_index returns the last index if it has at least one
    // unstable entry or snapshot.
    pub fn maybe_first_index(&self) -> Option<u64> {
        self.snapshot
            .as_ref()
            .map_or(None, |snap| Some(snap.get_metadata().get_index() + 1))
    }

    pub fn get_snapshot(&self) -> Snapshot {
        return *self.snapshot.as_ref().unwrap().clone();
    }

    // maybe_last_index returns the last index if it has at least one
    // unstable entry or snapshot.
    pub fn maybe_last_index(&self) -> Option<u64> {
        match self.entries.len() {
            0 => {
                self.snapshot
                    .as_ref()
                    .map_or(None, |snap| Some(snap.get_metadata().get_index()))
            }
            len => Some(self.offset + len as u64 - 1),
        }
    }

    // maybe_term returns the term of the entry at index idx, if there
    // is any.
    pub fn maybe_term(&self, idx: u64) -> Option<u64> {
        if idx < self.offset {
            if self.snapshot.is_none() {
                return None;
            }

            let meta = self.snapshot.as_ref().unwrap().get_metadata().clone();
            if idx == meta.get_index() {
                return Some(meta.get_term());
            }
            return None;
        }
        match self.maybe_last_index() {
            None => None,
            Some(last) => {
                if idx > last {
                    return None;
                }
                Some(self.entries[(idx - self.offset) as usize].get_Term())
            }
        }
    }

    pub fn stable_to(&mut self, idx: u64, term: u64) {
        let t = self.maybe_term(idx);
        if t.is_none() {
            return;
        }

        if t.unwrap() == term && idx >= self.offset {
            let start = idx + 1 - self.offset;
            let left = &self.entries.clone()[start as usize..];
            self.entries = vec![];
            self.entries.extend_from_slice(left);
            self.offset = idx + 1;
        }
    }

    pub fn stable_snap_to(&mut self, idx: u64) {
        if self.snapshot.is_none() {
            return;
        }
        if idx == self.snapshot.as_ref().unwrap().get_metadata().get_index() {
            self.snapshot = None;
        }
    }

    pub fn restore(&mut self, snap: Snapshot) {
        self.entries.clear();
        self.offset = snap.get_metadata().get_index() + 1;
        self.snapshot = Some(Box::new(snap));
    }

    pub fn truncate_and_append(&mut self, ents: &[Entry]) {
        let after = ents[0].get_Index() - 1;
        if after == self.offset + self.entries.len() as u64 - 1 {
            self.entries.extend_from_slice(ents);
        } else if after < self.offset {
            // The log is being truncated to before our current offset
            // portion, so set the offset and replace the entries
            self.offset = after + 1;
            self.entries.clear();
            self.entries.extend_from_slice(ents);
        } else {
            // truncate to after and copy to self.entries
            // then append
            let off = self.offset.clone();
            let cut_ents = &self.slice(off, after + 1);
            self.entries = vec![];
            self.entries.extend_from_slice(cut_ents);
            self.entries.extend_from_slice(ents);
        }
    }

    pub fn slice(&mut self, lo: u64, hi: u64) -> Vec<Entry> {
        self.must_check_outofbounds(lo, hi);
        let l = lo as usize;
        let h = hi as usize;
        let off = self.offset as usize;
        return self.entries.drain(l - off..h - off).map(|e| e).collect();
    }

    pub fn must_check_outofbounds(&self, lo: u64, hi: u64) {
        if lo > hi {
            panic!("invalid unstable.slice {} > {}", lo, hi)
        }
        let upper = self.offset + self.entries.len() as u64;
        if lo < self.offset || hi > upper {
            panic!("unstable.slice[{}, {}] out of bound[{}, {}]",
                   lo,
                   hi,
                   self.offset,
                   upper)
        }
    }
}

#[cfg(test)]
mod test {
    use proto::raftpb::{Entry, Snapshot};
    use raft::log_unstable::Unstable;

    fn new_entry(index: u64, term: u64) -> Entry {
        let mut e = Entry::new();
        e.set_Term(term);
        e.set_Index(index);
        e
    }

    fn new_snapshot(index: u64, term: u64) -> Snapshot {
        use proto::raftpb::{SnapshotMetadata, Snapshot};
        let mut snap = Snapshot::new();
        let mut meta = SnapshotMetadata::new();
        meta.set_index(index);
        meta.set_term(term);
        snap.set_metadata(meta);
        snap
    }

    #[test]
    fn test_maybe_first_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            // no snapshot
            (Some(new_entry(5,1)), 5, None, false, 0),
            (None, 0, None, false, 0),
            // has snapshot
            (Some(new_entry(5, 1)), 5, Some(new_snapshot(4,1)), true, 5),
            (None, 5, Some(new_snapshot(4,1)), true, 5),
        ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(vec![], |entry| vec![entry]),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_first_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    #[test]
    fn test_maybe_last_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            (Some(new_entry(5,1)), 5, None, true, 5),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), true, 5),
            // last in snapshot
            (None, 5, Some(new_snapshot(4,1)), true, 4),
            // empty unstable
            (None, 0, None, false, 0),
       ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(vec![], |entry| vec![entry]),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_last_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    #[test]
    fn test_maybe_term() {
        // entry, offset, snap, index, wok, wterm
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, u64, bool, u64)> = vec![
            // term from entries
            (Some(new_entry(5,1)), 5, None, 5, true, 1),
            (Some(new_entry(5,1)), 5, None, 6, false, 0),
            (Some(new_entry(5,1)), 5, None, 4, false, 0),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 5, true, 1),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 6, false, 0),
            // term from snapshot
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 4, true, 1),
            (None, 5, Some(new_snapshot(4,1)), 5, false, 0),
            (None, 5, Some(new_snapshot(4,1)), 4, true, 1),
            (None, 0, None, 5, false, 0),
       ];

        for (entries, offset, snapshot, index, wok, wterm) in tests {
            let u = Unstable {
                entries: entries.map_or(vec![], |entry| vec![entry]),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let term = u.maybe_term(index);
            match term {
                None => assert!(!wok),
                Some(term) => assert_eq!(term, wterm),
            }
        }
    }

    #[test]
    fn test_restore() {
        let mut u = Unstable {
            entries: vec![new_entry(5, 1)],
            offset: 5,
            snapshot: Some(Box::new(new_snapshot(4, 1))),
        };

        let s = new_snapshot(6, 2);
        u.restore(s.clone());

        assert_eq!(u.offset, s.get_metadata().get_index() + 1);
        assert_eq!(u.entries.len(), 0);
        assert_eq!(*u.snapshot.unwrap(), s);
    }

    #[test]
    fn test_stable_to() {
        // entries, offset, snap, index, term, woffset, wlen
        let tests: Vec<(Vec<Entry>, u64, Option<Snapshot>, u64, u64, u64, usize)> = vec![
            (vec![], 0, None, 5, 1, 0, 0),
            // stable to the first entry
            (vec![new_entry(5,1)], 5, None, 5, 1, 6, 0),
            (vec![new_entry(5,1), new_entry(6, 0)], 5, None, 5, 1, 6, 1),
            // stable to the first entry and term mismatch
            (vec![new_entry(6,2)], 5, None, 6, 1, 5, 1),
            // stable to old entry
            (vec![new_entry(5,1)], 5, None, 4, 1, 5, 1),
            (vec![new_entry(5,1)], 5, None, 4, 2, 5, 1),
            // with snapshot
            // stable to the first entry
            (vec![new_entry(5,1)], 5, Some(new_snapshot(4,1)), 5, 1, 6, 0),
            // stable to the first entry
            (vec![new_entry(5,1), new_entry(6,1)], 5, Some(new_snapshot(4,1)), 5, 1, 6, 1),
            // stable to the first entry and term mismatch
            (vec![new_entry(6,2)], 5, Some(new_snapshot(5,1)), 6, 1, 5, 1),
            // stable to snapshot
            (vec![new_entry(5,1)], 5, Some(new_snapshot(4,1)), 4, 1, 5, 1),
            // stable to old entry
            (vec![new_entry(5,2)], 5, Some(new_snapshot(4,2)), 4, 1, 5, 1),
       ];

        for (entries, offset, snapshot, index, term, woffset, wlen) in tests {
            let mut u = Unstable {
                entries: entries,
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            u.stable_to(index, term);
            assert_eq!(u.offset, woffset);
            assert_eq!(u.entries.len(), wlen);
        }
    }

    #[test]
    fn test_truncate_and_append() {
        // entries, offset, snap, to_append, woffset, wentries
        let tests: Vec<(Vec<Entry>,
                        u64,
                        Option<Snapshot>,
                        Vec<Entry>,
                        u64,
                        Vec<Entry>)> = vec![
            // replace to the end
            (vec![new_entry(5, 1)], 5, None,
                vec![new_entry(6, 1), new_entry(7, 1)],
                    5, vec![new_entry(5,1), new_entry(6,1), new_entry(7,1)]),

            // replace to unstable entries
           (vec![new_entry(5, 1)], 5, None,
               vec![new_entry(5, 2), new_entry(6, 2)],
                   5, vec![new_entry(5, 2), new_entry(6, 2)]),

            (vec![new_entry(5, 1)], 5, None,
                vec![new_entry(4, 2), new_entry(5, 2), new_entry(6, 2)],
                    4, vec![new_entry(4,2), new_entry(5, 2), new_entry(6, 2)]),

            // truncate existing entries and append
           (vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 1)], 5, None,
               vec![new_entry(6, 2)],
                   5, vec![new_entry(5, 1), new_entry(6, 2)]),

            (vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 1)], 5, None,
                vec![new_entry(7, 2), new_entry(8, 2)],
                    5, vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 2), new_entry(8, 2)]),
      ];

        for (entries, offset, snapshot, to_append, woffset, wentries) in tests {
            let mut u = Unstable {
                entries: entries,
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            u.truncate_and_append(&to_append);
            assert_eq!(u.offset, woffset);
            assert_eq!(u.entries, wentries);
        }
    }
}
<commit_msg>raft: Address comments<commit_after>#![allow(dead_code)]

use proto::raftpb::{Entry, Snapshot};
use std::ops::RangeTo;

// unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
#[derive(Debug, PartialEq)]
pub struct Unstable {
    // the incoming unstable snapshot, if any.
    pub snapshot: Option<Box<Snapshot>>,
    // all entries that have not yet been written to storage.
    pub entries: Vec<Entry>,
    pub offset: u64,
}

impl Unstable {
    pub fn new(offset: u64) -> Unstable {
        Unstable {
            offset: offset,
            snapshot: None,
            entries: vec![],
        }
    }
    // maybe_first_index returns the last index if it has at least one
    // unstable entry or snapshot.
    pub fn maybe_first_index(&self) -> Option<u64> {
        self.snapshot
            .as_ref()
            .map_or(None, |snap| Some(snap.get_metadata().get_index() + 1))
    }

    pub fn get_snapshot(&self) -> Snapshot {
        return *self.snapshot.as_ref().unwrap().clone();
    }

    // maybe_last_index returns the last index if it has at least one
    // unstable entry or snapshot.
    pub fn maybe_last_index(&self) -> Option<u64> {
        match self.entries.len() {
            0 => {
                self.snapshot
                    .as_ref()
                    .map_or(None, |snap| Some(snap.get_metadata().get_index()))
            }
            len => Some(self.offset + len as u64 - 1),
        }
    }

    // maybe_term returns the term of the entry at index idx, if there
    // is any.
    pub fn maybe_term(&self, idx: u64) -> Option<u64> {
        if idx < self.offset {
            if self.snapshot.is_none() {
                return None;
            }

            let meta = self.snapshot.as_ref().unwrap().get_metadata().clone();
            if idx == meta.get_index() {
                return Some(meta.get_term());
            }
            return None;
        }
        match self.maybe_last_index() {
            None => None,
            Some(last) => {
                if idx > last {
                    return None;
                }
                Some(self.entries[(idx - self.offset) as usize].get_Term())
            }
        }
    }

    pub fn stable_to(&mut self, idx: u64, term: u64) {
        let t = self.maybe_term(idx);
        if t.is_none() {
            return;
        }

        if t.unwrap() == term && idx >= self.offset {
            let start = idx + 1 - self.offset;
            self.entries.drain(RangeTo { end: start as usize });
            self.offset = idx + 1;
        }
    }

    pub fn stable_snap_to(&mut self, idx: u64) {
        if self.snapshot.is_none() {
            return;
        }
        if idx == self.snapshot.as_ref().unwrap().get_metadata().get_index() {
            self.snapshot = None;
        }
    }

    pub fn restore(&mut self, snap: Snapshot) {
        self.entries.clear();
        self.offset = snap.get_metadata().get_index() + 1;
        self.snapshot = Some(Box::new(snap));
    }

    pub fn truncate_and_append(&mut self, ents: &[Entry]) {
        let after = ents[0].get_Index() - 1;
        if after == self.offset + self.entries.len() as u64 - 1 {
            self.entries.extend_from_slice(ents);
        } else if after < self.offset {
            // The log is being truncated to before our current offset
            // portion, so set the offset and replace the entries
            self.offset = after + 1;
            self.entries.clear();
            self.entries.extend_from_slice(ents);
        } else {
            // truncate to after and copy to self.entries
            // then append
            let off = self.offset.clone();
            let cut_ents = &self.slice(off, after + 1);
            self.entries = vec![];
            self.entries.extend_from_slice(cut_ents);
            self.entries.extend_from_slice(ents);
        }
    }

    pub fn slice(&mut self, lo: u64, hi: u64) -> Vec<Entry> {
        self.must_check_outofbounds(lo, hi);
        let l = lo as usize;
        let h = hi as usize;
        let off = self.offset as usize;
        return self.entries.drain(l - off..h - off).map(|e| e).collect();
    }

    pub fn must_check_outofbounds(&self, lo: u64, hi: u64) {
        if lo > hi {
            panic!("invalid unstable.slice {} > {}", lo, hi)
        }
        let upper = self.offset + self.entries.len() as u64;
        if lo < self.offset || hi > upper {
            panic!("unstable.slice[{}, {}] out of bound[{}, {}]",
                   lo,
                   hi,
                   self.offset,
                   upper)
        }
    }
}

#[cfg(test)]
mod test {
    use proto::raftpb::{Entry, Snapshot};
    use raft::log_unstable::Unstable;

    fn new_entry(index: u64, term: u64) -> Entry {
        let mut e = Entry::new();
        e.set_Term(term);
        e.set_Index(index);
        e
    }

    fn new_snapshot(index: u64, term: u64) -> Snapshot {
        use proto::raftpb::{SnapshotMetadata, Snapshot};
        let mut snap = Snapshot::new();
        let mut meta = SnapshotMetadata::new();
        meta.set_index(index);
        meta.set_term(term);
        snap.set_metadata(meta);
        snap
    }

    #[test]
    fn test_maybe_first_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            // no snapshot
            (Some(new_entry(5,1)), 5, None, false, 0),
            (None, 0, None, false, 0),
            // has snapshot
            (Some(new_entry(5, 1)), 5, Some(new_snapshot(4,1)), true, 5),
            (None, 5, Some(new_snapshot(4,1)), true, 5),
        ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(vec![], |entry| vec![entry]),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_first_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    #[test]
    fn test_maybe_last_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            (Some(new_entry(5,1)), 5, None, true, 5),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), true, 5),
            // last in snapshot
            (None, 5, Some(new_snapshot(4,1)), true, 4),
            // empty unstable
            (None, 0, None, false, 0),
       ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(vec![], |entry| vec![entry]),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_last_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    #[test]
    fn test_maybe_term() {
        // entry, offset, snap, index, wok, wterm
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, u64, bool, u64)> = vec![
            // term from entries
            (Some(new_entry(5,1)), 5, None, 5, true, 1),
            (Some(new_entry(5,1)), 5, None, 6, false, 0),
            (Some(new_entry(5,1)), 5, None, 4, false, 0),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 5, true, 1),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 6, false, 0),
            // term from snapshot
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 4, true, 1),
            (None, 5, Some(new_snapshot(4,1)), 5, false, 0),
            (None, 5, Some(new_snapshot(4,1)), 4, true, 1),
            (None, 0, None, 5, false, 0),
       ];

        for (entries, offset, snapshot, index, wok, wterm) in tests {
            let u = Unstable {
                entries: entries.map_or(vec![], |entry| vec![entry]),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let term = u.maybe_term(index);
            match term {
                None => assert!(!wok),
                Some(term) => assert_eq!(term, wterm),
            }
        }
    }

    #[test]
    fn test_restore() {
        let mut u = Unstable {
            entries: vec![new_entry(5, 1)],
            offset: 5,
            snapshot: Some(Box::new(new_snapshot(4, 1))),
        };

        let s = new_snapshot(6, 2);
        u.restore(s.clone());

        assert_eq!(u.offset, s.get_metadata().get_index() + 1);
        assert_eq!(u.entries.len(), 0);
        assert_eq!(*u.snapshot.unwrap(), s);
    }

    #[test]
    fn test_stable_to() {
        // entries, offset, snap, index, term, woffset, wlen
        let tests: Vec<(Vec<Entry>, u64, Option<Snapshot>, u64, u64, u64, usize)> = vec![
            (vec![], 0, None, 5, 1, 0, 0),
            // stable to the first entry
            (vec![new_entry(5,1)], 5, None, 5, 1, 6, 0),
            (vec![new_entry(5,1), new_entry(6, 0)], 5, None, 5, 1, 6, 1),
            // stable to the first entry and term mismatch
            (vec![new_entry(6,2)], 5, None, 6, 1, 5, 1),
            // stable to old entry
            (vec![new_entry(5,1)], 5, None, 4, 1, 5, 1),
            (vec![new_entry(5,1)], 5, None, 4, 2, 5, 1),
            // with snapshot
            // stable to the first entry
            (vec![new_entry(5,1)], 5, Some(new_snapshot(4,1)), 5, 1, 6, 0),
            // stable to the first entry
            (vec![new_entry(5,1), new_entry(6,1)], 5, Some(new_snapshot(4,1)), 5, 1, 6, 1),
            // stable to the first entry and term mismatch
            (vec![new_entry(6,2)], 5, Some(new_snapshot(5,1)), 6, 1, 5, 1),
            // stable to snapshot
            (vec![new_entry(5,1)], 5, Some(new_snapshot(4,1)), 4, 1, 5, 1),
            // stable to old entry
            (vec![new_entry(5,2)], 5, Some(new_snapshot(4,2)), 4, 1, 5, 1),
       ];

        for (entries, offset, snapshot, index, term, woffset, wlen) in tests {
            let mut u = Unstable {
                entries: entries,
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            u.stable_to(index, term);
            assert_eq!(u.offset, woffset);
            assert_eq!(u.entries.len(), wlen);
        }
    }

    #[test]
    fn test_truncate_and_append() {
        // entries, offset, snap, to_append, woffset, wentries
        let tests: Vec<(Vec<Entry>,
                        u64,
                        Option<Snapshot>,
                        Vec<Entry>,
                        u64,
                        Vec<Entry>)> = vec![
            // replace to the end
            (vec![new_entry(5, 1)], 5, None,
                vec![new_entry(6, 1), new_entry(7, 1)],
                    5, vec![new_entry(5,1), new_entry(6,1), new_entry(7,1)]),

            // replace to unstable entries
           (vec![new_entry(5, 1)], 5, None,
               vec![new_entry(5, 2), new_entry(6, 2)],
                   5, vec![new_entry(5, 2), new_entry(6, 2)]),

            (vec![new_entry(5, 1)], 5, None,
                vec![new_entry(4, 2), new_entry(5, 2), new_entry(6, 2)],
                    4, vec![new_entry(4,2), new_entry(5, 2), new_entry(6, 2)]),

            // truncate existing entries and append
           (vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 1)], 5, None,
               vec![new_entry(6, 2)],
                   5, vec![new_entry(5, 1), new_entry(6, 2)]),

            (vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 1)], 5, None,
                vec![new_entry(7, 2), new_entry(8, 2)],
                    5, vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 2), new_entry(8, 2)]),
      ];

        for (entries, offset, snapshot, to_append, woffset, wentries) in tests {
            let mut u = Unstable {
                entries: entries,
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            u.truncate_and_append(&to_append);
            assert_eq!(u.offset, woffset);
            assert_eq!(u.entries, wentries);
        }
    }
}
<|endoftext|>


<commit_before>use autoconf;
use clap::App;
use clap::Arg;
use clap::ArgMatches;

pub fn cli_clap(number: &u32) -> ArgMatches {
    let application = App::new(autoconf::package())
        .about("Parses an input file to do awesome things")
        .version(autoconf::version_cli())
        .author("Owen Synge <osynge@googlemail.com>")
        .arg(
            Arg::with_name("verbose")
                .help("Increase log output.")
                .short("v")
                .multiple(true)
                .long("verbose"),
        )
        .arg(
            Arg::with_name("quiet")
                .help("Decrease log output.")
                .short("q")
                .multiple(true)
                .long("quiet"),
        )
        .arg(
            Arg::with_name("rdbms")
                .long("rdbms")
                .value_name("FILE_RDBMS")
                .help("sqlite rdbms file.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("env")
                .short("e")
                .long("env")
                .value_name("ENVIROMENT_VARIABLE")
                .help("Which enviroment variables to process")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-jobs")
                .long("dir-jobs")
                .value_name("DIR_JOB")
                .help("directory storing json jobs.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-sh")
                .long("dir-sh")
                .value_name("DIR_SHELL")
                .help("directory storing jobs shell scripts.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-py")
                .long("dir-py")
                .value_name("DIR_PYTHON")
                .help("directory storing jobs python scripts.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("config")
                .short("c")
                .long("config")
                .value_name("FILE")
                .help("Sets a custom config file")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("TARGET")
                .help("Sets the target to be selected, so jobs can be matched to provides. Defaults to 'execution'.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("list-provides")
                .long("list-provides")
                .help("List all jobs sorted by the functions they provide."),
        )
        .arg(
            Arg::with_name("list-target")
                .long("list-target")
                .help("List jobs by the target they provide. Not all jobs have a target."),
        )
        .arg(Arg::with_name("session").long("session").help("session"));
    let matches = application.get_matches();
    return matches;
}
<commit_msg>Use lifetime functions<commit_after>use autoconf;
use clap::App;
use clap::Arg;
use clap::ArgMatches;

pub fn cli_clap<'a>() -> ArgMatches<'a> {
    let application = App::new(autoconf::package())
        .about("Parses an input file to do awesome things")
        .version(autoconf::version_cli())
        .author("Owen Synge <osynge@googlemail.com>")
        .arg(
            Arg::with_name("verbose")
                .help("Increase log output.")
                .short("v")
                .multiple(true)
                .long("verbose"),
        )
        .arg(
            Arg::with_name("quiet")
                .help("Decrease log output.")
                .short("q")
                .multiple(true)
                .long("quiet"),
        )
        .arg(
            Arg::with_name("rdbms")
                .long("rdbms")
                .value_name("FILE_RDBMS")
                .help("sqlite rdbms file.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("env")
                .short("e")
                .long("env")
                .value_name("ENVIROMENT_VARIABLE")
                .help("Which enviroment variables to process")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-jobs")
                .long("dir-jobs")
                .value_name("DIR_JOB")
                .help("directory storing json jobs.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-sh")
                .long("dir-sh")
                .value_name("DIR_SHELL")
                .help("directory storing jobs shell scripts.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dir-py")
                .long("dir-py")
                .value_name("DIR_PYTHON")
                .help("directory storing jobs python scripts.")
                .multiple(true)
                .takes_value(true),
        )
        .arg(
            Arg::with_name("config")
                .short("c")
                .long("config")
                .value_name("FILE")
                .help("Sets a custom config file")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("TARGET")
                .help("Sets the target to be selected, so jobs can be matched to provides. Defaults to 'execution'.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("list-provides")
                .long("list-provides")
                .help("List all jobs sorted by the functions they provide."),
        )
        .arg(
            Arg::with_name("list-target")
                .long("list-target")
                .help("List jobs by the target they provide. Not all jobs have a target."),
        )
        .arg(Arg::with_name("session").long("session").help("session"));
    let matches = application.get_matches();
    return matches;
}
<|endoftext|>


<commit_before>use std::vec;
use std::slice;
use std::iter;
use std::cmp;

/// A **TrustedIterator** has exact size, always.
///
/// **Note:** TrustedIterator is *Experimental.*
pub unsafe trait TrustedIterator : ExactSizeIterator
{
    /* no methods */
}

unsafe impl TrustedIterator for ::std::ops::Range<usize> { }
unsafe impl TrustedIterator for ::std::ops::Range<u32> { }
unsafe impl TrustedIterator for ::std::ops::Range<i32> { }
unsafe impl TrustedIterator for ::std::ops::Range<u16> { }
unsafe impl TrustedIterator for ::std::ops::Range<i16> { }
unsafe impl TrustedIterator for ::std::ops::Range<u8> { }
unsafe impl TrustedIterator for ::std::ops::Range<i8> { }
unsafe impl<'a, T> TrustedIterator for slice::Iter<'a, T> { }
unsafe impl<'a, T> TrustedIterator for slice::IterMut<'a, T> { }
unsafe impl<T> TrustedIterator for vec::IntoIter<T> { }

unsafe impl<I> TrustedIterator for iter::Rev<I> where
    I: DoubleEndedIterator + TrustedIterator,
{ }
unsafe impl<I> TrustedIterator for iter::Take<I> where
    I: TrustedIterator,
{ }

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// **ZipTrusted** is an experimental version of **Zip**, and it can only use iterators that are
/// known to provide their exact size up front. The lockstep iteration can then compile to faster
/// code, ideally not checking more than once per lap for the end of iteration.
///
/// The iterator **ZipTrusted\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ```
/// use itertools::ZipTrusted;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in ZipTrusted::new((0..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct ZipTrusted<T> {
    length: usize,
    t: T
}

trait SetLength {
    fn set_length(&mut self);
}

impl<T> ZipTrusted<T> where ZipTrusted<T>: SetLength
{
    /// Create a new **ZipTrusted** from a tuple of iterators.
    #[inline]
    pub fn new(t: T) -> ZipTrusted<T>
    {
        let mut iter = ZipTrusted {
            length: 0,
            t: t,
        };
        iter.set_length();
        iter
    }
}

macro_rules! impl_zip_trusted {
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> SetLength for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            #[inline]
            fn set_length(&mut self)
            {
                let len = ::std::usize::MAX;
                let ($(ref $B,)*) = self.t;
                $(
                    let (l, h) = $B.size_hint();
                    let len = cmp::min(len, l);
                    debug_assert!(Some(l) == h);
                )*
                self.length = len;
            }
        }

        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            type Item = ($($B::Item,)*);

            fn next(&mut self) -> Option<Self::Item>
            {
                let ($(ref mut $B,)*) = self.t;

                if self.length == 0 {
                    return None
                }
                $(
                    let next_opt = $B.next();
                    let $B;
                    unsafe {
                        ::std::intrinsics::assume(match next_opt {
                            None => false,
                            Some(_) => true,
                        });
                        $B = match next_opt {
                            None => return None,
                            Some(elt) => elt
                        };
                    }
                )*
                self.length -= 1;
                Some(($($B,)*))
            }

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

        #[allow(non_snake_case)]
        impl<$($B),*> ExactSizeIterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        { }
    );
}

impl_zip_trusted!(A);
impl_zip_trusted!(A, B);
impl_zip_trusted!(A, B, C);
impl_zip_trusted!(A, B, C, D);
impl_zip_trusted!(A, B, C, D, E);
impl_zip_trusted!(A, B, C, D, E, F);
impl_zip_trusted!(A, B, C, D, E, F, G);
impl_zip_trusted!(A, B, C, D, E, F, G, H);
impl_zip_trusted!(A, B, C, D, E, F, G, H, I);

<commit_msg>Fix helper trait for ZipTrusted (unstable)<commit_after>use std::vec;
use std::slice;
use std::iter;
use std::cmp;

/// A **TrustedIterator** has exact size, always.
///
/// **Note:** TrustedIterator is *Experimental.*
pub unsafe trait TrustedIterator : ExactSizeIterator
{
    /* no methods */
}

unsafe impl TrustedIterator for ::std::ops::Range<usize> { }
unsafe impl TrustedIterator for ::std::ops::Range<u32> { }
unsafe impl TrustedIterator for ::std::ops::Range<i32> { }
unsafe impl TrustedIterator for ::std::ops::Range<u16> { }
unsafe impl TrustedIterator for ::std::ops::Range<i16> { }
unsafe impl TrustedIterator for ::std::ops::Range<u8> { }
unsafe impl TrustedIterator for ::std::ops::Range<i8> { }
unsafe impl<'a, T> TrustedIterator for slice::Iter<'a, T> { }
unsafe impl<'a, T> TrustedIterator for slice::IterMut<'a, T> { }
unsafe impl<T> TrustedIterator for vec::IntoIter<T> { }

unsafe impl<I> TrustedIterator for iter::Rev<I> where
    I: DoubleEndedIterator + TrustedIterator,
{ }
unsafe impl<I> TrustedIterator for iter::Take<I> where
    I: TrustedIterator,
{ }

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// **ZipTrusted** is an experimental version of **Zip**, and it can only use iterators that are
/// known to provide their exact size up front. The lockstep iteration can then compile to faster
/// code, ideally not checking more than once per lap for the end of iteration.
///
/// The iterator **ZipTrusted\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ```
/// use itertools::ZipTrusted;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in ZipTrusted::new((0..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct ZipTrusted<T> {
    length: usize,
    t: T
}

pub trait SetLength {
    fn set_length(&mut self);
}

impl<T> ZipTrusted<T> where ZipTrusted<T>: SetLength
{
    /// Create a new **ZipTrusted** from a tuple of iterators.
    #[inline]
    pub fn new(t: T) -> ZipTrusted<T>
    {
        let mut iter = ZipTrusted {
            length: 0,
            t: t,
        };
        iter.set_length();
        iter
    }
}

macro_rules! impl_zip_trusted {
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> SetLength for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            #[inline]
            fn set_length(&mut self)
            {
                let len = ::std::usize::MAX;
                let ($(ref $B,)*) = self.t;
                $(
                    let (l, h) = $B.size_hint();
                    let len = cmp::min(len, l);
                    debug_assert!(Some(l) == h);
                )*
                self.length = len;
            }
        }

        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            type Item = ($($B::Item,)*);

            fn next(&mut self) -> Option<Self::Item>
            {
                let ($(ref mut $B,)*) = self.t;

                if self.length == 0 {
                    return None
                }
                $(
                    let next_opt = $B.next();
                    let $B;
                    unsafe {
                        ::std::intrinsics::assume(match next_opt {
                            None => false,
                            Some(_) => true,
                        });
                        $B = match next_opt {
                            None => return None,
                            Some(elt) => elt
                        };
                    }
                )*
                self.length -= 1;
                Some(($($B,)*))
            }

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

        #[allow(non_snake_case)]
        impl<$($B),*> ExactSizeIterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        { }
    );
}

impl_zip_trusted!(A);
impl_zip_trusted!(A, B);
impl_zip_trusted!(A, B, C);
impl_zip_trusted!(A, B, C, D);
impl_zip_trusted!(A, B, C, D, E);
impl_zip_trusted!(A, B, C, D, E, F);
impl_zip_trusted!(A, B, C, D, E, F, G);
impl_zip_trusted!(A, B, C, D, E, F, G, H);
impl_zip_trusted!(A, B, C, D, E, F, G, H, I);

<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    let root = Path::new(std::os::getenv("CARGO_MANIFEST_DIR").unwrap())
        .join("libvorbis");

    let config = gcc::Config {
        include_directories: vec![
            root.join("include"),
            root.join("lib"),
            Path::new(std::os::getenv("DEP_OGG_INCLUDE").unwrap()),
        ],
        definitions: vec![
            ("_USRDLL".to_string(), None),
            ("LIBVORBIS_EXPORTS".to_string(), None)
        ],
        .. std::default::Default::default()
    };

    println!("cargo:include={}", root.join("include").as_str().unwrap());

    gcc::compile_library("libvorbis.a", &config, &[
        "libvorbis/lib/analysis.c",
        "libvorbis/lib/bitrate.c",
        "libvorbis/lib/block.c",
        "libvorbis/lib/codebook.c",
        "libvorbis/lib/envelope.c",
        "libvorbis/lib/floor0.c",
        "libvorbis/lib/floor1.c",
        "libvorbis/lib/info.c",
        "libvorbis/lib/lookup.c",
        "libvorbis/lib/lpc.c",
        "libvorbis/lib/lsp.c",
        "libvorbis/lib/mapping0.c",
        "libvorbis/lib/mdct.c",
        "libvorbis/lib/psy.c",
        "libvorbis/lib/registry.c",
        "libvorbis/lib/res0.c",
        "libvorbis/lib/sharedbook.c",
        "libvorbis/lib/smallft.c",
        "libvorbis/lib/synthesis.c",
        "libvorbis/lib/vorbisenc.c",
        "libvorbis/lib/window.c",
    ]);
}
<commit_msg>Export src directory for dependencies<commit_after>extern crate gcc;

fn main() {
    let root = Path::new(std::os::getenv("CARGO_MANIFEST_DIR").unwrap())
        .join("libvorbis");

    let config = gcc::Config {
        include_directories: vec![
            root.join("include"),
            root.join("lib"),
            Path::new(std::os::getenv("DEP_OGG_INCLUDE").unwrap()),
        ],
        definitions: vec![
            ("_USRDLL".to_string(), None),
            ("LIBVORBIS_EXPORTS".to_string(), None)
        ],
        .. std::default::Default::default()
    };

    println!("cargo:include={}", root.join("include").as_str().unwrap());
    println!("cargo:src={}", root.join("lib").as_str().unwrap());

    gcc::compile_library("libvorbis.a", &config, &[
        "libvorbis/lib/analysis.c",
        "libvorbis/lib/bitrate.c",
        "libvorbis/lib/block.c",
        "libvorbis/lib/codebook.c",
        "libvorbis/lib/envelope.c",
        "libvorbis/lib/floor0.c",
        "libvorbis/lib/floor1.c",
        "libvorbis/lib/info.c",
        "libvorbis/lib/lookup.c",
        "libvorbis/lib/lpc.c",
        "libvorbis/lib/lsp.c",
        "libvorbis/lib/mapping0.c",
        "libvorbis/lib/mdct.c",
        "libvorbis/lib/psy.c",
        "libvorbis/lib/registry.c",
        "libvorbis/lib/res0.c",
        "libvorbis/lib/sharedbook.c",
        "libvorbis/lib/smallft.c",
        "libvorbis/lib/synthesis.c",
        "libvorbis/lib/vorbisenc.c",
        "libvorbis/lib/window.c",
    ]);
}
<|endoftext|>


<commit_before>use theme::Style;
use super::Span;
use super::chunk::Chunk;
use super::row::Row;
use super::chunk_iterator::ChunkIterator;
use super::segment::Segment;

use super::SpanLinesIterator;

use std::borrow::Cow;

fn input() -> Vec<Span<'static>> {
    vec![
        Span {
            text: Cow::Borrowed("A beautiful "),
            style: Style::none(),
        },
        Span {
            text: Cow::Borrowed("boat"),
            style: Style::none(),
        },
        Span {
            text: Cow::Borrowed(" isn't it?\nYes indeed, my "),
            style: Style::none(),
        },
        Span {
            text: Cow::Borrowed("Super"),
            style: Style::none(),
        },
        Span {
            text: Cow::Borrowed("Captain !"),
            style: Style::none(),
        },
    ]
}

#[test]
fn test_lines_iter() {
    let input = input();

    let iter = SpanLinesIterator::new(&input, 16);
    let rows: Vec<Row> = iter.collect();
    let spans: Vec<_> = rows.iter().map(|row| row.resolve(&input)).collect();

    assert_eq!(
        &spans[..],
        &[
            vec![
                Span {
                    text: Cow::Borrowed("A beautiful "),
                    style: Style::none(),
                },
                Span {
                    text: Cow::Borrowed("boat"),
                    style: Style::none(),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("isn\'t it?"),
                    style: Style::none(),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("Yes indeed, my "),
                    style: Style::none(),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("Super"),
                    style: Style::none(),
                },
                Span {
                    text: Cow::Borrowed("Captain !"),
                    style: Style::none(),
                },
            ]
        ]
    );

    assert_eq!(
        &rows[..],
        &[
            Row {
                segments: vec![
                    Segment {
                        span_id: 0,
                        start: 0,
                        end: 12,
                        width: 12,
                    },
                    Segment {
                        span_id: 1,
                        start: 0,
                        end: 4,
                        width: 4,
                    },
                ],
                width: 16,
            },
            Row {
                segments: vec![
                    Segment {
                        span_id: 2,
                        start: 1,
                        end: 10,
                        width: 9,
                    },
                ],
                width: 9,
            },
            Row {
                segments: vec![
                    Segment {
                        span_id: 2,
                        start: 11,
                        end: 26,
                        width: 15,
                    },
                ],
                width: 15,
            },
            Row {
                segments: vec![
                    Segment {
                        span_id: 3,
                        start: 0,
                        end: 5,
                        width: 5,
                    },
                    Segment {
                        span_id: 4,
                        start: 0,
                        end: 9,
                        width: 9,
                    },
                ],
                width: 14,
            }
        ]
    );
}

#[test]
fn test_chunk_iter() {
    let input = input();

    let iter = ChunkIterator::new(&input);
    let chunks: Vec<Chunk> = iter.collect();

    assert_eq!(
        &chunks[..],
        &[
            Chunk {
                width: 2,
                segments: vec![
                    Segment {
                        span_id: 0,
                        start: 0,
                        end: 2,
                        width: 2,
                    }.with_text("A "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 10,
                segments: vec![
                    Segment {
                        span_id: 0,
                        start: 2,
                        end: 12,
                        width: 10,
                    }.with_text("beautiful "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 5,
                segments: vec![
                    Segment {
                        span_id: 1,
                        start: 0,
                        end: 4,
                        width: 4,
                    }.with_text("boat"),
                    Segment {
                        span_id: 2,
                        start: 0,
                        end: 1,
                        width: 1,
                    }.with_text(" "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 6,
                segments: vec![
                    // "isn't "
                    Segment {
                        span_id: 2,
                        start: 1,
                        end: 7,
                        width: 6,
                    }.with_text("isn't "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 3,
                segments: vec![
                    // "it?\n"
                    Segment {
                        span_id: 2,
                        start: 7,
                        end: 11,
                        width: 3,
                    }.with_text("it?\n"),
                ],
                hard_stop: true,
                ends_with_space: false,
            },
            Chunk {
                width: 4,
                segments: vec![
                    // "Yes "
                    Segment {
                        span_id: 2,
                        start: 11,
                        end: 15,
                        width: 4,
                    }.with_text("Yes "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 8,
                segments: vec![
                    // "indeed, "
                    Segment {
                        span_id: 2,
                        start: 15,
                        end: 23,
                        width: 8,
                    }.with_text("indeed, "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 3,
                segments: vec![
                    // "my "
                    Segment {
                        span_id: 2,
                        start: 23,
                        end: 26,
                        width: 3,
                    }.with_text("my "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 14,
                segments: vec![
                    // "Super"
                    Segment {
                        span_id: 3,
                        start: 0,
                        end: 5,
                        width: 5,
                    }.with_text("Super"),
                    // "Captain !"
                    Segment {
                        span_id: 4,
                        start: 0,
                        end: 9,
                        width: 9,
                    }.with_text("Captain !"),
                ],
                hard_stop: false,
                ends_with_space: false,
            }
        ]
    );
}
<commit_msg>Add span tests from markdown<commit_after>use super::Span;
use super::SpanLinesIterator;
use super::chunk::Chunk;
use super::chunk_iterator::ChunkIterator;
use super::row::Row;
use super::segment::Segment;
use std::borrow::Cow;
use theme::Style;

fn input() -> Vec<Span<'static>> {
    vec![
        Span {
            text: Cow::Borrowed("A beautiful "),
            style: Style::none(),
        },
        Span {
            text: Cow::Borrowed("boat"),
            style: Style::none(),
        },
        Span {
            text: Cow::Borrowed(" isn't it?\nYes indeed, my "),
            style: Style::none(),
        },
        Span {
            text: Cow::Borrowed("Super"),
            style: Style::none(),
        },
        Span {
            text: Cow::Borrowed("Captain !"),
            style: Style::none(),
        },
    ]
}

#[cfg(feature = "markdown")]
#[test]
fn test_lines_markdown() {
    let input = r"
A beautiful *boat* isn't it?
Yes indeed, my **Super**Captain !";

    let input_spans = ::utils::markup::markdown::parse(input);
    let iter = SpanLinesIterator::new(&input_spans, 16);
    let rows: Vec<Row> = iter.collect();
    let output_spans: Vec<_> =
        rows.iter().map(|row| row.resolve(&input_spans)).collect();

    assert_eq!(
        &output_spans[..],
        &[
            vec![
                Span {
                    text: Cow::Borrowed("A beautiful "),
                    style: Style::none(),
                },
                Span {
                    text: Cow::Borrowed("boat"),
                    style: Style::from(Effect::Italic),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("isn\'t it?"),
                    style: Style::none(),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("Yes indeed, my "),
                    style: Style::none(),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("Super"),
                    style: Style::from(Effect::Bold),
                },
                Span {
                    text: Cow::Borrowed("Captain "),
                    style: Style::none(),
                },
                Span {
                    text: Cow::Borrowed("!"),
                    style: Style::none(),
                },
            ]
        ]
    );
}

#[test]
fn test_lines_iter() {
    let input = input();

    let iter = SpanLinesIterator::new(&input, 16);
    let rows: Vec<Row> = iter.collect();
    let spans: Vec<_> = rows.iter().map(|row| row.resolve(&input)).collect();

    assert_eq!(
        &spans[..],
        &[
            vec![
                Span {
                    text: Cow::Borrowed("A beautiful "),
                    style: Style::none(),
                },
                Span {
                    text: Cow::Borrowed("boat"),
                    style: Style::none(),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("isn\'t it?"),
                    style: Style::none(),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("Yes indeed, my "),
                    style: Style::none(),
                },
            ],
            vec![
                Span {
                    text: Cow::Borrowed("Super"),
                    style: Style::none(),
                },
                Span {
                    text: Cow::Borrowed("Captain !"),
                    style: Style::none(),
                },
            ]
        ]
    );

    assert_eq!(
        &rows[..],
        &[
            Row {
                segments: vec![
                    Segment {
                        span_id: 0,
                        start: 0,
                        end: 12,
                        width: 12,
                    },
                    Segment {
                        span_id: 1,
                        start: 0,
                        end: 4,
                        width: 4,
                    },
                ],
                width: 16,
            },
            Row {
                segments: vec![
                    Segment {
                        span_id: 2,
                        start: 1,
                        end: 10,
                        width: 9,
                    },
                ],
                width: 9,
            },
            Row {
                segments: vec![
                    Segment {
                        span_id: 2,
                        start: 11,
                        end: 26,
                        width: 15,
                    },
                ],
                width: 15,
            },
            Row {
                segments: vec![
                    Segment {
                        span_id: 3,
                        start: 0,
                        end: 5,
                        width: 5,
                    },
                    Segment {
                        span_id: 4,
                        start: 0,
                        end: 9,
                        width: 9,
                    },
                ],
                width: 14,
            }
        ]
    );
}

#[test]
fn test_chunk_iter() {
    let input = input();

    let iter = ChunkIterator::new(&input);
    let chunks: Vec<Chunk> = iter.collect();

    assert_eq!(
        &chunks[..],
        &[
            Chunk {
                width: 2,
                segments: vec![
                    Segment {
                        span_id: 0,
                        start: 0,
                        end: 2,
                        width: 2,
                    }.with_text("A "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 10,
                segments: vec![
                    Segment {
                        span_id: 0,
                        start: 2,
                        end: 12,
                        width: 10,
                    }.with_text("beautiful "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 5,
                segments: vec![
                    Segment {
                        span_id: 1,
                        start: 0,
                        end: 4,
                        width: 4,
                    }.with_text("boat"),
                    Segment {
                        span_id: 2,
                        start: 0,
                        end: 1,
                        width: 1,
                    }.with_text(" "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 6,
                segments: vec![
                    // "isn't "
                    Segment {
                        span_id: 2,
                        start: 1,
                        end: 7,
                        width: 6,
                    }.with_text("isn't "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 3,
                segments: vec![
                    // "it?\n"
                    Segment {
                        span_id: 2,
                        start: 7,
                        end: 11,
                        width: 3,
                    }.with_text("it?\n"),
                ],
                hard_stop: true,
                ends_with_space: false,
            },
            Chunk {
                width: 4,
                segments: vec![
                    // "Yes "
                    Segment {
                        span_id: 2,
                        start: 11,
                        end: 15,
                        width: 4,
                    }.with_text("Yes "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 8,
                segments: vec![
                    // "indeed, "
                    Segment {
                        span_id: 2,
                        start: 15,
                        end: 23,
                        width: 8,
                    }.with_text("indeed, "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 3,
                segments: vec![
                    // "my "
                    Segment {
                        span_id: 2,
                        start: 23,
                        end: 26,
                        width: 3,
                    }.with_text("my "),
                ],
                hard_stop: false,
                ends_with_space: true,
            },
            Chunk {
                width: 14,
                segments: vec![
                    // "Super"
                    Segment {
                        span_id: 3,
                        start: 0,
                        end: 5,
                        width: 5,
                    }.with_text("Super"),
                    // "Captain !"
                    Segment {
                        span_id: 4,
                        start: 0,
                        end: 9,
                        width: 9,
                    }.with_text("Captain !"),
                ],
                hard_stop: false,
                ends_with_space: false,
            }
        ]
    );
}
<|endoftext|>