<commit_before>// Copyright 2018 Kyle Mayes
//
// 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.

use std::env;
use std::fs::File;
use std::io::{self, Error, ErrorKind, Read, Seek, SeekFrom};
use std::path::{Path, PathBuf};

use super::common;

/// Returns the ELF class from the ELF header in the supplied file.
fn parse_elf_header(path: &Path) -> io::Result<u8> {
    let mut file = File::open(path)?;
    let mut buffer = [0; 5];
    file.read_exact(&mut buffer)?;
    if buffer[..4] == [127, 69, 76, 70] {
        Ok(buffer[4])
    } else {
        Err(Error::new(ErrorKind::InvalidData, "invalid ELF header"))
    }
}

/// Returns the magic number from the PE header in the supplied file.
fn parse_pe_header(path: &Path) -> io::Result<u16> {
    let mut file = File::open(path)?;

    // Determine the header offset.
    let mut buffer = [0; 4];
    let start = SeekFrom::Start(0x3C);
    file.seek(start)?;
    file.read_exact(&mut buffer)?;
    let offset = i32::from_le_bytes(buffer);

    // Determine the validity of the header.
    file.seek(SeekFrom::Start(offset as u64))?;
    file.read_exact(&mut buffer)?;
    if buffer != [80, 69, 0, 0] {
        return Err(Error::new(ErrorKind::InvalidData, "invalid PE header"));
    }

    // Find the magic number.
    let mut buffer = [0; 2];
    file.seek(SeekFrom::Current(20))?;
    file.read_exact(&mut buffer)?;
    Ok(u16::from_le_bytes(buffer))
}

/// Validates the header for the supplied `libclang` shared library.
fn validate_header(path: &Path) -> Result<(), String> {
    if cfg!(any(target_os = "freebsd", target_os = "linux")) {
        let class = parse_elf_header(path).map_err(|e| e.to_string())?;

        if cfg!(target_pointer_width = "32") && class != 1 {
            return Err("invalid ELF class (64-bit)".into());
        }

        if cfg!(target_pointer_width = "64") && class != 2 {
            return Err("invalid ELF class (32-bit)".into());
        }

        Ok(())
    } else if cfg!(target_os = "windows") {
        let magic = parse_pe_header(path).map_err(|e| e.to_string())?;

        if cfg!(target_pointer_width = "32") && magic != 267 {
            return Err("invalid DLL (64-bit)".into());
        }

        if cfg!(target_pointer_width = "64") && magic != 523 {
            return Err("invalid DLL (32-bit)".into());
        }

        Ok(())
    } else {
        Ok(())
    }
}

/// Returns the components of the version in the supplied `libclang` shared
// library filename.
fn parse_version(filename: &str) -> Vec<u32> {
    let version = if filename.starts_with("libclang.so.") {
        &filename[12..]
    } else if filename.starts_with("libclang-") {
        &filename[9..filename.len() - 3]
    } else {
        return vec![];
    };

    version.split('.').map(|s| s.parse().unwrap_or(0)).collect()
}

/// Returns the paths to, the filenames, and the versions of the `libclang`
// shared libraries.
fn search_libclang_directories(runtime: bool) -> Result<Vec<(PathBuf, String, Vec<u32>)>, String> {
    let mut files = vec![format!(
        "{}clang{}",
        env::consts::DLL_PREFIX,
        env::consts::DLL_SUFFIX
    )];

    if cfg!(target_os = "linux") {
        // Some Linux distributions don't create a `libclang.so` symlink, so we
        // need to look for versioned files (e.g., `libclang-3.9.so`).
        files.push("libclang-*.so".into());

        // Some Linux distributions don't create a `libclang.so` symlink and
        // don't have versioned files as described above, so we need to look for
        // suffix versioned files (e.g., `libclang.so.1`). However, `ld` cannot
        // link to these files, so this will only be included when linking at
        // runtime.
        if runtime {
            files.push("libclang.so.*".into());
            files.push("libclang-*.so.*".into());
        }
    }

    if cfg!(any(
        target_os = "openbsd",
        target_os = "freebsd",
        target_os = "netbsd"
    )) {
        // Some BSD distributions don't create a `libclang.so` symlink either,
        // but use a different naming scheme for versioned files (e.g.,
        // `libclang.so.7.0`).
        files.push("libclang.so.*".into());
    }

    if cfg!(target_os = "windows") {
        // The official LLVM build uses `libclang.dll` on Windows instead of
        // `clang.dll`. However, unofficial builds such as MinGW use `clang.dll`.
        files.push("libclang.dll".into());
    }

    // Validate the `libclang` shared libraries and collect the versions.
    let mut valid = vec![];
    let mut invalid = vec![];
    for (directory, filename) in common::search_libclang_directories(&files, "LIBCLANG_PATH") {
        let path = directory.join(&filename);
        match validate_header(&path) {
            Ok(()) => {
                let version = parse_version(&filename);
                valid.push((directory, filename, version))
            }
            Err(message) => invalid.push(format!("({}: {})", path.display(), message)),
        }
    }

    if !valid.is_empty() {
        return Ok(valid);
    }

    let message = format!(
        "couldn't find any valid shared libraries matching: [{}], set the \
         `LIBCLANG_PATH` environment variable to a path where one of these files \
         can be found (invalid: [{}])",
        files
            .iter()
            .map(|f| format!("'{}'", f))
            .collect::<Vec<_>>()
            .join(", "),
        invalid.join(", "),
    );

    Err(message)
}

/// Returns the directory and filename of the "best" available `libclang` shared
/// library.
pub fn find(runtime: bool) -> Result<(PathBuf, String), String> {
    search_libclang_directories(runtime)?
        .iter()
        .rev() // `max_by_key` picks the last one but we want the first.
        .max_by_key(|f| &f.2)
        .cloned()
        .map(|(path, filename, _)| (path, filename))
        .ok_or_else(|| "unreachable".into())
}

