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

use mimir;

use geojson;
use geo;
use std::rc::Rc;

#[derive(Serialize, Deserialize, Debug)]
pub struct Geocoding {
    version: String,
    query: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Feature {
    #[serde(rename = "type")] pub feature_type: String,
    pub geometry: geojson::Geometry,
    pub properties: Properties,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Properties {
    pub geocoding: GeocodingResponse,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GeocodingResponse {
    pub id: String,
    #[serde(rename = "type")] pub place_type: String, // FIXME: use an enum?
    pub label: Option<String>,
    pub name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub housenumber: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub street: Option<String>,
    pub postcode: Option<String>,
    pub city: Option<String>,
    pub citycode: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub level: Option<u32>,
    // pub accuracy: Option<i32>,
    // pub district: Option<String>,
    // pub county: Option<String>,
    // pub state: Option<String>,
    // pub country: Option<String>,
    // pub geohash: Option<String>,
    pub administrative_regions: Vec<Rc<mimir::Admin>>,
    #[serde(skip_serializing_if = "Vec::is_empty", default)] pub poi_types: Vec<mimir::PoiType>,
    #[serde(skip_serializing_if = "Vec::is_empty", default)] pub properties: Vec<mimir::Property>,
}

trait ToGeom {
    fn to_geom(&self) -> geojson::Geometry;
}

impl ToGeom for mimir::Place {
    fn to_geom(&self) -> geojson::Geometry {
        match self {
            &mimir::Place::Admin(ref admin) => admin.coord.to_geom(),
            &mimir::Place::Street(ref street) => street.coord.to_geom(),
            &mimir::Place::Addr(ref addr) => addr.coord.to_geom(),
            &mimir::Place::Poi(ref poi) => poi.coord.to_geom(),
            &mimir::Place::Stop(ref stop) => stop.coord.to_geom(),
        }
    }
}

impl ToGeom for geo::Coordinate<f64> {
    fn to_geom(&self) -> geojson::Geometry {
        geojson::Geometry::new(geojson::Value::Point(vec![self.y, self.x]))
    }
}

impl From<mimir::Place> for Feature {
    fn from(other: mimir::Place) -> Feature {
        let geom = other.to_geom();
        let geocoding = match other {
            mimir::Place::Admin(admin) => GeocodingResponse::from(admin),
            mimir::Place::Street(street) => GeocodingResponse::from(street),
            mimir::Place::Addr(addr) => GeocodingResponse::from(addr),
            mimir::Place::Poi(poi) => GeocodingResponse::from(poi),
            mimir::Place::Stop(poi) => GeocodingResponse::from(poi),
        };
        Feature {
            feature_type: "Feature".to_string(),
            geometry: geom,
            properties: Properties {
                geocoding: geocoding,
            },
        }
    }
}

impl From<mimir::Admin> for GeocodingResponse {
    fn from(other: mimir::Admin) -> GeocodingResponse {
        let type_ = "city".to_string(); //to be improved: it can be something else
        let name = Some(other.name);
        let insee = Some(other.insee);
        let level = Some(other.level); //might be used for type_ and become useless
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let label = Some(other.label);
        GeocodingResponse {
            id: other.id,
            citycode: insee,
            level: level,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: None,
            street: None,
            city: None,
            administrative_regions: vec![],
            poi_types: vec![],
            properties: vec![],
        }
    }
}

fn get_city_name(admins: &Vec<Rc<mimir::Admin>>) -> Option<String> {
    // for the moment for the 'postcode' and the 'city', we take first admin
    // that has a postcode
    // TODO: change this (with a 'city tag in the admin ?')
    admins
        .iter()
        .find(|a| !a.zip_codes.is_empty())
        .or_else(|| admins.iter().next())
        .map(|admin| admin.name.clone())
}

fn get_citycode(admins: &Vec<Rc<mimir::Admin>>) -> Option<String> {
    admins
        .iter()
        .find(|a| !a.zip_codes.is_empty())
        .or_else(|| admins.iter().next())
        .map(|admin| admin.insee.clone())
}

impl From<mimir::Street> for GeocodingResponse {
    fn from(other: mimir::Street) -> GeocodingResponse {
        let type_ = "street".to_string();
        let name = Some(other.street_name);
        let label = Some(other.label);
        let admins = other.administrative_regions;
        let city = get_city_name(&admins);
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let citycode = get_citycode(&admins);

        GeocodingResponse {
            id: other.id,
            citycode: citycode,
            level: None,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: None,
            street: None,
            city: city,
            administrative_regions: admins,
            poi_types: vec![],
            properties: vec![],
        }
    }
}

impl From<mimir::Addr> for GeocodingResponse {
    fn from(other: mimir::Addr) -> GeocodingResponse {
        let type_ = "house".to_string();
        let label = Some(other.label);
        let housenumber = Some(other.house_number.to_string());
        let street_name = Some(other.street.street_name.to_string());
        let name = Some(format!(
            "{} {}",
            other.house_number, other.street.street_name
        ));
        let admins = other.street.administrative_regions;
        let city = get_city_name(&admins);
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let citycode = get_citycode(&admins);

        GeocodingResponse {
            id: other.id,
            citycode: citycode,
            level: None,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: housenumber,
            street: street_name,
            city: city,
            administrative_regions: admins,
            poi_types: vec![],
            properties: vec![],
        }
    }
}

impl From<mimir::Poi> for GeocodingResponse {
    fn from(other: mimir::Poi) -> GeocodingResponse {
        let type_ = "poi".to_string();
        let label = Some(other.label);
        let name = Some(other.name);
        let admins = other.administrative_regions;
        let city = get_city_name(&admins);
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let citycode = get_citycode(&admins);

        GeocodingResponse {
            id: other.id,
            citycode: citycode,
            level: None,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: None,
            street: None,
            city: city,
            administrative_regions: admins,
            poi_types: vec![other.poi_type],
            properties: other.properties,
        }
    }
}

impl From<mimir::Stop> for GeocodingResponse {
    fn from(other: mimir::Stop) -> GeocodingResponse {
        let type_ = "public_transport:stop_area".to_string();
        let label = Some(other.label);
        let name = Some(other.name);
        let admins = other.administrative_regions;
        let city = get_city_name(&admins);
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let citycode = get_citycode(&admins);

        GeocodingResponse {
            id: other.id,
            citycode: citycode,
            level: None,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: None,
            street: None,
            city: city,
            administrative_regions: admins,
            poi_types: vec![],
            properties: vec![],
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Autocomplete {
    #[serde(rename = "type")] format_type: String,
    geocoding: Geocoding,
    features: Vec<Feature>,
}

impl Autocomplete {
    pub fn new(q: String, features: Vec<Feature>) -> Autocomplete {
        // TODO couldn't we mode this function ? in Autocomplete ?
        Autocomplete {
            format_type: "FeatureCollection".to_string(),
            geocoding: Geocoding {
                version: "0.1.0".to_string(),
                query: Some(q),
            },
            features: features,
        }
    }
}

impl From<Vec<mimir::Place>> for Autocomplete {
    fn from(places: Vec<mimir::Place>) -> Autocomplete {
        Autocomplete::new(
            "".to_string(),
            places.into_iter().map(|p| Feature::from(p)).collect(),
        )
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Coord {
    pub lat: f64,
    pub lon: f64,
}

pub mod v1 {
    use mimir;
    use rs_es;

    // Note: I think this should be in api.rs but with the serde stuff it's easier for all
    // serde struct to be in the same file

    #[derive(Serialize, Deserialize, Debug)]
    pub struct EndPoint {
        pub description: String,
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub struct CustomError {
        pub short: String,
        pub long: String,
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub enum V1Reponse {
        Error(CustomError),
        Response { description: String },
    }
    #[derive(Debug)]
    pub enum AutocompleteResponse {
        Error(CustomError),
        Autocomplete(super::Autocomplete),
    }

    use serde;
    impl serde::Serialize for AutocompleteResponse {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: serde::Serializer,
        {
            match self {
                &AutocompleteResponse::Autocomplete(ref a) => serializer.serialize_some(a),
                &AutocompleteResponse::Error(ref e) => serializer.serialize_some(e),
            }
        }
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub struct Status {
        pub version: String,
        pub es: String,
        pub status: String,
    }

    impl From<Result<Vec<mimir::Place>, rs_es::error::EsError>> for AutocompleteResponse {
        fn from(r: Result<Vec<mimir::Place>, rs_es::error::EsError>) -> AutocompleteResponse {
            match r {
                Ok(places) => AutocompleteResponse::Autocomplete(super::Autocomplete::from(places)),
                Err(e) => AutocompleteResponse::Error(CustomError {
                    short: "query error".to_string(),
                    long: format!("invalid query {:?}", e),
                }),
            }
        }
    }
}
<commit_msg>Add street in street<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use mimir;

use geojson;
use geo;
use std::rc::Rc;

#[derive(Serialize, Deserialize, Debug)]
pub struct Geocoding {
    version: String,
    query: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Feature {
    #[serde(rename = "type")] pub feature_type: String,
    pub geometry: geojson::Geometry,
    pub properties: Properties,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Properties {
    pub geocoding: GeocodingResponse,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GeocodingResponse {
    pub id: String,
    #[serde(rename = "type")] pub place_type: String, // FIXME: use an enum?
    pub label: Option<String>,
    pub name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub housenumber: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub street: Option<String>,
    pub postcode: Option<String>,
    pub city: Option<String>,
    pub citycode: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub level: Option<u32>,
    // pub accuracy: Option<i32>,
    // pub district: Option<String>,
    // pub county: Option<String>,
    // pub state: Option<String>,
    // pub country: Option<String>,
    // pub geohash: Option<String>,
    pub administrative_regions: Vec<Rc<mimir::Admin>>,
    #[serde(skip_serializing_if = "Vec::is_empty", default)] pub poi_types: Vec<mimir::PoiType>,
    #[serde(skip_serializing_if = "Vec::is_empty", default)] pub properties: Vec<mimir::Property>,
}

trait ToGeom {
    fn to_geom(&self) -> geojson::Geometry;
}

impl ToGeom for mimir::Place {
    fn to_geom(&self) -> geojson::Geometry {
        match self {
            &mimir::Place::Admin(ref admin) => admin.coord.to_geom(),
            &mimir::Place::Street(ref street) => street.coord.to_geom(),
            &mimir::Place::Addr(ref addr) => addr.coord.to_geom(),
            &mimir::Place::Poi(ref poi) => poi.coord.to_geom(),
            &mimir::Place::Stop(ref stop) => stop.coord.to_geom(),
        }
    }
}

impl ToGeom for geo::Coordinate<f64> {
    fn to_geom(&self) -> geojson::Geometry {
        geojson::Geometry::new(geojson::Value::Point(vec![self.y, self.x]))
    }
}

impl From<mimir::Place> for Feature {
    fn from(other: mimir::Place) -> Feature {
        let geom = other.to_geom();
        let geocoding = match other {
            mimir::Place::Admin(admin) => GeocodingResponse::from(admin),
            mimir::Place::Street(street) => GeocodingResponse::from(street),
            mimir::Place::Addr(addr) => GeocodingResponse::from(addr),
            mimir::Place::Poi(poi) => GeocodingResponse::from(poi),
            mimir::Place::Stop(poi) => GeocodingResponse::from(poi),
        };
        Feature {
            feature_type: "Feature".to_string(),
            geometry: geom,
            properties: Properties {
                geocoding: geocoding,
            },
        }
    }
}

impl From<mimir::Admin> for GeocodingResponse {
    fn from(other: mimir::Admin) -> GeocodingResponse {
        let type_ = "city".to_string(); //to be improved: it can be something else
        let name = Some(other.name);
        let insee = Some(other.insee);
        let level = Some(other.level); //might be used for type_ and become useless
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let label = Some(other.label);
        GeocodingResponse {
            id: other.id,
            citycode: insee,
            level: level,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: None,
            street: None,
            city: None,
            administrative_regions: vec![],
            poi_types: vec![],
            properties: vec![],
        }
    }
}

fn get_city_name(admins: &Vec<Rc<mimir::Admin>>) -> Option<String> {
    // for the moment for the 'postcode' and the 'city', we take first admin
    // that has a postcode
    // TODO: change this (with a 'city tag in the admin ?')
    admins
        .iter()
        .find(|a| !a.zip_codes.is_empty())
        .or_else(|| admins.iter().next())
        .map(|admin| admin.name.clone())
}

fn get_citycode(admins: &Vec<Rc<mimir::Admin>>) -> Option<String> {
    admins
        .iter()
        .find(|a| !a.zip_codes.is_empty())
        .or_else(|| admins.iter().next())
        .map(|admin| admin.insee.clone())
}

impl From<mimir::Street> for GeocodingResponse {
    fn from(other: mimir::Street) -> GeocodingResponse {
        let type_ = "street".to_string();
        let name = Some(other.street_name);
        let label = Some(other.label);
        let admins = other.administrative_regions;
        let city = get_city_name(&admins);
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let citycode = get_citycode(&admins);

        GeocodingResponse {
            id: other.id,
            citycode: citycode,
            level: None,
            place_type: type_,
            name: name.clone(),
            postcode: postcode,
            label: label,
            housenumber: None,
            street: name,
            city: city,
            administrative_regions: admins,
            poi_types: vec![],
            properties: vec![],
        }
    }
}

impl From<mimir::Addr> for GeocodingResponse {
    fn from(other: mimir::Addr) -> GeocodingResponse {
        let type_ = "house".to_string();
        let label = Some(other.label);
        let housenumber = Some(other.house_number.to_string());
        let street_name = Some(other.street.street_name.to_string());
        let name = Some(format!(
            "{} {}",
            other.house_number, other.street.street_name
        ));
        let admins = other.street.administrative_regions;
        let city = get_city_name(&admins);
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let citycode = get_citycode(&admins);

        GeocodingResponse {
            id: other.id,
            citycode: citycode,
            level: None,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: housenumber,
            street: street_name,
            city: city,
            administrative_regions: admins,
            poi_types: vec![],
            properties: vec![],
        }
    }
}

impl From<mimir::Poi> for GeocodingResponse {
    fn from(other: mimir::Poi) -> GeocodingResponse {
        let type_ = "poi".to_string();
        let label = Some(other.label);
        let name = Some(other.name);
        let admins = other.administrative_regions;
        let city = get_city_name(&admins);
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let citycode = get_citycode(&admins);

        GeocodingResponse {
            id: other.id,
            citycode: citycode,
            level: None,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: None,
            street: None,
            city: city,
            administrative_regions: admins,
            poi_types: vec![other.poi_type],
            properties: other.properties,
        }
    }
}

impl From<mimir::Stop> for GeocodingResponse {
    fn from(other: mimir::Stop) -> GeocodingResponse {
        let type_ = "public_transport:stop_area".to_string();
        let label = Some(other.label);
        let name = Some(other.name);
        let admins = other.administrative_regions;
        let city = get_city_name(&admins);
        let postcode = if other.zip_codes.is_empty() {
            None
        } else {
            Some(other.zip_codes.join(";"))
        };
        let citycode = get_citycode(&admins);

        GeocodingResponse {
            id: other.id,
            citycode: citycode,
            level: None,
            place_type: type_,
            name: name,
            postcode: postcode,
            label: label,
            housenumber: None,
            street: None,
            city: city,
            administrative_regions: admins,
            poi_types: vec![],
            properties: vec![],
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Autocomplete {
    #[serde(rename = "type")] format_type: String,
    geocoding: Geocoding,
    features: Vec<Feature>,
}

impl Autocomplete {
    pub fn new(q: String, features: Vec<Feature>) -> Autocomplete {
        // TODO couldn't we mode this function ? in Autocomplete ?
        Autocomplete {
            format_type: "FeatureCollection".to_string(),
            geocoding: Geocoding {
                version: "0.1.0".to_string(),
                query: Some(q),
            },
            features: features,
        }
    }
}

impl From<Vec<mimir::Place>> for Autocomplete {
    fn from(places: Vec<mimir::Place>) -> Autocomplete {
        Autocomplete::new(
            "".to_string(),
            places.into_iter().map(|p| Feature::from(p)).collect(),
        )
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Coord {
    pub lat: f64,
    pub lon: f64,
}

pub mod v1 {
    use mimir;
    use rs_es;

    // Note: I think this should be in api.rs but with the serde stuff it's easier for all
    // serde struct to be in the same file

    #[derive(Serialize, Deserialize, Debug)]
    pub struct EndPoint {
        pub description: String,
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub struct CustomError {
        pub short: String,
        pub long: String,
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub enum V1Reponse {
        Error(CustomError),
        Response { description: String },
    }
    #[derive(Debug)]
    pub enum AutocompleteResponse {
        Error(CustomError),
        Autocomplete(super::Autocomplete),
    }

    use serde;
    impl serde::Serialize for AutocompleteResponse {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: serde::Serializer,
        {
            match self {
                &AutocompleteResponse::Autocomplete(ref a) => serializer.serialize_some(a),
                &AutocompleteResponse::Error(ref e) => serializer.serialize_some(e),
            }
        }
    }

    #[derive(Serialize, Deserialize, Debug)]
    pub struct Status {
        pub version: String,
        pub es: String,
        pub status: String,
    }

    impl From<Result<Vec<mimir::Place>, rs_es::error::EsError>> for AutocompleteResponse {
        fn from(r: Result<Vec<mimir::Place>, rs_es::error::EsError>) -> AutocompleteResponse {
            match r {
                Ok(places) => AutocompleteResponse::Autocomplete(super::Autocomplete::from(places)),
                Err(e) => AutocompleteResponse::Error(CustomError {
                    short: "query error".to_string(),
                    long: format!("invalid query {:?}", e),
                }),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let out_path = Path::new(&out_dir).join("bindgen.rs");
    if cfg!(feature = "sqlcipher") {
        if cfg!(feature = "bundled") {
            println!(
                "cargo:warning={}",
                "Builds with bundled SQLCipher are not supported. Searching for SQLCipher to link against. \
                 This can lead to issues if your version of SQLCipher is not up to date!");
        }
        build_linked::main(&out_dir, &out_path)
    } else {
        // This can't be `cfg!` without always requiring our `mod build_bundled` (and thus `cc`)
        #[cfg(feature = "bundled")]
        {
            build_bundled::main(&out_dir, &out_path)
        }
        #[cfg(not(feature = "bundled"))]
        {
            build_linked::main(&out_dir, &out_path)
        }
    }
}

#[cfg(feature = "bundled")]
mod build_bundled {
    use cc;
    use std::path::Path;
    use std::env;

    pub fn main(out_dir: &str, out_path: &Path) {
        if cfg!(feature = "sqlcipher") {
            // This is just a sanity check, the top level `main` should ensure this.
            panic!("Builds with bundled SQLCipher are not supported");
        }

        #[cfg(feature = "buildtime_bindgen")]
        {
            use super::{bindings, HeaderLocation};
            let header = HeaderLocation::FromPath("sqlite3/sqlite3.h".to_owned());
            bindings::write_to_out_dir(header, out_path);
        }
        #[cfg(not(feature = "buildtime_bindgen"))]
        {
            use std::fs;
            fs::copy("sqlite3/bindgen_bundled_version.rs", out_path)
                .expect("Could not copy bindings to output directory");
        }

        let mut cfg = cc::Build::new();
        cfg.file("sqlite3/sqlite3.c")
            .flag("-DSQLITE_CORE")
            .flag("-DSQLITE_DEFAULT_FOREIGN_KEYS=1")
            .flag("-DSQLITE_ENABLE_API_ARMOR")
            .flag("-DSQLITE_ENABLE_COLUMN_METADATA")
            .flag("-DSQLITE_ENABLE_DBSTAT_VTAB")
            .flag("-DSQLITE_ENABLE_FTS3")
            .flag("-DSQLITE_ENABLE_FTS3_PARENTHESIS")
            .flag("-DSQLITE_ENABLE_FTS5")
            .flag("-DSQLITE_ENABLE_JSON1")
            .flag("-DSQLITE_ENABLE_LOAD_EXTENSION=1")
            .flag("-DSQLITE_ENABLE_MEMORY_MANAGEMENT")
            .flag("-DSQLITE_ENABLE_RTREE")
            .flag("-DSQLITE_ENABLE_STAT2")
            .flag("-DSQLITE_ENABLE_STAT4")
            .flag("-DSQLITE_HAVE_ISNAN")
            .flag("-DSQLITE_SOUNDEX")
            .flag("-DSQLITE_THREADSAFE=1")
            .flag("-DSQLITE_USE_URI")
            .flag("-DHAVE_USLEEP=1");
        if cfg!(feature = "unlock_notify") {
            cfg.flag("-DSQLITE_ENABLE_UNLOCK_NOTIFY");
        }
        if cfg!(feature = "preupdate_hook") {
            cfg.flag("-DSQLITE_ENABLE_PREUPDATE_HOOK");
        }
        if cfg!(feature = "session") {
            cfg.flag("-DSQLITE_ENABLE_SESSION");
        }

        if let Ok(limit) = env::var("SQLITE_MAX_VARIABLE_NUMBER") {
            cfg.flag(&format!("-DSQLITE_MAX_VARIABLE_NUMBER={}", limit));
        }
        println!("cargo:rerun-if-env-changed=SQLITE_MAX_VARIABLE_NUMBER");

        if let Ok(limit) = env::var("SQLITE_MAX_EXPR_DEPTH") {
            cfg.flag(&format!("-DSQLITE_MAX_EXPR_DEPTH={}", limit));
        }
        println!("cargo:rerun-if-env-changed=SQLITE_MAX_EXPR_DEPTH");

        cfg.compile("libsqlite3.a");

        println!("cargo:lib_dir={}", out_dir);
    }
}

fn env_prefix() -> &'static str {
    if cfg!(feature = "sqlcipher") {
        "SQLCIPHER"
    } else {
        "SQLITE3"
    }
}

pub enum HeaderLocation {
    FromEnvironment,
    Wrapper,
    FromPath(String),
}

impl From<HeaderLocation> for String {
    fn from(header: HeaderLocation) -> String {
        match header {
            HeaderLocation::FromEnvironment => {
                let prefix = env_prefix();
                let mut header = env::var(format!("{}_INCLUDE_DIR", prefix)).expect(&format!(
                    "{}_INCLUDE_DIR must be set if {}_LIB_DIR is set",
                    prefix, prefix
                ));
                header.push_str("/sqlite3.h");
                header
            }
            HeaderLocation::Wrapper => "wrapper.h".into(),
            HeaderLocation::FromPath(path) => path,
        }
    }
}

mod build_linked {
    use pkg_config;

    #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
    extern crate vcpkg;

    use super::{bindings, env_prefix, HeaderLocation};
    use std::env;
    use std::path::Path;

    pub fn main(_out_dir: &str, out_path: &Path) {
        let header = find_sqlite();
        if cfg!(feature = "bundled") && !cfg!(feature = "buildtime_bindgen") {
            // We can only get here if `bundled` and `sqlcipher` were both
            // specified (and `builtime_bindgen` was not). In order to keep
            // `rusqlite` relatively clean we hide the fact that `bundled` can
            // be ignored in some cases, and just use the bundled bindings, even
            // though the library we found might not match their version.
            // Ideally we'd perform a version check here, but doing so is rather
            // tricky, since we might not have access to executables (and
            // moreover, we might be cross compiling).
            std::fs::copy("sqlite3/bindgen_bundled_version.rs", out_path)
                .expect("Could not copy bindings to output directory");
        } else {
            bindings::write_to_out_dir(header, out_path);
        }
    }

    fn find_link_mode() -> &'static str {
        // If the user specifies SQLITE_STATIC (or SQLCIPHER_STATIC), do static
        // linking, unless it's explicitly set to 0.
        match &env::var(format!("{}_STATIC", env_prefix())) {
            Ok(v) if v != "0" => "static",
            _ => "dylib",
        }
    }
    // Prints the necessary cargo link commands and returns the path to the header.
    fn find_sqlite() -> HeaderLocation {
        let link_lib = link_lib();

        println!("cargo:rerun-if-env-changed={}_INCLUDE_DIR", env_prefix());
        println!("cargo:rerun-if-env-changed={}_LIB_DIR", env_prefix());
        println!("cargo:rerun-if-env-changed={}_STATIC", env_prefix());
        if cfg!(target_os = "windows") {
            println!("cargo:rerun-if-env-changed=PATH");
        }
        if cfg!(all(feature = "vcpkg", target_env = "msvc")) {
            println!("cargo:rerun-if-env-changed=VCPKGRS_DYNAMIC");
        }
        // Allow users to specify where to find SQLite.
        if let Ok(dir) = env::var(format!("{}_LIB_DIR", env_prefix())) {
            // Try to use pkg-config to determine link commands
            let pkgconfig_path = Path::new(&dir).join("pkgconfig");
            env::set_var("PKG_CONFIG_PATH", pkgconfig_path);
            if let Err(_) = pkg_config::Config::new().probe(link_lib) {
                // Otherwise just emit the bare minimum link commands.
                println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib);
                println!("cargo:rustc-link-search={}", dir);
            }
            return HeaderLocation::FromEnvironment;
        }

        if let Some(header) = try_vcpkg() {
            return header;
        }

        // See if pkg-config can do everything for us.
        match pkg_config::Config::new()
            .print_system_libs(false)
            .probe(link_lib)
        {
            Ok(mut lib) => {
                if let Some(mut header) = lib.include_paths.pop() {
                    header.push("sqlite3.h");
                    HeaderLocation::FromPath(header.to_string_lossy().into())
                } else {
                    HeaderLocation::Wrapper
                }
            }
            Err(_) => {
                // No env var set and pkg-config couldn't help; just output the link-lib
                // request and hope that the library exists on the system paths. We used to
                // output /usr/lib explicitly, but that can introduce other linking problems;
                // see https://github.com/jgallagher/rusqlite/issues/207.
                println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib);
                HeaderLocation::Wrapper
            }
        }
    }

    #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
    fn try_vcpkg() -> Option<HeaderLocation> {
        // See if vcpkg can find it.
        if let Ok(mut lib) = vcpkg::Config::new().probe(link_lib()) {
            if let Some(mut header) = lib.include_paths.pop() {
                header.push("sqlite3.h");
                return Some(HeaderLocation::FromPath(header.to_string_lossy().into()));
            }
        }
        None
    }

    #[cfg(not(all(feature = "vcpkg", target_env = "msvc")))]
    fn try_vcpkg() -> Option<HeaderLocation> {
        None
    }

    fn link_lib() -> &'static str {
        if cfg!(feature = "sqlcipher") {
            "sqlcipher"
        } else {
            "sqlite3"
        }
    }
}

#[cfg(not(feature = "buildtime_bindgen"))]
mod bindings {
    use super::HeaderLocation;

    use std::fs;
    use std::path::Path;

    static PREBUILT_BINDGEN_PATHS: &'static [&'static str] = &[
        "bindgen-bindings/bindgen_3.6.8.rs",
        #[cfg(feature = "min_sqlite_version_3_6_23")]
        "bindgen-bindings/bindgen_3.6.23.rs",
        #[cfg(feature = "min_sqlite_version_3_7_7")]
        "bindgen-bindings/bindgen_3.7.7.rs",
        #[cfg(feature = "min_sqlite_version_3_7_16")]
        "bindgen-bindings/bindgen_3.7.16.rs",
    ];

    pub fn write_to_out_dir(_header: HeaderLocation, out_path: &Path) {
        let in_path = PREBUILT_BINDGEN_PATHS[PREBUILT_BINDGEN_PATHS.len() - 1];
        fs::copy(in_path, out_path).expect("Could not copy bindings to output directory");
    }
}

#[cfg(feature = "buildtime_bindgen")]
mod bindings {
    use bindgen;

    use self::bindgen::callbacks::{IntKind, ParseCallbacks};
    use super::HeaderLocation;

    use std::fs::OpenOptions;
    use std::io::Write;
    use std::path::Path;

    #[derive(Debug)]
    struct SqliteTypeChooser;

    impl ParseCallbacks for SqliteTypeChooser {
        fn int_macro(&self, _name: &str, value: i64) -> Option<IntKind> {
            if value >= i32::min_value() as i64 && value <= i32::max_value() as i64 {
                Some(IntKind::I32)
            } else {
                None
            }
        }
    }

    pub fn write_to_out_dir(header: HeaderLocation, out_path: &Path) {
        let header: String = header.into();
        let mut output = Vec::new();
        let mut bindings = bindgen::builder()
            .header(header.clone())
            .parse_callbacks(Box::new(SqliteTypeChooser))
            .rustfmt_bindings(true);

        if cfg!(feature = "unlock_notify") {
            bindings = bindings.clang_arg("-DSQLITE_ENABLE_UNLOCK_NOTIFY");
        }
        if cfg!(feature = "preupdate_hook") {
            bindings = bindings.clang_arg("-DSQLITE_ENABLE_PREUPDATE_HOOK");
        }
        if cfg!(feature = "session") {
            bindings = bindings.clang_arg("-DSQLITE_ENABLE_SESSION");
        }

        bindings
            .generate()
            .expect(&format!("could not run bindgen on header {}", header))
            .write(Box::new(&mut output))
            .expect("could not write output of bindgen");
        let mut output = String::from_utf8(output).expect("bindgen output was not UTF-8?!");

        // rusqlite's functions feature ors in the SQLITE_DETERMINISTIC flag when it
        // can. This flag was added in SQLite 3.8.3, but oring it in in prior
        // versions of SQLite is harmless. We don't want to not build just
        // because this flag is missing (e.g., if we're linking against
        // SQLite 3.7.x), so append the flag manually if it isn't present in bindgen's
        // output.
        if !output.contains("pub const SQLITE_DETERMINISTIC") {
            output.push_str("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n");
        }

        let mut file = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(true)
            .open(out_path.clone())
            .expect(&format!("Could not write to {:?}", out_path));

        file.write_all(output.as_bytes())
            .expect(&format!("Could not write to {:?}", out_path));
    }
}
<commit_msg>[ci skip] rustfmt<commit_after>use std::env;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let out_path = Path::new(&out_dir).join("bindgen.rs");
    if cfg!(feature = "sqlcipher") {
        if cfg!(feature = "bundled") {
            println!(
                "cargo:warning={}",
                "Builds with bundled SQLCipher are not supported. Searching for SQLCipher to link against. \
                 This can lead to issues if your version of SQLCipher is not up to date!");
        }
        build_linked::main(&out_dir, &out_path)
    } else {
        // This can't be `cfg!` without always requiring our `mod build_bundled` (and
        // thus `cc`)
        #[cfg(feature = "bundled")]
        {
            build_bundled::main(&out_dir, &out_path)
        }
        #[cfg(not(feature = "bundled"))]
        {
            build_linked::main(&out_dir, &out_path)
        }
    }
}

#[cfg(feature = "bundled")]
mod build_bundled {
    use cc;
    use std::env;
    use std::path::Path;

    pub fn main(out_dir: &str, out_path: &Path) {
        if cfg!(feature = "sqlcipher") {
            // This is just a sanity check, the top level `main` should ensure this.
            panic!("Builds with bundled SQLCipher are not supported");
        }

        #[cfg(feature = "buildtime_bindgen")]
        {
            use super::{bindings, HeaderLocation};
            let header = HeaderLocation::FromPath("sqlite3/sqlite3.h".to_owned());
            bindings::write_to_out_dir(header, out_path);
        }
        #[cfg(not(feature = "buildtime_bindgen"))]
        {
            use std::fs;
            fs::copy("sqlite3/bindgen_bundled_version.rs", out_path)
                .expect("Could not copy bindings to output directory");
        }

        let mut cfg = cc::Build::new();
        cfg.file("sqlite3/sqlite3.c")
            .flag("-DSQLITE_CORE")
            .flag("-DSQLITE_DEFAULT_FOREIGN_KEYS=1")
            .flag("-DSQLITE_ENABLE_API_ARMOR")
            .flag("-DSQLITE_ENABLE_COLUMN_METADATA")
            .flag("-DSQLITE_ENABLE_DBSTAT_VTAB")
            .flag("-DSQLITE_ENABLE_FTS3")
            .flag("-DSQLITE_ENABLE_FTS3_PARENTHESIS")
            .flag("-DSQLITE_ENABLE_FTS5")
            .flag("-DSQLITE_ENABLE_JSON1")
            .flag("-DSQLITE_ENABLE_LOAD_EXTENSION=1")
            .flag("-DSQLITE_ENABLE_MEMORY_MANAGEMENT")
            .flag("-DSQLITE_ENABLE_RTREE")
            .flag("-DSQLITE_ENABLE_STAT2")
            .flag("-DSQLITE_ENABLE_STAT4")
            .flag("-DSQLITE_HAVE_ISNAN")
            .flag("-DSQLITE_SOUNDEX")
            .flag("-DSQLITE_THREADSAFE=1")
            .flag("-DSQLITE_USE_URI")
            .flag("-DHAVE_USLEEP=1");
        if cfg!(feature = "unlock_notify") {
            cfg.flag("-DSQLITE_ENABLE_UNLOCK_NOTIFY");
        }
        if cfg!(feature = "preupdate_hook") {
            cfg.flag("-DSQLITE_ENABLE_PREUPDATE_HOOK");
        }
        if cfg!(feature = "session") {
            cfg.flag("-DSQLITE_ENABLE_SESSION");
        }

        if let Ok(limit) = env::var("SQLITE_MAX_VARIABLE_NUMBER") {
            cfg.flag(&format!("-DSQLITE_MAX_VARIABLE_NUMBER={}", limit));
        }
        println!("cargo:rerun-if-env-changed=SQLITE_MAX_VARIABLE_NUMBER");

        if let Ok(limit) = env::var("SQLITE_MAX_EXPR_DEPTH") {
            cfg.flag(&format!("-DSQLITE_MAX_EXPR_DEPTH={}", limit));
        }
        println!("cargo:rerun-if-env-changed=SQLITE_MAX_EXPR_DEPTH");

        cfg.compile("libsqlite3.a");

        println!("cargo:lib_dir={}", out_dir);
    }
}

fn env_prefix() -> &'static str {
    if cfg!(feature = "sqlcipher") {
        "SQLCIPHER"
    } else {
        "SQLITE3"
    }
}

pub enum HeaderLocation {
    FromEnvironment,
    Wrapper,
    FromPath(String),
}

impl From<HeaderLocation> for String {
    fn from(header: HeaderLocation) -> String {
        match header {
            HeaderLocation::FromEnvironment => {
                let prefix = env_prefix();
                let mut header = env::var(format!("{}_INCLUDE_DIR", prefix)).expect(&format!(
                    "{}_INCLUDE_DIR must be set if {}_LIB_DIR is set",
                    prefix, prefix
                ));
                header.push_str("/sqlite3.h");
                header
            }
            HeaderLocation::Wrapper => "wrapper.h".into(),
            HeaderLocation::FromPath(path) => path,
        }
    }
}

mod build_linked {
    use pkg_config;

    #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
    extern crate vcpkg;

    use super::{bindings, env_prefix, HeaderLocation};
    use std::env;
    use std::path::Path;

    pub fn main(_out_dir: &str, out_path: &Path) {
        let header = find_sqlite();
        if cfg!(feature = "bundled") && !cfg!(feature = "buildtime_bindgen") {
            // We can only get here if `bundled` and `sqlcipher` were both
            // specified (and `builtime_bindgen` was not). In order to keep
            // `rusqlite` relatively clean we hide the fact that `bundled` can
            // be ignored in some cases, and just use the bundled bindings, even
            // though the library we found might not match their version.
            // Ideally we'd perform a version check here, but doing so is rather
            // tricky, since we might not have access to executables (and
            // moreover, we might be cross compiling).
            std::fs::copy("sqlite3/bindgen_bundled_version.rs", out_path)
                .expect("Could not copy bindings to output directory");
        } else {
            bindings::write_to_out_dir(header, out_path);
        }
    }

    fn find_link_mode() -> &'static str {
        // If the user specifies SQLITE_STATIC (or SQLCIPHER_STATIC), do static
        // linking, unless it's explicitly set to 0.
        match &env::var(format!("{}_STATIC", env_prefix())) {
            Ok(v) if v != "0" => "static",
            _ => "dylib",
        }
    }
    // Prints the necessary cargo link commands and returns the path to the header.
    fn find_sqlite() -> HeaderLocation {
        let link_lib = link_lib();

        println!("cargo:rerun-if-env-changed={}_INCLUDE_DIR", env_prefix());
        println!("cargo:rerun-if-env-changed={}_LIB_DIR", env_prefix());
        println!("cargo:rerun-if-env-changed={}_STATIC", env_prefix());
        if cfg!(target_os = "windows") {
            println!("cargo:rerun-if-env-changed=PATH");
        }
        if cfg!(all(feature = "vcpkg", target_env = "msvc")) {
            println!("cargo:rerun-if-env-changed=VCPKGRS_DYNAMIC");
        }
        // Allow users to specify where to find SQLite.
        if let Ok(dir) = env::var(format!("{}_LIB_DIR", env_prefix())) {
            // Try to use pkg-config to determine link commands
            let pkgconfig_path = Path::new(&dir).join("pkgconfig");
            env::set_var("PKG_CONFIG_PATH", pkgconfig_path);
            if let Err(_) = pkg_config::Config::new().probe(link_lib) {
                // Otherwise just emit the bare minimum link commands.
                println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib);
                println!("cargo:rustc-link-search={}", dir);
            }
            return HeaderLocation::FromEnvironment;
        }

        if let Some(header) = try_vcpkg() {
            return header;
        }

        // See if pkg-config can do everything for us.
        match pkg_config::Config::new()
            .print_system_libs(false)
            .probe(link_lib)
        {
            Ok(mut lib) => {
                if let Some(mut header) = lib.include_paths.pop() {
                    header.push("sqlite3.h");
                    HeaderLocation::FromPath(header.to_string_lossy().into())
                } else {
                    HeaderLocation::Wrapper
                }
            }
            Err(_) => {
                // No env var set and pkg-config couldn't help; just output the link-lib
                // request and hope that the library exists on the system paths. We used to
                // output /usr/lib explicitly, but that can introduce other linking problems;
                // see https://github.com/jgallagher/rusqlite/issues/207.
                println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib);
                HeaderLocation::Wrapper
            }
        }
    }

    #[cfg(all(feature = "vcpkg", target_env = "msvc"))]
    fn try_vcpkg() -> Option<HeaderLocation> {
        // See if vcpkg can find it.
        if let Ok(mut lib) = vcpkg::Config::new().probe(link_lib()) {
            if let Some(mut header) = lib.include_paths.pop() {
                header.push("sqlite3.h");
                return Some(HeaderLocation::FromPath(header.to_string_lossy().into()));
            }
        }
        None
    }

    #[cfg(not(all(feature = "vcpkg", target_env = "msvc")))]
    fn try_vcpkg() -> Option<HeaderLocation> {
        None
    }

    fn link_lib() -> &'static str {
        if cfg!(feature = "sqlcipher") {
            "sqlcipher"
        } else {
            "sqlite3"
        }
    }
}

#[cfg(not(feature = "buildtime_bindgen"))]
mod bindings {
    use super::HeaderLocation;

    use std::fs;
    use std::path::Path;

    static PREBUILT_BINDGEN_PATHS: &'static [&'static str] = &[
        "bindgen-bindings/bindgen_3.6.8.rs",
        #[cfg(feature = "min_sqlite_version_3_6_23")]
        "bindgen-bindings/bindgen_3.6.23.rs",
        #[cfg(feature = "min_sqlite_version_3_7_7")]
        "bindgen-bindings/bindgen_3.7.7.rs",
        #[cfg(feature = "min_sqlite_version_3_7_16")]
        "bindgen-bindings/bindgen_3.7.16.rs",
    ];

    pub fn write_to_out_dir(_header: HeaderLocation, out_path: &Path) {
        let in_path = PREBUILT_BINDGEN_PATHS[PREBUILT_BINDGEN_PATHS.len() - 1];
        fs::copy(in_path, out_path).expect("Could not copy bindings to output directory");
    }
}

#[cfg(feature = "buildtime_bindgen")]
mod bindings {
    use bindgen;

    use self::bindgen::callbacks::{IntKind, ParseCallbacks};
    use super::HeaderLocation;

    use std::fs::OpenOptions;
    use std::io::Write;
    use std::path::Path;

    #[derive(Debug)]
    struct SqliteTypeChooser;

    impl ParseCallbacks for SqliteTypeChooser {
        fn int_macro(&self, _name: &str, value: i64) -> Option<IntKind> {
            if value >= i32::min_value() as i64 && value <= i32::max_value() as i64 {
                Some(IntKind::I32)
            } else {
                None
            }
        }
    }

    pub fn write_to_out_dir(header: HeaderLocation, out_path: &Path) {
        let header: String = header.into();
        let mut output = Vec::new();
        let mut bindings = bindgen::builder()
            .header(header.clone())
            .parse_callbacks(Box::new(SqliteTypeChooser))
            .rustfmt_bindings(true);

        if cfg!(feature = "unlock_notify") {
            bindings = bindings.clang_arg("-DSQLITE_ENABLE_UNLOCK_NOTIFY");
        }
        if cfg!(feature = "preupdate_hook") {
            bindings = bindings.clang_arg("-DSQLITE_ENABLE_PREUPDATE_HOOK");
        }
        if cfg!(feature = "session") {
            bindings = bindings.clang_arg("-DSQLITE_ENABLE_SESSION");
        }

        bindings
            .generate()
            .expect(&format!("could not run bindgen on header {}", header))
            .write(Box::new(&mut output))
            .expect("could not write output of bindgen");
        let mut output = String::from_utf8(output).expect("bindgen output was not UTF-8?!");

        // rusqlite's functions feature ors in the SQLITE_DETERMINISTIC flag when it
        // can. This flag was added in SQLite 3.8.3, but oring it in in prior
        // versions of SQLite is harmless. We don't want to not build just
        // because this flag is missing (e.g., if we're linking against
        // SQLite 3.7.x), so append the flag manually if it isn't present in bindgen's
        // output.
        if !output.contains("pub const SQLITE_DETERMINISTIC") {
            output.push_str("\npub const SQLITE_DETERMINISTIC: i32 = 2048;\n");
        }

        let mut file = OpenOptions::new()
            .write(true)
            .truncate(true)
            .create(true)
            .open(out_path.clone())
            .expect(&format!("Could not write to {:?}", out_path));

        file.write_all(output.as_bytes())
            .expect(&format!("Could not write to {:?}", out_path));
    }
}
<|endoftext|>


<commit_before>//! The underlying OsString/OsStr implementation on Unix and many other
//! systems: just a `Vec<u8>`/`[u8]`.

use crate::borrow::Cow;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::str;
use crate::mem;
use crate::rc::Rc;
use crate::sync::Arc;
use crate::sys_common::{FromInner, IntoInner, AsInner};
use crate::sys_common::bytestring::debug_fmt_bytestring;

use core::str::lossy::Utf8Lossy;

#[derive(Clone, Hash)]
pub(crate) struct Buf {
    pub inner: Vec<u8>
}

// FIXME:
// `Buf::as_slice` current implementation relies
// on `Slice` being layout-compatible with `[u8]`.
// When attribute privacy is implemented, `Slice` should be annotated as `#[repr(transparent)]`.
// Anyway, `Slice` representation and layout are considered implementation detail, are
// not documented and must not be relied upon.
pub(crate) struct Slice {
    pub inner: [u8]
}

impl fmt::Debug for Slice {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        debug_fmt_bytestring(&self.inner, formatter)
    }
}

impl fmt::Display for Slice {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
    }
}

impl fmt::Debug for Buf {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self.as_slice(), formatter)
    }
}

impl fmt::Display for Buf {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_slice(), formatter)
    }
}

impl IntoInner<Vec<u8>> for Buf {
    fn into_inner(self) -> Vec<u8> {
        self.inner
    }
}

impl AsInner<[u8]> for Buf {
    fn as_inner(&self) -> &[u8] {
        &self.inner
    }
}

impl Buf {
    pub fn from_string(s: String) -> Buf {
        Buf { inner: s.into_bytes() }
    }

    #[inline]
    pub fn with_capacity(capacity: usize) -> Buf {
        Buf {
            inner: Vec::with_capacity(capacity)
        }
    }

    #[inline]
    pub fn clear(&mut self) {
        self.inner.clear()
    }

    #[inline]
    pub fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.inner.reserve(additional)
    }

    #[inline]
    pub fn reserve_exact(&mut self, additional: usize) {
        self.inner.reserve_exact(additional)
    }

    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.inner.shrink_to_fit()
    }

    #[inline]
    pub fn shrink_to(&mut self, min_capacity: usize) {
        self.inner.shrink_to(min_capacity)
    }

    pub fn as_slice(&self) -> &Slice {
        unsafe { mem::transmute(&*self.inner) }
    }

    pub fn into_string(self) -> Result<String, Buf> {
        String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } )
    }

    pub fn push_slice(&mut self, s: &Slice) {
        self.inner.extend_from_slice(&s.inner)
    }

    #[inline]
    pub fn into_box(self) -> Box<Slice> {
        unsafe { mem::transmute(self.inner.into_boxed_slice()) }
    }

    #[inline]
    pub fn from_box(boxed: Box<Slice>) -> Buf {
        let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
        Buf { inner: inner.into_vec() }
    }

    #[inline]
    pub fn into_arc(&self) -> Arc<Slice> {
        self.as_slice().into_arc()
    }

    #[inline]
    pub fn into_rc(&self) -> Rc<Slice> {
        self.as_slice().into_rc()
    }
}

impl Slice {
    fn from_u8_slice(s: &[u8]) -> &Slice {
        unsafe { mem::transmute(s) }
    }

