<commit_before>#![feature(collections, convert, core, os, path_ext, rustc_private, tempdir)]

extern crate serialize;

use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
use std::fs::{File, PathExt, TempDir};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

fn main() {
    let (args, passthrough) = parse_arguments();

    // Find all the native shared libraries that exist in the target directory.
    let native_shared_libs = find_native_libs(&args);

    // Get the SDK path from the ANDROID_HOME env.
    let sdk_path = env::var("ANDROID_HOME").ok().expect("Please set the ANDROID_HOME environment variable");
    let sdk_path = Path::new(&sdk_path);

    // Get the NDK path from NDK_HOME env.
    let ndk_path = env::var("NDK_HOME").ok().expect("Please set the NDK_HOME environment variable");
    let ndk_path = Path::new(&ndk_path);

    // Get the standalone NDK path from NDK_STANDALONE env.
    let standalone_path = env::var("NDK_STANDALONE").ok().unwrap_or("/opt/ndk_standalone".to_string());
    let standalone_path = Path::new(&standalone_path);

    // creating the build directory that will contain all the necessary files to create the apk
    let directory = build_directory(&sdk_path, args.output.file_stem().and_then(|s| s.to_str()).unwrap(), &native_shared_libs);

    // Copy the additional native libs into the libs directory.
    for (name, path) in native_shared_libs.iter() {
        fs::copy(path, &directory.path().join("libs").join("armeabi").join(name)).unwrap();
    }

    // Set the paths for the tools used in one central place. Then we also use this to not
    // only invoke the tool when needed, but also to check before first invocation in order
    // to display a nice error message to the user if the tool is missing from the path.
    let toolgccpath = standalone_path.join("bin").join("arm-linux-androideabi-gcc");
    let toolantpath = Path::new("ant");

    if !&toolgccpath.exists() {
        println!("Missing Tool `{}`!", toolgccpath.display());
        std::os::set_exit_status(1);
    }
    // compiling android_native_app_glue.c
    if Command::new(&toolgccpath.clone())
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .status().unwrap().code().unwrap() != 0
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to a shared object
    if Command::new(&toolgccpath.clone())
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-shared")
        .arg("-Wl,-E")
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())//.current_dir(directory.path())
        .status().unwrap().code().unwrap() != 0
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling objdump to make sure that our object has `ANativeActivity_onCreate`
    // TODO: not working
    /*{
        let mut process =
            Command::new(standalone_path.join("bin").join("arm-linux-androideabi-objdump"))
            .arg("-x").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
            .stderr(Stdio::inherit())
            .spawn().unwrap();

        // TODO: use UFCS instead
        fn by_ref<'a, T: Reader>(r: &'a mut T) -> std::old_io::RefReader<'a, T> { r.by_ref() };

        let stdout = process.stdout.as_mut().unwrap();
        let mut stdout = std::old_io::BufferedReader::new(by_ref(stdout));

        if stdout.lines().filter_map(|l| l.ok())
            .find(|line| line.as_slice().contains("ANativeActivity_onCreate")).is_none()
        {
            println!("Error: the output file doesn't contain ANativeActivity_onCreate");
            std::os::set_exit_status(1);
            return;
        }
    }*/

    copy_assets(&directory.path());

    // executing ant
    let antcmd = Command::new(toolantpath).arg("debug")
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .current_dir(directory.path())
        .status();
    if antcmd.is_err() || antcmd.unwrap().code().unwrap() != 0 {
        println!("Error while executing program `ant` debug, or missing program.");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &args.output).unwrap();
}

#[cfg(feature = "assets_hack")]
fn copy_assets(build_path: &Path) {
    let cwd = std::os::getcwd().ok()
        .expect("Can not get current working directory!");
    let assets_path = cwd.join("assets");
    if assets_path.exists() {
        fs::symlink(&assets_path, &build_path.join("assets"))
            .ok().expect("Can not create symlink to assets");
    }
}

#[cfg(not(feature = "assets_hack"))]
fn copy_assets(_: &Path) {}

struct Args {
    output: PathBuf,
    library_path: Vec<PathBuf>,
    shared_libraries: HashSet<String>,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_library_path = Vec::new();
    let mut result_shared_libraries = HashSet::new();
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.into_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument"),
                    library_path: result_library_path,
                    shared_libraries: result_shared_libraries,
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(PathBuf::from(args.next().expect("-o must be followed by the output name")));
            },
            "-L" => {
                let path = args.next().expect("-L must be followed by a path");
                result_library_path.push(PathBuf::from(path.clone()));

                // Also pass these through.
                result_passthrough.push(arg);
                result_passthrough.push(path);
            },
            _ => {
                if arg.starts_with("-l") {
                    result_shared_libraries.insert(vec!["lib", &arg[2..], ".so"].concat());
                }
                result_passthrough.push(arg)
            }
        };
    }
}

fn find_native_libs(args: &Args) -> HashMap<String, PathBuf> {
    let mut native_shared_libs: HashMap<String, PathBuf> = HashMap::new();

    for dir in &args.library_path {
        fs::read_dir(&dir).and_then(|paths| {
            for path in paths {
                let path = path.unwrap().path();
                match (path.file_name(), path.extension()) {
                    (Some(filename), Some(ext)) => {
                        let filename = filename.to_str().unwrap();
                        if filename.starts_with("lib")
                            && ext == "so"
                            && args.shared_libraries.contains(filename) {
                            native_shared_libs.insert(filename.to_string(), path.clone());
                        }
                    }
                    _ => {}
                }
            }
            Ok(())
        }).ok();
    }
    native_shared_libs
}

fn build_directory(sdk_dir: &Path, crate_name: &str, libs: &HashMap<String, PathBuf>) -> TempDir {
    use std::io::Write;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    let activity_name = if libs.len() > 0 {
        let src_path = build_directory.path().join("src/rust/glutin");
        fs::create_dir_all(&src_path).unwrap();

        File::create(&src_path.join("MainActivity.java")).unwrap()
            .write_all(java_src(libs).as_bytes())
            .unwrap();

        "rust.glutin.MainActivity"
    } else {
        "android.app.NativeActivity"
    };

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_all(build_manifest(crate_name, activity_name).as_bytes())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_all(build_build_xml().as_bytes())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_all(build_local_properties(sdk_dir).as_bytes())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_all(build_project_properties().as_bytes())
        .unwrap();

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::create_dir_all(&libs_path).unwrap();
    }

    {
        // Make sure that 'src' directory is creates
        let src_path = build_directory.path().join("src");
        fs::create_dir_all(&src_path).unwrap();
    }

    build_directory
}

fn java_src(libs: &HashMap<String, PathBuf>) -> String {
    let mut libs_string = "".to_string();

    for (name, _) in libs.iter() {
        // Strip off the 'lib' prefix and ".so" suffix. This is safe since libs only get added
        // to the hash map if they start with lib.
        let line = format!("        System.loadLibrary(\"{}\");\n", name.slice(3, name.len()-3));
        libs_string.push_str(line.as_slice());
    }

    format!(r#"package rust.glutin;

public class MainActivity extends android.app.NativeActivity {{
    static {{
        {0}
    }}
}}"#, libs_string)
}

fn build_manifest(crate_name: &str, activity_name: &str) -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="9" />

    <uses-feature android:glEsVersion="0x00020000" android:required="true"></uses-feature>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application android:label="{0}">
        <activity android:name="{1}"
                android:label="{0}"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#, crate_name, activity_name)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    let abs_dir = if sdk_dir.is_absolute() {
        sdk_dir.to_path_buf()
    } else {
        env::current_dir().unwrap().join(sdk_dir)
    };
    format!(r"sdk.dir={:?}", abs_dir)
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}
<commit_msg>Fix sdk.dir written to local.properties to have no quotes.<commit_after>#![feature(collections, convert, core, os, path_ext, rustc_private, tempdir)]

extern crate serialize;

use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
use std::fs::{File, PathExt, TempDir};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

