<commit_before>//! The `pact_mock_server` crate provides a number of exported functions using C bindings for
//! controlling the mock server. These can be used in any language that supports C bindings.
//!
//! ## [create_mock_server](fn.create_mock_server_ffi.html)
//!
//! External interface to create a mock server. A pointer to the pact JSON as a C string is passed in,
//! as well as the port for the mock server to run on. A value of 0 for the port will result in a
//! port being allocated by the operating system. The port of the mock server is returned.
//!
//! ## [mock_server_matched](fn.mock_server_matched_ffi.html)
//!
//! Simple function that returns a boolean value given the port number of the mock service. This value will be true if all
//! the expectations of the pact that the mock server was created with have been met. It will return false if any request did
//! not match, an un-recognised request was received or an expected request was not received.
//!
//! ## [mock_server_mismatches](fn.mock_server_mismatches_ffi.html)
//!
//! This returns all the mismatches, un-expected requests and missing requests in JSON format, given the port number of the
//! mock server.
//!
//! **IMPORTANT NOTE:** The JSON string for the result is allocated on the rust heap, and will have to be freed once the
//! code using the mock server is complete. The [`cleanup_mock_server`](fn.cleanup_mock_server.html) function is provided for this purpose. If the mock
//! server is not cleaned up properly, this will result in memory leaks as the rust heap will not be reclaimed.
//!
//! ## [cleanup_mock_server](fn.cleanup_mock_server.html)
//!
//! This function will try terminate the mock server with the given port number and cleanup any memory allocated for it by
//! the [`mock_server_mismatches`](fn.mock_server_mismatches.html) function. Returns `true`, unless a mock server with the given port number does not exist,
//! or the function fails in some way.
//!
//! **NOTE:** Although `close()` on the listerner for the mock server is called, this does not currently work and the
//! listerner will continue handling requests. In this case, it will always return a 501 once the mock server has been
//! cleaned up.
//!
//! ## [write_pact_file](fn.write_pact_file.html)
//!
//! External interface to trigger a mock server to write out its pact file. This function should
//! be called if all the consumer tests have passed. The directory to write the file to is passed
//! as the second parameter. If a NULL pointer is passed, the current working directory is used.
//!
//! Returns 0 if the pact file was successfully written. Returns a positive code if the file can
//! not be written, or there is no mock server running on that port or the function panics.

#![warn(missing_docs)]

extern crate pact_mock_server;
extern crate libc;
extern crate serde_json;
extern crate env_logger;
#[macro_use] extern crate log;

use std::panic::catch_unwind;
use libc::c_char;
use std::ffi::CStr;
use std::ffi::CString;
use std::str;
use serde_json::json;
use pact_mock_server::{MockServerError, WritePactFileErr, MANAGER};
use pact_mock_server::server_manager::ServerManager;

/// External interface to create a mock server. A pointer to the pact JSON as a C string is passed in,
/// as well as the port for the mock server to run on. A value of 0 for the port will result in a
/// port being allocated by the operating system. The port of the mock server is returned.
///
/// # Errors
///
/// Errors are returned as negative values.
///
/// | Error | Description |
/// |-------|-------------|
/// | -1 | A null pointer was received |
/// | -2 | The pact JSON could not be parsed |
/// | -3 | The mock server could not be started |
/// | -4 | The method panicked |
/// | -5 | The address is not valid |
///
#[no_mangle]
pub extern fn create_mock_server(pact_str: *const c_char, addr_str: *const c_char) -> i32 {
    env_logger::try_init().unwrap_or(());

    let result = catch_unwind(|| {
        let c_str = unsafe {
            if pact_str.is_null() {
                error!("Got a null pointer instead of pact json");
                return -1;
            }
            CStr::from_ptr(pact_str)
        };

        let addr_c_str = unsafe {
            if addr_str.is_null() {
                error!("Got a null pointer instead of listener address");
                return -1;
            }
            CStr::from_ptr(addr_str)
        };

        if let Ok(Ok(addr)) = str::from_utf8(addr_c_str.to_bytes()).map(|s| s.parse::<std::net::SocketAddr>()) {
          match pact_mock_server::create_mock_server(str::from_utf8(c_str.to_bytes()).unwrap(), addr) {
            Ok(ms_port) => ms_port,
            Err(err) => match err {
              MockServerError::InvalidPactJson => -2,
              MockServerError::MockServerFailedToStart => -3
            }
          }
        }
        else {
          -5
        }
    });

    match result {
        Ok(val) => val,
        Err(cause) => {
            error!("Caught a general panic: {:?}", cause);
            -4
        }
    }
}

/// External interface to check if a mock server has matched all its requests. The port number is
/// passed in, and if all requests have been matched, true is returned. False is returned if there
/// is no mock server on the given port, or if any request has not been successfully matched, or
/// the method panics.
#[no_mangle]
pub extern fn mock_server_matched(mock_server_port: i32) -> bool {
  let result = catch_unwind(|| {
    pact_mock_server::mock_server_matched(mock_server_port)
  });

  match result {
    Ok(val) => val,
    Err(cause) => {
      error!("Caught a general panic: {:?}", cause);
      false
    }
  }
}

/// External interface to get all the mismatches from a mock server. The port number of the mock
/// server is passed in, and a pointer to a C string with the mismatches in JSON format is
/// returned.
///
/// **NOTE:** The JSON string for the result is allocated on the heap, and will have to be freed
/// once the code using the mock server is complete. The [`cleanup_mock_server`](fn.cleanup_mock_server.html) function is
/// provided for this purpose.
///
/// # Errors
///
/// If there is no mock server with the provided port number, or the function panics, a NULL
/// pointer will be returned. Don't try to dereference it, it will not end well for you.
///
#[no_mangle]
pub extern fn mock_server_mismatches(mock_server_port: i32) -> *mut c_char {
  let result = catch_unwind(|| {
    let result = MANAGER.lock().unwrap()
      .get_or_insert_with(ServerManager::new)
      .find_mock_server_by_port_mut(mock_server_port as u16, &|ref mut mock_server| {
        let mismatches = mock_server.mismatches().iter()
          .map(|mismatch| mismatch.to_json() )
          .collect::<Vec<serde_json::Value>>();
        let json = json!(mismatches);
        let s = CString::new(json.to_string()).unwrap();
        let p = s.as_ptr();
        mock_server.resources.push(s);
        p
      });
    match result {
      Some(p) => p as *mut _,
      None => 0 as *mut _
    }
  });

  match result {
    Ok(val) => val,
    Err(cause) => {
      error!("Caught a general panic: {:?}", cause);
      0 as *mut _
    }
  }
}

/// External interface to cleanup a mock server. This function will try terminate the mock server
/// with the given port number and cleanup any memory allocated for it. Returns true, unless a
/// mock server with the given port number does not exist, or the function panics.
///
/// **NOTE:** Although `close()` on the listener for the mock server is called, this does not
/// currently work and the listener will continue handling requests. In this
/// case, it will always return a 404 once the mock server has been cleaned up.
#[no_mangle]
pub extern fn cleanup_mock_server(mock_server_port: i32) -> bool {
  let result = catch_unwind(|| {
    MANAGER.lock().unwrap()
      .get_or_insert_with(ServerManager::new)
      .shutdown_mock_server_by_port(mock_server_port as u16)
  });

  match result {
    Ok(val) => val,
    Err(cause) => {
      error!("Caught a general panic: {:?}", cause);
      false
    }
  }
}

/// External interface to trigger a mock server to write out its pact file. This function should
/// be called if all the consumer tests have passed. The directory to write the file to is passed
/// as the second parameter. If a NULL pointer is passed, the current working directory is used.
///
/// Returns 0 if the pact file was successfully written. Returns a positive code if the file can
/// not be written, or there is no mock server running on that port or the function panics.
///
/// # Errors
///
/// Errors are returned as positive values.
///
/// | Error | Description |
/// |-------|-------------|
/// | 1 | A general panic was caught |
/// | 2 | The pact file was not able to be written |
/// | 3 | A mock server with the provided port was not found |
#[no_mangle]
pub extern fn write_pact_file(mock_server_port: i32, directory: *const c_char) -> i32 {
  let result = catch_unwind(|| {
    let dir = unsafe {
      if directory.is_null() {
        warn!("Directory to write to is NULL, defaulting to the current working directory");
        None
      } else {
        let c_str = CStr::from_ptr(directory);
        let dir_str = str::from_utf8(c_str.to_bytes()).unwrap();
        if dir_str.is_empty() {
          None
        } else {
          Some(dir_str.to_string())
        }
      }
    };

    pact_mock_server::write_pact_file(mock_server_port, dir)
  });

  match result {
    Ok(val) => match val {
      Ok(_) => 0,
      Err(err) => match err {
        WritePactFileErr::IOError => 2,
        WritePactFileErr::NoMockServer => 3
      }
    },
    Err(cause) => {
      error!("Caught a general panic: {:?}", cause);
      1
    }
  }
}
<commit_msg>pact_mock_server_ffi: Remove extern crate from lib.rs<commit_after>//! The `pact_mock_server` crate provides a number of exported functions using C bindings for
//! controlling the mock server. These can be used in any language that supports C bindings.
//!
//! ## [create_mock_server](fn.create_mock_server_ffi.html)
//!
//! External interface to create a mock server. A pointer to the pact JSON as a C string is passed in,
//! as well as the port for the mock server to run on. A value of 0 for the port will result in a
//! port being allocated by the operating system. The port of the mock server is returned.
//!
//! ## [mock_server_matched](fn.mock_server_matched_ffi.html)
//!
//! Simple function that returns a boolean value given the port number of the mock service. This value will be true if all
//! the expectations of the pact that the mock server was created with have been met. It will return false if any request did
//! not match, an un-recognised request was received or an expected request was not received.
//!
//! ## [mock_server_mismatches](fn.mock_server_mismatches_ffi.html)
//!
//! This returns all the mismatches, un-expected requests and missing requests in JSON format, given the port number of the
//! mock server.
//!
//! **IMPORTANT NOTE:** The JSON string for the result is allocated on the rust heap, and will have to be freed once the
//! code using the mock server is complete. The [`cleanup_mock_server`](fn.cleanup_mock_server.html) function is provided for this purpose. If the mock
//! server is not cleaned up properly, this will result in memory leaks as the rust heap will not be reclaimed.
//!
//! ## [cleanup_mock_server](fn.cleanup_mock_server.html)
//!
//! This function will try terminate the mock server with the given port number and cleanup any memory allocated for it by
//! the [`mock_server_mismatches`](fn.mock_server_mismatches.html) function. Returns `true`, unless a mock server with the given port number does not exist,
//! or the function fails in some way.
//!
//! **NOTE:** Although `close()` on the listerner for the mock server is called, this does not currently work and the
//! listerner will continue handling requests. In this case, it will always return a 501 once the mock server has been
//! cleaned up.
//!
//! ## [write_pact_file](fn.write_pact_file.html)
//!
//! External interface to trigger a mock server to write out its pact file. This function should
//! be called if all the consumer tests have passed. The directory to write the file to is passed
//! as the second parameter. If a NULL pointer is passed, the current working directory is used.
//!
//! Returns 0 if the pact file was successfully written. Returns a positive code if the file can
//! not be written, or there is no mock server running on that port or the function panics.