    pub fn from_str(s: &str) -> &Slice {
        Slice::from_u8_slice(s.as_bytes())
    }

    pub fn to_str(&self) -> Option<&str> {
        str::from_utf8(&self.inner).ok()
    }

    pub fn to_string_lossy(&self) -> Cow<'_, str> {
        String::from_utf8_lossy(&self.inner)
    }

    pub fn to_owned(&self) -> Buf {
        Buf { inner: self.inner.to_vec() }
    }

    #[inline]
    pub fn into_box(&self) -> Box<Slice> {
        let boxed: Box<[u8]> = self.inner.into();
        unsafe { mem::transmute(boxed) }
    }

    pub fn empty_box() -> Box<Slice> {
        let boxed: Box<[u8]> = Default::default();
        unsafe { mem::transmute(boxed) }
    }

    #[inline]
    pub fn into_arc(&self) -> Arc<Slice> {
        let arc: Arc<[u8]> = Arc::from(&self.inner);
        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
    }

    #[inline]
    pub fn into_rc(&self) -> Rc<Slice> {
        let rc: Rc<[u8]> = Rc::from(&self.inner);
        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
    }
}

/// Platform-specific extensions to [`OsString`].
///
/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
    /// Creates an [`OsString`] from a byte vector.
    ///
    /// See the module docmentation for an example.
    ///
    /// [`OsString`]: ../../../ffi/struct.OsString.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from_vec(vec: Vec<u8>) -> Self;

    /// Yields the underlying byte vector of this [`OsString`].
    ///
    /// See the module docmentation for an example.
    ///
    /// [`OsString`]: ../../../ffi/struct.OsString.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into_vec(self) -> Vec<u8>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStringExt for OsString {
    fn from_vec(vec: Vec<u8>) -> OsString {
        FromInner::from_inner(Buf { inner: vec })
    }
    fn into_vec(self) -> Vec<u8> {
        self.into_inner().inner
    }
}