fn main() {
    let (args, passthrough) = parse_arguments();

    // Find all the native shared libraries that exist in the target directory.
    let native_shared_libs = find_native_libs(&args);

    // Get the SDK path from the ANDROID_HOME env.
    let sdk_path = env::var("ANDROID_HOME").ok().expect("Please set the ANDROID_HOME environment variable");
    let sdk_path = Path::new(&sdk_path);

    // Get the NDK path from NDK_HOME env.
    let ndk_path = env::var("NDK_HOME").ok().expect("Please set the NDK_HOME environment variable");
    let ndk_path = Path::new(&ndk_path);

    // Get the standalone NDK path from NDK_STANDALONE env.
    let standalone_path = env::var("NDK_STANDALONE").ok().unwrap_or("/opt/ndk_standalone".to_string());
    let standalone_path = Path::new(&standalone_path);

    // creating the build directory that will contain all the necessary files to create the apk
    let directory = build_directory(&sdk_path, args.output.file_stem().and_then(|s| s.to_str()).unwrap(), &native_shared_libs);

    // Copy the additional native libs into the libs directory.
    for (name, path) in native_shared_libs.iter() {
        fs::copy(path, &directory.path().join("libs").join("armeabi").join(name)).unwrap();
    }

    // Set the paths for the tools used in one central place. Then we also use this to not
    // only invoke the tool when needed, but also to check before first invocation in order
    // to display a nice error message to the user if the tool is missing from the path.
    let toolgccpath = standalone_path.join("bin").join("arm-linux-androideabi-gcc");
    let toolantpath = Path::new("ant");

    if !&toolgccpath.exists() {
        println!("Missing Tool `{}`!", toolgccpath.display());
        std::os::set_exit_status(1);
    }
    // compiling android_native_app_glue.c
    if Command::new(&toolgccpath.clone())
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .status().unwrap().code().unwrap() != 0
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to a shared object
    if Command::new(&toolgccpath.clone())
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-shared")
        .arg("-Wl,-E")
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())//.current_dir(directory.path())
        .status().unwrap().code().unwrap() != 0
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling objdump to make sure that our object has `ANativeActivity_onCreate`
    // TODO: not working
    /*{
        let mut process =
            Command::new(standalone_path.join("bin").join("arm-linux-androideabi-objdump"))
            .arg("-x").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
            .stderr(Stdio::inherit())
            .spawn().unwrap();

        // TODO: use UFCS instead
        fn by_ref<'a, T: Reader>(r: &'a mut T) -> std::old_io::RefReader<'a, T> { r.by_ref() };

        let stdout = process.stdout.as_mut().unwrap();
        let mut stdout = std::old_io::BufferedReader::new(by_ref(stdout));

        if stdout.lines().filter_map(|l| l.ok())
            .find(|line| line.as_slice().contains("ANativeActivity_onCreate")).is_none()
        {
            println!("Error: the output file doesn't contain ANativeActivity_onCreate");
            std::os::set_exit_status(1);
            return;
        }
    }*/

    copy_assets(&directory.path());

    // executing ant
    let antcmd = Command::new(toolantpath).arg("debug")
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .current_dir(directory.path())
        .status();
    if antcmd.is_err() || antcmd.unwrap().code().unwrap() != 0 {
        println!("Error while executing program `ant` debug, or missing program.");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &args.output).unwrap();
}

#[cfg(feature = "assets_hack")]
fn copy_assets(build_path: &Path) {
    let cwd = std::os::getcwd().ok()
        .expect("Can not get current working directory!");
    let assets_path = cwd.join("assets");
    if assets_path.exists() {
        fs::symlink(&assets_path, &build_path.join("assets"))
            .ok().expect("Can not create symlink to assets");
    }
}

#[cfg(not(feature = "assets_hack"))]
fn copy_assets(_: &Path) {}

struct Args {
    output: PathBuf,
    library_path: Vec<PathBuf>,
    shared_libraries: HashSet<String>,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_library_path = Vec::new();
    let mut result_shared_libraries = HashSet::new();
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.into_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument"),
                    library_path: result_library_path,
                    shared_libraries: result_shared_libraries,
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(PathBuf::from(args.next().expect("-o must be followed by the output name")));
            },
            "-L" => {
                let path = args.next().expect("-L must be followed by a path");
                result_library_path.push(PathBuf::from(path.clone()));

                // Also pass these through.
                result_passthrough.push(arg);
                result_passthrough.push(path);
            },
            _ => {
                if arg.starts_with("-l") {
                    result_shared_libraries.insert(vec!["lib", &arg[2..], ".so"].concat());
                }
                result_passthrough.push(arg)
            }
        };
    }
}

fn find_native_libs(args: &Args) -> HashMap<String, PathBuf> {
    let mut native_shared_libs: HashMap<String, PathBuf> = HashMap::new();

    for dir in &args.library_path {
        fs::read_dir(&dir).and_then(|paths| {
            for path in paths {
                let path = path.unwrap().path();
                match (path.file_name(), path.extension()) {
                    (Some(filename), Some(ext)) => {
                        let filename = filename.to_str().unwrap();
                        if filename.starts_with("lib")
                            && ext == "so"
                            && args.shared_libraries.contains(filename) {
                            native_shared_libs.insert(filename.to_string(), path.clone());
                        }
                    }
                    _ => {}
                }
            }
            Ok(())
        }).ok();
    }
    native_shared_libs
}

fn build_directory(sdk_dir: &Path, crate_name: &str, libs: &HashMap<String, PathBuf>) -> TempDir {
    use std::io::Write;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    let activity_name = if libs.len() > 0 {
        let src_path = build_directory.path().join("src/rust/glutin");
        fs::create_dir_all(&src_path).unwrap();

        File::create(&src_path.join("MainActivity.java")).unwrap()
            .write_all(java_src(libs).as_bytes())
            .unwrap();

        "rust.glutin.MainActivity"
    } else {
        "android.app.NativeActivity"
    };

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_all(build_manifest(crate_name, activity_name).as_bytes())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_all(build_build_xml().as_bytes())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_all(build_local_properties(sdk_dir).as_bytes())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_all(build_project_properties().as_bytes())
        .unwrap();

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::create_dir_all(&libs_path).unwrap();
    }

    {
        // Make sure that 'src' directory is creates
        let src_path = build_directory.path().join("src");
        fs::create_dir_all(&src_path).unwrap();
    }

    build_directory
}

fn java_src(libs: &HashMap<String, PathBuf>) -> String {
    let mut libs_string = "".to_string();

    for (name, _) in libs.iter() {
        // Strip off the 'lib' prefix and ".so" suffix. This is safe since libs only get added
        // to the hash map if they start with lib.
        let line = format!("        System.loadLibrary(\"{}\");\n", name.slice(3, name.len()-3));
        libs_string.push_str(line.as_slice());
    }

    format!(r#"package rust.glutin;

public class MainActivity extends android.app.NativeActivity {{
    static {{
        {0}
    }}
}}"#, libs_string)
}

fn build_manifest(crate_name: &str, activity_name: &str) -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="9" />

    <uses-feature android:glEsVersion="0x00020000" android:required="true"></uses-feature>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application android:label="{0}">
        <activity android:name="{1}"
                android:label="{0}"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#, crate_name, activity_name)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    let abs_dir = if sdk_dir.is_absolute() {
        sdk_dir.to_path_buf()
    } else {
        env::current_dir().unwrap().join(sdk_dir)
    };
    format!(r"sdk.dir={}", abs_dir.to_str().unwrap())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}
<|endoftext|>


<commit_before>//! Generic matrix operations

use std;

///  A cairo_matrix_t holds an affine transformation, such as a scale, rotation, shear, or a combination of those. The transformation of a point (x, y) is given by:
///
/// ```
/// x_new = xx * x + xy * y + x0;
/// y_new = yx * x + yy * y + y0;
/// ```
///
/// Since 1.0
pub struct Matrix {
  /// double xx; xx component of the affine transformation
  xx: f64,
  /// double yx; yx component of the affine transformation
  yx: f64,
  /// double xy; xy component of the affine transformation
  xy: f64,
  /// double yy; yy component of the affine transformation
  yy: f64,
  /// double x0; X translation component of the affine transformation
  x0: f64,
  /// double y0; Y translation component of the affine transformation
  y0: f64
}

