<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Simple ANSI color library

#[allow(missing_doc)];

use core::prelude::*;

use core::io;

#[cfg(not(target_os = "win32"))] use core::os;
#[cfg(not(target_os = "win32"))] use terminfo::*;
#[cfg(not(target_os = "win32"))] use terminfo::searcher::open;
#[cfg(not(target_os = "win32"))] use terminfo::parser::compiled::parse;
#[cfg(not(target_os = "win32"))] use terminfo::parm::{expand, Number, Variables};

// FIXME (#2807): Windows support.

pub mod color {
    pub type Color = u16;

    pub static black:   Color = 0u16;
    pub static red:     Color = 1u16;
    pub static green:   Color = 2u16;
    pub static yellow:  Color = 3u16;
    pub static blue:    Color = 4u16;
    pub static magenta: Color = 5u16;
    pub static cyan:    Color = 6u16;
    pub static white:   Color = 7u16;

    pub static bright_black:   Color = 8u16;
    pub static bright_red:     Color = 9u16;
    pub static bright_green:   Color = 10u16;
    pub static bright_yellow:  Color = 11u16;
    pub static bright_blue:    Color = 12u16;
    pub static bright_magenta: Color = 13u16;
    pub static bright_cyan:    Color = 14u16;
    pub static bright_white:   Color = 15u16;
}

#[cfg(not(target_os = "win32"))]
pub struct Terminal {
    num_colors: u16,
    priv out: @io::Writer,
    priv ti: ~TermInfo
}

#[cfg(target_os = "win32")]
pub struct Terminal {
    num_colors: u16,
    priv out: @io::Writer,
}

#[cfg(not(target_os = "win32"))]
impl Terminal {
    pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
        let term = os::getenv("TERM");
        if term.is_none() {
            return Err(~"TERM environment variable undefined");
        }

        let entry = open(term.unwrap());
        if entry.is_err() {
            return Err(entry.unwrap_err());
        }

        let ti = parse(entry.unwrap(), false);
        if ti.is_err() {
            return Err(ti.unwrap_err());
        }

        let inf = ti.unwrap();
        let nc = if inf.strings.find_equiv(&("setaf")).is_some()
                 && inf.strings.find_equiv(&("setab")).is_some() {
                     inf.numbers.find_equiv(&("colors")).map_consume_default(0, |&n| n)
                 } else { 0 };

        return Ok(Terminal {out: out, ti: inf, num_colors: nc});
    }
    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    pub fn fg(&self, color: color::Color) {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
                           [Number(color as int)], &mut Variables::new());
            if s.is_ok() {
                self.out.write(s.unwrap());
            } else {
                warn!(s.unwrap_err());
            }
        }
    }
    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    pub fn bg(&self, color: color::Color) {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
                           [Number(color as int)], &mut Variables::new());
            if s.is_ok() {
                self.out.write(s.unwrap());
            } else {
                warn!(s.unwrap_err());
            }
        }
    }
    pub fn reset(&self) {
        let mut vars = Variables::new();
        let s = expand(*self.ti.strings.find_equiv(&("op")).unwrap(), [], &mut vars);
        if s.is_ok() {
            self.out.write(s.unwrap());
        } else {
            warn!(s.unwrap_err());
        }
    }

    priv fn dim_if_necessary(&self, color: color::Color) -> color::Color {
        if color >= self.num_colors && color >= 8 && color < 16 {
            color-8
        } else { color }
    }
}

#[cfg(target_os = "win32")]
impl Terminal {
    pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
        return Ok(Terminal {out: out, num_colors: 0});
    }

    pub fn fg(&self, _color: color::Color) {
    }

    pub fn bg(&self, _color: color::Color) {
    }

    pub fn reset(&self) {
    }
}
<commit_msg>auto merge of #7436 : kballard/rust/term-dumb, r=cmr<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Simple ANSI color library

#[allow(missing_doc)];

use core::prelude::*;

use core::io;

#[cfg(not(target_os = "win32"))] use core::os;
#[cfg(not(target_os = "win32"))] use terminfo::*;
#[cfg(not(target_os = "win32"))] use terminfo::searcher::open;
#[cfg(not(target_os = "win32"))] use terminfo::parser::compiled::parse;
#[cfg(not(target_os = "win32"))] use terminfo::parm::{expand, Number, Variables};

// FIXME (#2807): Windows support.

pub mod color {
    pub type Color = u16;

    pub static black:   Color = 0u16;
    pub static red:     Color = 1u16;
    pub static green:   Color = 2u16;
    pub static yellow:  Color = 3u16;
    pub static blue:    Color = 4u16;
    pub static magenta: Color = 5u16;
    pub static cyan:    Color = 6u16;
    pub static white:   Color = 7u16;

    pub static bright_black:   Color = 8u16;
    pub static bright_red:     Color = 9u16;
    pub static bright_green:   Color = 10u16;
    pub static bright_yellow:  Color = 11u16;
    pub static bright_blue:    Color = 12u16;
    pub static bright_magenta: Color = 13u16;
    pub static bright_cyan:    Color = 14u16;
    pub static bright_white:   Color = 15u16;
}

#[cfg(not(target_os = "win32"))]
pub struct Terminal {
    num_colors: u16,
    priv out: @io::Writer,
    priv ti: ~TermInfo
}

#[cfg(target_os = "win32")]
pub struct Terminal {
    num_colors: u16,
    priv out: @io::Writer,
}

#[cfg(not(target_os = "win32"))]
impl Terminal {
    pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
        let term = os::getenv("TERM");
        if term.is_none() {
            return Err(~"TERM environment variable undefined");
        }

        let entry = open(term.unwrap());
        if entry.is_err() {
            return Err(entry.unwrap_err());
        }

        let ti = parse(entry.unwrap(), false);
        if ti.is_err() {
            return Err(ti.unwrap_err());
        }

        let inf = ti.unwrap();
        let nc = if inf.strings.find_equiv(&("setaf")).is_some()
                 && inf.strings.find_equiv(&("setab")).is_some() {
                     inf.numbers.find_equiv(&("colors")).map_consume_default(0, |&n| n)
                 } else { 0 };

        return Ok(Terminal {out: out, ti: inf, num_colors: nc});
    }
    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    pub fn fg(&self, color: color::Color) {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
                           [Number(color as int)], &mut Variables::new());
            if s.is_ok() {
                self.out.write(s.unwrap());
            } else {
                warn!("%s", s.unwrap_err());
            }
        }
    }
    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    pub fn bg(&self, color: color::Color) {
        let color = self.dim_if_necessary(color);
        if self.num_colors > color {
            let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
                           [Number(color as int)], &mut Variables::new());
            if s.is_ok() {
                self.out.write(s.unwrap());
            } else {
                warn!("%s", s.unwrap_err());
            }
        }
    }
    pub fn reset(&self) {
        let mut vars = Variables::new();
        let s = do self.ti.strings.find_equiv(&("op"))
                       .map_consume_default(Err(~"can't find op")) |&op| {
                           expand(op, [], &mut vars)
                       };
        if s.is_ok() {
            self.out.write(s.unwrap());
        } else {
            warn!("%s", s.unwrap_err());
        }
    }

    priv fn dim_if_necessary(&self, color: color::Color) -> color::Color {
        if color >= self.num_colors && color >= 8 && color < 16 {
            color-8
        } else { color }
    }
}

#[cfg(target_os = "win32")]
impl Terminal {
    pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
        return Ok(Terminal {out: out, num_colors: 0});
    }

    pub fn fg(&self, _color: color::Color) {
    }

    pub fn bg(&self, _color: color::Color) {
    }

    pub fn reset(&self) {
    }
}
<|endoftext|>


