<commit_before>extern crate clap;
extern crate image;

use clap::{Arg,App,SubCommand};
use std::fs::File;
use image::{FilterType, GenericImage, Pixel};
use image::DynamicImage;
use std::path::Path;

fn main() {
     let matches = App::new("IPCLI")
                          .version("0.1")
                          .author("Mikolaj Wawrzyniak <mikolaj.wawrzyniak at fh-dortmund.de>")
                          .about("Basic CLI for image processing")
                          .arg(Arg::with_name("operation")
                               .short("o")
                               .long("operation")
                               .help("Specifies operation to be done on the image")
                               .takes_value(true)
                               .required(true))
                          .arg(Arg::with_name("image")
                               .short("i")
                               .long("image")
                               .value_name("FILE")
                               .help("Opens specified image file and uses it for transformations.")
                               .takes_value(true)
                               .required(true))
                          .arg(Arg::with_name("save")
                               .short("s")
                               .long("save")
                               .value_name("FILE")
                               .help("Outputs transformed image into specified file OR uses the second file to calculate the perceptual hash values and outputs their difference")
                               .takes_value(true)
                               .required(true))
                          .get_matches();

    let imagePath = matches.value_of("image").unwrap_or("empty");
    println!("Transforming the image: {}", imagePath);

    let savePath = matches.value_of("save").unwrap_or("empty");
    println!("Into: {}", savePath);

    let operation = matches.value_of("operation").unwrap_or("empty");
    println!("Operation: {}", operation);

    match operation.as_ref(){
        "copy" => {openAndSave(imagePath, savePath)}
        "thumbnail" => {createThumnbail(imagePath, savePath)}
        _ => {println!("Not implemented yet!")}
    }

    match matches.occurrences_of("v") {
        0 => println!("No verbose info"),
        1 => println!("Some verbose info"),
        2 => println!("Tons of verbose info"),
        3 | _ => println!("Don't be crazy"),
    }
}

fn createThumnbail(i: &str, s: &str){
    let img = image::open(i).expect("Opening image failed");
    let thumbnail = img.resize(120,120, FilterType::Lanczos3);
    saveFile(&thumbnail, &i, &s);

}

fn openAndSave(i: &str, s: &str){
    let img = image::open(i).expect("Opening image failed");
    saveFile(&img, &i, &s);
}

fn saveFile(img: &DynamicImage, i: &str, s: &str){
        let mut out = File::create(s).unwrap();
        let ext: String = i.chars().skip(i.len()-3).take(3).collect();
        match ext.as_ref() {
            "jpg" => {img.save(&mut out, image::JPEG).expect("Saving image failed");}
            "png" => {img.save(&mut out, image::PNG).expect("Saving image failed");}
            _ => {println!("something else")}
        }
}

<commit_msg>added value argument<commit_after>extern crate clap;
extern crate image;

use clap::{Arg,App,SubCommand};
use std::fs::File;
use image::{FilterType, GenericImage, Pixel};
use image::DynamicImage;
use std::path::Path;

fn main() {
     let matches = App::new("IPCLI")
                          .version("0.1")
                          .author("Mikolaj Wawrzyniak <mikolaj.wawrzyniak at fh-dortmund.de>")
                          .about("Basic CLI for image processing")
                          .arg(Arg::with_name("operation")
                               .short("o")
                               .long("operation")
                               .help("Specifies operation to be done on the image")
                               .takes_value(true)
                               .required(true))
                          .arg(Arg::with_name("value")
                               .short("v")
                               .long("value")
                               .help("Value for the transformation. To see what values are needed, check the documentation.")
                               .takes_value(true)
                               .required(false))
                          .arg(Arg::with_name("image")
                               .short("i")
                               .long("image")
                               .value_name("FILE")
                               .help("Opens specified image file and uses it for transformations.")
                               .takes_value(true)
                               .required(true))
                          .get_matches();

    let imagePath = matches.value_of("image").unwrap_or("empty");
    println!("Transforming the image: {}", imagePath);

    let operation = matches.value_of("operation").unwrap_or("empty");
    println!("Using operation: {}", operation);

    let value = matches.value_of("value").unwrap_or("empty");
    println!("Value: {}", value);

    match operation.as_ref(){
        "copy" => {copy(imagePath)}
        "thumbnail" => {
            let size: u32 = value.parse().unwrap();
            createThumnbail(imagePath, size)}
        "blur" => {
            let v : f32 = value.parse().unwrap();
            gaussianBlur(imagePath,v)}
        "brighten" => {
            let v: i32 = value.parse().unwrap();
            brighten(imagePath,v)}
        "huerotate" => {
            let v: i32 = value.parse().unwrap();
            huerotate(imagePath,v)}
        "contrast" => {
            let v: f32 = value.parse().unwrap();
            contrast(imagePath,v);}
        _ => {println!("Not implemented yet!")}
    }
}

fn createThumnbail(i: &str, size: u32){
    let operation = "Thumbnail";
    let img = image::open(i).expect("Opening image failed");
    let thumbnail = img.resize(size,size, FilterType::Lanczos3);
    saveFile(&thumbnail, &i, &operation);

}

fn copy(i: &str){
    let operation = "Copy";
    let img = image::open(i).expect("Opening image failed");
    saveFile(&img, &i, &operation);
}

fn gaussianBlur(i: &str, v: f32){
    let operation = "GuassianBlur";
    let img = image::open(i).expect("Opening image failed");
    let blurred = img.blur(v);
    saveFile(&blurred, &i, &operation);
}

fn brighten(i: &str,v: i32){
    let operation = "Brighten";
    let img = image::open(i).expect("Opening image failed");
    let brightened = img.brighten(v);
    saveFile(&brightened, &i, &operation);
}

fn huerotate(i: &str, v: i32){
    let operation = "Huerotate";
    let img = image::open(i).expect("Opening image failed");
    let huerotated = img.huerotate(v);
    saveFile(&huerotated, &i, &operation);
}

fn contrast(i: &str, v: f32){
    let operation = "AdjustContrast";
    let img = image::open(i).expect("Opening image failed");
    let contrast = img.adjust_contrast(v);
    saveFile(&contrast, &i, &operation);
}

fn saveFile(img: &DynamicImage, i: &str, operation: &str){
    let mut outputPath: String = i.chars().take(i.len()-4).collect();
    let ext: String = i.chars().skip(i.len()-3).take(3).collect();
    outputPath.push_str(operation);
    outputPath.push_str(".");
    outputPath.push_str(&ext);
    println!("Output path: {}", outputPath);
    let mut out = File::create(outputPath).unwrap();
    match ext.as_ref() {
        "jpg" | "JPG" => {img.save(&mut out, image::JPEG).expect("Saving image failed");}
        "png" | "PNG" => {img.save(&mut out, image::PNG).expect("Saving image failed");}
        "gif" | "GIF" => {img.save(&mut out, image::GIF).expect("Saving image failed");}
        "bmp" | "BMP" => {img.save(&mut out, image::BMP).expect("Saving image failed");}
        "ico" | "ICO" => {img.save(&mut out, image::ICO).expect("Saving image failed");}
        _ => {println!("Unsupported file format")}
    }
}

