<commit_before>use inflector::Inflector;

use std::collections::HashMap;

use botocore::{Operation, Service};
use super::GenerateProtocol;

pub struct JsonGenerator;

impl GenerateProtocol for JsonGenerator {

    fn generate_methods(&self, service: &Service) -> String {
        service.operations.values().map(|operation| {

            let output_type = operation.output_shape_or("()");

            format!("
                {documentation}
                {method_signature} -> {result_type} {{
                    {payload}
                    let mut request = SignedRequest::new(\"{http_method}\", \"{signing_name}\", self.region, \"{request_uri}\");
                    {modify_endpoint_prefix}
                    request.set_content_type(\"application/x-amz-json-{json_version}\".to_owned());
                    request.add_header(\"x-amz-target\", \"{target_prefix}.{name}\");
                    request.set_payload(payload);
                    let mut result = request.sign_and_execute(try!(self.credentials_provider.credentials()));
                    let status = result.status.to_u16();
                    let mut body = String::new();
                    result.read_to_string(&mut body).unwrap();
                    match status {{
                        200 => {{
                            {ok_response}
                        }}
                        _ => {err_response},
                    }}
                }}
                ",
                documentation = generate_documentation(operation).unwrap_or("".to_owned()),
                method_signature = generate_method_signature(operation),
                payload = generate_payload(operation),
                signing_name = service.signing_name(),
                modify_endpoint_prefix = generate_endpoint_modification(service).unwrap_or("".to_owned()),
                http_method = operation.http.method,
                name = operation.name,
                ok_response = generate_ok_response(operation, output_type),
                err_response = generate_err_response(service, operation),
                result_type = generate_result_type(service, operation, output_type),
                request_uri = operation.http.request_uri,
                target_prefix = service.metadata.target_prefix.as_ref().unwrap(),
                json_version = service.metadata.json_version.as_ref().unwrap(),
            )
        }).collect::<Vec<String>>().join("\n")
    }

    fn generate_prelude(&self, service: &Service) -> String {
        format!(
            "use std::io::Read;

            use serde_json;

            use credential::ProvideAwsCredentials;
            use region;
            use signature::SignedRequest;

            {error_imports}",
            error_imports = generate_error_imports(service))
    }

    fn generate_struct_attributes(&self) -> String {
        "#[derive(Debug, Default, Deserialize, Serialize)]".to_owned()
    }

    fn generate_error_types(&self, service: &Service) -> Option<String>{
        if service.typed_errors() {

            // grab error type documentation for use with error enums in generated code
            // botocore presents errors as structs.  we filter those out in generate_types.
            let mut error_documentation = HashMap::new();

            for (name, shape) in service.shapes.iter() {
                if shape.exception() && shape.documentation.is_some() {
                    error_documentation.insert(name, shape.documentation.as_ref().unwrap());
                }
            }

            Some(service.operations.iter()
                .filter_map(|(_, operation)| generate_error_type(operation, &error_documentation) )
                .collect::<Vec<String>>()
                .join("\n")
                )
        } else {
           None
        }
    }

    fn timestamp_type(&self) -> &'static str {
        "f64"
    }

    fn generate_additional_annotations(&self, service: &Service, shape_name: &str, type_name: &str) -> Vec<String> {
        let service_name = service.service_type_name();

        if (service_name == "DynamoDb" || service_name == "DynamoDbStreams") &&
           (type_name == "ListAttributeValue" || type_name == "MapAttributeValue") {
                vec![format!("#[serde(bound=\"\")]")]
        } else if service.service_type_name() == "Emr" &&
            shape_name == "Configuration" && type_name == "ConfigurationList" {
                vec![format!("#[serde(bound=\"\")]")]
        } else {
            Vec::<String>::with_capacity(0)
        }
    }

}

fn generate_endpoint_modification(service: &Service) -> Option<String> {
    if service.signing_name() == service.metadata.endpoint_prefix {
        None
    } else {
        Some(format!("request.set_endpoint_prefix(\"{}\".to_string());", service.metadata.endpoint_prefix))
    }
}

fn generate_method_signature(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "pub fn {method_name}(&self, input: &{input_type}) ",
            input_type = operation.input_shape(),
            method_name = operation.name.to_snake_case()
        )
    } else {
        format!(
            "pub fn {method_name}(&self) ",
            method_name = operation.name.to_snake_case()
        )
    }
}

fn generate_payload(operation: &Operation) -> String {
    if operation.input.is_some() {
        "let encoded = serde_json::to_string(input).unwrap();
         let payload = Some(encoded.as_bytes());".to_string()
    } else {
        "let payload = None;".to_string()
    }
}

pub fn generate_error_type(operation: &Operation, error_documentation: &HashMap<&String, &String>,) -> Option<String> {

    let error_type_name = operation.error_type_name();

    Some(format!("
        #[derive(Debug, PartialEq)]
        pub enum {type_name} {{
            {error_types}
        }}

        impl {type_name} {{
            pub fn from_body(body: &str) -> {type_name} {{
                match from_str::<SerdeJsonValue>(body) {{
                    Ok(json) => {{
                        let error_type: &str = match json.find(\"__type\") {{
                            Some(error_type) => error_type.as_string().unwrap_or(\"Unknown\"),
                            None => \"Unknown\",
                        }};

                        match error_type {{
                            {type_matchers}
                        }}
                    }},
                    Err(_) => {type_name}::Unknown(String::from(body))
                }}
            }}
        }}
        impl From<AwsError> for {type_name} {{
            fn from(err: AwsError) -> {type_name} {{
                {type_name}::Unknown(err.message)
            }}
        }}
        impl fmt::Display for {type_name} {{
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{
                write!(f, \"{{}}\", self.description())
            }}
        }}
        impl Error for {type_name} {{
            fn description(&self) -> &str {{
               match *self {{
                   {description_matchers}
               }}
           }}
       }}
       ",
       type_name = error_type_name,
       error_types = generate_error_enum_types(operation, error_documentation).unwrap_or(String::from("")),
       type_matchers = generate_error_type_matchers(operation).unwrap_or(String::from("")),
       description_matchers = generate_error_description_matchers(operation).unwrap_or(String::from(""))))
}

fn generate_error_enum_types(operation: &Operation, error_documentation: &HashMap<&String, &String>) -> Option<String> {
    let mut enum_types: Vec<String> = Vec::new();
    let mut add_validation = true;

    if operation.errors.is_some() {
        for error in operation.errors.as_ref().unwrap().iter() {
            let error_name = error.idiomatic_error_name();

            enum_types.push(format!("\n///{}\n{}(String)",
                error_documentation.get(&error.shape).unwrap_or(&&String::from("")),
                error_name));

            if error_name == "Validation" {
                add_validation = false;
            }
        }
    }

    if add_validation {
        enum_types.push("/// A validation error occurred.  Details from AWS are provided.\nValidation(String)".to_string());
    }

    enum_types.push("/// An unknown error occurred.  The raw HTTP response is provided.\nUnknown(String)".to_string());
    Some(enum_types.join(","))
}

fn generate_error_type_matchers(operation: &Operation) -> Option<String> {
    let mut type_matchers: Vec<String> = Vec::new();
    let error_type = operation.error_type_name();
    let mut add_validation = true;

    if operation.errors.is_some() {
        for error in operation.errors.as_ref().unwrap().iter() {
            let error_name = error.idiomatic_error_name();

            type_matchers.push(format!("\"{error_shape}\" => {error_type}::{error_name}(String::from(body))",
                error_shape = error.shape,
                error_type = error_type,
                error_name = error_name));

            if error_name == "Validation" {
                add_validation = false;
            }

        }
    }

    if add_validation {
        type_matchers.push(format!("\"ValidationException\" => {error_type}::Validation(String::from(body))", error_type = error_type));
    }

    type_matchers.push(format!("_ => {error_type}::Unknown(String::from(body))",  error_type = error_type));
    Some(type_matchers.join(","))
}

fn generate_error_description_matchers(operation: &Operation) -> Option<String> {
    let mut type_matchers: Vec<String> = Vec::new();
    let error_type = operation.error_type_name();
    let mut add_validation = true;

    if operation.errors.is_some() {
        for error in operation.errors.as_ref().unwrap().iter() {
            let error_name = error.idiomatic_error_name();
            type_matchers.push(format!("{error_type}::{error_shape}(ref cause) => cause",
                error_type = operation.error_type_name(),
                error_shape = error_name));

            if error_name == "Validation" {
                add_validation = false;
            }

        }
    }

    if add_validation {
        type_matchers.push(format!("{error_type}::Validation(ref cause) => cause", error_type = error_type));
    }

    type_matchers.push(format!("{error_type}::Unknown(ref cause) => cause", error_type = error_type));
    Some(type_matchers.join(","))
}

fn generate_result_type<'a>(service: &Service, operation: &Operation, output_type: &'a str) -> String {
    if service.typed_errors() {
        format!("Result<{}, {}>", output_type, operation.error_type_name())
    } else {
        format!("AwsResult<{}>", output_type)
    }
}

fn generate_error_imports(service: &Service) -> &'static str {
    if service.typed_errors() {
        "use error::AwsError;
        use std::error::Error;
        use std::fmt;
        use serde_json::Value as SerdeJsonValue;
        use serde_json::from_str;"
    } else {
        "use error::{AwsResult, parse_json_protocol_error};"
    }
}

fn generate_documentation(operation: &Operation) -> Option<String> {
    operation.documentation.as_ref().map(|docs| {
        format!("#[doc=\"{}\"]", docs.replace("\\","\\\\").replace("\"", "\\\""))
    })
}

fn generate_ok_response(operation: &Operation, output_type: &str) -> String {
    if operation.output.is_some() {
        format!("Ok(serde_json::from_str::<{}>(&body).unwrap())", output_type)
    } else {
        "Ok(())".to_owned()
    }
}