<commit_before>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::api::optional::Optional;
use ::datastore;
use ::sensors;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".to_string(), "error".to_json());
        d.insert("reason".to_string(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl ReadHandler {
    pub fn new(status: api::Status, datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> ReadHandler {
        ReadHandler {
            status: status,
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {
            sensor_spec.get_sensor_value(self.datastore.clone()).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(api::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        status_copy.state.open = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .and_then(|people_now_present| {
                match people_now_present[0].value {
                    0i64 => Optional::Value(false),
                    _ => Optional::Value(true),
                }
            }).into();

        // Serialize to JSON
        status_copy.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

error_type! {
    #[derive(Debug)]
    pub enum UpdateHandlerError {
        UnknownSensor(String) {
            desc (sensor) &sensor;
        },
        DataStoreError(datastore::DataStoreError) {
            cause;
        }
    }
}

impl UpdateHandler {
    pub fn new(datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in the `DataStore`
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), UpdateHandlerError> {
        // Validate sensor
        try!(self.sensor_specs.lock().unwrap().iter()
                              .find(|&spec| spec.data_key == sensor)
                              .ok_or(UpdateHandlerError::UnknownSensor(sensor.to_string())));

        // Store data to datastore
        let datastore_ref = self.datastore.clone();
        let mut datastore_lock = datastore_ref.lock().unwrap();
        datastore_lock.store(sensor, value)
                      .map(|_| ()).map_err(|e| {
                          error!("Could not update sensor value in datastore: {:?}", e);
                          UpdateHandlerError::DataStoreError(e)
                      })
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.to_string() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these println! invocations.
        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in datastore
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("update_sensor() failed: {:?}", e);
            let response = match e {
                UpdateHandlerError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                UpdateHandlerError::DataStoreError(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<commit_msg>Implement dynamic state message<commit_after>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::api::optional::Optional;
use ::datastore;
use ::sensors;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".to_string(), "error".to_json());
        d.insert("reason".to_string(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl ReadHandler {
    pub fn new(status: api::Status, datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> ReadHandler {
        ReadHandler {
            status: status,
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {
            sensor_spec.get_sensor_value(self.datastore.clone()).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(api::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        // Update state depending on number of people present
        let people_now_present: Option<i64> = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .map(|people_now_present| people_now_present[0].value)
            .into();
        if let Some(count) = people_now_present {
            status_copy.state.open = Some(count > 0);
            if count == 1 {
                status_copy.state.message = Optional::Value(format!("{} person here right now", count));
            } else if count > 1 {
                status_copy.state.message = Optional::Value(format!("{} people here right now", count));
            }
        }

        // Serialize to JSON
        status_copy.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

error_type! {
    #[derive(Debug)]
    pub enum UpdateHandlerError {
        UnknownSensor(String) {
            desc (sensor) &sensor;
        },
        DataStoreError(datastore::DataStoreError) {
            cause;
        }
    }
}

impl UpdateHandler {
    pub fn new(datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in the `DataStore`
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), UpdateHandlerError> {
        // Validate sensor
        try!(self.sensor_specs.lock().unwrap().iter()
                              .find(|&spec| spec.data_key == sensor)
                              .ok_or(UpdateHandlerError::UnknownSensor(sensor.to_string())));

        // Store data to datastore
        let datastore_ref = self.datastore.clone();
        let mut datastore_lock = datastore_ref.lock().unwrap();
        datastore_lock.store(sensor, value)
                      .map(|_| ()).map_err(|e| {
                          error!("Could not update sensor value in datastore: {:?}", e);
                          UpdateHandlerError::DataStoreError(e)
                      })
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.to_string() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these println! invocations.
        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in datastore
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("update_sensor() failed: {:?}", e);
            let response = match e {
                UpdateHandlerError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                UpdateHandlerError::DataStoreError(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<|endoftext|>


<commit_before>use super::collect_versions;
use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
use log::info;
use std::{collections::HashMap, fs::File, io::prelude::*};
use toml::{self, value::Table, Value};

pub fn generate(env: &Env) -> String {
    info!("Generating sys Cargo.toml for {}", env.config.library_name);

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = nameutil::exported_crate_name(crate_name);

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.0.1");
        set_string(package, "edition", "2021");
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let dep = upsert_table(deps, &ext_lib.crate_name);
        let ext_package = if ext_lib.crate_name == "cairo" {
            format!("{}-sys-rs", ext_lib.crate_name)
        } else if ext_lib.crate_name == "gdk_pixbuf" {
            "gdk-pixbuf-sys".into()
        } else {
            format!("{}-sys", ext_lib.crate_name)
        };
        let repo_url = match ext_package.as_str() {
            // Not sure if glib-macros and gobject-sys are needed here
            "cairo-sys-rs" | "gdk-pixbuf-sys" | "gio-sys" | "gobject-sys" | "glib-macros"
            | "glib-sys" | "graphene-sys" | "pango-sys" | "pangocairo-sys" => {
                "https://github.com/gtk-rs/gtk-rs-core"
            }
            // Not sure if gtk-macros is needed here
            "atk-sys" | "gdk-sys" | "gdkwayland-sys" | "gdkx11-sys" | "gtk-sys" | "gtk-macros" => {
                "https://github.com/gtk-rs/gtk3-rs"
            }
            // Not sure if gtk4-macros is needed here
            "gdk4-wayland-sys" | "gdk4-x11-sys" | "gdk4-sys" | "gsk4-sys" | "gtk4-macros"
            | "gtk4-sys" => "https://github.com/gtk-rs/gtk4-rs",
            &_ => "Unknown dependency, please create an issue",
        };
        set_string(dep, "package", ext_package);
        set_string(dep, "git", repo_url);
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "system-deps", "6");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "1.0.0");
        set_string(dev_deps, "tempfile", "3");
        unset(dev_deps, "tempdir");
    }

    {
        let features = upsert_table(root, "features");
        let versions = collect_versions(env);
        versions.keys().fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                get_feature_dependencies(version, prev, &env.config.feature_dependencies)
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert(
            "dox".to_string(),
            Value::Array(
                env.config
                    .dox_feature_dependencies
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect(),
            ),
        );
    }

    {
        let meta = upsert_table(root, "package");
        let meta = upsert_table(meta, "metadata");
        let meta = upsert_table(meta, "system-deps");

        let ns = env.namespaces.main();
        let lib_name = ns.package_name.as_ref().unwrap();

        let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
        // Allow both the name and version of a system dep to be overridden by hand
        meta.entry("name")
            .or_insert_with(|| Value::String(lib_name.to_owned()));
        meta.entry("version")
            .or_insert_with(|| Value::String(env.config.min_cfg_version.to_string()));

        // Old version API
        unset(meta, "feature-versions");

        collect_versions(env)
            .iter()
            .filter(|(&v, _)| v > env.config.min_cfg_version)
            .for_each(|(v, lib_version)| {
                let version_section = upsert_table(meta, &v.to_feature());
                // Allow system-deps version for this feature level to be overridden by hand
                version_section
                    .entry("version")
                    .or_insert_with(|| Value::String(lib_version.to_string()));
            });
    }

    {
        // Small trick to prevent having double quotes around it since toml doesn't like having '.'
        let docs_rs_metadata = upsert_table(root, "package");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
        let mut docs_rs_features = env.config.docs_rs_features.clone();
        docs_rs_features.push("dox".to_owned());
        docs_rs_metadata.insert(
            "features".to_string(),
            Value::Array(
                docs_rs_features
                    .into_iter()
                    .map(Value::String)
                    .collect::<Vec<_>>(),
            ),
        );
    }
}

fn get_feature_dependencies(
    version: Version,
    prev_version: Option<Version>,
    feature_dependencies: &HashMap<Version, Vec<String>>,
) -> Vec<String> {
    let mut vec = Vec::with_capacity(10);
    if let Some(v) = prev_version {
        vec.push(v.to_feature());
    }
    if let Some(dependencies) = feature_dependencies.get(&version) {
        vec.extend_from_slice(dependencies);
    }
    vec
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(Value::Table(lib)) = root.get("lib") {
        if let Some(Value::String(lib_name)) = lib.get("name") {
            //Converting don't needed as library target names cannot contain hyphens
            return lib_name.to_owned();
        }
    }
    if let Some(Value::Table(package)) = root.get("package") {
        if let Some(Value::String(package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    table.insert(name.into(), Value::String(new_value.into()));
}

fn unset(table: &mut Table, name: &str) {
    table.remove(name);
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(table) = parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(toml::map::Map::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<commit_msg>Changed branch for unknown deps<commit_after>use super::collect_versions;
use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
use log::info;
use std::{collections::HashMap, fs::File, io::prelude::*};
use toml::{self, value::Table, Value};

pub fn generate(env: &Env) -> String {
    info!("Generating sys Cargo.toml for {}", env.config.library_name);

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = nameutil::exported_crate_name(crate_name);

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.0.1");
        set_string(package, "edition", "2021");
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let dep = upsert_table(deps, &ext_lib.crate_name);
        let ext_package = if ext_lib.crate_name == "cairo" {
            format!("{}-sys-rs", ext_lib.crate_name)
        } else if ext_lib.crate_name == "gdk_pixbuf" {
            "gdk-pixbuf-sys".into()
        } else {
            format!("{}-sys", ext_lib.crate_name)
        };
        let repo_url = match ext_package.as_str() {
            "cairo-sys-rs" | "gdk-pixbuf-sys" | "gio-sys" | "gobject-sys" | "glib-sys"
            | "graphene-sys" | "pango-sys" | "pangocairo-sys" => {
                "https://github.com/gtk-rs/gtk-rs-core"
            }
            "atk-sys" | "gdk-sys" | "gdkwayland-sys" | "gdkx11-sys" | "gtk-sys" | "gtk-macros" => {
                "https://github.com/gtk-rs/gtk3-rs"
            }
            "gdk4-wayland-sys" | "gdk4-x11-sys" | "gdk4-sys" | "gsk4-sys" | "gtk4-sys" => {
                "https://github.com/gtk-rs/gtk4-rs"
            }
            &_ => "ADD GIT REPOSITORY URL HERE",
        };
        set_string(dep, "package", ext_package);
        set_string(dep, "git", repo_url);
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "system-deps", "6");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "1.0.0");
        set_string(dev_deps, "tempfile", "3");
        unset(dev_deps, "tempdir");
    }

    {
        let features = upsert_table(root, "features");
        let versions = collect_versions(env);
        versions.keys().fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                get_feature_dependencies(version, prev, &env.config.feature_dependencies)
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert(
            "dox".to_string(),
            Value::Array(
                env.config
                    .dox_feature_dependencies
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect(),
            ),
        );
    }

    {
        let meta = upsert_table(root, "package");
        let meta = upsert_table(meta, "metadata");
        let meta = upsert_table(meta, "system-deps");

        let ns = env.namespaces.main();
        let lib_name = ns.package_name.as_ref().unwrap();

        let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
        // Allow both the name and version of a system dep to be overridden by hand
        meta.entry("name")
            .or_insert_with(|| Value::String(lib_name.to_owned()));
        meta.entry("version")
            .or_insert_with(|| Value::String(env.config.min_cfg_version.to_string()));

        // Old version API
        unset(meta, "feature-versions");

        collect_versions(env)
            .iter()
            .filter(|(&v, _)| v > env.config.min_cfg_version)
            .for_each(|(v, lib_version)| {
                let version_section = upsert_table(meta, &v.to_feature());
                // Allow system-deps version for this feature level to be overridden by hand
                version_section
                    .entry("version")
                    .or_insert_with(|| Value::String(lib_version.to_string()));
            });
    }

    {
        // Small trick to prevent having double quotes around it since toml doesn't like having '.'
        let docs_rs_metadata = upsert_table(root, "package");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
        let mut docs_rs_features = env.config.docs_rs_features.clone();
        docs_rs_features.push("dox".to_owned());
        docs_rs_metadata.insert(
            "features".to_string(),
            Value::Array(
                docs_rs_features
                    .into_iter()
                    .map(Value::String)
                    .collect::<Vec<_>>(),
            ),
        );
    }
}

fn get_feature_dependencies(
    version: Version,
    prev_version: Option<Version>,
    feature_dependencies: &HashMap<Version, Vec<String>>,
) -> Vec<String> {
    let mut vec = Vec::with_capacity(10);
    if let Some(v) = prev_version {
        vec.push(v.to_feature());
    }
    if let Some(dependencies) = feature_dependencies.get(&version) {
        vec.extend_from_slice(dependencies);
    }
    vec
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(Value::Table(lib)) = root.get("lib") {
        if let Some(Value::String(lib_name)) = lib.get("name") {
            //Converting don't needed as library target names cannot contain hyphens
            return lib_name.to_owned();
        }
    }
    if let Some(Value::Table(package)) = root.get("package") {
        if let Some(Value::String(package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    table.insert(name.into(), Value::String(new_value.into()));
}

fn unset(table: &mut Table, name: &str) {
    table.remove(name);
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(table) = parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(toml::map::Map::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use std::fs::File;
use std::io::{Error, ErrorKind, Read};

use NetworkExt;

/// Contains network information.
#[derive(Debug)]
pub struct NetworkData {
    old_in: u64,
    old_out: u64,
    current_in: u64,
    current_out: u64,
}

impl NetworkExt for NetworkData {
    fn get_income(&self) -> u64 {
        self.current_in - self.old_in
    }

    fn get_outcome(&self) -> u64 {
        self.current_out - self.old_out
    }
}

pub fn new() -> NetworkData {
    NetworkData {
        old_in: 0,
        old_out: 0,
        current_in: 0,
        current_out: 0,
    }
}

fn read_things() -> Result<(u64, u64), Error> {
    fn read_interface_stat(iface: &str, typ: &str) -> Result<u64, Error> {
        let mut file = File::open(format!("/sys/class/net/{}/statistics/{}_bytes", iface, typ))?;
        let mut content = String::new();
        file.read_to_string(&mut content)?;
        content.trim()
               .parse()
               .map_err(|_| Error::new(ErrorKind::Other, "Failed to parse network stat"))
    }

    let default_interface = {
        let mut file = File::open("/proc/net/route")?;
        let mut content = String::new();
        file.read_to_string(&mut content)?;
        content.lines()
               .filter(|l| l.split_whitespace().nth(2).map(|l| l != "00000000").unwrap_or(false))
               .last()
               .and_then(|l| l.split_whitespace().nth(0))
               .ok_or(Error::new(ErrorKind::Other, "Default device not found"))?
               .to_owned()
    };

    Ok((read_interface_stat(&default_interface, "rx")?,
        read_interface_stat(&default_interface, "tx")?))
}

pub fn update_network(n: &mut NetworkData) {
    if let Ok((new_in, new_out)) = read_things() {
        n.old_in = n.current_in;
        n.old_out = n.current_out;
        n.current_in = new_in;
        n.current_out = new_out;
    }
    // TODO: maybe handle error here?
}
<commit_msg>Fix clippy lint<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

use std::fs::File;
use std::io::{Error, ErrorKind, Read};

use NetworkExt;

/// Contains network information.
#[derive(Debug)]
pub struct NetworkData {
    old_in: u64,
    old_out: u64,
    current_in: u64,
    current_out: u64,
}

impl NetworkExt for NetworkData {
    fn get_income(&self) -> u64 {
        self.current_in - self.old_in
    }

    fn get_outcome(&self) -> u64 {
        self.current_out - self.old_out
    }
}

pub fn new() -> NetworkData {
    NetworkData {
        old_in: 0,
        old_out: 0,
        current_in: 0,
        current_out: 0,
    }
}

fn read_things() -> Result<(u64, u64), Error> {
    fn read_interface_stat(iface: &str, typ: &str) -> Result<u64, Error> {
        let mut file = File::open(format!("/sys/class/net/{}/statistics/{}_bytes", iface, typ))?;
        let mut content = String::new();
        file.read_to_string(&mut content)?;
        content.trim()
               .parse()
               .map_err(|_| Error::new(ErrorKind::Other, "Failed to parse network stat"))
    }

    let default_interface = {
        let mut file = File::open("/proc/net/route")?;
        let mut content = String::new();
        file.read_to_string(&mut content)?;
        content.lines()
               .filter(|l| l.split_whitespace().nth(2).map(|l| l != "00000000").unwrap_or(false))
               .last()
               .and_then(|l| l.split_whitespace().nth(0))
               .ok_or_else(|| Error::new(ErrorKind::Other, "Default device not found"))?
               .to_owned()
    };

    Ok((read_interface_stat(&default_interface, "rx")?,
        read_interface_stat(&default_interface, "tx")?))
}

pub fn update_network(n: &mut NetworkData) {
    if let Ok((new_in, new_out)) = read_things() {
        n.old_in = n.current_in;
        n.old_out = n.current_out;
        n.current_in = new_in;
        n.current_out = new_out;
    }
    // TODO: maybe handle error here?
}
<|endoftext|>


<commit_before>//! The Host request header, defined in RFC 2616, Section 14.23.

use std::u16;
use std::rt::io::Reader;

/// A simple little thing for the host of a request
#[deriving(Clone, Eq)]
pub struct Host {

    /// The name of the host that was requested
    name: ~str,

    /// If unspecified, assume the default port was used (80 for HTTP, 443 for HTTPS).
    /// In that case, you shouldn't need to worry about it in URLs that you build, provided you
    /// include the scheme.
    port: Option<u16>,
}
impl ToStr for Host {
    fn to_str(&self) -> ~str {
        match self.port {
            Some(port) => fmt!("%s:%s", self.name, port.to_str()),
            None => self.name.clone(),
        }
    }
}

impl super::HeaderConvertible for Host {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<Host> {
        let s = reader.collect_to_str();
        // TODO: this doesn't support IPv6 address access (e.g. "[::1]")
        // Do this properly with correct authority parsing.
        let mut hi = s.splitn_iter(':', 1);
        Some(Host {
            name: hi.next().unwrap().to_owned(),
            port: match hi.next() {
                Some(name) => from_str::<u16>(name),
                None => None,
            },
        })
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}
<commit_msg>removed unused import<commit_after>//! The Host request header, defined in RFC 2616, Section 14.23.

use std::rt::io::Reader;

/// A simple little thing for the host of a request
#[deriving(Clone, Eq)]
pub struct Host {

    /// The name of the host that was requested
    name: ~str,

    /// If unspecified, assume the default port was used (80 for HTTP, 443 for HTTPS).
    /// In that case, you shouldn't need to worry about it in URLs that you build, provided you
    /// include the scheme.
    port: Option<u16>,
}
impl ToStr for Host {
    fn to_str(&self) -> ~str {
        match self.port {
            Some(port) => fmt!("%s:%s", self.name, port.to_str()),
            None => self.name.clone(),
        }
    }
}

impl super::HeaderConvertible for Host {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<Host> {
        let s = reader.collect_to_str();
        // TODO: this doesn't support IPv6 address access (e.g. "[::1]")
        // Do this properly with correct authority parsing.
        let mut hi = s.splitn_iter(':', 1);
        Some(Host {
            name: hi.next().unwrap().to_owned(),
            port: match hi.next() {
                Some(name) => from_str::<u16>(name),
                None => None,
            },
        })
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}
<|endoftext|>


<commit_before>
use std::sync::atomic::{Ordering, fence};

#[cfg(any(target_arch = "x64", target_arch = "x64_64", target_arch = "aarch64"))]
mod theimpl {
    use std::sync::atomic::{Ordering, fence};
    pub const MAYBE_ACQUIRE: Ordering = Ordering::Relaxed;

    #[inline(always)]
    pub fn maybe_acquire_fence() {
        fence(Ordering: Acquire)
    }
}

#[cfg(not(any(target_arch = "x64", target_arch = "x64_64", target_arch = "aarch64")))]
mod theimpl {
    use std::sync::atomic::Ordering;
    pub const MAYBE_ACQUIRE: Ordering = Ordering::Acquire;

    #[inline(always)]
    pub fn maybe_acquire_fence() {}
}

pub const MAYBE_ACQUIRE: Ordering = theimpl::MAYBE_ACQUIRE;

#[inline(always)]
pub fn maybe_acquire_fence() {
    theimpl::maybe_acquire_fence()
}
<commit_msg>Fixed typo in arm maybe_acquire<commit_after>
use std::sync::atomic::{Ordering, fence};

#[cfg(any(target_arch = "x64", target_arch = "x64_64", target_arch = "aarch64"))]
mod theimpl {
    use std::sync::atomic::{Ordering, fence};
    pub const MAYBE_ACQUIRE: Ordering = Ordering::Relaxed;

    #[inline(always)]
    pub fn maybe_acquire_fence() {
        fence(Ordering::Acquire)
    }
}

#[cfg(not(any(target_arch = "x64", target_arch = "x64_64", target_arch = "aarch64")))]
mod theimpl {
    use std::sync::atomic::Ordering;
    pub const MAYBE_ACQUIRE: Ordering = Ordering::Acquire;

    #[inline(always)]
    pub fn maybe_acquire_fence() {}
}

pub const MAYBE_ACQUIRE: Ordering = theimpl::MAYBE_ACQUIRE;

#[inline(always)]
pub fn maybe_acquire_fence() {
    theimpl::maybe_acquire_fence()
}
<|endoftext|>


<commit_before>//! The Rust AST Visitor. Extracts useful information and massages it into a form
//! usable for `clean`.

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::Node;
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
use rustc_span;
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};

use std::mem;

use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt};
use crate::core;
use crate::doctree::*;

// FIXME: Should this be replaced with tcx.def_path_str?
fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<String> {
    let crate_name = tcx.crate_name(did.krate).to_string();
    let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| {
        // extern blocks have an empty name
        let s = elem.data.to_string();
        if !s.is_empty() { Some(s) } else { None }
    });
    std::iter::once(crate_name).chain(relative).collect()
}

crate fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool {
    while let Some(id) = tcx.hir().get_enclosing_scope(node) {
        node = id;
        if tcx.hir().attrs(node).lists(sym::doc).has_word(sym::hidden) {
            return true;
        }
    }
    false
}

// Also, is there some reason that this doesn't use the 'visit'
// framework from syntax?.

crate struct RustdocVisitor<'a, 'tcx> {
    cx: &'a mut core::DocContext<'tcx>,
    view_item_stack: FxHashSet<hir::HirId>,
    inlining: bool,
    /// Are the current module and all of its parents public?
    inside_public_path: bool,
    exact_paths: FxHashMap<DefId, Vec<String>>,
}

impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
    crate fn new(cx: &'a mut core::DocContext<'tcx>) -> RustdocVisitor<'a, 'tcx> {
        // If the root is re-exported, terminate all recursion.
        let mut stack = FxHashSet::default();
        stack.insert(hir::CRATE_HIR_ID);
        RustdocVisitor {
            cx,
            view_item_stack: stack,
            inlining: false,
            inside_public_path: true,
            exact_paths: FxHashMap::default(),
        }
    }

    fn store_path(&mut self, did: DefId) {
        let tcx = self.cx.tcx;
        self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did));
    }

    crate fn visit(mut self) -> Module<'tcx> {
        let span = self.cx.tcx.def_span(CRATE_DEF_ID);
        let mut top_level_module = self.visit_mod_contents(
            &Spanned { span, node: hir::VisibilityKind::Public },
            hir::CRATE_HIR_ID,
            self.cx.tcx.hir().root_module(),
            self.cx.tcx.crate_name(LOCAL_CRATE),
        );

        // `#[macro_export] macro_rules!` items are reexported at the top level of the
        // crate, regardless of where they're defined. We want to document the
        // top level rexport of the macro, not its original definition, since
        // the rexport defines the path that a user will actually see. Accordingly,
        // we add the rexport as an item here, and then skip over the original
        // definition in `visit_item()` below.
        //
        // We also skip `#[macro_export] macro_rules!` that have alredy been inserted,
        // this can append if within the same module a `#[macro_export] macro_rules!`
        // is declared but also a reexport of itself producing two export of the same
        // macro in the same module.
        let mut inserted = FxHashSet::default();
        for export in self.cx.tcx.module_exports(CRATE_DEF_ID).unwrap_or(&[]) {
            if let Res::Def(DefKind::Macro(_), def_id) = export.res {
                if let Some(local_def_id) = def_id.as_local() {
                    if self.cx.tcx.has_attr(def_id, sym::macro_export) {
                        if !inserted.insert(def_id) {
                            let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
                            let item = self.cx.tcx.hir().expect_item(hir_id);
                            top_level_module.items.push((item, None));
                        }
                    }
                }
            }
        }

        self.cx.cache.hidden_cfg = self
            .cx
            .tcx
            .hir()
            .attrs(CRATE_HIR_ID)
            .iter()
            .filter(|attr| attr.has_name(sym::doc))
            .flat_map(|attr| attr.meta_item_list().into_iter().flatten())
            .filter(|attr| attr.has_name(sym::cfg_hide))
            .flat_map(|attr| {
                attr.meta_item_list()
                    .unwrap_or(&[])
                    .iter()
                    .filter_map(|attr| {
                        Some(
                            Cfg::parse(attr.meta_item()?)
                                .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
                                .ok()?,
                        )
                    })
                    .collect::<Vec<_>>()
            })
            .collect();

        self.cx.cache.exact_paths = self.exact_paths;
        top_level_module
    }

    fn visit_mod_contents(
        &mut self,
        vis: &hir::Visibility<'_>,
        id: hir::HirId,
        m: &'tcx hir::Mod<'tcx>,
        name: Symbol,
    ) -> Module<'tcx> {
        let mut om = Module::new(name, id, m.inner);
        // Keep track of if there were any private modules in the path.
        let orig_inside_public_path = self.inside_public_path;
        self.inside_public_path &= vis.node.is_pub();
        for &i in m.item_ids {
            let item = self.cx.tcx.hir().item(i);
            self.visit_item(item, None, &mut om);
        }
        self.inside_public_path = orig_inside_public_path;
        om
    }

    /// Tries to resolve the target of a `pub use` statement and inlines the
    /// target if it is defined locally and would not be documented otherwise,
    /// or when it is specifically requested with `please_inline`.
    /// (the latter is the case when the import is marked `doc(inline)`)
    ///
    /// Cross-crate inlining occurs later on during crate cleaning
    /// and follows different rules.
    ///
    /// Returns `true` if the target has been inlined.
    fn maybe_inline_local(
        &mut self,
        id: hir::HirId,
        res: Res,
        renamed: Option<Symbol>,
        glob: bool,
        om: &mut Module<'tcx>,
        please_inline: bool,
    ) -> bool {
        debug!("maybe_inline_local res: {:?}", res);

        let tcx = self.cx.tcx;
        let res_did = if let Some(did) = res.opt_def_id() {
            did
        } else {
            return false;
        };

        let use_attrs = tcx.hir().attrs(id);
        // Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
        let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline)
            || use_attrs.lists(sym::doc).has_word(sym::hidden);

        // For cross-crate impl inlining we need to know whether items are
        // reachable in documentation -- a previously unreachable item can be
        // made reachable by cross-crate inlining which we're checking here.
        // (this is done here because we need to know this upfront).
        if !res_did.is_local() && !is_no_inline {
            let attrs = clean::inline::load_attrs(self.cx, res_did);
            let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden);
            if !self_is_hidden {
                if let Res::Def(kind, did) = res {
                    if kind == DefKind::Mod {
                        crate::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did)
                    } else {
                        // All items need to be handled here in case someone wishes to link
                        // to them with intra-doc links
                        self.cx.cache.access_levels.map.insert(did, AccessLevel::Public);
                    }
                }
            }
            return false;
        }

        let res_hir_id = match res_did.as_local() {
            Some(n) => tcx.hir().local_def_id_to_hir_id(n),
            None => return false,
        };

        let is_private = !self.cx.cache.access_levels.is_public(res_did);
        let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);

        // Only inline if requested or if the item would otherwise be stripped.
        if (!please_inline && !is_private && !is_hidden) || is_no_inline {
            return false;
        }

        if !self.view_item_stack.insert(res_hir_id) {
            return false;
        }

        let ret = match tcx.hir().get(res_hir_id) {
            Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => {
                let prev = mem::replace(&mut self.inlining, true);
                for &i in m.item_ids {
                    let i = self.cx.tcx.hir().item(i);
                    self.visit_item(i, None, om);
                }
                self.inlining = prev;
                true
            }
            Node::Item(it) if !glob => {
                let prev = mem::replace(&mut self.inlining, true);
                self.visit_item(it, renamed, om);
                self.inlining = prev;
                true
            }
            Node::ForeignItem(it) if !glob => {
                let prev = mem::replace(&mut self.inlining, true);
                self.visit_foreign_item(it, renamed, om);
                self.inlining = prev;
                true
            }
            _ => false,
        };
        self.view_item_stack.remove(&res_hir_id);
        ret
    }

    fn visit_item(
        &mut self,
        item: &'tcx hir::Item<'_>,
        renamed: Option<Symbol>,
        om: &mut Module<'tcx>,
    ) {
        debug!("visiting item {:?}", item);
        let name = renamed.unwrap_or(item.ident.name);

        let def_id = item.def_id.to_def_id();
        let is_pub = item.vis.node.is_pub() || self.cx.tcx.has_attr(def_id, sym::macro_export);

        if is_pub {
            self.store_path(item.def_id.to_def_id());
        }

        match item.kind {
            hir::ItemKind::ForeignMod { items, .. } => {
                for item in items {
                    let item = self.cx.tcx.hir().foreign_item(item.id);
                    self.visit_foreign_item(item, None, om);
                }
            }
            // If we're inlining, skip private items.
            _ if self.inlining && !is_pub => {}
            hir::ItemKind::GlobalAsm(..) => {}
            hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
            hir::ItemKind::Use(ref path, kind) => {
                let is_glob = kind == hir::UseKind::Glob;

                // Struct and variant constructors and proc macro stubs always show up alongside
                // their definitions, we've already processed them so just discard these.
                if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = path.res {
                    return;
                }

                let attrs = self.cx.tcx.hir().attrs(item.hir_id());

                // If there was a private module in the current path then don't bother inlining
                // anything as it will probably be stripped anyway.
                if is_pub && self.inside_public_path {
                    let please_inline = attrs.iter().any(|item| match item.meta_item_list() {
                        Some(ref list) if item.has_name(sym::doc) => {
                            list.iter().any(|i| i.has_name(sym::inline))
                        }
                        _ => false,
                    });
                    let ident = if is_glob { None } else { Some(name) };
                    if self.maybe_inline_local(
                        item.hir_id(),
                        path.res,
                        ident,
                        is_glob,
                        om,
                        please_inline,
                    ) {
                        return;
                    }
                }

                om.items.push((item, renamed))
            }
            hir::ItemKind::Macro(ref macro_def) => {
                // `#[macro_export] macro_rules!` items are handled seperately in `visit()`,
                // above, since they need to be documented at the module top level. Accordingly,
                // we only want to handle macros if one of three conditions holds:
                //
                // 1. This macro was defined by `macro`, and thus isn't covered by the case
                //    above.
                // 2. This macro isn't marked with `#[macro_export]`, and thus isn't covered
                //    by the case above.
                // 3. We're inlining, since a reexport where inlining has been requested
                //    should be inlined even if it is also documented at the top level.

                let def_id = item.def_id.to_def_id();
                let is_macro_2_0 = !macro_def.macro_rules;
                let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export);

                if is_macro_2_0 || nonexported || self.inlining {
                    om.items.push((item, renamed));
                }
            }
            hir::ItemKind::Mod(ref m) => {
                om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name));
            }
            hir::ItemKind::Fn(..)
            | hir::ItemKind::ExternCrate(..)
            | hir::ItemKind::Enum(..)
            | hir::ItemKind::Struct(..)
            | hir::ItemKind::Union(..)
            | hir::ItemKind::TyAlias(..)
            | hir::ItemKind::OpaqueTy(..)
            | hir::ItemKind::Static(..)
            | hir::ItemKind::Trait(..)
            | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),
            hir::ItemKind::Const(..) => {
                // Underscore constants do not correspond to a nameable item and
                // so are never useful in documentation.
                if name != kw::Underscore {
                    om.items.push((item, renamed));
                }
            }
            hir::ItemKind::Impl(ref impl_) => {
                // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
                // them up regardless of where they're located.
                if !self.inlining && impl_.of_trait.is_none() {
                    om.items.push((item, None));
                }
            }
        }
    }

    fn visit_foreign_item(
        &mut self,
        item: &'tcx hir::ForeignItem<'_>,
        renamed: Option<Symbol>,
        om: &mut Module<'tcx>,
    ) {
        // If inlining we only want to include public functions.
        if !self.inlining || item.vis.node.is_pub() {
            om.foreigns.push((item, renamed));
        }
    }
}
<commit_msg>Oops, inverted condition, fix that<commit_after>//! The Rust AST Visitor. Extracts useful information and massages it into a form
//! usable for `clean`.

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::Node;
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
use rustc_span;
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};

use std::mem;

use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt};
use crate::core;
use crate::doctree::*;

// FIXME: Should this be replaced with tcx.def_path_str?
fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<String> {
    let crate_name = tcx.crate_name(did.krate).to_string();
    let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| {
        // extern blocks have an empty name
        let s = elem.data.to_string();
        if !s.is_empty() { Some(s) } else { None }
    });
    std::iter::once(crate_name).chain(relative).collect()
}

crate fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool {
    while let Some(id) = tcx.hir().get_enclosing_scope(node) {
        node = id;
        if tcx.hir().attrs(node).lists(sym::doc).has_word(sym::hidden) {
            return true;
        }
    }
    false
}

// Also, is there some reason that this doesn't use the 'visit'
// framework from syntax?.

crate struct RustdocVisitor<'a, 'tcx> {
    cx: &'a mut core::DocContext<'tcx>,
    view_item_stack: FxHashSet<hir::HirId>,
    inlining: bool,
    /// Are the current module and all of its parents public?
    inside_public_path: bool,
    exact_paths: FxHashMap<DefId, Vec<String>>,
}

impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
    crate fn new(cx: &'a mut core::DocContext<'tcx>) -> RustdocVisitor<'a, 'tcx> {
        // If the root is re-exported, terminate all recursion.
        let mut stack = FxHashSet::default();
        stack.insert(hir::CRATE_HIR_ID);
        RustdocVisitor {
            cx,
            view_item_stack: stack,
            inlining: false,
            inside_public_path: true,
            exact_paths: FxHashMap::default(),
        }
    }

    fn store_path(&mut self, did: DefId) {
        let tcx = self.cx.tcx;
        self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did));
    }

    crate fn visit(mut self) -> Module<'tcx> {
        let span = self.cx.tcx.def_span(CRATE_DEF_ID);
        let mut top_level_module = self.visit_mod_contents(
            &Spanned { span, node: hir::VisibilityKind::Public },
            hir::CRATE_HIR_ID,
            self.cx.tcx.hir().root_module(),
            self.cx.tcx.crate_name(LOCAL_CRATE),
        );

        // `#[macro_export] macro_rules!` items are reexported at the top level of the
        // crate, regardless of where they're defined. We want to document the
        // top level rexport of the macro, not its original definition, since
        // the rexport defines the path that a user will actually see. Accordingly,
        // we add the rexport as an item here, and then skip over the original
        // definition in `visit_item()` below.
        //
        // We also skip `#[macro_export] macro_rules!` that have alredy been inserted,
        // this can append if within the same module a `#[macro_export] macro_rules!`
        // is declared but also a reexport of itself producing two export of the same
        // macro in the same module.
        let mut inserted = FxHashSet::default();
        for export in self.cx.tcx.module_exports(CRATE_DEF_ID).unwrap_or(&[]) {
            if let Res::Def(DefKind::Macro(_), def_id) = export.res {
                if let Some(local_def_id) = def_id.as_local() {
                    if self.cx.tcx.has_attr(def_id, sym::macro_export) {
                        if inserted.insert(def_id) {
                            let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
                            let item = self.cx.tcx.hir().expect_item(hir_id);
                            top_level_module.items.push((item, None));
                        }
                    }
                }
            }
        }

        self.cx.cache.hidden_cfg = self
            .cx
            .tcx
            .hir()
            .attrs(CRATE_HIR_ID)
            .iter()
            .filter(|attr| attr.has_name(sym::doc))
            .flat_map(|attr| attr.meta_item_list().into_iter().flatten())
            .filter(|attr| attr.has_name(sym::cfg_hide))
            .flat_map(|attr| {
                attr.meta_item_list()
                    .unwrap_or(&[])
                    .iter()
                    .filter_map(|attr| {
                        Some(
                            Cfg::parse(attr.meta_item()?)
                                .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
                                .ok()?,
                        )
                    })
                    .collect::<Vec<_>>()
            })
            .collect();

        self.cx.cache.exact_paths = self.exact_paths;
        top_level_module
    }

    fn visit_mod_contents(
        &mut self,
        vis: &hir::Visibility<'_>,
        id: hir::HirId,
        m: &'tcx hir::Mod<'tcx>,
        name: Symbol,
    ) -> Module<'tcx> {
        let mut om = Module::new(name, id, m.inner);
        // Keep track of if there were any private modules in the path.
        let orig_inside_public_path = self.inside_public_path;
        self.inside_public_path &= vis.node.is_pub();
        for &i in m.item_ids {
            let item = self.cx.tcx.hir().item(i);
            self.visit_item(item, None, &mut om);
        }
        self.inside_public_path = orig_inside_public_path;
        om
    }

    /// Tries to resolve the target of a `pub use` statement and inlines the
    /// target if it is defined locally and would not be documented otherwise,
    /// or when it is specifically requested with `please_inline`.
    /// (the latter is the case when the import is marked `doc(inline)`)
    ///
    /// Cross-crate inlining occurs later on during crate cleaning
    /// and follows different rules.
    ///
    /// Returns `true` if the target has been inlined.
    fn maybe_inline_local(
        &mut self,
        id: hir::HirId,
        res: Res,
        renamed: Option<Symbol>,
        glob: bool,
        om: &mut Module<'tcx>,
        please_inline: bool,
    ) -> bool {
        debug!("maybe_inline_local res: {:?}", res);

        let tcx = self.cx.tcx;
        let res_did = if let Some(did) = res.opt_def_id() {
            did
        } else {
            return false;
        };

        let use_attrs = tcx.hir().attrs(id);
        // Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
        let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline)
            || use_attrs.lists(sym::doc).has_word(sym::hidden);

        // For cross-crate impl inlining we need to know whether items are
        // reachable in documentation -- a previously unreachable item can be
        // made reachable by cross-crate inlining which we're checking here.
        // (this is done here because we need to know this upfront).
        if !res_did.is_local() && !is_no_inline {
            let attrs = clean::inline::load_attrs(self.cx, res_did);
            let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden);
            if !self_is_hidden {
                if let Res::Def(kind, did) = res {
                    if kind == DefKind::Mod {
                        crate::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did)
                    } else {
                        // All items need to be handled here in case someone wishes to link
                        // to them with intra-doc links
                        self.cx.cache.access_levels.map.insert(did, AccessLevel::Public);
                    }
                }
            }
            return false;
        }

        let res_hir_id = match res_did.as_local() {
            Some(n) => tcx.hir().local_def_id_to_hir_id(n),
            None => return false,
        };

        let is_private = !self.cx.cache.access_levels.is_public(res_did);
        let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);

        // Only inline if requested or if the item would otherwise be stripped.
        if (!please_inline && !is_private && !is_hidden) || is_no_inline {
            return false;
        }

        if !self.view_item_stack.insert(res_hir_id) {
            return false;
        }

        let ret = match tcx.hir().get(res_hir_id) {
            Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => {
                let prev = mem::replace(&mut self.inlining, true);
                for &i in m.item_ids {
                    let i = self.cx.tcx.hir().item(i);
                    self.visit_item(i, None, om);
                }
                self.inlining = prev;
                true
            }
            Node::Item(it) if !glob => {
                let prev = mem::replace(&mut self.inlining, true);
                self.visit_item(it, renamed, om);
                self.inlining = prev;
                true
            }
            Node::ForeignItem(it) if !glob => {
                let prev = mem::replace(&mut self.inlining, true);
                self.visit_foreign_item(it, renamed, om);
                self.inlining = prev;
                true
            }
            _ => false,
        };
        self.view_item_stack.remove(&res_hir_id);
        ret
    }

    fn visit_item(
        &mut self,
        item: &'tcx hir::Item<'_>,
        renamed: Option<Symbol>,
        om: &mut Module<'tcx>,
    ) {
        debug!("visiting item {:?}", item);
        let name = renamed.unwrap_or(item.ident.name);

        let def_id = item.def_id.to_def_id();
        let is_pub = item.vis.node.is_pub() || self.cx.tcx.has_attr(def_id, sym::macro_export);

        if is_pub {
            self.store_path(item.def_id.to_def_id());
        }

        match item.kind {
            hir::ItemKind::ForeignMod { items, .. } => {
                for item in items {
                    let item = self.cx.tcx.hir().foreign_item(item.id);
                    self.visit_foreign_item(item, None, om);
                }
            }
            // If we're inlining, skip private items.
            _ if self.inlining && !is_pub => {}
            hir::ItemKind::GlobalAsm(..) => {}
            hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
            hir::ItemKind::Use(ref path, kind) => {
                let is_glob = kind == hir::UseKind::Glob;

                // Struct and variant constructors and proc macro stubs always show up alongside
                // their definitions, we've already processed them so just discard these.
                if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = path.res {
                    return;
                }

                let attrs = self.cx.tcx.hir().attrs(item.hir_id());

                // If there was a private module in the current path then don't bother inlining
                // anything as it will probably be stripped anyway.
                if is_pub && self.inside_public_path {
                    let please_inline = attrs.iter().any(|item| match item.meta_item_list() {
                        Some(ref list) if item.has_name(sym::doc) => {
                            list.iter().any(|i| i.has_name(sym::inline))
                        }
                        _ => false,
                    });
                    let ident = if is_glob { None } else { Some(name) };
                    if self.maybe_inline_local(
                        item.hir_id(),
                        path.res,
                        ident,
                        is_glob,
                        om,
                        please_inline,
                    ) {
                        return;
                    }
                }

                om.items.push((item, renamed))
            }
            hir::ItemKind::Macro(ref macro_def) => {
                // `#[macro_export] macro_rules!` items are handled seperately in `visit()`,
                // above, since they need to be documented at the module top level. Accordingly,
                // we only want to handle macros if one of three conditions holds:
                //
                // 1. This macro was defined by `macro`, and thus isn't covered by the case
                //    above.
                // 2. This macro isn't marked with `#[macro_export]`, and thus isn't covered
                //    by the case above.
                // 3. We're inlining, since a reexport where inlining has been requested
                //    should be inlined even if it is also documented at the top level.

                let def_id = item.def_id.to_def_id();
                let is_macro_2_0 = !macro_def.macro_rules;
                let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export);

                if is_macro_2_0 || nonexported || self.inlining {
                    om.items.push((item, renamed));
                }
            }
            hir::ItemKind::Mod(ref m) => {
                om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name));
            }
            hir::ItemKind::Fn(..)
            | hir::ItemKind::ExternCrate(..)
            | hir::ItemKind::Enum(..)
            | hir::ItemKind::Struct(..)
            | hir::ItemKind::Union(..)
            | hir::ItemKind::TyAlias(..)
            | hir::ItemKind::OpaqueTy(..)
            | hir::ItemKind::Static(..)
            | hir::ItemKind::Trait(..)
            | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),
            hir::ItemKind::Const(..) => {
                // Underscore constants do not correspond to a nameable item and
                // so are never useful in documentation.
                if name != kw::Underscore {
                    om.items.push((item, renamed));
                }
            }
            hir::ItemKind::Impl(ref impl_) => {
                // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
                // them up regardless of where they're located.
                if !self.inlining && impl_.of_trait.is_none() {
                    om.items.push((item, None));
                }
            }
        }
    }

    fn visit_foreign_item(
        &mut self,
        item: &'tcx hir::ForeignItem<'_>,
        renamed: Option<Symbol>,
        om: &mut Module<'tcx>,
    ) {
        // If inlining we only want to include public functions.
        if !self.inlining || item.vis.node.is_pub() {
            om.foreigns.push((item, renamed));
        }
    }
}
<|endoftext|>


