<commit_before>//! A CLI tool for overriding a DICOM file's image with another one.
//!
//! This command line tool takes a base DICOM file
//! and replaces the various DICOM attributes of the [_Image Pixel_ module][1]
//! (such as Rows, Columns, PixelData, ...)
//! with those of another file.
//! The _Presentation LUT Shape_ attribute is set to `IDENTITY`.
//! Other attributes are copied as is.
//!
//! The new DICOM object is saved to a new file,
//! with the same SOP instance UID and SOP class UID as the base file,
//! encoded in Explicit VR Little Endian.
//!
//! [1]: https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.3.html
use std::path::PathBuf;

use dicom_core::{value::PrimitiveValue, DataElement, VR};
use dicom_dictionary_std::tags;
use dicom_object::{open_file, FileMetaTableBuilder};
use snafu::ErrorCompat;
use structopt::StructOpt;

/// Convert and replace a DICOM file's image with another image
#[derive(Debug, StructOpt)]
struct App {
    /// Path to the base DICOM file to read
    dcm_file: PathBuf,
    /// Path to the image file to replace the DICOM file
    img_file: PathBuf,
    /// Path to the output image
    /// (default is to replace input extension with `.new.dcm`)
    #[structopt(short = "o", long = "out")]
    output: Option<PathBuf>,
    /// Print more information about the image and the output file
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,
}

fn report<E: 'static>(err: &E)
where
    E: std::error::Error,
{
    eprintln!("[ERROR] {}", err);
    if let Some(source) = err.source() {
        eprintln!();
        eprintln!("Caused by:");
        for (i, e) in std::iter::successors(Some(source), |e| e.source()).enumerate() {
            eprintln!("   {}: {}", i, e);
        }
    }
}

fn report_backtrace<E: 'static>(err: &E)
where
    E: std::error::Error,
    E: ErrorCompat,
{
    let env_backtrace = std::env::var("RUST_BACKTRACE").unwrap_or_default();
    let env_lib_backtrace = std::env::var("RUST_LIB_BACKTRACE").unwrap_or_default();
    if env_lib_backtrace == "1" || (env_backtrace == "1" && env_lib_backtrace != "0") {
        if let Some(backtrace) = ErrorCompat::backtrace(&err) {
            eprintln!();
            eprintln!("Backtrace:");
            eprintln!("{}", backtrace);
        }
    }
}

fn report_with_backtrace<E: 'static>(err: E)
where
    E: std::error::Error,
    E: ErrorCompat,
{
    report(&err);
    report_backtrace(&err);
}

fn main() {
    let App {
        dcm_file,
        img_file,
        output,
        verbose,
    } = App::from_args();

    let output = output.unwrap_or_else(|| {
        let mut path = dcm_file.clone();
        path.set_extension("new.dcm");
        path
    });

    let mut obj = open_file(&dcm_file).unwrap_or_else(|e| {
        report_with_backtrace(e);
        std::process::exit(-1);
    });

    let img = image::open(img_file).unwrap_or_else(|e| {
        report(&e);
        std::process::exit(-1);
    });

    let width = img.width();
    let height = img.height();
    let color = img.color();

    let (pi, spp, bits_stored, pixeldata): (&str, u16, u16, Vec<u8>) = match color {
        image::ColorType::L8 => ("MONOCHROME2", 1, 8, img.into_bytes()),
        image::ColorType::L16 => ("MONOCHROME2", 1, 16, img.into_bytes()),
        image::ColorType::Rgb8 => ("RGB", 3, 8, img.into_bytes()),
        image::ColorType::Rgb16 => ("RGB", 3, 16, img.into_bytes()),
        _ => {
            eprintln!("Unsupported image format {:?}", color);
            std::process::exit(-2);
        }
    };

    if verbose {
        println!("{}x{} {:?} image", width, height, color);
    }

    // override attributes at DICOM object
    obj.put(DataElement::new(
        tags::PHOTOMETRIC_INTERPRETATION,
        VR::CS,
        PrimitiveValue::from(pi),
    ));

    obj.put(DataElement::new(
        tags::PRESENTATION_LUT_SHAPE,
        VR::CS,
        PrimitiveValue::from("IDENTITY"),
    ));

    obj.put(DataElement::new(
        tags::SAMPLES_PER_PIXEL,
        VR::US,
        PrimitiveValue::from(spp),
    ));

    if spp > 1 {
        obj.put(DataElement::new(
            tags::PLANAR_CONFIGURATION,
            VR::US,
            PrimitiveValue::from(0_u16),
        ));
    } else {
        obj.remove_element(tags::PLANAR_CONFIGURATION);
    }

    obj.put(DataElement::new(
        tags::COLUMNS,
        VR::US,
        PrimitiveValue::from(width as u16),
    ));
    obj.put(DataElement::new(
        tags::ROWS,
        VR::US,
        PrimitiveValue::from(height as u16),
    ));
    obj.put(DataElement::new(
        tags::BITS_ALLOCATED,
        VR::US,
        PrimitiveValue::from(bits_stored),
    ));
    obj.put(DataElement::new(
        tags::BITS_STORED,
        VR::US,
        PrimitiveValue::from(bits_stored),
    ));
    obj.put(DataElement::new(
        tags::HIGH_BIT,
        VR::US,
        PrimitiveValue::from(bits_stored - 1),
    ));

    obj.put(DataElement::new(
        tags::PIXEL_REPRESENTATION,
        VR::US,
        PrimitiveValue::from(0_u16),
    ));

    for tag in [
        tags::PIXEL_ASPECT_RATIO,
        tags::SMALLEST_IMAGE_PIXEL_VALUE,
        tags::LARGEST_IMAGE_PIXEL_VALUE,
        tags::PIXEL_PADDING_RANGE_LIMIT,
        tags::RED_PALETTE_COLOR_LOOKUP_TABLE_DATA,
        tags::RED_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR,
        tags::GREEN_PALETTE_COLOR_LOOKUP_TABLE_DATA,
        tags::GREEN_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR,
        tags::BLUE_PALETTE_COLOR_LOOKUP_TABLE_DATA,
        tags::BLUE_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR,
        tags::ICC_PROFILE,
        tags::COLOR_SPACE,
        tags::PIXEL_DATA_PROVIDER_URL,
        tags::EXTENDED_OFFSET_TABLE,
        tags::EXTENDED_OFFSET_TABLE_LENGTHS,
    ] {
        obj.remove_element(tag);
    }

    obj.put(DataElement::new(
        tags::PIXEL_DATA,
        if bits_stored == 8 { VR::OB } else { VR::OW },
        PrimitiveValue::from(pixeldata),
    ));

    let class_uid = obj.meta().media_storage_sop_class_uid.clone();

    let obj = obj
        .into_inner()
        .with_meta(
            FileMetaTableBuilder::new()
                .transfer_syntax("1.2.840.10008.1.2.1")
                .media_storage_sop_class_uid(class_uid),
        )
        .unwrap_or_else(|e| {
            report_with_backtrace(e);
            std::process::exit(-3);
        });

    obj.write_to_file(&output).unwrap_or_else(|e| {
        report_with_backtrace(e);
        std::process::exit(-4);
    });

    if verbose {
        println!("DICOM file saved to {}", output.display());
    }
}
<commit_msg>[fromimage] simplify code a bit<commit_after>//! A CLI tool for overriding a DICOM file's image with another one.
//!
//! This command line tool takes a base DICOM file
//! and replaces the various DICOM attributes of the [_Image Pixel_ module][1]
//! (such as Rows, Columns, PixelData, ...)
//! with those of another file.
//! The _Presentation LUT Shape_ attribute is set to `IDENTITY`.
//! Other attributes are copied as is.
//!
//! The new DICOM object is saved to a new file,
//! with the same SOP instance UID and SOP class UID as the base file,
//! encoded in Explicit VR Little Endian.
//!
//! [1]: https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.3.html
use std::path::PathBuf;