#![warn(missing_docs)]

use std::panic::catch_unwind;
use libc::c_char;
use std::ffi::CStr;
use std::ffi::CString;
use std::str;
use serde_json::json;
use pact_mock_server::{MockServerError, WritePactFileErr, MANAGER};
use pact_mock_server::server_manager::ServerManager;

/// External interface to create a mock server. A pointer to the pact JSON as a C string is passed in,
/// as well as the port for the mock server to run on. A value of 0 for the port will result in a
/// port being allocated by the operating system. The port of the mock server is returned.
///
/// # Errors
///
/// Errors are returned as negative values.
///
/// | Error | Description |
/// |-------|-------------|
/// | -1 | A null pointer was received |
/// | -2 | The pact JSON could not be parsed |
/// | -3 | The mock server could not be started |
/// | -4 | The method panicked |
/// | -5 | The address is not valid |
///
#[no_mangle]
pub extern fn create_mock_server(pact_str: *const c_char, addr_str: *const c_char) -> i32 {
    env_logger::try_init().unwrap_or(());

    let result = catch_unwind(|| {
        let c_str = unsafe {
            if pact_str.is_null() {
                log::error!("Got a null pointer instead of pact json");
                return -1;
            }
            CStr::from_ptr(pact_str)
        };

        let addr_c_str = unsafe {
            if addr_str.is_null() {
                log::error!("Got a null pointer instead of listener address");
                return -1;
            }
            CStr::from_ptr(addr_str)
        };

        if let Ok(Ok(addr)) = str::from_utf8(addr_c_str.to_bytes()).map(|s| s.parse::<std::net::SocketAddr>()) {
          match pact_mock_server::create_mock_server(str::from_utf8(c_str.to_bytes()).unwrap(), addr) {
            Ok(ms_port) => ms_port,
            Err(err) => match err {
              MockServerError::InvalidPactJson => -2,
              MockServerError::MockServerFailedToStart => -3
            }
          }
        }
        else {
          -5
        }
    });

    match result {
        Ok(val) => val,
        Err(cause) => {
            log::error!("Caught a general panic: {:?}", cause);
            -4
        }
    }
}

/// External interface to check if a mock server has matched all its requests. The port number is
/// passed in, and if all requests have been matched, true is returned. False is returned if there
/// is no mock server on the given port, or if any request has not been successfully matched, or
/// the method panics.
#[no_mangle]
pub extern fn mock_server_matched(mock_server_port: i32) -> bool {
  let result = catch_unwind(|| {
    pact_mock_server::mock_server_matched(mock_server_port)
  });

  match result {
    Ok(val) => val,
    Err(cause) => {
      log::error!("Caught a general panic: {:?}", cause);
      false
    }
  }
}

/// External interface to get all the mismatches from a mock server. The port number of the mock
/// server is passed in, and a pointer to a C string with the mismatches in JSON format is
/// returned.
///
/// **NOTE:** The JSON string for the result is allocated on the heap, and will have to be freed
/// once the code using the mock server is complete. The [`cleanup_mock_server`](fn.cleanup_mock_server.html) function is
/// provided for this purpose.
///
/// # Errors
///
/// If there is no mock server with the provided port number, or the function panics, a NULL
/// pointer will be returned. Don't try to dereference it, it will not end well for you.
///
#[no_mangle]
pub extern fn mock_server_mismatches(mock_server_port: i32) -> *mut c_char {
  let result = catch_unwind(|| {
    let result = MANAGER.lock().unwrap()
      .get_or_insert_with(ServerManager::new)
      .find_mock_server_by_port_mut(mock_server_port as u16, &|ref mut mock_server| {
        let mismatches = mock_server.mismatches().iter()
          .map(|mismatch| mismatch.to_json() )
          .collect::<Vec<serde_json::Value>>();
        let json = json!(mismatches);
        let s = CString::new(json.to_string()).unwrap();
        let p = s.as_ptr();
        mock_server.resources.push(s);
        p
      });
    match result {
      Some(p) => p as *mut _,
      None => 0 as *mut _
    }
  });

  match result {
    Ok(val) => val,
    Err(cause) => {
      log::error!("Caught a general panic: {:?}", cause);
      0 as *mut _
    }
  }
}

/// External interface to cleanup a mock server. This function will try terminate the mock server
/// with the given port number and cleanup any memory allocated for it. Returns true, unless a
/// mock server with the given port number does not exist, or the function panics.
///
/// **NOTE:** Although `close()` on the listener for the mock server is called, this does not
/// currently work and the listener will continue handling requests. In this
/// case, it will always return a 404 once the mock server has been cleaned up.
#[no_mangle]
pub extern fn cleanup_mock_server(mock_server_port: i32) -> bool {
  let result = catch_unwind(|| {
    MANAGER.lock().unwrap()
      .get_or_insert_with(ServerManager::new)
      .shutdown_mock_server_by_port(mock_server_port as u16)
  });

  match result {
    Ok(val) => val,
    Err(cause) => {
      log::error!("Caught a general panic: {:?}", cause);
      false
    }
  }
}

/// External interface to trigger a mock server to write out its pact file. This function should
/// be called if all the consumer tests have passed. The directory to write the file to is passed
/// as the second parameter. If a NULL pointer is passed, the current working directory is used.
///
/// Returns 0 if the pact file was successfully written. Returns a positive code if the file can
/// not be written, or there is no mock server running on that port or the function panics.
///
/// # Errors
///
/// Errors are returned as positive values.
///
/// | Error | Description |
/// |-------|-------------|
/// | 1 | A general panic was caught |
/// | 2 | The pact file was not able to be written |
/// | 3 | A mock server with the provided port was not found |
#[no_mangle]
pub extern fn write_pact_file(mock_server_port: i32, directory: *const c_char) -> i32 {
  let result = catch_unwind(|| {
    let dir = unsafe {
      if directory.is_null() {
        log::warn!("Directory to write to is NULL, defaulting to the current working directory");
        None
      } else {
        let c_str = CStr::from_ptr(directory);
        let dir_str = str::from_utf8(c_str.to_bytes()).unwrap();
        if dir_str.is_empty() {
          None
        } else {
          Some(dir_str.to_string())
        }
      }
    };

    pact_mock_server::write_pact_file(mock_server_port, dir)
  });

  match result {
    Ok(val) => match val {
      Ok(_) => 0,
      Err(err) => match err {
        WritePactFileErr::IOError => 2,
        WritePactFileErr::NoMockServer => 3
      }
    },
    Err(cause) => {
      log::error!("Caught a general panic: {:?}", cause);
      1
    }
  }
}
<|endoftext|>


<commit_before>use std::error;

use clap;
use config;

use super::executer::Executer;

#[allow(dead_code)]
pub struct Command<'c> {
    config: &'c config::command::Config,
    name: Option<&'c str>,
    all: bool,
}

impl<'c> Command<'c> {
    pub fn from_args(config: &'c config::command::Config, args: &'c clap::ArgMatches<'c>) -> Self {
        trace!("command::schedule_task::delete::Command::from_args");

        Command {
            config: config,
            name: args.value_of("NAME"),
            all: args.is_present("ALL"),
        }
    }

    pub fn new(config: &'c config::command::Config, name: Option<&'c str>, all: bool) -> Self {
        trace!("command::schedule_task::delete::Command::new");

        Command {
            config: config,
            name: name,
            all: all,
        }
    }

    pub fn run(&self) -> Result<(), Box<error::Error>> {
        trace!("command::schedule_task::delete::Command::run");

        if let Some(name) = self.name {
            let schedule_del_exec = Executer::new();
            try!(schedule_del_exec.run(name));
        } else if self.all {
            if let Some(schedule_config_group) = self.config.schedule_task.as_ref() {
                for schedule_config in schedule_config_group {
                    let schedule_del_exec = Executer::new();
                    try!(schedule_del_exec.run(schedule_config.name.as_str()));
                }
            }
        }

        Ok(())
    }
}
<commit_msg>Fix target name of rule to be deleted<commit_after>use std::error;

use clap;
use config;

use super::executer::Executer;

#[allow(dead_code)]
pub struct Command<'c> {
    config: &'c config::command::Config,
    name: Option<&'c str>,
    all: bool,
}

impl<'c> Command<'c> {
    pub fn from_args(config: &'c config::command::Config, args: &'c clap::ArgMatches<'c>) -> Self {
        trace!("command::schedule_task::delete::Command::from_args");

        Command {
            config: config,
            name: args.value_of("NAME"),
            all: args.is_present("ALL"),
        }
    }

    pub fn new(config: &'c config::command::Config, name: Option<&'c str>, all: bool) -> Self {
        trace!("command::schedule_task::delete::Command::new");

        Command {
            config: config,
            name: name,
            all: all,
        }
    }