<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! 3-dimmensional vector type
use std::ops::{Add, Sub, Neg, Mul, Div, BitXor, Index, IndexMut};
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign};
use std::cmp::PartialEq;
use types::{Matrix3, Zero};

/// A 3-dimensional vector type
///
/// A `Vector3D` implement all the arithmetics operations:
/// ```rust
/// // `u`, `v` and `w` are vectors. `a` and `b` are scalar
/// let u = Vector3D::new(1.0, 2.0, 3.0);
/// let v = Vector3D::new(1.0, 2.0, 3.0);
/// let a = 42.0;
///
/// // Addition
/// let w = u + v;
/// // Substraction
/// let w = u - v;
/// // Negation
/// let w = -u;
/// // Cross product
/// let w = u ^ v;
///
/// // Multiplication
/// let w = a * u;
/// let w = v * a;
/// // Division
/// let w = u / a;
///
/// // Dot product
/// let b = u * v;
/// ```
#[derive(Copy, Clone, Debug)]
pub struct Vector3D([f64; 3]);

impl Vector3D {
    /// Create a new `Vector3D` with components `x`, `y`, `z`
    pub fn new(x: f64, y: f64, z: f64) -> Vector3D {
        Vector3D([x, y, z])
    }
    /// Return the squared euclidean norm of a Vector3D
    #[inline] pub fn norm2(&self) -> f64 {
        self * self
    }
    /// Return the euclidean norm of a Vector3D
    #[inline] pub fn norm(&self) -> f64 {
        f64::sqrt(self.norm2())
    }
    /// Normalize a Vector3D
    #[inline] pub fn normalized(&self) -> Vector3D {
        self / self.norm()
    }
    /// Tensorial product between vectors
    pub fn tensorial(&self, other: &Vector3D) -> Matrix3 {
        Matrix3::new(self[0] * other[0], self[0] * other[1], self[0] * other[2],
                     self[1] * other[0], self[1] * other[1], self[1] * other[2],
                     self[2] * other[0], self[2] * other[1], self[2] * other[2])
    }
}