use dicom_core::{value::PrimitiveValue, DataElement, VR};
use dicom_dictionary_std::tags;
use dicom_object::{open_file, FileMetaTableBuilder};
use snafu::ErrorCompat;
use structopt::StructOpt;

/// Convert and replace a DICOM file's image with another image
#[derive(Debug, StructOpt)]
struct App {
    /// Path to the base DICOM file to read
    dcm_file: PathBuf,
    /// Path to the image file to replace the DICOM file
    img_file: PathBuf,
    /// Path to the output image
    /// (default is to replace input extension with `.new.dcm`)
    #[structopt(short = "o", long = "out")]
    output: Option<PathBuf>,
    /// Print more information about the image and the output file
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,
}

fn report<E: 'static>(err: &E)
where
    E: std::error::Error,
{
    eprintln!("[ERROR] {}", err);
    if let Some(source) = err.source() {
        eprintln!();
        eprintln!("Caused by:");
        for (i, e) in std::iter::successors(Some(source), |e| e.source()).enumerate() {
            eprintln!("   {}: {}", i, e);
        }
    }
}

fn report_backtrace<E: 'static>(err: &E)
where
    E: std::error::Error,
    E: ErrorCompat,
{
    let env_backtrace = std::env::var("RUST_BACKTRACE").unwrap_or_default();
    let env_lib_backtrace = std::env::var("RUST_LIB_BACKTRACE").unwrap_or_default();
    if env_lib_backtrace == "1" || (env_backtrace == "1" && env_lib_backtrace != "0") {
        if let Some(backtrace) = ErrorCompat::backtrace(&err) {
            eprintln!();
            eprintln!("Backtrace:");
            eprintln!("{}", backtrace);
        }
    }
}

fn report_with_backtrace<E: 'static>(err: E)
where
    E: std::error::Error,
    E: ErrorCompat,
{
    report(&err);
    report_backtrace(&err);
}

fn main() {
    let App {
        dcm_file,
        img_file,
        output,
        verbose,
    } = App::from_args();

    let output = output.unwrap_or_else(|| {
        let mut path = dcm_file.clone();
        path.set_extension("new.dcm");
        path
    });

    let mut obj = open_file(&dcm_file).unwrap_or_else(|e| {
        report_with_backtrace(e);
        std::process::exit(-1);
    });

    let img = image::open(img_file).unwrap_or_else(|e| {
        report(&e);
        std::process::exit(-1);
    });

    let width = img.width();
    let height = img.height();
    let color = img.color();

    let (pi, spp, bits_stored): (&str, u16, u16) = match color {
        image::ColorType::L8 => ("MONOCHROME2", 1, 8),
        image::ColorType::L16 => ("MONOCHROME2", 1, 16),
        image::ColorType::Rgb8 => ("RGB", 3, 8),
        image::ColorType::Rgb16 => ("RGB", 3, 16),
        _ => {
            eprintln!("Unsupported image format {:?}", color);
            std::process::exit(-2);
        }
    };

    let pixeldata = img.into_bytes();

    if verbose {
        println!("{}x{} {:?} image", width, height, color);
    }

    // override attributes at DICOM object
    obj.put(DataElement::new(
        tags::PHOTOMETRIC_INTERPRETATION,
        VR::CS,
        PrimitiveValue::from(pi),
    ));

    obj.put(DataElement::new(
        tags::PRESENTATION_LUT_SHAPE,
        VR::CS,
        PrimitiveValue::from("IDENTITY"),
    ));

    obj.put(DataElement::new(
        tags::SAMPLES_PER_PIXEL,
        VR::US,
        PrimitiveValue::from(spp),
    ));

    if spp > 1 {
        obj.put(DataElement::new(
            tags::PLANAR_CONFIGURATION,
            VR::US,
            PrimitiveValue::from(0_u16),
        ));
    } else {
        obj.remove_element(tags::PLANAR_CONFIGURATION);
    }

    obj.put(DataElement::new(
        tags::COLUMNS,
        VR::US,
        PrimitiveValue::from(width as u16),
    ));
    obj.put(DataElement::new(
        tags::ROWS,
        VR::US,
        PrimitiveValue::from(height as u16),
    ));
    obj.put(DataElement::new(
        tags::BITS_ALLOCATED,
        VR::US,
        PrimitiveValue::from(bits_stored),
    ));
    obj.put(DataElement::new(
        tags::BITS_STORED,
        VR::US,
        PrimitiveValue::from(bits_stored),
    ));
    obj.put(DataElement::new(
        tags::HIGH_BIT,
        VR::US,
        PrimitiveValue::from(bits_stored - 1),
    ));

    obj.put(DataElement::new(
        tags::PIXEL_REPRESENTATION,
        VR::US,
        PrimitiveValue::from(0_u16),
    ));

    for tag in [
        tags::PIXEL_ASPECT_RATIO,
        tags::SMALLEST_IMAGE_PIXEL_VALUE,
        tags::LARGEST_IMAGE_PIXEL_VALUE,
        tags::PIXEL_PADDING_RANGE_LIMIT,
        tags::RED_PALETTE_COLOR_LOOKUP_TABLE_DATA,
        tags::RED_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR,
        tags::GREEN_PALETTE_COLOR_LOOKUP_TABLE_DATA,
        tags::GREEN_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR,
        tags::BLUE_PALETTE_COLOR_LOOKUP_TABLE_DATA,
        tags::BLUE_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR,
        tags::ICC_PROFILE,
        tags::COLOR_SPACE,
        tags::PIXEL_DATA_PROVIDER_URL,
        tags::EXTENDED_OFFSET_TABLE,
        tags::EXTENDED_OFFSET_TABLE_LENGTHS,
    ] {
        obj.remove_element(tag);
    }

    obj.put(DataElement::new(
        tags::PIXEL_DATA,
        if bits_stored == 8 { VR::OB } else { VR::OW },
        PrimitiveValue::from(pixeldata),
    ));

    let class_uid = obj.meta().media_storage_sop_class_uid.clone();

    let obj = obj
        .into_inner()
        .with_meta(
            FileMetaTableBuilder::new()
                .transfer_syntax("1.2.840.10008.1.2.1")
                .media_storage_sop_class_uid(class_uid),
        )
        .unwrap_or_else(|e| {
            report_with_backtrace(e);
            std::process::exit(-3);
        });

    obj.write_to_file(&output).unwrap_or_else(|e| {
        report_with_backtrace(e);
        std::process::exit(-4);
    });

    if verbose {
        println!("DICOM file saved to {}", output.display());
    }
}
<|endoftext|>


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

const MAX_LAT: f64 = 180f64;
const MIN_LAT: f64 = -180f64;

const MAX_LON: f64 = 90f64;
const MIN_LON: f64 = -90f64;
const DEFAULT_LIMIT: u64 = 10u64;
const DEFAULT_OFFSET: u64 = 0u64;

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

#[derive(Copy, Clone)]
enum Type {
    City,
    House,
    Poi,
    StopArea,
    Street,
}

impl Type {
    fn from_str(type_: &str) -> Option<Type> {
        match type_ {
            "city" => Some(Type::City),
            "house" => Some(Type::House),
            "poi" => Some(Type::Poi),
            "public_transport:stop_area" => Some(Type::StopArea),
            "street" => Some(Type::Street),
            _ => None,
        }
    }
}