    pub fn run(&self) -> Result<(), Box<error::Error>> {
        trace!("command::schedule_task::delete::Command::run");

        if let Some(name) = self.name {
            let schedule_del_exec = Executer::new();
            try!(schedule_del_exec.run(name));
        } else if self.all {
            if let Some(schedule_config_group) = self.config.schedule_task.as_ref() {
                for schedule_config in schedule_config_group {
                    let schedule_del_exec = Executer::new();
                    try!(schedule_del_exec.run(schedule_config.rule.name.as_str()));
                }
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>/// For Huffman codes used in the Deflate spec, is seems that the length of a code is at most 9 bits.
/// For this simple use case, we don't need/want to deal with type parameters.
pub type Symbol = u16;

#[derive(Debug, Clone, PartialEq)]
pub struct Node {
	left: Option<Box<Tree>>,
	right: Option<Box<Tree>>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Tree {
	Leaf(Symbol),
	Inner(Node),
}

impl Tree {
	pub fn new() -> Tree {
		Tree::Inner(Node{
			left: None,
			right: None,
		})
	}

	pub fn insert(&mut self, code: Vec<bool>, symbol: Symbol) {
		if code.len() == 1 {
			if code[0] {
				*self = Tree::Inner(Node{
					left: match self {
						&mut Tree::Inner(Node{
							ref left,
							right: _,
						}) => left.clone(),
						&mut Tree::Leaf(_) => unreachable!(),
					},
					right: Some(Box::new(Tree::Leaf(symbol))),
				});
			} else {
				*self = Tree::Inner(Node{
					left: Some(Box::new(Tree::Leaf(symbol))),
					right: match self {
						&mut Tree::Inner(Node{
							left: _,
							ref right,
						}) => right.clone(),
						&mut Tree::Leaf(_) => unreachable!(),
					},
				});
			}
		} else {
			if code[0] {
				match self {
					&mut Tree::Inner(Node{
						left: _,
						ref mut right,
					}) => {
						match right {
							&mut None => *right = Some(Box::new(Tree::new())),
							&mut Some(_) => {
								// Nothing to do
							},
						};
						// Now we can be sure that right is a subtree. So we can delegate to it.

						match right {
							&mut Some(ref mut boxed_tree) => (*boxed_tree).insert(code[1..].to_vec(), symbol),
							_ => unreachable!(),
						};
					},
					&mut Tree::Leaf(_) => unreachable!(),
				}
			} else {
				match self {
					&mut Tree::Inner(Node{
						ref mut left,
						right: _,
					}) => {
						match left {
							&mut None => *left = Some(Box::new(Tree::new())),
							&mut Some(_) => {
								// Nothing to do
							},
						};
						// Now we can be sure that left is a subtree. So we can delegate to it.

						match left {
							&mut Some(ref mut boxed_tree) => (*boxed_tree).insert(code[1..].to_vec(), symbol),
							_ => unreachable!(),
						};
					},
					&mut Tree::Leaf(_) => unreachable!(),
				}
			}
		}
	}

	pub fn lookup(&self, c: bool) -> Option<Tree> {
		match self {
			&Tree::Leaf(_) => None,
			&Tree::Inner(Node{
				ref left,
				ref right
			}) =>
				if c {
					match *right {
						Some(ref boxed_tree) => Some((**boxed_tree).clone()),
						None => None,
					}
				} else {
					match *left {
						Some(ref boxed_tree) => Some((**boxed_tree).clone()),
						None => None,
					}
				}
		}
	}
}

mod tests {
	#[test]
	fn should_create_empty_tree() {
		use super::{Tree, Node};
		use super::Tree::Inner;

		assert_eq!(Tree::new(), Inner(Node{
			left: None,
			right: None,
		}));
	}

	#[test]
	fn should_insert_first_level_leaf_on_left() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false], 666);

		assert_eq!(Inner(Node{
			left: Some(Box::new(Leaf(666))),
			right: None,
		}), tree);
	}

	#[test]
	fn should_insert_first_level_leaf_on_right() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true], 666);

		assert_eq!(Inner(Node{
			left: None,
			right: Some(Box::new(Leaf(666))),
		}), tree);
	}

	#[test]
	fn should_insert_first_level_leaf_on_left_then_on_right() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false], 667);
		tree.insert(vec![true], 666);

		assert_eq!(Inner(Node{
			left: Some(Box::new(Leaf(667))),
			right: Some(Box::new(Leaf(666))),
		}), tree);
	}

	#[test]
	fn should_insert_first_level_leaf_on_right_then_on_left() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true], 666);
		tree.insert(vec![false], 667);

		assert_eq!(Inner(Node{
			left: Some(Box::new(Leaf(667))),
			right: Some(Box::new(Leaf(666))),
		}), tree);
	}

	#[test]
	fn should_insert_second_level_leaf_left_right() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false, true], 6666);

		assert_eq!(Inner(Node{
			left: Some(Box::new(Inner(Node{
				left: None,
				right: Some(Box::new(Leaf(6666))),
			}))),
			right: None
		}), tree);
	}

	#[test]
	fn should_insert_second_level_leaf_right_left() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true, false], 6666);

		assert_eq!(Inner(Node{
			left: None,
			right: Some(Box::new(Inner(Node{
				left: Some(Box::new(Leaf(6666))),
				right: None,
			}))),
		}), tree);
	}

	#[test]
	fn should_lookup_first_level_leaf_left() {
		use super::{ Tree, Node };
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true, false], 6666);
		tree.insert(vec![false], 666);
		tree.insert(vec![true, true], 6667);

		assert_eq!(Some(Leaf(666)), tree.lookup(false));
	}

	#[test]
	fn should_lookup_first_level_leaf_right() {
		use super::{ Tree, Node };
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false, false], 6666);
		tree.insert(vec![true], 666);
		tree.insert(vec![false, true], 6667);

		assert_eq!(Some(Leaf(666)), tree.lookup(true));
	}

	#[test]
	fn should_lookup_first_level_node_left() {
		use super::{ Tree, Node };
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false, false], 6666);
		tree.insert(vec![true], 666);
		tree.insert(vec![false, true], 6667);

		assert_eq!(Some(Inner(Node{
			left: Some(Box::new(Tree::Leaf(6666))),
			right: Some(Box::new(Tree::Leaf(6667))),
		})), tree.lookup(false));
	}

	#[test]
	fn should_result_in_none() {
		use super::{ Tree, Node };
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true], 666);

		assert_eq!(None, tree.lookup(false));
	}
}
<commit_msg>MOD: preparation to hide implementation details of tree crate from user<commit_after>/// For Huffman codes used in the Deflate spec, is seems that the length of a code is at most 9 bits.
/// For this simple use case, we don't need/want to deal with type parameters.
pub type Symbol = u16;

#[derive(Debug, Clone, PartialEq)]
pub struct Node {
	left: Option<Box<Tree>>,
	right: Option<Box<Tree>>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Tree {
	Leaf(Symbol),
	Inner(Node),
}

const EMPTY_NODE: Tree = Tree::Inner(Node{
	left: None,
	right: None,
});

impl Tree {
	pub fn new() -> Tree {
		EMPTY_NODE
	}

	pub fn is_empty(&self) -> bool {
		*self == EMPTY_NODE
	}

	pub fn insert(&mut self, code: Vec<bool>, symbol: Symbol) {
		if code.len() == 1 {
			if code[0] {
				*self = Tree::Inner(Node{
					left: match self {
						&mut Tree::Inner(Node{
							ref left,
							right: _,
						}) => left.clone(),
						&mut Tree::Leaf(_) => unreachable!(),
					},
					right: Some(Box::new(Tree::Leaf(symbol))),
				});
			} else {
				*self = Tree::Inner(Node{
					left: Some(Box::new(Tree::Leaf(symbol))),
					right: match self {
						&mut Tree::Inner(Node{
							left: _,
							ref right,
						}) => right.clone(),
						&mut Tree::Leaf(_) => unreachable!(),
					},
				});
			}
		} else {
			if code[0] {
				match self {
					&mut Tree::Inner(Node{
						left: _,
						ref mut right,
					}) => {
						match right {
							&mut None => *right = Some(Box::new(Tree::new())),
							&mut Some(_) => {
								// Nothing to do
							},
						};
						// Now we can be sure that right is a subtree. So we can delegate to it.

						match right {
							&mut Some(ref mut boxed_tree) => (*boxed_tree).insert(code[1..].to_vec(), symbol),
							_ => unreachable!(),
						};
					},
					&mut Tree::Leaf(_) => unreachable!(),
				}
			} else {
				match self {
					&mut Tree::Inner(Node{
						ref mut left,
						right: _,
					}) => {
						match left {
							&mut None => *left = Some(Box::new(Tree::new())),
							&mut Some(_) => {
								// Nothing to do
							},
						};
						// Now we can be sure that left is a subtree. So we can delegate to it.

						match left {
							&mut Some(ref mut boxed_tree) => (*boxed_tree).insert(code[1..].to_vec(), symbol),
							_ => unreachable!(),
						};
					},
					&mut Tree::Leaf(_) => unreachable!(),
				}
			}
		}
	}

	pub fn lookup(&self, c: bool) -> Option<Tree> {
		match self {
			&Tree::Leaf(_) => None,
			&Tree::Inner(Node{
				ref left,
				ref right
			}) =>
				if c {
					match *right {
						Some(ref boxed_tree) => Some((**boxed_tree).clone()),
						None => None,
					}
				} else {
					match *left {
						Some(ref boxed_tree) => Some((**boxed_tree).clone()),
						None => None,
					}
				}
		}
	}
}

// These are not very good tests, because they rely
// on implementation details, for the tree data structure
mod tests {
	#[test]
	fn should_create_empty_tree() {
		use super::Tree;
		assert!(Tree::new().is_empty());
	}

	#[test]
	fn should_create_different_instances() {
		use super::Tree;
		let mut tree_0 = Tree::new();
		let mut tree_1 = Tree::new();

		tree_0.insert(vec![false], 666);
		assert!(!tree_0.is_empty());
		assert!(tree_1.is_empty());
	}