fn generate_err_response(service: &Service, operation: &Operation) -> String {
    if service.typed_errors() {
        format!("Err({}::from_body(&body))", operation.error_type_name())
    } else {
        String::from("Err(parse_json_protocol_error(&body))")
    }
}
<commit_msg>refactor a bit to implement code review feedback<commit_after>use inflector::Inflector;

use std::collections::HashMap;

use botocore::{Operation, Service};
use super::GenerateProtocol;

pub struct JsonGenerator;

impl GenerateProtocol for JsonGenerator {

    fn generate_methods(&self, service: &Service) -> String {
        service.operations.values().map(|operation| {

            let output_type = operation.output_shape_or("()");

            format!("
                {documentation}
                {method_signature} -> {result_type} {{
                    {payload}
                    let mut request = SignedRequest::new(\"{http_method}\", \"{signing_name}\", self.region, \"{request_uri}\");
                    {modify_endpoint_prefix}
                    request.set_content_type(\"application/x-amz-json-{json_version}\".to_owned());
                    request.add_header(\"x-amz-target\", \"{target_prefix}.{name}\");
                    request.set_payload(payload);
                    let mut result = request.sign_and_execute(try!(self.credentials_provider.credentials()));
                    let status = result.status.to_u16();
                    let mut body = String::new();
                    result.read_to_string(&mut body).unwrap();
                    match status {{
                        200 => {{
                            {ok_response}
                        }}
                        _ => {err_response},
                    }}
                }}
                ",
                documentation = generate_documentation(operation).unwrap_or("".to_owned()),
                method_signature = generate_method_signature(operation),
                payload = generate_payload(operation),
                signing_name = service.signing_name(),
                modify_endpoint_prefix = generate_endpoint_modification(service).unwrap_or("".to_owned()),
                http_method = operation.http.method,
                name = operation.name,
                ok_response = generate_ok_response(operation, output_type),
                err_response = generate_err_response(service, operation),
                result_type = generate_result_type(service, operation, output_type),
                request_uri = operation.http.request_uri,
                target_prefix = service.metadata.target_prefix.as_ref().unwrap(),
                json_version = service.metadata.json_version.as_ref().unwrap(),
            )
        }).collect::<Vec<String>>().join("\n")
    }

    fn generate_prelude(&self, service: &Service) -> String {
        format!(
            "use std::io::Read;

            use serde_json;

            use credential::ProvideAwsCredentials;
            use region;
            use signature::SignedRequest;

            {error_imports}",
            error_imports = generate_error_imports(service))
    }

    fn generate_struct_attributes(&self) -> String {
        "#[derive(Debug, Default, Deserialize, Serialize)]".to_owned()
    }

    fn generate_error_types(&self, service: &Service) -> Option<String>{
        if service.typed_errors() {

            // grab error type documentation for use with error enums in generated code
            // botocore presents errors as structs.  we filter those out in generate_types.
            let mut error_documentation = HashMap::new();

            for (name, shape) in service.shapes.iter() {
                if shape.exception() && shape.documentation.is_some() {
                    error_documentation.insert(name, shape.documentation.as_ref().unwrap());
                }
            }

            Some(service.operations.iter()
                .filter_map(|(_, operation)| generate_error_type(operation, &error_documentation) )
                .collect::<Vec<String>>()
                .join("\n")
                )
        } else {
           None
        }
    }

    fn timestamp_type(&self) -> &'static str {
        "f64"
    }

    fn generate_additional_annotations(&self, service: &Service, shape_name: &str, type_name: &str) -> Vec<String> {
        let service_name = service.service_type_name();

        // serde can no longer handle recursively defined types without help
        // annotate them to avoid compiler overflows
        match service_name {
            "DynamoDb" | "DynamoDbStreams" => {
                if type_name == "ListAttributeValue" || type_name == "MapAttributeValue" {
                    return vec![format!("#[serde(bound=\"\")]")];
                }
            },
            "Emr" => {
                if shape_name == "Configuration" && type_name == "ConfigurationList" {
                    return vec![format!("#[serde(bound=\"\")]")];
                }
            },
            _ => {}
        }

        Vec::<String>::with_capacity(0)
    }

}

fn generate_endpoint_modification(service: &Service) -> Option<String> {
    if service.signing_name() == service.metadata.endpoint_prefix {
        None
    } else {
        Some(format!("request.set_endpoint_prefix(\"{}\".to_string());", service.metadata.endpoint_prefix))
    }
}

fn generate_method_signature(operation: &Operation) -> String {
    if operation.input.is_some() {
        format!(
            "pub fn {method_name}(&self, input: &{input_type}) ",
            input_type = operation.input_shape(),
            method_name = operation.name.to_snake_case()
        )
    } else {
        format!(
            "pub fn {method_name}(&self) ",
            method_name = operation.name.to_snake_case()
        )
    }
}

fn generate_payload(operation: &Operation) -> String {
    if operation.input.is_some() {
        "let encoded = serde_json::to_string(input).unwrap();
         let payload = Some(encoded.as_bytes());".to_string()
    } else {
        "let payload = None;".to_string()
    }
}

pub fn generate_error_type(operation: &Operation, error_documentation: &HashMap<&String, &String>,) -> Option<String> {

    let error_type_name = operation.error_type_name();

    Some(format!("
        #[derive(Debug, PartialEq)]
        pub enum {type_name} {{
            {error_types}
        }}

        impl {type_name} {{
            pub fn from_body(body: &str) -> {type_name} {{
                match from_str::<SerdeJsonValue>(body) {{
                    Ok(json) => {{
                        let error_type: &str = match json.find(\"__type\") {{
                            Some(error_type) => error_type.as_string().unwrap_or(\"Unknown\"),
                            None => \"Unknown\",
                        }};

                        match error_type {{
                            {type_matchers}
                        }}
                    }},
                    Err(_) => {type_name}::Unknown(String::from(body))
                }}
            }}
        }}
        impl From<AwsError> for {type_name} {{
            fn from(err: AwsError) -> {type_name} {{
                {type_name}::Unknown(err.message)
            }}
        }}
        impl fmt::Display for {type_name} {{
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{
                write!(f, \"{{}}\", self.description())
            }}
        }}
        impl Error for {type_name} {{
            fn description(&self) -> &str {{
               match *self {{
                   {description_matchers}
               }}
           }}
       }}
       ",
       type_name = error_type_name,
       error_types = generate_error_enum_types(operation, error_documentation).unwrap_or(String::from("")),
       type_matchers = generate_error_type_matchers(operation).unwrap_or(String::from("")),
       description_matchers = generate_error_description_matchers(operation).unwrap_or(String::from(""))))
}

fn generate_error_enum_types(operation: &Operation, error_documentation: &HashMap<&String, &String>) -> Option<String> {
    let mut enum_types: Vec<String> = Vec::new();
    let mut add_validation = true;

    if operation.errors.is_some() {
        for error in operation.errors.as_ref().unwrap().iter() {
            let error_name = error.idiomatic_error_name();

            enum_types.push(format!("\n///{}\n{}(String)",
                error_documentation.get(&error.shape).unwrap_or(&&String::from("")),
                error_name));

            if error_name == "Validation" {
                add_validation = false;
            }
        }
    }

    if add_validation {
        enum_types.push("/// A validation error occurred.  Details from AWS are provided.\nValidation(String)".to_string());
    }

    enum_types.push("/// An unknown error occurred.  The raw HTTP response is provided.\nUnknown(String)".to_string());
    Some(enum_types.join(","))
}

fn generate_error_type_matchers(operation: &Operation) -> Option<String> {
    let mut type_matchers: Vec<String> = Vec::new();
    let error_type = operation.error_type_name();
    let mut add_validation = true;

    if operation.errors.is_some() {
        for error in operation.errors.as_ref().unwrap().iter() {
            let error_name = error.idiomatic_error_name();

            type_matchers.push(format!("\"{error_shape}\" => {error_type}::{error_name}(String::from(body))",
                error_shape = error.shape,
                error_type = error_type,
                error_name = error_name));

            if error_name == "Validation" {
                add_validation = false;
            }

        }
    }

    if add_validation {
        type_matchers.push(format!("\"ValidationException\" => {error_type}::Validation(String::from(body))", error_type = error_type));
    }

    type_matchers.push(format!("_ => {error_type}::Unknown(String::from(body))",  error_type = error_type));
    Some(type_matchers.join(","))
}

fn generate_error_description_matchers(operation: &Operation) -> Option<String> {
    let mut type_matchers: Vec<String> = Vec::new();
    let error_type = operation.error_type_name();
    let mut add_validation = true;

    if operation.errors.is_some() {
        for error in operation.errors.as_ref().unwrap().iter() {
            let error_name = error.idiomatic_error_name();
            type_matchers.push(format!("{error_type}::{error_shape}(ref cause) => cause",
                error_type = operation.error_type_name(),
                error_shape = error_name));

            if error_name == "Validation" {
                add_validation = false;
            }

        }
    }

    if add_validation {
        type_matchers.push(format!("{error_type}::Validation(ref cause) => cause", error_type = error_type));
    }

    type_matchers.push(format!("{error_type}::Unknown(ref cause) => cause", error_type = error_type));
    Some(type_matchers.join(","))
}

fn generate_result_type<'a>(service: &Service, operation: &Operation, output_type: &'a str) -> String {
    if service.typed_errors() {
        format!("Result<{}, {}>", output_type, operation.error_type_name())
    } else {
        format!("AwsResult<{}>", output_type)
    }
}

fn generate_error_imports(service: &Service) -> &'static str {
    if service.typed_errors() {
        "use error::AwsError;
        use std::error::Error;
        use std::fmt;
        use serde_json::Value as SerdeJsonValue;
        use serde_json::from_str;"
    } else {
        "use error::{AwsResult, parse_json_protocol_error};"
    }
}

