<commit_before>//! The middleware implementation with JSON Web Token support.
//!

use std::collections::HashMap;
use std::str::from_utf8;
use std::sync::Arc;
use std::vec::Vec;

use futures::future::{lazy, Future};
use futures::Stream;
use json::{object, parse as parse_json};
use lapin_futures_rustls::lapin::channel::{
    BasicConsumeOptions, BasicProperties, BasicPublishOptions, QueueBindOptions,
    QueueDeclareOptions, QueueDeleteOptions, QueueUnbindOptions,
};
use lapin_futures_rustls::lapin::types::{AMQPValue, FieldTable};
use log::error;
use uuid::Uuid;

use crate::error::PathfinderError;
use crate::engine::{RESPONSE_EXCHANGE};
use crate::engine::middleware::{
    TOKEN_VERIFY_ROUTING_KEY,
    TOKEN_VERIFY_EXCHANGE,
    TOKEN_USER_PROFILE_ROUTING_KEY,
    TOKEN_USER_PROFILE_EXCHANGE
};
use crate::engine::middleware::base::{Middleware, MiddlewareFuture, CustomUserHeaders};
use crate::engine::middleware::utils::get_permissions;
use crate::engine::options::RpcOptions;
use crate::engine::serializer::JsonMessage;
use crate::rabbitmq::RabbitMQContext;

/// A middleware class, that will check a JSON Web Token in WebSocket message.
/// If token wasn't specified or it's invalid returns a `PathfinderError` object.
pub struct JwtTokenMiddleware;

impl JwtTokenMiddleware {
    /// Returns a new instance of `JwtTokenMiddleware` structure.
    pub fn new() -> JwtTokenMiddleware {
        JwtTokenMiddleware {}
    }

    /// Performs a request to Auth/Auth microservice with the taken token
    /// that must be verified before doing any actions later.
    fn verify_token(&self, message: JsonMessage, token: String, rabbitmq_context: Arc<RabbitMQContext>)
        -> impl Future<Item=(), Error=PathfinderError> + Sync + Send + 'static
    {
        let access_token = token.clone();
        let rabbitmq_context_local = rabbitmq_context.clone();
        let options = Arc::new(RpcOptions::default()
            .with_message(message.clone())
            .with_queue_name(Arc::new(format!("{}", Uuid::new_v4())))
        );

        // 1. Create a channel
        rabbitmq_context_local.get_channel()
        // 2. Declare a response queue
        .and_then(move |channel| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let queue_declare_options = QueueDeclareOptions {
                passive: false,
                durable: true,
                exclusive: true,
                auto_delete: false,
                ..Default::default()
            };

            channel
                .queue_declare(&queue_name, queue_declare_options, FieldTable::new())
                .map(move |queue| (channel, queue, options))
        })
        // 3. Link the response queue the exchange
        .and_then(move |(channel, queue, options)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_bind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueBindOptions::default(),
                    FieldTable::new()
                )
                .map(move |_| (channel, queue, options))
        })
        // 4. Publish message into the microservice queue and make ensure that it's delivered
        .and_then(move |(channel, queue, options)| {
            let publish_message_options = BasicPublishOptions {
                mandatory: true,
                immediate: false,
                ..Default::default()
            };

            let request_headers: Vec<(String, String)> = vec![
                (String::from("routing_key"), String::from("auth.token.verify")),
                (String::from("request_url"), String::from("/auth/api/token/verify")),
            ];
            let mut message_headers = FieldTable::new();
            for &(ref key, ref value) in request_headers.iter() {
                let header_name = key.to_string();
                let header_value = AMQPValue::LongString(value.to_string());
                message_headers.insert(header_name, header_value);
            }

            let message = options.get_message().unwrap().clone();
            let queue_name_response = options.get_queue_name().unwrap().clone();
            let event_name = message["event-name"].as_str().unwrap_or("null");
            let request_body = object!{ "access_token" => access_token };
            let basic_properties = BasicProperties::default()
                .with_content_type("application/json".to_string())    // Content type
                .with_headers(message_headers)                        // Headers for the message
                .with_delivery_mode(2)                                // Message must be persistent
                .with_reply_to(queue_name_response.to_string())       // Response queue
                .with_correlation_id(event_name.clone().to_string()); // Event name

            channel
                .basic_publish(
                    TOKEN_VERIFY_EXCHANGE.clone(),
                    TOKEN_VERIFY_ROUTING_KEY.clone(),
                    request_body.dump().as_bytes().to_vec(),
                    publish_message_options,
                    basic_properties
                )
                .map(move |_confirmation| (channel, queue, options))
        })
        // 5. Consume a response message from the queue, that was declared on the 2nd step
        .and_then(move |(channel, queue, options)| {
            channel
                .basic_consume(
                    &queue,
                    "response_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::new()
                )
                .and_then(move |stream| {
                    stream
                        .take(1)
                        .into_future()
                        .map_err(|(err, _)| err)
                        .map(move |(message, _)| (channel, queue, message.unwrap(), options))
                })
        })
        // 6. Prepare a response for a client, serialize and pass to the next processing stage
        .and_then(move |(channel, queue, message, options)| {
            let raw_data = from_utf8(&message.data).unwrap();
            let json = parse_json(raw_data).unwrap();

            channel
                .basic_ack(message.delivery_tag, false)
                .map(move |_confirmation| (channel, queue, options, json))
        })
        // 7. Unbind the response queue from the exchange point
        .and_then(move |(channel, _queue, options, json)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_unbind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueUnbindOptions::default(),
                    FieldTable::new(),
                )
                .map(move |_| (channel, options, json))
        })
        // 8. Delete the response queue
        .and_then(move |(channel, options, json)| {
            let queue_delete_options = QueueDeleteOptions {
                if_unused: false,
                if_empty: false,
                ..Default::default()
            };
            let queue_name = options.get_queue_name().unwrap().clone();

            channel
                .queue_delete(&queue_name, queue_delete_options)
                .map(move |_| (channel, json))
        })
        // 9. Close the channel
        .and_then(move |(channel, json)| {
            channel.close(200, "Close the channel.").map(|_| json)
        })
        // 10. Prepare the response for the client.
        .then(move |result| match result {
            Ok(json) => {
                let has_errors = !json["error"].is_null();
                if has_errors {
                    let errors = json["error"].clone();
                    return Err(PathfinderError::MicroserviceError(errors))
                };

                let is_valid_response = !json["content"].is_null();
                let is_valid_token = json["content"]["is_valid"].as_bool().unwrap();
                match is_valid_response && is_valid_token {
                    true => Ok(()),
                    false => {
                        let message = String::from("Token is invalid.");
                        Err(PathfinderError::AuthenticationError(message))
                    }
                }
            },
            Err(err) => {
                error!("Error in RabbitMQ client. Reason: {}", err);
                let message = String::from("The request wasn't processed. Please, try once again.");
                Err(PathfinderError::MessageBrokerError(message))
            }
        })
    }

    /// Performs a request to Auth/Auth microservice with the taken token
    /// that will be used for getting a list of permissions to other resources.
    fn get_headers(&self, message: JsonMessage, token: String, rabbitmq_context: Arc<RabbitMQContext>)
        -> impl Future<Item=CustomUserHeaders, Error=PathfinderError> + Sync + Send + 'static
    {
        let access_token = token.clone();
        let rabbitmq_context_local = rabbitmq_context.clone();
        let options = Arc::new(RpcOptions::default()
            .with_message(message.clone())
            .with_queue_name(Arc::new(format!("{}", Uuid::new_v4())))
        );

        // 1. Create a channel
        rabbitmq_context_local.get_channel()
        // 2. Declare a response queue
        .and_then(move |channel| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let queue_declare_options = QueueDeclareOptions {
                passive: false,
                durable: true,
                exclusive: true,
                auto_delete: false,
                ..Default::default()
            };

            channel
                .queue_declare(&queue_name, queue_declare_options, FieldTable::new())
                .map(move |queue| (channel, queue, options))
        })
        // 3. Link the response queue the exchange
        .and_then(move |(channel, queue, options)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_bind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueBindOptions::default(),
                    FieldTable::new()
                )
                .map(move |_| (channel, queue, options))
        })
        // 4. Publish message into the microservice queue and make ensure that it's delivered
        .and_then(move |(channel, queue, options)| {
            let publish_message_options = BasicPublishOptions {
                mandatory: true,
                immediate: false,
                ..Default::default()
            };

            let request_headers: Vec<(String, String)> = vec![
                (String::from("microservice_name"), String::from("microservice-auth")),
                (String::from("request_url"), String::from("/auth/api/users/profile")),
            ];
            let mut message_headers = FieldTable::new();
            for &(ref key, ref value) in request_headers.iter() {
                let header_name = key.to_string();
                let header_value = AMQPValue::LongString(value.to_string());
                message_headers.insert(header_name, header_value);
            }

            let message = options.get_message().unwrap().clone();
            let queue_name_response = options.get_queue_name().unwrap().clone();
            let event_name = message["event-name"].as_str().unwrap_or("null");
            let request_body = object!{ "access_token" => access_token };
            let basic_properties = BasicProperties::default()
                .with_content_type("application/json".to_string())    // Content type
                .with_headers(message_headers)                        // Headers for the message
                .with_delivery_mode(2)                                // Message must be persistent
                .with_reply_to(queue_name_response.to_string())       // Response queue
                .with_correlation_id(event_name.clone().to_string()); // Event name

            channel
                .basic_publish(
                    TOKEN_USER_PROFILE_EXCHANGE.clone(),
                    TOKEN_USER_PROFILE_ROUTING_KEY.clone(),
                    request_body.dump().as_bytes().to_vec(),
                    publish_message_options,
                    basic_properties
                )
                .map(move |_confirmation| (channel, queue, options))
        })
        // 5. Consume a response message from the queue, that was declared on the 2nd step
        .and_then(move |(channel, queue, options)| {
            channel
                .basic_consume(
                    &queue,
                    "response_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::new()
                )
                .and_then(move |stream| {
                    stream
                        .take(1)
                        .into_future()
                        .map_err(|(err, _)| err)
                        .map(move |(message, _)| (channel, queue, message.unwrap(), options))
                })
        })
        // 6. Prepare a response for a client, serialize and pass to the next processing stage
        .and_then(move |(channel, queue, message, options)| {
            let raw_data = from_utf8(&message.data).unwrap();
            let json = parse_json(raw_data).unwrap();

            channel
                .basic_ack(message.delivery_tag, false)
                .map(move |_confirmation| (channel, queue, options, json))
        })
        // 7. Unbind the response queue from the exchange point
        .and_then(move |(channel, _queue, options, json)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_unbind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueUnbindOptions::default(),
                    FieldTable::new(),
                )
                .map(move |_| (channel, options, json))
        })
        // 8. Delete the response queue
        .and_then(move |(channel, options, json)| {
            let queue_delete_options = QueueDeleteOptions {
                if_unused: false,
                if_empty: false,
                ..Default::default()
            };
            let queue_name = options.get_queue_name().unwrap().clone();

            channel
                .queue_delete(&queue_name, queue_delete_options)
                .map(move |_| (channel, json))
        })
        // 9. Close the channel
        .and_then(move |(channel, json)| {
            channel.close(200, "Close the channel.").map(|_| json)
        })
        // 10. Prepare the response for the client.
        .then(move |result| match result {
            Ok(json) => {
                let has_errors = !json["error"].is_null();
                if has_errors {
                    let errors = json["error"].clone();
                    return Err(PathfinderError::MicroserviceError(errors))
                };

                let is_valid_response = !json["content"].is_null();
                match is_valid_response {
                    true => {
                        let mut extra_headers: CustomUserHeaders = HashMap::new();
                        extra_headers.insert(String::from("permissions"), get_permissions(&json));
                        Ok(extra_headers)
                    },
                    false => Ok(HashMap::new())
                }
            },
            Err(err) => {
                error!("Error in RabbitMQ client. Reason: {}", err);
                let message = String::from("The request wasn't processed. Please, try once again.");
                Err(PathfinderError::MessageBrokerError(message))
            }
        })
    }
}