pub struct ApiEndPoint {
    pub es_cnx_string: String,
}

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

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

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

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

    fn autocomplete(&self) -> rustless::Api {
        Api::build(|api| {
            api.post("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("q", json_dsl::string());
                    params.opt_typed("pt_dataset", json_dsl::string());
                    params.opt_typed("limit", json_dsl::u64());
                    params.opt_typed("offset", json_dsl::u64());
                    params.opt_typed("_all_data", json_dsl::boolean());
                    params.req("geometry", |geometry| {
                        geometry.coerce(json_dsl::object());
                        geometry.nest(|params| {
                            params.req("type", |geojson_type| {
                                geojson_type.coerce(json_dsl::string());
                                geojson_type.allow_values(&["Polygon".to_string()]);
                            });
                        });
                        geometry.nest(|params| {
                            params.req("coordinates", |shape| {
                                shape.coerce(json_dsl::array());
                                shape.validate_with(|val, path| {
                                    check_coordinates(val, path, "Coordinates is invalid")
                                });
                            });
                        });
                    });
                    params.opt("type", |t| {
                        t.coerce(json_dsl::encoded_array(","));
                        t.validate_with(|val, path| check_type(val.as_array().unwrap(), path));
                    });
                });

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

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
            api.get("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.req_typed("q", json_dsl::string());
                    params.opt_typed("pt_dataset", json_dsl::string());
                    params.opt_typed("limit", json_dsl::u64());
                    params.opt_typed("offset", json_dsl::u64());
                    params.opt_typed("_all_data", json_dsl::boolean());
                    params.opt("lon", |lon| {
                        lon.coerce(json_dsl::f64());
                        lon.validate_with(|val, path| {
                            check_bound(val, path, MIN_LON, MAX_LON, "lon is not a valid longitude")
                        });
                    });

                    params.opt("lat", |lat| {
                        lat.coerce(json_dsl::f64());
                        lat.validate_with(|val, path| {
                            check_bound(val, path, MIN_LAT, MAX_LAT, "lat is not a valid latitude")
                        });
                    });
                    params.opt("type", |t| {
                        t.coerce(json_dsl::encoded_array(","));
                        t.validate_with(|val, path| check_type(val.as_array().unwrap(), path));
                    });

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

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

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

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

fn check_bound(val: &serde_json::Value,
               path: &str,
               min: f64,
               max: f64,
               error_msg: &str)
               -> Result<(), valico_error::ValicoErrors> {
    if let Some(lon) = val.as_f64() {
        if min <= lon && lon <= max {
            Ok(())
        } else {
            Err(vec![Box::new(json_dsl::errors::WrongValue {
                         path: path.to_string(),
                         detail: Some(error_msg.to_string()),
                     })])
        }
    } else {
        unreachable!("should never happen, already checked");
    }
}

fn check_type(types: &Vec<serde_json::Value>,
              path: &str)
              -> Result<(), valico_error::ValicoErrors> {
    for type_ in types {
        let type_as_str = type_.as_str().unwrap();
        if Type::from_str(type_as_str).is_none() {
            return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                path: path.to_string(),
                                detail: Some(format!("{} is not a valid type", type_as_str)),
                            })]);
        }
    }

    Ok(())
}

fn check_coordinates(val: &serde_json::Value,
                     path: &str,
                     error_msg: &str)
                     -> Result<(), valico_error::ValicoErrors> {

    if !val.is_array() {
        return Err(vec![Box::new(json_dsl::errors::WrongType {
                            path: path.to_string(),
                            detail: error_msg.to_string(),
                        })]);
    }
    let array = val.as_array().unwrap();
    if array.is_empty() {
        return Err(vec![Box::new(json_dsl::errors::WrongValue {
                            path: path.to_string(),
                            detail: Some(error_msg.to_string()),
                        })]);
    }

    for arr0 in array {
        if !arr0.is_array() {
            return Err(vec![Box::new(json_dsl::errors::WrongType {
                                path: path.to_string(),
                                detail: error_msg.to_string(),
                            })]);
        }
        let arr1 = arr0.as_array().unwrap();
        if arr1.is_empty() {
            return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                path: path.to_string(),
                                detail: Some(error_msg.to_string()),
                            })]);
        }
        for arr2 in arr1 {
            if !arr2.is_array() {
                return Err(vec![Box::new(json_dsl::errors::WrongType {
                                    path: path.to_string(),
                                    detail: error_msg.to_string(),
                                })]);
            }
            let lonlat = arr2.as_array().unwrap();
            if lonlat.len() != 2 {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }

            if !(lonlat[0].is_f64() && lonlat[1].is_f64()) {
                return Err(vec![Box::new(json_dsl::errors::WrongType {
                                    path: path.to_string(),
                                    detail: error_msg.to_string(),
                                })]);
            }
            let lon = lonlat[0].as_f64().unwrap();
            let lat = lonlat[1].as_f64().unwrap();
            if !(MIN_LON <= lon && lon <= MAX_LON) {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }
            if !(MIN_LAT <= lat && lat <= MAX_LAT) {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }
        }
    }
    Ok(())
}
<commit_msg>Type impl FromStr<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
use rustless;
use serde;
use serde_json;
use rustless::server::{status, header};
use rustless::{Api, Nesting};
use valico::json_dsl;
use valico::common::error as valico_error;
use super::query;
use model::v1::*;
use model;
use std::str::FromStr;

const MAX_LAT: f64 = 180f64;
const MIN_LAT: f64 = -180f64;

const MAX_LON: f64 = 90f64;
const MIN_LON: f64 = -90f64;
const DEFAULT_LIMIT: u64 = 10u64;
const DEFAULT_OFFSET: u64 = 0u64;

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

#[derive(Copy, Clone, Debug)]
enum Type {
    City,
    House,
    Poi,
    StopArea,
    Street,
}

impl FromStr for Type {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "city" => Ok(Type::City),
            "house" => Ok(Type::House),
            "poi" => Ok(Type::Poi),
            "public_transport:stop_area" => Ok(Type::StopArea),
            "street" => Ok(Type::Street),
            _ => Err(format!("{} is not a valid type", s)),
        }
    }
}

pub struct ApiEndPoint {
    pub es_cnx_string: String,
}

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

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

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

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

    fn autocomplete(&self) -> rustless::Api {
        Api::build(|api| {
            api.post("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.opt_typed("q", json_dsl::string());
                    params.opt_typed("pt_dataset", json_dsl::string());
                    params.opt_typed("limit", json_dsl::u64());
                    params.opt_typed("offset", json_dsl::u64());
                    params.opt_typed("_all_data", json_dsl::boolean());
                    params.req("geometry", |geometry| {
                        geometry.coerce(json_dsl::object());
                        geometry.nest(|params| {
                            params.req("type", |geojson_type| {
                                geojson_type.coerce(json_dsl::string());
                                geojson_type.allow_values(&["Polygon".to_string()]);
                            });
                        });
                        geometry.nest(|params| {
                            params.req("coordinates", |shape| {
                                shape.coerce(json_dsl::array());
                                shape.validate_with(|val, path| {
                                    check_coordinates(val, path, "Coordinates is invalid")
                                });
                            });
                        });
                    });
                    params.opt("type", |t| {
                        t.coerce(json_dsl::encoded_array(","));
                        t.validate_with(|val, path| check_type(val.as_array().unwrap(), path));
                    });
                });

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

                    let response = model::v1::AutocompleteResponse::from(model_autocomplete);
                    render(client, response)
                })
            });
            api.get("autocomplete", |endpoint| {
                endpoint.params(|params| {
                    params.req_typed("q", json_dsl::string());
                    params.opt_typed("pt_dataset", json_dsl::string());
                    params.opt_typed("limit", json_dsl::u64());
                    params.opt_typed("offset", json_dsl::u64());
                    params.opt_typed("_all_data", json_dsl::boolean());
                    params.opt("lon", |lon| {
                        lon.coerce(json_dsl::f64());
                        lon.validate_with(|val, path| {
                            check_bound(val, path, MIN_LON, MAX_LON, "lon is not a valid longitude")
                        });
                    });

                    params.opt("lat", |lat| {
                        lat.coerce(json_dsl::f64());
                        lat.validate_with(|val, path| {
                            check_bound(val, path, MIN_LAT, MAX_LAT, "lat is not a valid latitude")
                        });
                    });
                    params.opt("type", |t| {
                        t.coerce(json_dsl::encoded_array(","));
                        t.validate_with(|val, path| check_type(val.as_array().unwrap(), path));
                    });

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

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

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

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

fn check_bound(val: &serde_json::Value,
               path: &str,
               min: f64,
               max: f64,
               error_msg: &str)
               -> Result<(), valico_error::ValicoErrors> {
    if let Some(lon) = val.as_f64() {
        if min <= lon && lon <= max {
            Ok(())
        } else {
            Err(vec![Box::new(json_dsl::errors::WrongValue {
                         path: path.to_string(),
                         detail: Some(error_msg.to_string()),
                     })])
        }
    } else {
        unreachable!("should never happen, already checked");
    }
}

fn check_type(types: &Vec<serde_json::Value>,
              path: &str)
              -> Result<(), valico_error::ValicoErrors> {
    for type_ in types {
        if let Err(e) = Type::from_str(type_.as_str().unwrap()) {
            return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                path: path.to_string(),
                                detail: Some(e),
                            })]);
        }
    }

    Ok(())
}