impl Matrix {
  ///  Sets matrix to be the affine transformation given by xx, yx, xy, yy, x0, y0. The transformation is given by:
  ///
  /// ```
  /// x_new = xx * x + xy * y + x0;
  /// y_new = yx * x + yy * y + y0;
  /// ```
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// xx : xx component of the affine transformation
  ///
  /// yx : yx component of the affine transformation
  ///
  /// xy : xy component of the affine transformation
  ///
  /// yy : yy component of the affine transformation
  ///
  /// x0 : X translation component of the affine transformation
  ///
  /// y0 : Y translation component of the affine transformation
  ///
  /// Since 1.0
  pub fn new(xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init(&mut this, xx, yx, xy, yy, x0, y0);
      return this;
    }
  }

  ///  Modifies matrix to be an identity transformation.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// Since 1.0
  pub fn identity() -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_identity(&mut this);
      return this;
    }
  }

  ///  Initializes matrix to a transformation that translates by tx and ty in the X and Y dimensions, respectively.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// tx : amount to translate in the X direction
  ///
  /// ty : amount to translate in the Y direction
  ///
  /// Since 1.0
  pub fn for_translation(x0: f64, y0: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_translate(&mut this, x0, y0);
      return this;
    }
  }

  ///  Initializes matrix to a transformation that scales by sx and sy in the X and Y dimensions, respectively.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// sx : scale factor in the X direction
  ///
  /// sy : scale factor in the Y direction
  ///
  /// Since 1.0
  pub fn for_scale(sx: f64, sy: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_scale(&mut this, sx, sy);
      return this;
    }
  }

  ///  Initialized matrix to a transformation that rotates by radians.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// radians : angle of rotation, in radians. The direction of rotation is defined such that positive angles rotate in the direction from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, positive angles rotate in a clockwise direction.
  ///
  /// Since 1.0
  pub fn for_rotation(radians: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_rotate(&mut this, radians);
      return this;
    }
  }

  ///  Multiplies the affine transformations in a and b together and stores the result in result. The effect of the resulting transformation is to first apply the transformation in a to the coordinates and then apply the transformation in b to the coordinates.
  ///
  /// It is allowable for result to be identical to either a or b.
  ///
  /// result : a cairo_matrix_t in which to store the result
  ///
  /// a : a cairo_matrix_t
  ///
  /// b : a cairo_matrix_t
  ///
  /// Since 1.0
  pub fn multiply(a: &Matrix, b: &Matrix) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_multiply(&mut this, a, b);
      return this;
    }
  }

  ///  Applies a translation by tx, ty to the transformation in matrix. The effect of the new transformation is to first translate the coordinates by tx and ty, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// tx : amount to translate in the X direction
  ///
  /// ty : amount to translate in the Y direction
  ///
  /// Since 1.0
  pub fn translate(&mut self, x0: f64, y0: f64) {
    unsafe {
      cairo_matrix_translate(self, x0, y0);
    }
  }

  ///  Applies scaling by sx, sy to the transformation in matrix. The effect of the new transformation is to first scale the coordinates by sx and sy, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// sx : scale factor in the X direction
  ///
  /// sy : scale factor in the Y direction
  ///
  /// Since 1.0
  pub fn scale(&mut self, sx: f64, sy: f64) {
    unsafe {
      cairo_matrix_scale(self, sx, sy);
    }
  }

  ///  Applies rotation by radians to the transformation in matrix. The effect of the new transformation is to first rotate the coordinates by radians, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// radians : angle of rotation, in radians. The direction of rotation is defined such that positive angles rotate in the direction from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, positive angles rotate in a clockwise direction.
  ///
  /// Since 1.0
  pub fn rotate(&mut self, radians: f64) {
    unsafe {
      cairo_matrix_rotate(self, radians);
    }
  }

  ///  Transforms the distance vector (dx,dy) by matrix. This is similar to cairo_matrix_transform_point() except that the translation components of the transformation are ignored. The calculation of the returned vector is as follows:
  ///
  /// ```
  /// dx2 = dx1 * a + dy1 * c;
  /// dy2 = dx1 * b + dy1 * d;
  /// ```
  ///
  /// Affine transformations are position invariant, so the same vector always transforms to the same vector. If (x1,y1) transforms to (x2,y2) then (x1+dx1,y1+dy1) will transform to (x1+dx2,y1+dy2) for all values of x1 and x2.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// dx : X component of a distance vector. An in/out parameter
  ///
  /// dy : Y component of a distance vector. An in/out parameter
  ///
  /// Since 1.0
  pub fn transform_distance(&self, dx_r: f64, dy_r: f64) -> (f64, f64) {
    unsafe {
      let mut dx = dx_r;
      let mut dy = dy_r;
      cairo_matrix_transform_distance(self, &mut dx, &mut dy);
      return (dx, dy);
    }
  }

  /// Transforms the point (x, y) by matrix.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// x : X position. An in/out parameter
  ///
  /// y : Y position. An in/out parameter
  ///
  /// Since 1.0
  pub fn transform_point(&self, x_r: f64, y_r: f64) -> (f64, f64) {
    unsafe {
      let mut x = x_r;
      let mut y = y_r;
      cairo_matrix_transform_point(self, &mut x, &mut y);
      return (x, y);
    }
  }

  /// Changes matrix to be the inverse of its original value. Not all transformation matrices have inverses; if the matrix collapses points together (it is degenerate), then it has no inverse and this function will fail.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// Returns : If matrix has an inverse, modifies matrix to be the inverse matrix and returns CAIRO_STATUS_SUCCESS. Otherwise, returns CAIRO_STATUS_INVALID_MATRIX.
  ///
  /// Since 1.0
  pub fn invert(&mut self) -> super::Status {
    unsafe {
      let foreign_result = cairo_matrix_invert(self);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_matrix_init(this: *mut Matrix, xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64);
  fn cairo_matrix_init_identity(this: *mut Matrix);
  fn cairo_matrix_init_translate(this: *mut Matrix, x0: f64, y0: f64);
  fn cairo_matrix_init_scale(this: *mut Matrix, sx: f64, sy: f64);
  fn cairo_matrix_init_rotate(this: *mut Matrix, radians: f64);
  fn cairo_matrix_multiply(this: *mut Matrix, a: *Matrix, b: *Matrix);
  fn cairo_matrix_translate(self_value: *mut Matrix, x0: f64, y0: f64);
  fn cairo_matrix_scale(self_value: *mut Matrix, sx: f64, sy: f64);
  fn cairo_matrix_rotate(self_value: *mut Matrix, radians: f64);
  fn cairo_matrix_transform_distance(self_value: *Matrix, dx: &mut f64, dy: &mut f64);
  fn cairo_matrix_transform_point(self_value: *Matrix, x: &mut f64, y: &mut f64);
  fn cairo_matrix_invert(self_value: *mut Matrix) -> super::Status;
}

<commit_msg>Replaced Cairo '_t' types with Rust-Cairo types<commit_after>//! Generic matrix operations

use std;

///  A matrix::Matrix holds an affine transformation, such as a scale, rotation, shear, or a combination of those. The transformation of a point (x, y) is given by:
///
/// ```
/// x_new = xx * x + xy * y + x0;
/// y_new = yx * x + yy * y + y0;
/// ```
///
/// Since 1.0
pub struct Matrix {
  /// double xx; xx component of the affine transformation
  xx: f64,
  /// double yx; yx component of the affine transformation
  yx: f64,
  /// double xy; xy component of the affine transformation
  xy: f64,
  /// double yy; yy component of the affine transformation
  yy: f64,
  /// double x0; X translation component of the affine transformation
  x0: f64,
  /// double y0; Y translation component of the affine transformation
  y0: f64
}

impl Matrix {
  ///  Sets matrix to be the affine transformation given by xx, yx, xy, yy, x0, y0. The transformation is given by:
  ///
  /// ```
  /// x_new = xx * x + xy * y + x0;
  /// y_new = yx * x + yy * y + y0;
  /// ```
  ///
  /// matrix : a matrix::Matrix
  ///
  /// xx : xx component of the affine transformation
  ///
  /// yx : yx component of the affine transformation
  ///
  /// xy : xy component of the affine transformation
  ///
  /// yy : yy component of the affine transformation
  ///
  /// x0 : X translation component of the affine transformation
  ///
  /// y0 : Y translation component of the affine transformation
  ///
  /// Since 1.0
  pub fn new(xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init(&mut this, xx, yx, xy, yy, x0, y0);
      return this;
    }
  }

  ///  Modifies matrix to be an identity transformation.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// Since 1.0
  pub fn identity() -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_identity(&mut this);
      return this;
    }
  }

  ///  Initializes matrix to a transformation that translates by tx and ty in the X and Y dimensions, respectively.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// tx : amount to translate in the X direction
  ///
  /// ty : amount to translate in the Y direction
  ///
  /// Since 1.0
  pub fn for_translation(x0: f64, y0: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_translate(&mut this, x0, y0);
      return this;
    }
  }

  ///  Initializes matrix to a transformation that scales by sx and sy in the X and Y dimensions, respectively.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// sx : scale factor in the X direction
  ///
  /// sy : scale factor in the Y direction
  ///
  /// Since 1.0
  pub fn for_scale(sx: f64, sy: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_scale(&mut this, sx, sy);
      return this;
    }
  }

  ///  Initialized matrix to a transformation that rotates by radians.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// radians : angle of rotation, in radians. The direction of rotation is defined such that positive angles rotate in the direction from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, positive angles rotate in a clockwise direction.
  ///
  /// Since 1.0
  pub fn for_rotation(radians: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_rotate(&mut this, radians);
      return this;
    }
  }

  ///  Multiplies the affine transformations in a and b together and stores the result in result. The effect of the resulting transformation is to first apply the transformation in a to the coordinates and then apply the transformation in b to the coordinates.
  ///
  /// It is allowable for result to be identical to either a or b.
  ///
  /// result : a matrix::Matrix in which to store the result
  ///
  /// a : a matrix::Matrix
  ///
  /// b : a matrix::Matrix
  ///
  /// Since 1.0
  pub fn multiply(a: &Matrix, b: &Matrix) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_multiply(&mut this, a, b);
      return this;
    }
  }

  ///  Applies a translation by tx, ty to the transformation in matrix. The effect of the new transformation is to first translate the coordinates by tx and ty, then apply the original transformation to the coordinates.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// tx : amount to translate in the X direction
  ///
  /// ty : amount to translate in the Y direction
  ///
  /// Since 1.0
  pub fn translate(&mut self, x0: f64, y0: f64) {
    unsafe {
      cairo_matrix_translate(self, x0, y0);
    }
  }

  ///  Applies scaling by sx, sy to the transformation in matrix. The effect of the new transformation is to first scale the coordinates by sx and sy, then apply the original transformation to the coordinates.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// sx : scale factor in the X direction
  ///
  /// sy : scale factor in the Y direction
  ///
  /// Since 1.0
  pub fn scale(&mut self, sx: f64, sy: f64) {
    unsafe {
      cairo_matrix_scale(self, sx, sy);
    }
  }

  ///  Applies rotation by radians to the transformation in matrix. The effect of the new transformation is to first rotate the coordinates by radians, then apply the original transformation to the coordinates.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// radians : angle of rotation, in radians. The direction of rotation is defined such that positive angles rotate in the direction from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, positive angles rotate in a clockwise direction.
  ///
  /// Since 1.0
  pub fn rotate(&mut self, radians: f64) {
    unsafe {
      cairo_matrix_rotate(self, radians);
    }
  }

  ///  Transforms the distance vector (dx,dy) by matrix. This is similar to cairo_matrix_transform_point() except that the translation components of the transformation are ignored. The calculation of the returned vector is as follows:
  ///
  /// ```
  /// dx2 = dx1 * a + dy1 * c;
  /// dy2 = dx1 * b + dy1 * d;
  /// ```
  ///
  /// Affine transformations are position invariant, so the same vector always transforms to the same vector. If (x1,y1) transforms to (x2,y2) then (x1+dx1,y1+dy1) will transform to (x1+dx2,y1+dy2) for all values of x1 and x2.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// dx : X component of a distance vector. An in/out parameter
  ///
  /// dy : Y component of a distance vector. An in/out parameter
  ///
  /// Since 1.0
  pub fn transform_distance(&self, dx_r: f64, dy_r: f64) -> (f64, f64) {
    unsafe {
      let mut dx = dx_r;
      let mut dy = dy_r;
      cairo_matrix_transform_distance(self, &mut dx, &mut dy);
      return (dx, dy);
    }
  }

  /// Transforms the point (x, y) by matrix.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// x : X position. An in/out parameter
  ///
  /// y : Y position. An in/out parameter
  ///
  /// Since 1.0
  pub fn transform_point(&self, x_r: f64, y_r: f64) -> (f64, f64) {
    unsafe {
      let mut x = x_r;
      let mut y = y_r;
      cairo_matrix_transform_point(self, &mut x, &mut y);
      return (x, y);
    }
  }

  /// Changes matrix to be the inverse of its original value. Not all transformation matrices have inverses; if the matrix collapses points together (it is degenerate), then it has no inverse and this function will fail.
  ///
  /// matrix : a matrix::Matrix
  ///
  /// Returns : If matrix has an inverse, modifies matrix to be the inverse matrix and returns CAIRO_STATUS_SUCCESS. Otherwise, returns CAIRO_STATUS_INVALID_MATRIX.
  ///
  /// Since 1.0
  pub fn invert(&mut self) -> super::Status {
    unsafe {
      let foreign_result = cairo_matrix_invert(self);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_matrix_init(this: *mut Matrix, xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64);
  fn cairo_matrix_init_identity(this: *mut Matrix);
  fn cairo_matrix_init_translate(this: *mut Matrix, x0: f64, y0: f64);
  fn cairo_matrix_init_scale(this: *mut Matrix, sx: f64, sy: f64);
  fn cairo_matrix_init_rotate(this: *mut Matrix, radians: f64);
  fn cairo_matrix_multiply(this: *mut Matrix, a: *Matrix, b: *Matrix);
  fn cairo_matrix_translate(self_value: *mut Matrix, x0: f64, y0: f64);
  fn cairo_matrix_scale(self_value: *mut Matrix, sx: f64, sy: f64);
  fn cairo_matrix_rotate(self_value: *mut Matrix, radians: f64);
  fn cairo_matrix_transform_distance(self_value: *Matrix, dx: &mut f64, dy: &mut f64);
  fn cairo_matrix_transform_point(self_value: *Matrix, x: &mut f64, y: &mut f64);
  fn cairo_matrix_invert(self_value: *mut Matrix) -> super::Status;
}

<|endoftext|>


<commit_before>fn main() {

    fn is_palindrome(n: i64) -> bool {
        let s = n.to_string();
        let rev: String = n.to_string().chars().rev().collect();
        s == rev
    }

    // println!("{}", is_palindrome(1234321));

    let mut largest = 0;

    for x in (800..999).rev() {
        for y in (800..999).rev() {
            let mult = x * y;
            if is_palindrome(mult) && mult > largest {
                println!("{}", mult);
                largest = mult
            }
        }
    }
}
<commit_msg>Refactoring problem_4<commit_after>fn main() {

    fn is_palindrome(n: usize) -> bool {
        n.to_string() == n.to_string().chars().rev().collect::<String>()
    }

    let result = (800..999).rev()
        .map(|x| {
            (800..999)
                .rev()
                .map(|y| x * y)
                .filter(|&z| is_palindrome(z as usize))
                .max()
                .unwrap_or(0)
            })
        .max().unwrap();

    println!("{}", result);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Genymobile
 *
 * 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
 *
 *     http://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.
 */

extern crate chrono;
extern crate ctrlc;
#[macro_use]
extern crate log;
extern crate relaylib;

mod cli_args;
mod logger;

use std::env;
use cli_args::CommandLineArguments;
use logger::SimpleLogger;
use std::error;
use std::io;
use std::fmt;
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
use std::process::{self, ExitStatus, exit};
use std::thread;
use std::time::Duration;

const COMMANDS: &[&'static Command] = &[
    &InstallCommand,
    &UninstallCommand,
    &ReinstallCommand,
    &RunCommand,
    &StartCommand,
    &StopCommand,
    &RestartCommand,
    &RelayCommand,
];

trait Command {
    fn command(&self) -> &'static str;
    fn accepted_parameters(&self) -> u8;
    fn description(&self) -> &'static str;
    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError>;
}

struct InstallCommand;
struct UninstallCommand;
struct ReinstallCommand;
struct RunCommand;
struct StartCommand;
struct StopCommand;
struct RestartCommand;
struct RelayCommand;

impl Command for InstallCommand {
    fn command(&self) -> &'static str {
        "install"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL
    }

    fn description(&self) -> &'static str {
        "Install the client on the Android device and exit.\n\
        If several devices are connected via adb, then serial must be\n\
        specified."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        info!("Installing gnirehtet...");
        exec_adb(args.serial(), vec!["install", "-r", "gnirehtet.apk"])
    }
}