impl Middleware for JwtTokenMiddleware {
    fn process_request(&self, message: JsonMessage, rabbitmq_context: Arc<RabbitMQContext>) -> MiddlewareFuture {
        // Extract a token from a JSON object
        let token = match message["token"].as_str() {
            Some(token) => String::from(token),
            _ => {
                return Box::new(lazy(move || {
                    let message = String::from("The `token` field must be specified.");
                    Err(PathfinderError::AuthenticationError(message))
                }))
            }
        };

        // Verify the passed JSON Web Token and extract permissions
        let verify_token_future = self.verify_token(message.clone(),token.clone(), rabbitmq_context.clone());
        let get_headers_future = self.get_headers(message.clone(),token.clone(), rabbitmq_context.clone());
        Box::new(verify_token_future.and_then(move |_| get_headers_future))
    }
}
<commit_msg>Refactores futures used by JWT middleware<commit_after>//! The middleware implementation with JSON Web Token support.
//!

use std::collections::HashMap;
use std::str::from_utf8;
use std::sync::Arc;
use std::vec::Vec;

use futures::future::{lazy, Future};
use futures::Stream;
use json::{object, parse as parse_json};
use lapin_futures_rustls::lapin::channel::{
    BasicConsumeOptions, BasicProperties, BasicPublishOptions, QueueBindOptions,
    QueueDeclareOptions, QueueDeleteOptions, QueueUnbindOptions,
};
use lapin_futures_rustls::lapin::types::{AMQPValue, FieldTable};
use log::error;
use uuid::Uuid;

use crate::error::PathfinderError;
use crate::engine::{RESPONSE_EXCHANGE};
use crate::engine::middleware::{
    TOKEN_VERIFY_ROUTING_KEY,
    TOKEN_VERIFY_EXCHANGE,
    TOKEN_USER_PROFILE_ROUTING_KEY,
    TOKEN_USER_PROFILE_EXCHANGE
};
use crate::engine::middleware::base::{Middleware, MiddlewareFuture, CustomUserHeaders};
use crate::engine::middleware::utils::get_permissions;
use crate::engine::options::RpcOptions;
use crate::engine::serializer::JsonMessage;
use crate::rabbitmq::RabbitMQContext;

/// A middleware class, that will check a JSON Web Token in WebSocket message.
/// If token wasn't specified or it's invalid returns a `PathfinderError` object.
pub struct JwtTokenMiddleware;

impl JwtTokenMiddleware {
    /// Returns a new instance of `JwtTokenMiddleware` structure.
    pub fn new() -> JwtTokenMiddleware {
        JwtTokenMiddleware {}
    }