<|endoftext|>


<commit_before>//! Generic Tree Implementation for Plan

pub enum TreeBuildError
{
  EmptyStack,
  StillRemainStackItem
}

pub enum TreeNode<T>
{
  Branch(T, Vec<Box<TreeNode<T>>>),
  Leaf(T)
}

#[allow(unused_variables)]
pub trait Visitor<'v, T>: Sized {
  fn visit(&self, data: &'v T, child: Option<&'v Vec<Box<TreeNode<T>>>>) {
    self.visit_by_default(child);
  }

  fn visit_by_default(&self, child: Option<&'v Vec<Box<TreeNode<T>>>>) {
    match child {
      Some(v) => {
        for node in v.iter().map(|n| &*n) {
          walk_tree(self, node);
        }
      },
      None    => {}
    };
  }
}

pub fn walk_tree<'v, V, T>(v: &V, node: &'v TreeNode<T>)
    where V: Visitor<'v, T> {
  match *node {
    TreeNode::Leaf(ref data) => v.visit(data, None),
    TreeNode::Branch(ref data, ref child) => v.visit(data, Some(child))
  };
}

/// Tree Builder in a bottom up approach.
pub struct TreeBuilder<T>
{
  stack: Vec<TreeNode<T>>
}

impl<T> TreeBuilder<T> {

  pub fn new() -> TreeBuilder<T>
  {
    TreeBuilder {
      stack: Vec::new()
    }
  }

  pub fn push(&mut self, node: TreeNode<T>) -> Result<usize, TreeBuildError>
  {
    self.stack.push(node);

    Ok(self.stack.len())
  }

  pub fn pop(&mut self) -> TreeNode<T>
  {
    debug_assert!(self.stack.len() > 0);
    self.stack.pop().unwrap()
  }

  pub fn pop_and_push(&mut self, data: T, child_num: usize) -> Result<usize, TreeBuildError>
  {
    let stack_size = self.stack.len();
    debug_assert!(stack_size >= child_num);

    let child = self.stack.split_off(stack_size - child_num)
      .into_iter()
      .map(|node| Box::new(node))
      .collect::<Vec<Box<TreeNode<T>>>>();

    self.stack.push(TreeNode::Branch(data, child));

    Ok(self.stack.len())
  }

  pub fn build(&mut self) -> Result<TreeNode<T>, TreeBuildError>  {
    match self.stack.len() {
      0 => { Err(TreeBuildError::EmptyStack) },
      1 => { Ok(self.stack.pop().unwrap()) },
      _ => { Err(TreeBuildError::StillRemainStackItem) }
   }
  }
}

#[cfg(test)]
mod tests {
  use super::{TreeBuilder, TreeNode};

  #[test]
  fn test_tree() {
    let mut builder: TreeBuilder<&'static str> = TreeBuilder::new();

    builder.push(TreeNode::Leaf("l1")).ok();
    builder.push(TreeNode::Leaf("l2")).ok();

    builder.pop_and_push("l3", 2).ok();

    let tree = builder.build().ok().unwrap();
  }
}<commit_msg>Add SimpleVisitor.<commit_after>//! Generic Tree Implementation for Plan

use std::rc::Rc;

pub enum TreeBuildError
{
  EmptyStack,
  StillRemainStackItem
}

pub enum TreeNode<T>
{
  Branch(T, Vec<Box<TreeNode<T>>>),
  Leaf(T)
}

#[allow(unused_variables)]
pub trait Visitor<'v, T>: Sized {
  fn accept(&mut self, data: &'v T, child: Option<&'v Vec<Box<TreeNode<T>>>>) {
    self.accept_by_default(child);
  }

  fn accept_by_default(&mut self, child: Option<&'v Vec<Box<TreeNode<T>>>>) {
    match child {
      Some(v) => {
        for node in v.iter().map(|n| &*n) {
          walk_tree(self, node);
        }
      },
      None    => {}
    };
  }
}

pub fn walk_tree<'v, V, T>(v: &mut V, node: &'v TreeNode<T>)
    where V: Visitor<'v, T> {
  match *node {
    TreeNode::Leaf(ref data) => v.accept(data, None),
    TreeNode::Branch(ref data, ref child) => v.accept(data, Some(child))
  };
}

pub type SimpleVisitor<T> = Rc<Fn(&T, Option<&Vec<Box<TreeNode<T>>>>)>;

pub struct BatchVisitor<T> {
  batch: Vec<SimpleVisitor<T>>
}

impl<T> BatchVisitor<T> {
  pub fn new() -> BatchVisitor<T> {
    BatchVisitor {
      batch: Vec::new()
    }
  }

  pub fn add(&mut self, v: SimpleVisitor<T>) -> &mut Self {
    self.batch.push(v);

    self
  }
}

/// Tree Builder in a bottom up approach.
pub struct TreeBuilder<T>
{
  stack: Vec<TreeNode<T>>
}

impl<T> TreeBuilder<T> {

  pub fn new() -> TreeBuilder<T>
  {
    TreeBuilder {
      stack: Vec::new()
    }
  }

  pub fn push(&mut self, node: TreeNode<T>) -> Result<usize, TreeBuildError>
  {
    self.stack.push(node);

    Ok(self.stack.len())
  }

  pub fn pop(&mut self) -> TreeNode<T>
  {
    debug_assert!(self.stack.len() > 0);
    self.stack.pop().unwrap()
  }

  pub fn pop_and_push(&mut self, data: T, child_num: usize) -> Result<usize, TreeBuildError>
  {
    let stack_size = self.stack.len();
    debug_assert!(stack_size >= child_num);

    let child = self.stack.split_off(stack_size - child_num)
      .into_iter()
      .map(|node| Box::new(node))
      .collect::<Vec<Box<TreeNode<T>>>>();

    self.stack.push(TreeNode::Branch(data, child));

    Ok(self.stack.len())
  }

  pub fn build(&mut self) -> Result<TreeNode<T>, TreeBuildError>  {
    match self.stack.len() {
      0 => { Err(TreeBuildError::EmptyStack) },
      1 => { Ok(self.stack.pop().unwrap()) },
      _ => { Err(TreeBuildError::StillRemainStackItem) }
   }
  }
}

#[cfg(test)]
mod tests {
  use super::{TreeBuilder, TreeNode, Visitor};

 pub struct TestVisitor;

 pub struct AA;

 impl<'v> Visitor<'v, AA> for TestVisitor {
    fn accept(&mut self, data: &AA, child: Option<&'v Vec<Box<TreeNode<AA>>>>) {
      self.accept_by_default(child);
    }
  }

  #[test]
  fn test_tree() {
    let mut builder: TreeBuilder<&'static str> = TreeBuilder::new();

    builder.push(TreeNode::Leaf("l1")).ok();
    builder.push(TreeNode::Leaf("l2")).ok();

    builder.pop_and_push("l3", 2).ok();

    let tree = builder.build().ok().unwrap();
  }
}<|endoftext|>