impl_arithmetic!(
    Vector3D, Vector3D, Add, add, Vector3D,
    self, other,
    Vector3D::new(self[0] + other[0], self[1] + other[1], self[2] + other[2])
);

impl_inplace_arithmetic!(
    Vector3D, Vector3D, AddAssign, add_assign,
    self, other,
    {self[0] += other[0]; self[1] += other[1]; self[2] += other[2]}
);

impl_arithmetic!(
    Vector3D, Vector3D, Sub, sub, Vector3D,
    self, other,
    Vector3D::new(self[0] - other[0], self[1] - other[1], self[2] - other[2])
);

impl_inplace_arithmetic!(
    Vector3D, Vector3D, SubAssign, sub_assign,
    self, other,
    {self[0] -= other[0]; self[1] -= other[1]; self[2] -= other[2]}
);

// Dot product
impl_arithmetic!(
    Vector3D, Vector3D, Mul, mul, f64,
    self, other,
    self[0] * other[0] + self[1] * other[1] + self[2] * other[2]
);

// Cross product
impl_arithmetic!(
    Vector3D, Vector3D, BitXor, bitxor, Vector3D,
    self, other,
    {let x = self[1] * other[2] - self[2] * other[1];
    let y = self[2] * other[0] - self[0] * other[2];
    let z = self[0] * other[1] - self[1] * other[0];
    Vector3D::new(x, y, z)}
);