    /// Performs a request to Auth/Auth microservice with the taken token
    /// that must be verified before doing any actions later.
    fn verify_token(&self, message: JsonMessage, token: String, rabbitmq_context: Arc<RabbitMQContext>)
        -> impl Future<Item=(), Error=PathfinderError> + Sync + Send + 'static
    {
        let access_token = token.clone();
        let options = Arc::new(RpcOptions::default()
            .with_message(message.clone())
            .with_queue_name(Arc::new(format!("{}", Uuid::new_v4())))
        );
        let rabbitmq_context_local = rabbitmq_context.clone();
        let publish_channel = rabbitmq_context_local.publish_channel.clone();
        let consume_channel = rabbitmq_context_local.consume_channel.clone();

        let queue_name = options.get_queue_name().unwrap().clone();
        let queue_declare_options = QueueDeclareOptions {
            passive: false,
            durable: true,
            exclusive: true,
            auto_delete: false,
            ..Default::default()
        };

        // 1. Declare a response queue
        consume_channel
            .queue_declare(&queue_name, queue_declare_options, FieldTable::new())
            .map(move |queue| (publish_channel, consume_channel, queue, options))
        // 2. Link the response queue the exchange
        .and_then(move |(publish_channel, consume_channel, queue, options)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            consume_channel
                .queue_bind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueBindOptions::default(),
                    FieldTable::new()
                )
                .map(move |_| (publish_channel, consume_channel, queue, options))
        })
        // 3. Publish message into the microservice queue and make ensure that it's delivered
        .and_then(move |(publish_channel, consume_channel, queue, options)| {
            let publish_message_options = BasicPublishOptions {
                mandatory: true,
                immediate: false,
                ..Default::default()
            };

            let request_headers: Vec<(String, String)> = vec![
                (String::from("routing_key"), String::from("auth.token.verify")),
                (String::from("request_url"), String::from("/auth/api/token/verify")),
            ];
            let mut message_headers = FieldTable::new();
            for &(ref key, ref value) in request_headers.iter() {
                let header_name = key.to_string();
                let header_value = AMQPValue::LongString(value.to_string());
                message_headers.insert(header_name, header_value);
            }

            let message = options.get_message().unwrap().clone();
            let queue_name_response = options.get_queue_name().unwrap().clone();
            let event_name = message["event-name"].as_str().unwrap_or("null");
            let request_body = object!{ "access_token" => access_token };
            let basic_properties = BasicProperties::default()
                .with_content_type("application/json".to_string())    // Content type
                .with_headers(message_headers)                        // Headers for the message
                .with_delivery_mode(2)                                // Message must be persistent
                .with_reply_to(queue_name_response.to_string())       // Response queue
                .with_correlation_id(event_name.clone().to_string()); // Event name

            publish_channel
                .basic_publish(
                    TOKEN_VERIFY_EXCHANGE.clone(),
                    TOKEN_VERIFY_ROUTING_KEY.clone(),
                    request_body.dump().as_bytes().to_vec(),
                    publish_message_options,
                    basic_properties
                )
                .map(move |_confirmation| (publish_channel, consume_channel, queue, options))
        })
        // 4. Consume a response message from the queue, that was declared on the 2nd step
        .and_then(move |(publish_channel, consume_channel, queue, options)| {
            consume_channel
                .basic_consume(
                    &queue,
                    "response_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::new()
                )
                .and_then(move |stream| {
                    stream
                        .take(1)
                        .into_future()
                        .map_err(|(err, _)| err)
                        .map(move |(message, _)| (publish_channel, consume_channel, queue, message.unwrap(), options))
                })
        })
        // 5. Prepare a response for a client, serialize and pass to the next processing stage
        .and_then(move |(publish_channel, consume_channel, queue, message, options)| {
            let raw_data = from_utf8(&message.data).unwrap();
            let json = parse_json(raw_data).unwrap();

            consume_channel
                .basic_ack(message.delivery_tag, false)
                .map(move |_confirmation| (publish_channel, consume_channel, queue, options, json))
        })
        // 6. Unbind the response queue from the exchange point
        .and_then(move |(publish_channel, consume_channel, _queue, options, json)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            consume_channel
                .queue_unbind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueUnbindOptions::default(),
                    FieldTable::new(),
                )
                .map(move |_| (publish_channel, consume_channel, options, json))
        })
        // 7. Delete the response queue
        .and_then(move |(publish_channel, consume_channel, options, json)| {
            let queue_delete_options = QueueDeleteOptions {
                if_unused: false,
                if_empty: false,
                ..Default::default()
            };
            let queue_name = options.get_queue_name().unwrap().clone();

            consume_channel
                .queue_delete(&queue_name, queue_delete_options)
                .map(move |_| json)
        })
        // 8. Prepare the response for the client
        .then(move |result| match result {
            Ok(json) => {
                let has_errors = !json["error"].is_null();
                if has_errors {
                    let errors = json["error"].clone();
                    return Err(PathfinderError::MicroserviceError(errors))
                };

                let is_valid_response = !json["content"].is_null();
                let is_valid_token = json["content"]["is_valid"].as_bool().unwrap();
                match is_valid_response && is_valid_token {
                    true => Ok(()),
                    false => {
                        let message = String::from("Token is invalid.");
                        Err(PathfinderError::AuthenticationError(message))
                    }
                }
            },
            Err(err) => {
                error!("Error in RabbitMQ client. Reason: {}", err);
                let message = String::from("The request wasn't processed. Please, try once again.");
                Err(PathfinderError::MessageBrokerError(message))
            }
        })
    }

    /// Performs a request to Auth/Auth microservice with the taken token
    /// that will be used for getting a list of permissions to other resources.
    fn get_headers(&self, message: JsonMessage, token: String, rabbitmq_context: Arc<RabbitMQContext>)
        -> impl Future<Item=CustomUserHeaders, Error=PathfinderError> + Sync + Send + 'static
    {
        let access_token = token.clone();
        let options = Arc::new(RpcOptions::default()
            .with_message(message.clone())
            .with_queue_name(Arc::new(format!("{}", Uuid::new_v4())))
        );
        let rabbitmq_context_local = rabbitmq_context.clone();
        let publish_channel = rabbitmq_context_local.publish_channel.clone();
        let consume_channel = rabbitmq_context_local.consume_channel.clone();

        let queue_name = options.get_queue_name().unwrap().clone();
        let queue_declare_options = QueueDeclareOptions {
            passive: false,
            durable: true,
            exclusive: true,
            auto_delete: false,
            ..Default::default()
        };

        // 1. Declare a response queue
        consume_channel
            .queue_declare(&queue_name, queue_declare_options, FieldTable::new())
            .map(move |queue| (publish_channel, consume_channel, queue, options))
        // 2. Link the response queue the exchange
        .and_then(move |(publish_channel, consume_channel, queue, options)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            consume_channel
                .queue_bind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueBindOptions::default(),
                    FieldTable::new()
                )
                .map(move |_| (publish_channel, consume_channel, queue, options))
        })
        // 3. Publish message into the microservice queue and make ensure that it's delivered
        .and_then(move |(publish_channel, consume_channel, queue, options)| {
            let publish_message_options = BasicPublishOptions {
                mandatory: true,
                immediate: false,
                ..Default::default()
            };

            let request_headers: Vec<(String, String)> = vec![
                (String::from("microservice_name"), String::from("microservice-auth")),
                (String::from("request_url"), String::from("/auth/api/users/profile")),
            ];
            let mut message_headers = FieldTable::new();
            for &(ref key, ref value) in request_headers.iter() {
                let header_name = key.to_string();
                let header_value = AMQPValue::LongString(value.to_string());
                message_headers.insert(header_name, header_value);
            }

            let message = options.get_message().unwrap().clone();
            let queue_name_response = options.get_queue_name().unwrap().clone();
            let event_name = message["event-name"].as_str().unwrap_or("null");
            let request_body = object!{ "access_token" => access_token };
            let basic_properties = BasicProperties::default()
                .with_content_type("application/json".to_string())    // Content type
                .with_headers(message_headers)                        // Headers for the message
                .with_delivery_mode(2)                                // Message must be persistent
                .with_reply_to(queue_name_response.to_string())       // Response queue
                .with_correlation_id(event_name.clone().to_string()); // Event name

            publish_channel
                .basic_publish(
                    TOKEN_USER_PROFILE_EXCHANGE.clone(),
                    TOKEN_USER_PROFILE_ROUTING_KEY.clone(),
                    request_body.dump().as_bytes().to_vec(),
                    publish_message_options,
                    basic_properties
                )
                .map(move |_confirmation| (publish_channel, consume_channel, queue, options))
        })
        // 4. Consume a response message from the queue, that was declared on the 2nd step
        .and_then(move |(publish_channel, consume_channel, queue, options)| {
            consume_channel
                .basic_consume(
                    &queue,
                    "response_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::new()
                )
                .and_then(move |stream| {
                    stream
                        .take(1)
                        .into_future()
                        .map_err(|(err, _)| err)
                        .map(move |(message, _)| (publish_channel, consume_channel, queue, message.unwrap(), options))
                })
        })
        // 5. Prepare a response for a client, serialize and pass to the next processing stage
        .and_then(move |(publish_channel, consume_channel, queue, message, options)| {
            let raw_data = from_utf8(&message.data).unwrap();
            let json = parse_json(raw_data).unwrap();

            consume_channel
                .basic_ack(message.delivery_tag, false)
                .map(move |_confirmation| (publish_channel, consume_channel, queue, options, json))
        })
        // 6. Unbind the response queue from the exchange point
        .and_then(move |(publish_channel, consume_channel, _queue, options, json)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            consume_channel
                .queue_unbind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueUnbindOptions::default(),
                    FieldTable::new(),
                )
                .map(move |_| (publish_channel, consume_channel, options, json))
        })
        // 7. Delete the response queue
        .and_then(move |(publish_channel, consume_channel, options, json)| {
            let queue_delete_options = QueueDeleteOptions {
                if_unused: false,
                if_empty: false,
                ..Default::default()
            };
            let queue_name = options.get_queue_name().unwrap().clone();

            consume_channel
                .queue_delete(&queue_name, queue_delete_options)
                .map(move |_| json)
        })
        // 8. Prepare the response for the client
        .then(move |result| match result {
            Ok(json) => {
                let has_errors = !json["error"].is_null();
                if has_errors {
                    let errors = json["error"].clone();
                    return Err(PathfinderError::MicroserviceError(errors))
                };

                let is_valid_response = !json["content"].is_null();
                match is_valid_response {
                    true => {
                        let mut extra_headers: CustomUserHeaders = HashMap::new();
                        extra_headers.insert(String::from("permissions"), get_permissions(&json));
                        Ok(extra_headers)
                    },
                    false => Ok(HashMap::new())
                }
            },
            Err(err) => {
                error!("Error in RabbitMQ client. Reason: {}", err);
                let message = String::from("The request wasn't processed. Please, try once again.");
                Err(PathfinderError::MessageBrokerError(message))
            }
        })
    }
}

impl Middleware for JwtTokenMiddleware {
    fn process_request(&self, message: JsonMessage, rabbitmq_context: Arc<RabbitMQContext>) -> MiddlewareFuture {
        // Extract a token from a JSON object
        let token = match message["token"].as_str() {
            Some(token) => String::from(token),
            _ => {
                return Box::new(lazy(move || {
                    let message = String::from("The `token` field must be specified.");
                    Err(PathfinderError::AuthenticationError(message))
                }))
            }
        };

        // Verify the passed JSON Web Token and extract permissions
        let verify_token_future = self.verify_token(message.clone(),token.clone(), rabbitmq_context.clone());
        let get_headers_future = self.get_headers(message.clone(),token.clone(), rabbitmq_context.clone());
        Box::new(verify_token_future.and_then(move |_| get_headers_future))
    }
}
<|endoftext|>


<commit_before>use std::{io, mem, ptr, slice};

use bytes::{BufMut, BytesMut};
use http::Version;

use crate::extensions::Extensions;

const DEC_DIGITS_LUT: &[u8] = b"0001020304050607080910111213141516171819\
      2021222324252627282930313233343536373839\
      4041424344454647484950515253545556575859\
      6061626364656667686970717273747576777879\
      8081828384858687888990919293949596979899";

pub(crate) const STATUS_LINE_BUF_SIZE: usize = 13;

pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) {
    let mut buf: [u8; STATUS_LINE_BUF_SIZE] = [
        b'H', b'T', b'T', b'P', b'/', b'1', b'.', b'1', b' ', b' ', b' ', b' ', b' ',
    ];
    match version {
        Version::HTTP_2 => buf[5] = b'2',
        Version::HTTP_10 => buf[7] = b'0',
        Version::HTTP_09 => {
            buf[5] = b'0';
            buf[7] = b'9';
        }
        _ => (),
    }

    let mut curr: isize = 12;
    let buf_ptr = buf.as_mut_ptr();
    let lut_ptr = DEC_DIGITS_LUT.as_ptr();
    let four = n > 999;

    // decode 2 more chars, if > 2 chars
    let d1 = (n % 100) << 1;
    n /= 100;
    curr -= 2;
    unsafe {
        ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(curr), 2);
    }

    // decode last 1 or 2 chars
    if n < 10 {
        curr -= 1;
        unsafe {
            *buf_ptr.offset(curr) = (n as u8) + b'0';
        }
    } else {
        let d1 = n << 1;
        curr -= 2;
        unsafe {
            ptr::copy_nonoverlapping(
                lut_ptr.offset(d1 as isize),
                buf_ptr.offset(curr),
                2,
            );
        }
    }

    bytes.put_slice(&buf);
    if four {
        bytes.put_u8(b' ');
    }
}