<commit_before>pub const L_tmpnam: ::c_uint = 14;
pub const TMP_MAX: ::c_uint = 0x7fff;

extern {
    pub fn strcasecmp(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int;
    pub fn strncasecmp(s1: *const ::c_char, s2: *const ::c_char,
                       n: ::size_t) -> ::c_int;
}
<commit_msg>Auto merge of #1180 - xmclark:add-stdio-constants-windows, r=alexcrichton<commit_after>pub const L_tmpnam: ::c_uint = 14;
pub const TMP_MAX: ::c_uint = 0x7fff;

// stdio file descriptor numbers
pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

extern {
    pub fn strcasecmp(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int;
    pub fn strncasecmp(s1: *const ::c_char, s2: *const ::c_char,
                       n: ::size_t) -> ::c_int;
}
<|endoftext|>


<commit_before>use clap::IntoApp;
use clap_generate::generate_to;
use clap_generate::generators::{Bash, Elvish, Fish, PowerShell, Zsh};
use std::{env, fs, path};
use vergen::vergen;

include!("src/cli.rs");

fn main() {
    let mut flags = vergen::Config::default();
    // If passed a version, use that instead of vergen's formatting
    if let Ok(val) = env::var("CASILE_VERSION") {
        *flags.git_mut().semver_mut() = false;
        println!("cargo:rustc-env=VERGEN_GIT_SEMVER={}", val)
    };
    vergen(flags).expect("Unable to generate the cargo keys!");
    pass_on_configure_details();
    generate_shell_completions();
}

/// Generate shell completion files from CLI interface
fn generate_shell_completions() {
    let out_dir = match env::var_os("OUT_DIR") {
        None => return,
        Some(out_dir) => out_dir,
    };
    let completions_dir = path::Path::new(&out_dir).join("completions");
    fs::create_dir_all(&completions_dir)
        .expect("Could not create directory in which to place completions");
    let app = Cli::into_app();
    let bin_name: &str = app
        .get_bin_name()
        .expect("Could not retrieve bin-name from generated Clap app");
    let mut app = Cli::into_app();
    generate_to::<Bash, _, _>(&mut app, bin_name, &completions_dir);
    generate_to::<Elvish, _, _>(&mut app, bin_name, &completions_dir);
    generate_to::<Fish, _, _>(&mut app, bin_name, &completions_dir);
    generate_to::<PowerShell, _, _>(&mut app, bin_name, &completions_dir);
    generate_to::<Zsh, _, _>(&mut app, bin_name, &completions_dir);
}

/// Pass through some variables set by autoconf/automake about where we're installed to cargo for
/// use in finding resources at runtime
fn pass_on_configure_details() {
    let mut autoconf_vars = std::collections::HashMap::new();
    autoconf_vars.insert("CONFIGURE_PREFIX", String::from("./"));
    autoconf_vars.insert("CONFIGURE_BINDIR", String::from("./"));
    autoconf_vars.insert("CONFIGURE_DATADIR", String::from("./"));
    for (var, default) in autoconf_vars {
        let val = env::var(var).unwrap_or(default);
        println!("cargo:rustc-env={}={}", var, val);
    }
}
<commit_msg>fix(build): Don't expect release tarballs to be Git repos<commit_after>use clap::IntoApp;
use clap_generate::generate_to;
use clap_generate::generators::{Bash, Elvish, Fish, PowerShell, Zsh};
use std::{env, fs, path};
use vergen::vergen;

include!("src/cli.rs");

fn main() {
    let mut flags = vergen::Config::default();
    // If passed a version, use that instead of vergen's formatting
    if let Ok(val) = env::var("CASILE_VERSION") {
        *flags.git_mut().enabled_mut() = false;
        println!("cargo:rustc-env=VERGEN_GIT_SEMVER={}", val)
    };
    vergen(flags).expect("Unable to generate the cargo keys!");
    pass_on_configure_details();
    generate_shell_completions();
}

/// Generate shell completion files from CLI interface
fn generate_shell_completions() {
    let out_dir = match env::var_os("OUT_DIR") {
        None => return,
        Some(out_dir) => out_dir,
    };
    let completions_dir = path::Path::new(&out_dir).join("completions");
    fs::create_dir_all(&completions_dir)
        .expect("Could not create directory in which to place completions");
    let app = Cli::into_app();
    let bin_name: &str = app
        .get_bin_name()
        .expect("Could not retrieve bin-name from generated Clap app");
    let mut app = Cli::into_app();
    generate_to::<Bash, _, _>(&mut app, bin_name, &completions_dir);
    generate_to::<Elvish, _, _>(&mut app, bin_name, &completions_dir);
    generate_to::<Fish, _, _>(&mut app, bin_name, &completions_dir);
    generate_to::<PowerShell, _, _>(&mut app, bin_name, &completions_dir);
    generate_to::<Zsh, _, _>(&mut app, bin_name, &completions_dir);
}

/// Pass through some variables set by autoconf/automake about where we're installed to cargo for
/// use in finding resources at runtime
fn pass_on_configure_details() {
    let mut autoconf_vars = std::collections::HashMap::new();
    autoconf_vars.insert("CONFIGURE_PREFIX", String::from("./"));
    autoconf_vars.insert("CONFIGURE_BINDIR", String::from("./"));
    autoconf_vars.insert("CONFIGURE_DATADIR", String::from("./"));
    for (var, default) in autoconf_vars {
        let val = env::var(var).unwrap_or(default);
        println!("cargo:rustc-env={}={}", var, val);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::io::Result as IoResult;
use std::path::{ Path, PathBuf };
use std::process::{ Command, ExitStatus };

fn update_local_git_hook() {
    let p = env::current_dir().unwrap();
    let origin_path = Path::new(&p).join("./tools/pre-commit");
    let dest_path = Path::new(&p).join(".git/hooks/pre-commit");

    fs::copy(&origin_path, &dest_path).unwrap();
}

fn cp_r(origin: &Path, dest: &Path) {
    let dir = fs::read_dir(origin).unwrap();
    for file in dir {
        let file = file.unwrap();
        let origin_buf = origin.join(file.file_name());
        let origin = origin_buf.as_path();
        let dest_buf = dest.join(file.file_name());
        let dest = dest_buf.as_path();

        if file.file_type().unwrap().is_dir() {
            let dest_str = dest.to_str().unwrap();
            if let Err(_) = fs::metadata(&dest_str) {
                fs::create_dir(dest_str).unwrap();
            }
            cp_r(origin, dest);
        } else {
            fs::copy(origin, dest).unwrap();
        }
    }
}

fn copy_shared_static_files() {
    let current = env::current_dir().unwrap();
    let shared = Path::new(&current).join("./static/shared");
    for dest in vec!["./static/setup/shared", "./static/main/shared"] {
        let dest = Path::new(&current).join(dest);
        let dest_str = dest.to_str().unwrap();
        if let Err(_) = fs::metadata(&dest_str) {
            fs::create_dir(dest_str).unwrap();
        }
        cp_r(&shared, &dest);
    }
}

fn cargo_build_in_directory(directory: &str) -> IoResult<ExitStatus> {
    let current_dir = env::current_dir().unwrap();
    let mut run_in_dir = PathBuf::from(&current_dir);
    run_in_dir.push(directory);

    Command::new("cargo")
            .arg("build")
            .current_dir(run_in_dir)
            .spawn()
            .unwrap()
            .wait()
}

fn main() {
    update_local_git_hook();
    copy_shared_static_files();
    cargo_build_in_directory("./components/dns_challenge").unwrap();
}
<commit_msg>Build the dns_challenge crate properly (#415)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::env;
use std::fs;
use std::path::{ Path, PathBuf };
use std::process::Command;

fn update_local_git_hook() {
    let p = env::current_dir().unwrap();
    let origin_path = Path::new(&p).join("./tools/pre-commit");
    let dest_path = Path::new(&p).join(".git/hooks/pre-commit");

    fs::copy(&origin_path, &dest_path).unwrap();
}

fn cp_r(origin: &Path, dest: &Path) {
    let dir = fs::read_dir(origin).unwrap();
    for file in dir {
        let file = file.unwrap();
        let origin_buf = origin.join(file.file_name());
        let origin = origin_buf.as_path();
        let dest_buf = dest.join(file.file_name());
        let dest = dest_buf.as_path();

        if file.file_type().unwrap().is_dir() {
            let dest_str = dest.to_str().unwrap();
            if let Err(_) = fs::metadata(&dest_str) {
                fs::create_dir(dest_str).unwrap();
            }
            cp_r(origin, dest);
        } else {
            fs::copy(origin, dest).unwrap();
        }
    }
}

fn copy_shared_static_files() {
    let current = env::current_dir().unwrap();
    let shared = Path::new(&current).join("./static/shared");
    for dest in vec!["./static/setup/shared", "./static/main/shared"] {
        let dest = Path::new(&current).join(dest);
        let dest_str = dest.to_str().unwrap();
        if let Err(_) = fs::metadata(&dest_str) {
            fs::create_dir(dest_str).unwrap();
        }
        cp_r(&shared, &dest);
    }
}

// Looks for an environmental variable, defaulting to the empty string.
fn get_env(key: &str) -> String {
    env::var(key).unwrap_or("".to_owned())
}

// Returns the appropriate --target=XXX command line argument, or None
// if we are not cross compiling.
fn get_target() -> Option<String> {
    let target = get_env("TARGET");
    let host = get_env("HOST");
    if host != target {
        return Some(format!("--target={}", target));
    }

    None
}

fn cargo_build_in_directory(directory: &str) {
    let current_dir = env::current_dir().unwrap();
    let mut run_in_dir = PathBuf::from(&current_dir);
    run_in_dir.push(directory);

    let mut exec = Command::new("cargo");
    let mut command = exec.arg("build")
                          .arg("--verbose"); // Ideally should reflect the --verbose flag of the main
                                             // cargo command.

    let target = get_target();
    if target.is_some() {
        let tmp = command;
        command = tmp.arg(target.unwrap());
    }

    // $PROFILE is either `debug` (default value) or `release`.
    if get_env("PROFILE") == "release" {
        let tmp = command;
        command = tmp.arg("--release");
    }

    command.current_dir(run_in_dir)
           .spawn()
           .unwrap()
           .wait()
           .unwrap();

    /*if !output.status.success() {
        println!("status: {}", output.status);
        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
        panic!("debug"); // Forces the println!(...) to display.
    }*/
}

fn main() {
    update_local_git_hook();
    copy_shared_static_files();
    cargo_build_in_directory("./components/dns_challenge");
}
<|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()),
            "",
        )
    }

    /// 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>Record known type constructors<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>,
    has_const_copy_constructor: bool,
    has_move_constructor: bool,
}

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

    /// 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,
        false,
        true,
    ));
    db.insert(TypeDetails::new(
        "cxx::CxxVector",
        "std::vector",
        Behavior::CxxContainerNotByValueSafe,
        None,
        false,
        true,
    ));
    db.insert(TypeDetails::new(
        "cxx::SharedPtr",
        "std::shared_ptr",
        Behavior::CxxContainerByValueSafe,
        None,
        true,
        true,
    ));
    db.insert(TypeDetails::new(
        "cxx::WeakPtr",
        "std::weak_ptr",
        Behavior::CxxContainerByValueSafe,
        None,
        true,
        true,
    ));
    db.insert(TypeDetails::new(
        "cxx::CxxString",
        "std::string",
        Behavior::CxxString,
        None,
        true,
        true,
    ));
    db.insert(TypeDetails::new(
        "str",
        "rust::Str",
        Behavior::RustStr,
        None,
        false, // TODO - check
        false, // TODO - check
    ));
    db.insert(TypeDetails::new(
        "String",
        "rust::String",
        Behavior::RustString,
        None,
        false, // TODO - check
        false, // TODO - check
    ));
    db.insert(TypeDetails::new(
        "std::boxed::Box",
        "rust::Box",
        Behavior::RustContainerByValueSafe,
        None,
        false, // TODO - check
        false, // TODO - check
    ));
    db.insert(TypeDetails::new(
        "i8",
        "int8_t",
        Behavior::CByValue,
        Some("std::os::raw::c_schar".into()),
        true,
        true,
    ));
    db.insert(TypeDetails::new(
        "u8",
        "uint8_t",
        Behavior::CByValue,
        Some("std::os::raw::c_uchar".into()),
        true,
        true,
    ));
    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,
            true,
            true,
        ));
    }
    db.insert(TypeDetails::new(
        "bool",
        "bool",
        Behavior::CByValue,
        None,
        true,
        true,
    ));

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

    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)),
            true,
            true,
        ));
        db.insert(TypeDetails::new(
            format!("autocxx::c_u{}", concatenated_name),
            format!("unsigned {}", cname),
            Behavior::CVariableLengthByValue,
            Some(format!("std::os::raw::c_u{}", concatenated_name)),
            true,
            true,
        ));
    };

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

    db.insert(TypeDetails::new(
        "f32",
        "float",
        Behavior::CByValue,
        None,
        true,
        true,
    ));
    db.insert(TypeDetails::new(
        "f64",
        "double",
        Behavior::CByValue,
        None,
        true,
        true,
    ));
    db.insert(TypeDetails::new(
        "::std::os::raw::c_char",
        "char",
        Behavior::CByValue,
        None,
        true,
        true,
    ));
    db.insert(TypeDetails::new(
        "autocxx::c_void",
        "void",
        Behavior::CVoid,
        Some("std::os::raw::c_void".into()),
        false,
        false,
    ));
    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|>