/// Platform-specific extensions to [`OsStr`].
///
/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
    #[stable(feature = "rust1", since = "1.0.0")]
    /// Creates an [`OsStr`] from a byte slice.
    ///
    /// See the module docmentation for an example.
    ///
    /// [`OsStr`]: ../../../ffi/struct.OsStr.html
    fn from_bytes(slice: &[u8]) -> &Self;

    /// Gets the underlying byte view of the [`OsStr`] slice.
    ///
    /// See the module docmentation for an example.
    ///
    /// [`OsStr`]: ../../../ffi/struct.OsStr.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_bytes(&self) -> &[u8];
}

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStrExt for OsStr {
    #[inline]
    fn from_bytes(slice: &[u8]) -> &OsStr {
        unsafe { mem::transmute(slice) }
    }
    #[inline]
    fn as_bytes(&self) -> &[u8] {
        &self.as_inner().inner
    }
}
<commit_msg>Rollup merge of #65486 - mathstuf:osstr-doc-typo, r=TimNN<commit_after>//! The underlying OsString/OsStr implementation on Unix and many other
//! systems: just a `Vec<u8>`/`[u8]`.

use crate::borrow::Cow;
use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::str;
use crate::mem;
use crate::rc::Rc;
use crate::sync::Arc;
use crate::sys_common::{FromInner, IntoInner, AsInner};
use crate::sys_common::bytestring::debug_fmt_bytestring;