/******************************************************************************/

lsh_scal_arithmetic!(
    Vector3D, Mul, mul, Vector3D,
    self, other,
    Vector3D::new(self[0] * other, self[1] * other, self[2] * other)
);

rhs_scal_arithmetic!(
    Vector3D, Mul, mul, Vector3D,
    self, other,
    Vector3D::new(self * other[0], self * other[1], self * other[2])
);

impl_inplace_arithmetic!(
    Vector3D, f64, MulAssign, mul_assign,
    self, other,
    {let other = other.clone(); self[0] *= other; self[1] *= other; self[2] *= other}
);

lsh_scal_arithmetic!(
    Vector3D, Div, div, Vector3D,
    self, other,
    Vector3D::new(self[0] / other, self[1] / other, self[2] / other)
);

impl_inplace_arithmetic!(
    Vector3D, f64, DivAssign, div_assign,
    self, other,
    {let other = other.clone(); self[0] /= other; self[1] /= other; self[2] /= other}
);

/******************************************************************************/

impl Neg for Vector3D {
    type Output = Vector3D;
    #[inline] fn neg(self) -> Vector3D {
        Vector3D::new(-self[0], -self[1], -self[2])
    }
}

impl<'a> Neg for &'a Vector3D {
    type Output = Vector3D;
    #[inline] fn neg(self) -> Vector3D {
        Vector3D::new(-self[0], -self[1], -self[2])
    }
}