/// NOTE: bytes object has to contain enough space
pub fn write_content_length(mut n: usize, bytes: &mut BytesMut) {
    if n < 10 {
        let mut buf: [u8; 21] = [
            b'\r', b'\n', b'c', b'o', b'n', b't', b'e', b'n', b't', b'-', b'l', b'e',
            b'n', b'g', b't', b'h', b':', b' ', b'0', b'\r', b'\n',
        ];
        buf[18] = (n as u8) + b'0';
        bytes.put_slice(&buf);
    } else if n < 100 {
        let mut buf: [u8; 22] = [
            b'\r', b'\n', b'c', b'o', b'n', b't', b'e', b'n', b't', b'-', b'l', b'e',
            b'n', b'g', b't', b'h', b':', b' ', b'0', b'0', b'\r', b'\n',
        ];
        let d1 = n << 1;
        unsafe {
            ptr::copy_nonoverlapping(
                DEC_DIGITS_LUT.as_ptr().add(d1),
                buf.as_mut_ptr().offset(18),
                2,
            );
        }
        bytes.put_slice(&buf);
    } else if n < 1000 {
        let mut buf: [u8; 23] = [
            b'\r', b'\n', b'c', b'o', b'n', b't', b'e', b'n', b't', b'-', b'l', b'e',
            b'n', b'g', b't', b'h', b':', b' ', b'0', b'0', b'0', b'\r', b'\n',
        ];
        // decode 2 more chars, if > 2 chars
        let d1 = (n % 100) << 1;
        n /= 100;
        unsafe {
            ptr::copy_nonoverlapping(
                DEC_DIGITS_LUT.as_ptr().add(d1),
                buf.as_mut_ptr().offset(19),
                2,
            )
        };

        // decode last 1
        buf[18] = (n as u8) + b'0';

        bytes.put_slice(&buf);
    } else {
        bytes.put_slice(b"\r\ncontent-length: ");
        convert_usize(n, bytes);
    }
}

pub(crate) fn convert_usize(mut n: usize, bytes: &mut BytesMut) {
    let mut curr: isize = 39;
    let mut buf: [u8; 41] = unsafe { mem::MaybeUninit::uninit().assume_init() };
    buf[39] = b'\r';
    buf[40] = b'\n';
    let buf_ptr = buf.as_mut_ptr();
    let lut_ptr = DEC_DIGITS_LUT.as_ptr();

    // eagerly decode 4 characters at a time
    while n >= 10_000 {
        let rem = (n % 10_000) as isize;
        n /= 10_000;

        let d1 = (rem / 100) << 1;
        let d2 = (rem % 100) << 1;
        curr -= 4;
        unsafe {
            ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
            ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
        }
    }

    // if we reach here numbers are <= 9999, so at most 4 chars long
    let mut n = n as isize; // possibly reduce 64bit math

    // decode 2 more chars, if > 2 chars
    if n >= 100 {
        let d1 = (n % 100) << 1;
        n /= 100;
        curr -= 2;
        unsafe {
            ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
        }
    }

    // decode last 1 or 2 chars
    if n < 10 {
        curr -= 1;
        unsafe {
            *buf_ptr.offset(curr) = (n as u8) + b'0';
        }
    } else {
        let d1 = n << 1;
        curr -= 2;
        unsafe {
            ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
        }
    }

    unsafe {
        bytes.extend_from_slice(slice::from_raw_parts(
            buf_ptr.offset(curr),
            41 - curr as usize,
        ));
    }
}

pub(crate) struct Writer<'a>(pub &'a mut BytesMut);

impl<'a> io::Write for Writer<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.extend_from_slice(buf);
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

pub(crate) trait DataFactory {
    fn set(&self, ext: &mut Extensions);
}

pub(crate) struct Data<T>(pub(crate) T);