fn check_coordinates(val: &serde_json::Value,
                     path: &str,
                     error_msg: &str)
                     -> Result<(), valico_error::ValicoErrors> {

    if !val.is_array() {
        return Err(vec![Box::new(json_dsl::errors::WrongType {
                            path: path.to_string(),
                            detail: error_msg.to_string(),
                        })]);
    }
    let array = val.as_array().unwrap();
    if array.is_empty() {
        return Err(vec![Box::new(json_dsl::errors::WrongValue {
                            path: path.to_string(),
                            detail: Some(error_msg.to_string()),
                        })]);
    }

    for arr0 in array {
        if !arr0.is_array() {
            return Err(vec![Box::new(json_dsl::errors::WrongType {
                                path: path.to_string(),
                                detail: error_msg.to_string(),
                            })]);
        }
        let arr1 = arr0.as_array().unwrap();
        if arr1.is_empty() {
            return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                path: path.to_string(),
                                detail: Some(error_msg.to_string()),
                            })]);
        }
        for arr2 in arr1 {
            if !arr2.is_array() {
                return Err(vec![Box::new(json_dsl::errors::WrongType {
                                    path: path.to_string(),
                                    detail: error_msg.to_string(),
                                })]);
            }
            let lonlat = arr2.as_array().unwrap();
            if lonlat.len() != 2 {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }

            if !(lonlat[0].is_f64() && lonlat[1].is_f64()) {
                return Err(vec![Box::new(json_dsl::errors::WrongType {
                                    path: path.to_string(),
                                    detail: error_msg.to_string(),
                                })]);
            }
            let lon = lonlat[0].as_f64().unwrap();
            let lat = lonlat[1].as_f64().unwrap();
            if !(MIN_LON <= lon && lon <= MAX_LON) {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }
            if !(MIN_LAT <= lat && lat <= MAX_LAT) {
                return Err(vec![Box::new(json_dsl::errors::WrongValue {
                                    path: path.to_string(),
                                    detail: Some(error_msg.to_string()),
                                })]);
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use crate::{
    codegen, is_release_tag,
    not_bash::{date_iso, fs2, pushd, run},
    project_root, Mode, Result,
};

pub struct ReleaseCmd {
    pub dry_run: bool,
}

impl ReleaseCmd {
    pub fn run(self) -> Result<()> {
        if !self.dry_run {
            run!("git switch release")?;
            run!("git fetch upstream --tags --force")?;
            run!("git reset --hard tags/nightly")?;
            run!("git push")?;
        }
        codegen::generate_assists_docs(Mode::Overwrite)?;
        codegen::generate_feature_docs(Mode::Overwrite)?;

        let website_root = project_root().join("../rust-analyzer.github.io");
        let changelog_dir = website_root.join("./thisweek/_posts");

        let today = date_iso()?;
        let commit = run!("git rev-parse HEAD")?;
        let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();

        let contents = format!(
            "\
= Changelog #{}
:sectanchors:
:page-layout: post

Commit: commit:{}[] +
Release: release:{}[]

== Sponsors

**Become a sponsor:** https://opencollective.com/rust-analyzer/[opecollective.com/rust-analyzer]

== New Features

* pr:[] .

== Fixes

== Internal Improvements
",
            changelog_n, commit, today
        );

        let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
        fs2::write(&path, &contents)?;

        for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
            let src = project_root().join("./docs/user/").join(adoc);
            let dst = website_root.join(adoc);
            fs2::copy(src, dst)?;
        }

        let tags = run!("git tag --list"; echo = false)?;
        let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();

        let git_log = run!("git log {}..HEAD --merges --reverse", prev_tag; echo = false)?;
        let git_log_dst = website_root.join("git.log");
        fs2::write(git_log_dst, &git_log)?;

        Ok(())
    }
}

pub struct PromoteCmd {
    pub dry_run: bool,
}

impl PromoteCmd {
    pub fn run(self) -> Result<()> {
        let _dir = pushd("../rust-rust-analyzer");
        run!("git switch master")?;
        run!("git fetch upstream")?;
        run!("git reset --hard upstream/master")?;
        run!("git submodule update --recursive")?;

        let branch = format!("rust-analyzer-{}", date_iso()?);
        run!("git switch -c {}", branch)?;
        {
            let _dir = pushd("src/tools/rust-analyzer");
            run!("git fetch origin")?;
            run!("git reset --hard origin/release")?;
        }
        run!("git add src/tools/rust-analyzer")?;
        run!("git commit -m':arrow_up: rust-analyzer'")?;
        if !self.dry_run {
            run!("git push")?;
            run!("xdg-open https://github.com/matklad/rust/pull/new/{}", branch)?;
        }
        Ok(())
    }
}
<commit_msg>Prefill reviewer<commit_after>use crate::{
    codegen, is_release_tag,
    not_bash::{date_iso, fs2, pushd, run},
    project_root, Mode, Result,
};

pub struct ReleaseCmd {
    pub dry_run: bool,
}

impl ReleaseCmd {
    pub fn run(self) -> Result<()> {
        if !self.dry_run {
            run!("git switch release")?;
            run!("git fetch upstream --tags --force")?;
            run!("git reset --hard tags/nightly")?;
            run!("git push")?;
        }
        codegen::generate_assists_docs(Mode::Overwrite)?;
        codegen::generate_feature_docs(Mode::Overwrite)?;

        let website_root = project_root().join("../rust-analyzer.github.io");
        let changelog_dir = website_root.join("./thisweek/_posts");

        let today = date_iso()?;
        let commit = run!("git rev-parse HEAD")?;
        let changelog_n = fs2::read_dir(changelog_dir.as_path())?.count();

        let contents = format!(
            "\
= Changelog #{}
:sectanchors:
:page-layout: post

Commit: commit:{}[] +
Release: release:{}[]

== Sponsors

**Become a sponsor:** https://opencollective.com/rust-analyzer/[opecollective.com/rust-analyzer]

== New Features

* pr:[] .

== Fixes

== Internal Improvements
",
            changelog_n, commit, today
        );

        let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
        fs2::write(&path, &contents)?;

        for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
            let src = project_root().join("./docs/user/").join(adoc);
            let dst = website_root.join(adoc);
            fs2::copy(src, dst)?;
        }

        let tags = run!("git tag --list"; echo = false)?;
        let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();

        let git_log = run!("git log {}..HEAD --merges --reverse", prev_tag; echo = false)?;
        let git_log_dst = website_root.join("git.log");
        fs2::write(git_log_dst, &git_log)?;

        Ok(())
    }
}

pub struct PromoteCmd {
    pub dry_run: bool,
}