impl<'a> Neg for &'a mut Vector3D {
    type Output = Vector3D;
    #[inline] fn neg(self) -> Vector3D {
        Vector3D::new(-self[0], -self[1], -self[2])
    }
}

/******************************************************************************/

/// Comparing two vectors
impl PartialEq for Vector3D {
    #[inline] fn eq(&self, other: &Vector3D) -> bool {
        self[0] == other[0] && self[1] == other[1] && self[2] == other[2]
    }
}

/// This is provided for convenience only, and is slower than direct field access
impl Index<usize> for Vector3D {
    type Output = f64;
    #[inline]
    fn index(&self, index: usize) -> &f64 {
        &self.0[index]
    }
}

/// This is provided for convenience only, and is slower than direct field access
impl IndexMut<usize> for Vector3D {
    #[inline]
    fn index_mut(&mut self, index: usize) -> &mut f64 {
        &mut self.0[index]
    }
}

impl Zero for Vector3D {
    fn zero() -> Vector3D {
        Vector3D::new(0.0, 0.0, 0.0)
    }

    fn is_zero(&self) -> bool {
        self.norm2() == 0.0
    }
}

/******************************************************************************/

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

    #[test]
    fn add() {
        let mut a = Vector3D::new(2.0, 3.5, 4.8);
        let mut b = Vector3D::new(6.1, -8.5, 7.3);

        let c = a + b;
        assert_eq!(c, Vector3D::new(8.1, -5.0, 12.1));

        a += b;
        assert_eq!(a, Vector3D::new(8.1, -5.0, 12.1));

        // Just checking that everything compile
        let _ = &a + b;
        let _ = a + &b;
        let _ = &a + &b;
        let _ = a + &mut b;
        let _ = &mut a + b;
        let _ = &mut a + &mut b;
        let _ = &mut a + &b;
        let _ = &a + &mut b;
        a += &b;
        a += &mut b;
        let _ = a;
    }

    #[test]
    fn sub() {
        let mut a = Vector3D::new(2.0, 3.5, 4.8);
        let mut b = Vector3D::new(6.1, -8.5, 7.3);

        let c = a - b;
        assert_eq!(c, Vector3D::new(-4.1, 12.0, -2.5));

        a -= b;
        assert_eq!(a, Vector3D::new(-4.1, 12.0, -2.5));

        // Just checking that everything compile
        let _ = &a - b;
        let _ = a - &b;
        let _ = &a - &b;
        let _ = a - &mut b;
        let _ = &mut a - b;
        let _ = &mut a - &mut b;
        let _ = &mut a - &b;
        let _ = &a - &mut b;
        a -= &b;
        a -= &mut b;
        let _ = a;
    }

    #[test]
    fn neg() {
        let mut a = Vector3D::new(6.1, -8.5, 7.3);

        let b = -a;
        assert_eq!(b, Vector3D::new(-6.1, 8.5, -7.3));

        let _ = -&a;
        let _ = -&mut a;
    }

    #[test]
    fn mul() {
        let mut a = Vector3D::new(2.0, 3.5, 4.8);
        let b = 2.0;

        let c = b * a;
        assert_eq!(c, Vector3D::new(4.0, 7.0, 9.6));

        let _ = b * &a;
        let _ = b * &mut a;

        let mut b = 1.5;
        let c = a * b;
        assert_eq!(c, Vector3D::new(3.0, 5.25, 7.199999999999999));

        a *= b;
        assert_eq!(a, Vector3D::new(3.0, 5.25, 7.199999999999999));

        // Just checking that everything compile
        let _ = &a * b;
        let _ = &mut a * b;
        a *= &b;
        a *= &mut b;
        let _ = a;
    }

    #[test]
    fn div() {
        let mut a = Vector3D::new(2.0, 3.5, 4.8);
        let mut b = 2.0;
        let c = a / b;
        assert_eq!(c, Vector3D::new(1.0, 1.75, 2.4));

        a /= b;
        assert_eq!(a, Vector3D::new(1.0, 1.75, 2.4));

        // Just checking that everything compile
        let _ = &a / b;
        let _ = &mut a / b;
        a /= &b;
        a /= &mut b;
        let _ = a;
    }

    #[test]
    fn dot_product() {
        let mut a = Vector3D::new(2.1, 3.5, 4.8);
        let mut b = Vector3D::new(6.1, -8.5, 7.3);

        let c = a * b;
        assert_eq!(c, 18.1);

        // Just checking that everything compile
        let _ = &a * b;
        let _ = a * &b;
        let _ = &a * &b;
        let _ = a * &mut b;
        let _ = &mut a * b;
        let _ = &mut a * &mut b;
        let _ = &mut a * &b;
        let _ = &a * &mut b;
    }

    #[test]
    fn cross_product() {
        let a = Vector3D::new(2.1, 3.5, 4.8);
        let b = Vector3D::new(6.1, -8.5, 7.3);

        let c = a ^ b;
        assert_eq!(c*a, 0.0);

        let mut a = Vector3D::new(1.0, 0.0, 0.0);
        let mut b = Vector3D::new(0.0, 1.0, 0.0);

        let c = a ^ b;
        assert_eq!(c, Vector3D::new(0.0, 0.0, 1.0));

        // Just checking that everything compile
        let _ = &a ^ b;
        let _ = a ^ &b;
        let _ = &a ^ &b;
        let _ = a ^ &mut b;
        let _ = &mut a ^ b;
        let _ = &mut a ^ &mut b;
        let _ = &mut a ^ &b;
        let _ = &a ^ &mut b;
    }

    #[test]
    fn index() {
        let mut a = Vector3D::new(2.1, 3.5, 4.8);

        assert_eq!(a[0], a[0]);
        assert_eq!(a[1], a[1]);
        assert_eq!(a[2], a[2]);

        a[0] = 1.0;
        a[1] = 1.0;
        a[2] = 1.0;

        assert_eq!(a[0], 1.0);
        assert_eq!(a[1], 1.0);
        assert_eq!(a[2], 1.0);
    }

    #[test]
    #[should_panic]
    fn index_out_of_bounds() {
        let mut a = Vector3D::new(2.1, 3.5, 4.8);
        a[3] += 4.0;
    }
}
<commit_msg>[doc] Add examples to all Vector3D functions<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! 3-dimmensional vector type
use std::ops::{Add, Sub, Neg, Mul, Div, BitXor, Index, IndexMut};
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign};
use std::cmp::PartialEq;
use types::{Matrix3, Zero};