/// Find and link to `libclang` dynamically.
#[cfg(not(feature = "runtime"))]
pub fn link() {
    let cep = common::CommandErrorPrinter::default();

    use std::fs;

    let (directory, filename) = find(false).unwrap();
    println!("cargo:rustc-link-search={}", directory.display());

    if cfg!(all(target_os = "windows", target_env = "msvc")) {
        // Find the `libclang` stub static library required for the MSVC
        // toolchain.
        let lib = if !directory.ends_with("bin") {
            directory
        } else {
            directory.parent().unwrap().join("lib")
        };

        if lib.join("libclang.lib").exists() {
            println!("cargo:rustc-link-search={}", lib.display());
        } else if lib.join("libclang.dll.a").exists() {
            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`.
            // It is linkable with the MSVC linker, but Rust doesn't recognize
            // the `.a` suffix, so we need to copy it with a different name.
            //
            // FIXME: Maybe we can just hardlink or symlink it?
            let out = env::var("OUT_DIR").unwrap();
            fs::copy(
                lib.join("libclang.dll.a"),
                Path::new(&out).join("libclang.lib"),
            )
            .unwrap();
            println!("cargo:rustc-link-search=native={}", out);
        } else {
            panic!(
                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be \
                 available in {}",
                filename,
                lib.display(),
            );
        }

        println!("cargo:rustc-link-lib=dylib=libclang");
    } else {
        let name = filename.trim_start_matches("lib");

        // Strip extensions and trailing version numbers (e.g., the `.so.7.0` in
        // `libclang.so.7.0`).
        let name = match name.find(".dylib").or_else(|| name.find(".so")) {
            Some(index) => &name[0..index],
            None => &name,
        };

        println!("cargo:rustc-link-lib=dylib={}", name);
    }

    cep.discard();
}
<commit_msg>Expand explanatory comment about tiebreaking<commit_after>// Copyright 2018 Kyle Mayes
//
// 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.

use std::env;
use std::fs::File;
use std::io::{self, Error, ErrorKind, Read, Seek, SeekFrom};
use std::path::{Path, PathBuf};

use super::common;

/// Returns the ELF class from the ELF header in the supplied file.
fn parse_elf_header(path: &Path) -> io::Result<u8> {
    let mut file = File::open(path)?;
    let mut buffer = [0; 5];
    file.read_exact(&mut buffer)?;
    if buffer[..4] == [127, 69, 76, 70] {
        Ok(buffer[4])
    } else {
        Err(Error::new(ErrorKind::InvalidData, "invalid ELF header"))
    }
}

/// Returns the magic number from the PE header in the supplied file.
fn parse_pe_header(path: &Path) -> io::Result<u16> {
    let mut file = File::open(path)?;

    // Determine the header offset.
    let mut buffer = [0; 4];
    let start = SeekFrom::Start(0x3C);
    file.seek(start)?;
    file.read_exact(&mut buffer)?;
    let offset = i32::from_le_bytes(buffer);

    // Determine the validity of the header.
    file.seek(SeekFrom::Start(offset as u64))?;
    file.read_exact(&mut buffer)?;
    if buffer != [80, 69, 0, 0] {
        return Err(Error::new(ErrorKind::InvalidData, "invalid PE header"));
    }

    // Find the magic number.
    let mut buffer = [0; 2];
    file.seek(SeekFrom::Current(20))?;
    file.read_exact(&mut buffer)?;
    Ok(u16::from_le_bytes(buffer))
}

/// Validates the header for the supplied `libclang` shared library.
fn validate_header(path: &Path) -> Result<(), String> {
    if cfg!(any(target_os = "freebsd", target_os = "linux")) {
        let class = parse_elf_header(path).map_err(|e| e.to_string())?;

        if cfg!(target_pointer_width = "32") && class != 1 {
            return Err("invalid ELF class (64-bit)".into());
        }

        if cfg!(target_pointer_width = "64") && class != 2 {
            return Err("invalid ELF class (32-bit)".into());
        }

        Ok(())
    } else if cfg!(target_os = "windows") {
        let magic = parse_pe_header(path).map_err(|e| e.to_string())?;

        if cfg!(target_pointer_width = "32") && magic != 267 {
            return Err("invalid DLL (64-bit)".into());
        }

        if cfg!(target_pointer_width = "64") && magic != 523 {
            return Err("invalid DLL (32-bit)".into());
        }

        Ok(())
    } else {
        Ok(())
    }
}

/// Returns the components of the version in the supplied `libclang` shared
// library filename.
fn parse_version(filename: &str) -> Vec<u32> {
    let version = if filename.starts_with("libclang.so.") {
        &filename[12..]
    } else if filename.starts_with("libclang-") {
        &filename[9..filename.len() - 3]
    } else {
        return vec![];
    };

    version.split('.').map(|s| s.parse().unwrap_or(0)).collect()
}

/// Returns the paths to, the filenames, and the versions of the `libclang`
// shared libraries.
fn search_libclang_directories(runtime: bool) -> Result<Vec<(PathBuf, String, Vec<u32>)>, String> {
    let mut files = vec![format!(
        "{}clang{}",
        env::consts::DLL_PREFIX,
        env::consts::DLL_SUFFIX
    )];

    if cfg!(target_os = "linux") {
        // Some Linux distributions don't create a `libclang.so` symlink, so we
        // need to look for versioned files (e.g., `libclang-3.9.so`).
        files.push("libclang-*.so".into());

        // Some Linux distributions don't create a `libclang.so` symlink and
        // don't have versioned files as described above, so we need to look for
        // suffix versioned files (e.g., `libclang.so.1`). However, `ld` cannot
        // link to these files, so this will only be included when linking at
        // runtime.
        if runtime {
            files.push("libclang.so.*".into());
            files.push("libclang-*.so.*".into());
        }
    }

    if cfg!(any(
        target_os = "openbsd",
        target_os = "freebsd",
        target_os = "netbsd"
    )) {
        // Some BSD distributions don't create a `libclang.so` symlink either,
        // but use a different naming scheme for versioned files (e.g.,
        // `libclang.so.7.0`).
        files.push("libclang.so.*".into());
    }

    if cfg!(target_os = "windows") {
        // The official LLVM build uses `libclang.dll` on Windows instead of
        // `clang.dll`. However, unofficial builds such as MinGW use `clang.dll`.
        files.push("libclang.dll".into());
    }

    // Validate the `libclang` shared libraries and collect the versions.
    let mut valid = vec![];
    let mut invalid = vec![];
    for (directory, filename) in common::search_libclang_directories(&files, "LIBCLANG_PATH") {
        let path = directory.join(&filename);
        match validate_header(&path) {
            Ok(()) => {
                let version = parse_version(&filename);
                valid.push((directory, filename, version))
            }
            Err(message) => invalid.push(format!("({}: {})", path.display(), message)),
        }
    }

    if !valid.is_empty() {
        return Ok(valid);
    }

    let message = format!(
        "couldn't find any valid shared libraries matching: [{}], set the \
         `LIBCLANG_PATH` environment variable to a path where one of these files \
         can be found (invalid: [{}])",
        files
            .iter()
            .map(|f| format!("'{}'", f))
            .collect::<Vec<_>>()
            .join(", "),
        invalid.join(", "),
    );

    Err(message)
}

/// Returns the directory and filename of the "best" available `libclang` shared
/// library.
pub fn find(runtime: bool) -> Result<(PathBuf, String), String> {
    search_libclang_directories(runtime)?
        .iter()
        // We want to find the `libclang` shared library with the highest
        // version number, hence `max_by_key` below.
        //
        // However, in the case where there are multiple such `libclang` shared
        // libraries, we want to use the order in which they appeared in the
        // list returned by `search_libclang_directories` as a tiebreaker since
        // that function returns `libclang` shared libraries in descending order
        // of preference by how they were found.
        //
        // `max_by_key`, perhaps surprisingly, returns the *last* item with the
        // maximum key rather than the first which results in the opposite of
        // the tiebreaking behavior we want. This is easily fixed by reversing
        // the list first.
        .rev()
        .max_by_key(|f| &f.2)
        .cloned()
        .map(|(path, filename, _)| (path, filename))
        .ok_or_else(|| "unreachable".into())
}

/// Find and link to `libclang` dynamically.
#[cfg(not(feature = "runtime"))]
pub fn link() {
    let cep = common::CommandErrorPrinter::default();

    use std::fs;

    let (directory, filename) = find(false).unwrap();
    println!("cargo:rustc-link-search={}", directory.display());

    if cfg!(all(target_os = "windows", target_env = "msvc")) {
        // Find the `libclang` stub static library required for the MSVC
        // toolchain.
        let lib = if !directory.ends_with("bin") {
            directory
        } else {
            directory.parent().unwrap().join("lib")
        };

        if lib.join("libclang.lib").exists() {
            println!("cargo:rustc-link-search={}", lib.display());
        } else if lib.join("libclang.dll.a").exists() {
            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`.
            // It is linkable with the MSVC linker, but Rust doesn't recognize
            // the `.a` suffix, so we need to copy it with a different name.
            //
            // FIXME: Maybe we can just hardlink or symlink it?
            let out = env::var("OUT_DIR").unwrap();
            fs::copy(
                lib.join("libclang.dll.a"),
                Path::new(&out).join("libclang.lib"),
            )
            .unwrap();
            println!("cargo:rustc-link-search=native={}", out);
        } else {
            panic!(
                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be \
                 available in {}",
                filename,
                lib.display(),
            );
        }

        println!("cargo:rustc-link-lib=dylib=libclang");
    } else {
        let name = filename.trim_start_matches("lib");

        // Strip extensions and trailing version numbers (e.g., the `.so.7.0` in
        // `libclang.so.7.0`).
        let name = match name.find(".dylib").or_else(|| name.find(".so")) {
            Some(index) => &name[0..index],
            None => &name,
        };

        println!("cargo:rustc-link-lib=dylib={}", name);
    }

    cep.discard();
}
<|endoftext|>


<commit_before>extern mod encoding;

use io::Writer;
use io::WriterUtil;
use encoding::Codec;
use path::Path;