impl PromoteCmd {
    pub fn run(self) -> Result<()> {
        let _dir = pushd("../rust-rust-analyzer");
        run!("git switch master")?;
        run!("git fetch upstream")?;
        run!("git reset --hard upstream/master")?;
        run!("git submodule update --recursive")?;

        let branch = format!("rust-analyzer-{}", date_iso()?);
        run!("git switch -c {}", branch)?;
        {
            let _dir = pushd("src/tools/rust-analyzer");
            run!("git fetch origin")?;
            run!("git reset --hard origin/release")?;
        }
        run!("git add src/tools/rust-analyzer")?;
        run!("git commit -m':arrow_up: rust-analyzer'")?;
        if !self.dry_run {
            run!("git push")?;
            run!(
                "xdg-open https://github.com/matklad/rust/pull/new/{}?body=r%3F%20%40ghost",
                branch
            )?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use futures::{Future, Poll};
use lapin::{Connect as LapinConnect, Connection, ConnectionPromise, Result};

use crate::{
    tcp::Identity, uri::AMQPUri, Channel, ConfirmationFuture, ConnectionProperties, Error,
};

/// Connect to a server and create channels
#[derive(Clone)]
pub struct Client {
    conn: Connection,
}

impl Client {
    /// Connect to an AMQP Server
    pub fn connect(uri: &str, options: ConnectionProperties) -> ClientFuture {
        Connect::connect(uri, options, None)
    }

    /// Connect to an AMQP Server
    pub fn connect_with_identity(
        uri: &str,
        options: ConnectionProperties,
        identity: Identity<'_, '_>,
    ) -> ClientFuture {
        Connect::connect(uri, options, Some(identity))
    }

    /// Connect to an AMQP Server
    pub fn connect_uri(uri: AMQPUri, options: ConnectionProperties) -> ClientFuture {
        Connect::connect(uri, options, None)
    }

    /// Connect to an AMQP Server
    pub fn connect_uri_with_identity(
        uri: AMQPUri,
        options: ConnectionProperties,
        identity: Identity<'_, '_>,
    ) -> ClientFuture {
        Connect::connect(uri, options, Some(identity))
    }

    /// Return a future that resolves to a `Channel` once the method succeeds
    pub fn create_channel(&self) -> impl Future<Item = Channel, Error = Error> + Send + 'static {
        Channel::create(&self.conn)
    }

    /// Update the secret used by some authentication module such as oauth2
    pub fn update_secret(&self, new_secret: &str, reason: &str) -> ConfirmationFuture<()> {
        self.conn.update_secret(new_secret, reason).into()
    }

    /// Block all consumers and publishers on this connection
    pub fn block(&self, reason: &str) -> ConfirmationFuture<()> {
        self.conn.block(reason).into()
    }

    /// Unblock all consumers and publishers on this connection
    pub fn unblock(&self) -> ConfirmationFuture<()> {
        self.conn.unblock().into()
    }

    /// Register an error handler which will be called when connection reaches an Error state
    pub fn on_error<E: Fn() + Send + 'static>(&self, handler: Box<E>) {
        self.conn.on_error(handler);
    }
}

pub struct ClientFuture(ConfirmationFuture<Connection, Result<()>>);

impl Future for ClientFuture {
    type Item = Client;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        Ok(self.0.poll()?.map(|conn| Client { conn }))
    }
}

impl From<ConnectionPromise> for ClientFuture {
    fn from(promise: ConnectionPromise) -> Self {
        Self(promise.into())
    }
}

/// Trait providing a method to connect to an AMQP server
pub trait Connect {
    /// Connect to an AMQP server
    fn connect(
        self,
        options: ConnectionProperties,
        identity: Option<Identity<'_, '_>>,
    ) -> ClientFuture;
}

impl Connect for AMQPUri {
    fn connect(
        self,
        options: ConnectionProperties,
        identity: Option<Identity<'_, '_>>,
    ) -> ClientFuture {
        LapinConnect::connect(self, options, identity).into()
    }
}

impl Connect for &str {
    fn connect(
        self,
        options: ConnectionProperties,
        identity: Option<Identity<'_, '_>>,
    ) -> ClientFuture {
        LapinConnect::connect(self, options, identity).into()
    }
}
<commit_msg>futures: adapt to ErrorHandler API change<commit_after>use futures::{Future, Poll};
use lapin::{Connect as LapinConnect, Connection, ConnectionPromise, Result};

use crate::{
    tcp::Identity, uri::AMQPUri, Channel, ConfirmationFuture, ConnectionProperties, Error,
};

/// Connect to a server and create channels
#[derive(Clone)]
pub struct Client {
    conn: Connection,
}

impl Client {
    /// Connect to an AMQP Server
    pub fn connect(uri: &str, options: ConnectionProperties) -> ClientFuture {
        Connect::connect(uri, options, None)
    }

    /// Connect to an AMQP Server
    pub fn connect_with_identity(
        uri: &str,
        options: ConnectionProperties,
        identity: Identity<'_, '_>,
    ) -> ClientFuture {
        Connect::connect(uri, options, Some(identity))
    }

    /// Connect to an AMQP Server
    pub fn connect_uri(uri: AMQPUri, options: ConnectionProperties) -> ClientFuture {
        Connect::connect(uri, options, None)
    }

    /// Connect to an AMQP Server
    pub fn connect_uri_with_identity(
        uri: AMQPUri,
        options: ConnectionProperties,
        identity: Identity<'_, '_>,
    ) -> ClientFuture {
        Connect::connect(uri, options, Some(identity))
    }

    /// Return a future that resolves to a `Channel` once the method succeeds
    pub fn create_channel(&self) -> impl Future<Item = Channel, Error = Error> + Send + 'static {
        Channel::create(&self.conn)
    }

    /// Update the secret used by some authentication module such as oauth2
    pub fn update_secret(&self, new_secret: &str, reason: &str) -> ConfirmationFuture<()> {
        self.conn.update_secret(new_secret, reason).into()
    }

    /// Block all consumers and publishers on this connection
    pub fn block(&self, reason: &str) -> ConfirmationFuture<()> {
        self.conn.block(reason).into()
    }

    /// Unblock all consumers and publishers on this connection
    pub fn unblock(&self) -> ConfirmationFuture<()> {
        self.conn.unblock().into()
    }

    /// Register an error handler which will be called when connection reaches an Error state
    pub fn on_error<E: Fn(Error) + Send + 'static>(&self, handler: Box<E>) {
        self.conn.on_error(handler);
    }
}

pub struct ClientFuture(ConfirmationFuture<Connection, Result<()>>);

impl Future for ClientFuture {
    type Item = Client;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        Ok(self.0.poll()?.map(|conn| Client { conn }))
    }
}

impl From<ConnectionPromise> for ClientFuture {
    fn from(promise: ConnectionPromise) -> Self {
        Self(promise.into())
    }
}

/// Trait providing a method to connect to an AMQP server
pub trait Connect {
    /// Connect to an AMQP server
    fn connect(
        self,
        options: ConnectionProperties,
        identity: Option<Identity<'_, '_>>,
    ) -> ClientFuture;
}

impl Connect for AMQPUri {
    fn connect(
        self,
        options: ConnectionProperties,
        identity: Option<Identity<'_, '_>>,
    ) -> ClientFuture {
        LapinConnect::connect(self, options, identity).into()
    }
}

impl Connect for &str {
    fn connect(
        self,
        options: ConnectionProperties,
        identity: Option<Identity<'_, '_>>,
    ) -> ClientFuture {
        LapinConnect::connect(self, options, identity).into()
    }
}
<|endoftext|>


<commit_before>// 此函数拥有 box 的所有权并销毁它
fn eat_box(boxed_int: Box<i32>) {
    println!("Destroying box that contains {}", boxed_int);
}

// 此函数借用了一个 i32 类型
fn borrow_box(borrowed_int: &i32) {
    println!("This int is: {}", borrowed_int);
}

fn main() {
    // 创建了一个装箱的整型（boxed integer）
    let boxed_int = Box::new(5);

    // 借用了  box 的内容，但没有取得所有权，所以 box 的内容可以
    // 再次借用。
    borrow_box(&boxed_int);
    borrow_box(&boxed_int);

    {
        // 给出一个指向 box 里面所包含数据的引用
        let _ref_to_int: &i32 = &boxed_int;

        // 报错！
        // 当 `boxed_int` 里面的值被借用时，不能销毁 `boxed_int`。
        eat_box(boxed_int);
        // 改正 ^ 注释掉此行

        // `_ref_to_int` 离开作用域且不再被借用。
    }

    // box 现在可以放弃 `eat_box` 的所有权且可以销毁
    eat_box(boxed_int);
}
<commit_msg>More emphasis on the type system<commit_after>// 此函数拥有 box 的所有权并销毁它
fn eat_box_i32(boxed_i32: Box<i32>) {
    println!("Destroying box that contains {}", boxed_i32);
}