/// A 3-dimensional vector type
///
/// A `Vector3D` implement all the arithmetics operations:
///
/// ```
/// # use lumol::Vector3D;
/// let u = Vector3D::new(1.0, 2.0, 3.0);
/// let v = Vector3D::new(4.0, -2.0, 1.0);
///
/// // Indexing
/// assert_eq!(u[0], 1.0);
/// assert_eq!(u[1], 2.0);
/// assert_eq!(u[2], 3.0);
///
/// // Addition
/// let w = u + v;
/// assert_eq!(w, Vector3D::new(5.0, 0.0, 4.0));
///
/// // Substraction
/// let w = u - v;
/// assert_eq!(w, Vector3D::new(-3.0, 4.0, 2.0));
///
/// // Negation
/// let w = -u;
/// assert_eq!(w, Vector3D::new(-1.0, -2.0, -3.0));
///
/// // Cross product
/// let w = u ^ v;
/// assert_eq!(w, Vector3D::new(8.0, 11.0, -10.0));
///
/// // Multiplication
/// let w = 2.0 * u;
/// assert_eq!(w, Vector3D::new(2.0, 4.0, 6.0));
///
/// let w = u * 3.0;
/// assert_eq!(w, Vector3D::new(3.0, 6.0, 9.0));
///
/// // Division
/// let w = u / 2.0;
/// assert_eq!(w, Vector3D::new(0.5, 1.0, 1.5));
///
/// // Dot product
/// let a = u * v;
/// assert_eq!(a, 3.0);
/// ```
#[derive(Copy, Clone, Debug)]
pub struct Vector3D([f64; 3]);

impl Vector3D {
    /// Create a new `Vector3D` with components `x`, `y`, `z`
    ///
    /// # Examples
    /// ```
    /// # use lumol::Vector3D;
    /// let vec = Vector3D::new(1.0, 0.0, -42.0);
    /// ```
    pub fn new(x: f64, y: f64, z: f64) -> Vector3D {
        Vector3D([x, y, z])
    }

    /// Return the squared euclidean norm of a Vector3D
    ///
    /// # Examples
    /// ```
    /// # use lumol::Vector3D;
    /// let vec = Vector3D::new(1.0, 0.0, -4.0);
    /// assert_eq!(vec.norm2(), 17.0);
    /// ```
    #[inline] pub fn norm2(&self) -> f64 {
        self * self
    }

    /// Return the euclidean norm of a Vector3D
    /// # Examples
    /// ```
    /// # use lumol::Vector3D;
    /// # use std::f64;
    /// let vec = Vector3D::new(1.0, 0.0, -4.0);
    /// assert_eq!(vec.norm(), f64::sqrt(17.0));
    /// ```
    #[inline] pub fn norm(&self) -> f64 {
        f64::sqrt(self.norm2())
    }

    /// Normalize a `Vector3D`.
    /// # Examples
    /// ```
    /// # use lumol::Vector3D;
    /// let vec = Vector3D::new(1.0, 0.0, -4.0);
    /// let n = vec.normalized();
    /// assert_eq!(n.norm(), 1.0);
    /// ```
    #[inline] pub fn normalized(&self) -> Vector3D {
        self / self.norm()
    }

    /// Tensorial product between vectors. The tensorial product between the
    /// vectors `a` and `b` creates a `Matrix3` with component (i, j) equals to
    /// `a[i] * b[j]`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use lumol::Vector3D;
    /// # use lumol::Matrix3;
    /// let a = Vector3D::new(1.0, 0.0, -4.0);
    /// let b = Vector3D::new(1.0, 2.0, 3.0);
    /// let matrix = Matrix3::new(
    ///     1.0, 2.0, 3.0,
    ///     0.0, 0.0, 0.0,
    ///     -4.0, -8.0, -12.0
    /// );
    /// assert_eq!(a.tensorial(&b), matrix);
    /// ```
    pub fn tensorial(&self, other: &Vector3D) -> Matrix3 {
        Matrix3::new(self[0] * other[0], self[0] * other[1], self[0] * other[2],
                     self[1] * other[0], self[1] * other[1], self[1] * other[2],
                     self[2] * other[0], self[2] * other[1], self[2] * other[2])
    }
}