use core::str::lossy::Utf8Lossy;

#[derive(Clone, Hash)]
pub(crate) struct Buf {
    pub inner: Vec<u8>
}

// FIXME:
// `Buf::as_slice` current implementation relies
// on `Slice` being layout-compatible with `[u8]`.
// When attribute privacy is implemented, `Slice` should be annotated as `#[repr(transparent)]`.
// Anyway, `Slice` representation and layout are considered implementation detail, are
// not documented and must not be relied upon.
pub(crate) struct Slice {
    pub inner: [u8]
}

impl fmt::Debug for Slice {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        debug_fmt_bytestring(&self.inner, formatter)
    }
}

impl fmt::Display for Slice {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
    }
}

impl fmt::Debug for Buf {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self.as_slice(), formatter)
    }
}

impl fmt::Display for Buf {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_slice(), formatter)
    }
}

impl IntoInner<Vec<u8>> for Buf {
    fn into_inner(self) -> Vec<u8> {
        self.inner
    }
}

impl AsInner<[u8]> for Buf {
    fn as_inner(&self) -> &[u8] {
        &self.inner
    }
}

impl Buf {
    pub fn from_string(s: String) -> Buf {
        Buf { inner: s.into_bytes() }
    }

    #[inline]
    pub fn with_capacity(capacity: usize) -> Buf {
        Buf {
            inner: Vec::with_capacity(capacity)
        }
    }