<commit_before>extern crate lua52_sys as ffi;
extern crate libc;

use std::ffi::{CStr, CString};
use std::io::Read;
use std::io::Error as IoError;
use std::borrow::Borrow;
use std::marker::PhantomData;

pub use functions_read::LuaFunction;
pub use functions_write::{Function, InsideCallback};
pub use functions_write::{function0, function1, function2, function3, function4, function5};
pub use functions_write::{function6, function7, function8, function9, function10};
pub use lua_tables::LuaTable;
pub mod any;
pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod functions_write;
mod macros;
mod rust_tables;
mod values;
mod tuples;

/// Main object of the library.
///
/// The lifetime parameter corresponds to the lifetime of the content of the Lua context.
pub struct Lua<'lua> {
    lua: LuaContext,
    must_be_closed: bool,
    marker: PhantomData<&'lua ()>,
}

/// RAII guard for a value pushed on the stack.
pub struct PushGuard<L> where L: AsMutLua {
    lua: L,
    size: i32,
}

impl<L> PushGuard<L> where L: AsMutLua {
    /// Prevents the value from being poped when the `PushGuard` is destroyed, and returns the
    /// number of elements on the stack.
    fn forget(mut self) -> i32 {
        let size = self.size;
        self.size = 0;
        size
    }