fn main(args: ~[~str]) {
    let binary = copy args[0];
    let stdout = io::stdout();
    let stderr = io::stderr();

    if args.len() < 2u {
        stderr.write_line(fmt!("Usage: %s <mode> <filename>", binary));
        return;
    }

    match io::read_whole_file(&Path(args[2])) {
        result::Ok(data) => match args[1] {
            ~"encode" => stdout.write(data.encode(encoding::Base64)),
            ~"decode" => stdout.write(data.decode(encoding::Base64)),
            _         => return
        },
        result::Err(msg) => {
            stderr.write_line(fmt!("Error: %s", msg));
        }
    }
}
<commit_msg>examples: de-moding b64.rs<commit_after>extern mod encoding;

use io::Writer;
use io::WriterUtil;
use encoding::Codec;
use path::Path;

fn main(args: ~[~str]) {
    let binary = copy args[0];
    let stdout = io::stdout();
    let stderr = io::stderr();

    if args.len() < 2u {
        stderr.write_line(fmt!("Usage: %s <mode> <filename>", binary));
        return;
    }

    match io::read_whole_file(&Path(args[2])) {
        Ok(move data) => match args[1] {
            ~"encode" => stdout.write(data.encode(encoding::Base64)),
            ~"decode" => stdout.write(data.decode(encoding::Base64)),
            _         => return
        },
        Err(ref msg) => {
            stderr.write_line(fmt!("Error: %s", *msg));
        }
    }
}
<|endoftext|>