    #[inline]
    pub fn clear(&mut self) {
        self.inner.clear()
    }

    #[inline]
    pub fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.inner.reserve(additional)
    }

    #[inline]
    pub fn reserve_exact(&mut self, additional: usize) {
        self.inner.reserve_exact(additional)
    }

    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.inner.shrink_to_fit()
    }

    #[inline]
    pub fn shrink_to(&mut self, min_capacity: usize) {
        self.inner.shrink_to(min_capacity)
    }

    pub fn as_slice(&self) -> &Slice {
        unsafe { mem::transmute(&*self.inner) }
    }

    pub fn into_string(self) -> Result<String, Buf> {
        String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } )
    }

    pub fn push_slice(&mut self, s: &Slice) {
        self.inner.extend_from_slice(&s.inner)
    }

    #[inline]
    pub fn into_box(self) -> Box<Slice> {
        unsafe { mem::transmute(self.inner.into_boxed_slice()) }
    }

    #[inline]
    pub fn from_box(boxed: Box<Slice>) -> Buf {
        let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
        Buf { inner: inner.into_vec() }
    }

    #[inline]
    pub fn into_arc(&self) -> Arc<Slice> {
        self.as_slice().into_arc()
    }

    #[inline]
    pub fn into_rc(&self) -> Rc<Slice> {
        self.as_slice().into_rc()
    }
}

impl Slice {
    fn from_u8_slice(s: &[u8]) -> &Slice {
        unsafe { mem::transmute(s) }
    }

    pub fn from_str(s: &str) -> &Slice {
        Slice::from_u8_slice(s.as_bytes())
    }

    pub fn to_str(&self) -> Option<&str> {
        str::from_utf8(&self.inner).ok()
    }