impl_arithmetic!(
    Vector3D, Vector3D, Add, add, Vector3D,
    self, other,
    Vector3D::new(self[0] + other[0], self[1] + other[1], self[2] + other[2])
);

impl_inplace_arithmetic!(
    Vector3D, Vector3D, AddAssign, add_assign,
    self, other,
    {self[0] += other[0]; self[1] += other[1]; self[2] += other[2]}
);

impl_arithmetic!(
    Vector3D, Vector3D, Sub, sub, Vector3D,
    self, other,
    Vector3D::new(self[0] - other[0], self[1] - other[1], self[2] - other[2])
);

impl_inplace_arithmetic!(
    Vector3D, Vector3D, SubAssign, sub_assign,
    self, other,
    {self[0] -= other[0]; self[1] -= other[1]; self[2] -= other[2]}
);

// Dot product
impl_arithmetic!(
    Vector3D, Vector3D, Mul, mul, f64,
    self, other,
    self[0] * other[0] + self[1] * other[1] + self[2] * other[2]
);

// Cross product
impl_arithmetic!(
    Vector3D, Vector3D, BitXor, bitxor, Vector3D,
    self, other,
    {let x = self[1] * other[2] - self[2] * other[1];
    let y = self[2] * other[0] - self[0] * other[2];
    let z = self[0] * other[1] - self[1] * other[0];
    Vector3D::new(x, y, z)}
);

/******************************************************************************/

lsh_scal_arithmetic!(
    Vector3D, Mul, mul, Vector3D,
    self, other,
    Vector3D::new(self[0] * other, self[1] * other, self[2] * other)
);

rhs_scal_arithmetic!(
    Vector3D, Mul, mul, Vector3D,
    self, other,
    Vector3D::new(self * other[0], self * other[1], self * other[2])
);

impl_inplace_arithmetic!(
    Vector3D, f64, MulAssign, mul_assign,
    self, other,
    {let other = other.clone(); self[0] *= other; self[1] *= other; self[2] *= other}
);

lsh_scal_arithmetic!(
    Vector3D, Div, div, Vector3D,
    self, other,
    Vector3D::new(self[0] / other, self[1] / other, self[2] / other)
);

impl_inplace_arithmetic!(
    Vector3D, f64, DivAssign, div_assign,
    self, other,
    {let other = other.clone(); self[0] /= other; self[1] /= other; self[2] /= other}
);

/******************************************************************************/

impl Neg for Vector3D {
    type Output = Vector3D;
    #[inline] fn neg(self) -> Vector3D {
        Vector3D::new(-self[0], -self[1], -self[2])
    }
}

impl<'a> Neg for &'a Vector3D {
    type Output = Vector3D;
    #[inline] fn neg(self) -> Vector3D {
        Vector3D::new(-self[0], -self[1], -self[2])
    }
}

impl<'a> Neg for &'a mut Vector3D {
    type Output = Vector3D;
    #[inline] fn neg(self) -> Vector3D {
        Vector3D::new(-self[0], -self[1], -self[2])
    }
}

/******************************************************************************/

/// Comparing two vectors
impl PartialEq for Vector3D {
    #[inline] fn eq(&self, other: &Vector3D) -> bool {
        self[0] == other[0] && self[1] == other[1] && self[2] == other[2]
    }
}

impl Index<usize> for Vector3D {
    type Output = f64;
    #[inline]
    fn index(&self, index: usize) -> &f64 {
        &self.0[index]
    }
}

impl IndexMut<usize> for Vector3D {
    #[inline]
    fn index_mut(&mut self, index: usize) -> &mut f64 {
        &mut self.0[index]
    }
}

impl Zero for Vector3D {
    fn zero() -> Vector3D {
        Vector3D::new(0.0, 0.0, 0.0)
    }

    fn is_zero(&self) -> bool {
        self.norm2() == 0.0
    }
}

/******************************************************************************/

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

    #[test]
    fn add() {
        let mut a = Vector3D::new(2.0, 3.5, 4.8);
        let mut b = Vector3D::new(6.1, -8.5, 7.3);

        let c = a + b;
        assert_eq!(c, Vector3D::new(8.1, -5.0, 12.1));

        a += b;
        assert_eq!(a, Vector3D::new(8.1, -5.0, 12.1));

        // Just checking that everything compile
        let _ = &a + b;
        let _ = a + &b;
        let _ = &a + &b;
        let _ = a + &mut b;
        let _ = &mut a + b;
        let _ = &mut a + &mut b;
        let _ = &mut a + &b;
        let _ = &a + &mut b;
        a += &b;
        a += &mut b;
        let _ = a;
    }

    #[test]
    fn sub() {
        let mut a = Vector3D::new(2.0, 3.5, 4.8);
        let mut b = Vector3D::new(6.1, -8.5, 7.3);

        let c = a - b;
        assert_eq!(c, Vector3D::new(-4.1, 12.0, -2.5));

        a -= b;
        assert_eq!(a, Vector3D::new(-4.1, 12.0, -2.5));

        // Just checking that everything compile
        let _ = &a - b;
        let _ = a - &b;
        let _ = &a - &b;
        let _ = a - &mut b;
        let _ = &mut a - b;
        let _ = &mut a - &mut b;
        let _ = &mut a - &b;
        let _ = &a - &mut b;
        a -= &b;
        a -= &mut b;
        let _ = a;
    }

    #[test]
    fn neg() {
        let mut a = Vector3D::new(6.1, -8.5, 7.3);

        let b = -a;
        assert_eq!(b, Vector3D::new(-6.1, 8.5, -7.3));

        let _ = -&a;
        let _ = -&mut a;
    }

    #[test]
    fn mul() {
        let mut a = Vector3D::new(2.0, 3.5, 4.8);
        let b = 2.0;

        let c = b * a;
        assert_eq!(c, Vector3D::new(4.0, 7.0, 9.6));

        let _ = b * &a;
        let _ = b * &mut a;

        let mut b = 1.5;
        let c = a * b;
        assert_eq!(c, Vector3D::new(3.0, 5.25, 7.199999999999999));

        a *= b;
        assert_eq!(a, Vector3D::new(3.0, 5.25, 7.199999999999999));

        // Just checking that everything compile
        let _ = &a * b;
        let _ = &mut a * b;
        a *= &b;
        a *= &mut b;
        let _ = a;
    }

    #[test]
    fn div() {
        let mut a = Vector3D::new(2.0, 3.5, 4.8);
        let mut b = 2.0;
        let c = a / b;
        assert_eq!(c, Vector3D::new(1.0, 1.75, 2.4));

        a /= b;
        assert_eq!(a, Vector3D::new(1.0, 1.75, 2.4));

        // Just checking that everything compile
        let _ = &a / b;
        let _ = &mut a / b;
        a /= &b;
        a /= &mut b;
        let _ = a;
    }

    #[test]
    fn dot_product() {
        let mut a = Vector3D::new(2.1, 3.5, 4.8);
        let mut b = Vector3D::new(6.1, -8.5, 7.3);

        let c = a * b;
        assert_eq!(c, 18.1);

        // Just checking that everything compile
        let _ = &a * b;
        let _ = a * &b;
        let _ = &a * &b;
        let _ = a * &mut b;
        let _ = &mut a * b;
        let _ = &mut a * &mut b;
        let _ = &mut a * &b;
        let _ = &a * &mut b;
    }

    #[test]
    fn cross_product() {
        let a = Vector3D::new(2.1, 3.5, 4.8);
        let b = Vector3D::new(6.1, -8.5, 7.3);

        let c = a ^ b;
        assert_eq!(c*a, 0.0);

        let mut a = Vector3D::new(1.0, 0.0, 0.0);
        let mut b = Vector3D::new(0.0, 1.0, 0.0);

        let c = a ^ b;
        assert_eq!(c, Vector3D::new(0.0, 0.0, 1.0));

        // Just checking that everything compile
        let _ = &a ^ b;
        let _ = a ^ &b;
        let _ = &a ^ &b;
        let _ = a ^ &mut b;
        let _ = &mut a ^ b;
        let _ = &mut a ^ &mut b;
        let _ = &mut a ^ &b;
        let _ = &a ^ &mut b;
    }

    #[test]
    fn index() {
        let mut a = Vector3D::new(2.1, 3.5, 4.8);

        assert_eq!(a[0], a[0]);
        assert_eq!(a[1], a[1]);
        assert_eq!(a[2], a[2]);

        a[0] = 1.0;
        a[1] = 1.0;
        a[2] = 1.0;

        assert_eq!(a[0], 1.0);
        assert_eq!(a[1], 1.0);
        assert_eq!(a[2], 1.0);
    }

    #[test]
    #[should_panic]
    fn index_out_of_bounds() {
        let mut a = Vector3D::new(2.1, 3.5, 4.8);
        a[3] += 4.0;
    }
}
<|endoftext|>