    /// Destroys the guard, popping the value. Returns the inner part,
    /// which returns access when using by-value capture.
    pub fn into_inner(mut self) -> L {
        use std::{mem, ptr};

        let mut res;
        unsafe {
            res = mem::uninitialized();
            ptr::copy_nonoverlapping(&self.lua, &mut res, 1);
            if self.size != 0 {
                ffi::lua_pop(self.lua.as_mut_lua().0, self.size);
            }
        };
        mem::forget(self);

        res
    }
}

/// Trait for objects that have access to a Lua context. When using a context returned by a
/// `AsLua`, you are not allowed to modify the stack.
pub unsafe trait AsLua {
    fn as_lua(&self) -> LuaContext;
}

/// Trait for objects that have access to a Lua context. You are allowed to modify the stack, but
/// it must be in the same state as it was when you started.
pub unsafe trait AsMutLua: AsLua {
    fn as_mut_lua(&mut self) -> LuaContext;
}

/// Opaque type that contains the raw Lua context.
#[derive(Copy, Clone)]
#[allow(raw_pointer_derive)]
pub struct LuaContext(*mut ffi::lua_State);
unsafe impl Send for LuaContext {}

unsafe impl<'a, 'lua> AsLua for Lua<'lua> {
    fn as_lua(&self) -> LuaContext {
        self.lua
    }
}

unsafe impl<'lua> AsMutLua for Lua<'lua> {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.lua
    }
}

unsafe impl<L> AsLua for PushGuard<L> where L: AsMutLua {
    fn as_lua(&self) -> LuaContext {
        self.lua.as_lua()
    }
}

unsafe impl<L> AsMutLua for PushGuard<L> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.lua.as_mut_lua()
    }
}

unsafe impl<'a, L> AsLua for &'a L where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        (**self).as_lua()
    }
}

unsafe impl<'a, L> AsLua for &'a mut L where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        (**self).as_lua()
    }
}

unsafe impl<'a, L> AsMutLua for &'a mut L where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        (**self).as_mut_lua()
    }
}

/// Types that can be given to a Lua context, for example with `lua.set()` or as a return value
/// of a function.
pub trait Push<L> where L: AsMutLua {
    /// Pushes the value on the top of the stack.
    ///
    /// Must return a guard representing the elements that have been pushed.
    ///
    /// You can implement this for any type you want by redirecting to call to
    /// another implementation (for example `5.push_to_lua`) or by calling
    /// `userdata::push_userdata`.
    fn push_to_lua(self, lua: L) -> PushGuard<L>;
}

/// Types that can be obtained from a Lua context.
///
/// Most types that implement `Push` also implement `LuaRead`, but this is not always the case
/// (for example `&'static str` implements `Push` but not `LuaRead`).
pub trait LuaRead<L>: Sized where L: AsLua {
    /// Reads the data from Lua.
    fn lua_read(lua: L) -> Result<Self, L> {
        LuaRead::lua_read_at_position(lua, -1)
    }

    /// Reads the data from Lua at a given position.
    fn lua_read_at_position(lua: L, index: i32) -> Result<Self, L>;
}

/// Error that can happen when executing Lua code.
#[derive(Debug)]
pub enum LuaError {
    /// There was a syntax error when parsing the Lua code.
    SyntaxError(String),

    /// There was an error during execution of the Lua code
    /// (for example not enough parameters for a function call).
    ExecutionError(String),

    /// There was an IoError while reading the source code to execute.
    ReadError(IoError),

    /// The call to `execute` has requested the wrong type of data.
    WrongType,
}

impl<'lua> Lua<'lua> {
    /// Builds a new Lua context.
    ///
    /// # Panic
    ///
    /// The function panics if the underlying call to `lua_newstate` fails
    /// (which indicates lack of memory).
    pub fn new() -> Lua<'lua> {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::null_mut()) };
        if lua.is_null() {
            panic!("lua_newstate failed");
        }

        // this alloc function is required to create a lua state.
        extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t,
                            nsize: libc::size_t) -> *mut libc::c_void
        {
            unsafe {
                if nsize == 0 {
                    libc::free(ptr as *mut libc::c_void);
                    std::ptr::null_mut()
                } else {
                    libc::realloc(ptr, nsize)
                }
            }
        }

        // called whenever lua encounters an unexpected error.
        extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
            let err = unsafe { ffi::lua_tostring(lua, -1) };
            let err = unsafe { CStr::from_ptr(err) };
            let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();
            panic!("PANIC: unprotected error in call to Lua API ({})\n", err);
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: LuaContext(lua),
            must_be_closed: true,
            marker: PhantomData,
        }
    }

    /// Takes an existing `lua_State` and build a Lua object from it.
    ///
    /// # Arguments
    ///
    ///  * `close_at_the_end`: if true, lua_close will be called on the lua_State on the destructor
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua<'lua> {
        Lua {
            lua: std::mem::transmute(lua),
            must_be_closed: close_at_the_end,
            marker: PhantomData,
        }
    }

    /// Opens all standard Lua libraries.
    /// This is done by calling `luaL_openlibs`.
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua.0) }
    }

    /// Executes some Lua code on the context.
    pub fn execute<'a, T>(&'a mut self, code: &str) -> Result<T, LuaError>
                          where T: for<'g> LuaRead<PushGuard<&'g mut PushGuard<&'a mut Lua<'lua>>>>
    {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /// Executes some Lua code on the context.
    pub fn execute_from_reader<'a, T, R>(&'a mut self, code: R) -> Result<T, LuaError>
            where T: for<'g> LuaRead<PushGuard<&'g mut PushGuard<&'a mut Lua<'lua>>>>,
                  R: Read
    {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /// Reads the value of a global variable.
    pub fn get<'l, V, I>(&'l mut self, index: I) -> Option<V>
                         where I: Borrow<str>, V: LuaRead<PushGuard<&'l mut Lua<'lua>>>
    {
        let index = CString::new(index.borrow()).unwrap();
        unsafe { ffi::lua_getglobal(self.lua.0, index.as_ptr()); }
        let guard = PushGuard { lua: self, size: 1 };
        LuaRead::lua_read(guard).ok()
    }

    /// Reads the value of a global, capturing the context by value.
    pub fn into_get<V, I>(self, index: I) -> Result<V, PushGuard<Self>>
        where I: Borrow<str>, V: LuaRead<PushGuard<Lua<'lua>>>
    {
        let index = CString::new(index.borrow()).unwrap();
        unsafe { ffi::lua_getglobal(self.lua.0, index.as_ptr()); }
        let guard = PushGuard { lua: self, size: 1 };
        LuaRead::lua_read(guard)
    }

    /// Modifies the value of a global variable.
    pub fn set<I, V>(&mut self, index: I, value: V)
                         where I: Borrow<str>, for<'a> V: Push<&'a mut Lua<'lua>>
    {
        let index = CString::new(index.borrow()).unwrap();
        value.push_to_lua(self).forget();
        unsafe { ffi::lua_setglobal(self.lua.0, index.as_ptr()); }
    }

    /// Inserts an empty array, then loads it.
    pub fn empty_array<'a, I>(&'a mut self, index: I) -> LuaTable<PushGuard<&'a mut Lua<'lua>>>
                              where I: Borrow<str>
    {
        // TODO: cleaner implementation
        let mut me = self;
        let index2 = CString::new(index.borrow()).unwrap();
        Vec::<u8>::with_capacity(0).push_to_lua(&mut me).forget();
        unsafe { ffi::lua_setglobal(me.lua.0, index2.as_ptr()); }

        me.get(index).unwrap()
    }
}

impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua.0) }
        }
    }
}

impl<L> Drop for PushGuard<L> where L: AsMutLua {
    fn drop(&mut self) {
        if self.size != 0 {
            unsafe { ffi::lua_pop(self.lua.as_mut_lua().0, self.size); }
        }
    }
}
<commit_msg>Made Lua.get return None if the value is nil, even if the type being casted to has a value for nil<commit_after>extern crate lua52_sys as ffi;
extern crate libc;

use std::ffi::{CStr, CString};
use std::io::Read;
use std::io::Error as IoError;
use std::borrow::Borrow;
use std::marker::PhantomData;

pub use functions_read::LuaFunction;
pub use functions_write::{Function, InsideCallback};
pub use functions_write::{function0, function1, function2, function3, function4, function5};
pub use functions_write::{function6, function7, function8, function9, function10};
pub use lua_tables::LuaTable;
pub mod any;
pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod functions_write;
mod macros;
mod rust_tables;
mod values;
mod tuples;

/// Main object of the library.
///
/// The lifetime parameter corresponds to the lifetime of the content of the Lua context.
pub struct Lua<'lua> {
    lua: LuaContext,
    must_be_closed: bool,
    marker: PhantomData<&'lua ()>,
}

/// RAII guard for a value pushed on the stack.
pub struct PushGuard<L> where L: AsMutLua {
    lua: L,
    size: i32,
}

impl<L> PushGuard<L> where L: AsMutLua {
    /// Prevents the value from being poped when the `PushGuard` is destroyed, and returns the
    /// number of elements on the stack.
    fn forget(mut self) -> i32 {
        let size = self.size;
        self.size = 0;
        size
    }

    /// Destroys the guard, popping the value. Returns the inner part,
    /// which returns access when using by-value capture.
    pub fn into_inner(mut self) -> L {
        use std::{mem, ptr};

        let mut res;
        unsafe {
            res = mem::uninitialized();
            ptr::copy_nonoverlapping(&self.lua, &mut res, 1);
            if self.size != 0 {
                ffi::lua_pop(self.lua.as_mut_lua().0, self.size);
            }
        };
        mem::forget(self);

        res
    }
}

/// Trait for objects that have access to a Lua context. When using a context returned by a
/// `AsLua`, you are not allowed to modify the stack.
pub unsafe trait AsLua {
    fn as_lua(&self) -> LuaContext;
}

/// Trait for objects that have access to a Lua context. You are allowed to modify the stack, but
/// it must be in the same state as it was when you started.
pub unsafe trait AsMutLua: AsLua {
    fn as_mut_lua(&mut self) -> LuaContext;
}

/// Opaque type that contains the raw Lua context.
#[derive(Copy, Clone)]
#[allow(raw_pointer_derive)]
pub struct LuaContext(*mut ffi::lua_State);
unsafe impl Send for LuaContext {}

unsafe impl<'a, 'lua> AsLua for Lua<'lua> {
    fn as_lua(&self) -> LuaContext {
        self.lua
    }
}

unsafe impl<'lua> AsMutLua for Lua<'lua> {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.lua
    }
}

unsafe impl<L> AsLua for PushGuard<L> where L: AsMutLua {
    fn as_lua(&self) -> LuaContext {
        self.lua.as_lua()
    }
}

unsafe impl<L> AsMutLua for PushGuard<L> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.lua.as_mut_lua()
    }
}

unsafe impl<'a, L> AsLua for &'a L where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        (**self).as_lua()
    }
}

unsafe impl<'a, L> AsLua for &'a mut L where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        (**self).as_lua()
    }
}

unsafe impl<'a, L> AsMutLua for &'a mut L where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        (**self).as_mut_lua()
    }
}

/// Types that can be given to a Lua context, for example with `lua.set()` or as a return value
/// of a function.
pub trait Push<L> where L: AsMutLua {
    /// Pushes the value on the top of the stack.
    ///
    /// Must return a guard representing the elements that have been pushed.
    ///
    /// You can implement this for any type you want by redirecting to call to
    /// another implementation (for example `5.push_to_lua`) or by calling
    /// `userdata::push_userdata`.
    fn push_to_lua(self, lua: L) -> PushGuard<L>;
}

/// Types that can be obtained from a Lua context.
///
/// Most types that implement `Push` also implement `LuaRead`, but this is not always the case
/// (for example `&'static str` implements `Push` but not `LuaRead`).
pub trait LuaRead<L>: Sized where L: AsLua {
    /// Reads the data from Lua.
    fn lua_read(lua: L) -> Result<Self, L> {
        LuaRead::lua_read_at_position(lua, -1)
    }

    /// Reads the data from Lua at a given position.
    fn lua_read_at_position(lua: L, index: i32) -> Result<Self, L>;
}

/// Error that can happen when executing Lua code.
#[derive(Debug)]
pub enum LuaError {
    /// There was a syntax error when parsing the Lua code.
    SyntaxError(String),

    /// There was an error during execution of the Lua code
    /// (for example not enough parameters for a function call).
    ExecutionError(String),

    /// There was an IoError while reading the source code to execute.
    ReadError(IoError),

    /// The call to `execute` has requested the wrong type of data.
    WrongType,
}