    pub fn to_string_lossy(&self) -> Cow<'_, str> {
        String::from_utf8_lossy(&self.inner)
    }

    pub fn to_owned(&self) -> Buf {
        Buf { inner: self.inner.to_vec() }
    }

    #[inline]
    pub fn into_box(&self) -> Box<Slice> {
        let boxed: Box<[u8]> = self.inner.into();
        unsafe { mem::transmute(boxed) }
    }

    pub fn empty_box() -> Box<Slice> {
        let boxed: Box<[u8]> = Default::default();
        unsafe { mem::transmute(boxed) }
    }

    #[inline]
    pub fn into_arc(&self) -> Arc<Slice> {
        let arc: Arc<[u8]> = Arc::from(&self.inner);
        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
    }

    #[inline]
    pub fn into_rc(&self) -> Rc<Slice> {
        let rc: Rc<[u8]> = Rc::from(&self.inner);
        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
    }
}

/// Platform-specific extensions to [`OsString`].
///
/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
    /// Creates an [`OsString`] from a byte vector.
    ///
    /// See the module documentation for an example.
    ///
    /// [`OsString`]: ../../../ffi/struct.OsString.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from_vec(vec: Vec<u8>) -> Self;

    /// Yields the underlying byte vector of this [`OsString`].
    ///
    /// See the module documentation for an example.
    ///
    /// [`OsString`]: ../../../ffi/struct.OsString.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into_vec(self) -> Vec<u8>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStringExt for OsString {
    fn from_vec(vec: Vec<u8>) -> OsString {
        FromInner::from_inner(Buf { inner: vec })
    }
    fn into_vec(self) -> Vec<u8> {
        self.into_inner().inner
    }
}

/// Platform-specific extensions to [`OsStr`].
///
/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
    #[stable(feature = "rust1", since = "1.0.0")]
    /// Creates an [`OsStr`] from a byte slice.
    ///
    /// See the module documentation for an example.
    ///
    /// [`OsStr`]: ../../../ffi/struct.OsStr.html
    fn from_bytes(slice: &[u8]) -> &Self;

    /// Gets the underlying byte view of the [`OsStr`] slice.
    ///
    /// See the module documentation for an example.
    ///
    /// [`OsStr`]: ../../../ffi/struct.OsStr.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn as_bytes(&self) -> &[u8];
}

#[stable(feature = "rust1", since = "1.0.0")]
impl OsStrExt for OsStr {
    #[inline]
    fn from_bytes(slice: &[u8]) -> &OsStr {
        unsafe { mem::transmute(slice) }
    }
    #[inline]
    fn as_bytes(&self) -> &[u8] {
        &self.as_inner().inner
    }
}
<|endoftext|>


<commit_before>//! Utility methods and constructors for Lua objects

use std::fmt::Display;
use std::convert::From;
use rlua::{self, Lua, Table, UserData, AnyUserData, Value,
           FromLua, ToLua, Function};
use super::signal;
use super::class::Class;
use super::property::Property;

/// All Lua objects can be cast to this.
#[derive(Clone, Debug)]
pub struct Object<'lua> {
    pub object: AnyUserData<'lua>
}

impl <'lua> From<AnyUserData<'lua>> for Object<'lua> {
    fn from(object: AnyUserData<'lua>) -> Self {
        Object { object }
    }
}

/// Construct a new object, used when using the default Objectable::new.
pub struct ObjectBuilder<'lua>{
    lua: &'lua Lua,
    object: Object<'lua>
}

impl <'lua> ObjectBuilder<'lua> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.table()?.get_metatable()
            .expect("Object had no meta table");
        for entry in new_meta.pairs::<rlua::Value, rlua::Value>() {
            let (key, value) = entry?;
            meta.set(key, value)?;
        }
        self.object.table()?.set_metatable(Some(meta));
        Ok(self)
    }

    #[allow(dead_code)]
    pub fn add_to_signals(self, name: String, func: rlua::Function)
                          -> rlua::Result<Self> {
        signal::connect_signal(self.lua, self.object.clone(), name, &[func])?;
        Ok(self)
    }

    pub fn handle_constructor_argument(self, args: Table) -> rlua::Result<Self> {
        let meta = self.object.table()?.get_metatable()
            .expect("Object had no meta table");
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;

        // Handle all table entries that correspond to known properties,
        // silently ignore all other keys
        for pair in args.pairs() {
            let (key, value): (Value, Value) = pair?;
            if let rlua::Value::String(key) = key {
                if let Ok(key) = key.to_str() {
                    // Find the property
                    for prop in props.iter() {
                        if prop.name == key {
                            // Property exists and has a cb_new callback
                            if let Some(ref new) = prop.cb_new {
                                let _: () = new.bind(self.object.clone())?.call(value)?;
                                break;
                            }
                        }
                    }
                }
            }
        }
        Ok(self)
    }

    pub fn build(self) -> Object<'lua> {
        self.object
    }
}

/// Trait implemented by all objects that represent OO lua objects.
///
/// This trait allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
/// You can't do anything to the object until it has been converted into a
/// canonical form using this trait.
pub trait Objectable<'lua, T, S: UserData + Default + Display + Clone> {
    fn cast(obj: Object<'lua>) -> rlua::Result<T> {
        if obj.object.is::<S>()? {
            Ok(Self::_wrap(obj))
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Given the internal object table, constructs a concrete object out
    /// of it.
    ///
    /// This is only used internally, which is why it's prefixed with a "_"
    /// Please do not use it outside of object.rs.
    fn _wrap(table: Object<'lua>) -> T;

    fn state(&self) -> rlua::Result<S> {
        Ok(self.get_object()?.clone())
    }

    fn set_state(&mut self, data: S) -> rlua::Result<()> {
        *self.get_object_mut()? = data;
        Ok(())
    }

    /// Gets the internal state for the concrete object.
    /// Used internally `state`, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_object(&self) -> rlua::Result<S>;

    /// Gets a mutable reference to the internal state for the concrete object.
    /// Used internally `set_state`, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_object_mut(&mut self) -> rlua::Result<::std::cell::RefMut<S>>;

    /// Lua objects in Way Cooler are just how they are in Awesome:
    /// * We expose the user data directly.
    /// * State for the object is stored using set_user_value in a "wrapper" table.
    /// * The wrapper table has a data field which hosts the data.
    /// * Class methods/attributes are on the meta table of the wrapper table.
    fn allocate(lua: &'lua Lua, class: Class) -> rlua::Result<ObjectBuilder<'lua>>
    {
        let object = lua.create_userdata(S::default())?;
        // TODO Increment the instance count
        let wrapper_table = lua.create_table()?;
        let data_table = lua.create_table()?;
        wrapper_table.set("data", data_table)?;
        let meta = lua.create_table()?;
        meta.set("__class", class)?;
        meta.set("properties", Vec::<Property>::new().to_lua(lua)?)?;
        meta.set("signals", lua.create_table()?)?;
        meta.set("connect_signal",
                 lua.create_function(connect_signal)?)?;
        meta.set("disconnect_signal",
                 lua.create_function(disconnect_signal)?)?;
        meta.set("emit_signal", lua.create_function(emit_signal)?)?;
        meta.set("__index", meta.clone())?;
        meta.set("__tostring", lua.create_function(|_, data: AnyUserData| {
            Ok(format!("{}", data.borrow::<S>()?.clone()))
        })?)?;
        wrapper_table.set_metatable(Some(meta));
        object.set_user_value(wrapper_table)?;
        // TODO Emit new signal event
        let object = Object { object };
        Ok(ObjectBuilder { object, lua })
    }
}

impl <'lua> ToLua<'lua> for Object<'lua> {
    fn to_lua(self, _: &'lua Lua) -> rlua::Result<Value<'lua>> {
        Ok(Value::UserData(self.object))
    }
}

impl <'lua> Object<'lua> {
    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.table()?.get::<_, Table>("signals")
    }

    pub fn table(&self) -> rlua::Result<Table<'lua>> {
        self.object.get_user_value::<Table<'lua>>()
    }
}

/// Default indexing of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_index<'lua>(lua: &'lua Lua,
                           (obj, index): (AnyUserData<'lua>, Value<'lua>))
                           -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let obj: Object<'lua> = obj.into();
    let obj_table = obj.table()?;
    let meta = obj_table.get_metatable()
        .expect("Object had no metatable");
    if meta.get::<_, AnyUserData>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
    }
    let index = match String::from_lua(index, lua) {
        Ok(s) => s,
        Err(_) => return Ok(Value::Nil)
    };
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(
                if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                    let class: Class = class.into();
                    class.checker()?
                        .map(|checker| checker(obj))
                        .unwrap_or(true)
                } else {
                    false
                }))
        },
        "data" => {
            obj_table.to_lua(lua)
        },
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                let class_table = class.get_user_value::<Table>()?;
                let props = class_table.get::<_, Vec<Property>>("properties")?;
                for prop in props {
                    if prop.name.as_str() == index {
                        // Property exists and has an index callback
                        if let Some(index) = prop.cb_index {
                            return index.call(obj)
                        }
                    }
                }
                match class_table.get::<_, Function>("__index_miss_handler") {
                    Ok(function) => {
                        return function.bind(obj_table)?.call(index)
                    },
                    Err(_) => {}
                }
            }
            // TODO property miss handler if index doesn't exst
            Ok(rlua::Value::Nil)
        }
    }
}

/// Default new indexing (assignment) of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_newindex<'lua>(_: &'lua Lua,
                              (obj, index, val):
                              (AnyUserData<'lua>, String, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let obj: Object<'lua> = obj.into();
    let obj_table = obj.table()?;
    if let Some(meta) = obj_table.get_metatable() {
        meta.set(index.clone(), val.clone())?;
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;
        for prop in props {
            if prop.name.as_str() == index {
                // Property exists and has a newindex callback
                if let Some(newindex) = prop.cb_newindex {
                    return newindex.bind(obj.clone())?.call(val)
                }
            }
        }
        match class_table.get::<_, Function>("__newindex_miss_handler") {
            Ok(function) => {
                return function.bind(obj)?.call((index, val))
            },
            Err(_) => {}
        }
        // TODO property miss handler if index doesn't exst
    }
    Ok(Value::Nil)
}

fn connect_signal(lua: &Lua, (obj, signal, func): (AnyUserData, String, Function))
                  -> rlua::Result<()> {
    signal::connect_signal(lua, obj.into(), signal, &[func])
}

fn disconnect_signal(lua: &Lua, (obj, signal): (AnyUserData, String))
                     -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj.into(), signal)
}

fn emit_signal(lua: &Lua, (obj, signal, args): (AnyUserData, String, Value))
               -> rlua::Result<()> {
    signal::emit_object_signal(lua, obj.into(), signal, args)
}
<commit_msg>__index_miss_handler takes the userdata<commit_after>//! Utility methods and constructors for Lua objects

use std::fmt::Display;
use std::convert::From;
use rlua::{self, Lua, Table, UserData, AnyUserData, Value,
           FromLua, ToLua, Function};