impl Command for UninstallCommand {
    fn command(&self) -> &'static str {
        "uninstall"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL
    }

    fn description(&self) -> &'static str {
        "Uninstall the client from the Android device and exit.\n\
        If several devices are connected via adb, then serial must be\n\
        specified."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        info!("Uninstalling gnirehtet...");
        exec_adb(args.serial(), vec!["uninstall", "com.genymobile.gnirehtet"])
    }
}

impl Command for ReinstallCommand {
    fn command(&self) -> &'static str {
        "reinstall"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL
    }

    fn description(&self) -> &'static str {
        "Uninstall then install."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        UninstallCommand.execute(args)?;
        InstallCommand.execute(args)?;
        Ok(())
    }
}

impl Command for RunCommand {
    fn command(&self) -> &'static str {
        "run"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL | cli_args::PARAM_DNS_SERVERS
    }

    fn description(&self) -> &'static str {
        "Enable reverse tethering for exactly one device:\n  \
          - install the client if necessary;\n  \
          - start the client;\n  \
          - start the relay server;\n  \
          - on Ctrl+C, stop both the relay server and the client."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        if !is_gnirehtet_installed(args.serial())? {
            InstallCommand.execute(args)?;
            // wait a bit after the app is installed so that intent actions are correctly
            // registered
            thread::sleep(Duration::from_millis(500));
        }

        {
            // start in parallel so that the relay server is ready when the client connects
            let serial = args.serial().cloned();
            let dns_servers = args.dns_servers().cloned();
            thread::spawn(move || if let Err(err) = start_gnirehtet(
                serial.as_ref(),
                dns_servers.as_ref(),
            )
            {
                error!("Cannot start gnirehtet: {}", err);
            });
        }

        let serial = args.serial().cloned();
        ctrlc::set_handler(move || {
            info!("Interrupted");

            if let Err(err) = stop_gnirehtet(serial.as_ref()) {
                error!("Cannot stop gnirehtet: {}", err);
            }

            exit(0);
        }).expect("Error setting Ctrl-C handler");

        match relay() {
            Err(ref err) => {
                panic!("Cannot relay: {}", err);
            }
            ok => ok,
        }
    }
}

impl Command for StartCommand {
    fn command(&self) -> &'static str {
        "start"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL | cli_args::PARAM_DNS_SERVERS
    }

    fn description(&self) -> &'static str {
        "Start a client on the Android device and exit.\n\
        If several devices are connected via adb, then serial must be\n\
        specified.\n\
        If -d is given, then make the Android device use the specified\n\
        DNS server(s). Otherwise, use 8.8.8.8 (Google public DNS).\n\
        If the client is already started, then do nothing, and ignore\n\
        DNS servers parameter.\n\
        To use the host 'localhost' as DNS, use 10.0.2.2."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        start_gnirehtet(args.serial(), args.dns_servers())
    }
}

impl Command for StopCommand {
    fn command(&self) -> &'static str {
        "stop"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL
    }

    fn description(&self) -> &'static str {
        "Stop the client on the Android device and exit.\n\
        If several devices are connected via adb, then serial must be\n\
        specified."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        stop_gnirehtet(args.serial())
    }
}

impl Command for RestartCommand {
    fn command(&self) -> &'static str {
        "restart"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL | cli_args::PARAM_DNS_SERVERS
    }

    fn description(&self) -> &'static str {
        "Stop then start."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        StopCommand.execute(args)?;
        StartCommand.execute(args)?;
        Ok(())
    }
}

impl Command for RelayCommand {
    fn command(&self) -> &'static str {
        "relay"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_NONE
    }

    fn description(&self) -> &'static str {
        "Start the relay server in the current terminal."
    }

    fn execute(&self, _: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        relay()
    }
}

#[derive(Debug)]
enum Termination {
    Value(i32),
    #[cfg(unix)]
    Signal(i32),
}

impl Termination {
    fn from(status: ExitStatus) -> Self {
        match status.code() {
            Some(code) => Termination::Value(code),
            #[cfg(unix)]
            None => Termination::Signal(status.signal().unwrap()),
            #[cfg(not(unix))]
            None => panic!("Unexpected signal termination on non-unix system"),
        }
    }
}

#[derive(Debug)]
struct CommandStatusError {
    command: Vec<String>,
    termination: Termination,
}

impl CommandStatusError {
    fn new(command: Vec<String>, status: ExitStatus) -> Self {
        Self {
            command: command,
            termination: Termination::from(status),
        }
    }
}

impl fmt::Display for CommandStatusError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.termination {
            Termination::Value(code) => {
                write!(f, "Command {:?} returned with value {}", self.command, code)
            }
            #[cfg(unix)]
            Termination::Signal(sig) => {
                write!(f, "Command {:?} terminated by signal {}", self.command, sig)
            }
        }
    }
}