<commit_before>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("mkdir -p path_name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");

    println!("cd {path_name}");

    env::set_current_dir(&path_name).expect("changing directory failed");

    let app_name = format!("{program_name}-{program_type}");
    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    println!("cd {folder_name}");

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let git_rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    println!(
        "rev-list stdout: {}",
        String::from_utf8(git_rev_list_output.stdout.clone()).unwrap()
    );

    if git_rev_list_output.status.success() {
        let git_rev_list_output_cow =
            String::from_utf8_lossy(&git_rev_list_output.stdout).to_string();

        for (i, commit_hash) in git_rev_list_output_cow.split("\n").enumerate() {
            println!("i: {i}");
            if !commit_hash.is_empty() {
                println!("git checkout {commit_hash}");

                let git_checkout_output = Command::new("git")
                    .arg("checkout")
                    .arg(commit_hash)
                    .output()
                    .expect("checkout failed");

                if git_checkout_output.status.success() {
                    println!(
                        "git checkout stdout: {}",
                        String::from_utf8(git_checkout_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git checkout stderr: {}",
                        String::from_utf8(git_checkout_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                println!("git show");

                let git_show_output = Command::new("git")
                    .arg("show")
                    .output()
                    .expect("show failed");

                if git_show_output.status.success() {
                    println!(
                        "git show stdout: {}",
                        String::from_utf8(git_show_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git show stderr: {}",
                        String::from_utf8(git_show_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                let parent_path = env::current_dir().expect("getting current directory failed");
                let mut path = parent_path.clone();
                path.push(&app_name);
                let metadata = fs::metadata(path);
                match metadata {
                    Ok(_) => {
                        println!("{app_name} found");
                    }
                    Err(_) => {
                        println!("{app_name} not found");
                        continue;
                    }
                };

                println!("cd {app_name}");

                env::set_current_dir(&app_name).expect("changing directory failed");

                println!("cargo test");

                let cargo_test_output = Command::new("cargo")
                    .arg("test")
                    .output()
                    .expect("test failed");

                if cargo_test_output.status.success() {
                    println!(
                        "cargo test stdout: {}",
                        String::from_utf8(cargo_test_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "cargo test stderr: {}",
                        String::from_utf8(cargo_test_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                println!("cd ..");

                env::set_current_dir(parent_path).expect("changing directory failed");
            }
        }
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8(git_rev_list_output.stderr).unwrap()
        );

        process::exit(1);
    }
}
<commit_msg>changed repo names<commit_after>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - default-library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "default-library" {
        "default-library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("mkdir -p path_name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");

    println!("cd {path_name}");

    env::set_current_dir(&path_name).expect("changing directory failed");

    let app_name = format!("{program_name}-{program_type}");
    let folder_name = format!("{program_name}-using-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    println!("cd {folder_name}");

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let git_rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    println!(
        "rev-list stdout: {}",
        String::from_utf8(git_rev_list_output.stdout.clone()).unwrap()
    );

    if git_rev_list_output.status.success() {
        let git_rev_list_output_cow =
            String::from_utf8_lossy(&git_rev_list_output.stdout).to_string();

        for (i, commit_hash) in git_rev_list_output_cow.split("\n").enumerate() {
            println!("i: {i}");
            if !commit_hash.is_empty() {
                println!("git checkout {commit_hash}");

                let git_checkout_output = Command::new("git")
                    .arg("checkout")
                    .arg(commit_hash)
                    .output()
                    .expect("checkout failed");

                if git_checkout_output.status.success() {
                    println!(
                        "git checkout stdout: {}",
                        String::from_utf8(git_checkout_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git checkout stderr: {}",
                        String::from_utf8(git_checkout_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                println!("git show");

                let git_show_output = Command::new("git")
                    .arg("show")
                    .output()
                    .expect("show failed");

                if git_show_output.status.success() {
                    println!(
                        "git show stdout: {}",
                        String::from_utf8(git_show_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git show stderr: {}",
                        String::from_utf8(git_show_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                let parent_path = env::current_dir().expect("getting current directory failed");
                let mut path = parent_path.clone();
                path.push(&app_name);
                let metadata = fs::metadata(path);
                match metadata {
                    Ok(_) => {
                        println!("{app_name} found");
                    }
                    Err(_) => {
                        println!("{app_name} not found");
                        continue;
                    }
                };

                println!("cd {app_name}");

                env::set_current_dir(&app_name).expect("changing directory failed");

                println!("cargo test");

                let cargo_test_output = Command::new("cargo")
                    .arg("test")
                    .output()
                    .expect("test failed");

                if cargo_test_output.status.success() {
                    println!(
                        "cargo test stdout: {}",
                        String::from_utf8(cargo_test_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "cargo test stderr: {}",
                        String::from_utf8(cargo_test_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                println!("cd ..");

                env::set_current_dir(parent_path).expect("changing directory failed");
            }
        }
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8(git_rev_list_output.stderr).unwrap()
        );

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]
#![feature(plugin_registrar, macro_rules, quote)]

#![allow(unused_imports)]

extern crate syntax;
extern crate rustc;
extern crate docopt;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;
use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItem, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use docopt::{DEFAULT_CONFIG, Config, Docopt, ValueMap};
use docopt::parse::{
    Options,
    Atom, Short, Long, Command, Positional,
    Argument, Zero, One,
};

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_name: ast::Ident,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `uint`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, Gc<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_name;
        let full_doc = self.doc.parser().full_doc.as_slice();
        its.push(quote_item!(cx,
            impl docopt::FlagParser for $struct_name {
                #[allow(dead_code)]
                fn parse_args(conf: docopt::Config, args: &[&str])
                             -> Result<$struct_name, docopt::Error> {
                    docopt::docopt_args(conf, args, $full_doc).and_then(|v| {
                        v.decode()
                    })
                }
            }
        ).unwrap());
        MacItems::new(its)
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> Gc<ast::Item> {
        let def = ast::StructDef {
            fields: self.struct_fields(cx),
            ctor_id: None,
            super_struct: None,
            is_virtual: false,
        };
        let sp = codemap::DUMMY_SP;
        let traits = vec![meta_item(cx, "Decodable"), meta_item(cx, "Show")];
        let deriving = cx.meta_list(sp, intern("deriving"), traits);
        let attrs = vec![cx.attribute(codemap::DUMMY_SP, deriving)];
        let st = cx.item_struct(sp, self.struct_name.clone(), def);
        cx.item(sp, self.struct_name.clone(), attrs, st.node.clone())
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ValueMap::key_to_struct_field(atom.to_string().as_slice());
            let ty = match self.types.find(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(name.as_slice(), ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> Gc<ast::Ty> {
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => quote_ty!(cx, String),
                    _ => quote_ty!(cx, bool),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => quote_ty!(cx, Vec<String>),
                    _ => quote_ty!(cx, uint),
                }
            }
            (false, &One(_)) => quote_ty!(cx, String),
            (true, &One(_)) => quote_ty!(cx, Vec<String>),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: Gc<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b> {
    cx: &'b mut ExtCtxt<'a>,
    p: Parser<'a>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'b mut ExtCtxt<'a>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> Result<Parsed, ()> {
        if self.p.token == token::EOF {
            self.cx.span_err(self.cx.call_site(), "macro expects arguments");
            return Err(());
        }
        let struct_name = self.p.parse_ident();
        self.p.expect(&token::COMMA);
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::COMMA),
            trailing_sep_allowed: true,
        };
        let types = self.p.parse_seq_to_end(
            &token::EOF, sep, |p| MacParser::parse_type_annotation(p)
        ).move_iter()
         .map(|(ident, ty)| {
             let field_name = token::get_ident(ident).to_string();
             let key = ValueMap::struct_field_to_key(field_name.as_slice());
             (Atom::new(key.as_slice()), ty)
          })
         .collect::<HashMap<Atom, Gc<ast::Ty>>>();
        self.p.expect(&token::EOF);

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(DEFAULT_CONFIG.clone(), docstr.as_slice()) {
            Ok(doc) => doc,
            Err(err) => {
                self.cx.span_err(self.cx.call_site(),
                                 format!("Invalid Docopt usage: {}",
                                         err).as_slice());
                return Err(());
            }
        };
        Ok(Parsed {
            struct_name: struct_name,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> Result<String, ()> {
        fn lit_is_str(lit: Gc<ast::Lit>) -> bool {
            match lit.node {
                ast::LitStr(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: Gc<ast::Lit>) -> String {
            match lit.node {
                ast::LitStr(ref s, _) => s.to_string(),
                _ => fail!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expand_expr(self.p.parse_expr());
        let s = match exp.node {
            ast::ExprLit(lit) if lit_is_str(lit) => lit_to_string(lit),
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                self.cx.span_err(exp.span, err.as_slice());
                return Err(());
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser) -> (ast::Ident, Gc<ast::Ty>) {
        let ident = p.parse_ident();
        p.expect(&token::COLON);
        let ty = p.parse_ty(false);
        (ident, ty)
    }
}

/// MacItems is just like `syntax::ext::base::MacItem`, except it supports
/// writing multiple items.
struct MacItems {
    its: Vec<Gc<ast::Item>>,
}

impl MacResult for MacItems {
    fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
        let mut small = SmallVector::zero();
        for it in self.its.iter() {
            small.push(it.clone());
        }
        Some(small)
    }
}

impl MacItems {
    fn new(its: Vec<Gc<ast::Item>>) -> Box<MacResult> {
        box MacItems { its: its } as Box<MacResult>
    }
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::new(token::intern(s))
}

fn meta_item(cx: &ExtCtxt, s: &str) -> Gc<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}
<commit_msg>expand_expr -> expander().fold_expr<commit_after>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]
#![feature(plugin_registrar, macro_rules, quote)]

#![allow(unused_imports)]

extern crate syntax;
extern crate rustc;
extern crate docopt;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;
use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItem, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use docopt::{DEFAULT_CONFIG, Config, Docopt, ValueMap};
use docopt::parse::{
    Options,
    Atom, Short, Long, Command, Positional,
    Argument, Zero, One,
};

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_name: ast::Ident,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `uint`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, Gc<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_name;
        let full_doc = self.doc.parser().full_doc.as_slice();
        its.push(quote_item!(cx,
            impl docopt::FlagParser for $struct_name {
                #[allow(dead_code)]
                fn parse_args(conf: docopt::Config, args: &[&str])
                             -> Result<$struct_name, docopt::Error> {
                    docopt::docopt_args(conf, args, $full_doc).and_then(|v| {
                        v.decode()
                    })
                }
            }
        ).unwrap());
        MacItems::new(its)
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> Gc<ast::Item> {
        let def = ast::StructDef {
            fields: self.struct_fields(cx),
            ctor_id: None,
            super_struct: None,
            is_virtual: false,
        };
        let sp = codemap::DUMMY_SP;
        let traits = vec![meta_item(cx, "Decodable"), meta_item(cx, "Show")];
        let deriving = cx.meta_list(sp, intern("deriving"), traits);
        let attrs = vec![cx.attribute(codemap::DUMMY_SP, deriving)];
        let st = cx.item_struct(sp, self.struct_name.clone(), def);
        cx.item(sp, self.struct_name.clone(), attrs, st.node.clone())
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ValueMap::key_to_struct_field(atom.to_string().as_slice());
            let ty = match self.types.find(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(name.as_slice(), ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> Gc<ast::Ty> {
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => quote_ty!(cx, String),
                    _ => quote_ty!(cx, bool),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => quote_ty!(cx, Vec<String>),
                    _ => quote_ty!(cx, uint),
                }
            }
            (false, &One(_)) => quote_ty!(cx, String),
            (true, &One(_)) => quote_ty!(cx, Vec<String>),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: Gc<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b> {
    cx: &'b mut ExtCtxt<'a>,
    p: Parser<'a>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'b mut ExtCtxt<'a>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> Result<Parsed, ()> {
        if self.p.token == token::EOF {
            self.cx.span_err(self.cx.call_site(), "macro expects arguments");
            return Err(());
        }
        let struct_name = self.p.parse_ident();
        self.p.expect(&token::COMMA);
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::COMMA),
            trailing_sep_allowed: true,
        };
        let types = self.p.parse_seq_to_end(
            &token::EOF, sep, |p| MacParser::parse_type_annotation(p)
        ).move_iter()
         .map(|(ident, ty)| {
             let field_name = token::get_ident(ident).to_string();
             let key = ValueMap::struct_field_to_key(field_name.as_slice());
             (Atom::new(key.as_slice()), ty)
          })
         .collect::<HashMap<Atom, Gc<ast::Ty>>>();
        self.p.expect(&token::EOF);

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(DEFAULT_CONFIG.clone(), docstr.as_slice()) {
            Ok(doc) => doc,
            Err(err) => {
                self.cx.span_err(self.cx.call_site(),
                                 format!("Invalid Docopt usage: {}",
                                         err).as_slice());
                return Err(());
            }
        };
        Ok(Parsed {
            struct_name: struct_name,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> Result<String, ()> {
        fn lit_is_str(lit: Gc<ast::Lit>) -> bool {
            match lit.node {
                ast::LitStr(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: Gc<ast::Lit>) -> String {
            match lit.node {
                ast::LitStr(ref s, _) => s.to_string(),
                _ => fail!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr());
        let s = match exp.node {
            ast::ExprLit(lit) if lit_is_str(lit) => lit_to_string(lit),
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                self.cx.span_err(exp.span, err.as_slice());
                return Err(());
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser) -> (ast::Ident, Gc<ast::Ty>) {
        let ident = p.parse_ident();
        p.expect(&token::COLON);
        let ty = p.parse_ty(false);
        (ident, ty)
    }
}

/// MacItems is just like `syntax::ext::base::MacItem`, except it supports
/// writing multiple items.
struct MacItems {
    its: Vec<Gc<ast::Item>>,
}

impl MacResult for MacItems {
    fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
        let mut small = SmallVector::zero();
        for it in self.its.iter() {
            small.push(it.clone());
        }
        Some(small)
    }
}

impl MacItems {
    fn new(its: Vec<Gc<ast::Item>>) -> Box<MacResult> {
        box MacItems { its: its } as Box<MacResult>
    }
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::new(token::intern(s))
}

fn meta_item(cx: &ExtCtxt, s: &str) -> Gc<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}
<|endoftext|>


<commit_before>use quote::{Tokens, Ident};
use syn::Visibility;
use structs::Struct;

pub fn derive(input: &Struct) -> Tokens {
    let name = &input.name;
    let visibility = &input.visibility;
    let detail_mod = Ident::from(format!("__detail_iter_{}", name.as_ref().to_lowercase()));
    let vec_name = &input.vec_name();
    let slice_name = &input.slice_name();
    let slice_mut_name = &input.slice_mut_name();
    let ref_name = &input.ref_name();
    let ref_mut_name = &input.ref_mut_name();

    let ref_doc_url = format!("[`{0}`](struct.{0}.html)", ref_name);
    let ref_mut_doc_url = format!("[`{0}`](struct.{0}.html)", ref_mut_name);

    let fields_names = &input.fields.iter()
                                    .map(|field| field.ident.clone().unwrap())
                                    .collect::<Vec<_>>();
    let first_field = &fields_names[0];

    let fields_types = &input.fields.iter()
                                    .map(|field| &field.ty)
                                    .collect::<Vec<_>>();
    let first_field_type = &fields_types[0];

    let mut iter_type = quote!{
        slice::Iter<'a, #first_field_type>
    };
    let mut iter_pat = quote!{
        #first_field
    };
    let mut create_iter = quote!{
        self.#first_field.iter()
    };

    let mut iter_mut_type = quote!{
        slice::IterMut<'a, #first_field_type>
    };
    let mut create_iter_mut = quote!{
        self.#first_field.iter_mut()
    };

    if fields_types.len() > 1 {
        for field in &input.fields[1..] {
            let field_name = &field.ident;
            let field_type = &field.ty;

            iter_pat = quote!{
                (#iter_pat, #field_name)
            };

            iter_type = quote!{
                iter::Zip<#iter_type, slice::Iter<'a, #field_type>>
            };

            create_iter = quote!{
                #create_iter.zip(self.#field_name.iter())
            };

            iter_mut_type = quote!{
                iter::Zip<#iter_mut_type, slice::IterMut<'a, #field_type>>
            };

            create_iter_mut = quote!{
                #create_iter_mut.zip(self.#field_name.iter_mut())
            };
        }
    }

    let mut generated = quote! {
        #[allow(non_snake_case, dead_code)]
        mod #detail_mod {
            use super::*;
            use std::slice;
            #[allow(unused_imports)]
            use std::iter;

            #visibility struct Iter<'a>(pub(super) #iter_type);

            impl<'a> Iterator for Iter<'a> {
                type Item = #ref_name<'a>;
                fn next(&mut self) -> Option<#ref_name<'a>> {
                    self.0.next().and_then(|#iter_pat|
                        Some(#ref_name{
                            #(#fields_names,)*
                        })
                    )
                }

                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.0.size_hint()
                }
            }

            impl<'a> DoubleEndedIterator for Iter<'a> {
                fn next_back(&mut self) -> Option<#ref_name<'a>> {
                    self.0.next_back().and_then(|#iter_pat|
                        Some(#ref_name{
                            #(#fields_names,)*
                        })
                    )
                }
            }

            impl #vec_name {
                /// Get an iterator over the
                #[doc = #ref_doc_url]
                /// in this vector
                #visibility fn iter(&self) -> Iter {
                    Iter(#create_iter)
                }
            }

            impl<'a> #slice_name<'a> {
                /// Get an iterator over the
                #[doc = #ref_doc_url]
                /// in this slice.
                #visibility fn iter(&self) -> Iter {
                    Iter(#create_iter)
                }
            }

            #visibility struct IterMut<'a>(pub(super) #iter_mut_type);

            impl<'a> Iterator for IterMut<'a> {
                type Item = #ref_mut_name<'a>;
                fn next(&mut self) -> Option<#ref_mut_name<'a>> {
                    self.0.next().and_then(|#iter_pat|
                        Some(#ref_mut_name{
                            #(#fields_names,)*
                        })
                    )
                }

                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.0.size_hint()
                }
            }

            impl<'a> DoubleEndedIterator for IterMut<'a> {
                fn next_back(&mut self) -> Option<#ref_mut_name<'a>> {
                    self.0.next_back().and_then(|#iter_pat|
                        Some(#ref_mut_name{
                            #(#fields_names,)*
                        })
                    )
                }
            }

            impl #vec_name {
                /// Get a mutable iterator over the
                #[doc = #ref_mut_doc_url]
                /// in this vector
                #visibility fn iter_mut(&mut self) -> IterMut {
                    IterMut(#create_iter_mut)
                }
            }

            impl<'a> #slice_mut_name<'a> {
                /// Get an iterator over the
                #[doc = #ref_doc_url]
                /// in this vector
                #visibility fn iter(&mut self) -> Iter {
                    Iter(#create_iter)
                }

                /// Get a mutable iterator over the
                #[doc = #ref_mut_doc_url]
                /// in this vector
                #visibility fn iter_mut(&mut self) -> IterMut {
                    IterMut(#create_iter_mut)
                }
            }
        }
    };

    if let Visibility::Public = *visibility {
        generated.append(quote!{
            impl<'a> IntoIterator for #slice_name<'a> {
                type Item = #ref_name<'a>;
                type IntoIter = #detail_mod::Iter<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::Iter(#create_iter)
                }
            }

            impl<'a,'b> IntoIterator for &'a #slice_name<'b> {
                type Item = #ref_name<'a>;
                type IntoIter = #detail_mod::Iter<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::Iter(#create_iter)
                }
            }

            impl<'a> IntoIterator for &'a #vec_name {
                type Item = #ref_name<'a>;
                type IntoIter = #detail_mod::Iter<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::Iter(#create_iter)
                }
            }

            impl<'a> IntoIterator for #slice_mut_name<'a> {
                type Item = #ref_mut_name<'a>;
                type IntoIter = #detail_mod::IterMut<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::IterMut(#create_iter_mut)
                }
            }

            impl<'a> IntoIterator for &'a mut #vec_name {
                type Item = #ref_mut_name<'a>;
                type IntoIter = #detail_mod::IterMut<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::IterMut(#create_iter_mut)
                }
            }
        });
    }

    return generated;
}
<commit_msg>DoubleEndedIterator bench fix<commit_after>use quote::{Tokens, Ident};
use syn::Visibility;
use structs::Struct;

pub fn derive(input: &Struct) -> Tokens {
    let name = &input.name;
    let visibility = &input.visibility;
    let detail_mod = Ident::from(format!("__detail_iter_{}", name.as_ref().to_lowercase()));
    let vec_name = &input.vec_name();
    let slice_name = &input.slice_name();
    let slice_mut_name = &input.slice_mut_name();
    let ref_name = &input.ref_name();
    let ref_mut_name = &input.ref_mut_name();

    let ref_doc_url = format!("[`{0}`](struct.{0}.html)", ref_name);
    let ref_mut_doc_url = format!("[`{0}`](struct.{0}.html)", ref_mut_name);

    let fields_names = &input.fields.iter()
                                    .map(|field| field.ident.clone().unwrap())
                                    .collect::<Vec<_>>();
    let first_field = &fields_names[0];

    let fields_types = &input.fields.iter()
                                    .map(|field| &field.ty)
                                    .collect::<Vec<_>>();
    let first_field_type = &fields_types[0];

    let mut iter_type = quote!{
        slice::Iter<'a, #first_field_type>
    };
    let mut iter_pat = quote!{
        #first_field
    };
    let mut create_iter = quote!{
        self.#first_field.iter()
    };

    let mut iter_mut_type = quote!{
        slice::IterMut<'a, #first_field_type>
    };
    let mut create_iter_mut = quote!{
        self.#first_field.iter_mut()
    };

    if fields_types.len() > 1 {
        for field in &input.fields[1..] {
            let field_name = &field.ident;
            let field_type = &field.ty;

            iter_pat = quote!{
                (#iter_pat, #field_name)
            };

            iter_type = quote!{
                iter::Zip<#iter_type, slice::Iter<'a, #field_type>>
            };

            create_iter = quote!{
                #create_iter.zip(self.#field_name.iter())
            };

            iter_mut_type = quote!{
                iter::Zip<#iter_mut_type, slice::IterMut<'a, #field_type>>
            };

            create_iter_mut = quote!{
                #create_iter_mut.zip(self.#field_name.iter_mut())
            };
        }
    }

    let mut generated = quote! {
        #[allow(non_snake_case, dead_code)]
        mod #detail_mod {
            use super::*;
            use std::slice;
            #[allow(unused_imports)]
            use std::iter;

            #visibility struct Iter<'a>(pub(super) #iter_type);

            impl<'a> Iterator for Iter<'a> {
                type Item = #ref_name<'a>;

                #[inline]
                fn next(&mut self) -> Option<#ref_name<'a>> {
                    self.0.next().and_then(|#iter_pat|
                        Some(#ref_name{
                            #(#fields_names,)*
                        })
                    )
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.0.size_hint()
                }
            }

            impl<'a> DoubleEndedIterator for Iter<'a> {

                #[inline]
                fn next_back(&mut self) -> Option<#ref_name<'a>> {
                    self.0.next_back().and_then(|#iter_pat|
                        Some(#ref_name{
                            #(#fields_names,)*
                        })
                    )
                }
            }

            impl #vec_name {
                /// Get an iterator over the
                #[doc = #ref_doc_url]
                /// in this vector
                #visibility fn iter(&self) -> Iter {
                    Iter(#create_iter)
                }
            }

            impl<'a> #slice_name<'a> {
                /// Get an iterator over the
                #[doc = #ref_doc_url]
                /// in this slice.
                #visibility fn iter(&self) -> Iter {
                    Iter(#create_iter)
                }
            }

            #visibility struct IterMut<'a>(pub(super) #iter_mut_type);

            impl<'a> Iterator for IterMut<'a> {
                type Item = #ref_mut_name<'a>;

                #[inline]
                fn next(&mut self) -> Option<#ref_mut_name<'a>> {
                    self.0.next().and_then(|#iter_pat|
                        Some(#ref_mut_name{
                            #(#fields_names,)*
                        })
                    )
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.0.size_hint()
                }
            }

            impl<'a> DoubleEndedIterator for IterMut<'a> {

                #[inline]
                fn next_back(&mut self) -> Option<#ref_mut_name<'a>> {
                    self.0.next_back().and_then(|#iter_pat|
                        Some(#ref_mut_name{
                            #(#fields_names,)*
                        })
                    )
                }
            }

            impl #vec_name {
                /// Get a mutable iterator over the
                #[doc = #ref_mut_doc_url]
                /// in this vector
                #visibility fn iter_mut(&mut self) -> IterMut {
                    IterMut(#create_iter_mut)
                }
            }

            impl<'a> #slice_mut_name<'a> {
                /// Get an iterator over the
                #[doc = #ref_doc_url]
                /// in this vector
                #visibility fn iter(&mut self) -> Iter {
                    Iter(#create_iter)
                }

                /// Get a mutable iterator over the
                #[doc = #ref_mut_doc_url]
                /// in this vector
                #visibility fn iter_mut(&mut self) -> IterMut {
                    IterMut(#create_iter_mut)
                }
            }
        }
    };

    if let Visibility::Public = *visibility {
        generated.append(quote!{
            impl<'a> IntoIterator for #slice_name<'a> {
                type Item = #ref_name<'a>;
                type IntoIter = #detail_mod::Iter<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::Iter(#create_iter)
                }
            }

            impl<'a,'b> IntoIterator for &'a #slice_name<'b> {
                type Item = #ref_name<'a>;
                type IntoIter = #detail_mod::Iter<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::Iter(#create_iter)
                }
            }

            impl<'a> IntoIterator for &'a #vec_name {
                type Item = #ref_name<'a>;
                type IntoIter = #detail_mod::Iter<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::Iter(#create_iter)
                }
            }

            impl<'a> IntoIterator for #slice_mut_name<'a> {
                type Item = #ref_mut_name<'a>;
                type IntoIter = #detail_mod::IterMut<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::IterMut(#create_iter_mut)
                }
            }

            impl<'a> IntoIterator for &'a mut #vec_name {
                type Item = #ref_mut_name<'a>;
                type IntoIter = #detail_mod::IterMut<'a>;

                fn into_iter(self) -> Self::IntoIter {
                    #detail_mod::IterMut(#create_iter_mut)
                }
            }
        });
    }

    return generated;
}
<|endoftext|>