impl<'lua> Lua<'lua> {
    /// Builds a new Lua context.
    ///
    /// # Panic
    ///
    /// The function panics if the underlying call to `lua_newstate` fails
    /// (which indicates lack of memory).
    pub fn new() -> Lua<'lua> {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::null_mut()) };
        if lua.is_null() {
            panic!("lua_newstate failed");
        }

        // this alloc function is required to create a lua state.
        extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t,
                            nsize: libc::size_t) -> *mut libc::c_void
        {
            unsafe {
                if nsize == 0 {
                    libc::free(ptr as *mut libc::c_void);
                    std::ptr::null_mut()
                } else {
                    libc::realloc(ptr, nsize)
                }
            }
        }

        // called whenever lua encounters an unexpected error.
        extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
            let err = unsafe { ffi::lua_tostring(lua, -1) };
            let err = unsafe { CStr::from_ptr(err) };
            let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();
            panic!("PANIC: unprotected error in call to Lua API ({})\n", err);
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: LuaContext(lua),
            must_be_closed: true,
            marker: PhantomData,
        }
    }

    /// Takes an existing `lua_State` and build a Lua object from it.
    ///
    /// # Arguments
    ///
    ///  * `close_at_the_end`: if true, lua_close will be called on the lua_State on the destructor
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua<'lua> {
        Lua {
            lua: std::mem::transmute(lua),
            must_be_closed: close_at_the_end,
            marker: PhantomData,
        }
    }

    /// Opens all standard Lua libraries.
    /// This is done by calling `luaL_openlibs`.
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua.0) }
    }

    /// Executes some Lua code on the context.
    pub fn execute<'a, T>(&'a mut self, code: &str) -> Result<T, LuaError>
                          where T: for<'g> LuaRead<PushGuard<&'g mut PushGuard<&'a mut Lua<'lua>>>>
    {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /// Executes some Lua code on the context.
    pub fn execute_from_reader<'a, T, R>(&'a mut self, code: R) -> Result<T, LuaError>
            where T: for<'g> LuaRead<PushGuard<&'g mut PushGuard<&'a mut Lua<'lua>>>>,
                  R: Read
    {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /// Reads the value of a global variable.
    pub fn get<'l, V, I>(&'l mut self, index: I) -> Option<V>
                         where I: Borrow<str>, V: LuaRead<PushGuard<&'l mut Lua<'lua>>>
    {
        let index = CString::new(index.borrow()).unwrap();
        unsafe { ffi::lua_getglobal(self.lua.0, index.as_ptr()); }
        if unsafe { ffi::lua_isnil(self.as_lua().0, -1) } {
            let _guard = PushGuard { lua: self, size: 1 };
            return None;
        }
        let guard = PushGuard { lua: self, size: 1 };
        LuaRead::lua_read(guard).ok()
    }

    /// Reads the value of a global, capturing the context by value.
    pub fn into_get<V, I>(self, index: I) -> Result<V, PushGuard<Self>>
        where I: Borrow<str>, V: LuaRead<PushGuard<Lua<'lua>>>
    {
        let index = CString::new(index.borrow()).unwrap();
        unsafe { ffi::lua_getglobal(self.lua.0, index.as_ptr()); }
        let guard = PushGuard { lua: self, size: 1 };
        LuaRead::lua_read(guard)
    }

    /// Modifies the value of a global variable.
    pub fn set<I, V>(&mut self, index: I, value: V)
                         where I: Borrow<str>, for<'a> V: Push<&'a mut Lua<'lua>>
    {
        let index = CString::new(index.borrow()).unwrap();
        value.push_to_lua(self).forget();
        unsafe { ffi::lua_setglobal(self.lua.0, index.as_ptr()); }
    }

    /// Inserts an empty array, then loads it.
    pub fn empty_array<'a, I>(&'a mut self, index: I) -> LuaTable<PushGuard<&'a mut Lua<'lua>>>
                              where I: Borrow<str>
    {
        // TODO: cleaner implementation
        let mut me = self;
        let index2 = CString::new(index.borrow()).unwrap();
        Vec::<u8>::with_capacity(0).push_to_lua(&mut me).forget();
        unsafe { ffi::lua_setglobal(me.lua.0, index2.as_ptr()); }

        me.get(index).unwrap()
    }
}

impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua.0) }
        }
    }
}

impl<L> Drop for PushGuard<L> where L: AsMutLua {
    fn drop(&mut self) {
        if self.size != 0 {
            unsafe { ffi::lua_pop(self.lua.as_mut_lua().0, self.size); }
        }
    }
}
<|endoftext|>


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

use ctl10n;

const LOCALES: &[&str] = &["zh", "en"];

fn main() {
    for locale in LOCALES {
        println!("cargo:rerun-if-changed=locales/{}.toml", locale);
    }
    if let Err(err) = ctl10n::convert_strings_file(
        format!(
            "locales/{}.toml",
            &env::var("LOCALE").unwrap_or("zh".to_string())
        ),
        Path::new(&env::var("OUT_DIR").unwrap()).join("ctl10n_macros.rs"),
    ) {
        panic!("{}", err);
    }
}
<commit_msg>Rerun build.rs when LOCALE changed<commit_after>use std::env;
use std::path::Path;

use ctl10n;

const LOCALES: &[&str] = &["zh", "en"];

fn main() {
    for locale in LOCALES {
        println!("cargo:rerun-if-changed=locales/{}.toml", locale);
    }
    println!("cargo:rerun-if-env-changed=LOCALE");
    if let Err(err) = ctl10n::convert_strings_file(
        format!(
            "locales/{}.toml",
            &env::var("LOCALE").unwrap_or("zh".to_string())
        ),
        Path::new(&env::var("OUT_DIR").unwrap()).join("ctl10n_macros.rs"),
    ) {
        panic!("{}", err);
    }
}
<|endoftext|>


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

use ctl10n;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=locales/*.toml");
    if let Err(err) = ctl10n::convert_strings_file(
        format!(
            "locales/{}.toml",
            &env::var("LOCALE").unwrap_or("zh".to_string())
        ),
        Path::new(&env::var("OUT_DIR").unwrap()).join("ctl10n_macros.rs"),
    ) {
        panic!("{}", err);
    }
}
<commit_msg>Remove build.rs from rerun-if-changed, it is default dependent<commit_after>use std::env;
use std::path::Path;

use ctl10n;

fn main() {
    println!("cargo:rerun-if-changed=locales/*.toml");
    if let Err(err) = ctl10n::convert_strings_file(
        format!(
            "locales/{}.toml",
            &env::var("LOCALE").unwrap_or("zh".to_string())
        ),
        Path::new(&env::var("OUT_DIR").unwrap()).join("ctl10n_macros.rs"),
    ) {
        panic!("{}", err);
    }
}
<|endoftext|>


<commit_before>/*use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;*/