impl error::Error for CommandStatusError {
    fn description(&self) -> &str {
        "Execution terminated with failure"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

#[derive(Debug)]
enum CommandExecutionError {
    Io(io::Error),
    Status(CommandStatusError),
}

impl fmt::Display for CommandExecutionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandExecutionError::Io(ref err) => write!(f, "IO error: {}", err),
            CommandExecutionError::Status(ref err) => write!(f, "Status in error: {}", err),
        }
    }
}

impl error::Error for CommandExecutionError {
    fn description(&self) -> &str {
        match *self {
            CommandExecutionError::Io(ref err) => err.description(),
            CommandExecutionError::Status(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CommandExecutionError::Io(ref err) => Some(err),
            CommandExecutionError::Status(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for CommandExecutionError {
    fn from(error: io::Error) -> Self {
        CommandExecutionError::Io(error)
    }
}

impl From<CommandStatusError> for CommandExecutionError {
    fn from(error: CommandStatusError) -> Self {
        CommandExecutionError::Status(error)
    }
}

fn create_adb_args<S: Into<String>>(serial: Option<&String>, args: Vec<S>) -> Vec<String> {
    let mut command = Vec::<String>::new();
    if let Some(serial) = serial {
        command.push("-s".into());
        command.push(serial.clone());
    }
    for arg in args {
        command.push(arg.into());
    }
    command
}

fn exec_adb<S: Into<String>>(
    serial: Option<&String>,
    args: Vec<S>,
) -> Result<(), CommandExecutionError> {
    let mut adb_args = create_adb_args(serial, args);
    info!("Execute: adb {:?}", adb_args);
    let exit_status = process::Command::new("adb").args(&adb_args[..]).status()?;
    if exit_status.success() {
        Ok(())
    } else {
        let mut cmd = vec!["adb".to_string()];
        cmd.append(&mut adb_args);
        Err(CommandStatusError::new(cmd, exit_status).into())
    }
}

fn is_gnirehtet_installed(serial: Option<&String>) -> Result<bool, CommandExecutionError> {
    let args = create_adb_args(
        serial,
        vec![
            "shell",
            "pm",
            "list",
            "packages",
            "com.genymobile.gnirehtet",
        ],
    );
    let output = process::Command::new("adb").args(&args[..]).output()?;
    // empty output when not found
    Ok(!output.stdout.is_empty())
}

fn start_gnirehtet(
    serial: Option<&String>,
    dns_servers: Option<&String>,
) -> Result<(), CommandExecutionError> {
    info!("Starting gnirehtet...");
    exec_adb(serial, vec!["reverse", "tcp:31416", "tcp:31416"])?;

    let mut adb_args = vec![
        "shell",
        "am",
        "startservice",
        "-a",
        "com.genymobile.gnirehtet.START",
    ];
    if let Some(dns_servers) = dns_servers {
        adb_args.append(&mut vec!["--esa", "dnsServers", dns_servers]);
    }
    exec_adb(serial, adb_args)
}

fn stop_gnirehtet(serial: Option<&String>) -> Result<(), CommandExecutionError> {
    info!("Stopping gnirehtet...");
    exec_adb(
        serial,
        vec![
            "shell",
            "am",
            "startservice",
            "-a",
            "com.genymobile.gnirehtet.STOP",
        ],
    )
}

fn relay() -> Result<(), CommandExecutionError> {
    relaylib::relay()?;
    Ok(())
}

fn print_usage() {
    let mut msg = "Syntax: gnirehtet (".to_string();
    msg.push_str(COMMANDS[0].command());
    for command in &COMMANDS[1..] {
        msg.push('|');
        msg.push_str(command.command());
    }
    msg.push_str(") ...\n");
    for &command in COMMANDS {
        msg.push('\n');
        append_command_usage(&mut msg, command);
    }
    eprint!("{}", msg);
}

fn append_command_usage(msg: &mut String, command: &Command) {
    msg.push_str("  gnirehtet ");
    msg.push_str(command.command());
    let accepted_parameters = command.accepted_parameters();
    if (accepted_parameters & cli_args::PARAM_SERIAL) != 0 {
        msg.push_str(" [serial]");
    }
    if (accepted_parameters & cli_args::PARAM_DNS_SERVERS) != 0 {
        msg.push_str(" [-d DNS[,DNS2,...]]");
    }
    msg.push('\n');
    for desc_line in command.description().split('\n') {
        msg.push_str("      ");
        msg.push_str(desc_line);
        msg.push('\n');
    }
}

fn print_command_usage(command: &Command) {
    let mut msg = String::new();
    append_command_usage(&mut msg, command);
    eprint!("{}", msg);
}

fn main() {
    SimpleLogger::init().unwrap();
    let mut args = env::args();
    // args.nth(1) will consume the two first arguments (the binary name and the command name)
    if let Some(command_name) = args.nth(1) {
        let command = COMMANDS.iter().find(
            |&&command| command.command() == command_name,
        );
        match command {
            Some(&command) => {
                // args now contains only the command parameters
                let arguments =
                    CommandLineArguments::parse(command.accepted_parameters(), args.collect());
                match arguments {
                    Ok(arguments) => {
                        if let Err(err) = command.execute(&arguments) {
                            error!("Execution error: {}", err);
                            exit(3);
                        }
                    }
                    Err(err) => {
                        error!("{}", err);
                        print_command_usage(command);
                        exit(2);
                    }
                }
            }
            None => {
                if command_name == "rt" {
                    error!(
                        "The 'rt' command has been renamed to 'run'. Try 'gnirehtet run' instead."
                    );
                    print_command_usage(&RunCommand);
                } else {
                    error!("Unknown command: {}", command_name);
                    print_usage();
                }
                exit(1);
            }
        }
    } else {
        print_usage();
    }
}
<commit_msg>Log with explicit TAG in Main<commit_after>/*
 * Copyright (C) 2017 Genymobile
 *
 * 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
 *
 *     http://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.
 */

extern crate chrono;
extern crate ctrlc;
#[macro_use]
extern crate log;
extern crate relaylib;

mod cli_args;
mod logger;

use std::env;
use cli_args::CommandLineArguments;
use logger::SimpleLogger;
use std::error;
use std::io;
use std::fmt;
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
use std::process::{self, ExitStatus, exit};
use std::thread;
use std::time::Duration;

const TAG: &'static str = "Main";

const COMMANDS: &[&'static Command] = &[
    &InstallCommand,
    &UninstallCommand,
    &ReinstallCommand,
    &RunCommand,
    &StartCommand,
    &StopCommand,
    &RestartCommand,
    &RelayCommand,
];

trait Command {
    fn command(&self) -> &'static str;
    fn accepted_parameters(&self) -> u8;
    fn description(&self) -> &'static str;
    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError>;
}

struct InstallCommand;
struct UninstallCommand;
struct ReinstallCommand;
struct RunCommand;
struct StartCommand;
struct StopCommand;
struct RestartCommand;
struct RelayCommand;

impl Command for InstallCommand {
    fn command(&self) -> &'static str {
        "install"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL
    }

    fn description(&self) -> &'static str {
        "Install the client on the Android device and exit.\n\
        If several devices are connected via adb, then serial must be\n\
        specified."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        info!(target: TAG, "Installing gnirehtet...");
        exec_adb(args.serial(), vec!["install", "-r", "gnirehtet.apk"])
    }
}

impl Command for UninstallCommand {
    fn command(&self) -> &'static str {
        "uninstall"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL
    }

    fn description(&self) -> &'static str {
        "Uninstall the client from the Android device and exit.\n\
        If several devices are connected via adb, then serial must be\n\
        specified."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        info!(target: TAG, "Uninstalling gnirehtet...");
        exec_adb(args.serial(), vec!["uninstall", "com.genymobile.gnirehtet"])
    }
}

impl Command for ReinstallCommand {
    fn command(&self) -> &'static str {
        "reinstall"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL
    }

    fn description(&self) -> &'static str {
        "Uninstall then install."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        UninstallCommand.execute(args)?;
        InstallCommand.execute(args)?;
        Ok(())
    }
}

impl Command for RunCommand {
    fn command(&self) -> &'static str {
        "run"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL | cli_args::PARAM_DNS_SERVERS
    }

    fn description(&self) -> &'static str {
        "Enable reverse tethering for exactly one device:\n  \
          - install the client if necessary;\n  \
          - start the client;\n  \
          - start the relay server;\n  \
          - on Ctrl+C, stop both the relay server and the client."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        if !is_gnirehtet_installed(args.serial())? {
            InstallCommand.execute(args)?;
            // wait a bit after the app is installed so that intent actions are correctly
            // registered
            thread::sleep(Duration::from_millis(500));
        }

        {
            // start in parallel so that the relay server is ready when the client connects
            let serial = args.serial().cloned();
            let dns_servers = args.dns_servers().cloned();
            thread::spawn(move || if let Err(err) = start_gnirehtet(
                serial.as_ref(),
                dns_servers.as_ref(),
            )
            {
                error!(target: TAG, "Cannot start gnirehtet: {}", err);
            });
        }

        let serial = args.serial().cloned();
        ctrlc::set_handler(move || {
            info!(target: TAG, "Interrupted");

            if let Err(err) = stop_gnirehtet(serial.as_ref()) {
                error!(target: TAG, "Cannot stop gnirehtet: {}", err);
            }

            exit(0);
        }).expect("Error setting Ctrl-C handler");

        match relay() {
            Err(ref err) => {
                panic!("Cannot relay: {}", err);
            }
            ok => ok,
        }
    }
}