// 此函数借用了一个 i32 类型
fn borrow_i32(borrowed_i32: &i32) {
    println!("This int is: {}", borrowed_i32);
}

fn main() {
    // 创建一个装箱的 i32 类型，以及一个存在栈中的 i32 类型。
    let boxed_int = Box::new(5_i32);
    let stacked_i32 = 6_i32;

    // 借用了  box 的内容，但没有取得所有权，所以 box 的内容可以
    // 再次借用。
    borrow_i32(&boxed_i32);
    borrow_i32(&tacked_i32);

    {
        // 给出一个指向 box 里面所包含数据的引用
        let _ref_to_i32: &i32 = &boxed_i32;

        // 报错！
        // 当 `boxed_i32` 里面的值被借用时，不能销毁 `boxed_int`。
        eat_box_i32(boxed_i32);
        // 改正 ^ 注释掉此行

        // `_ref_to_i32` 离开作用域且不再被借用。
    }

    // box 现在可以放弃 `eat_i32` 的所有权且可以销毁
    eat_i32(boxed_i32);
}
<|endoftext|>


<commit_before>extern mod std;
use std::map::HashMap;

fn get_at(map: HashMap<uint, uint>, n: uint) -> uint {
    match map.find(n) {
      Some(x) => x,
      None    => {
        let x = if n % 2 == 0 {
            get_at(map, n / 2) + 1
        } else {
            get_at(map, 3 * n + 1) + 1
        };
        map.insert(n, x);
        return x;
      }
    }
}

fn main() {
    let map = std::map::uint_hash();
    map.insert(1u, 1u);
    let mut max     = 1u;
    let mut max_idx = 1u;
    for uint::range(2u, 1000000u) |n| {
        let x = get_at(map, n);
        if x > max {
            max     = x;
            max_idx = n;
        }
    }
    io::println(#fmt("%u => %u", max_idx, max));
}
<commit_msg>uint hash is now std::map::HashMap::<uint, uint><commit_after>extern mod std;
use std::map::HashMap;

fn get_at(map: HashMap<uint, uint>, n: uint) -> uint {
    match map.find(n) {
      Some(x) => x,
      None    => {
        let x = if n % 2 == 0 {
            get_at(map, n / 2) + 1
        } else {
            get_at(map, 3 * n + 1) + 1
        };
        map.insert(n, x);
        return x;
      }
    }
}

fn main() {
    let map = std::map::HashMap::<uint, uint>();
    map.insert(1u, 1u);
    let mut max     = 1u;
    let mut max_idx = 1u;
    for uint::range(2u, 1000000u) |n| {
        let x = get_at(map, n);
        if x > max {
            max     = x;
            max_idx = n;
        }
    }
    io::println(#fmt("%u => %u", max_idx, max));
}
<|endoftext|>


<commit_before>#![no_std]
#![feature(test)]
extern crate threefish;

extern crate test;
extern crate block_cipher_trait;
extern crate generic_array;

use test::Bencher;
use block_cipher_trait::BlockCipher;
use generic_array::GenericArray;

#[bench]
pub fn encrypt_1_256(bh: &mut Bencher) {
    let key = Default::default();
    let state = threefish::Threefish256::new(&key);
    let mut input = [1u8; 32];
    let input = GenericArray::from_mut_slice(&mut input);
    bh.iter(|| state.encrypt_block(input));
    bh.bytes = 32u64;
}

#[bench]
pub fn encrypt_2_512(bh: &mut Bencher) {
    let key = Default::default();
    let state = threefish::Threefish512::new(&key);
    let mut input = [1u8; 64];
    let input = GenericArray::from_mut_slice(&mut input);
    bh.iter(|| state.encrypt_block(input));
    bh.bytes = 64u64;
}

#[bench]
pub fn encrypt_3_1024(bh: &mut Bencher) {
    let key = Default::default();
    let state = threefish::Threefish1024::new(&key);
    let mut input = [1u8; 128];
    let input = GenericArray::from_mut_slice(&mut input);
    bh.iter(|| state.encrypt_block(input));
    bh.bytes = 128u64;
}
<commit_msg>fixup benches<commit_after>#![no_std]
#![feature(test)]
extern crate threefish_cipher;

extern crate test;
extern crate block_cipher_trait;
extern crate generic_array;

use test::Bencher;
use block_cipher_trait::BlockCipher;
use generic_array::GenericArray;

#[bench]
pub fn encrypt_1_256(bh: &mut Bencher) {
    let key = Default::default();
    let state = threefish_cipher::Threefish256::new(&key);
    let mut input = [1u8; 32];
    let input = GenericArray::from_mut_slice(&mut input);
    bh.iter(|| state.encrypt_block(input));
    bh.bytes = 32u64;
}

#[bench]
pub fn encrypt_2_512(bh: &mut Bencher) {
    let key = Default::default();
    let state = threefish_cipher::Threefish512::new(&key);
    let mut input = [1u8; 64];
    let input = GenericArray::from_mut_slice(&mut input);
    bh.iter(|| state.encrypt_block(input));
    bh.bytes = 64u64;
}

#[bench]
pub fn encrypt_3_1024(bh: &mut Bencher) {
    let key = Default::default();
    let state = threefish_cipher::Threefish1024::new(&key);
    let mut input = [1u8; 128];
    let input = GenericArray::from_mut_slice(&mut input);
    bh.iter(|| state.encrypt_block(input));
    bh.bytes = 128u64;
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::contains_return_break_continue_macro;
use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, is_else_clause, is_lang_ctor};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionSome;
use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:**
    /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more
    /// idiomatically done with `Option::map_or` (if the else bit is a pure
    /// expression) or `Option::map_or_else` (if the else bit is an impure
    /// expression).
    ///
    /// **Why is this bad?**
    /// Using the dedicated functions of the Option type is clearer and
    /// more concise than an `if let` expression.
    ///
    /// **Known problems:**
    /// This lint uses a deliberately conservative metric for checking
    /// if the inside of either body contains breaks or continues which will
    /// cause it to not suggest a fix if either block contains a loop with
    /// continues or breaks contained within the loop.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// # let optional: Option<u32> = Some(0);
    /// # fn do_complicated_function() -> u32 { 5 };
    /// let _ = if let Some(foo) = optional {
    ///     foo
    /// } else {
    ///     5
    /// };
    /// let _ = if let Some(foo) = optional {
    ///     foo
    /// } else {
    ///     let y = do_complicated_function();
    ///     y*y
    /// };
    /// ```
    ///
    /// should be
    ///
    /// ```rust
    /// # let optional: Option<u32> = Some(0);
    /// # fn do_complicated_function() -> u32 { 5 };
    /// let _ = optional.map_or(5, |foo| foo);
    /// let _ = optional.map_or_else(||{
    ///     let y = do_complicated_function();
    ///     y*y
    /// }, |foo| foo);
    /// ```
    pub OPTION_IF_LET_ELSE,
    pedantic,
    "reimplementation of Option::map_or"
}

declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);

/// Returns true iff the given expression is the result of calling `Result::ok`
fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
    if let ExprKind::MethodCall(path, _, &[ref receiver], _) = &expr.kind {
        path.ident.name.as_str() == "ok"
            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::result_type)
    } else {
        false
    }
}

/// A struct containing information about occurrences of the
/// `if let Some(..) = .. else` construct that this lint detects.
struct OptionIfLetElseOccurence {
    option: String,
    method_sugg: String,
    some_expr: String,
    none_expr: String,
    wrap_braces: bool,
}