	#[test]
	fn should_insert_first_level_leaf_on_left() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false], 666);

		assert_eq!(Inner(Node{
			left: Some(Box::new(Leaf(666))),
			right: None,
		}), tree);
	}

	#[test]
	fn should_insert_first_level_leaf_on_right() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true], 666);

		assert_eq!(Inner(Node{
			left: None,
			right: Some(Box::new(Leaf(666))),
		}), tree);
	}

	#[test]
	fn should_insert_first_level_leaf_on_left_then_on_right() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false], 667);
		tree.insert(vec![true], 666);

		assert_eq!(Inner(Node{
			left: Some(Box::new(Leaf(667))),
			right: Some(Box::new(Leaf(666))),
		}), tree);
	}

	#[test]
	fn should_insert_first_level_leaf_on_right_then_on_left() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true], 666);
		tree.insert(vec![false], 667);

		assert_eq!(Inner(Node{
			left: Some(Box::new(Leaf(667))),
			right: Some(Box::new(Leaf(666))),
		}), tree);
	}

	#[test]
	fn should_insert_second_level_leaf_left_right() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false, true], 6666);

		assert_eq!(Inner(Node{
			left: Some(Box::new(Inner(Node{
				left: None,
				right: Some(Box::new(Leaf(6666))),
			}))),
			right: None
		}), tree);
	}

	#[test]
	fn should_insert_second_level_leaf_right_left() {
		use super::{Tree, Node};
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true, false], 6666);

		assert_eq!(Inner(Node{
			left: None,
			right: Some(Box::new(Inner(Node{
				left: Some(Box::new(Leaf(6666))),
				right: None,
			}))),
		}), tree);
	}

	#[test]
	fn should_lookup_first_level_leaf_left() {
		use super::{ Tree, Node };
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true, false], 6666);
		tree.insert(vec![false], 666);
		tree.insert(vec![true, true], 6667);

		assert_eq!(Some(Leaf(666)), tree.lookup(false));
	}

	#[test]
	fn should_lookup_first_level_leaf_right() {
		use super::{ Tree, Node };
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false, false], 6666);
		tree.insert(vec![true], 666);
		tree.insert(vec![false, true], 6667);

		assert_eq!(Some(Leaf(666)), tree.lookup(true));
	}

	#[test]
	fn should_lookup_first_level_node_left() {
		use super::{ Tree, Node };
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![false, false], 6666);
		tree.insert(vec![true], 666);
		tree.insert(vec![false, true], 6667);

		assert_eq!(Some(Inner(Node{
			left: Some(Box::new(Tree::Leaf(6666))),
			right: Some(Box::new(Tree::Leaf(6667))),
		})), tree.lookup(false));
	}

	#[test]
	fn should_result_in_none() {
		use super::{ Tree, Node };
		use super::Tree::{ Inner, Leaf };

		let mut tree = Tree::new();
		tree.insert(vec![true], 666);

		assert_eq!(None, tree.lookup(false));
	}
}
<|endoftext|>


<commit_before>use crate::{build, shim};
use rustc_index::vec::IndexVec;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::mir::{Body, MirPhase, Promoted};
use rustc::ty::{TyCtxt, InstanceDef};
use rustc::ty::query::Providers;
use rustc::ty::steal::Steal;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::util::nodemap::DefIdSet;
use std::borrow::Cow;
use syntax::ast;
use syntax_pos::Span;

pub mod add_retag;
pub mod add_moves_for_packed_drops;
pub mod cleanup_post_borrowck;
pub mod check_consts;
pub mod check_unsafety;
pub mod simplify_branches;
pub mod simplify;
pub mod erase_regions;
pub mod no_landing_pads;
pub mod rustc_peek;
pub mod elaborate_drops;
pub mod add_call_guards;
pub mod promote_consts;
pub mod qualify_consts;
pub mod qualify_min_const_fn;
pub mod remove_noop_landing_pads;
pub mod dump_mir;
pub mod deaggregator;
pub mod instcombine;
pub mod copy_prop;
pub mod const_prop;
pub mod generator;
pub mod inline;
pub mod uniform_array_move_out;
pub mod uninhabited_enum_branching;

pub(crate) fn provide(providers: &mut Providers<'_>) {
    self::qualify_consts::provide(providers);
    self::check_unsafety::provide(providers);
    *providers = Providers {
        mir_keys,
        mir_built,
        mir_const,
        mir_validated,
        optimized_mir,
        is_mir_available,
        promoted_mir,
        ..*providers
    };
}

fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    tcx.mir_keys(def_id.krate).contains(&def_id)
}

/// Finds the full set of `DefId`s within the current crate that have
/// MIR associated with them.
fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> &DefIdSet {
    assert_eq!(krate, LOCAL_CRATE);

    let mut set = DefIdSet::default();

    // All body-owners have MIR associated with them.
    set.extend(tcx.body_owners());

    // Additionally, tuple struct/variant constructors have MIR, but
    // they don't have a BodyId, so we need to build them separately.
    struct GatherCtors<'a, 'tcx> {
        tcx: TyCtxt<'tcx>,
        set: &'a mut DefIdSet,
    }
    impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
        fn visit_variant_data(&mut self,
                              v: &'tcx hir::VariantData,
                              _: ast::Name,
                              _: &'tcx hir::Generics,
                              _: hir::HirId,
                              _: Span) {
            if let hir::VariantData::Tuple(_, hir_id) = *v {
                self.set.insert(self.tcx.hir().local_def_id(hir_id));
            }
            intravisit::walk_struct_def(self, v)
        }
        fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
            NestedVisitorMap::None
        }
    }
    tcx.hir().krate().visit_all_item_likes(&mut GatherCtors {
        tcx,
        set: &mut set,
    }.as_deep_visitor());

    tcx.arena.alloc(set)
}

fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<Body<'_>> {
    let mir = build::mir_build(tcx, def_id);
    tcx.alloc_steal_mir(mir)
}

/// Where a specific `mir::Body` comes from.
#[derive(Debug, Copy, Clone)]
pub struct MirSource<'tcx> {
    pub instance: InstanceDef<'tcx>,

    /// If `Some`, this is a promoted rvalue within the parent function.
    pub promoted: Option<Promoted>,
}

impl<'tcx> MirSource<'tcx> {
    pub fn item(def_id: DefId) -> Self {
        MirSource {
            instance: InstanceDef::Item(def_id),
            promoted: None
        }
    }

    #[inline]
    pub fn def_id(&self) -> DefId {
        self.instance.def_id()
    }
}

/// Generates a default name for the pass based on the name of the
/// type `T`.
pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
    let name = ::std::any::type_name::<T>();
    if let Some(tail) = name.rfind(":") {
        Cow::from(&name[tail+1..])
    } else {
        Cow::from(name)
    }
}

/// A streamlined trait that you can implement to create a pass; the
/// pass will be named after the type, and it will consist of a main
/// loop that goes over each available MIR and applies `run_pass`.
pub trait MirPass<'tcx> {
    fn name(&self) -> Cow<'_, str> {
        default_name::<Self>()
    }

    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>);
}

pub fn run_passes(
    tcx: TyCtxt<'tcx>,
    body: &mut Body<'tcx>,
    instance: InstanceDef<'tcx>,
    promoted: Option<Promoted>,
    mir_phase: MirPhase,
    passes: &[&dyn MirPass<'tcx>],
) {
    let phase_index = mir_phase.phase_index();

    if body.phase >= mir_phase {
        return;
    }

    let source = MirSource {
        instance,
        promoted,
    };
    let mut index = 0;
    let mut run_pass = |pass: &dyn MirPass<'tcx>| {
        let run_hooks = |body: &_, index, is_after| {
            dump_mir::on_mir_pass(tcx, &format_args!("{:03}-{:03}", phase_index, index),
                                    &pass.name(), source, body, is_after);
        };
        run_hooks(body, index, false);
        pass.run_pass(tcx, source, body);
        run_hooks(body, index, true);

        index += 1;
    };

    for pass in passes {
        run_pass(*pass);
    }

    body.phase = mir_phase;
}

fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<Body<'_>> {
    // Unsafety check uses the raw mir, so make sure it is run
    let _ = tcx.unsafety_check_result(def_id);

    let mut body = tcx.mir_built(def_id).steal();
    run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Const, &[
        // What we need to do constant evaluation.
        &simplify::SimplifyCfg::new("initial"),
        &rustc_peek::SanityCheck,
        &uniform_array_move_out::UniformArrayMoveOut,
    ]);
    tcx.alloc_steal_mir(body)
}

fn mir_validated(
    tcx: TyCtxt<'tcx>,
    def_id: DefId,
) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
    if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(hir_id) {
        // Ensure that we compute the `mir_const_qualif` for constants at
        // this point, before we steal the mir-const result.
        let _ = tcx.mir_const_qualif(def_id);
    }

    let mut body = tcx.mir_const(def_id).steal();
    let promote_pass = promote_consts::PromoteTemps::default();
    run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Validated, &[
        // What we need to run borrowck etc.
        &qualify_consts::QualifyAndPromoteConstants::default(),
        &promote_pass,
        &simplify::SimplifyCfg::new("qualify-consts"),
    ]);
    let promoted = promote_pass.promoted_fragments.into_inner();
    (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
}

fn run_optimization_passes<'tcx>(
    tcx: TyCtxt<'tcx>,
    body: &mut Body<'tcx>,
    def_id: DefId,
    promoted: Option<Promoted>,
) {
    run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[
        // Remove all things only needed by analysis
        &no_landing_pads::NoLandingPads::new(tcx),
        &simplify_branches::SimplifyBranches::new("initial"),
        &remove_noop_landing_pads::RemoveNoopLandingPads,
        &cleanup_post_borrowck::CleanupNonCodegenStatements,

        &simplify::SimplifyCfg::new("early-opt"),

        // These next passes must be executed together
        &add_call_guards::CriticalCallEdges,
        &elaborate_drops::ElaborateDrops,
        &no_landing_pads::NoLandingPads::new(tcx),
        // AddMovesForPackedDrops needs to run after drop
        // elaboration.
        &add_moves_for_packed_drops::AddMovesForPackedDrops,
        // AddRetag needs to run after ElaborateDrops, and it needs
        // an AllCallEdges pass right before it.  Otherwise it should
        // run fairly late, but before optimizations begin.
        &add_call_guards::AllCallEdges,
        &add_retag::AddRetag,

        &simplify::SimplifyCfg::new("elaborate-drops"),

        // No lifetime analysis based on borrowing can be done from here on out.

        // From here on out, regions are gone.
        &erase_regions::EraseRegions,

        // Optimizations begin.
        &uninhabited_enum_branching::UninhabitedEnumBranching,
        &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
        &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
        &inline::Inline,

        // Lowering generator control-flow and variables
        // has to happen before we do anything else to them.
        &generator::StateTransform,

        &instcombine::InstCombine,
        &const_prop::ConstProp,
        &simplify_branches::SimplifyBranches::new("after-const-prop"),
        &deaggregator::Deaggregator,
        &copy_prop::CopyPropagation,
        &simplify_branches::SimplifyBranches::new("after-copy-prop"),
        &remove_noop_landing_pads::RemoveNoopLandingPads,
        &simplify::SimplifyCfg::new("final"),
        &simplify::SimplifyLocals,

        &add_call_guards::CriticalCallEdges,
        &dump_mir::Marker("PreCodegen"),
    ]);
}

fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> {
    if tcx.is_constructor(def_id) {
        // There's no reason to run all of the MIR passes on constructors when
        // we can just output the MIR we want directly. This also saves const
        // qualification and borrow checking the trouble of special casing
        // constructors.
        return shim::build_adt_ctor(tcx, def_id);
    }

    // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
    // execute before we can steal.
    tcx.ensure().mir_borrowck(def_id);

    let (body, _) = tcx.mir_validated(def_id);
    let mut body = body.steal();
    run_optimization_passes(tcx, &mut body, def_id, None);
    tcx.arena.alloc(body)
}

fn promoted_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
    if tcx.is_constructor(def_id) {
        return tcx.intern_promoted(IndexVec::new());
    }

    tcx.ensure().mir_borrowck(def_id);
    let (_, promoted) = tcx.mir_validated(def_id);
    let mut promoted = promoted.steal();

    for (p, mut body) in promoted.iter_enumerated_mut() {
        run_optimization_passes(tcx, &mut body, def_id, Some(p));
    }

    tcx.intern_promoted(promoted)
}
<commit_msg>Use new const-checker for `mir_const_qualif`<commit_after>use crate::{build, shim};
use rustc_index::vec::IndexVec;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::mir::{Body, MirPhase, Promoted};
use rustc::ty::{TyCtxt, InstanceDef, TypeFoldable};
use rustc::ty::query::Providers;
use rustc::ty::steal::Steal;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::util::nodemap::DefIdSet;
use std::borrow::Cow;
use syntax::ast;
use syntax_pos::Span;

pub mod add_retag;
pub mod add_moves_for_packed_drops;
pub mod cleanup_post_borrowck;
pub mod check_consts;
pub mod check_unsafety;
pub mod simplify_branches;
pub mod simplify;
pub mod erase_regions;
pub mod no_landing_pads;
pub mod rustc_peek;
pub mod elaborate_drops;
pub mod add_call_guards;
pub mod promote_consts;
pub mod qualify_consts;
pub mod qualify_min_const_fn;
pub mod remove_noop_landing_pads;
pub mod dump_mir;
pub mod deaggregator;
pub mod instcombine;
pub mod copy_prop;
pub mod const_prop;
pub mod generator;
pub mod inline;
pub mod uniform_array_move_out;
pub mod uninhabited_enum_branching;

pub(crate) fn provide(providers: &mut Providers<'_>) {
    self::check_unsafety::provide(providers);
    *providers = Providers {
        mir_keys,
        mir_built,
        mir_const,
        mir_const_qualif,
        mir_validated,
        optimized_mir,
        is_mir_available,
        promoted_mir,
        ..*providers
    };
}

fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    tcx.mir_keys(def_id.krate).contains(&def_id)
}

/// Finds the full set of `DefId`s within the current crate that have
/// MIR associated with them.
fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> &DefIdSet {
    assert_eq!(krate, LOCAL_CRATE);

    let mut set = DefIdSet::default();

    // All body-owners have MIR associated with them.
    set.extend(tcx.body_owners());

    // Additionally, tuple struct/variant constructors have MIR, but
    // they don't have a BodyId, so we need to build them separately.
    struct GatherCtors<'a, 'tcx> {
        tcx: TyCtxt<'tcx>,
        set: &'a mut DefIdSet,
    }
    impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
        fn visit_variant_data(&mut self,
                              v: &'tcx hir::VariantData,
                              _: ast::Name,
                              _: &'tcx hir::Generics,
                              _: hir::HirId,
                              _: Span) {
            if let hir::VariantData::Tuple(_, hir_id) = *v {
                self.set.insert(self.tcx.hir().local_def_id(hir_id));
            }
            intravisit::walk_struct_def(self, v)
        }
        fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
            NestedVisitorMap::None
        }
    }
    tcx.hir().krate().visit_all_item_likes(&mut GatherCtors {
        tcx,
        set: &mut set,
    }.as_deep_visitor());

    tcx.arena.alloc(set)
}

fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<Body<'_>> {
    let mir = build::mir_build(tcx, def_id);
    tcx.alloc_steal_mir(mir)
}

/// Where a specific `mir::Body` comes from.
#[derive(Debug, Copy, Clone)]
pub struct MirSource<'tcx> {
    pub instance: InstanceDef<'tcx>,

    /// If `Some`, this is a promoted rvalue within the parent function.
    pub promoted: Option<Promoted>,
}

impl<'tcx> MirSource<'tcx> {
    pub fn item(def_id: DefId) -> Self {
        MirSource {
            instance: InstanceDef::Item(def_id),
            promoted: None
        }
    }

    #[inline]
    pub fn def_id(&self) -> DefId {
        self.instance.def_id()
    }
}

/// Generates a default name for the pass based on the name of the
/// type `T`.
pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
    let name = ::std::any::type_name::<T>();
    if let Some(tail) = name.rfind(":") {
        Cow::from(&name[tail+1..])
    } else {
        Cow::from(name)
    }
}

/// A streamlined trait that you can implement to create a pass; the
/// pass will be named after the type, and it will consist of a main
/// loop that goes over each available MIR and applies `run_pass`.
pub trait MirPass<'tcx> {
    fn name(&self) -> Cow<'_, str> {
        default_name::<Self>()
    }

    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>);
}

pub fn run_passes(
    tcx: TyCtxt<'tcx>,
    body: &mut Body<'tcx>,
    instance: InstanceDef<'tcx>,
    promoted: Option<Promoted>,
    mir_phase: MirPhase,
    passes: &[&dyn MirPass<'tcx>],
) {
    let phase_index = mir_phase.phase_index();

    if body.phase >= mir_phase {
        return;
    }

    let source = MirSource {
        instance,
        promoted,
    };
    let mut index = 0;
    let mut run_pass = |pass: &dyn MirPass<'tcx>| {
        let run_hooks = |body: &_, index, is_after| {
            dump_mir::on_mir_pass(tcx, &format_args!("{:03}-{:03}", phase_index, index),
                                    &pass.name(), source, body, is_after);
        };
        run_hooks(body, index, false);
        pass.run_pass(tcx, source, body);
        run_hooks(body, index, true);

        index += 1;
    };

    for pass in passes {
        run_pass(*pass);
    }

    body.phase = mir_phase;
}

fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
    let const_kind = check_consts::ConstKind::for_item(tcx, def_id);

    // No need to const-check a non-const `fn`.
    if const_kind.is_none() {
        return 0;
    }

    // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
    // cannot yet be stolen), because `mir_validated()`, which steals
    // from `mir_const(), forces this query to execute before
    // performing the steal.
    let body = &tcx.mir_const(def_id).borrow();

    if body.return_ty().references_error() {
        tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
        return 0;
    }

    let item = check_consts::Item {
        body,
        tcx,
        def_id,
        const_kind,
        param_env: tcx.param_env(def_id),
    };

    let mut validator = check_consts::validation::Validator::new(&item);
    validator.check_body();

    // We return the qualifs in the return place for every MIR body, even though it is only used
    // when deciding to promote a reference to a `const` for now.
    validator.qualifs_in_return_place().into()
}

fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<Body<'_>> {
    // Unsafety check uses the raw mir, so make sure it is run
    let _ = tcx.unsafety_check_result(def_id);

    let mut body = tcx.mir_built(def_id).steal();
    run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Const, &[
        // What we need to do constant evaluation.
        &simplify::SimplifyCfg::new("initial"),
        &rustc_peek::SanityCheck,
        &uniform_array_move_out::UniformArrayMoveOut,
    ]);
    tcx.alloc_steal_mir(body)
}

fn mir_validated(
    tcx: TyCtxt<'tcx>,
    def_id: DefId,
) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
    if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(hir_id) {
        // Ensure that we compute the `mir_const_qualif` for constants at
        // this point, before we steal the mir-const result.
        let _ = tcx.mir_const_qualif(def_id);
    }

    let mut body = tcx.mir_const(def_id).steal();
    let promote_pass = promote_consts::PromoteTemps::default();
    run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Validated, &[
        // What we need to run borrowck etc.
        &qualify_consts::QualifyAndPromoteConstants::default(),
        &promote_pass,
        &simplify::SimplifyCfg::new("qualify-consts"),
    ]);
    let promoted = promote_pass.promoted_fragments.into_inner();
    (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
}

fn run_optimization_passes<'tcx>(
    tcx: TyCtxt<'tcx>,
    body: &mut Body<'tcx>,
    def_id: DefId,
    promoted: Option<Promoted>,
) {
    run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[
        // Remove all things only needed by analysis
        &no_landing_pads::NoLandingPads::new(tcx),
        &simplify_branches::SimplifyBranches::new("initial"),
        &remove_noop_landing_pads::RemoveNoopLandingPads,
        &cleanup_post_borrowck::CleanupNonCodegenStatements,

        &simplify::SimplifyCfg::new("early-opt"),

        // These next passes must be executed together
        &add_call_guards::CriticalCallEdges,
        &elaborate_drops::ElaborateDrops,
        &no_landing_pads::NoLandingPads::new(tcx),
        // AddMovesForPackedDrops needs to run after drop
        // elaboration.
        &add_moves_for_packed_drops::AddMovesForPackedDrops,
        // AddRetag needs to run after ElaborateDrops, and it needs
        // an AllCallEdges pass right before it.  Otherwise it should
        // run fairly late, but before optimizations begin.
        &add_call_guards::AllCallEdges,
        &add_retag::AddRetag,

        &simplify::SimplifyCfg::new("elaborate-drops"),

        // No lifetime analysis based on borrowing can be done from here on out.

        // From here on out, regions are gone.
        &erase_regions::EraseRegions,

        // Optimizations begin.
        &uninhabited_enum_branching::UninhabitedEnumBranching,
        &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
        &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
        &inline::Inline,

        // Lowering generator control-flow and variables
        // has to happen before we do anything else to them.
        &generator::StateTransform,

        &instcombine::InstCombine,
        &const_prop::ConstProp,
        &simplify_branches::SimplifyBranches::new("after-const-prop"),
        &deaggregator::Deaggregator,
        &copy_prop::CopyPropagation,
        &simplify_branches::SimplifyBranches::new("after-copy-prop"),
        &remove_noop_landing_pads::RemoveNoopLandingPads,
        &simplify::SimplifyCfg::new("final"),
        &simplify::SimplifyLocals,

        &add_call_guards::CriticalCallEdges,
        &dump_mir::Marker("PreCodegen"),
    ]);
}

fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> {
    if tcx.is_constructor(def_id) {
        // There's no reason to run all of the MIR passes on constructors when
        // we can just output the MIR we want directly. This also saves const
        // qualification and borrow checking the trouble of special casing
        // constructors.
        return shim::build_adt_ctor(tcx, def_id);
    }

    // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
    // execute before we can steal.
    tcx.ensure().mir_borrowck(def_id);

    let (body, _) = tcx.mir_validated(def_id);
    let mut body = body.steal();
    run_optimization_passes(tcx, &mut body, def_id, None);
    tcx.arena.alloc(body)
}

fn promoted_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
    if tcx.is_constructor(def_id) {
        return tcx.intern_promoted(IndexVec::new());
    }

    tcx.ensure().mir_borrowck(def_id);
    let (_, promoted) = tcx.mir_validated(def_id);
    let mut promoted = promoted.steal();

    for (p, mut body) in promoted.iter_enumerated_mut() {
        run_optimization_passes(tcx, &mut body, def_id, Some(p));
    }

    tcx.intern_promoted(promoted)
}
<|endoftext|>


<commit_before>//! Check that public constants have documentation

use syntax::ast::{Item, Item_, Visibility};
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, LintContext};

declare_lint!(PRIV_MISSING_DOCS, Warn,
    "Warn about private traits, impls, functions and const items without \
    documentation");

pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(PRIV_MISSING_DOCS)
    }
}

impl EarlyLintPass for Pass {
    fn check_item(&mut self, cx: &EarlyContext, i: &Item) {
        match i.node {
            Item_::ItemConst(..) | Item_::ItemFn(..) |
                Item_::ItemImpl(..) | Item_::ItemTrait(..) |
                Item_::ItemStruct(..) | Item_::ItemEnum(..) |
                Item_::ItemMod(..) => {
                    if let Visibility::Public = i.vis {
                        // Publicly visible items are handled by other lints
                        return;
                    }

                    let doc_found = i.attrs.iter().find(
                        |a| a.node.is_sugared_doc);
                    if let None = doc_found {
                        cx.span_lint(PRIV_MISSING_DOCS, i.span,
                                    "private item is missing documentation");
                    }
            },

            _ => return,
        }
    }
}
<commit_msg>Fix incorrect documentation<commit_after>//! Check that private traits, impls, functions and const items have docs

use syntax::ast::{Item, Item_, Visibility};
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, LintContext};

declare_lint!(PRIV_MISSING_DOCS, Warn,
    "Warn about private traits, impls, functions and const items without \
    documentation");

pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(PRIV_MISSING_DOCS)
    }
}