impl<T: Clone + 'static> DataFactory for Data<T> {
    fn set(&self, ext: &mut Extensions) {
        ext.insert(self.0.clone())
    }
}

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

    #[test]
    fn test_write_content_length() {
        let mut bytes = BytesMut::new();
        bytes.reserve(50);
        write_content_length(0, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 0\r\n"[..]);
        bytes.reserve(50);
        write_content_length(9, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 9\r\n"[..]);
        bytes.reserve(50);
        write_content_length(10, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 10\r\n"[..]);
        bytes.reserve(50);
        write_content_length(99, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 99\r\n"[..]);
        bytes.reserve(50);
        write_content_length(100, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 100\r\n"[..]);
        bytes.reserve(50);
        write_content_length(101, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 101\r\n"[..]);
        bytes.reserve(50);
        write_content_length(998, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 998\r\n"[..]);
        bytes.reserve(50);
        write_content_length(1000, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1000\r\n"[..]);
        bytes.reserve(50);
        write_content_length(1001, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1001\r\n"[..]);
        bytes.reserve(50);
        write_content_length(5909, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 5909\r\n"[..]);
    }
}
<commit_msg>replace unsafe content length implementation<commit_after>use std::{io, ptr, slice};

use bytes::{BufMut, BytesMut};
use http::Version;

use crate::extensions::Extensions;

const DEC_DIGITS_LUT: &[u8] = b"0001020304050607080910111213141516171819\
      2021222324252627282930313233343536373839\
      4041424344454647484950515253545556575859\
      6061626364656667686970717273747576777879\
      8081828384858687888990919293949596979899";

pub(crate) const STATUS_LINE_BUF_SIZE: usize = 13;

pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) {
    let mut buf: [u8; STATUS_LINE_BUF_SIZE] = *b"HTTP/1.1     ";
    match version {
        Version::HTTP_2 => buf[5] = b'2',
        Version::HTTP_10 => buf[7] = b'0',
        Version::HTTP_09 => {
            buf[5] = b'0';
            buf[7] = b'9';
        }
        _ => (),
    }

    let mut curr: isize = 12;
    let buf_ptr = buf.as_mut_ptr();
    let lut_ptr = DEC_DIGITS_LUT.as_ptr();
    let four = n > 999;

    // decode 2 more chars, if > 2 chars
    let d1 = (n % 100) << 1;
    n /= 100;
    curr -= 2;
    unsafe {
        ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(curr), 2);
    }

    // decode last 1 or 2 chars
    if n < 10 {
        curr -= 1;
        unsafe {
            *buf_ptr.offset(curr) = (n as u8) + b'0';
        }
    } else {
        let d1 = n << 1;
        curr -= 2;
        unsafe {
            ptr::copy_nonoverlapping(
                lut_ptr.offset(d1 as isize),
                buf_ptr.offset(curr),
                2,
            );
        }
    }

    bytes.put_slice(&buf);
    if four {
        bytes.put_u8(b' ');
    }
}

const DIGITS_START: u8 = b'0';

/// NOTE: bytes object has to contain enough space
pub fn write_content_length(n: usize, bytes: &mut BytesMut) {
    bytes.put_slice(b"\r\ncontent-length: ");

    if n < 10 {
        bytes.put_u8(DIGITS_START + (n as u8));
    } else if n < 100 {
        let n = n as u8;

        let d10 = n / 10;
        let d1 = n % 10;

        bytes.put_u8(DIGITS_START + d10);
        bytes.put_u8(DIGITS_START + d1);
    } else if n < 1000 {
        let n = n as u16;

        let d100 = (n / 100) as u8;
        let d10 = ((n / 10) % 10) as u8;
        let d1 = (n % 10) as u8;

        bytes.put_u8(DIGITS_START + d100);
        bytes.put_u8(DIGITS_START + d10);
        bytes.put_u8(DIGITS_START + d1);
    } else if n < 10000 {
        let n = n as u16;

        let d1000 = (n / 1000) as u8;
        let d100 = ((n / 100) % 10) as u8;
        let d10 = ((n / 10) % 10) as u8;
        let d1 = (n % 10) as u8;

        bytes.put_u8(DIGITS_START + d1000);
        bytes.put_u8(DIGITS_START + d100);
        bytes.put_u8(DIGITS_START + d10);
        bytes.put_u8(DIGITS_START + d1);
    } else {
        write_usize(n, bytes);
    }

    bytes.put_slice(b"\r\n");
}

pub(crate) fn write_usize(mut n: usize, bytes: &mut BytesMut) {
    let mut curr: isize = 39;
    let mut buf = [0u8; 39];

    let buf_ptr = buf.as_mut_ptr();
    let lut_ptr = DEC_DIGITS_LUT.as_ptr();

    // eagerly decode 4 characters at a time
    while n >= 10_000 {
        let rem = (n % 10_000) as isize;
        n /= 10_000;

        let d1 = (rem / 100) << 1;
        let d2 = (rem % 100) << 1;
        curr -= 4;
        unsafe {
            ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
            ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
        }
    }

    // if we reach here numbers are <= 9999, so at most 4 chars long
    let mut n = n as isize; // possibly reduce 64bit math

    // decode 2 more chars, if > 2 chars
    if n >= 100 {
        let d1 = (n % 100) << 1;
        n /= 100;
        curr -= 2;
        unsafe {
            ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
        }
    }

    // decode last 1 or 2 chars
    if n < 10 {
        curr -= 1;
        unsafe {
            *buf_ptr.offset(curr) = (n as u8) + b'0';
        }
    } else {
        let d1 = n << 1;
        curr -= 2;
        unsafe {
            ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
        }
    }

    unsafe {
        bytes.extend_from_slice(slice::from_raw_parts(
            buf_ptr.offset(curr),
            39 - curr as usize,
        ));
    }
}

pub(crate) struct Writer<'a>(pub &'a mut BytesMut);

impl<'a> io::Write for Writer<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.extend_from_slice(buf);
        Ok(buf.len())
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

pub(crate) trait DataFactory {
    fn set(&self, ext: &mut Extensions);
}

pub(crate) struct Data<T>(pub(crate) T);

impl<T: Clone + 'static> DataFactory for Data<T> {
    fn set(&self, ext: &mut Extensions) {
        ext.insert(self.0.clone())
    }
}

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

    #[test]
    fn test_write_content_length() {
        let mut bytes = BytesMut::new();
        bytes.reserve(50);
        write_content_length(0, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 0\r\n"[..]);
        bytes.reserve(50);
        write_content_length(9, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 9\r\n"[..]);
        bytes.reserve(50);
        write_content_length(10, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 10\r\n"[..]);
        bytes.reserve(50);
        write_content_length(99, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 99\r\n"[..]);
        bytes.reserve(50);
        write_content_length(100, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 100\r\n"[..]);
        bytes.reserve(50);
        write_content_length(101, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 101\r\n"[..]);
        bytes.reserve(50);
        write_content_length(998, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 998\r\n"[..]);
        bytes.reserve(50);
        write_content_length(1000, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1000\r\n"[..]);
        bytes.reserve(50);
        write_content_length(1001, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1001\r\n"[..]);
        bytes.reserve(50);
        write_content_length(5909, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 5909\r\n"[..]);
        bytes.reserve(50);
        write_content_length(10001, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 10001\r\n"[..]);
        bytes.reserve(50);
        write_content_length(59094, &mut bytes);
        assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 59094\r\n"[..]);
    }
}
<|endoftext|>


<commit_before>//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(const_cstr_unchecked)]
#![feature(crate_visibility_modifier)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(nll)]
#![recursion_limit = "256"]

use back::write::{create_informational_target_machine, create_target_machine};

pub use llvm_util::target_features;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
use rustc_codegen_ssa::back::write::{
    CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_ssa::{CodegenResults, CompiledModule};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{ErrorReported, FatalError, Handler};
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
use rustc_session::Session;
use rustc_span::symbol::Symbol;

use std::any::Any;
use std::ffi::CStr;

mod back {
    pub mod archive;
    pub mod lto;
    mod profiling;
    pub mod write;
}

mod abi;
mod allocator;
mod asm;
mod attributes;
mod base;
mod builder;
mod callee;
mod common;
mod consts;
mod context;
mod coverageinfo;
mod debuginfo;
mod declare;
mod intrinsic;

// The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
#[path = "llvm/mod.rs"]
mod llvm_;
pub mod llvm {
    pub use super::llvm_::*;
}

mod llvm_util;
mod mono_item;
mod type_;
mod type_of;
mod va_arg;
mod value;

#[derive(Clone)]
pub struct LlvmCodegenBackend(());

impl ExtraBackendMethods for LlvmCodegenBackend {
    fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
        ModuleLlvm::new_metadata(tcx, mod_name)
    }

    fn write_compressed_metadata<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: &EncodedMetadata,
        llvm_module: &mut ModuleLlvm,
    ) {
        base::write_compressed_metadata(tcx, metadata, llvm_module)
    }
    fn codegen_allocator<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        mods: &mut ModuleLlvm,
        kind: AllocatorKind,
        has_alloc_error_handler: bool,
    ) {
        unsafe { allocator::codegen(tcx, mods, kind, has_alloc_error_handler) }
    }
    fn compile_codegen_unit(
        &self,
        tcx: TyCtxt<'_>,
        cgu_name: Symbol,
    ) -> (ModuleCodegen<ModuleLlvm>, u64) {
        base::compile_codegen_unit(tcx, cgu_name)
    }
    fn target_machine_factory(
        &self,
        sess: &Session,
        optlvl: OptLevel,
    ) -> TargetMachineFactoryFn<Self> {
        back::write::target_machine_factory(sess, optlvl)
    }
    fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
        llvm_util::target_cpu(sess)
    }
    fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
        llvm_util::tune_cpu(sess)
    }
}

impl WriteBackendMethods for LlvmCodegenBackend {
    type Module = ModuleLlvm;
    type ModuleBuffer = back::lto::ModuleBuffer;
    type Context = llvm::Context;
    type TargetMachine = &'static mut llvm::TargetMachine;
    type ThinData = back::lto::ThinData;
    type ThinBuffer = back::lto::ThinBuffer;
    fn print_pass_timings(&self) {
        unsafe {
            llvm::LLVMRustPrintPassTimings();
        }
    }
    fn run_link(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        modules: Vec<ModuleCodegen<Self::Module>>,
    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
        back::write::link(cgcx, diag_handler, modules)
    }
    fn run_fat_lto(
        cgcx: &CodegenContext<Self>,
        modules: Vec<FatLTOInput<Self>>,
        cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
    ) -> Result<LtoModuleCodegen<Self>, FatalError> {
        back::lto::run_fat(cgcx, modules, cached_modules)
    }
    fn run_thin_lto(
        cgcx: &CodegenContext<Self>,
        modules: Vec<(String, Self::ThinBuffer)>,
        cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
    ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
        back::lto::run_thin(cgcx, modules, cached_modules)
    }
    unsafe fn optimize(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        module: &ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
    ) -> Result<(), FatalError> {
        back::write::optimize(cgcx, diag_handler, module, config)
    }
    unsafe fn optimize_thin(
        cgcx: &CodegenContext<Self>,
        thin: &mut ThinModule<Self>,
    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
        back::lto::optimize_thin_module(thin, cgcx)
    }
    unsafe fn codegen(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        module: ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
    ) -> Result<CompiledModule, FatalError> {
        back::write::codegen(cgcx, diag_handler, module, config)
    }
    fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
        back::lto::prepare_thin(module)
    }
    fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
        (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
    }
    fn run_lto_pass_manager(
        cgcx: &CodegenContext<Self>,
        module: &ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
        thin: bool,
    ) -> Result<(), FatalError> {
        let diag_handler = cgcx.create_diag_handler();
        back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin)
    }
}

unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
unsafe impl Sync for LlvmCodegenBackend {}

impl LlvmCodegenBackend {
    pub fn new() -> Box<dyn CodegenBackend> {
        Box::new(LlvmCodegenBackend(()))
    }
}

impl CodegenBackend for LlvmCodegenBackend {
    fn init(&self, sess: &Session) {
        llvm_util::init(sess); // Make sure llvm is inited
    }

    fn print(&self, req: PrintRequest, sess: &Session) {
        match req {
            PrintRequest::RelocationModels => {
                println!("Available relocation models:");
                for name in
                    &["static", "pic", "dynamic-no-pic", "ropi", "rwpi", "ropi-rwpi", "default"]
                {
                    println!("    {}", name);
                }
                println!();
            }
            PrintRequest::CodeModels => {
                println!("Available code models:");
                for name in &["tiny", "small", "kernel", "medium", "large"] {
                    println!("    {}", name);
                }
                println!();
            }
            PrintRequest::TlsModels => {
                println!("Available TLS models:");
                for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
                    println!("    {}", name);
                }
                println!();
            }
            req => llvm_util::print(req, sess),
        }
    }

    fn print_passes(&self) {
        llvm_util::print_passes();
    }

    fn print_version(&self) {
        llvm_util::print_version();
    }

    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
        target_features(sess)
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        Box::new(rustc_codegen_ssa::base::codegen_crate(
            LlvmCodegenBackend(()),
            tcx,
            crate::llvm_util::target_cpu(tcx.sess).to_string(),
            metadata,
            need_metadata_module,
        ))
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let (codegen_results, work_products) = ongoing_codegen
            .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
            .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
            .join(sess);

        sess.time("llvm_dump_timing_file", || {
            if sess.opts.debugging_opts.llvm_time_trace {
                llvm_util::time_trace_profiler_finish("llvm_timings.json");
            }
        });

        Ok((codegen_results, work_products))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use crate::back::archive::LlvmArchiveBuilder;
        use rustc_codegen_ssa::back::link::link_binary;

        // Run the linker on any artifacts that resulted from the LLVM run.
        // This should produce either a finished executable or library.
        link_binary::<LlvmArchiveBuilder<'_>>(sess, &codegen_results, outputs)
    }
}

pub struct ModuleLlvm {
    llcx: &'static mut llvm::Context,
    llmod_raw: *const llvm::Module,
    tm: &'static mut llvm::TargetMachine,
}

unsafe impl Send for ModuleLlvm {}
unsafe impl Sync for ModuleLlvm {}

impl ModuleLlvm {
    fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
            ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) }
        }
    }

    fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
            ModuleLlvm { llmod_raw, llcx, tm: create_informational_target_machine(tcx.sess) }
        }
    }

    fn parse(
        cgcx: &CodegenContext<LlvmCodegenBackend>,
        name: &CStr,
        buffer: &[u8],
        handler: &Handler,
    ) -> Result<Self, FatalError> {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
            let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
            let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap());
            let tm = match (cgcx.tm_factory)(tm_factory_config) {
                Ok(m) => m,
                Err(e) => {
                    handler.struct_err(&e).emit();
                    return Err(FatalError);
                }
            };

            Ok(ModuleLlvm { llmod_raw, llcx, tm })
        }
    }

    fn llmod(&self) -> &llvm::Module {
        unsafe { &*self.llmod_raw }
    }
}

impl Drop for ModuleLlvm {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
            llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
        }
    }
}
<commit_msg>Dispose LLVM context after TargetMachine<commit_after>//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(const_cstr_unchecked)]
#![feature(crate_visibility_modifier)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(nll)]
#![recursion_limit = "256"]

use back::write::{create_informational_target_machine, create_target_machine};