use super::signal;
use super::class::Class;
use super::property::Property;

/// All Lua objects can be cast to this.
#[derive(Clone, Debug)]
pub struct Object<'lua> {
    pub object: AnyUserData<'lua>
}

impl <'lua> From<AnyUserData<'lua>> for Object<'lua> {
    fn from(object: AnyUserData<'lua>) -> Self {
        Object { object }
    }
}

/// Construct a new object, used when using the default Objectable::new.
pub struct ObjectBuilder<'lua>{
    lua: &'lua Lua,
    object: Object<'lua>
}

impl <'lua> ObjectBuilder<'lua> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.table()?.get_metatable()
            .expect("Object had no meta table");
        for entry in new_meta.pairs::<rlua::Value, rlua::Value>() {
            let (key, value) = entry?;
            meta.set(key, value)?;
        }
        self.object.table()?.set_metatable(Some(meta));
        Ok(self)
    }

    #[allow(dead_code)]
    pub fn add_to_signals(self, name: String, func: rlua::Function)
                          -> rlua::Result<Self> {
        signal::connect_signal(self.lua, self.object.clone(), name, &[func])?;
        Ok(self)
    }

    pub fn handle_constructor_argument(self, args: Table) -> rlua::Result<Self> {
        let meta = self.object.table()?.get_metatable()
            .expect("Object had no meta table");
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;

        // Handle all table entries that correspond to known properties,
        // silently ignore all other keys
        for pair in args.pairs() {
            let (key, value): (Value, Value) = pair?;
            if let rlua::Value::String(key) = key {
                if let Ok(key) = key.to_str() {
                    // Find the property
                    for prop in props.iter() {
                        if prop.name == key {
                            // Property exists and has a cb_new callback
                            if let Some(ref new) = prop.cb_new {
                                let _: () = new.bind(self.object.clone())?.call(value)?;
                                break;
                            }
                        }
                    }
                }
            }
        }
        Ok(self)
    }

    pub fn build(self) -> Object<'lua> {
        self.object
    }
}

/// Trait implemented by all objects that represent OO lua objects.
///
/// This trait allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
/// You can't do anything to the object until it has been converted into a
/// canonical form using this trait.
pub trait Objectable<'lua, T, S: UserData + Default + Display + Clone> {
    fn cast(obj: Object<'lua>) -> rlua::Result<T> {
        if obj.object.is::<S>()? {
            Ok(Self::_wrap(obj))
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Given the internal object table, constructs a concrete object out
    /// of it.
    ///
    /// This is only used internally, which is why it's prefixed with a "_"
    /// Please do not use it outside of object.rs.
    fn _wrap(table: Object<'lua>) -> T;

    fn state(&self) -> rlua::Result<S> {
        Ok(self.get_object()?.clone())
    }

    fn set_state(&mut self, data: S) -> rlua::Result<()> {
        *self.get_object_mut()? = data;
        Ok(())
    }

    /// Gets the internal state for the concrete object.
    /// Used internally `state`, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_object(&self) -> rlua::Result<S>;

    /// Gets a mutable reference to the internal state for the concrete object.
    /// Used internally `set_state`, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_object_mut(&mut self) -> rlua::Result<::std::cell::RefMut<S>>;

    /// Lua objects in Way Cooler are just how they are in Awesome:
    /// * We expose the user data directly.
    /// * State for the object is stored using set_user_value in a "wrapper" table.
    /// * The wrapper table has a data field which hosts the data.
    /// * Class methods/attributes are on the meta table of the wrapper table.
    fn allocate(lua: &'lua Lua, class: Class) -> rlua::Result<ObjectBuilder<'lua>>
    {
        let object = lua.create_userdata(S::default())?;
        // TODO Increment the instance count
        let wrapper_table = lua.create_table()?;
        let data_table = lua.create_table()?;
        wrapper_table.set("data", data_table)?;
        let meta = lua.create_table()?;
        meta.set("__class", class)?;
        meta.set("properties", Vec::<Property>::new().to_lua(lua)?)?;
        meta.set("signals", lua.create_table()?)?;
        meta.set("connect_signal",
                 lua.create_function(connect_signal)?)?;
        meta.set("disconnect_signal",
                 lua.create_function(disconnect_signal)?)?;
        meta.set("emit_signal", lua.create_function(emit_signal)?)?;
        meta.set("__index", meta.clone())?;
        meta.set("__tostring", lua.create_function(|_, data: AnyUserData| {
            Ok(format!("{}", data.borrow::<S>()?.clone()))
        })?)?;
        wrapper_table.set_metatable(Some(meta));
        object.set_user_value(wrapper_table)?;
        // TODO Emit new signal event
        let object = Object { object };
        Ok(ObjectBuilder { object, lua })
    }
}

impl <'lua> ToLua<'lua> for Object<'lua> {
    fn to_lua(self, _: &'lua Lua) -> rlua::Result<Value<'lua>> {
        Ok(Value::UserData(self.object))
    }
}

impl <'lua> Object<'lua> {
    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.table()?.get::<_, Table>("signals")
    }

    pub fn table(&self) -> rlua::Result<Table<'lua>> {
        self.object.get_user_value::<Table<'lua>>()
    }
}

/// Default indexing of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_index<'lua>(lua: &'lua Lua,
                           (obj, index): (AnyUserData<'lua>, Value<'lua>))
                           -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let obj: Object<'lua> = obj.into();
    let obj_table = obj.table()?;
    let meta = obj_table.get_metatable()
        .expect("Object had no metatable");
    if meta.get::<_, AnyUserData>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
    }
    let index = match String::from_lua(index, lua) {
        Ok(s) => s,
        Err(_) => return Ok(Value::Nil)
    };
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(
                if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                    let class: Class = class.into();
                    class.checker()?
                        .map(|checker| checker(obj))
                        .unwrap_or(true)
                } else {
                    false
                }))
        },
        "data" => {
            obj_table.to_lua(lua)
        },
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                let class_table = class.get_user_value::<Table>()?;
                let props = class_table.get::<_, Vec<Property>>("properties")?;
                for prop in props {
                    if prop.name.as_str() == index {
                        // Property exists and has an index callback
                        if let Some(index) = prop.cb_index {
                            return index.call(obj)
                        }
                    }
                }
                match class_table.get::<_, Function>("__index_miss_handler") {
                    Ok(function) => {
                        return function.bind(obj)?.call(index)
                    },
                    Err(_) => {}
                }
            }
            // TODO property miss handler if index doesn't exst
            Ok(rlua::Value::Nil)
        }
    }
}

/// Default new indexing (assignment) of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_newindex<'lua>(_: &'lua Lua,
                              (obj, index, val):
                              (AnyUserData<'lua>, String, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let obj: Object<'lua> = obj.into();
    let obj_table = obj.table()?;
    if let Some(meta) = obj_table.get_metatable() {
        meta.set(index.clone(), val.clone())?;
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;
        for prop in props {
            if prop.name.as_str() == index {
                // Property exists and has a newindex callback
                if let Some(newindex) = prop.cb_newindex {
                    return newindex.bind(obj.clone())?.call(val)
                }
            }
        }
        match class_table.get::<_, Function>("__newindex_miss_handler") {
            Ok(function) => {
                return function.bind(obj)?.call((index, val))
            },
            Err(_) => {}
        }
        // TODO property miss handler if index doesn't exst
    }
    Ok(Value::Nil)
}

fn connect_signal(lua: &Lua, (obj, signal, func): (AnyUserData, String, Function))
                  -> rlua::Result<()> {
    signal::connect_signal(lua, obj.into(), signal, &[func])
}

fn disconnect_signal(lua: &Lua, (obj, signal): (AnyUserData, String))
                     -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj.into(), signal)
}

fn emit_signal(lua: &Lua, (obj, signal, args): (AnyUserData, String, Value))
               -> rlua::Result<()> {
    signal::emit_object_signal(lua, obj.into(), signal, args)
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate libc;
#[macro_use] extern crate log;
extern crate regex;

extern crate argparse;
extern crate quire;
#[macro_use] extern crate lithos;

use std::env;
use std::rc::Rc;
use std::str::FromStr;
use std::process::exit;
use std::path::{Path, PathBuf};
use std::io::{stderr, Write};
use std::default::Default;
use std::collections::BTreeMap;

use regex::Regex;
use quire::parse_config;
use argparse::{ArgumentParser, Parse, List, StoreTrue, StoreOption};
use rustc_serialize::json;
use libc::funcs::posix88::unistd::getpid;

use lithos::setup::{clean_child, init_logging};
use lithos::master_config::{MasterConfig, create_master_dirs};
use lithos::tree_config::TreeConfig;
use lithos::container_config::ContainerKind::{Command};
use lithos::child_config::ChildConfig;
use lithos::container::{Command};
use lithos::monitor::{Monitor, Executor};
use lithos::signal;

struct Child<'a> {
    name: Rc<String>,
    master_file: PathBuf,
    master_config: &'a MasterConfig,
    child_config_serialized: String,
    root_binary: PathBuf,
    args: Vec<String>,
}

impl<'a> Executor for Child<'a> {
    fn command(&self) -> Command
    {
        let mut cmd = Command::new((*self.name).clone(), &self.root_binary);
        cmd.keep_sigmask();

        // Name is first here, so it's easily visible in ps
        cmd.arg("--name");
        cmd.arg(&self.name[..]);

        cmd.arg("--master");
        cmd.arg(&self.master_file.to_str().unwrap()[..]);
        cmd.arg("--config");
        cmd.arg(&self.child_config_serialized[..]);
        cmd.set_env("TERM".to_string(),
                    env::var("TERM").unwrap_or("dumb".to_string()));
        if let Ok(x) = env::var("RUST_LOG") {
            cmd.set_env("RUST_LOG".to_string(), x);
        }
        if let Ok(x) = env::var("RUST_BACKTRACE") {
            cmd.set_env("RUST_BACKTRACE".to_string(), x);
        }
        cmd.args(&self.args);
        cmd.container();
        return cmd;
    }
    fn finish(&self) -> bool {
        clean_child(&*self.name, self.master_config);
        return false;  // Do not restart
    }
}