fn generate_documentation(operation: &Operation) -> Option<String> {
    operation.documentation.as_ref().map(|docs| {
        format!("#[doc=\"{}\"]", docs.replace("\\","\\\\").replace("\"", "\\\""))
    })
}

fn generate_ok_response(operation: &Operation, output_type: &str) -> String {
    if operation.output.is_some() {
        format!("Ok(serde_json::from_str::<{}>(&body).unwrap())", output_type)
    } else {
        "Ok(())".to_owned()
    }
}

fn generate_err_response(service: &Service, operation: &Operation) -> String {
    if service.typed_errors() {
        format!("Err({}::from_body(&body))", operation.error_type_name())
    } else {
        String::from("Err(parse_json_protocol_error(&body))")
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Memory profiling functions.

use libc::{c_char,c_int,c_void,size_t};
use std::borrow::ToOwned;
use std::ffi::CString;
use std::iter::AdditiveIterator;
use std::old_io::timer::sleep;
#[cfg(target_os="linux")]
use std::old_io::File;
use std::mem::size_of;
use std::ptr::null_mut;
use std::sync::mpsc::{Sender, channel, Receiver};
use std::time::duration::Duration;
use task::spawn_named;
#[cfg(target_os="macos")]
use task_info::task_basic_info::{virtual_size,resident_size};

pub struct MemoryProfilerChan(pub Sender<MemoryProfilerMsg>);

impl MemoryProfilerChan {
    pub fn send(&self, msg: MemoryProfilerMsg) {
        let MemoryProfilerChan(ref c) = *self;
        c.send(msg).unwrap();
    }
}

pub enum MemoryProfilerMsg {
    /// Message used to force print the memory profiling metrics.
    Print,
    /// Tells the memory profiler to shut down.
    Exit,
}

pub struct MemoryProfiler {
    pub port: Receiver<MemoryProfilerMsg>,
}

impl MemoryProfiler {
    pub fn create(period: Option<f64>) -> MemoryProfilerChan {
        let (chan, port) = channel();
        match period {
            Some(period) => {
                let period = Duration::milliseconds((period * 1000f64) as i64);
                let chan = chan.clone();
                spawn_named("Memory profiler timer".to_owned(), move || {
                    loop {
                        sleep(period);
                        if chan.send(MemoryProfilerMsg::Print).is_err() {
                            break;
                        }
                    }
                });
                // Spawn the memory profiler.
                spawn_named("Memory profiler".to_owned(), move || {
                    let memory_profiler = MemoryProfiler::new(port);
                    memory_profiler.start();
                });
            }
            None => {
                // No-op to handle messages when the memory profiler is
                // inactive.
                spawn_named("Memory profiler".to_owned(), move || {
                    loop {
                        match port.recv() {
                            Err(_) | Ok(MemoryProfilerMsg::Exit) => break,
                            _ => {}
                        }
                    }
                });
            }
        }

        MemoryProfilerChan(chan)
    }

    pub fn new(port: Receiver<MemoryProfilerMsg>) -> MemoryProfiler {
        MemoryProfiler {
            port: port
        }
    }

    pub fn start(&self) {
        loop {
            match self.port.recv() {
               Ok(msg) => {
                   if !self.handle_msg(msg) {
                       break
                   }
               }
               _ => break
            }
        }
    }

    fn handle_msg(&self, msg: MemoryProfilerMsg) -> bool {
        match msg {
            MemoryProfilerMsg::Print => {
                self.handle_print_msg();
                true
            },
            MemoryProfilerMsg::Exit => false
        }
    }

    fn print_measurement(path: &str, nbytes: Option<u64>) {
        match nbytes {
            Some(nbytes) => {
                let mebi = 1024f64 * 1024f64;
                println!("{:12.2}: {}", (nbytes as f64) / mebi, path);
            }
            None => {
                println!("{:>12}: {}", "???", path);
            }
        }
    }

    fn handle_print_msg(&self) {
        println!("{:12}: {}", "_size (MiB)_", "_category_");

        // Virtual and physical memory usage, as reported by the OS.
        MemoryProfiler::print_measurement("vsize", get_vsize());
        MemoryProfiler::print_measurement("resident", get_resident());

        for seg in get_resident_segments().iter() {
            MemoryProfiler::print_measurement(seg.0.as_slice(), Some(seg.1));
        }

        // Total number of bytes allocated by the application on the system
        // heap.
        MemoryProfiler::print_measurement("system-heap-allocated",
                                          get_system_heap_allocated());

        // The descriptions of the following jemalloc measurements are taken
        // directly from the jemalloc documentation.

        // "Total number of bytes allocated by the application."
        MemoryProfiler::print_measurement("jemalloc-heap-allocated",
                                          get_jemalloc_stat("stats.allocated"));

        // "Total number of bytes in active pages allocated by the application.
        // This is a multiple of the page size, and greater than or equal to
        // |stats.allocated|."
        MemoryProfiler::print_measurement("jemalloc-heap-active",
                                          get_jemalloc_stat("stats.active"));

        // "Total number of bytes in chunks mapped on behalf of the application.
        // This is a multiple of the chunk size, and is at least as large as
        // |stats.active|. This does not include inactive chunks."
        MemoryProfiler::print_measurement("jemalloc-heap-mapped",
                                          get_jemalloc_stat("stats.mapped"));

        println!("");
    }
}

#[cfg(target_os="linux")]
extern {
    fn mallinfo() -> struct_mallinfo;
}

#[cfg(target_os="linux")]
#[repr(C)]
pub struct struct_mallinfo {
    arena:    c_int,
    ordblks:  c_int,
    smblks:   c_int,
    hblks:    c_int,
    hblkhd:   c_int,
    usmblks:  c_int,
    fsmblks:  c_int,
    uordblks: c_int,
    fordblks: c_int,
    keepcost: c_int,
}

#[cfg(target_os="linux")]
fn get_system_heap_allocated() -> Option<u64> {
    let mut info: struct_mallinfo;
    unsafe {
        info = mallinfo();
    }
    // The documentation in the glibc man page makes it sound like |uordblks|
    // would suffice, but that only gets the small allocations that are put in
    // the brk heap. We need |hblkhd| as well to get the larger allocations
    // that are mmapped.
    Some((info.hblkhd + info.uordblks) as u64)
}

#[cfg(not(target_os="linux"))]
fn get_system_heap_allocated() -> Option<u64> {
    None
}

extern {
    fn je_mallctl(name: *const c_char, oldp: *mut c_void, oldlenp: *mut size_t,
                  newp: *mut c_void, newlen: size_t) -> c_int;
}

fn get_jemalloc_stat(value_name: &str) -> Option<u64> {
    // Before we request the measurement of interest, we first send an "epoch"
    // request. Without that jemalloc gives cached statistics(!) which can be
    // highly inaccurate.
    let epoch_name = "epoch";
    let epoch_c_name = CString::from_slice(epoch_name.as_bytes());
    let mut epoch: u64 = 0;
    let epoch_ptr = &mut epoch as *mut _ as *mut c_void;
    let mut epoch_len = size_of::<u64>() as size_t;

    let value_c_name = CString::from_slice(value_name.as_bytes());
    let mut value: size_t = 0;
    let value_ptr = &mut value as *mut _ as *mut c_void;
    let mut value_len = size_of::<size_t>() as size_t;

    // Using the same values for the `old` and `new` parameters is enough
    // to get the statistics updated.
    let rv = unsafe {
        je_mallctl(epoch_c_name.as_ptr(), epoch_ptr, &mut epoch_len, epoch_ptr,
                   epoch_len)
    };
    if rv != 0 {
        return None;
    }

    let rv = unsafe {
        je_mallctl(value_c_name.as_ptr(), value_ptr, &mut value_len,
                   null_mut(), 0)
    };
    if rv != 0 {
        return None;
    }

    Some(value as u64)
}

// Like std::macros::try!, but for Option<>.
macro_rules! option_try(
    ($e:expr) => (match $e { Some(e) => e, None => return None })
);

#[cfg(target_os="linux")]
fn get_proc_self_statm_field(field: usize) -> Option<u64> {
    let mut f = File::open(&Path::new("/proc/self/statm"));
    match f.read_to_string() {
        Ok(contents) => {
            let s = option_try!(contents.as_slice().words().nth(field));
            let npages = option_try!(s.parse::<u64>().ok());
            Some(npages * (::std::env::page_size() as u64))
        }
        Err(_) => None
    }
}

#[cfg(target_os="linux")]
fn get_vsize() -> Option<u64> {
    get_proc_self_statm_field(0)
}

#[cfg(target_os="linux")]
fn get_resident() -> Option<u64> {
    get_proc_self_statm_field(1)
}

#[cfg(target_os="macos")]
fn get_vsize() -> Option<u64> {
    virtual_size()
}

#[cfg(target_os="macos")]
fn get_resident() -> Option<u64> {
    resident_size()
}

#[cfg(not(any(target_os="linux", target_os = "macos")))]
fn get_vsize() -> Option<u64> {
    None
}

#[cfg(not(any(target_os="linux", target_os = "macos")))]
fn get_resident() -> Option<u64> {
    None
}

#[cfg(target_os="linux")]
fn get_resident_segments() -> Vec<(String, u64)> {
    use regex::Regex;
    use std::collections::HashMap;
    use std::collections::hash_map::Entry;

    // The first line of an entry in /proc/<pid>/smaps looks just like an entry
    // in /proc/<pid>/maps:
    //
    //   address           perms offset  dev   inode  pathname
    //   02366000-025d8000 rw-p 00000000 00:00 0      [heap]
    //
    // Each of the following lines contains a key and a value, separated
    // by ": ", where the key does not contain either of those characters.
    // For example:
    //
    //   Rss:           132 kB

    let path = Path::new("/proc/self/smaps");
    let mut f = ::std::old_io::BufferedReader::new(File::open(&path));

    let seg_re = Regex::new(
        r"^[:xdigit:]+-[:xdigit:]+ (....) [:xdigit:]+ [:xdigit:]+:[:xdigit:]+ \d+ +(.*)").unwrap();
    let rss_re = Regex::new(r"^Rss: +(\d+) kB").unwrap();

    // We record each segment's resident size.
    let mut seg_map: HashMap<String, u64> = HashMap::new();

    #[derive(PartialEq)]
    enum LookingFor { Segment, Rss }
    let mut looking_for = LookingFor::Segment;

    let mut curr_seg_name = String::new();

    // Parse the file.
    for line in f.lines() {
        let line = match line {
            Ok(line) => line,
            Err(_) => continue,
        };
        if looking_for == LookingFor::Segment {
            // Look for a segment info line.
            let cap = match seg_re.captures(line.as_slice()) {
                Some(cap) => cap,
                None => continue,
            };
            let perms = cap.at(1).unwrap();
            let pathname = cap.at(2).unwrap();

            // Construct the segment name from its pathname and permissions.
            curr_seg_name.clear();
            curr_seg_name.push_str("- ");
            if pathname == "" || pathname.starts_with("[stack:") {
                // Anonymous memory. Entries marked with "[stack:nnn]"
                // look like thread stacks but they may include other
                // anonymous mappings, so we can't trust them and just
                // treat them as entirely anonymous.
                curr_seg_name.push_str("anonymous");
            } else {
                curr_seg_name.push_str(pathname);
            }
            curr_seg_name.push_str(" (");
            curr_seg_name.push_str(perms);
            curr_seg_name.push_str(")");

            looking_for = LookingFor::Rss;
        } else {
            // Look for an "Rss:" line.
            let cap = match rss_re.captures(line.as_slice()) {
                Some(cap) => cap,
                None => continue,
            };
            let rss = cap.at(1).unwrap().parse::<u64>().unwrap() * 1024;

            if rss > 0 {
                // Aggregate small segments into "- other".
                let seg_name = if rss < 512 * 1024 {
                    "- other".to_owned()
                } else {
                    curr_seg_name.clone()
                };
                match seg_map.entry(seg_name) {
                    Entry::Vacant(entry) => { entry.insert(rss); },
                    Entry::Occupied(mut entry) => *entry.get_mut() += rss,
                }
            }

            looking_for = LookingFor::Segment;
        }
    }

    let mut segs: Vec<(String, u64)> = seg_map.into_iter().collect();

    // Get the total and add it to the vector. Note that this total differs
    // from the "resident" measurement obtained via /proc/<pid>/statm in
    // get_resident(). It's unclear why this difference occurs; for some
    // processes the measurements match, but for Servo they do not.
    let total = segs.iter().map(|&(_, size)| size).sum();
    segs.push(("resident-according-to-smaps".to_owned(), total));

    // Sort by size; the total will be first.
    segs.sort_by(|&(_, rss1), &(_, rss2)| rss2.cmp(&rss1));

    segs
}

#[cfg(not(target_os="linux"))]
fn get_resident_segments() -> Vec<(String, u64)> {
    vec![]
}

<commit_msg>auto merge of #5137 : Adenilson/servo/cleanupWarning02, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Memory profiling functions.

use libc::{c_char,c_int,c_void,size_t};
use std::borrow::ToOwned;
use std::ffi::CString;
#[cfg(target_os = "linux")]
use std::iter::AdditiveIterator;
use std::old_io::timer::sleep;
#[cfg(target_os="linux")]
use std::old_io::File;
use std::mem::size_of;
use std::ptr::null_mut;
use std::sync::mpsc::{Sender, channel, Receiver};
use std::time::duration::Duration;
use task::spawn_named;
#[cfg(target_os="macos")]
use task_info::task_basic_info::{virtual_size,resident_size};

pub struct MemoryProfilerChan(pub Sender<MemoryProfilerMsg>);

impl MemoryProfilerChan {
    pub fn send(&self, msg: MemoryProfilerMsg) {
        let MemoryProfilerChan(ref c) = *self;
        c.send(msg).unwrap();
    }
}

pub enum MemoryProfilerMsg {
    /// Message used to force print the memory profiling metrics.
    Print,
    /// Tells the memory profiler to shut down.
    Exit,
}

pub struct MemoryProfiler {
    pub port: Receiver<MemoryProfilerMsg>,
}

impl MemoryProfiler {
    pub fn create(period: Option<f64>) -> MemoryProfilerChan {
        let (chan, port) = channel();
        match period {
            Some(period) => {
                let period = Duration::milliseconds((period * 1000f64) as i64);
                let chan = chan.clone();
                spawn_named("Memory profiler timer".to_owned(), move || {
                    loop {
                        sleep(period);
                        if chan.send(MemoryProfilerMsg::Print).is_err() {
                            break;
                        }
                    }
                });
                // Spawn the memory profiler.
                spawn_named("Memory profiler".to_owned(), move || {
                    let memory_profiler = MemoryProfiler::new(port);
                    memory_profiler.start();
                });
            }
            None => {
                // No-op to handle messages when the memory profiler is
                // inactive.
                spawn_named("Memory profiler".to_owned(), move || {
                    loop {
                        match port.recv() {
                            Err(_) | Ok(MemoryProfilerMsg::Exit) => break,
                            _ => {}
                        }
                    }
                });
            }
        }

        MemoryProfilerChan(chan)
    }

    pub fn new(port: Receiver<MemoryProfilerMsg>) -> MemoryProfiler {
        MemoryProfiler {
            port: port
        }
    }

    pub fn start(&self) {
        loop {
            match self.port.recv() {
               Ok(msg) => {
                   if !self.handle_msg(msg) {
                       break
                   }
               }
               _ => break
            }
        }
    }

    fn handle_msg(&self, msg: MemoryProfilerMsg) -> bool {
        match msg {
            MemoryProfilerMsg::Print => {
                self.handle_print_msg();
                true
            },
            MemoryProfilerMsg::Exit => false
        }
    }

    fn print_measurement(path: &str, nbytes: Option<u64>) {
        match nbytes {
            Some(nbytes) => {
                let mebi = 1024f64 * 1024f64;
                println!("{:12.2}: {}", (nbytes as f64) / mebi, path);
            }
            None => {
                println!("{:>12}: {}", "???", path);
            }
        }
    }

    fn handle_print_msg(&self) {
        println!("{:12}: {}", "_size (MiB)_", "_category_");

        // Virtual and physical memory usage, as reported by the OS.
        MemoryProfiler::print_measurement("vsize", get_vsize());
        MemoryProfiler::print_measurement("resident", get_resident());

        for seg in get_resident_segments().iter() {
            MemoryProfiler::print_measurement(seg.0.as_slice(), Some(seg.1));
        }

        // Total number of bytes allocated by the application on the system
        // heap.
        MemoryProfiler::print_measurement("system-heap-allocated",
                                          get_system_heap_allocated());

        // The descriptions of the following jemalloc measurements are taken
        // directly from the jemalloc documentation.

        // "Total number of bytes allocated by the application."
        MemoryProfiler::print_measurement("jemalloc-heap-allocated",
                                          get_jemalloc_stat("stats.allocated"));

        // "Total number of bytes in active pages allocated by the application.
        // This is a multiple of the page size, and greater than or equal to
        // |stats.allocated|."
        MemoryProfiler::print_measurement("jemalloc-heap-active",
                                          get_jemalloc_stat("stats.active"));

        // "Total number of bytes in chunks mapped on behalf of the application.
        // This is a multiple of the chunk size, and is at least as large as
        // |stats.active|. This does not include inactive chunks."
        MemoryProfiler::print_measurement("jemalloc-heap-mapped",
                                          get_jemalloc_stat("stats.mapped"));

        println!("");
    }
}

#[cfg(target_os="linux")]
extern {
    fn mallinfo() -> struct_mallinfo;
}

#[cfg(target_os="linux")]
#[repr(C)]
pub struct struct_mallinfo {
    arena:    c_int,
    ordblks:  c_int,
    smblks:   c_int,
    hblks:    c_int,
    hblkhd:   c_int,
    usmblks:  c_int,
    fsmblks:  c_int,
    uordblks: c_int,
    fordblks: c_int,
    keepcost: c_int,
}

#[cfg(target_os="linux")]
fn get_system_heap_allocated() -> Option<u64> {
    let mut info: struct_mallinfo;
    unsafe {
        info = mallinfo();
    }
    // The documentation in the glibc man page makes it sound like |uordblks|
    // would suffice, but that only gets the small allocations that are put in
    // the brk heap. We need |hblkhd| as well to get the larger allocations
    // that are mmapped.
    Some((info.hblkhd + info.uordblks) as u64)
}

#[cfg(not(target_os="linux"))]
fn get_system_heap_allocated() -> Option<u64> {
    None
}

extern {
    fn je_mallctl(name: *const c_char, oldp: *mut c_void, oldlenp: *mut size_t,
                  newp: *mut c_void, newlen: size_t) -> c_int;
}

fn get_jemalloc_stat(value_name: &str) -> Option<u64> {
    // Before we request the measurement of interest, we first send an "epoch"
    // request. Without that jemalloc gives cached statistics(!) which can be
    // highly inaccurate.
    let epoch_name = "epoch";
    let epoch_c_name = CString::from_slice(epoch_name.as_bytes());
    let mut epoch: u64 = 0;
    let epoch_ptr = &mut epoch as *mut _ as *mut c_void;
    let mut epoch_len = size_of::<u64>() as size_t;

    let value_c_name = CString::from_slice(value_name.as_bytes());
    let mut value: size_t = 0;
    let value_ptr = &mut value as *mut _ as *mut c_void;
    let mut value_len = size_of::<size_t>() as size_t;

    // Using the same values for the `old` and `new` parameters is enough
    // to get the statistics updated.
    let rv = unsafe {
        je_mallctl(epoch_c_name.as_ptr(), epoch_ptr, &mut epoch_len, epoch_ptr,
                   epoch_len)
    };
    if rv != 0 {
        return None;
    }

    let rv = unsafe {
        je_mallctl(value_c_name.as_ptr(), value_ptr, &mut value_len,
                   null_mut(), 0)
    };
    if rv != 0 {
        return None;
    }

    Some(value as u64)
}

// Like std::macros::try!, but for Option<>.
macro_rules! option_try(
    ($e:expr) => (match $e { Some(e) => e, None => return None })
);

#[cfg(target_os="linux")]
fn get_proc_self_statm_field(field: usize) -> Option<u64> {
    let mut f = File::open(&Path::new("/proc/self/statm"));
    match f.read_to_string() {
        Ok(contents) => {
            let s = option_try!(contents.as_slice().words().nth(field));
            let npages = option_try!(s.parse::<u64>().ok());
            Some(npages * (::std::env::page_size() as u64))
        }
        Err(_) => None
    }
}

#[cfg(target_os="linux")]
fn get_vsize() -> Option<u64> {
    get_proc_self_statm_field(0)
}

#[cfg(target_os="linux")]
fn get_resident() -> Option<u64> {
    get_proc_self_statm_field(1)
}

#[cfg(target_os="macos")]
fn get_vsize() -> Option<u64> {
    virtual_size()
}

#[cfg(target_os="macos")]
fn get_resident() -> Option<u64> {
    resident_size()
}

#[cfg(not(any(target_os="linux", target_os = "macos")))]
fn get_vsize() -> Option<u64> {
    None
}

#[cfg(not(any(target_os="linux", target_os = "macos")))]
fn get_resident() -> Option<u64> {
    None
}

#[cfg(target_os="linux")]
fn get_resident_segments() -> Vec<(String, u64)> {
    use regex::Regex;
    use std::collections::HashMap;
    use std::collections::hash_map::Entry;

    // The first line of an entry in /proc/<pid>/smaps looks just like an entry
    // in /proc/<pid>/maps:
    //
    //   address           perms offset  dev   inode  pathname
    //   02366000-025d8000 rw-p 00000000 00:00 0      [heap]
    //
    // Each of the following lines contains a key and a value, separated
    // by ": ", where the key does not contain either of those characters.
    // For example:
    //
    //   Rss:           132 kB

    let path = Path::new("/proc/self/smaps");
    let mut f = ::std::old_io::BufferedReader::new(File::open(&path));

    let seg_re = Regex::new(
        r"^[:xdigit:]+-[:xdigit:]+ (....) [:xdigit:]+ [:xdigit:]+:[:xdigit:]+ \d+ +(.*)").unwrap();
    let rss_re = Regex::new(r"^Rss: +(\d+) kB").unwrap();

    // We record each segment's resident size.
    let mut seg_map: HashMap<String, u64> = HashMap::new();

    #[derive(PartialEq)]
    enum LookingFor { Segment, Rss }
    let mut looking_for = LookingFor::Segment;

    let mut curr_seg_name = String::new();

    // Parse the file.
    for line in f.lines() {
        let line = match line {
            Ok(line) => line,
            Err(_) => continue,
        };
        if looking_for == LookingFor::Segment {
            // Look for a segment info line.
            let cap = match seg_re.captures(line.as_slice()) {
                Some(cap) => cap,
                None => continue,
            };
            let perms = cap.at(1).unwrap();
            let pathname = cap.at(2).unwrap();

            // Construct the segment name from its pathname and permissions.
            curr_seg_name.clear();
            curr_seg_name.push_str("- ");
            if pathname == "" || pathname.starts_with("[stack:") {
                // Anonymous memory. Entries marked with "[stack:nnn]"
                // look like thread stacks but they may include other
                // anonymous mappings, so we can't trust them and just
                // treat them as entirely anonymous.
                curr_seg_name.push_str("anonymous");
            } else {
                curr_seg_name.push_str(pathname);
            }
            curr_seg_name.push_str(" (");
            curr_seg_name.push_str(perms);
            curr_seg_name.push_str(")");

            looking_for = LookingFor::Rss;
        } else {
            // Look for an "Rss:" line.
            let cap = match rss_re.captures(line.as_slice()) {
                Some(cap) => cap,
                None => continue,
            };
            let rss = cap.at(1).unwrap().parse::<u64>().unwrap() * 1024;

            if rss > 0 {
                // Aggregate small segments into "- other".
                let seg_name = if rss < 512 * 1024 {
                    "- other".to_owned()
                } else {
                    curr_seg_name.clone()
                };
                match seg_map.entry(seg_name) {
                    Entry::Vacant(entry) => { entry.insert(rss); },
                    Entry::Occupied(mut entry) => *entry.get_mut() += rss,
                }
            }

            looking_for = LookingFor::Segment;
        }
    }

    let mut segs: Vec<(String, u64)> = seg_map.into_iter().collect();

    // Get the total and add it to the vector. Note that this total differs
    // from the "resident" measurement obtained via /proc/<pid>/statm in
    // get_resident(). It's unclear why this difference occurs; for some
    // processes the measurements match, but for Servo they do not.
    let total = segs.iter().map(|&(_, size)| size).sum();
    segs.push(("resident-according-to-smaps".to_owned(), total));

    // Sort by size; the total will be first.
    segs.sort_by(|&(_, rss1), &(_, rss2)| rss2.cmp(&rss1));

    segs
}

#[cfg(not(target_os="linux"))]
fn get_resident_segments() -> Vec<(String, u64)> {
    vec![]
}

<|endoftext|>


<commit_before><commit_msg>There are unused use statements in unittests<commit_after><|endoftext|>


<commit_before><commit_msg>Add preliminary test of walking data pointers via reflection.<commit_after>import libc::c_void;

iface data_cursor {
    fn set_ptr(p: *c_void);
    fn get_ptr() -> *c_void;
}

enum my_visitor = @{
    mut ptr: *c_void,
    mut vals: [str]
};

impl methods for my_visitor {
    fn get<T>(f: fn(T)) {
        unsafe {
            f(*(self.ptr as *T));
        }
    }
}

impl of data_cursor for my_visitor {
    fn set_ptr(p: *c_void) { self.ptr = p; }
    fn get_ptr() -> *c_void { self.ptr }
}

impl of intrinsic::ty_visitor for my_visitor {

    fn visit_bot() -> bool { true }
    fn visit_nil() -> bool { true }
    fn visit_bool() -> bool {
        self.get::<bool>() {|b|
            self.vals += [bool::to_str(b)];
        }
        true
    }
    fn visit_int() -> bool {
        self.get::<int>() {|i|
            self.vals += [int::to_str(i, 10u)];
        }
        true
    }
    fn visit_i8() -> bool { true }
    fn visit_i16() -> bool { true }
    fn visit_i32() -> bool { true }
    fn visit_i64() -> bool { true }

    fn visit_uint() -> bool { true }
    fn visit_u8() -> bool { true }
    fn visit_u16() -> bool { true }
    fn visit_u32() -> bool { true }
    fn visit_u64() -> bool { true }

    fn visit_float() -> bool { true }
    fn visit_f32() -> bool { true }
    fn visit_f64() -> bool { true }

    fn visit_char() -> bool { true }
    fn visit_str() -> bool { true }

    fn visit_estr_box() -> bool { true }
    fn visit_estr_uniq() -> bool { true }
    fn visit_estr_slice() -> bool { true }
    fn visit_estr_fixed(_sz: uint) -> bool { true }

    fn visit_enter_box(_mtbl: uint) -> bool { true }
    fn visit_leave_box(_mtbl: uint) -> bool { true }
    fn visit_enter_uniq(_mtbl: uint) -> bool { true }
    fn visit_leave_uniq(_mtbl: uint) -> bool { true }
    fn visit_enter_ptr(_mtbl: uint) -> bool { true }
    fn visit_leave_ptr(_mtbl: uint) -> bool { true }
    fn visit_enter_rptr(_mtbl: uint) -> bool { true }
    fn visit_leave_rptr(_mtbl: uint) -> bool { true }

    fn visit_enter_vec(_mtbl: uint) -> bool { true }
    fn visit_leave_vec(_mtbl: uint) -> bool { true }
    fn visit_enter_evec_box(_mtbl: uint) -> bool { true }
    fn visit_leave_evec_box(_mtbl: uint) -> bool { true }
    fn visit_enter_evec_uniq(_mtbl: uint) -> bool { true }
    fn visit_leave_evec_uniq(_mtbl: uint) -> bool { true }
    fn visit_enter_evec_slice(_mtbl: uint) -> bool { true }
    fn visit_leave_evec_slice(_mtbl: uint) -> bool { true }
    fn visit_enter_evec_fixed(_mtbl: uint, _sz: uint) -> bool { true }
    fn visit_leave_evec_fixed(_mtbl: uint, _sz: uint) -> bool { true }

    fn visit_enter_rec(_n_fields: uint) -> bool { true }
    fn visit_enter_rec_field(_mtbl: uint, _i: uint,
                             _name: str/&) -> bool { true }
    fn visit_leave_rec_field(_mtbl: uint, _i: uint,
                             _name: str/&) -> bool { true }
    fn visit_leave_rec(_n_fields: uint) -> bool { true }

    fn visit_enter_class(_n_fields: uint) -> bool { true }
    fn visit_enter_class_field(_mtbl: uint, _i: uint,
                               _name: str/&) -> bool { true }
    fn visit_leave_class_field(_mtbl: uint, _i: uint,
                               _name: str/&) -> bool { true }
    fn visit_leave_class(_n_fields: uint) -> bool { true }

    fn visit_enter_tup(_n_fields: uint) -> bool { true }
    fn visit_enter_tup_field(_i: uint) -> bool { true }
    fn visit_leave_tup_field(_i: uint) -> bool { true }
    fn visit_leave_tup(_n_fields: uint) -> bool { true }

    fn visit_enter_fn(_purity: uint, _proto: uint,
                      _n_inputs: uint, _retstyle: uint) -> bool { true }
    fn visit_enter_fn_input(_i: uint, _mode: uint) -> bool { true }
    fn visit_leave_fn_input(_i: uint, _mode: uint) -> bool { true }
    fn visit_enter_fn_output(_retstyle: uint) -> bool { true }
    fn visit_leave_fn_output(_retstyle: uint) -> bool { true }
    fn visit_leave_fn(_purity: uint, _proto: uint,
                      _n_inputs: uint, _retstyle: uint) -> bool { true }

    fn visit_enter_enum(_n_variants: uint) -> bool { true }
    fn visit_enter_enum_variant(_variant: uint,
                                _disr_val: int,
                                _n_fields: uint,
                                _name: str/&) -> bool { true }
    fn visit_enter_enum_variant_field(_i: uint) -> bool { true }
    fn visit_leave_enum_variant_field(_i: uint) -> bool { true }
    fn visit_leave_enum_variant(_variant: uint,
                                _disr_val: int,
                                _n_fields: uint,
                                _name: str/&) -> bool { true }
    fn visit_leave_enum(_n_variants: uint) -> bool { true }

    fn visit_iface() -> bool { true }
    fn visit_enter_res() -> bool { true }
    fn visit_leave_res() -> bool { true }
    fn visit_var() -> bool { true }
    fn visit_var_integral() -> bool { true }
    fn visit_param(_i: uint) -> bool { true }
    fn visit_self() -> bool { true }
    fn visit_type() -> bool { true }
    fn visit_opaque_box() -> bool { true }
    fn visit_enter_constr() -> bool { true }
    fn visit_leave_constr() -> bool { true }
    fn visit_closure_ptr(_ck: uint) -> bool { true }
}

enum data_visitor<V:intrinsic::ty_visitor data_cursor> = {
    inner: V
};

fn align_to<T>(size: uint, align: uint) -> uint {
    ((size + align) - 1u) & !(align - 1u)
}

impl dv<V: intrinsic::ty_visitor data_cursor> of
    intrinsic::ty_visitor for data_visitor<V> {

    fn move_ptr(f: fn(*c_void) -> *c_void) {
        self.inner.set_ptr(f(self.inner.get_ptr()));
    }

    fn bump(sz: uint) {
        self.move_ptr() {|p|
            ((p as uint) + sz) as *c_void
        }
    }

    fn align_to<T>() {
        self.move_ptr() {|p|
            align_to::<T>(p as uint,
                          sys::min_align_of::<T>()) as *c_void
        }
    }

    fn bump_past<T>() {
        self.bump(sys::size_of::<T>());
    }

    fn visit_bot() -> bool {
        self.align_to::<bool>();
        self.inner.visit_bot();
        self.bump_past::<bool>();
        true
    }
    fn visit_nil() -> bool { true }
    fn visit_bool() -> bool {
        self.align_to::<bool>();
        self.inner.visit_bool();
        self.bump_past::<bool>();
        true
    }
    fn visit_int() -> bool {
        self.align_to::<int>();
        self.inner.visit_int();
        self.bump_past::<int>();
        true
    }
    fn visit_i8() -> bool { true }
    fn visit_i16() -> bool { true }
    fn visit_i32() -> bool { true }
    fn visit_i64() -> bool { true }

    fn visit_uint() -> bool { true }
    fn visit_u8() -> bool { true }
    fn visit_u16() -> bool { true }
    fn visit_u32() -> bool { true }
    fn visit_u64() -> bool { true }

    fn visit_float() -> bool { true }
    fn visit_f32() -> bool { true }
    fn visit_f64() -> bool { true }

    fn visit_char() -> bool { true }
    fn visit_str() -> bool { true }

    fn visit_estr_box() -> bool { true }
    fn visit_estr_uniq() -> bool { true }
    fn visit_estr_slice() -> bool { true }
    fn visit_estr_fixed(_sz: uint) -> bool { true }

    fn visit_enter_box(_mtbl: uint) -> bool { true }
    fn visit_leave_box(_mtbl: uint) -> bool { true }
    fn visit_enter_uniq(_mtbl: uint) -> bool { true }
    fn visit_leave_uniq(_mtbl: uint) -> bool { true }
    fn visit_enter_ptr(_mtbl: uint) -> bool { true }
    fn visit_leave_ptr(_mtbl: uint) -> bool { true }
    fn visit_enter_rptr(_mtbl: uint) -> bool { true }
    fn visit_leave_rptr(_mtbl: uint) -> bool { true }

    fn visit_enter_vec(_mtbl: uint) -> bool { true }
    fn visit_leave_vec(_mtbl: uint) -> bool { true }
    fn visit_enter_evec_box(_mtbl: uint) -> bool { true }
    fn visit_leave_evec_box(_mtbl: uint) -> bool { true }
    fn visit_enter_evec_uniq(_mtbl: uint) -> bool { true }
    fn visit_leave_evec_uniq(_mtbl: uint) -> bool { true }
    fn visit_enter_evec_slice(_mtbl: uint) -> bool { true }
    fn visit_leave_evec_slice(_mtbl: uint) -> bool { true }
    fn visit_enter_evec_fixed(_mtbl: uint, _sz: uint) -> bool { true }
    fn visit_leave_evec_fixed(_mtbl: uint, _sz: uint) -> bool { true }

    fn visit_enter_rec(_n_fields: uint) -> bool { true }
    fn visit_enter_rec_field(_mtbl: uint, _i: uint,
                             _name: str/&) -> bool { true }
    fn visit_leave_rec_field(_mtbl: uint, _i: uint,
                             _name: str/&) -> bool { true }
    fn visit_leave_rec(_n_fields: uint) -> bool { true }

    fn visit_enter_class(_n_fields: uint) -> bool { true }
    fn visit_enter_class_field(_mtbl: uint, _i: uint,
                               _name: str/&) -> bool { true }
    fn visit_leave_class_field(_mtbl: uint, _i: uint,
                               _name: str/&) -> bool { true }
    fn visit_leave_class(_n_fields: uint) -> bool { true }

    fn visit_enter_tup(_n_fields: uint) -> bool { true }
    fn visit_enter_tup_field(_i: uint) -> bool { true }
    fn visit_leave_tup_field(_i: uint) -> bool { true }
    fn visit_leave_tup(_n_fields: uint) -> bool { true }

    fn visit_enter_fn(_purity: uint, _proto: uint,
                      _n_inputs: uint, _retstyle: uint) -> bool { true }
    fn visit_enter_fn_input(_i: uint, _mode: uint) -> bool { true }
    fn visit_leave_fn_input(_i: uint, _mode: uint) -> bool { true }
    fn visit_enter_fn_output(_retstyle: uint) -> bool { true }
    fn visit_leave_fn_output(_retstyle: uint) -> bool { true }
    fn visit_leave_fn(_purity: uint, _proto: uint,
                      _n_inputs: uint, _retstyle: uint) -> bool { true }

    fn visit_enter_enum(_n_variants: uint) -> bool { true }
    fn visit_enter_enum_variant(_variant: uint,
                                _disr_val: int,
                                _n_fields: uint,
                                _name: str/&) -> bool { true }
    fn visit_enter_enum_variant_field(_i: uint) -> bool { true }
    fn visit_leave_enum_variant_field(_i: uint) -> bool { true }
    fn visit_leave_enum_variant(_variant: uint,
                                _disr_val: int,
                                _n_fields: uint,
                                _name: str/&) -> bool { true }
    fn visit_leave_enum(_n_variants: uint) -> bool { true }

    fn visit_iface() -> bool { true }
    fn visit_enter_res() -> bool { true }
    fn visit_leave_res() -> bool { true }
    fn visit_var() -> bool { true }
    fn visit_var_integral() -> bool { true }
    fn visit_param(_i: uint) -> bool { true }
    fn visit_self() -> bool { true }
    fn visit_type() -> bool { true }
    fn visit_opaque_box() -> bool { true }
    fn visit_enter_constr() -> bool { true }
    fn visit_leave_constr() -> bool { true }
    fn visit_closure_ptr(_ck: uint) -> bool { true }
}

fn main() {
    let r = (1,2,3,true,false);
    let p = ptr::addr_of(r) as *c_void;
    let u = my_visitor(@{mut ptr: p,
                         mut vals: []});
    let v = data_visitor({inner: u});
    let vv = v as intrinsic::ty_visitor;
    intrinsic::visit_ty::<(int,int,int,bool,bool)>(vv);

    for u.vals.each {|s|
        io::println(#fmt("val: %s", s));
    }
    assert u.vals == ["1", "2", "3", "true", "false"];

 }
<|endoftext|>


<commit_before><commit_msg>Add test for Item::Verbatim splitting a None group<commit_after>use proc_macro2::{Delimiter, Group};
use quote::quote;

#[test]
fn main() {
    // Okay. Rustc allows top-level `static` with no value syntactically, but
    // not semantically. Syn parses as Item::Verbatim.
    let tokens = quote!(
        pub static FOO: usize;
        pub static BAR: usize;
    );
    let file = syn::parse2::<syn::File>(tokens).unwrap();
    println!("{:#?}", file);

    // Okay.
    let inner = Group::new(
        Delimiter::None,
        quote!(static FOO: usize = 0; pub static BAR: usize = 0),
    );
    let tokens = quote!(pub #inner;);
    let file = syn::parse2::<syn::File>(tokens).unwrap();
    println!("{:#?}", file);

    // Parser crash.
    let inner = Group::new(
        Delimiter::None,
        quote!(static FOO: usize; pub static BAR: usize),
    );
    let tokens = quote!(pub #inner;);
    let file = syn::parse2::<syn::File>(tokens).unwrap();
    println!("{:#?}", file);
}
<|endoftext|>


<commit_before><commit_msg>Add codegen test for issue #73827<commit_after>// This test checks that bounds checks are elided when
// index is part of a (x | y) < C style condition

// min-llvm-version: 11.0.0
// compile-flags: -O

#![crate_type = "lib"]

// CHECK-LABEL: @get
#[no_mangle]
pub fn get(array: &[u8; 8], x: usize, y: usize) -> u8 {
    if x > 7 || y > 7 {
        0
    } else {
        // CHECK-NOT: panic_bounds_check
        array[y]
    }
}
<|endoftext|>


<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.

//! Implementation of running at_exit routines
//!
//! Documentation can be found on the `rt::at_exit` function.

use boxed::FnBox;
use ptr;
use mem;
use sys_common::mutex::Mutex;

type Queue = Vec<Box<dyn FnBox()>>;

// NB these are specifically not types from `std::sync` as they currently rely
// on poisoning and this module needs to operate at a lower level than requiring
// the thread infrastructure to be in place (useful on the borders of
// initialization/destruction).
// `LOCK` is never initialized fully, so this mutex is reentrant!
// Do not use it in a way that might be reentrant, that could lead to
// aliasing `&mut`.
static LOCK: Mutex = Mutex::new();
static mut QUEUE: *mut Queue = ptr::null_mut();

const DONE: *mut Queue = 1_usize as *mut _;

// The maximum number of times the cleanup routines will be run. While running
// the at_exit closures new ones may be registered, and this count is the number
// of times the new closures will be allowed to register successfully. After
// this number of iterations all new registrations will return `false`.
const ITERS: usize = 10;

unsafe fn init() -> bool {
    if QUEUE.is_null() {
        let state: Box<Queue> = box Vec::new();
        QUEUE = Box::into_raw(state);
    } else if QUEUE == DONE {
        // can't re-init after a cleanup
        return false
    }

    true
}

pub fn cleanup() {
    for i in 1..=ITERS {
        unsafe {
            let queue = {
                let _guard = LOCK.lock();
                mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() })
            };

            // make sure we're not recursively cleaning up
            assert!(queue != DONE);

            // If we never called init, not need to cleanup!
            if !queue.is_null() {
                let queue: Box<Queue> = Box::from_raw(queue);
                for to_run in *queue {
                    to_run();
                }
            }
        }
    }
}

pub fn push(f: Box<dyn FnBox()>) -> bool {
    unsafe {
        let _guard = LOCK.lock();
        if init() {
            // This could reentrantly call `push` again, which is a problem because
            // `LOCK` allows reentrancy!
            // FIXME: Add argument why this is okay.
            (*QUEUE).push(f);
            true
        } else {
            false
        }
    }
}
<commit_msg>argue why at_exit_imp is fine<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.

//! Implementation of running at_exit routines
//!
//! Documentation can be found on the `rt::at_exit` function.

use boxed::FnBox;
use ptr;
use mem;
use sys_common::mutex::Mutex;

type Queue = Vec<Box<dyn FnBox()>>;

// NB these are specifically not types from `std::sync` as they currently rely
// on poisoning and this module needs to operate at a lower level than requiring
// the thread infrastructure to be in place (useful on the borders of
// initialization/destruction).
// `LOCK` is never initialized fully, so this mutex is reentrant!
// Do not use it in a way that might be reentrant, that could lead to
// aliasing `&mut`.
static LOCK: Mutex = Mutex::new();
static mut QUEUE: *mut Queue = ptr::null_mut();

const DONE: *mut Queue = 1_usize as *mut _;

// The maximum number of times the cleanup routines will be run. While running
// the at_exit closures new ones may be registered, and this count is the number
// of times the new closures will be allowed to register successfully. After
// this number of iterations all new registrations will return `false`.
const ITERS: usize = 10;

unsafe fn init() -> bool {
    if QUEUE.is_null() {
        let state: Box<Queue> = box Vec::new();
        QUEUE = Box::into_raw(state);
    } else if QUEUE == DONE {
        // can't re-init after a cleanup
        return false
    }

    true
}

pub fn cleanup() {
    for i in 1..=ITERS {
        unsafe {
            let queue = {
                let _guard = LOCK.lock();
                mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() })
            };

            // make sure we're not recursively cleaning up
            assert!(queue != DONE);

            // If we never called init, not need to cleanup!
            if !queue.is_null() {
                let queue: Box<Queue> = Box::from_raw(queue);
                for to_run in *queue {
                    // We are not holding any lock, so reentrancy is fine.
                    to_run();
                }
            }
        }
    }
}

pub fn push(f: Box<dyn FnBox()>) -> bool {
    unsafe {
        let _guard = LOCK.lock();
        if init() {
            // We are just moving `f` around, not calling it.
            // There is no possibility of reentrancy here.
            (*QUEUE).push(f);
            true
        } else {
            false
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Skeleton for problem 2469<commit_after>// https://leetcode.com/problems/convert-the-temperature/
pub fn convert_temperature(celsius: f64) -> Vec<f64> {
    todo!()
}

fn main() {
    println!("{:?}", convert_temperature(36.50)); // [309.65000,97.70000]
    println!("{:?}", convert_temperature(122.11)); // [395.26000,251.79800]
}
<|endoftext|>


<commit_before>// Copyright 2016 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.
#![feature(rustc_attrs)]
// error-pattern:panic 1
// error-pattern:drop 2
use std::io::{self, Write};

struct Droppable(u32);
impl Drop for Droppable {
    fn drop(&mut self) {
        if self.0 == 1 {
            panic!("panic 1");
        } else {
            write!(io::stderr(), "drop {}", self.0);
        }
    }
}

#[rustc_mir]
fn mir() {
    let x = Droppable(2);
    let y = Droppable(1);
}

fn main() {
    mir();
}
<commit_msg>Ignore a test on MSVC<commit_after>// Copyright 2016 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.
#![feature(rustc_attrs)]

// ignore-msvc: FIXME(#30941)
// error-pattern:panic 1
// error-pattern:drop 2
use std::io::{self, Write};

struct Droppable(u32);
impl Drop for Droppable {
    fn drop(&mut self) {
        if self.0 == 1 {
            panic!("panic 1");
        } else {
            write!(io::stderr(), "drop {}", self.0);
        }
    }
}

#[rustc_mir]
fn mir() {
    let x = Droppable(2);
    let y = Droppable(1);
}

fn main() {
    mir();
}
<|endoftext|>


<commit_before><commit_msg>Add test for uninit raw ptrs<commit_after>fn main() {
    let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() };
    //~^ ERROR type validation failed at .value: encountered uninitialized raw pointer
}
<|endoftext|>


<commit_before><commit_msg>Adding a test for checking if test files are missing.<commit_after>use std::fs::{self, DirEntry};
use std::io;
use std::path::Path;

#[test]
fn test_missing_tests() {
    explore_directory(Path::new("./tests")).unwrap();
}

/*
Test for missing files.

Since rs files are alphabetically before stderr/stdout, we can sort by the full name
and iter in that order. If we've seen the file stem for the first time and it's not
a rust file, it means the rust file has to be missing.
*/
fn explore_directory(dir: &Path) -> io::Result<()> {
    let mut current_file = String::new();
    let mut files: Vec<DirEntry> = fs::read_dir(dir)?.filter_map(Result::ok).collect();
    files.sort_by_key(|e| e.path());
    for entry in files.iter() {
        let path = entry.path();
        if path.is_dir() {
            explore_directory(&path)?;
        } else {
            let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
            match path.extension() {
                Some(ext) => {
                    match ext.to_str().unwrap() {
                        "rs" => current_file = file_stem.clone(),
                        "stderr" | "stdout" => {
                            assert_eq!(
                                file_stem,
                                current_file,
                                "{}",
                                format!("Didn't see a test file for {:}", path.to_str().unwrap())
                            );
                        },
                        _ => continue,
                    };
                },
                None => {},
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before><commit_msg>chore: holy dijkstra<commit_after><|endoftext|>


<commit_before>// Copyright 2014 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.

use build::{ScopeAuxiliaryVec, ScopeId};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::mir::repr::*;
use rustc::mir::mir_map::MirMap;
use rustc::mir::transform::MirSource;
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv::FnvHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use std::path::{PathBuf, Path};

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 40;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          disambiguator: &Display,
                          src: MirSource,
                          mir: &Mir<'tcx>,
                          auxiliary: Option<&ScopeAuxiliaryVec>) {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return,
        Some(ref filters) => filters,
    };
    let node_id = src.item_id();
    let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
    let is_matched =
        filters.split("&")
               .any(|filter| {
                   filter == "all" ||
                       pass_name.contains(filter) ||
                       node_path.contains(filter)
               });
    if !is_matched {
        return;
    }

    let promotion_id = match src {
        MirSource::Promoted(_, id) => format!("-{:?}", id),
        _ => String::new()
    };

    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let file_name = format!("rustc.node{}{}.{}.{}.mir",
                            node_id, promotion_id, pass_name, disambiguator);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        try!(writeln!(file, "// MIR for `{}`", node_path));
        try!(writeln!(file, "// node_id = {}", node_id));
        try!(writeln!(file, "// pass_name = {}", pass_name));
        try!(writeln!(file, "// disambiguator = {}", disambiguator));
        try!(writeln!(file, ""));
        try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary));
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                         iter: I,
                                         mir_map: &MirMap<'tcx>,
                                         w: &mut Write)
                                         -> io::Result<()>
    where I: Iterator<Item=DefId>, 'tcx: 'a
{
    let mut first = true;
    for def_id in iter {
        let mir = &mir_map.map[&def_id];

        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let id = tcx.map.as_local_node_id(def_id).unwrap();
        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w, None)?;

        for (i, mir) in mir.promoted.iter_enumerated() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
        }
    }
    Ok(())
}

enum Annotation {
    EnterScope(ScopeId),
    ExitScope(ScopeId),
}

fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>)
                                -> FnvHashMap<Location, Vec<Annotation>>
{
    // compute scope/entry exit annotations
    let mut annotations = FnvHashMap();
    if let Some(auxiliary) = auxiliary {
        for (scope_id, auxiliary) in auxiliary.iter_enumerated() {
            annotations.entry(auxiliary.dom)
                       .or_insert(vec![])
                       .push(Annotation::EnterScope(scope_id));

            for &loc in &auxiliary.postdoms {
                annotations.entry(loc)
                           .or_insert(vec![])
                           .push(Annotation::ExitScope(scope_id));
            }
        }
    }
    return annotations;
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write,
                              auxiliary: Option<&ScopeAuxiliaryVec>)
                              -> io::Result<()> {
    let annotations = scope_entry_exit_annotations(auxiliary);
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        write_basic_block(tcx, block, mir, w, &annotations)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write,
                     annotations: &FnvHashMap<Location, Vec<Annotation>>)
                     -> io::Result<()> {
    let data = &mir[block];

    // Basic block label at the top.
    writeln!(w, "{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        if let Some(ref annotations) = annotations.get(&current_location) {
            for annotation in annotations.iter() {
                match *annotation {
                    Annotation::EnterScope(id) =>
                        writeln!(w, "{0}{0}// Enter Scope({1})",
                                 INDENT, id.index())?,
                    Annotation::ExitScope(id) =>
                        writeln!(w, "{0}{0}// Exit Scope({1})",
                                 INDENT, id.index())?,
                }
            }
        }

        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.source_info))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().source_info))?;

    writeln!(w, "{}}}", INDENT)
}

fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
                    w: &mut Write,
                    parent: VisibilityScope,
                    depth: usize)
                    -> io::Result<()> {
    let indent = depth * INDENT.len();

    let children = match scope_tree.get(&parent) {
        Some(childs) => childs,
        None => return Ok(()),
    };

    for &child in children {
        let data = &mir.visibility_scopes[child];
        assert_eq!(data.parent_scope, Some(parent));
        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;

        // User variable types (including the user's name in a comment).
        for (id, var) in mir.var_decls.iter_enumerated() {
            // Skip if not declared in this scope.
            if var.source_info.scope != child {
                continue;
            }

            let mut_str = if var.mutability == Mutability::Mut {
                "mut "
            } else {
                ""
            };

            let indent = indent + INDENT.len();
            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
                                       INDENT,
                                       indent,
                                       mut_str,
                                       id,
                                       var.ty);
            writeln!(w, "{0:1$} // \"{2}\" in {3}",
                     indented_var,
                     ALIGN,
                     var.name,
                     comment(tcx, var.source_info))?;
        }

        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;

        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    write_mir_sig(tcx, src, mir, w)?;
    writeln!(w, " {{")?;

    // construct a scope tree and write it out
    let mut scope_tree: FnvHashMap<VisibilityScope, Vec<VisibilityScope>> = FnvHashMap();
    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
        if let Some(parent) = scope_data.parent_scope {
            scope_tree.entry(parent)
                      .or_insert(vec![])
                      .push(VisibilityScope::new(index));
        } else {
            // Only the argument scope has no parent, because it's the root.
            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
        }
    }

    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;

    write_mir_decls(mir, w)
}

fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                 -> io::Result<()>
{
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
    }

    write!(w, " {}", tcx.node_path_str(src.item_id()))?;

    if let MirSource::Fn(_) = src {
        write!(w, "(")?;

        // fn argument types.
        for (i, arg) in mir.arg_decls.iter_enumerated() {
            if i.index() != 0 {
                write!(w, ", ")?;
            }
            write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
        }

        write!(w, ") -> {}", mir.return_ty)
    } else {
        assert!(mir.arg_decls.is_empty());
        write!(w, ": {} =", mir.return_ty)
    }
}

fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
    // Compiler-introduced temporary types.
    for (id, temp) in mir.temp_decls.iter_enumerated() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
    }

    // Wrote any declaration? Add an empty line before the first block is printed.
    if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
        writeln!(w, "")?;
    }

    Ok(())
}
<commit_msg>Use question_mark feature in librustc_mir.<commit_after>// Copyright 2014 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.

use build::{ScopeAuxiliaryVec, ScopeId};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::mir::repr::*;
use rustc::mir::mir_map::MirMap;
use rustc::mir::transform::MirSource;
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv::FnvHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use std::path::{PathBuf, Path};

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 40;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          disambiguator: &Display,
                          src: MirSource,
                          mir: &Mir<'tcx>,
                          auxiliary: Option<&ScopeAuxiliaryVec>) {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return,
        Some(ref filters) => filters,
    };
    let node_id = src.item_id();
    let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
    let is_matched =
        filters.split("&")
               .any(|filter| {
                   filter == "all" ||
                       pass_name.contains(filter) ||
                       node_path.contains(filter)
               });
    if !is_matched {
        return;
    }

    let promotion_id = match src {
        MirSource::Promoted(_, id) => format!("-{:?}", id),
        _ => String::new()
    };

    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let file_name = format!("rustc.node{}{}.{}.{}.mir",
                            node_id, promotion_id, pass_name, disambiguator);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR for `{}`", node_path)?;
        writeln!(file, "// node_id = {}", node_id)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "// disambiguator = {}", disambiguator)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, src, mir, &mut file, auxiliary)?;
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                         iter: I,
                                         mir_map: &MirMap<'tcx>,
                                         w: &mut Write)
                                         -> io::Result<()>
    where I: Iterator<Item=DefId>, 'tcx: 'a
{
    let mut first = true;
    for def_id in iter {
        let mir = &mir_map.map[&def_id];

        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let id = tcx.map.as_local_node_id(def_id).unwrap();
        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w, None)?;

        for (i, mir) in mir.promoted.iter_enumerated() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w, None)?;
        }
    }
    Ok(())
}