pub use llvm_util::target_features;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
use rustc_codegen_ssa::back::write::{
    CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_ssa::{CodegenResults, CompiledModule};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{ErrorReported, FatalError, Handler};
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
use rustc_session::Session;
use rustc_span::symbol::Symbol;

use std::any::Any;
use std::ffi::CStr;

mod back {
    pub mod archive;
    pub mod lto;
    mod profiling;
    pub mod write;
}

mod abi;
mod allocator;
mod asm;
mod attributes;
mod base;
mod builder;
mod callee;
mod common;
mod consts;
mod context;
mod coverageinfo;
mod debuginfo;
mod declare;
mod intrinsic;

// The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
#[path = "llvm/mod.rs"]
mod llvm_;
pub mod llvm {
    pub use super::llvm_::*;
}

mod llvm_util;
mod mono_item;
mod type_;
mod type_of;
mod va_arg;
mod value;

#[derive(Clone)]
pub struct LlvmCodegenBackend(());

impl ExtraBackendMethods for LlvmCodegenBackend {
    fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
        ModuleLlvm::new_metadata(tcx, mod_name)
    }

    fn write_compressed_metadata<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: &EncodedMetadata,
        llvm_module: &mut ModuleLlvm,
    ) {
        base::write_compressed_metadata(tcx, metadata, llvm_module)
    }
    fn codegen_allocator<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        mods: &mut ModuleLlvm,
        kind: AllocatorKind,
        has_alloc_error_handler: bool,
    ) {
        unsafe { allocator::codegen(tcx, mods, kind, has_alloc_error_handler) }
    }
    fn compile_codegen_unit(
        &self,
        tcx: TyCtxt<'_>,
        cgu_name: Symbol,
    ) -> (ModuleCodegen<ModuleLlvm>, u64) {
        base::compile_codegen_unit(tcx, cgu_name)
    }
    fn target_machine_factory(
        &self,
        sess: &Session,
        optlvl: OptLevel,
    ) -> TargetMachineFactoryFn<Self> {
        back::write::target_machine_factory(sess, optlvl)
    }
    fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
        llvm_util::target_cpu(sess)
    }
    fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
        llvm_util::tune_cpu(sess)
    }
}

impl WriteBackendMethods for LlvmCodegenBackend {
    type Module = ModuleLlvm;
    type ModuleBuffer = back::lto::ModuleBuffer;
    type Context = llvm::Context;
    type TargetMachine = &'static mut llvm::TargetMachine;
    type ThinData = back::lto::ThinData;
    type ThinBuffer = back::lto::ThinBuffer;
    fn print_pass_timings(&self) {
        unsafe {
            llvm::LLVMRustPrintPassTimings();
        }
    }
    fn run_link(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        modules: Vec<ModuleCodegen<Self::Module>>,
    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
        back::write::link(cgcx, diag_handler, modules)
    }
    fn run_fat_lto(
        cgcx: &CodegenContext<Self>,
        modules: Vec<FatLTOInput<Self>>,
        cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
    ) -> Result<LtoModuleCodegen<Self>, FatalError> {
        back::lto::run_fat(cgcx, modules, cached_modules)
    }
    fn run_thin_lto(
        cgcx: &CodegenContext<Self>,
        modules: Vec<(String, Self::ThinBuffer)>,
        cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
    ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
        back::lto::run_thin(cgcx, modules, cached_modules)
    }
    unsafe fn optimize(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        module: &ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
    ) -> Result<(), FatalError> {
        back::write::optimize(cgcx, diag_handler, module, config)
    }
    unsafe fn optimize_thin(
        cgcx: &CodegenContext<Self>,
        thin: &mut ThinModule<Self>,
    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
        back::lto::optimize_thin_module(thin, cgcx)
    }
    unsafe fn codegen(
        cgcx: &CodegenContext<Self>,
        diag_handler: &Handler,
        module: ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
    ) -> Result<CompiledModule, FatalError> {
        back::write::codegen(cgcx, diag_handler, module, config)
    }
    fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
        back::lto::prepare_thin(module)
    }
    fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
        (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
    }
    fn run_lto_pass_manager(
        cgcx: &CodegenContext<Self>,
        module: &ModuleCodegen<Self::Module>,
        config: &ModuleConfig,
        thin: bool,
    ) -> Result<(), FatalError> {
        let diag_handler = cgcx.create_diag_handler();
        back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin)
    }
}

unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
unsafe impl Sync for LlvmCodegenBackend {}

impl LlvmCodegenBackend {
    pub fn new() -> Box<dyn CodegenBackend> {
        Box::new(LlvmCodegenBackend(()))
    }
}

impl CodegenBackend for LlvmCodegenBackend {
    fn init(&self, sess: &Session) {
        llvm_util::init(sess); // Make sure llvm is inited
    }

    fn print(&self, req: PrintRequest, sess: &Session) {
        match req {
            PrintRequest::RelocationModels => {
                println!("Available relocation models:");
                for name in
                    &["static", "pic", "dynamic-no-pic", "ropi", "rwpi", "ropi-rwpi", "default"]
                {
                    println!("    {}", name);
                }
                println!();
            }
            PrintRequest::CodeModels => {
                println!("Available code models:");
                for name in &["tiny", "small", "kernel", "medium", "large"] {
                    println!("    {}", name);
                }
                println!();
            }
            PrintRequest::TlsModels => {
                println!("Available TLS models:");
                for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
                    println!("    {}", name);
                }
                println!();
            }
            req => llvm_util::print(req, sess),
        }
    }

    fn print_passes(&self) {
        llvm_util::print_passes();
    }

    fn print_version(&self) {
        llvm_util::print_version();
    }

    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
        target_features(sess)
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        Box::new(rustc_codegen_ssa::base::codegen_crate(
            LlvmCodegenBackend(()),
            tcx,
            crate::llvm_util::target_cpu(tcx.sess).to_string(),
            metadata,
            need_metadata_module,
        ))
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let (codegen_results, work_products) = ongoing_codegen
            .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
            .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
            .join(sess);

        sess.time("llvm_dump_timing_file", || {
            if sess.opts.debugging_opts.llvm_time_trace {
                llvm_util::time_trace_profiler_finish("llvm_timings.json");
            }
        });

        Ok((codegen_results, work_products))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use crate::back::archive::LlvmArchiveBuilder;
        use rustc_codegen_ssa::back::link::link_binary;

        // Run the linker on any artifacts that resulted from the LLVM run.
        // This should produce either a finished executable or library.
        link_binary::<LlvmArchiveBuilder<'_>>(sess, &codegen_results, outputs)
    }
}

pub struct ModuleLlvm {
    llcx: &'static mut llvm::Context,
    llmod_raw: *const llvm::Module,
    tm: &'static mut llvm::TargetMachine,
}

unsafe impl Send for ModuleLlvm {}
unsafe impl Sync for ModuleLlvm {}

impl ModuleLlvm {
    fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
            ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) }
        }
    }

    fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
            ModuleLlvm { llmod_raw, llcx, tm: create_informational_target_machine(tcx.sess) }
        }
    }

    fn parse(
        cgcx: &CodegenContext<LlvmCodegenBackend>,
        name: &CStr,
        buffer: &[u8],
        handler: &Handler,
    ) -> Result<Self, FatalError> {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
            let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
            let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap());
            let tm = match (cgcx.tm_factory)(tm_factory_config) {
                Ok(m) => m,
                Err(e) => {
                    handler.struct_err(&e).emit();
                    return Err(FatalError);
                }
            };

            Ok(ModuleLlvm { llmod_raw, llcx, tm })
        }
    }

    fn llmod(&self) -> &llvm::Module {
        unsafe { &*self.llmod_raw }
    }
}

impl Drop for ModuleLlvm {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
        }
    }
}
<|endoftext|>


<commit_before>use crate::ty;
use crate::ty::Ty;

use rustc_hir::HirId;
use rustc_target::abi::VariantIdx;

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    TyEncodable,
    TyDecodable,
    TypeFoldable,
    HashStable
)]
pub enum PlaceBase {
    /// A temporary variable
    Rvalue,
    /// A named `static` item
    StaticItem,
    /// A named local variable
    Local(HirId),
    /// An upvar referenced by closure env
    Upvar(ty::UpvarId),
}

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    TyEncodable,
    TyDecodable,
    TypeFoldable,
    HashStable
)]
pub enum ProjectionKind {
    /// A dereference of a pointer, reference or `Box<T>` of the given type
    Deref,

    /// `B.F` where `B` is the base expression and `F` is
    /// the field. The field is identified by which variant
    /// it appears in along with a field index. The variant
    /// is used for enums.
    Field(u32, VariantIdx),

    /// Some index like `B[x]`, where `B` is the base
    /// expression. We don't preserve the index `x` because
    /// we won't need it.
    Index,

    /// A subslice covering a range of values like `B[x..y]`.
    Subslice,
}

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    TyEncodable,
    TyDecodable,
    TypeFoldable,
    HashStable
)]
pub struct Projection<'tcx> {
    /// Type after the projection is being applied.
    pub ty: Ty<'tcx>,

    /// Defines the type of access
    pub kind: ProjectionKind,
}

/// A `Place` represents how a value is located in memory.
///
/// This is an HIR version of `mir::Place`
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct Place<'tcx> {
    /// The type of the `PlaceBase`
    pub base_ty: Ty<'tcx>,
    /// The "outermost" place that holds this value.
    pub base: PlaceBase,
    /// How this place is derived from the base place.
    pub projections: Vec<Projection<'tcx>>,
}

/// A `PlaceWithHirId` represents how a value is located in memory.
///
/// This is an HIR version of `mir::Place`
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct PlaceWithHirId<'tcx> {
    /// `HirId` of the expression or pattern producing this value.
    pub hir_id: HirId,

    /// Information about the `Place`
    pub place: Place<'tcx>,
}

impl<'tcx> PlaceWithHirId<'tcx> {
    pub fn new(
        hir_id: HirId,
        base_ty: Ty<'tcx>,
        base: PlaceBase,
        projections: Vec<Projection<'tcx>>,
    ) -> PlaceWithHirId<'tcx> {
        PlaceWithHirId {
            hir_id: hir_id,
            place: Place { base_ty: base_ty, base: base, projections: projections },
        }
    }
}