impl Command for StartCommand {
    fn command(&self) -> &'static str {
        "start"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL | cli_args::PARAM_DNS_SERVERS
    }

    fn description(&self) -> &'static str {
        "Start a client on the Android device and exit.\n\
        If several devices are connected via adb, then serial must be\n\
        specified.\n\
        If -d is given, then make the Android device use the specified\n\
        DNS server(s). Otherwise, use 8.8.8.8 (Google public DNS).\n\
        If the client is already started, then do nothing, and ignore\n\
        DNS servers parameter.\n\
        To use the host 'localhost' as DNS, use 10.0.2.2."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        start_gnirehtet(args.serial(), args.dns_servers())
    }
}

impl Command for StopCommand {
    fn command(&self) -> &'static str {
        "stop"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL
    }

    fn description(&self) -> &'static str {
        "Stop the client on the Android device and exit.\n\
        If several devices are connected via adb, then serial must be\n\
        specified."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        stop_gnirehtet(args.serial())
    }
}

impl Command for RestartCommand {
    fn command(&self) -> &'static str {
        "restart"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_SERIAL | cli_args::PARAM_DNS_SERVERS
    }

    fn description(&self) -> &'static str {
        "Stop then start."
    }

    fn execute(&self, args: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        StopCommand.execute(args)?;
        StartCommand.execute(args)?;
        Ok(())
    }
}

impl Command for RelayCommand {
    fn command(&self) -> &'static str {
        "relay"
    }

    fn accepted_parameters(&self) -> u8 {
        cli_args::PARAM_NONE
    }

    fn description(&self) -> &'static str {
        "Start the relay server in the current terminal."
    }

    fn execute(&self, _: &CommandLineArguments) -> Result<(), CommandExecutionError> {
        relay()
    }
}

#[derive(Debug)]
enum Termination {
    Value(i32),
    #[cfg(unix)]
    Signal(i32),
}

impl Termination {
    fn from(status: ExitStatus) -> Self {
        match status.code() {
            Some(code) => Termination::Value(code),
            #[cfg(unix)]
            None => Termination::Signal(status.signal().unwrap()),
            #[cfg(not(unix))]
            None => panic!("Unexpected signal termination on non-unix system"),
        }
    }
}

#[derive(Debug)]
struct CommandStatusError {
    command: Vec<String>,
    termination: Termination,
}

impl CommandStatusError {
    fn new(command: Vec<String>, status: ExitStatus) -> Self {
        Self {
            command: command,
            termination: Termination::from(status),
        }
    }
}

impl fmt::Display for CommandStatusError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.termination {
            Termination::Value(code) => {
                write!(f, "Command {:?} returned with value {}", self.command, code)
            }
            #[cfg(unix)]
            Termination::Signal(sig) => {
                write!(f, "Command {:?} terminated by signal {}", self.command, sig)
            }
        }
    }
}

impl error::Error for CommandStatusError {
    fn description(&self) -> &str {
        "Execution terminated with failure"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

#[derive(Debug)]
enum CommandExecutionError {
    Io(io::Error),
    Status(CommandStatusError),
}

impl fmt::Display for CommandExecutionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CommandExecutionError::Io(ref err) => write!(f, "IO error: {}", err),
            CommandExecutionError::Status(ref err) => write!(f, "Status in error: {}", err),
        }
    }
}

impl error::Error for CommandExecutionError {
    fn description(&self) -> &str {
        match *self {
            CommandExecutionError::Io(ref err) => err.description(),
            CommandExecutionError::Status(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CommandExecutionError::Io(ref err) => Some(err),
            CommandExecutionError::Status(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for CommandExecutionError {
    fn from(error: io::Error) -> Self {
        CommandExecutionError::Io(error)
    }
}

impl From<CommandStatusError> for CommandExecutionError {
    fn from(error: CommandStatusError) -> Self {
        CommandExecutionError::Status(error)
    }
}

fn create_adb_args<S: Into<String>>(serial: Option<&String>, args: Vec<S>) -> Vec<String> {
    let mut command = Vec::<String>::new();
    if let Some(serial) = serial {
        command.push("-s".into());
        command.push(serial.clone());
    }
    for arg in args {
        command.push(arg.into());
    }
    command
}

fn exec_adb<S: Into<String>>(
    serial: Option<&String>,
    args: Vec<S>,
) -> Result<(), CommandExecutionError> {
    let mut adb_args = create_adb_args(serial, args);
    info!(target: TAG, "Execute: adb {:?}", adb_args);
    let exit_status = process::Command::new("adb").args(&adb_args[..]).status()?;
    if exit_status.success() {
        Ok(())
    } else {
        let mut cmd = vec!["adb".to_string()];
        cmd.append(&mut adb_args);
        Err(CommandStatusError::new(cmd, exit_status).into())
    }
}

fn is_gnirehtet_installed(serial: Option<&String>) -> Result<bool, CommandExecutionError> {
    let args = create_adb_args(
        serial,
        vec![
            "shell",
            "pm",
            "list",
            "packages",
            "com.genymobile.gnirehtet",
        ],
    );
    let output = process::Command::new("adb").args(&args[..]).output()?;
    // empty output when not found
    Ok(!output.stdout.is_empty())
}

fn start_gnirehtet(
    serial: Option<&String>,
    dns_servers: Option<&String>,
) -> Result<(), CommandExecutionError> {
    info!(target: TAG, "Starting gnirehtet...");
    exec_adb(serial, vec!["reverse", "tcp:31416", "tcp:31416"])?;

    let mut adb_args = vec![
        "shell",
        "am",
        "startservice",
        "-a",
        "com.genymobile.gnirehtet.START",
    ];
    if let Some(dns_servers) = dns_servers {
        adb_args.append(&mut vec!["--esa", "dnsServers", dns_servers]);
    }
    exec_adb(serial, adb_args)
}

fn stop_gnirehtet(serial: Option<&String>) -> Result<(), CommandExecutionError> {
    info!(target: TAG, "Stopping gnirehtet...");
    exec_adb(
        serial,
        vec![
            "shell",
            "am",
            "startservice",
            "-a",
            "com.genymobile.gnirehtet.STOP",
        ],
    )
}

fn relay() -> Result<(), CommandExecutionError> {
    relaylib::relay()?;
    Ok(())
}

fn print_usage() {
    let mut msg = "Syntax: gnirehtet (".to_string();
    msg.push_str(COMMANDS[0].command());
    for command in &COMMANDS[1..] {
        msg.push('|');
        msg.push_str(command.command());
    }
    msg.push_str(") ...\n");
    for &command in COMMANDS {
        msg.push('\n');
        append_command_usage(&mut msg, command);
    }
    eprint!("{}", msg);
}

fn append_command_usage(msg: &mut String, command: &Command) {
    msg.push_str("  gnirehtet ");
    msg.push_str(command.command());
    let accepted_parameters = command.accepted_parameters();
    if (accepted_parameters & cli_args::PARAM_SERIAL) != 0 {
        msg.push_str(" [serial]");
    }
    if (accepted_parameters & cli_args::PARAM_DNS_SERVERS) != 0 {
        msg.push_str(" [-d DNS[,DNS2,...]]");
    }
    msg.push('\n');
    for desc_line in command.description().split('\n') {
        msg.push_str("      ");
        msg.push_str(desc_line);
        msg.push('\n');
    }
}

fn print_command_usage(command: &Command) {
    let mut msg = String::new();
    append_command_usage(&mut msg, command);
    eprint!("{}", msg);
}

fn main() {
    SimpleLogger::init().unwrap();
    let mut args = env::args();
    // args.nth(1) will consume the two first arguments (the binary name and the command name)
    if let Some(command_name) = args.nth(1) {
        let command = COMMANDS.iter().find(
            |&&command| command.command() == command_name,
        );
        match command {
            Some(&command) => {
                // args now contains only the command parameters
                let arguments =
                    CommandLineArguments::parse(command.accepted_parameters(), args.collect());
                match arguments {
                    Ok(arguments) => {
                        if let Err(err) = command.execute(&arguments) {
                            error!(target: TAG, "Execution error: {}", err);
                            exit(3);
                        }
                    }
                    Err(err) => {
                        error!(target: TAG, "{}", err);
                        print_command_usage(command);
                        exit(2);
                    }
                }
            }
            None => {
                if command_name == "rt" {
                    error!(
                        target: TAG,
                        "The 'rt' command has been renamed to 'run'. Try 'gnirehtet run' instead."
                    );
                    print_command_usage(&RunCommand);
                } else {
                    error!(target: TAG, "Unknown command: {}", command_name);
                    print_usage();
                }
                exit(1);
            }
        }
    } else {
        print_usage();
    }
}
<|endoftext|>


<commit_before>extern crate serialize;

use std::io::BufReader;
use std::collections::HashMap;
use serialize::{Decodable, json};

static json: &'static [u8] = include_bin!("../data/mime.json");

pub struct Types {
    ext_by_type: HashMap<String, Vec<String>>,
    type_by_ext: HashMap<String, String>

}

impl Types {
    pub fn new() -> Result<Types, ()> {
        let parsed = try!(json::from_reader(&mut BufReader::new(json)).map_err(|_| ()));
        let mut decoder = json::Decoder::new(parsed);
        let decoded: HashMap<String, Vec<String>> =
            try!(Decodable::decode(&mut decoder).map_err(|_| ()));

        let mut by_ext = HashMap::new();

        for (mime_type, exts) in decoded.iter() {
            for ext in exts.iter() {
                by_ext.insert(ext.clone(), mime_type.clone());
            }
        }

        Ok(Types { ext_by_type: decoded, type_by_ext: by_ext })
    }

    pub fn get_extension<'a>(&'a self, name: &str) -> Option<&'a [String]> {
        self.ext_by_type.find_equiv(&name).map(|v| v.as_slice())
    }

    pub fn get_mime_type<'a>(&'a self, ext: &str) -> Option<&'a str> {
        self.type_by_ext.find_equiv(&ext).map(|v| v.as_slice())
    }
}

#[cfg(test)]
mod test {
    extern crate test;
    use Types;