enum Annotation {
    EnterScope(ScopeId),
    ExitScope(ScopeId),
}

fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>)
                                -> FnvHashMap<Location, Vec<Annotation>>
{
    // compute scope/entry exit annotations
    let mut annotations = FnvHashMap();
    if let Some(auxiliary) = auxiliary {
        for (scope_id, auxiliary) in auxiliary.iter_enumerated() {
            annotations.entry(auxiliary.dom)
                       .or_insert(vec![])
                       .push(Annotation::EnterScope(scope_id));

            for &loc in &auxiliary.postdoms {
                annotations.entry(loc)
                           .or_insert(vec![])
                           .push(Annotation::ExitScope(scope_id));
            }
        }
    }
    return annotations;
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write,
                              auxiliary: Option<&ScopeAuxiliaryVec>)
                              -> io::Result<()> {
    let annotations = scope_entry_exit_annotations(auxiliary);
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        write_basic_block(tcx, block, mir, w, &annotations)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write,
                     annotations: &FnvHashMap<Location, Vec<Annotation>>)
                     -> io::Result<()> {
    let data = &mir[block];

    // Basic block label at the top.
    writeln!(w, "{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        if let Some(ref annotations) = annotations.get(&current_location) {
            for annotation in annotations.iter() {
                match *annotation {
                    Annotation::EnterScope(id) =>
                        writeln!(w, "{0}{0}// Enter Scope({1})",
                                 INDENT, id.index())?,
                    Annotation::ExitScope(id) =>
                        writeln!(w, "{0}{0}// Exit Scope({1})",
                                 INDENT, id.index())?,
                }
            }
        }

        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.source_info))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().source_info))?;

    writeln!(w, "{}}}", INDENT)
}

fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
                    w: &mut Write,
                    parent: VisibilityScope,
                    depth: usize)
                    -> io::Result<()> {
    let indent = depth * INDENT.len();

    let children = match scope_tree.get(&parent) {
        Some(childs) => childs,
        None => return Ok(()),
    };

    for &child in children {
        let data = &mir.visibility_scopes[child];
        assert_eq!(data.parent_scope, Some(parent));
        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;

        // User variable types (including the user's name in a comment).
        for (id, var) in mir.var_decls.iter_enumerated() {
            // Skip if not declared in this scope.
            if var.source_info.scope != child {
                continue;
            }

            let mut_str = if var.mutability == Mutability::Mut {
                "mut "
            } else {
                ""
            };

            let indent = indent + INDENT.len();
            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
                                       INDENT,
                                       indent,
                                       mut_str,
                                       id,
                                       var.ty);
            writeln!(w, "{0:1$} // \"{2}\" in {3}",
                     indented_var,
                     ALIGN,
                     var.name,
                     comment(tcx, var.source_info))?;
        }

        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;

        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    write_mir_sig(tcx, src, mir, w)?;
    writeln!(w, " {{")?;

    // construct a scope tree and write it out
    let mut scope_tree: FnvHashMap<VisibilityScope, Vec<VisibilityScope>> = FnvHashMap();
    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
        if let Some(parent) = scope_data.parent_scope {
            scope_tree.entry(parent)
                      .or_insert(vec![])
                      .push(VisibilityScope::new(index));
        } else {
            // Only the argument scope has no parent, because it's the root.
            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
        }
    }

    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;

    write_mir_decls(mir, w)
}

fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                 -> io::Result<()>
{
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
    }

    write!(w, " {}", tcx.node_path_str(src.item_id()))?;

    if let MirSource::Fn(_) = src {
        write!(w, "(")?;

        // fn argument types.
        for (i, arg) in mir.arg_decls.iter_enumerated() {
            if i.index() != 0 {
                write!(w, ", ")?;
            }
            write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
        }

        write!(w, ") -> {}", mir.return_ty)
    } else {
        assert!(mir.arg_decls.is_empty());
        write!(w, ": {} =", mir.return_ty)
    }
}

fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
    // Compiler-introduced temporary types.
    for (id, temp) in mir.temp_decls.iter_enumerated() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
    }

    // Wrote any declaration? Add an empty line before the first block is printed.
    if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
        writeln!(w, "")?;
    }

    Ok(())
}
<|endoftext|>