impl<'tcx> Place<'tcx> {
    /// Returns an iterator of the types that have to be dereferenced to access
    /// the `Place`.
    ///
    /// The types are in the reverse order that they are applied. So if
    /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
    ///`*const u32` then `&*const u32`.
    pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
        self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
            if ProjectionKind::Deref == proj.kind {
                Some(self.ty_before_projection(index))
            } else {
                None
            }
        })
    }

    /// Returns the type of this `Place` after all projections have been applied.
    pub fn ty(&self) -> Ty<'tcx> {
        self.projections.last().map_or(self.base_ty, |proj| proj.ty)
    }

    /// Returns the type of this `Place` immediately before `projection_index`th projection
    /// is applied.
    pub fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> {
        assert!(projection_index < self.projections.len());
        if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty }
    }
}
<commit_msg>Edit rustc_middle docs<commit_after>use crate::ty;
use crate::ty::Ty;

use rustc_hir::HirId;
use rustc_target::abi::VariantIdx;

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    TyEncodable,
    TyDecodable,
    TypeFoldable,
    HashStable
)]
pub enum PlaceBase {
    /// A temporary variable.
    Rvalue,
    /// A named `static` item.
    StaticItem,
    /// A named local variable.
    Local(HirId),
    /// An upvar referenced by closure env.
    Upvar(ty::UpvarId),
}

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    TyEncodable,
    TyDecodable,
    TypeFoldable,
    HashStable
)]
pub enum ProjectionKind {
    /// A dereference of a pointer, reference or `Box<T>` of the given type.
    Deref,

    /// `B.F` where `B` is the base expression and `F` is
    /// the field. The field is identified by which variant
    /// it appears in along with a field index. The variant
    /// is used for enums.
    Field(u32, VariantIdx),

    /// Some index like `B[x]`, where `B` is the base
    /// expression. We don't preserve the index `x` because
    /// we won't need it.
    Index,

    /// A subslice covering a range of values like `B[x..y]`.
    Subslice,
}

#[derive(
    Clone,
    Copy,
    Debug,
    PartialEq,
    Eq,
    Hash,
    TyEncodable,
    TyDecodable,
    TypeFoldable,
    HashStable
)]
pub struct Projection<'tcx> {
    /// Type after the projection is applied.
    pub ty: Ty<'tcx>,

    /// Defines the kind of access made by the projection.
    pub kind: ProjectionKind,
}

/// A `Place` represents how a value is located in memory.
///
/// This is an HIR version of [`rustc_middle::mir::Place`].
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct Place<'tcx> {
    /// The type of the `PlaceBase`
    pub base_ty: Ty<'tcx>,
    /// The "outermost" place that holds this value.
    pub base: PlaceBase,
    /// How this place is derived from the base place.
    pub projections: Vec<Projection<'tcx>>,
}

/// A `PlaceWithHirId` represents how a value is located in memory.
///
/// This is an HIR version of [`rustc_middle::mir::Place`].
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct PlaceWithHirId<'tcx> {
    /// `HirId` of the expression or pattern producing this value.
    pub hir_id: HirId,

    /// Information about the `Place`.
    pub place: Place<'tcx>,
}

impl<'tcx> PlaceWithHirId<'tcx> {
    pub fn new(
        hir_id: HirId,
        base_ty: Ty<'tcx>,
        base: PlaceBase,
        projections: Vec<Projection<'tcx>>,
    ) -> PlaceWithHirId<'tcx> {
        PlaceWithHirId {
            hir_id: hir_id,
            place: Place { base_ty: base_ty, base: base, projections: projections },
        }
    }
}

impl<'tcx> Place<'tcx> {
    /// Returns an iterator of the types that have to be dereferenced to access
    /// the `Place`.
    ///
    /// The types are in the reverse order that they are applied. So if
    /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
    ///`*const u32` then `&*const u32`.
    pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
        self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
            if ProjectionKind::Deref == proj.kind {
                Some(self.ty_before_projection(index))
            } else {
                None
            }
        })
    }

    /// Returns the type of this `Place` after all projections have been applied.
    pub fn ty(&self) -> Ty<'tcx> {
        self.projections.last().map_or(self.base_ty, |proj| proj.ty)
    }

    /// Returns the type of this `Place` immediately before `projection_index`th projection
    /// is applied.
    pub fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> {
        assert!(projection_index < self.projections.len());
        if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty }
    }
}
<|endoftext|>


<commit_before>// from src/libsyntax/ext/tt/macro_rules.rs

use std::cell::RefCell;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::ast;
use syntax::ptr::P;

use syntax::ext::base::MacResult;
use syntax::util::small_vector::SmallVector;

macro_rules! panictry {
    ($e:expr) => ({
        use std::result::Result::{Ok, Err};
        use syntax::errors::FatalError;
        match $e {
            Ok(e) => e,
            Err(FatalError) => panic!(FatalError)
        }
    })
}

pub struct ParserAnyMacro<'a> {
    parser: RefCell<Parser<'a>>,
}