<commit_before>use crate::common::util::*;
use std::env;

#[test]
fn test_normal() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.run();
    println!("result.stdout = {}", result.stdout);
    println!("result.stderr = {}", result.stderr);
    println!("env::var(CI).is_ok() = {}", env::var("CI").is_ok());

    for (key, value) in env::vars() {
        println!("{}: {}", key, value);
    }
    if env::var("USER").is_ok()
        && env::var("USER").unwrap() == "runner"
        && result.stderr.contains("failed to get username")
    {
        // In the CI, some server are failing to return whoami.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(!result.stdout.trim().is_empty());
}

#[test]
fn test_normal_compare_id() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.run();

    println!("result.stdout = {}", result.stdout);
    println!("result.stderr = {}", result.stderr);
    if env::var("USER").is_ok()
        && env::var("USER").unwrap() == "runner"
        && result.stderr.contains("failed to get username")
    {
        // In the CI, some server are failing to return whoami.
        // As seems to be a configuration issue, ignoring it
        return;
    }
    assert!(result.success);
    let ts = TestScenario::new("id");
    let id = ts.cmd("id").arg("-un").run();

    if env::var("USER").is_ok()
        && env::var("USER").unwrap() == "runner"
        && id.stderr.contains("cannot find name for user ID")
    {
        // In the CI, some server are failing to return whoami.
        // As seems to be a configuration issue, ignoring it
        return;
    }
    assert_eq!(result.stdout.trim(), id.stdout.trim());
}
<commit_msg>tests ~ disable `whoami` test using `id` for 'windows' (fixes #1519)<commit_after>use crate::common::util::*;
use std::env;

#[test]
fn test_normal() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.run();
    println!("result.stdout = {}", result.stdout);
    println!("result.stderr = {}", result.stderr);
    println!("env::var(CI).is_ok() = {}", env::var("CI").is_ok());

    for (key, value) in env::vars() {
        println!("{}: {}", key, value);
    }
    if env::var("USER").is_ok()
        && env::var("USER").unwrap() == "runner"
        && result.stderr.contains("failed to get username")
    {
        // In the CI, some server are failing to return whoami.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(!result.stdout.trim().is_empty());
}

#[test]
#[cfg(not(windows))]
fn test_normal_compare_id() {
    let (_, mut ucmd) = at_and_ucmd!();

    let result = ucmd.run();

    println!("result.stdout = {}", result.stdout);
    println!("result.stderr = {}", result.stderr);
    if env::var("USER").is_ok()
        && env::var("USER").unwrap() == "runner"
        && result.stderr.contains("failed to get username")
    {
        // In the CI, some server are failing to return whoami.
        // As seems to be a configuration issue, ignoring it
        return;
    }
    assert!(result.success);
    let ts = TestScenario::new("id");
    let id = ts.cmd("id").arg("-un").run();

    if env::var("USER").is_ok()
        && env::var("USER").unwrap() == "runner"
        && id.stderr.contains("cannot find name for user ID")
    {
        // In the CI, some server are failing to return whoami.
        // As seems to be a configuration issue, ignoring it
        return;
    }
    assert_eq!(result.stdout.trim(), id.stdout.trim());
}
<|endoftext|>


<commit_before>//! Generic serialization framework.

pub mod impls;

///////////////////////////////////////////////////////////////////////////////

pub trait Serialize {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer;
}

///////////////////////////////////////////////////////////////////////////////

pub trait Serializer {
    type Error;

    /// `visit_bool` serializes a `bool` value.
    fn visit_bool(&mut self, v: bool) -> Result<(), Self::Error>;

    /// `visit_isize` serializes a `isize` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i8` serializes a `i8` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i16` serializes a `i16` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i32` serializes a `i32` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i64` serializes a `i64` value.
    #[inline]
    fn visit_i64(&mut self, v: i64) -> Result<(), Self::Error>;

    /// `visit_usize` serializes a `usize` value. By default it casts the value to a `u64` and
    /// passes it to the `visit_u64` method.
    #[inline]
    fn visit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u8` serializes a `u8` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u32` serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u32` serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u64` serializes a `u64` value.
    #[inline]
    fn visit_u64(&mut self, v: u64) -> Result<(), Self::Error>;

    /// `visit_f32` serializes a `f32` value. By default it casts the value to a `f64` and passes
    /// it to the `visit_f64` method.
    #[inline]
    fn visit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.visit_f64(v as f64)
    }

    /// `visit_f64` serializes a `f64` value.
    fn visit_f64(&mut self, v: f64) -> Result<(), Self::Error>;

    /// `visit_char` serializes a character. By default it serializes it as a `&str` containing a
    /// single character.
    #[inline]
    fn visit_char(&mut self, v: char) -> Result<(), Self::Error> {
        // FIXME: this allocation is required in order to be compatible with stable rust, which
        // doesn't support encoding a `char` into a stack buffer.
        self.visit_str(&v.to_string())
    }

    /// `visit_str` serializes a `&str`.
    fn visit_str(&mut self, value: &str) -> Result<(), Self::Error>;

    /// `visit_bytes` is a hook that enables those serialization formats that support serializing
    /// byte slices separately from generic arrays. By default it serializes as a regular array.
    #[inline]
    fn visit_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
        self.visit_seq(impls::SeqIteratorVisitor::new(value.iter(), Some(value.len())))
    }

    fn visit_unit(&mut self) -> Result<(), Self::Error>;

    #[inline]
    fn visit_unit_struct(&mut self, _name: &'static str) -> Result<(), Self::Error> {
        self.visit_unit()
    }

    #[inline]
    fn visit_unit_variant(&mut self,
                          _name: &'static str,
                          _variant_index: usize,
                          _variant: &'static str) -> Result<(), Self::Error> {
        self.visit_unit()
    }

    /// The `visit_newtype_struct` allows a tuple struct with a single element, also known as a
    /// newtyped value, to be more efficiently serialized than a tuple struct with multiple items.
    /// By default it just serializes the value as a tuple struct sequence.
    #[inline]
    fn visit_newtype_struct<T>(&mut self,
                               name: &'static str,
                               value: T) -> Result<(), Self::Error>
        where T: Serialize,
    {
        self.visit_tuple_struct(name, Some(value))
    }

    /// The `visit_newtype_variant` allows a variant with a single item to be more efficiently
    /// serialized than a variant with multiple items. By default it just serializes the value as a
    /// tuple variant sequence.
    #[inline]
    fn visit_newtype_variant<T>(&mut self,
                                name: &'static str,
                                variant_index: usize,
                                variant: &'static str,
                                value: T) -> Result<(), Self::Error>
        where T: Serialize,
    {
        self.visit_tuple_variant(
            name,
            variant_index,
            variant,
            Some(value))
    }

    fn visit_none(&mut self) -> Result<(), Self::Error>;

    fn visit_some<V>(&mut self, value: V) -> Result<(), Self::Error>
        where V: Serialize;

    fn visit_seq<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor;

    fn visit_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize;

    #[inline]
    fn visit_tuple<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_seq(visitor)
    }

    #[inline]
    fn visit_tuple_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_seq_elt(value)
    }

    #[inline]
    fn visit_tuple_struct<V>(&mut self,
                             _name: &'static str,
                             visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_tuple(visitor)
    }

    #[inline]
    fn visit_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_tuple_elt(value)
    }

    #[inline]
    fn visit_tuple_variant<V>(&mut self,
                              _name: &'static str,
                              _variant_index: usize,
                              variant: &'static str,
                              visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_tuple_struct(variant, visitor)
    }

    #[inline]
    fn visit_tuple_variant_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_tuple_struct_elt(value)
    }

    fn visit_map<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor;

    fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize;

    #[inline]
    fn visit_struct<V>(&mut self,
                       _name: &'static str,
                       visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor,
    {
        self.visit_map(visitor)
    }

    #[inline]
    fn visit_struct_elt<K, V>(&mut self,
                              key: K,
                              value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize,
    {
        self.visit_map_elt(key, value)
    }

    #[inline]
    fn visit_struct_variant<V>(&mut self,
                               _name: &'static str,
                               _variant_index: usize,
                               variant: &'static str,
                               visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor,
    {
        self.visit_struct(variant, visitor)
    }

    #[inline]
    fn visit_struct_variant_elt<K, V>(&mut self,
                                      key: K,
                                      value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize,
    {
        self.visit_struct_elt(key, value)
    }

    /// Specify a format string for the serializer.
    ///
    /// The serializer format is used to determine which format
    /// specific field attributes should be used with the serializer.
    fn format() -> &'static str {
        ""
    }
}

pub trait SeqVisitor {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer;

    /// Return the length of the sequence if known.
    #[inline]
    fn len(&self) -> Option<usize> {
        None
    }
}

pub trait MapVisitor {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer;

    /// Return the length of the map if known.
    #[inline]
    fn len(&self) -> Option<usize> {
        None
    }
}
<commit_msg>Explicitly make the visit_struct_{,variant}_elt key a `&'static str`<commit_after>//! Generic serialization framework.

pub mod impls;

///////////////////////////////////////////////////////////////////////////////

pub trait Serialize {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer;
}

///////////////////////////////////////////////////////////////////////////////

pub trait Serializer {
    type Error;

    /// `visit_bool` serializes a `bool` value.
    fn visit_bool(&mut self, v: bool) -> Result<(), Self::Error>;

    /// `visit_isize` serializes a `isize` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i8` serializes a `i8` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i16` serializes a `i16` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i32` serializes a `i32` value. By default it casts the value to a `i64` and
    /// passes it to the `visit_i64` method.
    #[inline]
    fn visit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.visit_i64(v as i64)
    }

    /// `visit_i64` serializes a `i64` value.
    #[inline]
    fn visit_i64(&mut self, v: i64) -> Result<(), Self::Error>;

    /// `visit_usize` serializes a `usize` value. By default it casts the value to a `u64` and
    /// passes it to the `visit_u64` method.
    #[inline]
    fn visit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u8` serializes a `u8` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u32` serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u32` serializes a `u32` value. By default it casts the value to a `u64` and passes
    /// it to the `visit_u64` method.
    #[inline]
    fn visit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        self.visit_u64(v as u64)
    }

    /// `visit_u64` serializes a `u64` value.
    #[inline]
    fn visit_u64(&mut self, v: u64) -> Result<(), Self::Error>;

    /// `visit_f32` serializes a `f32` value. By default it casts the value to a `f64` and passes
    /// it to the `visit_f64` method.
    #[inline]
    fn visit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.visit_f64(v as f64)
    }

    /// `visit_f64` serializes a `f64` value.
    fn visit_f64(&mut self, v: f64) -> Result<(), Self::Error>;

    /// `visit_char` serializes a character. By default it serializes it as a `&str` containing a
    /// single character.
    #[inline]
    fn visit_char(&mut self, v: char) -> Result<(), Self::Error> {
        // FIXME: this allocation is required in order to be compatible with stable rust, which
        // doesn't support encoding a `char` into a stack buffer.
        self.visit_str(&v.to_string())
    }

    /// `visit_str` serializes a `&str`.
    fn visit_str(&mut self, value: &str) -> Result<(), Self::Error>;

    /// `visit_bytes` is a hook that enables those serialization formats that support serializing
    /// byte slices separately from generic arrays. By default it serializes as a regular array.
    #[inline]
    fn visit_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
        self.visit_seq(impls::SeqIteratorVisitor::new(value.iter(), Some(value.len())))
    }

    fn visit_unit(&mut self) -> Result<(), Self::Error>;

    #[inline]
    fn visit_unit_struct(&mut self, _name: &'static str) -> Result<(), Self::Error> {
        self.visit_unit()
    }

    #[inline]
    fn visit_unit_variant(&mut self,
                          _name: &'static str,
                          _variant_index: usize,
                          _variant: &'static str) -> Result<(), Self::Error> {
        self.visit_unit()
    }

    /// The `visit_newtype_struct` allows a tuple struct with a single element, also known as a
    /// newtyped value, to be more efficiently serialized than a tuple struct with multiple items.
    /// By default it just serializes the value as a tuple struct sequence.
    #[inline]
    fn visit_newtype_struct<T>(&mut self,
                               name: &'static str,
                               value: T) -> Result<(), Self::Error>
        where T: Serialize,
    {
        self.visit_tuple_struct(name, Some(value))
    }

    /// The `visit_newtype_variant` allows a variant with a single item to be more efficiently
    /// serialized than a variant with multiple items. By default it just serializes the value as a
    /// tuple variant sequence.
    #[inline]
    fn visit_newtype_variant<T>(&mut self,
                                name: &'static str,
                                variant_index: usize,
                                variant: &'static str,
                                value: T) -> Result<(), Self::Error>
        where T: Serialize,
    {
        self.visit_tuple_variant(
            name,
            variant_index,
            variant,
            Some(value))
    }

    fn visit_none(&mut self) -> Result<(), Self::Error>;

    fn visit_some<V>(&mut self, value: V) -> Result<(), Self::Error>
        where V: Serialize;

    fn visit_seq<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor;

    fn visit_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize;

    #[inline]
    fn visit_tuple<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_seq(visitor)
    }

    #[inline]
    fn visit_tuple_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_seq_elt(value)
    }

    #[inline]
    fn visit_tuple_struct<V>(&mut self,
                             _name: &'static str,
                             visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_tuple(visitor)
    }

    #[inline]
    fn visit_tuple_struct_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_tuple_elt(value)
    }

    #[inline]
    fn visit_tuple_variant<V>(&mut self,
                              _name: &'static str,
                              _variant_index: usize,
                              variant: &'static str,
                              visitor: V) -> Result<(), Self::Error>
        where V: SeqVisitor,
    {
        self.visit_tuple_struct(variant, visitor)
    }

    #[inline]
    fn visit_tuple_variant_elt<T>(&mut self, value: T) -> Result<(), Self::Error>
        where T: Serialize
    {
        self.visit_tuple_struct_elt(value)
    }

    fn visit_map<V>(&mut self, visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor;

    fn visit_map_elt<K, V>(&mut self, key: K, value: V) -> Result<(), Self::Error>
        where K: Serialize,
              V: Serialize;

    #[inline]
    fn visit_struct<V>(&mut self,
                       _name: &'static str,
                       visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor,
    {
        self.visit_map(visitor)
    }

    #[inline]
    fn visit_struct_elt<V>(&mut self,
                           key: &'static str,
                           value: V) -> Result<(), Self::Error>
        where V: Serialize,
    {
        self.visit_map_elt(key, value)
    }

    #[inline]
    fn visit_struct_variant<V>(&mut self,
                               _name: &'static str,
                               _variant_index: usize,
                               variant: &'static str,
                               visitor: V) -> Result<(), Self::Error>
        where V: MapVisitor,
    {
        self.visit_struct(variant, visitor)
    }

    #[inline]
    fn visit_struct_variant_elt<V>(&mut self,
                                   key: &'static str,
                                   value: V) -> Result<(), Self::Error>
        where V: Serialize,
    {
        self.visit_struct_elt(key, value)
    }

    /// Specify a format string for the serializer.
    ///
    /// The serializer format is used to determine which format
    /// specific field attributes should be used with the serializer.
    fn format() -> &'static str {
        ""
    }
}

pub trait SeqVisitor {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer;

    /// Return the length of the sequence if known.
    #[inline]
    fn len(&self) -> Option<usize> {
        None
    }
}

pub trait MapVisitor {
    fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer;

    /// Return the length of the map if known.
    #[inline]
    fn len(&self) -> Option<usize> {
        None
    }
}
<|endoftext|>


<commit_before>extern mod std;

use std::run;
use std::str;
use std::option::*;
use std::trie::*;

fn session_is_attached(line: &str) -> bool {
    line.ends_with("(attached)")
}

fn session_number(line: &str) -> Option<uint> {
    line.split_iter(':').next().and_then(|s| from_str(s))
}

fn detached_sessions(output: ~str) -> TrieSet {
    let mut set = TrieSet::new();
    for line in output.line_iter(){
        if !session_is_attached(line) {
            match session_number(line) {
                Some(n) => { set.insert(n); }
                None => ()
            }
        }
    }
    set
}

fn main() {
    let proc = run::process_output("tmux", &[~"list-sessions"]);
    if proc.status != 0 {
        fail!(fmt!("Tmux exited with an error status: %d", proc.status));
    }
    let output = str::from_utf8(proc.output);
    let sessions = detached_sessions(output);
    match sessions.iter().next() {
        Some(n) => { println(fmt!("Can attach to %u", n)); }
        _ => { println("Have no sessions to attach to"); }
    }
}

#[test]
fn test_session_is_attached() {
    assert!(session_is_attached("11: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)"));
    assert!(!session_is_attached("20: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65]"));
}

#[test]
fn test_session_number_with_numbers(){
    match(session_number("11: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)")) {
        Some(11) => (),
        Some(n) => fail!(fmt!("Should have returned 11, got %u!", n)),
        None => fail!("Should have returned something, got nothing"),
    }
}

#[test]
fn test_session_number_with_strings(){
    match(session_number("oink: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)")) {
        Some(n) => fail!(fmt!("Should have returned None, got %u!", n)),
        None => ()
    }
}

#[test]
fn test_detached_sessions() {
    let set = detached_sessions(~"3: foo (attached)\n2: bar\n4: abz (attached)\nfoo: baz");
    assert!(!set.contains(&2));
    assert!(set.contains(&3));
    assert!(set.contains(&4));
    assert!(!set.contains(&1));
}
<commit_msg>Fix the test.<commit_after>extern mod std;

use std::run;
use std::str;
use std::option::*;
use std::trie::*;

fn session_is_attached(line: &str) -> bool {
    line.ends_with("(attached)")
}

fn session_number(line: &str) -> Option<uint> {
    line.split_iter(':').next().and_then(|s| from_str(s))
}

fn detached_sessions(output: ~str) -> TrieSet {
    let mut set = TrieSet::new();
    for line in output.line_iter(){
        if !session_is_attached(line) {
            match session_number(line) {
                Some(n) => { set.insert(n); }
                None => ()
            }
        }
    }
    set
}

fn main() {
    let proc = run::process_output("tmux", &[~"list-sessions"]);
    if proc.status != 0 {
        fail!(fmt!("Tmux exited with an error status: %d", proc.status));
    }
    let output = str::from_utf8(proc.output);
    let sessions = detached_sessions(output);
    match sessions.iter().next() {
        Some(n) => { println(fmt!("Can attach to %u", n)); }
        _ => { println("Have no sessions to attach to"); }
    }
}

#[test]
fn test_session_is_attached() {
    assert!(session_is_attached("11: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)"));
    assert!(!session_is_attached("20: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65]"));
}

#[test]
fn test_session_number_with_numbers(){
    match(session_number("11: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)")) {
        Some(11) => (),
        Some(n) => fail!(fmt!("Should have returned 11, got %u!", n)),
        None => fail!("Should have returned something, got nothing"),
    }
}

#[test]
fn test_session_number_with_strings(){
    match(session_number("oink: 1 windows (created Sat Sep 14 17:11:29 2013) [130x65] (attached)")) {
        Some(n) => fail!(fmt!("Should have returned None, got %u!", n)),
        None => ()
    }
}

#[test]
fn test_detached_sessions() {
    let set = detached_sessions(~"3: foo (attached)\n2: bar\n4: abz (attached)\nfoo: baz");
    assert!(set.contains(&2));

    // attached sessions:
    assert!(!set.contains(&3));
    assert!(!set.contains(&4));

    // missing session:
    assert!(!set.contains(&1));
}
<|endoftext|>