/// Extracts the body of a given arm. If the arm contains only an expression,
/// then it returns the expression. Otherwise, it returns the entire block
fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
    if let ExprKind::Block(
        Block {
            stmts: statements,
            expr: Some(expr),
            ..
        },
        _,
    ) = &arm.body.kind
    {
        if let [] = statements {
            Some(expr)
        } else {
            Some(arm.body)
        }
    } else {
        None
    }
}

/// If this is the else body of an if/else expression, then we need to wrap
/// it in curly braces. Otherwise, we don't.
fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
        let mut should_wrap = false;

        if let Some(Expr {
            kind:
                ExprKind::Match(
                    _,
                    arms,
                    MatchSource::IfLetDesugar {
                        contains_else_clause: true,
                    },
                ),
            ..
        }) = parent.expr
        {
            should_wrap = expr.hir_id == arms[1].body.hir_id;
        } else if let Some(Expr {
            kind: ExprKind::If(_, _, Some(else_clause)),
            ..
        }) = parent.expr
        {
            should_wrap = expr.hir_id == else_clause.hir_id;
        }

        should_wrap
    })
}

fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
    format!(
        "{}{}",
        Sugg::hir(cx, cond_expr, "..").maybe_par(),
        if as_mut {
            ".as_mut()"
        } else if as_ref {
            ".as_ref()"
        } else {
            ""
        }
    )
}

/// If this expression is the option if let/else construct we're detecting, then
/// this function returns an `OptionIfLetElseOccurence` struct with details if
/// this construct is found, or None if this construct is not found.
fn detect_option_if_let_else<'tcx>(
    cx: &'_ LateContext<'tcx>,
    expr: &'_ Expr<'tcx>,
) -> Option<OptionIfLetElseOccurence> {
    if_chain! {
        if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly
        if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
        if !is_else_clause(cx.tcx, expr);
        if arms.len() == 2;
        if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already
        if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind;
        if is_lang_ctor(cx, struct_qpath, OptionSome);
        if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
        if !contains_return_break_continue_macro(arms[0].body);
        if !contains_return_break_continue_macro(arms[1].body);

        then {
            let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
            let some_body = extract_body_from_arm(&arms[0])?;
            let none_body = extract_body_from_arm(&arms[1])?;
            let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" };
            let capture_name = id.name.to_ident_string();
            let wrap_braces = should_wrap_in_braces(cx, expr);
            let (as_ref, as_mut) = match &cond_expr.kind {
                ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
                _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut),
            };
            let cond_expr = match &cond_expr.kind {
                // Pointer dereferencing happens automatically, so we can omit it in the suggestion
                ExprKind::Unary(UnOp::Deref, expr) | ExprKind::AddrOf(_, _, expr) => expr,
                _ => cond_expr,
            };
            Some(OptionIfLetElseOccurence {
                option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
                method_sugg: method_sugg.to_string(),
                some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")),
                none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")),
                wrap_braces,
            })
        } else {
            None
        }
    }
}

impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
        if let Some(detection) = detect_option_if_let_else(cx, expr) {
            span_lint_and_sugg(
                cx,
                OPTION_IF_LET_ELSE,
                expr.span,
                format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(),
                "try",
                format!(
                    "{}{}.{}({}, {}){}",
                    if detection.wrap_braces { "{ " } else { "" },
                    detection.option,
                    detection.method_sugg,
                    detection.none_expr,
                    detection.some_expr,
                    if detection.wrap_braces { " }" } else { "" },
                ),
                Applicability::MaybeIncorrect,
            );
        }
    }
}
<commit_msg>Remove dead code after not linting else if let<commit_after>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::contains_return_break_continue_macro;
use clippy_utils::{eager_or_lazy, in_macro, is_else_clause, is_lang_ctor};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionSome;
use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:**
    /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more
    /// idiomatically done with `Option::map_or` (if the else bit is a pure
    /// expression) or `Option::map_or_else` (if the else bit is an impure
    /// expression).
    ///
    /// **Why is this bad?**
    /// Using the dedicated functions of the Option type is clearer and
    /// more concise than an `if let` expression.
    ///
    /// **Known problems:**
    /// This lint uses a deliberately conservative metric for checking
    /// if the inside of either body contains breaks or continues which will
    /// cause it to not suggest a fix if either block contains a loop with
    /// continues or breaks contained within the loop.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// # let optional: Option<u32> = Some(0);
    /// # fn do_complicated_function() -> u32 { 5 };
    /// let _ = if let Some(foo) = optional {
    ///     foo
    /// } else {
    ///     5
    /// };
    /// let _ = if let Some(foo) = optional {
    ///     foo
    /// } else {
    ///     let y = do_complicated_function();
    ///     y*y
    /// };
    /// ```
    ///
    /// should be
    ///
    /// ```rust
    /// # let optional: Option<u32> = Some(0);
    /// # fn do_complicated_function() -> u32 { 5 };
    /// let _ = optional.map_or(5, |foo| foo);
    /// let _ = optional.map_or_else(||{
    ///     let y = do_complicated_function();
    ///     y*y
    /// }, |foo| foo);
    /// ```
    pub OPTION_IF_LET_ELSE,
    pedantic,
    "reimplementation of Option::map_or"
}

declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);

/// Returns true iff the given expression is the result of calling `Result::ok`
fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
    if let ExprKind::MethodCall(path, _, &[ref receiver], _) = &expr.kind {
        path.ident.name.as_str() == "ok"
            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::result_type)
    } else {
        false
    }
}

/// A struct containing information about occurrences of the
/// `if let Some(..) = .. else` construct that this lint detects.
struct OptionIfLetElseOccurence {
    option: String,
    method_sugg: String,
    some_expr: String,
    none_expr: String,
}

/// Extracts the body of a given arm. If the arm contains only an expression,
/// then it returns the expression. Otherwise, it returns the entire block
fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
    if let ExprKind::Block(
        Block {
            stmts: statements,
            expr: Some(expr),
            ..
        },
        _,
    ) = &arm.body.kind
    {
        if let [] = statements {
            Some(expr)
        } else {
            Some(arm.body)
        }
    } else {
        None
    }
}

fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
    format!(
        "{}{}",
        Sugg::hir(cx, cond_expr, "..").maybe_par(),
        if as_mut {
            ".as_mut()"
        } else if as_ref {
            ".as_ref()"
        } else {
            ""
        }
    )
}

/// If this expression is the option if let/else construct we're detecting, then
/// this function returns an `OptionIfLetElseOccurence` struct with details if
/// this construct is found, or None if this construct is not found.
fn detect_option_if_let_else<'tcx>(
    cx: &'_ LateContext<'tcx>,
    expr: &'_ Expr<'tcx>,
) -> Option<OptionIfLetElseOccurence> {
    if_chain! {
        if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly
        if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
        if !is_else_clause(cx.tcx, expr);
        if arms.len() == 2;
        if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already
        if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind;
        if is_lang_ctor(cx, struct_qpath, OptionSome);
        if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
        if !contains_return_break_continue_macro(arms[0].body);
        if !contains_return_break_continue_macro(arms[1].body);

        then {
            let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
            let some_body = extract_body_from_arm(&arms[0])?;
            let none_body = extract_body_from_arm(&arms[1])?;
            let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" };
            let capture_name = id.name.to_ident_string();
            let (as_ref, as_mut) = match &cond_expr.kind {
                ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
                _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut),
            };
            let cond_expr = match &cond_expr.kind {
                // Pointer dereferencing happens automatically, so we can omit it in the suggestion
                ExprKind::Unary(UnOp::Deref, expr) | ExprKind::AddrOf(_, _, expr) => expr,
                _ => cond_expr,
            };
            Some(OptionIfLetElseOccurence {
                option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
                method_sugg: method_sugg.to_string(),
                some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")),
                none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")),
            })
        } else {
            None
        }
    }
}

impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
        if let Some(detection) = detect_option_if_let_else(cx, expr) {
            span_lint_and_sugg(
                cx,
                OPTION_IF_LET_ELSE,
                expr.span,
                format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(),
                "try",
                format!(
                    "{}.{}({}, {})",
                    detection.option, detection.method_sugg, detection.none_expr, detection.some_expr,
                ),
                Applicability::MaybeIncorrect,
            );
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

//! A module containing the HTTP server and handlers for servicing client requests

pub mod handlers;

use std::sync::{mpsc, Arc};
use std::thread::{self, JoinHandle};

use depot;
use hab_net::http::middleware::*;
use hab_net::oauth::github::GitHubClient;
use hab_net::privilege;
use hab_core::event::EventLogger;
use iron::prelude::*;
use mount::Mount;
use persistent::{self, Read};
use staticfile::Static;

use config::Config;
use error::Result;
use self::handlers::*;

// Iron defaults to a threadpool of size `8 * num_cpus`.
// See: http://172.16.2.131:9633/iron/prelude/struct.Iron.html#method.http
const HTTP_THREAD_COUNT: usize = 128;

/// Create a new `iron::Chain` containing a Router and it's required middleware
pub fn router(config: Arc<Config>) -> Result<Chain> {
    let basic = Authenticated::new(&*config);
    let bldr = Authenticated::new(&*config).require(privilege::BUILDER);
    let router = router!(
        status: get "/status" => status,
        authenticate: get "/authenticate/:code" => github_authenticate,

        jobs: post "/jobs" => XHandler::new(job_create).before(bldr.clone()),
        job: get "/jobs/:id" => XHandler::new(job_show).before(bldr.clone()),
        job_log: get "/jobs/:id/log" => XHandler::new(job_log).before(bldr.clone()),

        user_invitations: get "/user/invitations" => {
            XHandler::new(list_account_invitations).before(basic.clone())
        },
        user_origins: get "/user/origins" => XHandler::new(list_user_origins).before(basic.clone()),

        projects: post "/projects" => XHandler::new(project_create).before(bldr.clone()),
        project: get "/projects/:origin/:name" => XHandler::new(project_show).before(bldr.clone()),

        project_jobs: get "/projects/:origin/:name/jobs" => {
            XHandler::new(project_jobs).before(bldr.clone())
        },
        edit_project: put "/projects/:origin/:name" => {
            XHandler::new(project_update).before(bldr.clone())
        },
        delete_project: delete "/projects/:origin/:name" => {
            XHandler::new(project_delete).before(bldr.clone())
        }
    );
    let mut chain = Chain::new(router);
    chain.link(persistent::Read::<GitHubCli>::both(GitHubClient::new(&*config)));
    chain.link(Read::<EventLog>::both(EventLogger::new(&config.log_dir, config.events_enabled)));
    chain.link_before(RouteBroker);
    chain.link_after(Cors);
    Ok(chain)
}

/// Create a new HTTP listener and run it in a separate thread. This function will block the calling
/// thread until the new listener has successfully started.
///
/// # Errors
///
/// * Depot could not be started
/// * Couldn't create Router or it's middleware
///
/// # Panics
///
/// * Listener crashed during startup
pub fn run(config: Arc<Config>) -> Result<JoinHandle<()>> {
    let (tx, rx) = mpsc::sync_channel(1);

    let depot = depot::DepotUtil::new(config.depot.clone());
    let depot_chain = try!(depot::server::router(depot));

    let mut mount = Mount::new();
    if let Some(ref path) = config.ui.root {
        debug!("Mounting UI at filepath {}", path);
        mount.mount("/", Static::new(path));
    }
    let chain = try!(router(config.clone()));
    mount.mount("/v1", chain).mount("/v1/depot", depot_chain);

    let handle = thread::Builder::new()
        .name("http-srv".to_string())
        .spawn(move || {
                   let mut server = Iron::new(mount);
                   server.threads = HTTP_THREAD_COUNT;
                   server.http(&config.http).unwrap();
                   tx.send(()).unwrap();
               })
        .unwrap();
    match rx.recv() {
        Ok(()) => Ok(handle),
        Err(e) => panic!("http-srv thread startup error, err={}", e),
    }
}
<commit_msg>Relax authorization checks on Builder API read-only endpoints<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

//! A module containing the HTTP server and handlers for servicing client requests

pub mod handlers;

use std::sync::{mpsc, Arc};
use std::thread::{self, JoinHandle};

use depot;
use hab_net::http::middleware::*;
use hab_net::oauth::github::GitHubClient;
use hab_net::privilege;
use hab_core::event::EventLogger;
use iron::prelude::*;
use mount::Mount;
use persistent::{self, Read};
use staticfile::Static;

use config::Config;
use error::Result;
use self::handlers::*;

// Iron defaults to a threadpool of size `8 * num_cpus`.
// See: http://172.16.2.131:9633/iron/prelude/struct.Iron.html#method.http
const HTTP_THREAD_COUNT: usize = 128;

/// Create a new `iron::Chain` containing a Router and it's required middleware
pub fn router(config: Arc<Config>) -> Result<Chain> {
    let basic = Authenticated::new(&*config);
    let bldr = Authenticated::new(&*config).require(privilege::BUILDER);
    let router = router!(
        status: get "/status" => status,
        authenticate: get "/authenticate/:code" => github_authenticate,

        jobs: post "/jobs" => XHandler::new(job_create).before(bldr.clone()),
        job: get "/jobs/:id" => XHandler::new(job_show).before(basic.clone()),
        job_log: get "/jobs/:id/log" => XHandler::new(job_log).before(basic.clone()),

        user_invitations: get "/user/invitations" => {
            XHandler::new(list_account_invitations).before(basic.clone())
        },
        user_origins: get "/user/origins" => XHandler::new(list_user_origins).before(basic.clone()),

        projects: post "/projects" => XHandler::new(project_create).before(bldr.clone()),
        project: get "/projects/:origin/:name" => XHandler::new(project_show).before(basic.clone()),
        project_jobs: get "/projects/:origin/:name/jobs" => {
            XHandler::new(project_jobs).before(basic.clone())
        },
        edit_project: put "/projects/:origin/:name" => {
            XHandler::new(project_update).before(bldr.clone())
        },
        delete_project: delete "/projects/:origin/:name" => {
            XHandler::new(project_delete).before(bldr.clone())
        }
    );
    let mut chain = Chain::new(router);
    chain.link(persistent::Read::<GitHubCli>::both(GitHubClient::new(&*config)));
    chain.link(Read::<EventLog>::both(EventLogger::new(&config.log_dir, config.events_enabled)));
    chain.link_before(RouteBroker);
    chain.link_after(Cors);
    Ok(chain)
}

/// Create a new HTTP listener and run it in a separate thread. This function will block the calling
/// thread until the new listener has successfully started.
///
/// # Errors
///
/// * Depot could not be started
/// * Couldn't create Router or it's middleware
///
/// # Panics
///
/// * Listener crashed during startup
pub fn run(config: Arc<Config>) -> Result<JoinHandle<()>> {
    let (tx, rx) = mpsc::sync_channel(1);

    let depot = depot::DepotUtil::new(config.depot.clone());
    let depot_chain = try!(depot::server::router(depot));

    let mut mount = Mount::new();
    if let Some(ref path) = config.ui.root {
        debug!("Mounting UI at filepath {}", path);
        mount.mount("/", Static::new(path));
    }
    let chain = try!(router(config.clone()));
    mount.mount("/v1", chain).mount("/v1/depot", depot_chain);

    let handle = thread::Builder::new()
        .name("http-srv".to_string())
        .spawn(move || {
                   let mut server = Iron::new(mount);
                   server.threads = HTTP_THREAD_COUNT;
                   server.http(&config.http).unwrap();
                   tx.send(()).unwrap();
               })
        .unwrap();
    match rx.recv() {
        Ok(()) => Ok(handle),
        Err(e) => panic!("http-srv thread startup error, err={}", e),
    }
}
<|endoftext|>