impl<'a> ParserAnyMacro<'a> {
    pub fn new(p: Parser<'a>) -> ParserAnyMacro<'a> {
        ParserAnyMacro {
            parser: RefCell::new(p)
        }
    }
    /// Make sure we don't have any tokens left to parse, so we don't
    /// silently drop anything. `allow_semi` is so that "optional"
    /// semicolons at the end of normal expressions aren't complained
    /// about e.g. the semicolon in `macro_rules! kapow { () => {
    /// panic!(); } }` doesn't get picked up by .parse_expr(), but it's
    /// allowed to be there.
    fn ensure_complete_parse(&self, allow_semi: bool) {
        let mut parser = self.parser.borrow_mut();
        if allow_semi && parser.token == token::Semi {
            panictry!(parser.bump())
        }
        if parser.token != token::Eof {
            let token_str = parser.this_token_to_string();
            let msg = format!("macro expansion ignores token `{}` and any \
                               following",
                              token_str);
            let span = parser.span;
            parser.span_err(span, &msg[..]);
        }
    }
}

impl<'a> MacResult for ParserAnyMacro<'a> {
    fn make_expr(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Expr>> {
        let ret = self.parser.borrow_mut().parse_expr().unwrap();
        self.ensure_complete_parse(true);
        Some(ret)
    }
    fn make_pat(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Pat>> {
        let ret = self.parser.borrow_mut().parse_pat().unwrap();
        self.ensure_complete_parse(false);
        Some(ret)
    }
    fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
        let mut ret = SmallVector::zero();
        while let Some(item) = self.parser.borrow_mut().parse_item().unwrap() {
            ret.push(item);
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }

    fn make_impl_items(self: Box<ParserAnyMacro<'a>>)
                       -> Option<SmallVector<P<ast::ImplItem>>> {
        let mut ret = SmallVector::zero();
        loop {
            let mut parser = self.parser.borrow_mut();
            match parser.token {
                token::Eof => break,
                _ => ret.push(panictry!(parser.parse_impl_item()))
            }
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }

    fn make_stmts(self: Box<ParserAnyMacro<'a>>)
                 -> Option<SmallVector<P<ast::Stmt>>> {
        let mut ret = SmallVector::zero();
        loop {
            let mut parser = self.parser.borrow_mut();
            match parser.token {
                token::Eof => break,
                _ => match parser.parse_stmt() {
                    Ok(maybe_stmt) => match maybe_stmt {
                        Some(stmt) => ret.push(stmt),
                        None => (),
                    },
                    Err(_) => break,
                }
            }
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }
}
<commit_msg>Small adjustment to nightly<commit_after>// from src/libsyntax/ext/tt/macro_rules.rs

use std::cell::RefCell;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::ast;
use syntax::ptr::P;

use syntax::ext::base::MacResult;
use syntax::util::small_vector::SmallVector;

macro_rules! panictry {
    ($e:expr) => ({
        use std::result::Result::{Ok, Err};
        use syntax::errors::FatalError;
        match $e {
            Ok(e) => e,
            Err(mut e) => {
                   e.emit();
                   panic!(FatalError);
               }
        }
    })
}

pub struct ParserAnyMacro<'a> {
    parser: RefCell<Parser<'a>>,
}

impl<'a> ParserAnyMacro<'a> {
    pub fn new(p: Parser<'a>) -> ParserAnyMacro<'a> {
        ParserAnyMacro {
            parser: RefCell::new(p)
        }
    }
    /// Make sure we don't have any tokens left to parse, so we don't
    /// silently drop anything. `allow_semi` is so that "optional"
    /// semicolons at the end of normal expressions aren't complained
    /// about e.g. the semicolon in `macro_rules! kapow { () => {
    /// panic!(); } }` doesn't get picked up by .parse_expr(), but it's
    /// allowed to be there.
    fn ensure_complete_parse(&self, allow_semi: bool) {
        let mut parser = self.parser.borrow_mut();
        if allow_semi && parser.token == token::Semi {
            panictry!(parser.bump())
        }
        if parser.token != token::Eof {
            let token_str = parser.this_token_to_string();
            let msg = format!("macro expansion ignores token `{}` and any \
                               following",
                              token_str);
            let span = parser.span;
            parser.span_err(span, &msg[..]);
        }
    }
}

impl<'a> MacResult for ParserAnyMacro<'a> {
    fn make_expr(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Expr>> {
        let ret = self.parser.borrow_mut().parse_expr().unwrap();
        self.ensure_complete_parse(true);
        Some(ret)
    }
    fn make_pat(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Pat>> {
        let ret = self.parser.borrow_mut().parse_pat().unwrap();
        self.ensure_complete_parse(false);
        Some(ret)
    }
    fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
        let mut ret = SmallVector::zero();
        while let Some(item) = self.parser.borrow_mut().parse_item().unwrap() {
            ret.push(item);
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }

    fn make_impl_items(self: Box<ParserAnyMacro<'a>>)
                       -> Option<SmallVector<P<ast::ImplItem>>> {
        let mut ret = SmallVector::zero();
        loop {
            let mut parser = self.parser.borrow_mut();
            match parser.token {
                token::Eof => break,
                _ => ret.push(panictry!(parser.parse_impl_item()))
            }
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }

    fn make_stmts(self: Box<ParserAnyMacro<'a>>)
                 -> Option<SmallVector<P<ast::Stmt>>> {
        let mut ret = SmallVector::zero();
        loop {
            let mut parser = self.parser.borrow_mut();
            match parser.token {
                token::Eof => break,
                _ => match parser.parse_stmt() {
                    Ok(maybe_stmt) => match maybe_stmt {
                        Some(stmt) => ret.push(stmt),
                        None => (),
                    },
                    Err(_) => break,
                }
            }
        }
        self.ensure_complete_parse(false);
        Some(ret)
    }
}
<|endoftext|>


<commit_before>pub use self::imp::*;

#[cfg(not(cross_platform_docs))]
mod imp {
    pub use core::option::Option;
    pub use core::clone::Clone;
    pub use core::marker::Copy;
    pub use core::mem;
}

#[cfg(cross_platform_docs)]
mod imp {
    pub enum Option<T> {
        Some(T),
        None,
    }
    impl<T: Copy> Copy for Option<T> {}
    impl<T: Clone> Clone for Option<T> {
        fn clone(&self) -> Option<T> { loop {} }
    }

    impl<T> Copy for *mut T {}
    impl<T> Clone for *mut T {
        fn clone(&self) -> *mut T { loop {} }
    }

    impl<T> Copy for *const T {}
    impl<T> Clone for *const T {
        fn clone(&self) -> *const T { loop {} }
    }

    pub trait Clone {
        fn clone(&self) -> Self;
    }

    #[lang = "copy"]
    pub trait Copy {}

    #[lang = "freeze"]
    pub trait Freeze {}

    #[lang = "sync"]
    pub trait Sync {}
    impl<T> Sync for T {}

    #[lang = "sized"]
    pub trait Sized {}

    macro_rules! each_int {
        ($mac:ident) => (
            $mac!(u8);
            $mac!(u16);
            $mac!(u32);
            $mac!(u64);
            $mac!(usize);
            each_signed_int!($mac);
        )
    }

    macro_rules! each_signed_int {
        ($mac:ident) => (
            $mac!(i8);
            $mac!(i16);
            $mac!(i32);
            $mac!(i64);
            $mac!(isize);
        )
    }

    #[lang = "div"]
    pub trait Div<RHS=Self> {
        type Output;
        fn div(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "shl"]
    pub trait Shl<RHS=Self> {
        type Output;
        fn shl(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "mul"]
    pub trait Mul<RHS=Self> {
        type Output;
        fn mul(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "sub"]
    pub trait Sub<RHS=Self> {
        type Output;
        fn sub(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitor"]
    pub trait Bitor<RHS=Self> {
        type Output;
        fn bitor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "neg"]
    pub trait Neg {
        type Output;
        fn neg(self) -> Self::Output;
    }

    #[lang = "not"]
    pub trait Not {
        type Output;
        fn not(self) -> Self::Output;
    }

    #[lang = "add"]
    pub trait Add<RHS = Self> {
        type Output;
        fn add(self, r: RHS) -> Self::Output;
    }

    macro_rules! impl_traits {
        ($($i:ident)*) => ($(
            impl Div<$i> for $i {
                type Output = $i;
                fn div(self, rhs: $i) -> $i { self / rhs }
            }
            impl Shl<$i> for $i {
                type Output = $i;
                fn shl(self, rhs: $i) -> $i { self << rhs }
            }
            impl Mul for $i {
                type Output = $i;
                fn mul(self, rhs: $i) -> $i { self * rhs }
            }

            impl Sub for $i {
                type Output = $i;
                fn sub(self, rhs: $i) -> $i { self - rhs }
            }
            impl Bitor for $i {
                type Output = $i;
                fn bitor(self, rhs: $i) -> $i { self | rhs }
            }
            impl Neg for $i {
                type Output = $i;
                fn neg(self) -> $i { -self }
            }
            impl Not for $i {
                type Output = $i;
                fn not(self) -> $i { !self }
            }
            impl Add<$i> for $i {
                type Output = $i;
                fn add(self, other: $i) -> $i { self + other }
            }
            impl Copy for $i {}
            impl Clone for $i {
                fn clone(&self) -> $i { loop {} }
            }
        )*)
    }
    each_int!(impl_traits);

    pub mod mem {
        pub fn size_of_val<T>(_: &T) -> usize { 4 }
        pub fn size_of<T>() -> usize { 4 }
    }
}
<commit_msg>add more built-in traits to dox.rs<commit_after>pub use self::imp::*;

#[cfg(not(cross_platform_docs))]
mod imp {
    pub use core::option::Option;
    pub use core::clone::Clone;
    pub use core::marker::Copy;
    pub use core::mem;
}

#[cfg(cross_platform_docs)]
mod imp {
    pub enum Option<T> {
        Some(T),
        None,
    }
    impl<T: Copy> Copy for Option<T> {}
    impl<T: Clone> Clone for Option<T> {
        fn clone(&self) -> Option<T> { loop {} }
    }

    impl<T> Copy for *mut T {}
    impl<T> Clone for *mut T {
        fn clone(&self) -> *mut T { loop {} }
    }

    impl<T> Copy for *const T {}
    impl<T> Clone for *const T {
        fn clone(&self) -> *const T { loop {} }
    }

    pub trait Clone {
        fn clone(&self) -> Self;
    }

    #[lang = "copy"]
    pub trait Copy {}

    #[lang = "freeze"]
    pub trait Freeze {}

    #[lang = "sync"]
    pub trait Sync {}
    impl<T> Sync for T {}

    #[lang = "sized"]
    pub trait Sized {}

    macro_rules! each_int {
        ($mac:ident) => (
            $mac!(u8);
            $mac!(u16);
            $mac!(u32);
            $mac!(u64);
            $mac!(usize);
            each_signed_int!($mac);
        )
    }

    macro_rules! each_signed_int {
        ($mac:ident) => (
            $mac!(i8);
            $mac!(i16);
            $mac!(i32);
            $mac!(i64);
            $mac!(isize);
        )
    }

    #[lang = "div"]
    pub trait Div<RHS=Self> {
        type Output;
        fn div(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "shl"]
    pub trait Shl<RHS=Self> {
        type Output;
        fn shl(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "mul"]
    pub trait Mul<RHS=Self> {
        type Output;
        fn mul(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "sub"]
    pub trait Sub<RHS=Self> {
        type Output;
        fn sub(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitand"]
    pub trait BitAnd<RHS=Self> {
        type Output;
        fn bitand(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitand_assign"]
    pub trait BitAndAssign<RHS = Self> {
        fn bitand_assign(&mut self, rhs: RHS);
    }

    #[lang = "bitor"]
    pub trait BitOr<RHS=Self> {
        type Output;
        fn bitor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitor_assign"]
    pub trait BitOrAssign<RHS = Self> {
        fn bitor_assign(&mut self, rhs: RHS);
    }

    #[lang = "bitxor"]
    pub trait BitXor<RHS=Self> {
        type Output;
        fn bitxor(self, rhs: RHS) -> Self::Output;
    }

    #[lang = "bitxor_assign"]
    pub trait BitXorAssign<RHS = Self> {
        fn bitxor_assign(&mut self, rhs: RHS);
    }

    #[lang = "neg"]
    pub trait Neg {
        type Output;
        fn neg(self) -> Self::Output;
    }

    #[lang = "not"]
    pub trait Not {
        type Output;
        fn not(self) -> Self::Output;
    }

    #[lang = "add"]
    pub trait Add<RHS = Self> {
        type Output;
        fn add(self, r: RHS) -> Self::Output;
    }

    macro_rules! impl_traits {
        ($($i:ident)*) => ($(
            impl Div<$i> for $i {
                type Output = $i;
                fn div(self, rhs: $i) -> $i { self / rhs }
            }
            impl Shl<$i> for $i {
                type Output = $i;
                fn shl(self, rhs: $i) -> $i { self << rhs }
            }
            impl Mul for $i {
                type Output = $i;
                fn mul(self, rhs: $i) -> $i { self * rhs }
            }

            impl Sub for $i {
                type Output = $i;
                fn sub(self, rhs: $i) -> $i { self - rhs }
            }
            impl BitAnd for $i {
                type Output = $i;
                fn bitand(self, rhs: $i) -> $i { self & rhs }
            }
            impl BitAndAssign for $i {
                fn bitand_assign(&mut self, rhs: $i) { *self &= rhs; }
            }
            impl BitOr for $i {
                type Output = $i;
                fn bitor(self, rhs: $i) -> $i { self | rhs }
            }
            impl BitOrAssign for $i {
                fn bitor_assign(&mut self, rhs: $i) { *self |= rhs; }
            }
            impl BitXor for $i {
                type Output = $i;
                fn bitxor(self, rhs: $i) -> $i { self ^ rhs }
            }
            impl BitXorAssign for $i {
                fn bitxor_assign(&mut self, rhs: $i) { *self ^= rhs; }
            }
            impl Neg for $i {
                type Output = $i;
                fn neg(self) -> $i { -self }
            }
            impl Not for $i {
                type Output = $i;
                fn not(self) -> $i { !self }
            }
            impl Add<$i> for $i {
                type Output = $i;
                fn add(self, other: $i) -> $i { self + other }
            }
            impl Copy for $i {}
            impl Clone for $i {
                fn clone(&self) -> $i { loop {} }
            }
        )*)
    }
    each_int!(impl_traits);

    pub mod mem {
        pub fn size_of_val<T>(_: &T) -> usize { 4 }
        pub fn size_of<T>() -> usize { 4 }
    }
}
<|endoftext|>