impl EarlyLintPass for Pass {
    fn check_item(&mut self, cx: &EarlyContext, i: &Item) {
        match i.node {
            Item_::ItemConst(..) | Item_::ItemFn(..) |
                Item_::ItemImpl(..) | Item_::ItemTrait(..) |
                Item_::ItemStruct(..) | Item_::ItemEnum(..) |
                Item_::ItemMod(..) => {
                    if let Visibility::Public = i.vis {
                        // Publicly visible items are handled by other lints
                        return;
                    }

                    let doc_found = i.attrs.iter().find(
                        |a| a.node.is_sugared_doc);
                    if let None = doc_found {
                        cx.span_lint(PRIV_MISSING_DOCS, i.span,
                                    "private item is missing documentation");
                    }
            },

            _ => return,
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>If TT is full but key already exists, update it<commit_after><|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{
    conversion::ConvertError,
    types::{make_ident, QualifiedName},
};
use indoc::indoc;
use once_cell::sync::OnceCell;
use std::collections::HashMap;
use syn::{parse_quote, Type, TypePath, TypePtr};

//// The behavior of the type.
#[derive(Debug)]
enum Behavior {
    CxxContainerByValueSafe,
    CxxContainerNotByValueSafe,
    CxxString,
    RustStr,
    RustString,
    RustByValue,
    CByValue,
    CVariableLengthByValue,
    CVoid,
    RustContainerByValueSafe,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    //// The behavior of the type.
    behavior: Behavior,
    /// Any extra non-canonical names
    extra_non_canonical_name: Option<String>,
}

impl TypeDetails {
    fn new(
        rs_name: impl Into<String>,
        cpp_name: impl Into<String>,
        behavior: Behavior,
        extra_non_canonical_name: Option<String>,
    ) -> Self {
        TypeDetails {
            rs_name: rs_name.into(),
            cpp_name: cpp_name.into(),
            behavior,
            extra_non_canonical_name,
        }
    }

    /// Whether and how to include this in the prelude given to bindgen.
    fn get_prelude_entry(&self) -> Option<String> {
        match self.behavior {
            Behavior::RustString
            | Behavior::RustStr
            | Behavior::CxxString
            | Behavior::CxxContainerByValueSafe
            | Behavior::CxxContainerNotByValueSafe
            | Behavior::RustContainerByValueSafe => {
                let tn = QualifiedName::new_from_cpp_name(&self.rs_name);
                let cxx_name = tn.get_final_item();
                let (templating, payload) = match self.behavior {
                    Behavior::CxxContainerByValueSafe
                    | Behavior::CxxContainerNotByValueSafe
                    | Behavior::RustContainerByValueSafe => ("template<typename T> ", "T* ptr"),
                    _ => ("", "char* ptr"),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};

                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
            _ => None,
        }
    }

    fn to_type_path(&self) -> TypePath {
        let mut segs = self.rs_name.split("::").peekable();
        if segs.peek().map(|seg| seg.is_empty()).unwrap_or_default() {
            segs.next();
            let segs = segs.into_iter().map(make_ident);
            parse_quote! {
                ::#(#segs)::*
            }
        } else {
            let segs = segs.into_iter().map(make_ident);
            parse_quote! {
                #(#segs)::*
            }
        }
    }

    fn to_typename(&self) -> QualifiedName {
        QualifiedName::new_from_cpp_name(&self.rs_name)
    }

    fn get_generic_behavior(&self) -> CxxGenericType {
        match self.behavior {
            Behavior::CxxContainerByValueSafe | Behavior::CxxContainerNotByValueSafe => {
                CxxGenericType::Cpp
            }
            Behavior::RustContainerByValueSafe => CxxGenericType::Rust,
            _ => CxxGenericType::Not,
        }
    }
}

/// Database of known types.
#[derive(Default)]
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<QualifiedName, TypeDetails>,
    canonical_names: HashMap<QualifiedName, QualifiedName>,
}

/// Returns a database of known types.
pub(crate) fn known_types() -> &'static TypeDatabase {
    static KNOWN_TYPES: OnceCell<TypeDatabase> = OnceCell::new();
    KNOWN_TYPES.get_or_init(create_type_database)
}

/// The type of payload that a cxx generic can contain.
#[derive(PartialEq, Clone, Copy)]
pub enum CxxGenericType {
    /// Not a generic at all
    Not,
    /// Some generic like cxx::UniquePtr where the contents must be a
    /// complete type.
    Cpp,
    /// Some generic like rust::Box where forward declarations are OK
    Rust,
}

impl TypeDatabase {
    fn get(&self, ty: &QualifiedName) -> Option<&TypeDetails> {
        // The following line is important. It says that
        // when we encounter something like 'std::unique_ptr'
        // in the bindgen-generated bindings, we'll immediately
        // start to refer to that as 'UniquePtr' henceforth.
        let canonical_name = self.canonical_names.get(ty).unwrap_or(ty);
        self.by_rs_name.get(canonical_name)
    }

    /// Prelude of C++ for squirting into bindgen. This configures
    /// bindgen to output simpler types to replace some STL types
    /// that bindgen just can't cope with. Although we then replace
    /// those types with cxx types (e.g. UniquePtr), this intermediate
    /// step is still necessary because bindgen can't otherwise
    /// give us the templated types (e.g. when faced with the STL
    /// unique_ptr, bindgen would normally give us std_unique_ptr
    /// as opposed to std_unique_ptr<T>.)
    pub(crate) fn get_prelude(&self) -> String {
        itertools::join(
            self.by_rs_name
                .values()
                .filter_map(|t| t.get_prelude_entry()),
            "\n",
        )
    }

    /// Types which are known to be safe (or unsafe) to hold and pass by
    /// value in Rust.
    pub(crate) fn get_pod_safe_types(&self) -> impl Iterator<Item = (QualifiedName, bool)> {
        let pod_safety = self
            .canonical_names
            .keys()
            .chain(self.by_rs_name.keys())
            .map(|tn| {
                (
                    tn.clone(),
                    match self.get(tn).unwrap().behavior {
                        Behavior::CxxContainerByValueSafe
                        | Behavior::RustStr
                        | Behavior::RustString
                        | Behavior::RustByValue
                        | Behavior::CByValue
                        | Behavior::CVariableLengthByValue
                        | Behavior::RustContainerByValueSafe => true,
                        Behavior::CxxString
                        | Behavior::CxxContainerNotByValueSafe
                        | Behavior::CVoid => false,
                    },
                )
            })
            .collect::<HashMap<_, _>>();
        pod_safety.into_iter()
    }

    /// Whether this TypePath should be treated as a value in C++
    /// but a reference in Rust. This only applies to rust::Str
    /// (C++ name) which is &str in Rust.
    pub(crate) fn should_dereference_in_cpp(&self, tn: &QualifiedName) -> bool {
        self.get(tn)
            .map(|td| matches!(td.behavior, Behavior::RustStr))
            .unwrap_or(false)
    }

    /// Here we substitute any names which we know are Special from
    /// our type database, e.g. std::unique_ptr -> UniquePtr.
    /// We strip off and ignore
    /// any PathArguments within this TypePath - callers should
    /// put them back again if needs be.
    pub(crate) fn consider_substitution(&self, tn: &QualifiedName) -> Option<TypePath> {
        self.get(tn).map(|td| td.to_type_path())
    }

    pub(crate) fn special_cpp_name(&self, rs: &QualifiedName) -> Option<String> {
        self.get(rs).map(|x| x.cpp_name.to_string())
    }

    pub(crate) fn is_known_type(&self, ty: &QualifiedName) -> bool {
        self.get(ty).is_some()
    }

    pub(crate) fn known_type_type_path(&self, ty: &QualifiedName) -> Option<TypePath> {
        self.get(ty).map(|td| td.to_type_path())
    }

    /// Get the list of types to give to bindgen to ask it _not_ to
    /// generate code for.
    pub(crate) fn get_initial_blocklist(&self) -> impl Iterator<Item = &str> + '_ {
        self.by_rs_name
            .iter()
            .filter_map(|(_, td)| td.get_prelude_entry().map(|_| td.cpp_name.as_str()))
    }

    /// Whether this is one of the ctypes (mostly variable length integers)
    /// which we need to wrap.
    pub(crate) fn is_ctype(&self, ty: &QualifiedName) -> bool {
        self.get(ty)
            .map(|td| {
                matches!(
                    td.behavior,
                    Behavior::CVariableLengthByValue | Behavior::CVoid
                )
            })
            .unwrap_or(false)
    }

    /// Whether this is a generic type acceptable to cxx. Otherwise,
    /// if we encounter a generic, we'll replace it with a synthesized concrete
    /// type.
    pub(crate) fn cxx_generic_behavior(&self, ty: &QualifiedName) -> CxxGenericType {
        self.get(ty)
            .map(|x| x.get_generic_behavior())
            .unwrap_or(CxxGenericType::Not)
    }

    pub(crate) fn is_cxx_acceptable_receiver(&self, ty: &QualifiedName) -> bool {
        self.get(ty).is_none() // at present, none of our known types can have
                               // methods attached.
    }

    pub(crate) fn conflicts_with_built_in_type(&self, ty: &QualifiedName) -> bool {
        self.get(ty).is_some()
    }

    pub(crate) fn convertible_from_strs(&self, ty: &QualifiedName) -> bool {
        self.get(ty)
            .map(|x| matches!(x.behavior, Behavior::CxxString))
            .unwrap_or(false)
    }

    fn insert(&mut self, td: TypeDetails) {
        let rs_name = td.to_typename();
        if let Some(extra_non_canonical_name) = &td.extra_non_canonical_name {
            self.canonical_names.insert(
                QualifiedName::new_from_cpp_name(extra_non_canonical_name),
                rs_name.clone(),
            );
        }
        self.canonical_names.insert(
            QualifiedName::new_from_cpp_name(&td.cpp_name),
            rs_name.clone(),
        );
        self.by_rs_name.insert(rs_name, td);
    }
}

fn create_type_database() -> TypeDatabase {
    let mut db = TypeDatabase::default();
    db.insert(TypeDetails::new(
        "cxx::UniquePtr",
        "std::unique_ptr",
        Behavior::CxxContainerByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "cxx::CxxVector",
        "std::vector",
        Behavior::CxxContainerNotByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "cxx::SharedPtr",
        "std::shared_ptr",
        Behavior::CxxContainerByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "cxx::WeakPtr",
        "std::weak_ptr",
        Behavior::CxxContainerByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "cxx::CxxString",
        "std::string",
        Behavior::CxxString,
        None,
    ));
    db.insert(TypeDetails::new(
        "str",
        "rust::Str",
        Behavior::RustStr,
        None,
    ));
    db.insert(TypeDetails::new(
        "String",
        "rust::String",
        Behavior::RustString,
        None,
    ));
    db.insert(TypeDetails::new(
        "std::boxed::Box",
        "rust::Box",
        Behavior::RustContainerByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "i8",
        "int8_t",
        Behavior::CByValue,
        Some("std::os::raw::c_schar".into()),
    ));
    db.insert(TypeDetails::new(
        "u8",
        "uint8_t",
        Behavior::CByValue,
        Some("std::os::raw::c_uchar".into()),
    ));
    for (cpp_type, rust_type) in (4..7).map(|x| 2i32.pow(x)).flat_map(|x| {
        vec![
            (format!("uint{}_t", x), format!("u{}", x)),
            (format!("int{}_t", x), format!("i{}", x)),
        ]
    }) {
        db.insert(TypeDetails::new(
            rust_type,
            cpp_type,
            Behavior::CByValue,
            None,
        ));
    }
    db.insert(TypeDetails::new("bool", "bool", Behavior::CByValue, None));

    db.insert(TypeDetails::new(
        "std::pin::Pin",
        "Pin",
        Behavior::RustByValue, // because this is actually Pin<&something>
        None,
    ));

    let mut insert_ctype = |cname: &str| {
        let concatenated_name = cname.replace(' ', "");
        db.insert(TypeDetails::new(
            format!("autocxx::c_{}", concatenated_name),
            cname,
            Behavior::CVariableLengthByValue,
            Some(format!("std::os::raw::c_{}", concatenated_name)),
        ));
        db.insert(TypeDetails::new(
            format!("autocxx::c_u{}", concatenated_name),
            format!("unsigned {}", cname),
            Behavior::CVariableLengthByValue,
            Some(format!("std::os::raw::c_u{}", concatenated_name)),
        ));
    };

    insert_ctype("long");
    insert_ctype("int");
    insert_ctype("short");
    insert_ctype("long long");

    db.insert(TypeDetails::new("f32", "float", Behavior::CByValue, None));
    db.insert(TypeDetails::new("f64", "double", Behavior::CByValue, None));
    db.insert(TypeDetails::new(
        "::std::os::raw::c_char",
        "char",
        Behavior::CByValue,
        None,
    ));
    db.insert(TypeDetails::new(
        "autocxx::c_void",
        "void",
        Behavior::CVoid,
        Some("std::os::raw::c_void".into()),
    ));
    db
}

/// If a given type lacks a copy constructor, we should always use
/// std::move in wrapper functions.
pub(crate) fn type_lacks_copy_constructor(ty: &Type) -> bool {
    // In future we may wish to look this up in KNOWN_TYPES.
    match ty {
        Type::Path(typ) => {
            let tn = QualifiedName::from_type_path(typ);
            tn.to_cpp_name().starts_with("std::unique_ptr")
                || tn.to_cpp_name().starts_with("rust::Box")
        }
        _ => false,
    }
}

pub(crate) fn ensure_pointee_is_valid(ptr: &TypePtr) -> Result<(), ConvertError> {
    match *ptr.elem {
        Type::Path(..) => Ok(()),
        _ => Err(ConvertError::InvalidPointee),
    }
}
<commit_msg>Reduce logging whitespace.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::{
    conversion::ConvertError,
    types::{make_ident, QualifiedName},
};
use indoc::indoc;
use once_cell::sync::OnceCell;
use std::collections::HashMap;
use syn::{parse_quote, Type, TypePath, TypePtr};

//// The behavior of the type.
#[derive(Debug)]
enum Behavior {
    CxxContainerByValueSafe,
    CxxContainerNotByValueSafe,
    CxxString,
    RustStr,
    RustString,
    RustByValue,
    CByValue,
    CVariableLengthByValue,
    CVoid,
    RustContainerByValueSafe,
}

/// Details about known special types, mostly primitives.
#[derive(Debug)]
struct TypeDetails {
    /// The name used by cxx (in Rust code) for this type.
    rs_name: String,
    /// C++ equivalent name for a Rust type.
    cpp_name: String,
    //// The behavior of the type.
    behavior: Behavior,
    /// Any extra non-canonical names
    extra_non_canonical_name: Option<String>,
}

impl TypeDetails {
    fn new(
        rs_name: impl Into<String>,
        cpp_name: impl Into<String>,
        behavior: Behavior,
        extra_non_canonical_name: Option<String>,
    ) -> Self {
        TypeDetails {
            rs_name: rs_name.into(),
            cpp_name: cpp_name.into(),
            behavior,
            extra_non_canonical_name,
        }
    }

    /// Whether and how to include this in the prelude given to bindgen.
    fn get_prelude_entry(&self) -> Option<String> {
        match self.behavior {
            Behavior::RustString
            | Behavior::RustStr
            | Behavior::CxxString
            | Behavior::CxxContainerByValueSafe
            | Behavior::CxxContainerNotByValueSafe
            | Behavior::RustContainerByValueSafe => {
                let tn = QualifiedName::new_from_cpp_name(&self.rs_name);
                let cxx_name = tn.get_final_item();
                let (templating, payload) = match self.behavior {
                    Behavior::CxxContainerByValueSafe
                    | Behavior::CxxContainerNotByValueSafe
                    | Behavior::RustContainerByValueSafe => ("template<typename T> ", "T* ptr"),
                    _ => ("", "char* ptr"),
                };
                Some(format!(
                    indoc! {"
                    /**
                    *

                    */
                    {}class {} {{
                        {};
                    }};
                    "},
                    self.cpp_name, templating, cxx_name, payload
                ))
            }
            _ => None,
        }
    }

    fn to_type_path(&self) -> TypePath {
        let mut segs = self.rs_name.split("::").peekable();
        if segs.peek().map(|seg| seg.is_empty()).unwrap_or_default() {
            segs.next();
            let segs = segs.into_iter().map(make_ident);
            parse_quote! {
                ::#(#segs)::*
            }
        } else {
            let segs = segs.into_iter().map(make_ident);
            parse_quote! {
                #(#segs)::*
            }
        }
    }

    fn to_typename(&self) -> QualifiedName {
        QualifiedName::new_from_cpp_name(&self.rs_name)
    }

    fn get_generic_behavior(&self) -> CxxGenericType {
        match self.behavior {
            Behavior::CxxContainerByValueSafe | Behavior::CxxContainerNotByValueSafe => {
                CxxGenericType::Cpp
            }
            Behavior::RustContainerByValueSafe => CxxGenericType::Rust,
            _ => CxxGenericType::Not,
        }
    }
}

/// Database of known types.
#[derive(Default)]
pub(crate) struct TypeDatabase {
    by_rs_name: HashMap<QualifiedName, TypeDetails>,
    canonical_names: HashMap<QualifiedName, QualifiedName>,
}

/// Returns a database of known types.
pub(crate) fn known_types() -> &'static TypeDatabase {
    static KNOWN_TYPES: OnceCell<TypeDatabase> = OnceCell::new();
    KNOWN_TYPES.get_or_init(create_type_database)
}

/// The type of payload that a cxx generic can contain.
#[derive(PartialEq, Clone, Copy)]
pub enum CxxGenericType {
    /// Not a generic at all
    Not,
    /// Some generic like cxx::UniquePtr where the contents must be a
    /// complete type.
    Cpp,
    /// Some generic like rust::Box where forward declarations are OK
    Rust,
}

impl TypeDatabase {
    fn get(&self, ty: &QualifiedName) -> Option<&TypeDetails> {
        // The following line is important. It says that
        // when we encounter something like 'std::unique_ptr'
        // in the bindgen-generated bindings, we'll immediately
        // start to refer to that as 'UniquePtr' henceforth.
        let canonical_name = self.canonical_names.get(ty).unwrap_or(ty);
        self.by_rs_name.get(canonical_name)
    }