    #[bench]
    fn bench_load_types(b: &mut test::Bencher) {
        b.iter(|| {
            Types::new()
        });
    }

    #[test]
    fn test_by_ext() {
        let t = Types::new().ok().expect("Types didn't load");
        assert_eq!(t.get_extension("text/css"), Some(["css".to_str()].as_slice()));
    }

    #[test]
    fn test_by_type() {
        let t = Types::new().ok().expect("Types didn't load");
        assert_eq!(t.get_mime_type("css"), Some("text/css"));
    }
}
<commit_msg>Embed string, not [u8]<commit_after>extern crate serialize;

use std::io::BufReader;
use std::collections::HashMap;
use serialize::{Decodable, json};

static json: &'static str = include_str!("../data/mime.json");

pub struct Types {
    ext_by_type: HashMap<String, Vec<String>>,
    type_by_ext: HashMap<String, String>

}

impl Types {
    pub fn new() -> Result<Types, ()> {
        let parsed = try!(json::from_str(json).map_err(|_| ()));
        let mut decoder = json::Decoder::new(parsed);
        let decoded: HashMap<String, Vec<String>> =
            try!(Decodable::decode(&mut decoder).map_err(|_| ()));

        let mut by_ext = HashMap::new();

        for (mime_type, exts) in decoded.iter() {
            for ext in exts.iter() {
                by_ext.insert(ext.clone(), mime_type.clone());
            }
        }

        Ok(Types { ext_by_type: decoded, type_by_ext: by_ext })
    }

    pub fn get_extension<'a>(&'a self, name: &str) -> Option<&'a [String]> {
        self.ext_by_type.find_equiv(&name).map(|v| v.as_slice())
    }

    pub fn get_mime_type<'a>(&'a self, ext: &str) -> Option<&'a str> {
        self.type_by_ext.find_equiv(&ext).map(|v| v.as_slice())
    }
}

#[cfg(test)]
mod test {
    extern crate test;
    use Types;

    #[bench]
    fn bench_load_types(b: &mut test::Bencher) {
        b.iter(|| {
            Types::new()
        });
    }

    #[test]
    fn test_by_ext() {
        let t = Types::new().ok().expect("Types didn't load");
        assert_eq!(t.get_extension("text/css"), Some(["css".to_str()].as_slice()));
    }

    #[test]
    fn test_by_type() {
        let t = Types::new().ok().expect("Types didn't load");
        assert_eq!(t.get_mime_type("css"), Some("text/css"));
    }
}
<|endoftext|>


<commit_before>use ocr_numbers as ocr;