fn run(master_cfg: &Path, tree_name: String,
    command_name: String, args: Vec<String>,
    log_stderr: bool, log_level: Option<log::LogLevel>)
    -> Result<(), String>
{
    let master: MasterConfig = try!(parse_config(&master_cfg,
        &*MasterConfig::validator(), Default::default())
        .map_err(|e| format!("Error reading master config: {}", e)));
    try!(create_master_dirs(&master));

    if !Regex::new(r"^[\w-]+$").unwrap().is_match(&tree_name) {
        return Err(format!("Wrong tree name: {}", tree_name));
    }
    if !Regex::new(r"^[\w-]+$").unwrap().is_match(&command_name) {
        return Err(format!("Wrong command name: {}", command_name));
    }

    let tree: TreeConfig = try!(parse_config(
        &master_cfg.join(&master.sandboxes_dir).join(tree_name.clone() + ".yaml"),
        &*TreeConfig::validator(), Default::default())
        .map_err(|e| format!("Error reading tree config: {}", e)));

    let mut log_file;
    if let Some(ref fname) = tree.log_file {
        log_file = master.default_log_dir.join(fname);
    } else {
        log_file = master.default_log_dir.join(format!("{}.log", tree_name));
    }
    try!(init_logging(&log_file,
          log_level
            .or(tree.log_level
                .and_then(|x| FromStr::from_str(&x).ok()))
            .or_else(|| FromStr::from_str(&master.log_level).ok())
            .unwrap_or(log::LogLevel::Warn),
        log_stderr));

    let cfg = master_cfg.parent().unwrap()
        .join(&master.processes_dir)
        .join(tree.config_file.as_ref().unwrap_or(
            &PathBuf::from(&(tree_name.clone() + ".yaml"))));
    debug!("Children config {:?}", cfg);
    let tree_children: BTreeMap<String, ChildConfig>;
    tree_children = try!(parse_config(&cfg,
            &*ChildConfig::mapping_validator(), Default::default())
        .map_err(|e| format!("Error reading children config: {}", e)));
    let child_cfg = try!(tree_children.get(&command_name)
        .ok_or(format!("Command {:?} not found", command_name)));

    if child_cfg.kind != Command {
        return Err(format!("The target container is: {:?}", child_cfg.kind));
    }

    let name = Rc::new(format!("{}/cmd.{}.{}", tree_name,
        command_name, unsafe { getpid() }));
    info!("[{}] Running command with args {:?}", name, args);
    let mut mon = Monitor::new((*name).clone());
    let timeo = 0;
    let mut args = args;
    args.insert(0, "--".to_string());
    mon.add(name.clone(), Box::new(Child {
        name: name,
        master_file: PathBuf::from(master_cfg),
        master_config: &master,
        child_config_serialized: json::encode(&child_cfg).unwrap(),
        root_binary: env::current_exe().unwrap()
                     .parent().unwrap().join("lithos_knot"),
        args: args,
    }), timeo, None);
    mon.run();

    return Ok(());
}

fn main() {

    signal::block_all();

    let mut master_config = PathBuf::from("/etc/lithos/master.yaml");
    let mut command_name = "".to_string();
    let mut tree_name = "".to_string();
    let mut args = vec!();
    let mut log_stderr: bool = false;
    let mut log_level: Option<log::LogLevel> = None;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Runs tree of processes");
        ap.refer(&mut master_config)
          .add_option(&["--master"], Parse,
            "Name of the master configuration file \
             (default /etc/lithos/master.yaml)")
          .metavar("FILE");
        ap.refer(&mut log_stderr)
          .add_option(&["--log-stderr"], StoreTrue,
            "Print debugging info to stderr");
        ap.refer(&mut log_level)
          .add_option(&["--log-level"], StoreOption,
            "Set log level (default info for now)");
        ap.refer(&mut tree_name)
          .add_argument("subtree", Parse,
            "Name of the tree to run command for")
          .required();
        ap.refer(&mut command_name)
          .add_argument("name", Parse,
            "Name of the command to run")
          .required();
        ap.refer(&mut args)
          .add_argument("argument", List,
            "Arguments for the command");
        ap.stop_on_first_argument(true);
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }
    match run(&master_config, tree_name, command_name, args,
              log_stderr, log_level)
    {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            write!(&mut stderr(), "Fatal error: {}\n", e).ok();
            error!("Fatal error: {}", e);
            exit(1);
        }
    }
}
<commit_msg>Fix lithos_cmd (was broken by refactoring of directories)<commit_after>extern crate rustc_serialize;
extern crate libc;
#[macro_use] extern crate log;
extern crate regex;

extern crate argparse;
extern crate quire;
#[macro_use] extern crate lithos;

use std::env;
use std::rc::Rc;
use std::str::FromStr;
use std::process::exit;
use std::path::{Path, PathBuf};
use std::io::{stderr, Write};
use std::default::Default;
use std::collections::BTreeMap;

use regex::Regex;
use quire::parse_config;
use argparse::{ArgumentParser, Parse, List, StoreTrue, StoreOption};
use rustc_serialize::json;
use libc::funcs::posix88::unistd::getpid;

use lithos::setup::{clean_child, init_logging};
use lithos::master_config::{MasterConfig, create_master_dirs};
use lithos::tree_config::TreeConfig;
use lithos::container_config::ContainerKind::{Command};
use lithos::child_config::ChildConfig;
use lithos::container::{Command};
use lithos::monitor::{Monitor, Executor};
use lithos::signal;

struct Child<'a> {
    name: Rc<String>,
    master_file: PathBuf,
    master_config: &'a MasterConfig,
    child_config_serialized: String,
    root_binary: PathBuf,
    args: Vec<String>,
}

impl<'a> Executor for Child<'a> {
    fn command(&self) -> Command
    {
        let mut cmd = Command::new((*self.name).clone(), &self.root_binary);
        cmd.keep_sigmask();

        // Name is first here, so it's easily visible in ps
        cmd.arg("--name");
        cmd.arg(&self.name[..]);

        cmd.arg("--master");
        cmd.arg(&self.master_file.to_str().unwrap()[..]);
        cmd.arg("--config");
        cmd.arg(&self.child_config_serialized[..]);
        cmd.set_env("TERM".to_string(),
                    env::var("TERM").unwrap_or("dumb".to_string()));
        if let Ok(x) = env::var("RUST_LOG") {
            cmd.set_env("RUST_LOG".to_string(), x);
        }
        if let Ok(x) = env::var("RUST_BACKTRACE") {
            cmd.set_env("RUST_BACKTRACE".to_string(), x);
        }
        cmd.args(&self.args);
        cmd.container();
        return cmd;
    }
    fn finish(&self) -> bool {
        clean_child(&*self.name, self.master_config);
        return false;  // Do not restart
    }
}

fn run(master_cfg: &Path, tree_name: String,
    command_name: String, args: Vec<String>,
    log_stderr: bool, log_level: Option<log::LogLevel>)
    -> Result<(), String>
{
    let master: MasterConfig = try!(parse_config(&master_cfg,
        &*MasterConfig::validator(), Default::default())
        .map_err(|e| format!("Error reading master config: {}", e)));
    try!(create_master_dirs(&master));

    if !Regex::new(r"^[\w-]+$").unwrap().is_match(&tree_name) {
        return Err(format!("Wrong tree name: {}", tree_name));
    }
    if !Regex::new(r"^[\w-]+$").unwrap().is_match(&command_name) {
        return Err(format!("Wrong command name: {}", command_name));
    }

    let tree: TreeConfig = try!(parse_config(
        &master_cfg.parent().unwrap()
         .join(&master.sandboxes_dir).join(tree_name.clone() + ".yaml"),
        &*TreeConfig::validator(), Default::default())
        .map_err(|e| format!("Error reading tree config: {}", e)));

    let mut log_file;
    if let Some(ref fname) = tree.log_file {
        log_file = master.default_log_dir.join(fname);
    } else {
        log_file = master.default_log_dir.join(format!("{}.log", tree_name));
    }
    try!(init_logging(&log_file,
          log_level
            .or(tree.log_level
                .and_then(|x| FromStr::from_str(&x).ok()))
            .or_else(|| FromStr::from_str(&master.log_level).ok())
            .unwrap_or(log::LogLevel::Warn),
        log_stderr));

    let cfg = master_cfg.parent().unwrap()
        .join(&master.processes_dir)
        .join(tree.config_file.as_ref().unwrap_or(
            &PathBuf::from(&(tree_name.clone() + ".yaml"))));
    debug!("Children config {:?}", cfg);
    let tree_children: BTreeMap<String, ChildConfig>;
    tree_children = try!(parse_config(&cfg,
            &*ChildConfig::mapping_validator(), Default::default())
        .map_err(|e| format!("Error reading children config: {}", e)));
    let child_cfg = try!(tree_children.get(&command_name)
        .ok_or(format!("Command {:?} not found", command_name)));

    if child_cfg.kind != Command {
        return Err(format!("The target container is: {:?}", child_cfg.kind));
    }

    let name = Rc::new(format!("{}/cmd.{}.{}", tree_name,
        command_name, unsafe { getpid() }));
    info!("[{}] Running command with args {:?}", name, args);
    let mut mon = Monitor::new((*name).clone());
    let timeo = 0;
    let mut args = args;
    args.insert(0, "--".to_string());
    mon.add(name.clone(), Box::new(Child {
        name: name,
        master_file: PathBuf::from(master_cfg),
        master_config: &master,
        child_config_serialized: json::encode(&child_cfg).unwrap(),
        root_binary: env::current_exe().unwrap()
                     .parent().unwrap().join("lithos_knot"),
        args: args,
    }), timeo, None);
    mon.run();

    return Ok(());
}

fn main() {

    signal::block_all();

    let mut master_config = PathBuf::from("/etc/lithos/master.yaml");
    let mut command_name = "".to_string();
    let mut tree_name = "".to_string();
    let mut args = vec!();
    let mut log_stderr: bool = false;
    let mut log_level: Option<log::LogLevel> = None;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Runs tree of processes");
        ap.refer(&mut master_config)
          .add_option(&["--master"], Parse,
            "Name of the master configuration file \
             (default /etc/lithos/master.yaml)")
          .metavar("FILE");
        ap.refer(&mut log_stderr)
          .add_option(&["--log-stderr"], StoreTrue,
            "Print debugging info to stderr");
        ap.refer(&mut log_level)
          .add_option(&["--log-level"], StoreOption,
            "Set log level (default info for now)");
        ap.refer(&mut tree_name)
          .add_argument("subtree", Parse,
            "Name of the tree to run command for")
          .required();
        ap.refer(&mut command_name)
          .add_argument("name", Parse,
            "Name of the command to run")
          .required();
        ap.refer(&mut args)
          .add_argument("argument", List,
            "Arguments for the command");
        ap.stop_on_first_argument(true);
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }
    match run(&master_config, tree_name, command_name, args,
              log_stderr, log_level)
    {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            write!(&mut stderr(), "Fatal error: {}\n", e).ok();
            error!("Fatal error: {}", e);
            exit(1);
        }
    }
}
<|endoftext|>