    /// Prelude of C++ for squirting into bindgen. This configures
    /// bindgen to output simpler types to replace some STL types
    /// that bindgen just can't cope with. Although we then replace
    /// those types with cxx types (e.g. UniquePtr), this intermediate
    /// step is still necessary because bindgen can't otherwise
    /// give us the templated types (e.g. when faced with the STL
    /// unique_ptr, bindgen would normally give us std_unique_ptr
    /// as opposed to std_unique_ptr<T>.)
    pub(crate) fn get_prelude(&self) -> String {
        itertools::join(
            self.by_rs_name
                .values()
                .filter_map(|t| t.get_prelude_entry()),
            "",
        )
    }

    /// Types which are known to be safe (or unsafe) to hold and pass by
    /// value in Rust.
    pub(crate) fn get_pod_safe_types(&self) -> impl Iterator<Item = (QualifiedName, bool)> {
        let pod_safety = self
            .canonical_names
            .keys()
            .chain(self.by_rs_name.keys())
            .map(|tn| {
                (
                    tn.clone(),
                    match self.get(tn).unwrap().behavior {
                        Behavior::CxxContainerByValueSafe
                        | Behavior::RustStr
                        | Behavior::RustString
                        | Behavior::RustByValue
                        | Behavior::CByValue
                        | Behavior::CVariableLengthByValue
                        | Behavior::RustContainerByValueSafe => true,
                        Behavior::CxxString
                        | Behavior::CxxContainerNotByValueSafe
                        | Behavior::CVoid => false,
                    },
                )
            })
            .collect::<HashMap<_, _>>();
        pod_safety.into_iter()
    }

    /// Whether this TypePath should be treated as a value in C++
    /// but a reference in Rust. This only applies to rust::Str
    /// (C++ name) which is &str in Rust.
    pub(crate) fn should_dereference_in_cpp(&self, tn: &QualifiedName) -> bool {
        self.get(tn)
            .map(|td| matches!(td.behavior, Behavior::RustStr))
            .unwrap_or(false)
    }

    /// Here we substitute any names which we know are Special from
    /// our type database, e.g. std::unique_ptr -> UniquePtr.
    /// We strip off and ignore
    /// any PathArguments within this TypePath - callers should
    /// put them back again if needs be.
    pub(crate) fn consider_substitution(&self, tn: &QualifiedName) -> Option<TypePath> {
        self.get(tn).map(|td| td.to_type_path())
    }

    pub(crate) fn special_cpp_name(&self, rs: &QualifiedName) -> Option<String> {
        self.get(rs).map(|x| x.cpp_name.to_string())
    }

    pub(crate) fn is_known_type(&self, ty: &QualifiedName) -> bool {
        self.get(ty).is_some()
    }

    pub(crate) fn known_type_type_path(&self, ty: &QualifiedName) -> Option<TypePath> {
        self.get(ty).map(|td| td.to_type_path())
    }

    /// Get the list of types to give to bindgen to ask it _not_ to
    /// generate code for.
    pub(crate) fn get_initial_blocklist(&self) -> impl Iterator<Item = &str> + '_ {
        self.by_rs_name
            .iter()
            .filter_map(|(_, td)| td.get_prelude_entry().map(|_| td.cpp_name.as_str()))
    }

    /// Whether this is one of the ctypes (mostly variable length integers)
    /// which we need to wrap.
    pub(crate) fn is_ctype(&self, ty: &QualifiedName) -> bool {
        self.get(ty)
            .map(|td| {
                matches!(
                    td.behavior,
                    Behavior::CVariableLengthByValue | Behavior::CVoid
                )
            })
            .unwrap_or(false)
    }

    /// Whether this is a generic type acceptable to cxx. Otherwise,
    /// if we encounter a generic, we'll replace it with a synthesized concrete
    /// type.
    pub(crate) fn cxx_generic_behavior(&self, ty: &QualifiedName) -> CxxGenericType {
        self.get(ty)
            .map(|x| x.get_generic_behavior())
            .unwrap_or(CxxGenericType::Not)
    }

    pub(crate) fn is_cxx_acceptable_receiver(&self, ty: &QualifiedName) -> bool {
        self.get(ty).is_none() // at present, none of our known types can have
                               // methods attached.
    }

    pub(crate) fn conflicts_with_built_in_type(&self, ty: &QualifiedName) -> bool {
        self.get(ty).is_some()
    }

    pub(crate) fn convertible_from_strs(&self, ty: &QualifiedName) -> bool {
        self.get(ty)
            .map(|x| matches!(x.behavior, Behavior::CxxString))
            .unwrap_or(false)
    }

    fn insert(&mut self, td: TypeDetails) {
        let rs_name = td.to_typename();
        if let Some(extra_non_canonical_name) = &td.extra_non_canonical_name {
            self.canonical_names.insert(
                QualifiedName::new_from_cpp_name(extra_non_canonical_name),
                rs_name.clone(),
            );
        }
        self.canonical_names.insert(
            QualifiedName::new_from_cpp_name(&td.cpp_name),
            rs_name.clone(),
        );
        self.by_rs_name.insert(rs_name, td);
    }
}

fn create_type_database() -> TypeDatabase {
    let mut db = TypeDatabase::default();
    db.insert(TypeDetails::new(
        "cxx::UniquePtr",
        "std::unique_ptr",
        Behavior::CxxContainerByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "cxx::CxxVector",
        "std::vector",
        Behavior::CxxContainerNotByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "cxx::SharedPtr",
        "std::shared_ptr",
        Behavior::CxxContainerByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "cxx::WeakPtr",
        "std::weak_ptr",
        Behavior::CxxContainerByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "cxx::CxxString",
        "std::string",
        Behavior::CxxString,
        None,
    ));
    db.insert(TypeDetails::new(
        "str",
        "rust::Str",
        Behavior::RustStr,
        None,
    ));
    db.insert(TypeDetails::new(
        "String",
        "rust::String",
        Behavior::RustString,
        None,
    ));
    db.insert(TypeDetails::new(
        "std::boxed::Box",
        "rust::Box",
        Behavior::RustContainerByValueSafe,
        None,
    ));
    db.insert(TypeDetails::new(
        "i8",
        "int8_t",
        Behavior::CByValue,
        Some("std::os::raw::c_schar".into()),
    ));
    db.insert(TypeDetails::new(
        "u8",
        "uint8_t",
        Behavior::CByValue,
        Some("std::os::raw::c_uchar".into()),
    ));
    for (cpp_type, rust_type) in (4..7).map(|x| 2i32.pow(x)).flat_map(|x| {
        vec![
            (format!("uint{}_t", x), format!("u{}", x)),
            (format!("int{}_t", x), format!("i{}", x)),
        ]
    }) {
        db.insert(TypeDetails::new(
            rust_type,
            cpp_type,
            Behavior::CByValue,
            None,
        ));
    }
    db.insert(TypeDetails::new("bool", "bool", Behavior::CByValue, None));

    db.insert(TypeDetails::new(
        "std::pin::Pin",
        "Pin",
        Behavior::RustByValue, // because this is actually Pin<&something>
        None,
    ));

    let mut insert_ctype = |cname: &str| {
        let concatenated_name = cname.replace(' ', "");
        db.insert(TypeDetails::new(
            format!("autocxx::c_{}", concatenated_name),
            cname,
            Behavior::CVariableLengthByValue,
            Some(format!("std::os::raw::c_{}", concatenated_name)),
        ));
        db.insert(TypeDetails::new(
            format!("autocxx::c_u{}", concatenated_name),
            format!("unsigned {}", cname),
            Behavior::CVariableLengthByValue,
            Some(format!("std::os::raw::c_u{}", concatenated_name)),
        ));
    };

    insert_ctype("long");
    insert_ctype("int");
    insert_ctype("short");
    insert_ctype("long long");

    db.insert(TypeDetails::new("f32", "float", Behavior::CByValue, None));
    db.insert(TypeDetails::new("f64", "double", Behavior::CByValue, None));
    db.insert(TypeDetails::new(
        "::std::os::raw::c_char",
        "char",
        Behavior::CByValue,
        None,
    ));
    db.insert(TypeDetails::new(
        "autocxx::c_void",
        "void",
        Behavior::CVoid,
        Some("std::os::raw::c_void".into()),
    ));
    db
}

/// If a given type lacks a copy constructor, we should always use
/// std::move in wrapper functions.
pub(crate) fn type_lacks_copy_constructor(ty: &Type) -> bool {
    // In future we may wish to look this up in KNOWN_TYPES.
    match ty {
        Type::Path(typ) => {
            let tn = QualifiedName::from_type_path(typ);
            tn.to_cpp_name().starts_with("std::unique_ptr")
                || tn.to_cpp_name().starts_with("rust::Box")
        }
        _ => false,
    }
}

pub(crate) fn ensure_pointee_is_valid(ptr: &TypePtr) -> Result<(), ConvertError> {
    match *ptr.elem {
        Type::Path(..) => Ok(()),
        _ => Err(ConvertError::InvalidPointee),
    }
}
<|endoftext|>