fn main() -> () {
    println!("cargo:rustc-link-search=native={}/blis/lib", std::env::home_dir().unwrap().to_str().unwrap() );
    println!("cargo:rustc-link-search=native=/usr/local/lib");
    println!("cargo:rustc-link-lib=static=blis");

//  The following is needed for compiling with mkl
//    println!("cargo:rustc-link-lib=static=irc");
}
<commit_msg>change build.rs so it links to libgomp.so on ubuntu<commit_after>/*use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;*/

fn main() -> () {
    println!("cargo:rustc-link-search=native={}/blis/lib", std::env::home_dir().unwrap().to_str().unwrap() );
    println!("cargo:rustc-link-search=native=/usr/local/lib");
    println!("cargo:rustc-link-lib=static=blis");
//
//    println!("cargo:rustc-link-search=native=/usr/lib/gcc/x86_64-linux-gnu/5");
//    println!("cargo:rustc-link-lib=static=gomp");
    println!("cargo:rustc-link-search=native=/usr/lib/gcc/x86_64-linux-gnu/5");
    println!("cargo:rustc-link-lib=dylib=gomp");

//  The following is needed for compiling with mkl
//    println!("cargo:rustc-link-lib=static=irc");
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::env;

#[cfg(not(feature = "orangepi"))]
const TARGET: &'static str = "wiringpi";
#[cfg(feature = "orangepi")]
const TARGET: &'static str = "wiringop";

fn main() {
    if cfg!(feature = "development") {
        return;
    }
    if let Ok(target) = env::var("TARGET") {
        if !target.starts_with("arm-") {
            return;
        }
    }

    let out_dir = env::var("OUT_DIR").unwrap();
    match Command::new("make").arg("-e").arg(TARGET).status() {
        Ok(status) if !status.success() => panic!(
            "failed to build wiringPi C library (exit code {:?})",
            status.code()
        ),
        Err(e) => panic!("failed to build wiringPi C library: {}", e),
        _ => {}
    }
    println!("cargo:rustc-flags=-L native={} -l static=wiringpi", out_dir);
}
<commit_msg>Fix build for cross-compilation<commit_after>use std::process::Command;
use std::env;

#[cfg(not(feature = "orangepi"))]
const TARGET: &'static str = "wiringpi";
#[cfg(feature = "orangepi")]
const TARGET: &'static str = "wiringop";

fn main() {
    if cfg!(feature = "development") {
        return;
    }

    let out_dir = env::var("OUT_DIR").unwrap();

    let target = env::var("TARGET").unwrap();
    match target.as_str() {
        "armv7-unknown-linux-gnueabihf" => {
            env::set_var("CC", "arm-linux-gnueabihf-gcc");
        },
        _ => {}
    }

    match Command::new("make").arg("-e").arg(TARGET).status() {
        Ok(status) if !status.success() => panic!(
            "failed to build wiringPi C library (exit code {:?})",
            status.code()
        ),
        Err(e) => panic!("failed to build wiringPi C library: {}", e),
        _ => {}
    }

    println!("cargo:rustc-link-lib-static=wiringpi");
    println!("cargo:rustc-link-search={}", out_dir);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bencher;

extern crate gluon;

extern crate bincode;
extern crate serde_state;

use std::fs::File;
use std::io::Read;

use bencher::{black_box, Bencher};

use serde_state::ser::SerializeState;

use gluon::{new_vm, Compiler, Future};
use gluon::vm::thread::ThreadInternal;
use gluon::vm::serialization::SeSeed;

fn precompiled_prelude(b: &mut Bencher) {
    let thread = new_vm();
    Compiler::new()
        .implicit_prelude(false)
        .load_file(&thread, "std/prelude.glu")
        .unwrap();
    let mut serialized_prelude = Vec::new();
    {
        let env = thread.global_env().get_env();
        let prelude = env.globals.get("std.prelude").unwrap();
        prelude
            .serialize_state(
                &mut bincode::Serializer::new(&mut serialized_prelude),
                &SeSeed::new(),
            )
            .unwrap();
    }
    b.iter(|| {
        use gluon::compiler_pipeline::{Executable, Precompiled};

        let mut deserializer = bincode::Deserializer::new(
            bincode::read_types::SliceReader::new(&serialized_prelude),
            bincode::Infinite,
        );
        let result = Precompiled(&mut deserializer)
            .run_expr(&mut Compiler::new(), &*thread, "std.prelude", "", ())
            .wait()
            .unwrap();
        black_box(result)
    })
}

fn source_prelude(b: &mut Bencher) {
    let mut prelude_source = String::new();
    File::open("std/prelude.glu")
        .and_then(|mut f| f.read_to_string(&mut prelude_source))
        .unwrap();
    let thread = new_vm();

    b.iter(|| {
        use gluon::compiler_pipeline::Executable;

        let result = prelude_source
            .run_expr(
                &mut Compiler::new(),
                &*thread,
                "std.prelude",
                &prelude_source,
                None,
            )
            .wait()
            .unwrap();
        black_box(result)
    })
}

benchmark_group!(precompiled, precompiled_prelude, source_prelude);
benchmark_main!(precompiled);
<commit_msg>test: Fix the precompiled benchmark<commit_after>#[macro_use]
extern crate bencher;

extern crate gluon;

extern crate bincode;
extern crate serde_json;
extern crate serde_state;

use std::fs::File;
use std::io::Read;

use bencher::{black_box, Bencher};

use gluon::{new_vm, Compiler, Future};
use gluon::compiler_pipeline::compile_to;

fn precompiled_prelude(b: &mut Bencher) {
    let thread = new_vm();
    let prelude = {
        let mut out = String::new();
        File::open("std/prelude.glu")
            .unwrap()
            .read_to_string(&mut out)
            .unwrap();
        out
    };
    let mut serialized_prelude = Vec::new();
    {
        let mut serializer = serde_json::Serializer::new(&mut serialized_prelude);
        compile_to(
            &prelude[..],
            &mut Compiler::new(),
            &thread,
            "std.prelude",
            &prelude,
            None,
            &mut serializer,
        ).unwrap()
    }
    b.iter(|| {
        use gluon::compiler_pipeline::{Executable, Precompiled};

        let mut deserializer = serde_json::Deserializer::from_slice(&serialized_prelude);
        let result = Precompiled(&mut deserializer)
            .run_expr(&mut Compiler::new(), &*thread, "std.prelude", "", ())
            .wait()
            .unwrap();
        black_box(result)
    })
}

fn source_prelude(b: &mut Bencher) {
    let mut prelude_source = String::new();
    File::open("std/prelude.glu")
        .and_then(|mut f| f.read_to_string(&mut prelude_source))
        .unwrap();
    let thread = new_vm();

    b.iter(|| {
        use gluon::compiler_pipeline::Executable;

        let result = prelude_source
            .run_expr(
                &mut Compiler::new(),
                &*thread,
                "std.prelude",
                &prelude_source,
                None,
            )
            .wait()
            .unwrap();
        black_box(result)
    })
}

benchmark_group!(precompiled, precompiled_prelude, source_prelude);
benchmark_main!(precompiled);
<|endoftext|>