#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn input_with_lines_not_multiple_of_four_is_error() {
    let input = " _ \n".to_string() +
                "| |\n" +
                "   ";

    assert_eq!(Err(ocr::Error::InvalidRowCount(3)), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn input_with_columns_not_multiple_of_three_is_error() {
    let input = "    \n".to_string() +
                "   |\n" +
                "   |\n" +
                "    ";

    assert_eq!(Err(ocr::Error::InvalidColumnCount(4)), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn unrecognized_characters_return_question_mark() {
    let input = "   \n".to_string() +
                "  _\n" +
                "  |\n" +
                "   ";

    assert_eq!(Ok("?".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_0() {
    let input = " _ \n".to_string() +
                "| |\n" +
                "|_|\n" +
                "   ";

    assert_eq!(Ok("0".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_1() {
    let input = "   \n".to_string() +
                "  |\n" +
                "  |\n" +
                "   ";

    assert_eq!(Ok("1".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_2() {
    let input = " _ \n".to_string() +
                " _|\n" +
                "|_ \n" +
                "   ";

    assert_eq!(Ok("2".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_3() {
    let input = " _ \n".to_string() +
                " _|\n" +
                " _|\n" +
                "   ";

    assert_eq!(Ok("3".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_4() {
    let input = "   \n".to_string() +
                "|_|\n" +
                "  |\n" +
                "   ";

    assert_eq!(Ok("4".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_5() {
    let input = " _ \n".to_string() +
                "|_ \n" +
                " _|\n" +
                "   ";

    assert_eq!(Ok("5".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_6() {
    let input = " _ \n".to_string() +
                "|_ \n" +
                "|_|\n" +
                "   ";

    assert_eq!(Ok("6".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_7() {
    let input = " _ \n".to_string() +
                "  |\n" +
                "  |\n" +
                "   ";

    assert_eq!(Ok("7".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_8() {
    let input = " _ \n".to_string() +
                "|_|\n" +
                "|_|\n" +
                "   ";

    assert_eq!(Ok("8".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_9() {
    let input = " _ \n".to_string() +
                "|_|\n" +
                " _|\n" +
                "   ";

    assert_eq!(Ok("9".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_110101100() {
    let input = "       _     _        _  _ \n".to_string() +
                "  |  || |  || |  |  || || |\n" +
                "  |  ||_|  ||_|  |  ||_||_|\n" +
                "                           ";

    assert_eq!(Ok("110101100".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn replaces_only_garbled_numbers_with_question_mark() {
    let input = "       _     _           _ \n".to_string() +
                "  |  || |  || |     || || |\n" +
                "  |  | _|  ||_|  |  ||_||_|\n" +
                "                           ";

    assert_eq!(Ok("11?10?1?0".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn recognizes_string_of_decimal_numbers() {
    let input = "    _  _     _  _  _  _  _  _ \n".to_string() +
                "  | _| _||_||_ |_   ||_||_|| |\n" +
                "  ||_  _|  | _||_|  ||_| _||_|\n" +
                "                              ";

    assert_eq!(Ok("1234567890".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn numbers_across_multiple_lines_are_joined_by_commas() {
    let input = "    _  _ \n".to_string() +
                "  | _| _|\n" +
                "  ||_  _|\n" +
                "         \n" +
                "    _  _ \n" +
                "|_||_ |_ \n" +
                "  | _||_|\n" +
                "         \n" +
                " _  _  _ \n" +
                "  ||_||_|\n" +
                "  ||_| _|\n" +
                "         ";
    assert_eq!(Ok("123,456,789".to_string()), ocr::convert(&input));
}
<commit_msg>ocr-numbers: change `cfg_attr(rustfmt, rustfmt_skip)` to `rustfmt::skip` (#818)<commit_after>use ocr_numbers as ocr;

#[test]
#[rustfmt::skip]
fn input_with_lines_not_multiple_of_four_is_error() {
    let input = " _ \n".to_string() +
                "| |\n" +
                "   ";

    assert_eq!(Err(ocr::Error::InvalidRowCount(3)), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn input_with_columns_not_multiple_of_three_is_error() {
    let input = "    \n".to_string() +
                "   |\n" +
                "   |\n" +
                "    ";

    assert_eq!(Err(ocr::Error::InvalidColumnCount(4)), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn unrecognized_characters_return_question_mark() {
    let input = "   \n".to_string() +
                "  _\n" +
                "  |\n" +
                "   ";

    assert_eq!(Ok("?".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_0() {
    let input = " _ \n".to_string() +
                "| |\n" +
                "|_|\n" +
                "   ";

    assert_eq!(Ok("0".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_1() {
    let input = "   \n".to_string() +
                "  |\n" +
                "  |\n" +
                "   ";

    assert_eq!(Ok("1".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_2() {
    let input = " _ \n".to_string() +
                " _|\n" +
                "|_ \n" +
                "   ";

    assert_eq!(Ok("2".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_3() {
    let input = " _ \n".to_string() +
                " _|\n" +
                " _|\n" +
                "   ";

    assert_eq!(Ok("3".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_4() {
    let input = "   \n".to_string() +
                "|_|\n" +
                "  |\n" +
                "   ";

    assert_eq!(Ok("4".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_5() {
    let input = " _ \n".to_string() +
                "|_ \n" +
                " _|\n" +
                "   ";

    assert_eq!(Ok("5".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_6() {
    let input = " _ \n".to_string() +
                "|_ \n" +
                "|_|\n" +
                "   ";

    assert_eq!(Ok("6".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_7() {
    let input = " _ \n".to_string() +
                "  |\n" +
                "  |\n" +
                "   ";

    assert_eq!(Ok("7".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_8() {
    let input = " _ \n".to_string() +
                "|_|\n" +
                "|_|\n" +
                "   ";

    assert_eq!(Ok("8".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_9() {
    let input = " _ \n".to_string() +
                "|_|\n" +
                " _|\n" +
                "   ";

    assert_eq!(Ok("9".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_110101100() {
    let input = "       _     _        _  _ \n".to_string() +
                "  |  || |  || |  |  || || |\n" +
                "  |  ||_|  ||_|  |  ||_||_|\n" +
                "                           ";

    assert_eq!(Ok("110101100".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn replaces_only_garbled_numbers_with_question_mark() {
    let input = "       _     _           _ \n".to_string() +
                "  |  || |  || |     || || |\n" +
                "  |  | _|  ||_|  |  ||_||_|\n" +
                "                           ";

    assert_eq!(Ok("11?10?1?0".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn recognizes_string_of_decimal_numbers() {
    let input = "    _  _     _  _  _  _  _  _ \n".to_string() +
                "  | _| _||_||_ |_   ||_||_|| |\n" +
                "  ||_  _|  | _||_|  ||_| _||_|\n" +
                "                              ";

    assert_eq!(Ok("1234567890".to_string()), ocr::convert(&input));
}

#[test]
#[ignore]
#[rustfmt::skip]
fn numbers_across_multiple_lines_are_joined_by_commas() {
    let input = "    _  _ \n".to_string() +
                "  | _| _|\n" +
                "  ||_  _|\n" +
                "         \n" +
                "    _  _ \n" +
                "|_||_ |_ \n" +
                "  | _||_|\n" +
                "         \n" +
                " _  _  _ \n" +
                "  ||_||_|\n" +
                "  ||_| _|\n" +
                "         ";
    assert_eq!(Ok("123,456,789".to_string()), ocr::convert(&input));
}
<|endoftext|>


<commit_before>use std::fs::{self, File};
use std::io::{BufRead, BufReader};

use bson::Bson;
use mongodb::{Client, ClientOptions, CommandResult, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use rand;

fn timed_query(_client: Client, command_result: &CommandResult) {
    let (command_name, duration) = match command_result {
        &CommandResult::Success { ref command_name, duration, .. } => (command_name.clone(), duration),
        _ => panic!("Command failed!")
    };

    if command_name.eq("find") {
        // Sanity check
        assert!(duration >= 1500000000);

        // Technically not guaranteed, but since the query is running locally, it shouldn't even be close
        assert!(duration < 2000000000);
    }
}

#[test]
fn command_duration() {
    let mut client = Client::connect("localhost", 27017).ok().expect("damn it!");
    let db = client.db("test");
    let coll = db.collection("event_hooks");
    coll.drop().unwrap();

    let docs = (1..4).map(|i| doc! { "_id" => i, "x" => (rand::random::<u8>() as u32) }).collect();
    coll.insert_many(docs, None).unwrap();
    client.add_completion_hook(timed_query).unwrap();

    let doc = doc! {
        "$where" => (Bson::JavaScriptCode("function() { sleep(500); }".to_owned()))
    };

    coll.find(Some(doc), None).unwrap();
}

fn read_first_non_monitor_line(file: &mut BufReader<&File>, line: &mut String) {
    loop {
        file.read_line(line).unwrap();
        if !line.starts_with("COMMAND.is_master") {
            break;
        }
        line.clear();
    }
}

#[test]
fn logging() {
    for file in fs::read_dir(".").unwrap() {
        if file.unwrap().path().file_name().unwrap().eq("test_log.txt") {
            fs::remove_file("test_log.txt").unwrap();
        }
    }

    let client_options = ClientOptions::with_log_file("test_log.txt");
    let client = Client::connect_with_options("localhost", 27017, client_options).unwrap();

    let db = client.db("test");
    db.create_collection("logging", None).unwrap();
    let coll = db.collection("logging");
    coll.drop().unwrap();

    let doc1 = doc! { "_id" => 1 };
    let doc2 = doc! { "_id" => 2 };
    let doc3 = doc! { "_id" => 3 };

    coll.insert_one(doc1, None).unwrap();
    coll.insert_one(doc2, None).unwrap();
    coll.insert_one(doc3, None).unwrap();

    let filter = doc! {
        "_id" => { "$gt" => 1 }
    };

    coll.find(Some(filter), None).unwrap();

    let f = File::open("test_log.txt").unwrap();
    let mut file = BufReader::new(&f);
    let mut line = String::new();

    // Create collection started
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.create_collection 127.0.0.1:27017 STARTED: { create: \"logging\", capped: false, auto_index_id: true, flags: 1 }\n", &line);

    // Create Collection completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.create_collection 127.0.0.1:27017 COMPLETED: { ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Drop collection started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.drop_collection 127.0.0.1:27017 STARTED: { drop: \"logging\" }\n", &line);

    // Drop collection completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.drop_collection 127.0.0.1:27017 COMPLETED: { ns: \"test.logging\", nIndexesWas: 1, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // First insert started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 1 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // First insert completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Second insert started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 2 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Second insert completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Third insert started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 3 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Third insert completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Find command started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.find 127.0.0.1:27017 STARTED: { find: \"logging\", filter: {  }, projection: {  }, skip: 0, limit: 0, batchSize: 20, sort: {  } }\n", &line);

    // Find command completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.find 127.0.0.1:27017 COMPLETED: { cursor: { id: 0, ns: \"test.logging\", firstBatch: [{ _id: 2 }, { _id: 3 }] }, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    coll.drop().unwrap();
}
<commit_msg>remove generated test log file<commit_after>use std::fs::{self, File};
use std::io::{BufRead, BufReader};

use bson::Bson;
use mongodb::{Client, ClientOptions, CommandResult, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use rand;

fn timed_query(_client: Client, command_result: &CommandResult) {
    let (command_name, duration) = match command_result {
        &CommandResult::Success { ref command_name, duration, .. } => (command_name.clone(), duration),
        _ => panic!("Command failed!")
    };

    if command_name.eq("find") {
        // Sanity check
        assert!(duration >= 1500000000);

        // Technically not guaranteed, but since the query is running locally, it shouldn't even be close
        assert!(duration < 2000000000);
    }
}

#[test]
fn command_duration() {
    let mut client = Client::connect("localhost", 27017).ok().expect("damn it!");
    let db = client.db("test");
    let coll = db.collection("event_hooks");
    coll.drop().unwrap();

    let docs = (1..4).map(|i| doc! { "_id" => i, "x" => (rand::random::<u8>() as u32) }).collect();
    coll.insert_many(docs, None).unwrap();
    client.add_completion_hook(timed_query).unwrap();

    let doc = doc! {
        "$where" => (Bson::JavaScriptCode("function() { sleep(500); }".to_owned()))
    };

    coll.find(Some(doc), None).unwrap();
}

fn read_first_non_monitor_line(file: &mut BufReader<&File>, line: &mut String) {
    loop {
        file.read_line(line).unwrap();
        if !line.starts_with("COMMAND.is_master") {
            break;
        }
        line.clear();
    }
}

#[test]
fn logging() {
    let _ = fs::remove_file("test_log.txt");

    let client_options = ClientOptions::with_log_file("test_log.txt");
    let client = Client::connect_with_options("localhost", 27017, client_options).unwrap();

    let db = client.db("test");
    db.create_collection("logging", None).unwrap();
    let coll = db.collection("logging");
    coll.drop().unwrap();

    let doc1 = doc! { "_id" => 1 };
    let doc2 = doc! { "_id" => 2 };
    let doc3 = doc! { "_id" => 3 };

    coll.insert_one(doc1, None).unwrap();
    coll.insert_one(doc2, None).unwrap();
    coll.insert_one(doc3, None).unwrap();

    let filter = doc! {
        "_id" => { "$gt" => 1 }
    };

    coll.find(Some(filter), None).unwrap();

    let f = File::open("test_log.txt").unwrap();
    let mut file = BufReader::new(&f);
    let mut line = String::new();

    // Create collection started
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.create_collection 127.0.0.1:27017 STARTED: { create: \"logging\", capped: false, auto_index_id: true, flags: 1 }\n", &line);

    // Create Collection completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.create_collection 127.0.0.1:27017 COMPLETED: { ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Drop collection started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.drop_collection 127.0.0.1:27017 STARTED: { drop: \"logging\" }\n", &line);

    // Drop collection completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.drop_collection 127.0.0.1:27017 COMPLETED: { ns: \"test.logging\", nIndexesWas: 1, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // First insert started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 1 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // First insert completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Second insert started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 2 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Second insert completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Third insert started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 3 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Third insert completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Find command started
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert_eq!("COMMAND.find 127.0.0.1:27017 STARTED: { find: \"logging\", filter: {  }, projection: {  }, skip: 0, limit: 0, batchSize: 20, sort: {  } }\n", &line);

    // Find command completed
    line.clear();
    read_first_non_monitor_line(&mut file, &mut line);
    assert!(line.starts_with("COMMAND.find 127.0.0.1:27017 COMPLETED: { cursor: { id: 0, ns: \"test.logging\", firstBatch: [{ _id: 2 }, { _id: 3 }] }, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    coll.drop().unwrap();

    let _ = fs::remove_file("test_log.txt").unwrap();
}
<|endoftext|>


<commit_before>#[test]
fn dogfood() {
    let root_dir = std::env::current_dir().unwrap();
    for d in &[".", "clippy_lints"] {
        std::env::set_current_dir(root_dir.join(d)).unwrap();
        let output = std::process::Command::new("cargo")
            .arg("run")
            .arg("--bin").arg("cargo-clippy")
            .arg("--manifest-path").arg(root_dir.join("Cargo.toml"))
            .output().unwrap();
        println!("status: {}", output.status);
        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

        assert!(output.status.success());
    }
}
<commit_msg>Don't run dogfood tests in the rustc test suite<commit_after>#[test]
fn dogfood() {
    if option_env!("RUSTC_TEST_SUITE").is_some() {
        return;
    }
    let root_dir = std::env::current_dir().unwrap();
    for d in &[".", "clippy_lints"] {
        std::env::set_current_dir(root_dir.join(d)).unwrap();
        let output = std::process::Command::new("cargo")
            .arg("run")
            .arg("--bin").arg("cargo-clippy")
            .arg("--manifest-path").arg(root_dir.join("Cargo.toml"))
            .output().unwrap();
        println!("status: {}", output.status);
        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

        assert!(output.status.success());
    }
}
<|endoftext|>