<commit_before>use crate::common::util::*;
use rust_users::*;
use std::os::unix::fs::PermissionsExt;

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

    assert!(ucmd
        .arg("--help")
        .succeeds()
        .no_stderr()
        .stdout
        .contains("FLAGS:"));
}

#[test]
fn test_install_basic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_a";
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    at.touch(file2);
    at.mkdir(dir);
    ucmd.arg(file1).arg(file2).arg(dir).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
    assert!(at.file_exists(&format!("{}/{}", dir, file1)));
    assert!(at.file_exists(&format!("{}/{}", dir, file2)));
}

#[test]
fn test_install_twice_dir() {
    let dir = "test_install_target_dir_dir_a";
    let scene = TestScenario::new(util_name!());

    scene.ucmd().arg("-d").arg(dir).succeeds();
    scene.ucmd().arg("-d").arg(dir).succeeds();
    let at = &scene.fixtures;

    assert!(at.dir_exists(dir));
}

#[test]
fn test_install_failing_not_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";
    let file3 = "test_install_target_dir_file_a3";

    at.touch(file1);
    at.touch(file2);
    at.touch(file3);
    assert!(ucmd
        .arg(file1)
        .arg(file2)
        .arg(file3)
        .fails()
        .stderr
        .contains("not a directory"));
}

#[test]
fn test_install_unimplemented_arg() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_b";
    let file = "test_install_target_dir_file_b";
    let context_arg = "--context";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd
        .arg(context_arg)
        .arg(file)
        .arg(dir)
        .fails()
        .stderr
        .contains("Unimplemented"));

    assert!(!at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_component_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component1 = "test_install_target_dir_component_c1";
    let component2 = "test_install_target_dir_component_c2";
    let component3 = "test_install_target_dir_component_c3";
    let directories_arg = "-d";

    ucmd.args(&[directories_arg, component1, component2, component3])
        .succeeds()
        .no_stderr();

    assert!(at.dir_exists(component1));
    assert!(at.dir_exists(component2));
    assert!(at.dir_exists(component3));
}

#[test]
fn test_install_mode_numeric() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    let dir = "test_install_target_dir_dir_e";
    let dir2 = "test_install_target_dir_dir_e2";

    let file = "test_install_target_dir_file_e";
    let mode_arg = "--mode=333";

    at.touch(file);
    at.mkdir(dir);
    scene
        .ucmd()
        .arg(file)
        .arg(dir)
        .arg(mode_arg)
        .succeeds()
        .no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));

    let mode_arg = "-m 0333";
    at.mkdir(dir2);

    let result = scene.ucmd().arg(mode_arg).arg(file).arg(dir2).run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    assert!(result.success);
    let dest_file = &format!("{}/{}", dir2, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_symbolic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_f";
    let file = "test_install_target_dir_file_f";
    let mode_arg = "--mode=o+wx";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100003 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_failing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_g";
    let file = "test_install_target_dir_file_g";
    let mode_arg = "--mode=999";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd
        .arg(file)
        .arg(dir)
        .arg(mode_arg)
        .fails()
        .stderr
        .contains("Invalid mode string: invalid digit found in string"));

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(!at.file_exists(dest_file));
}

#[test]
fn test_install_mode_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component = "test_install_target_dir_component_h";
    let directories_arg = "-d";
    let mode_arg = "--mode=333";

    ucmd.arg(directories_arg)
        .arg(component)
        .arg(mode_arg)
        .succeeds()
        .no_stderr();

    assert!(at.dir_exists(component));
    let permissions = at.metadata(component).permissions();
    assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_target_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_file_file_i1";
    let file2 = "test_install_target_file_file_i2";

    at.touch(file1);
    at.touch(file2);
    ucmd.arg(file1).arg(file2).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
}

#[test]
fn test_install_target_new_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file)
        .arg(format!("{}/{}", dir, file))
        .succeeds()
        .no_stderr();

    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_with_group() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";
    let gid = get_effective_gid();

    at.touch(file);
    at.mkdir(dir);
    let result = ucmd
        .arg(file)
        .arg("--group")
        .arg(gid.to_string())
        .arg(format!("{}/{}", dir, file))
        .run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    if is_ci() && result.stderr.contains("error: no such group:") {
        // In the CI, some server are failing to return the group.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_with_owner() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";
    let uid = get_effective_uid();

    at.touch(file);
    at.mkdir(dir);
    let result = ucmd
        .arg(file)
        .arg("--owner")
        .arg(uid.to_string())
        .arg(format!("{}/{}", dir, file))
        .run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    if is_ci() && result.stderr.contains("error: no such user:") {
        // In the CI, some server are failing to return the user id.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_failing_nonexistent_parent() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_new_file_failing_file_k1";
    let file2 = "test_install_target_new_file_failing_file_k2";
    let dir = "test_install_target_new_file_failing_dir_k";

    at.touch(file1);

    let err = ucmd
        .arg(file1)
        .arg(format!("{}/{}", dir, file2))
        .fails()
        .stderr;

    assert!(err.contains("not a directory"))
}

#[test]
fn test_install_preserve_timestamps() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";
    at.touch(file1);

    ucmd.arg(file1).arg(file2).arg("-p").succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));

    let file1_metadata = at.metadata(file1);
    let file2_metadata = at.metadata(file2);

    assert_eq!(
        file1_metadata.accessed().ok(),
        file2_metadata.accessed().ok()
    );
    assert_eq!(
        file1_metadata.modified().ok(),
        file2_metadata.modified().ok()
    );
}

// These two tests are failing but should work
#[test]
fn test_install_copy_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    ucmd.arg(file1).arg(file2).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
}

#[test]
#[cfg(target_os = "linux")]
fn test_install_target_file_dev_null() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "/dev/null";
    let file2 = "test_install_target_file_file_i2";

    ucmd.arg(file1).arg(file2).succeeds().no_stderr();
    assert!(at.file_exists(file2));
}

#[test]
fn test_install_copy_file_leading_dot() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir1 = "test_install_target_new_file_dir_l";
    let dir2 = "test_install_target_new_file_dir_m";
    let file1 = "test_install_target_file_file_l1";

    at.mkdir(dir1);
    at.mkdir(dir2);
    at.touch(&format!("{}/{}", dir1, file1));

    ucmd.arg(format!("{}/{}", dir1, file1)).arg(dir2).succeeds().no_stderr();
    assert!(at.file_exists(&format!("{}/{}", dir2, file1)));
}
<commit_msg>install: rustfmt test<commit_after>use crate::common::util::*;
use rust_users::*;
use std::os::unix::fs::PermissionsExt;

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

    assert!(ucmd
        .arg("--help")
        .succeeds()
        .no_stderr()
        .stdout
        .contains("FLAGS:"));
}

#[test]
fn test_install_basic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_a";
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    at.touch(file2);
    at.mkdir(dir);
    ucmd.arg(file1).arg(file2).arg(dir).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
    assert!(at.file_exists(&format!("{}/{}", dir, file1)));
    assert!(at.file_exists(&format!("{}/{}", dir, file2)));
}

#[test]
fn test_install_twice_dir() {
    let dir = "test_install_target_dir_dir_a";
    let scene = TestScenario::new(util_name!());

    scene.ucmd().arg("-d").arg(dir).succeeds();
    scene.ucmd().arg("-d").arg(dir).succeeds();
    let at = &scene.fixtures;

    assert!(at.dir_exists(dir));
}

#[test]
fn test_install_failing_not_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";
    let file3 = "test_install_target_dir_file_a3";

    at.touch(file1);
    at.touch(file2);
    at.touch(file3);
    assert!(ucmd
        .arg(file1)
        .arg(file2)
        .arg(file3)
        .fails()
        .stderr
        .contains("not a directory"));
}

#[test]
fn test_install_unimplemented_arg() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_b";
    let file = "test_install_target_dir_file_b";
    let context_arg = "--context";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd
        .arg(context_arg)
        .arg(file)
        .arg(dir)
        .fails()
        .stderr
        .contains("Unimplemented"));

    assert!(!at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_component_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component1 = "test_install_target_dir_component_c1";
    let component2 = "test_install_target_dir_component_c2";
    let component3 = "test_install_target_dir_component_c3";
    let directories_arg = "-d";

    ucmd.args(&[directories_arg, component1, component2, component3])
        .succeeds()
        .no_stderr();

    assert!(at.dir_exists(component1));
    assert!(at.dir_exists(component2));
    assert!(at.dir_exists(component3));
}

#[test]
fn test_install_mode_numeric() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    let dir = "test_install_target_dir_dir_e";
    let dir2 = "test_install_target_dir_dir_e2";

    let file = "test_install_target_dir_file_e";
    let mode_arg = "--mode=333";

    at.touch(file);
    at.mkdir(dir);
    scene
        .ucmd()
        .arg(file)
        .arg(dir)
        .arg(mode_arg)
        .succeeds()
        .no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));

    let mode_arg = "-m 0333";
    at.mkdir(dir2);

    let result = scene.ucmd().arg(mode_arg).arg(file).arg(dir2).run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    assert!(result.success);
    let dest_file = &format!("{}/{}", dir2, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_symbolic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_f";
    let file = "test_install_target_dir_file_f";
    let mode_arg = "--mode=o+wx";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100003 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_failing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_g";
    let file = "test_install_target_dir_file_g";
    let mode_arg = "--mode=999";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd
        .arg(file)
        .arg(dir)
        .arg(mode_arg)
        .fails()
        .stderr
        .contains("Invalid mode string: invalid digit found in string"));

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(!at.file_exists(dest_file));
}

#[test]
fn test_install_mode_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component = "test_install_target_dir_component_h";
    let directories_arg = "-d";
    let mode_arg = "--mode=333";

    ucmd.arg(directories_arg)
        .arg(component)
        .arg(mode_arg)
        .succeeds()
        .no_stderr();

    assert!(at.dir_exists(component));
    let permissions = at.metadata(component).permissions();
    assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_target_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_file_file_i1";
    let file2 = "test_install_target_file_file_i2";

    at.touch(file1);
    at.touch(file2);
    ucmd.arg(file1).arg(file2).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
}

#[test]
fn test_install_target_new_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file)
        .arg(format!("{}/{}", dir, file))
        .succeeds()
        .no_stderr();

    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_with_group() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";
    let gid = get_effective_gid();

    at.touch(file);
    at.mkdir(dir);
    let result = ucmd
        .arg(file)
        .arg("--group")
        .arg(gid.to_string())
        .arg(format!("{}/{}", dir, file))
        .run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    if is_ci() && result.stderr.contains("error: no such group:") {
        // In the CI, some server are failing to return the group.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_with_owner() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";
    let uid = get_effective_uid();

    at.touch(file);
    at.mkdir(dir);
    let result = ucmd
        .arg(file)
        .arg("--owner")
        .arg(uid.to_string())
        .arg(format!("{}/{}", dir, file))
        .run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    if is_ci() && result.stderr.contains("error: no such user:") {
        // In the CI, some server are failing to return the user id.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_failing_nonexistent_parent() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_new_file_failing_file_k1";
    let file2 = "test_install_target_new_file_failing_file_k2";
    let dir = "test_install_target_new_file_failing_dir_k";

    at.touch(file1);

    let err = ucmd
        .arg(file1)
        .arg(format!("{}/{}", dir, file2))
        .fails()
        .stderr;

    assert!(err.contains("not a directory"))
}

#[test]
fn test_install_preserve_timestamps() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";
    at.touch(file1);

    ucmd.arg(file1).arg(file2).arg("-p").succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));

    let file1_metadata = at.metadata(file1);
    let file2_metadata = at.metadata(file2);

    assert_eq!(
        file1_metadata.accessed().ok(),
        file2_metadata.accessed().ok()
    );
    assert_eq!(
        file1_metadata.modified().ok(),
        file2_metadata.modified().ok()
    );
}

// These two tests are failing but should work
#[test]
fn test_install_copy_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    ucmd.arg(file1).arg(file2).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
}

#[test]
#[cfg(target_os = "linux")]
fn test_install_target_file_dev_null() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "/dev/null";
    let file2 = "test_install_target_file_file_i2";

    ucmd.arg(file1).arg(file2).succeeds().no_stderr();
    assert!(at.file_exists(file2));
}

#[test]
fn test_install_copy_file_leading_dot() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir1 = "test_install_target_new_file_dir_l";
    let dir2 = "test_install_target_new_file_dir_m";
    let file1 = "test_install_target_file_file_l1";

    at.mkdir(dir1);
    at.mkdir(dir2);
    at.touch(&format!("{}/{}", dir1, file1));

    ucmd.arg(format!("{}/{}", dir1, file1))
        .arg(dir2)
        .succeeds()
        .no_stderr();
    assert!(at.file_exists(&format!("{}/{}", dir2, file1)));
}
<|endoftext|>


<commit_before>//! Process resource limit information from `/proc/[pid]/limits`.

use std::fs::File;
use std::io::Result;
use std::str::{self};
use std::time::Duration;

use libc::pid_t;
use nom::{
    IResult,
    space,
};

use parsers::{
    map_result,
    parse_u64,
    parse_usize,
    read_to_end
};

fn parse_limit<'a, P, T>(input: &'a [u8], value_parser: P) -> IResult<&'a [u8], Limit<T>>
where P: Fn(&[u8]) -> IResult<&[u8], T> {
    let parse_field = closure!(&'a [u8], alt!(
         tag!("unlimited") => { |_| None }
       | value_parser => { |value| Some(value) }
    ));

    map!(input, separated_pair!(parse_field, space, parse_field),
         |(soft, hard)| Limit { soft: soft, hard: hard })
}

fn duration_from_micros(micros: u64) -> Duration {
    let micros_per_sec = 1_000_000;
    let nanos_per_micro = 1000;
    let secs = micros / micros_per_sec;
    let nanos = ((micros % micros_per_sec) as u32) * nanos_per_micro;
    Duration::new(secs, nanos)
}

named!(parse_limit_usize( &[u8] ) -> Limit<usize>, apply!(parse_limit, parse_usize));
named!(parse_limit_u64( &[u8] ) -> Limit<u64>, apply!(parse_limit, parse_u64));
named!(parse_limit_seconds( &[u8] ) -> Limit<Duration>,
       map!(apply!(parse_limit, parse_u64),
            | Limit { soft, hard } | {
                Limit {
                    soft: soft.map(Duration::from_secs),
                    hard: hard.map(Duration::from_secs),
                }
            }
       ));
named!(parse_limit_micros( &[u8] ) -> Limit<Duration>,
       map!(apply!(parse_limit, parse_u64),
            | Limit { soft, hard } | {
                Limit {
                    soft: soft.map(duration_from_micros),
                    hard: hard.map(duration_from_micros),
                }
            }
       ));

named!(parse_limits( &[u8] ) -> Limits,
    ws!(do_parse!(
        tag!("Limit") >> tag!("Soft Limit") >> tag!("Hard Limit") >> tag!("Units") >>
        tag!("Max cpu time")          >> max_cpu_time: parse_limit_seconds        >> tag!("seconds")    >>
        tag!("Max file size")         >> max_file_size: parse_limit_u64           >> tag!("bytes")      >>
        tag!("Max data size")         >> max_data_size: parse_limit_usize         >> tag!("bytes")      >>
        tag!("Max stack size")        >> max_stack_size: parse_limit_usize        >> tag!("bytes")      >>
        tag!("Max core file size")    >> max_core_file_size: parse_limit_usize    >> tag!("bytes")      >>
        tag!("Max resident set")      >> max_resident_set: parse_limit_usize      >> tag!("bytes")      >>
        tag!("Max processes")         >> max_processes: parse_limit_usize         >> tag!("processes")  >>
        tag!("Max open files")        >> max_open_files: parse_limit_usize        >> tag!("files")      >>
        tag!("Max locked memory")     >> max_locked_memory: parse_limit_usize     >> tag!("bytes")      >>
        tag!("Max address space")     >> max_address_space: parse_limit_usize     >> tag!("bytes")      >>
        tag!("Max file locks")        >> max_file_locks: parse_limit_usize        >> tag!("locks")      >>
        tag!("Max pending signals")   >> max_pending_signals: parse_limit_usize   >> tag!("signals")    >>
        tag!("Max msgqueue size")     >> max_msgqueue_size: parse_limit_usize     >> tag!("bytes")      >>
        tag!("Max nice priority")     >> max_nice_priority: parse_limit_usize     >>
        tag!("Max realtime priority") >> max_realtime_priority: parse_limit_usize >>
        tag!("Max realtime timeout")  >> max_realtime_timeout: parse_limit_micros >> tag!("us")         >>
        (Limits {
            max_cpu_time: max_cpu_time,
            max_file_size: max_file_size,
            max_data_size: max_data_size,
            max_stack_size: max_stack_size,
            max_core_file_size: max_core_file_size,
            max_resident_set: max_resident_set,
            max_processes: max_processes,
            max_open_files: max_open_files,
            max_locked_memory: max_locked_memory,
            max_address_space: max_address_space,
            max_file_locks: max_file_locks,
            max_pending_signals: max_pending_signals,
            max_msgqueue_size: max_msgqueue_size,
            max_nice_priority: max_nice_priority,
            max_realtime_priority: max_realtime_priority,
            max_realtime_timeout: max_realtime_timeout,
        })
    ))
);

/// A resource limit, including a soft and hard bound.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Limit<T> {
    /// The soft resource limit.
    ///
    /// The kernel enforces that resource usage does not exceed this value.
    soft: Option<T>,

    /// The hard resource limit.
    ///
    /// The kernel allows the soft limit to be raised until this limit using
    /// `setrlimit`.
    hard: Option<T>,
}

/// Process limits information
/// See `man 2 getrlimit`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Limits {
    /// The maximum CPU time a process can use.
    pub max_cpu_time: Limit<Duration>,
    /// The maximum size of files that the process may create in bytes.
    pub max_file_size: Limit<u64>,
    /// The maximum size of the process's data segment in bytes.
    pub max_data_size: Limit<usize>,
    /// The maximum size of the process stack in bytes.
    pub max_stack_size: Limit<usize>,
    /// Maximum size of a core file in bytes.
    pub max_core_file_size: Limit<usize>,
    /// Specifies the limit of the process's resident set in bytes.
    pub max_resident_set: Limit<usize>,
    /// The maximum number of processes (or, more precisely on Linux, threads)
    /// that can be created for the real user ID of the calling process.
    pub max_processes: Limit<usize>,
    /// Specifies a value one greater than the maximum file descriptor
    /// number that can be opened by this process.
    pub max_open_files: Limit<usize>,
    /// The maximum number of bytes of memory that may be locked into RAM.
    pub max_locked_memory: Limit<usize>,
    /// The maximum size of the process's virtual memory (address space) in bytes.
    pub max_address_space: Limit<usize>,
    /// A limit on the combined number of locks and leases that this process may
    /// establish.
    pub max_file_locks: Limit<usize>,
    /// Specifies the limit on the number of signals that may be queued for the
    /// real user ID of the calling process.
    pub max_pending_signals: Limit<usize>,
    /// Specifies the limit on the number of bytes that can be allocated for
    /// POSIX message queues for the real user ID of the calling process.
    pub max_msgqueue_size: Limit<usize>,
    /// Specifies a ceiling to which the process's nice value can be raised.
    pub max_nice_priority: Limit<usize>,
    /// Specifies a limit on the amount of CPU time that a process scheduled
    /// under a real-time scheduling policy may consume without making a blocking
    /// system call.
    pub max_realtime_priority: Limit<usize>,
    /// Specifies a ceiling on the real-time priority that may be set for this process.
    pub max_realtime_timeout: Limit<Duration>,
}

fn limits_file(file: &mut File) -> Result<Limits> {
    let mut buf = [0; 2048]; // A typical limits file is about 1350 bytes
    map_result(parse_limits(try!(read_to_end(file, &mut buf))))
}

/// Returns resource limit information from the process with the provided pid.
pub fn limits(pid: pid_t) -> Result<Limits> {
    limits_file(&mut try!(File::open(&format!("/proc/{}/limits", pid))))
}

/// Returns resource limit information for the current process.
pub fn limits_self() -> Result<Limits> {
    limits_file(&mut try!(File::open("/proc/self/limits")))
}

#[cfg(test)]
pub mod tests {

    use std::time::Duration;

    use parsers::tests::unwrap;
    use super::{limits, limits_self, parse_limits};

    /// Test that the system limit file can be parsed.
    #[test]
    fn test_limits() {
        limits_self().unwrap();
        limits(1).unwrap();
    }

    #[test]
    fn test_parse_limits() {
        let text = b"Limit                     Soft Limit           Hard Limit           Units         \n
                     Max cpu time              10                   60                   seconds       \n
                     Max file size             unlimited            unlimited            bytes         \n
                     Max data size             unlimited            unlimited            bytes         \n
                     Max stack size            8388608              unlimited            bytes         \n
                     Max core file size        unlimited            unlimited            bytes         \n
                     Max resident set          unlimited            unlimited            bytes         \n
                     Max processes             63632                63632                processes     \n
                     Max open files            1024                 4096                 files         \n
                     Max locked memory         65536                65536                bytes         \n
                     Max address space         unlimited            unlimited            bytes         \n
                     Max file locks            unlimited            unlimited            locks         \n
                     Max pending signals       63632                63632                signals       \n
                     Max msgqueue size         819200               819200               bytes         \n
                     Max nice priority         0                    0                                  \n
                     Max realtime priority     0                    0                                  \n
                     Max realtime timeout      500                  unlimited            us            \n";

        let limits = unwrap(parse_limits(text));

        assert_eq!(Some(Duration::new(10, 0)), limits.max_cpu_time.soft);
        assert_eq!(Some(Duration::new(60, 0)), limits.max_cpu_time.hard);

        assert_eq!(None, limits.max_file_size.soft);
        assert_eq!(None, limits.max_file_size.hard);

        assert_eq!(None, limits.max_data_size.soft);
        assert_eq!(None, limits.max_data_size.hard);

        assert_eq!(Some(8388608), limits.max_stack_size.soft);
        assert_eq!(None, limits.max_stack_size.hard);

        assert_eq!(None, limits.max_core_file_size.soft);
        assert_eq!(None, limits.max_core_file_size.hard);

        assert_eq!(None, limits.max_resident_set.soft);
        assert_eq!(None, limits.max_resident_set.hard);

        assert_eq!(Some(63632), limits.max_processes.soft);
        assert_eq!(Some(63632), limits.max_processes.hard);

        assert_eq!(Some(1024), limits.max_open_files.soft);
        assert_eq!(Some(4096), limits.max_open_files.hard);

        assert_eq!(Some(65536), limits.max_locked_memory.soft);
        assert_eq!(Some(65536), limits.max_locked_memory.hard);

        assert_eq!(None, limits.max_address_space.soft);
        assert_eq!(None, limits.max_address_space.hard);

        assert_eq!(None, limits.max_file_locks.soft);
        assert_eq!(None, limits.max_file_locks.hard);

        assert_eq!(Some(63632), limits.max_pending_signals.soft);
        assert_eq!(Some(63632), limits.max_pending_signals.hard);

        assert_eq!(Some(819200), limits.max_msgqueue_size.soft);
        assert_eq!(Some(819200), limits.max_msgqueue_size.hard);

        assert_eq!(Some(0), limits.max_nice_priority.soft);
        assert_eq!(Some(0), limits.max_nice_priority.hard);

        assert_eq!(Some(0), limits.max_realtime_priority.soft);
        assert_eq!(Some(0), limits.max_realtime_priority.hard);

        assert_eq!(Some(Duration::new(0, 500 * 1000)), limits.max_realtime_timeout.soft);
        assert_eq!(None, limits.max_realtime_timeout.hard);
    }
}

#[cfg(all(test, rustc_nightly))]
mod benches {
    extern crate test;

    use std::fs::File;

    use parsers::read_to_end;
    use super::*;

    #[bench]
    fn bench_limits(b: &mut test::Bencher) {
        b.iter(|| test::black_box(limits(1)));
    }

    #[bench]
    fn bench_limits_parse(b: &mut test::Bencher) {
        let mut buf = [0; 2048];
        let limits = read_to_end(&mut File::open("/proc/1/limits").unwrap(), &mut buf).unwrap();
        b.iter(|| test::black_box(parse_limits(limits)));
    }
}
<commit_msg>pid::limits::Limit: make fields public (#24)<commit_after>//! Process resource limit information from `/proc/[pid]/limits`.

use std::fs::File;
use std::io::Result;
use std::str::{self};
use std::time::Duration;

use libc::pid_t;
use nom::{
    IResult,
    space,
};

use parsers::{
    map_result,
    parse_u64,
    parse_usize,
    read_to_end
};

fn parse_limit<'a, P, T>(input: &'a [u8], value_parser: P) -> IResult<&'a [u8], Limit<T>>
where P: Fn(&[u8]) -> IResult<&[u8], T> {
    let parse_field = closure!(&'a [u8], alt!(
         tag!("unlimited") => { |_| None }
       | value_parser => { |value| Some(value) }
    ));

    map!(input, separated_pair!(parse_field, space, parse_field),
         |(soft, hard)| Limit { soft: soft, hard: hard })
}

fn duration_from_micros(micros: u64) -> Duration {
    let micros_per_sec = 1_000_000;
    let nanos_per_micro = 1000;
    let secs = micros / micros_per_sec;
    let nanos = ((micros % micros_per_sec) as u32) * nanos_per_micro;
    Duration::new(secs, nanos)
}

named!(parse_limit_usize( &[u8] ) -> Limit<usize>, apply!(parse_limit, parse_usize));
named!(parse_limit_u64( &[u8] ) -> Limit<u64>, apply!(parse_limit, parse_u64));
named!(parse_limit_seconds( &[u8] ) -> Limit<Duration>,
       map!(apply!(parse_limit, parse_u64),
            | Limit { soft, hard } | {
                Limit {
                    soft: soft.map(Duration::from_secs),
                    hard: hard.map(Duration::from_secs),
                }
            }
       ));
named!(parse_limit_micros( &[u8] ) -> Limit<Duration>,
       map!(apply!(parse_limit, parse_u64),
            | Limit { soft, hard } | {
                Limit {
                    soft: soft.map(duration_from_micros),
                    hard: hard.map(duration_from_micros),
                }
            }
       ));

named!(parse_limits( &[u8] ) -> Limits,
    ws!(do_parse!(
        tag!("Limit") >> tag!("Soft Limit") >> tag!("Hard Limit") >> tag!("Units") >>
        tag!("Max cpu time")          >> max_cpu_time: parse_limit_seconds        >> tag!("seconds")    >>
        tag!("Max file size")         >> max_file_size: parse_limit_u64           >> tag!("bytes")      >>
        tag!("Max data size")         >> max_data_size: parse_limit_usize         >> tag!("bytes")      >>
        tag!("Max stack size")        >> max_stack_size: parse_limit_usize        >> tag!("bytes")      >>
        tag!("Max core file size")    >> max_core_file_size: parse_limit_usize    >> tag!("bytes")      >>
        tag!("Max resident set")      >> max_resident_set: parse_limit_usize      >> tag!("bytes")      >>
        tag!("Max processes")         >> max_processes: parse_limit_usize         >> tag!("processes")  >>
        tag!("Max open files")        >> max_open_files: parse_limit_usize        >> tag!("files")      >>
        tag!("Max locked memory")     >> max_locked_memory: parse_limit_usize     >> tag!("bytes")      >>
        tag!("Max address space")     >> max_address_space: parse_limit_usize     >> tag!("bytes")      >>
        tag!("Max file locks")        >> max_file_locks: parse_limit_usize        >> tag!("locks")      >>
        tag!("Max pending signals")   >> max_pending_signals: parse_limit_usize   >> tag!("signals")    >>
        tag!("Max msgqueue size")     >> max_msgqueue_size: parse_limit_usize     >> tag!("bytes")      >>
        tag!("Max nice priority")     >> max_nice_priority: parse_limit_usize     >>
        tag!("Max realtime priority") >> max_realtime_priority: parse_limit_usize >>
        tag!("Max realtime timeout")  >> max_realtime_timeout: parse_limit_micros >> tag!("us")         >>
        (Limits {
            max_cpu_time: max_cpu_time,
            max_file_size: max_file_size,
            max_data_size: max_data_size,
            max_stack_size: max_stack_size,
            max_core_file_size: max_core_file_size,
            max_resident_set: max_resident_set,
            max_processes: max_processes,
            max_open_files: max_open_files,
            max_locked_memory: max_locked_memory,
            max_address_space: max_address_space,
            max_file_locks: max_file_locks,
            max_pending_signals: max_pending_signals,
            max_msgqueue_size: max_msgqueue_size,
            max_nice_priority: max_nice_priority,
            max_realtime_priority: max_realtime_priority,
            max_realtime_timeout: max_realtime_timeout,
        })
    ))
);

/// A resource limit, including a soft and hard bound.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Limit<T> {
    /// The soft resource limit.
    ///
    /// The kernel enforces that resource usage does not exceed this value.
    pub soft: Option<T>,

    /// The hard resource limit.
    ///
    /// The kernel allows the soft limit to be raised until this limit using
    /// `setrlimit`.
    pub hard: Option<T>,
}

/// Process limits information
/// See `man 2 getrlimit`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Limits {
    /// The maximum CPU time a process can use.
    pub max_cpu_time: Limit<Duration>,
    /// The maximum size of files that the process may create in bytes.
    pub max_file_size: Limit<u64>,
    /// The maximum size of the process's data segment in bytes.
    pub max_data_size: Limit<usize>,
    /// The maximum size of the process stack in bytes.
    pub max_stack_size: Limit<usize>,
    /// Maximum size of a core file in bytes.
    pub max_core_file_size: Limit<usize>,
    /// Specifies the limit of the process's resident set in bytes.
    pub max_resident_set: Limit<usize>,
    /// The maximum number of processes (or, more precisely on Linux, threads)
    /// that can be created for the real user ID of the calling process.
    pub max_processes: Limit<usize>,
    /// Specifies a value one greater than the maximum file descriptor
    /// number that can be opened by this process.
    pub max_open_files: Limit<usize>,
    /// The maximum number of bytes of memory that may be locked into RAM.
    pub max_locked_memory: Limit<usize>,
    /// The maximum size of the process's virtual memory (address space) in bytes.
    pub max_address_space: Limit<usize>,
    /// A limit on the combined number of locks and leases that this process may
    /// establish.
    pub max_file_locks: Limit<usize>,
    /// Specifies the limit on the number of signals that may be queued for the
    /// real user ID of the calling process.
    pub max_pending_signals: Limit<usize>,
    /// Specifies the limit on the number of bytes that can be allocated for
    /// POSIX message queues for the real user ID of the calling process.
    pub max_msgqueue_size: Limit<usize>,
    /// Specifies a ceiling to which the process's nice value can be raised.
    pub max_nice_priority: Limit<usize>,
    /// Specifies a limit on the amount of CPU time that a process scheduled
    /// under a real-time scheduling policy may consume without making a blocking
    /// system call.
    pub max_realtime_priority: Limit<usize>,
    /// Specifies a ceiling on the real-time priority that may be set for this process.
    pub max_realtime_timeout: Limit<Duration>,
}

fn limits_file(file: &mut File) -> Result<Limits> {
    let mut buf = [0; 2048]; // A typical limits file is about 1350 bytes
    map_result(parse_limits(try!(read_to_end(file, &mut buf))))
}

/// Returns resource limit information from the process with the provided pid.
pub fn limits(pid: pid_t) -> Result<Limits> {
    limits_file(&mut try!(File::open(&format!("/proc/{}/limits", pid))))
}

/// Returns resource limit information for the current process.
pub fn limits_self() -> Result<Limits> {
    limits_file(&mut try!(File::open("/proc/self/limits")))
}

#[cfg(test)]
pub mod tests {

    use std::time::Duration;

    use parsers::tests::unwrap;
    use super::{limits, limits_self, parse_limits};

    /// Test that the system limit file can be parsed.
    #[test]
    fn test_limits() {
        limits_self().unwrap();
        limits(1).unwrap();
    }

    #[test]
    fn test_parse_limits() {
        let text = b"Limit                     Soft Limit           Hard Limit           Units         \n
                     Max cpu time              10                   60                   seconds       \n
                     Max file size             unlimited            unlimited            bytes         \n
                     Max data size             unlimited            unlimited            bytes         \n
                     Max stack size            8388608              unlimited            bytes         \n
                     Max core file size        unlimited            unlimited            bytes         \n
                     Max resident set          unlimited            unlimited            bytes         \n
                     Max processes             63632                63632                processes     \n
                     Max open files            1024                 4096                 files         \n
                     Max locked memory         65536                65536                bytes         \n
                     Max address space         unlimited            unlimited            bytes         \n
                     Max file locks            unlimited            unlimited            locks         \n
                     Max pending signals       63632                63632                signals       \n
                     Max msgqueue size         819200               819200               bytes         \n
                     Max nice priority         0                    0                                  \n
                     Max realtime priority     0                    0                                  \n
                     Max realtime timeout      500                  unlimited            us            \n";

        let limits = unwrap(parse_limits(text));

        assert_eq!(Some(Duration::new(10, 0)), limits.max_cpu_time.soft);
        assert_eq!(Some(Duration::new(60, 0)), limits.max_cpu_time.hard);

        assert_eq!(None, limits.max_file_size.soft);
        assert_eq!(None, limits.max_file_size.hard);

        assert_eq!(None, limits.max_data_size.soft);
        assert_eq!(None, limits.max_data_size.hard);

        assert_eq!(Some(8388608), limits.max_stack_size.soft);
        assert_eq!(None, limits.max_stack_size.hard);

        assert_eq!(None, limits.max_core_file_size.soft);
        assert_eq!(None, limits.max_core_file_size.hard);

        assert_eq!(None, limits.max_resident_set.soft);
        assert_eq!(None, limits.max_resident_set.hard);

        assert_eq!(Some(63632), limits.max_processes.soft);
        assert_eq!(Some(63632), limits.max_processes.hard);

        assert_eq!(Some(1024), limits.max_open_files.soft);
        assert_eq!(Some(4096), limits.max_open_files.hard);

        assert_eq!(Some(65536), limits.max_locked_memory.soft);
        assert_eq!(Some(65536), limits.max_locked_memory.hard);

        assert_eq!(None, limits.max_address_space.soft);
        assert_eq!(None, limits.max_address_space.hard);

        assert_eq!(None, limits.max_file_locks.soft);
        assert_eq!(None, limits.max_file_locks.hard);

        assert_eq!(Some(63632), limits.max_pending_signals.soft);
        assert_eq!(Some(63632), limits.max_pending_signals.hard);

        assert_eq!(Some(819200), limits.max_msgqueue_size.soft);
        assert_eq!(Some(819200), limits.max_msgqueue_size.hard);

        assert_eq!(Some(0), limits.max_nice_priority.soft);
        assert_eq!(Some(0), limits.max_nice_priority.hard);

        assert_eq!(Some(0), limits.max_realtime_priority.soft);
        assert_eq!(Some(0), limits.max_realtime_priority.hard);

        assert_eq!(Some(Duration::new(0, 500 * 1000)), limits.max_realtime_timeout.soft);
        assert_eq!(None, limits.max_realtime_timeout.hard);
    }
}

#[cfg(all(test, rustc_nightly))]
mod benches {
    extern crate test;

    use std::fs::File;

    use parsers::read_to_end;
    use super::*;

    #[bench]
    fn bench_limits(b: &mut test::Bencher) {
        b.iter(|| test::black_box(limits(1)));
    }

    #[bench]
    fn bench_limits_parse(b: &mut test::Bencher) {
        let mut buf = [0; 2048];
        let limits = read_to_end(&mut File::open("/proc/1/limits").unwrap(), &mut buf).unwrap();
        b.iter(|| test::black_box(parse_limits(limits)));
    }
}
<|endoftext|>


<commit_before>//! Traits for serializing and deserializing rust types from/to ASN.1.
//!
//! The traits in this module can be used to implement serialization and
//! deserialization for a Rust type from/to ASN.1. For built-in types,
//! this module provides an implementation already. For more complex
//! types (like structs and enumms), macros are provided to generate
//! an implementation for them.
//!
//! # Usage
//! The below example defines a Rust struct, and uses a macro to generate
//! the code required to serialize it to an ASN.1 sequence, or to deserialize
//! an ASN.1 sequence into an instance of the struct.
//!
//! The example then uses the BerSerialize::serialize function to encode
//! the struct to a DER-encoded byte stream.
//!
//!
//! ```
//! #[macro_use] extern crate asn1_cereal; fn main() {
//!   struct ShortSequence {
//!     z: u64,
//!     y: u32,
//!   }
//!
//!   asn1_sequence!(
//!     ShortSequence,
//!     "SHORT_SEQUENCE",
//!     z,
//!     y
//!   );
//!
//!   use asn1_cereal::serial;
//!
//!   let data = ShortSequence{ z: 1, y: 2 };
//!   let mut bytes: Vec<u8> = Vec::new();
//!   BerSerialize::serialize(&data, &mut bytes).unwrap();
//! }
//! ```

#[macro_export]
/// This macro defines the Asn1Info trait for a rust type.
///
/// This information is used to match tag information during deserialization,
/// so it should match the expected values in the ASN.1 stream.
macro_rules! asn1_info {
  ($rs_type:ty, $class:expr, $tagnum:expr, $constructed:expr, $asn1_ty:expr) => (
    impl $crate::Asn1Info for $rs_type {
      fn asn1_tag() -> $crate::tag::Tag {
        $crate::tag::Tag {
          class: ($class as u8).into(),
          tagnum: $tagnum as $crate::tag::TagNum,
          constructed: $constructed,

        }
      }

      fn asn1_type() -> $crate::tag::Type {
        $crate::tag::Type::from($asn1_ty)
      }
    }
  )
}

pub mod traits;
mod prim;

pub mod int;
pub mod str;
pub mod assign;
pub mod choice;
pub mod seq;
pub mod seq_of;
<commit_msg>Fix BerSerialize example<commit_after>//! Traits for serializing and deserializing rust types from/to ASN.1.
//!
//! The traits in this module can be used to implement serialization and
//! deserialization for a Rust type from/to ASN.1. For built-in types,
//! this module provides an implementation already. For more complex
//! types (like structs and enumms), macros are provided to generate
//! an implementation for them.
//!
//! # Usage
//! The below example defines a Rust struct, and uses a macro to generate
//! the code required to serialize it to an ASN.1 sequence, or to deserialize
//! an ASN.1 sequence into an instance of the struct.
//!
//! The example then uses the BerSerialize::serialize function to encode
//! the struct to a DER-encoded byte stream.
//!
//!
//! ```
//! #[macro_use] extern crate asn1_cereal; fn main() {
//!   struct ShortSequence {
//!     z: u64,
//!     y: u32,
//!   }
//!
//!   asn1_sequence!(
//!     ShortSequence,
//!     "SHORT_SEQUENCE",
//!     z,
//!     y
//!   );
//!
//!   use asn1_cereal::BerSerialize;
//!
//!   let data = ShortSequence{ z: 1, y: 2 };
//!   let mut bytes: Vec<u8> = Vec::new();
//!   BerSerialize::serialize(&data, &mut bytes).unwrap();
//! }
//! ```

#[macro_export]
/// This macro defines the Asn1Info trait for a rust type.
///
/// This information is used to match tag information during deserialization,
/// so it should match the expected values in the ASN.1 stream.
macro_rules! asn1_info {
  ($rs_type:ty, $class:expr, $tagnum:expr, $constructed:expr, $asn1_ty:expr) => (
    impl $crate::Asn1Info for $rs_type {
      fn asn1_tag() -> $crate::tag::Tag {
        $crate::tag::Tag {
          class: ($class as u8).into(),
          tagnum: $tagnum as $crate::tag::TagNum,
          constructed: $constructed,

        }
      }

      fn asn1_type() -> $crate::tag::Type {
        $crate::tag::Type::from($asn1_ty)
      }
    }
  )
}

pub mod traits;
mod prim;

pub mod int;
pub mod str;
pub mod assign;
pub mod choice;
pub mod seq;
pub mod seq_of;
<|endoftext|>


<commit_before>extern crate slog;

use std::time::Instant;
use slog::Logger;

// When this struct is dropped, it logs a message stating its name and how long, in seconds,
// execution time was. Can be used to time functions or other critical areas.
pub struct ExecutionTimer<'a> {
	start_time: Instant,
	name: &'a str,
	logger: &'a Logger
}

impl<'a> ExecutionTimer<'a> {
	// Construct a new ExecutionTimer, silently.
	#[allow(dead_code)]
	pub fn new(logger: &'a Logger, name: &'a str) -> ExecutionTimer<'a> {
		ExecutionTimer {
			start_time: Instant::now(),
			logger: logger,
			name: name
		}
	}

	// Construct a new ExecutionTimer and prints a message saying execution is starting.
	#[allow(dead_code)]
	pub fn new2(logger: &'a Logger, name: &'a str) -> ExecutionTimer<'a> {
		debug!(logger, "Execution Started"; "Name" => name);
		ExecutionTimer::new(logger, name)
	}
}

impl<'a> Drop for ExecutionTimer<'a> {
	fn drop(&mut self) {
		let elapsed = self.start_time.elapsed();
        let secs = (elapsed.as_secs() as f64) + (elapsed.subsec_nanos() as f64 / 1000_000_000.0);
		debug!(self.logger, "Execution Completed"; "Seconds" => secs, "Name" => self.name);
	}
}
<commit_msg>Remove unneccessary 'extern crate' declaration.<commit_after>use std::time::Instant;
use slog::Logger;

// When this struct is dropped, it logs a message stating its name and how long, in seconds,
// execution time was. Can be used to time functions or other critical areas.
pub struct ExecutionTimer<'a> {
	start_time: Instant,
	name: &'a str,
	logger: &'a Logger
}

impl<'a> ExecutionTimer<'a> {
	pub fn new(logger: &'a Logger, name: &'a str) -> ExecutionTimer<'a> {
		ExecutionTimer {
			start_time: Instant::now(),
			logger: logger,
			name: name
		}
	}

	// Construct a new ExecutionTimer and prints a message saying execution is starting.
	#[allow(dead_code)]
	pub fn new2(logger: &'a Logger, name: &'a str) -> ExecutionTimer<'a> {
		debug!(logger, "Execution Started"; "Name" => name);
		ExecutionTimer::new(logger, name)
	}
}

impl<'a> Drop for ExecutionTimer<'a> {
	fn drop(&mut self) {
		let elapsed = self.start_time.elapsed();
        let secs = (elapsed.as_secs() as f64) + (elapsed.subsec_nanos() as f64 / 1000_000_000.0);
		debug!(self.logger, "Execution Completed"; "Seconds" => secs, "Name" => self.name);
	}
}
<|endoftext|>


<commit_before>//! Handle `cargo add` arguments

#![allow(clippy::bool_assert_comparison)]

use cargo_edit::{
    find, get_manifest_from_path, get_manifest_from_url, registry_url, workspace_members,
    Dependency,
};
use cargo_edit::{get_latest_dependency, CrateName};
use cargo_metadata::Package;
use std::path::PathBuf;
use structopt::{clap::AppSettings, StructOpt};

use crate::errors::*;

#[derive(Debug, StructOpt)]
#[structopt(bin_name = "cargo")]
pub enum Command {
    /// Add dependency to a Cargo.toml manifest file.
    #[structopt(name = "add")]
    #[structopt(after_help = "\
This command allows you to add a dependency to a Cargo.toml manifest file. If <crate> is a github \
or gitlab repository URL, or a local path, `cargo add` will try to automatically get the crate \
name and set the appropriate `--git` or `--path` value.

Please note that Cargo treats versions like '1.2.3' as '^1.2.3' (and that '^1.2.3' is specified \
as '>=1.2.3 and <2.0.0'). By default, `cargo add` will use this format, as it is the one that the \
crates.io registry suggests. One goal of `cargo add` is to prevent you from using wildcard \
dependencies (version set to '*').")]
    Add(Args),
}

#[derive(Debug, StructOpt)]
#[structopt(setting = AppSettings::ColoredHelp)]
pub struct Args {
    /// Crates to be added.
    #[structopt(name = "crate", required = true)]
    pub crates: Vec<String>,

    /// Rename a dependency in Cargo.toml,
    /// https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml.
    /// Only works when specifying a single dependency.
    #[structopt(long = "rename", short = "r")]
    pub rename: Option<String>,

    /// Add crate as development dependency.
    #[structopt(long = "dev", short = "D", conflicts_with = "build")]
    pub dev: bool,

    /// Add crate as build dependency.
    #[structopt(long = "build", short = "B", conflicts_with = "dev")]
    pub build: bool,

    /// Specify the version to grab from the registry(crates.io).
    /// You can also specify version as part of name, e.g
    /// `cargo add bitflags@0.3.2`.
    #[structopt(long = "vers", value_name = "uri", conflicts_with = "git")]
    pub vers: Option<String>,

    /// Specify a git repository to download the crate from.
    #[structopt(
        long = "git",
        value_name = "uri",
        conflicts_with = "vers",
        conflicts_with = "path"
    )]
    pub git: Option<String>,

    /// Specify a git branch to download the crate from.
    #[structopt(
        long = "branch",
        value_name = "branch",
        conflicts_with = "vers",
        conflicts_with = "path"
    )]
    pub branch: Option<String>,

    /// Specify the path the crate should be loaded from.
    #[structopt(long = "path", conflicts_with = "git")]
    pub path: Option<PathBuf>,

    /// Add as dependency to the given target platform.
    #[structopt(long = "target", conflicts_with = "dev", conflicts_with = "build")]
    pub target: Option<String>,

    /// Add as an optional dependency (for use in features).
    #[structopt(long = "optional", conflicts_with = "dev")]
    pub optional: bool,

    /// Path to the manifest to add a dependency to.
    #[structopt(long = "manifest-path", value_name = "path", conflicts_with = "pkgid")]
    pub manifest_path: Option<PathBuf>,

    /// Package id of the crate to add this dependency to.
    #[structopt(
        long = "package",
        short = "p",
        value_name = "pkgid",
        conflicts_with = "path"
    )]
    pub pkgid: Option<String>,

    /// Choose method of semantic version upgrade.  Must be one of "none" (exact version, `=`
    /// modifier), "patch" (`~` modifier), "minor" (`^` modifier), "all" (`>=`), or "default" (no
    /// modifier).
    #[structopt(
        long = "upgrade",
        value_name = "method",
        possible_value = "none",
        possible_value = "patch",
        possible_value = "minor",
        possible_value = "all",
        possible_value = "default",
        default_value = "default"
    )]
    pub upgrade: String,

    /// Include prerelease versions when fetching from crates.io (e.g.
    /// '0.6.0-alpha').
    #[structopt(long = "allow-prerelease")]
    pub allow_prerelease: bool,

    /// Space-separated list of features to add. For an alternative approach to
    /// enabling features, consider installing the `cargo-feature` utility.
    #[structopt(long = "features", number_of_values = 1)]
    pub features: Option<Vec<String>>,

    /// Set `default-features = false` for the added dependency.
    #[structopt(long = "no-default-features")]
    pub no_default_features: bool,

    /// Do not print any output in case of success.
    #[structopt(long = "quiet", short = "q")]
    pub quiet: bool,

    /// Run without accessing the network
    #[structopt(long = "offline")]
    pub offline: bool,

    /// Sort dependencies even if currently unsorted
    #[structopt(long = "sort", short = "s")]
    pub sort: bool,

    /// Registry to use
    #[structopt(long = "registry", conflicts_with = "git", conflicts_with = "path")]
    pub registry: Option<String>,
}

fn parse_version_req(s: &str) -> Result<&str> {
    semver::VersionReq::parse(s).chain_err(|| "Invalid dependency version requirement")?;
    Ok(s)
}

impl Args {
    /// Get dependency section
    pub fn get_section(&self) -> Vec<String> {
        if self.dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.build {
            vec!["build-dependencies".to_owned()]
        } else if let Some(ref target) = self.target {
            assert!(!target.is_empty(), "Target specification may not be empty");

            vec![
                "target".to_owned(),
                target.clone(),
                "dependencies".to_owned(),
            ]
        } else {
            vec!["dependencies".to_owned()]
        }
    }

    fn parse_single_dependency(
        &self,
        crate_name: &str,
        workspace_members: &[Package],
    ) -> Result<Dependency> {
        let crate_name = CrateName::new(crate_name);

        if let Some(mut dependency) = crate_name.parse_as_version()? {
            // crate specifier includes a version (e.g. `docopt@0.8`)
            if let Some(ref url) = self.git {
                let url = url.clone();
                let version = dependency.version().unwrap().to_string();
                return Err(ErrorKind::GitUrlWithVersion(url, version).into());
            }

            if let Some(ref path) = self.path {
                let manifest = get_manifest_from_path(path)?;
                let dep_path = dunce::canonicalize(path)?;

                dependency = dependency.set_available_features(manifest.features()?);
                dependency = dependency.set_path(dep_path);
            }

            Ok(dependency)
        } else if let Some(mut dependency) = crate_name.parse_crate_name_from_uri()? {
            // dev-dependencies do not need the version populated
            if !self.dev {
                let dep_path = dependency.path().map(ToOwned::to_owned);
                if let Some(dep_path) = dep_path {
                    if let Some(package) = workspace_members.iter().find(|p| {
                        p.manifest_path.parent().map(|p| p.as_std_path())
                            == Some(dep_path.as_path())
                    }) {
                        let v = format!(
                            "{prefix}{version}",
                            prefix = self.get_upgrade_prefix(),
                            version = package.version
                        );

                        dependency = dependency.set_version(&v);

                        if let Some(registry) = &self.registry {
                            dependency = dependency.set_registry(registry);
                        }
                    }
                }
            }
            Ok(dependency)
        } else {
            let mut dependency = Dependency::new(crate_name.name());

            if let Some(repo) = &self.git {
                assert!(self.vers.is_none());
                assert!(self.path.is_none());
                assert!(self.registry.is_none());
                let features = get_manifest_from_url(repo)?
                    .map(|m| m.features())
                    .transpose()?
                    .unwrap_or_else(Vec::new);

                dependency = dependency
                    .set_git(repo, self.branch.clone())
                    .set_available_features(features);
            } else {
                if let Some(path) = &self.path {
                    assert!(self.registry.is_none());
                    let manifest = get_manifest_from_path(path)?;

                    dependency = dependency.set_available_features(manifest.features()?);
                    dependency = dependency.set_path(dunce::canonicalize(path)?);
                }
                if let Some(version) = &self.vers {
                    dependency = dependency.set_version(parse_version_req(version)?);
                }
                let registry_url = if let Some(registry) = &self.registry {
                    Some(registry_url(&find(&self.manifest_path)?, Some(registry))?)
                } else {
                    None
                };

                if self.git.is_none() && self.path.is_none() && self.vers.is_none() {
                    // Only special-case workspaces when the user doesn't provide any extra
                    // information, otherwise, trust the user.
                    if let Some(package) = workspace_members
                        .iter()
                        .find(|p| p.name == crate_name.name())
                    {
                        dependency = dependency.set_path(
                            package
                                .manifest_path
                                .parent()
                                .expect("at least parent dir")
                                .as_std_path()
                                .to_owned(),
                        );
                        // dev-dependencies do not need the version populated
                        if !self.dev {
                            let v = format!(
                                "{prefix}{version}",
                                prefix = self.get_upgrade_prefix(),
                                version = package.version
                            );
                            dependency = dependency.set_version(&v);
                        }
                    } else {
                        dependency = get_latest_dependency(
                            crate_name.name(),
                            self.allow_prerelease,
                            &find(&self.manifest_path)?,
                            &registry_url,
                        )?;
                        let v = format!(
                            "{prefix}{version}",
                            prefix = self.get_upgrade_prefix(),
                            // If version is unavailable `get_latest_dependency` must have
                            // returned `Err(FetchVersionError::GetVersion)`
                            version = dependency.version().unwrap_or_else(|| unreachable!())
                        );
                        dependency = dependency.set_version(&v);
                    }
                }

                // Set the registry after getting the latest version as
                // get_latest_dependency returns a registry-less Dependency
                if let Some(registry) = &self.registry {
                    dependency = dependency.set_registry(registry);
                }
            }

            Ok(dependency)
        }
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self) -> Result<Vec<Dependency>> {
        let workspace_members = workspace_members(self.manifest_path.as_deref())?;

        if self.crates.len() > 1
            && (self.git.is_some() || self.path.is_some() || self.vers.is_some())
        {
            return Err(ErrorKind::MultipleCratesWithGitOrPathOrVers.into());
        }

        if self.crates.len() > 1 && self.rename.is_some() {
            return Err(ErrorKind::MultipleCratesWithRename.into());
        }

        if self.crates.len() > 1 && self.features.is_some() {
            return Err(ErrorKind::MultipleCratesWithFeatures.into());
        }

        self.crates
            .iter()
            .map(|crate_name| {
                self.parse_single_dependency(crate_name, &workspace_members)
                    .map(|x| {
                        let mut x = x
                            .set_optional(self.optional)
                            .set_features(self.features.clone())
                            .set_default_features(!self.no_default_features);
                        if let Some(ref rename) = self.rename {
                            x = x.set_rename(rename);
                        }
                        x
                    })
            })
            .collect()
    }

    fn get_upgrade_prefix(&self) -> &'static str {
        match self.upgrade.as_ref() {
            "default" => "",
            "none" => "=",
            "patch" => "~",
            "minor" => "^",
            "all" => ">=",
            _ => unreachable!(),
        }
    }
}

#[cfg(test)]
impl Default for Args {
    fn default() -> Args {
        Args {
            crates: vec!["demo".to_owned()],
            rename: None,
            dev: false,
            build: false,
            vers: None,
            git: None,
            branch: None,
            path: None,
            target: None,
            optional: false,
            manifest_path: None,
            pkgid: None,
            upgrade: "minor".to_string(),
            allow_prerelease: false,
            features: None,
            no_default_features: false,
            quiet: false,
            offline: true,
            sort: false,
            registry: None,
        }
    }
}

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

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            vers: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(
            args.parse_dependencies().unwrap(),
            vec![Dependency::new("demo").set_version("0.4.2")]
        );
    }

    #[test]
    #[cfg(feature = "test-external-apis")]
    fn test_repo_as_arg_parsing() {
        let github_url = "https://github.com/killercup/cargo-edit/";
        let args_github = Args {
            crates: vec![github_url.to_owned()],
            ..Args::default()
        };
        assert_eq!(
            args_github.parse_dependencies().unwrap(),
            vec![Dependency::new("cargo-edit").set_git(github_url, None)]
        );

        let gitlab_url = "https://gitlab.com/Polly-lang/Polly.git";
        let args_gitlab = Args {
            crates: vec![gitlab_url.to_owned()],
            ..Args::default()
        };
        assert_eq!(
            args_gitlab.parse_dependencies().unwrap(),
            vec![Dependency::new("polly").set_git(gitlab_url, None)]
        );
    }

    #[test]
    fn test_path_as_arg_parsing() {
        let self_path = dunce::canonicalize(std::env::current_dir().unwrap()).unwrap();
        let args_path = Args {
            // Hacky to `display` but should generally work
            crates: vec![self_path.display().to_string()],
            ..Args::default()
        };
        assert_eq!(
            args_path.parse_dependencies().unwrap()[0].path().unwrap(),
            self_path
        );
    }
}
<commit_msg>fix: Allow --registry with name@version (#543)<commit_after>//! Handle `cargo add` arguments

#![allow(clippy::bool_assert_comparison)]

use cargo_edit::{
    find, get_manifest_from_path, get_manifest_from_url, registry_url, workspace_members,
    Dependency,
};
use cargo_edit::{get_latest_dependency, CrateName};
use cargo_metadata::Package;
use std::path::PathBuf;
use structopt::{clap::AppSettings, StructOpt};

use crate::errors::*;

#[derive(Debug, StructOpt)]
#[structopt(bin_name = "cargo")]
pub enum Command {
    /// Add dependency to a Cargo.toml manifest file.
    #[structopt(name = "add")]
    #[structopt(after_help = "\
This command allows you to add a dependency to a Cargo.toml manifest file. If <crate> is a github \
or gitlab repository URL, or a local path, `cargo add` will try to automatically get the crate \
name and set the appropriate `--git` or `--path` value.

Please note that Cargo treats versions like '1.2.3' as '^1.2.3' (and that '^1.2.3' is specified \
as '>=1.2.3 and <2.0.0'). By default, `cargo add` will use this format, as it is the one that the \
crates.io registry suggests. One goal of `cargo add` is to prevent you from using wildcard \
dependencies (version set to '*').")]
    Add(Args),
}

#[derive(Debug, StructOpt)]
#[structopt(setting = AppSettings::ColoredHelp)]
pub struct Args {
    /// Crates to be added.
    #[structopt(name = "crate", required = true)]
    pub crates: Vec<String>,

    /// Rename a dependency in Cargo.toml,
    /// https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml.
    /// Only works when specifying a single dependency.
    #[structopt(long = "rename", short = "r")]
    pub rename: Option<String>,

    /// Add crate as development dependency.
    #[structopt(long = "dev", short = "D", conflicts_with = "build")]
    pub dev: bool,

    /// Add crate as build dependency.
    #[structopt(long = "build", short = "B", conflicts_with = "dev")]
    pub build: bool,

    /// Specify the version to grab from the registry(crates.io).
    /// You can also specify version as part of name, e.g
    /// `cargo add bitflags@0.3.2`.
    #[structopt(long = "vers", value_name = "uri", conflicts_with = "git")]
    pub vers: Option<String>,

    /// Specify a git repository to download the crate from.
    #[structopt(
        long = "git",
        value_name = "uri",
        conflicts_with = "vers",
        conflicts_with = "path"
    )]
    pub git: Option<String>,

    /// Specify a git branch to download the crate from.
    #[structopt(
        long = "branch",
        value_name = "branch",
        conflicts_with = "vers",
        conflicts_with = "path"
    )]
    pub branch: Option<String>,

    /// Specify the path the crate should be loaded from.
    #[structopt(long = "path", conflicts_with = "git")]
    pub path: Option<PathBuf>,

    /// Add as dependency to the given target platform.
    #[structopt(long = "target", conflicts_with = "dev", conflicts_with = "build")]
    pub target: Option<String>,

    /// Add as an optional dependency (for use in features).
    #[structopt(long = "optional", conflicts_with = "dev")]
    pub optional: bool,

    /// Path to the manifest to add a dependency to.
    #[structopt(long = "manifest-path", value_name = "path", conflicts_with = "pkgid")]
    pub manifest_path: Option<PathBuf>,

    /// Package id of the crate to add this dependency to.
    #[structopt(
        long = "package",
        short = "p",
        value_name = "pkgid",
        conflicts_with = "path"
    )]
    pub pkgid: Option<String>,

    /// Choose method of semantic version upgrade.  Must be one of "none" (exact version, `=`
    /// modifier), "patch" (`~` modifier), "minor" (`^` modifier), "all" (`>=`), or "default" (no
    /// modifier).
    #[structopt(
        long = "upgrade",
        value_name = "method",
        possible_value = "none",
        possible_value = "patch",
        possible_value = "minor",
        possible_value = "all",
        possible_value = "default",
        default_value = "default"
    )]
    pub upgrade: String,

    /// Include prerelease versions when fetching from crates.io (e.g.
    /// '0.6.0-alpha').
    #[structopt(long = "allow-prerelease")]
    pub allow_prerelease: bool,

    /// Space-separated list of features to add. For an alternative approach to
    /// enabling features, consider installing the `cargo-feature` utility.
    #[structopt(long = "features", number_of_values = 1)]
    pub features: Option<Vec<String>>,

    /// Set `default-features = false` for the added dependency.
    #[structopt(long = "no-default-features")]
    pub no_default_features: bool,

    /// Do not print any output in case of success.
    #[structopt(long = "quiet", short = "q")]
    pub quiet: bool,

    /// Run without accessing the network
    #[structopt(long = "offline")]
    pub offline: bool,

    /// Sort dependencies even if currently unsorted
    #[structopt(long = "sort", short = "s")]
    pub sort: bool,

    /// Registry to use
    #[structopt(long = "registry", conflicts_with = "git", conflicts_with = "path")]
    pub registry: Option<String>,
}

fn parse_version_req(s: &str) -> Result<&str> {
    semver::VersionReq::parse(s).chain_err(|| "Invalid dependency version requirement")?;
    Ok(s)
}

impl Args {
    /// Get dependency section
    pub fn get_section(&self) -> Vec<String> {
        if self.dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.build {
            vec!["build-dependencies".to_owned()]
        } else if let Some(ref target) = self.target {
            assert!(!target.is_empty(), "Target specification may not be empty");

            vec![
                "target".to_owned(),
                target.clone(),
                "dependencies".to_owned(),
            ]
        } else {
            vec!["dependencies".to_owned()]
        }
    }

    fn parse_single_dependency(
        &self,
        crate_name: &str,
        workspace_members: &[Package],
    ) -> Result<Dependency> {
        let crate_name = CrateName::new(crate_name);
        let registry_url = if let Some(registry) = &self.registry {
            Some(registry_url(&find(&self.manifest_path)?, Some(registry))?)
        } else {
            None
        };

        let mut dependency = if let Some(mut dependency) = crate_name.parse_as_version()? {
            // crate specifier includes a version (e.g. `docopt@0.8`)
            if let Some(ref url) = self.git {
                let url = url.clone();
                let version = dependency.version().unwrap().to_string();
                return Err(ErrorKind::GitUrlWithVersion(url, version).into());
            }

            if let Some(ref path) = self.path {
                let manifest = get_manifest_from_path(path)?;
                let dep_path = dunce::canonicalize(path)?;

                dependency = dependency.set_available_features(manifest.features()?);
                dependency = dependency.set_path(dep_path);
            }

            dependency
        } else if let Some(mut dependency) = crate_name.parse_crate_name_from_uri()? {
            // dev-dependencies do not need the version populated
            if !self.dev {
                let dep_path = dependency.path().map(ToOwned::to_owned);
                if let Some(dep_path) = dep_path {
                    if let Some(package) = workspace_members.iter().find(|p| {
                        p.manifest_path.parent().map(|p| p.as_std_path())
                            == Some(dep_path.as_path())
                    }) {
                        let v = format!(
                            "{prefix}{version}",
                            prefix = self.get_upgrade_prefix(),
                            version = package.version
                        );

                        dependency = dependency.set_version(&v);
                    }
                }
            }
            dependency
        } else {
            let mut dependency = Dependency::new(crate_name.name());

            if let Some(repo) = &self.git {
                assert!(self.vers.is_none());
                assert!(self.path.is_none());
                assert!(self.registry.is_none());
                let features = get_manifest_from_url(repo)?
                    .map(|m| m.features())
                    .transpose()?
                    .unwrap_or_else(Vec::new);

                dependency = dependency
                    .set_git(repo, self.branch.clone())
                    .set_available_features(features);
            } else {
                if let Some(path) = &self.path {
                    assert!(self.registry.is_none());
                    let manifest = get_manifest_from_path(path)?;

                    dependency = dependency.set_available_features(manifest.features()?);
                    dependency = dependency.set_path(dunce::canonicalize(path)?);
                }
                if let Some(version) = &self.vers {
                    dependency = dependency.set_version(parse_version_req(version)?);
                }

                if self.git.is_none() && self.path.is_none() && self.vers.is_none() {
                    // Only special-case workspaces when the user doesn't provide any extra
                    // information, otherwise, trust the user.
                    if let Some(package) = workspace_members
                        .iter()
                        .find(|p| p.name == crate_name.name())
                    {
                        dependency = dependency.set_path(
                            package
                                .manifest_path
                                .parent()
                                .expect("at least parent dir")
                                .as_std_path()
                                .to_owned(),
                        );
                        // dev-dependencies do not need the version populated
                        if !self.dev {
                            let v = format!(
                                "{prefix}{version}",
                                prefix = self.get_upgrade_prefix(),
                                version = package.version
                            );
                            dependency = dependency.set_version(&v);
                        }
                    } else {
                        dependency = get_latest_dependency(
                            crate_name.name(),
                            self.allow_prerelease,
                            &find(&self.manifest_path)?,
                            &registry_url,
                        )?;
                        let v = format!(
                            "{prefix}{version}",
                            prefix = self.get_upgrade_prefix(),
                            // If version is unavailable `get_latest_dependency` must have
                            // returned `Err(FetchVersionError::GetVersion)`
                            version = dependency.version().unwrap_or_else(|| unreachable!())
                        );
                        dependency = dependency.set_version(&v);
                    }
                }
            }

            dependency
        };

        if let Some(registry) = &self.registry {
            dependency = dependency.set_registry(registry);
        }

        Ok(dependency)
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self) -> Result<Vec<Dependency>> {
        let workspace_members = workspace_members(self.manifest_path.as_deref())?;

        if self.crates.len() > 1
            && (self.git.is_some() || self.path.is_some() || self.vers.is_some())
        {
            return Err(ErrorKind::MultipleCratesWithGitOrPathOrVers.into());
        }

        if self.crates.len() > 1 && self.rename.is_some() {
            return Err(ErrorKind::MultipleCratesWithRename.into());
        }

        if self.crates.len() > 1 && self.features.is_some() {
            return Err(ErrorKind::MultipleCratesWithFeatures.into());
        }

        self.crates
            .iter()
            .map(|crate_name| {
                self.parse_single_dependency(crate_name, &workspace_members)
                    .map(|x| {
                        let mut x = x
                            .set_optional(self.optional)
                            .set_features(self.features.clone())
                            .set_default_features(!self.no_default_features);
                        if let Some(ref rename) = self.rename {
                            x = x.set_rename(rename);
                        }
                        x
                    })
            })
            .collect()
    }

    fn get_upgrade_prefix(&self) -> &'static str {
        match self.upgrade.as_ref() {
            "default" => "",
            "none" => "=",
            "patch" => "~",
            "minor" => "^",
            "all" => ">=",
            _ => unreachable!(),
        }
    }
}

#[cfg(test)]
impl Default for Args {
    fn default() -> Args {
        Args {
            crates: vec!["demo".to_owned()],
            rename: None,
            dev: false,
            build: false,
            vers: None,
            git: None,
            branch: None,
            path: None,
            target: None,
            optional: false,
            manifest_path: None,
            pkgid: None,
            upgrade: "minor".to_string(),
            allow_prerelease: false,
            features: None,
            no_default_features: false,
            quiet: false,
            offline: true,
            sort: false,
            registry: None,
        }
    }
}

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

    #[test]
    fn test_dependency_parsing() {
        let args = Args {
            vers: Some("0.4.2".to_owned()),
            ..Args::default()
        };

        assert_eq!(
            args.parse_dependencies().unwrap(),
            vec![Dependency::new("demo").set_version("0.4.2")]
        );
    }

    #[test]
    #[cfg(feature = "test-external-apis")]
    fn test_repo_as_arg_parsing() {
        let github_url = "https://github.com/killercup/cargo-edit/";
        let args_github = Args {
            crates: vec![github_url.to_owned()],
            ..Args::default()
        };
        assert_eq!(
            args_github.parse_dependencies().unwrap(),
            vec![Dependency::new("cargo-edit").set_git(github_url, None)]
        );

        let gitlab_url = "https://gitlab.com/Polly-lang/Polly.git";
        let args_gitlab = Args {
            crates: vec![gitlab_url.to_owned()],
            ..Args::default()
        };
        assert_eq!(
            args_gitlab.parse_dependencies().unwrap(),
            vec![Dependency::new("polly").set_git(gitlab_url, None)]
        );
    }

    #[test]
    fn test_path_as_arg_parsing() {
        let self_path = dunce::canonicalize(std::env::current_dir().unwrap()).unwrap();
        let args_path = Args {
            // Hacky to `display` but should generally work
            crates: vec![self_path.display().to_string()],
            ..Args::default()
        };
        assert_eq!(
            args_path.parse_dependencies().unwrap()[0].path().unwrap(),
            self_path
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! Angle units for type-safe, self-documenting code.

pub use std::num::{cast, zero};
pub use std::num::{sinh, cosh, tanh};
pub use std::num::{asinh, acosh, atanh};

use std::num::Zero;

#[deriving(Clone, Eq, Ord, Zero)] pub struct Rad<S> { s: S }
#[deriving(Clone, Eq, Ord, Zero)] pub struct Deg<S> { s: S }

#[inline] pub fn rad<S: Float>(s: S) -> Rad<S> { Rad { s: s } }
#[inline] pub fn deg<S: Float>(s: S) -> Deg<S> { Deg { s: s } }

pub trait ToRad<S: Float> { fn to_rad(&self) -> Rad<S>; }
pub trait ToDeg<S: Float> { fn to_deg(&self) -> Deg<S>; }

impl<S: Float> ToRad<S> for Rad<S> { #[inline] fn to_rad(&self) -> Rad<S> { self.clone() } }
impl<S: Float> ToRad<S> for Deg<S> { #[inline] fn to_rad(&self) -> Rad<S> { rad(self.s.to_radians()) } }

impl<S: Float> ToDeg<S> for Rad<S> { #[inline] fn to_deg(&self) -> Deg<S> { deg(self.s.to_degrees()) } }
impl<S: Float> ToDeg<S> for Deg<S> { #[inline] fn to_deg(&self) -> Deg<S> { self.clone() } }

impl<S: Float> Neg<Rad<S>> for Rad<S> { #[inline] fn neg(&self) -> Rad<S> { rad(-self.s) } }
impl<S: Float> Neg<Deg<S>> for Deg<S> { #[inline] fn neg(&self) -> Deg<S> { deg(-self.s) } }

/// Private utility functions for converting to/from scalars
trait ScalarConv<S> {
    fn from(s: S) -> Self;
    fn s<'a>(&'a self) -> &'a S;
    fn mut_s<'a>(&'a mut self) -> &'a mut S;
}

impl<S: Float> ScalarConv<S> for Rad<S> {
    #[inline] fn from(s: S) -> Rad<S> { rad(s) }
    #[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s }
    #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s }
}

impl<S: Float> ScalarConv<S> for Deg<S> {
    #[inline] fn from(s: S) -> Deg<S> { deg(s) }
    #[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s }
    #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s }
}

pub trait Angle
<
    S: Float
>
:   Clone + Zero
+   Eq + Ord
+   ApproxEq<S>
+   Neg<Self>
+   ToRad<S>
+   ToDeg<S>
+   ScalarConv<S>
{
    fn from<A: Angle<S>>(theta: A) -> Self;

    #[inline] fn neg_self(&mut self) { *self = -*self }

    #[inline] fn add_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() + *other.s()) }
    #[inline] fn sub_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() - *other.s()) }
    #[inline] fn div_a(&self, other: Self) -> S { *self.s() / *other.s() }
    #[inline] fn rem_a(&self, other: Self) -> S { *self.s() % *other.s() }
    #[inline] fn mul_s(&self, s: S) -> Self { ScalarConv::from(*self.s() * s) }
    #[inline] fn div_s(&self, s: S) -> Self { ScalarConv::from(*self.s() / s) }
    #[inline] fn rem_s(&self, s: S) -> Self { ScalarConv::from(*self.s() % s) }

    #[inline] fn add_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() + *other.s() }
    #[inline] fn sub_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() - *other.s() }
    #[inline] fn mul_self_s(&mut self, s: S) { *self.mut_s() = *self.s() * s }
    #[inline] fn div_self_s(&mut self, s: S) { *self.mut_s() = *self.s() / s }
    #[inline] fn rem_self_s(&mut self, s: S) { *self.mut_s() = *self.s() % s }

    /// Return the angle, normalized to the range `[0, full_turn)`.
    #[inline]
    fn normalize(&self) -> Self {
        let mut a = self.clone();
        a.normalize_self();
        a
    }

    /// Normalize the angle to the range `[0, full_turn)`.
    #[inline]
    fn normalize_self(&mut self) {
        let full_turn: Self = Angle::full_turn();
        self.rem_self_s(full_turn.s().clone());
        if *self < zero() { self.add_self_a(full_turn) };
    }

    /// Return the angle rotated by half a turn
    #[inline]
    fn opposite(&self) -> Self {
        self.add_a(Angle::turn_div_2()).normalize()
    }

    fn full_turn() -> Self;

    #[inline] fn turn_div_2() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(2)) }
    #[inline] fn turn_div_3() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(3)) }
    #[inline] fn turn_div_4() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(4)) }
    #[inline] fn turn_div_6() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(6)) }
}

impl<S: Float> Rad<S> {
    #[inline] pub fn zero() -> Rad<S> { zero() }
    #[inline] pub fn full_turn() -> Rad<S> { Angle::full_turn() }
    #[inline] pub fn turn_div_2() -> Rad<S> { Angle::turn_div_2() }
    #[inline] pub fn turn_div_3() -> Rad<S> { Angle::turn_div_3() }
    #[inline] pub fn turn_div_4() -> Rad<S> { Angle::turn_div_4() }
    #[inline] pub fn turn_div_6() -> Rad<S> { Angle::turn_div_6() }
}

impl<S: Float> Deg<S> {
    #[inline] pub fn zero() -> Deg<S> { zero() }
    #[inline] pub fn full_turn() -> Deg<S> { Angle::full_turn() }
    #[inline] pub fn turn_div_2() -> Deg<S> { Angle::turn_div_2() }
    #[inline] pub fn turn_div_3() -> Deg<S> { Angle::turn_div_3() }
    #[inline] pub fn turn_div_4() -> Deg<S> { Angle::turn_div_4() }
    #[inline] pub fn turn_div_6() -> Deg<S> { Angle::turn_div_6() }
}

impl<S: Float> Angle<S> for Rad<S> {
    #[inline] fn from<A: Angle<S>>(theta: A) -> Rad<S> { theta.to_rad() }
    #[inline] fn full_turn() -> Rad<S> { rad(Real::two_pi()) }
}

impl<S: Float> Angle<S> for Deg<S> {
    #[inline] fn from<A: Angle<S>>(theta: A) -> Deg<S> { theta.to_deg() }
    #[inline] fn full_turn() -> Deg<S> { deg(cast(360)) }
}

#[inline] pub fn sin<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.sin() }
#[inline] pub fn cos<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.cos() }
#[inline] pub fn tan<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.tan() }
#[inline] pub fn sin_cos<S: Float, A: Angle<S>>(theta: A) -> (S, S) { theta.to_rad().s.sin_cos() }

#[inline] pub fn cot<S: Float, A: Angle<S>>(theta: A) -> S { tan(theta).recip() }
#[inline] pub fn sec<S: Float, A: Angle<S>>(theta: A) -> S { cos(theta).recip() }
#[inline] pub fn csc<S: Float, A: Angle<S>>(theta: A) -> S { sin(theta).recip() }

#[inline] pub fn asin<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.asin())) }
#[inline] pub fn acos<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.acos())) }
#[inline] pub fn atan<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.atan())) }
#[inline] pub fn atan2<S: Float, A: Angle<S>>(a: S, b: S) -> A { Angle::from(rad(a.atan2(&b))) }

impl<S: Float> ToStr for Rad<S> { fn to_str(&self) -> ~str { fmt!("%? rad", self.s) } }
impl<S: Float> ToStr for Deg<S> { fn to_str(&self) -> ~str { fmt!("%?°", self.s) } }

impl<S: Float> ApproxEq<S> for Rad<S> {
    #[inline]
    fn approx_epsilon() -> S {
        // TODO: fix this after static methods are fixed in rustc
        fail!(~"Doesn't work!");
    }

    #[inline]
    fn approx_eq(&self, other: &Rad<S>) -> bool {
        self.s.approx_eq(&other.s)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Rad<S>, approx_epsilon: &S) -> bool {
        self.s.approx_eq_eps(&other.s, approx_epsilon)
    }
}

impl<S: Float> ApproxEq<S> for Deg<S> {
    #[inline]
    fn approx_epsilon() -> S {
        // TODO: fix this after static methods are fixed in rustc
        fail!(~"Doesn't work!");
    }

    #[inline]
    fn approx_eq(&self, other: &Deg<S>) -> bool {
        self.s.approx_eq(&other.s)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Deg<S>, approx_epsilon: &S) -> bool {
        self.s.approx_eq_eps(&other.s, approx_epsilon)
    }
}
<commit_msg>Add bisection method for angles<commit_after>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! Angle units for type-safe, self-documenting code.

pub use std::num::{cast, zero};
pub use std::num::{sinh, cosh, tanh};
pub use std::num::{asinh, acosh, atanh};

use std::num::Zero;

#[deriving(Clone, Eq, Ord, Zero)] pub struct Rad<S> { s: S }
#[deriving(Clone, Eq, Ord, Zero)] pub struct Deg<S> { s: S }

#[inline] pub fn rad<S: Float>(s: S) -> Rad<S> { Rad { s: s } }
#[inline] pub fn deg<S: Float>(s: S) -> Deg<S> { Deg { s: s } }

pub trait ToRad<S: Float> { fn to_rad(&self) -> Rad<S>; }
pub trait ToDeg<S: Float> { fn to_deg(&self) -> Deg<S>; }

impl<S: Float> ToRad<S> for Rad<S> { #[inline] fn to_rad(&self) -> Rad<S> { self.clone() } }
impl<S: Float> ToRad<S> for Deg<S> { #[inline] fn to_rad(&self) -> Rad<S> { rad(self.s.to_radians()) } }

impl<S: Float> ToDeg<S> for Rad<S> { #[inline] fn to_deg(&self) -> Deg<S> { deg(self.s.to_degrees()) } }
impl<S: Float> ToDeg<S> for Deg<S> { #[inline] fn to_deg(&self) -> Deg<S> { self.clone() } }

impl<S: Float> Neg<Rad<S>> for Rad<S> { #[inline] fn neg(&self) -> Rad<S> { rad(-self.s) } }
impl<S: Float> Neg<Deg<S>> for Deg<S> { #[inline] fn neg(&self) -> Deg<S> { deg(-self.s) } }

/// Private utility functions for converting to/from scalars
trait ScalarConv<S> {
    fn from(s: S) -> Self;
    fn s<'a>(&'a self) -> &'a S;
    fn mut_s<'a>(&'a mut self) -> &'a mut S;
}

impl<S: Float> ScalarConv<S> for Rad<S> {
    #[inline] fn from(s: S) -> Rad<S> { rad(s) }
    #[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s }
    #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s }
}

impl<S: Float> ScalarConv<S> for Deg<S> {
    #[inline] fn from(s: S) -> Deg<S> { deg(s) }
    #[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s }
    #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s }
}

pub trait Angle
<
    S: Float
>
:   Clone + Zero
+   Eq + Ord
+   ApproxEq<S>
+   Neg<Self>
+   ToRad<S>
+   ToDeg<S>
+   ScalarConv<S>
{
    fn from<A: Angle<S>>(theta: A) -> Self;

    #[inline] fn neg_self(&mut self) { *self = -*self }

    #[inline] fn add_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() + *other.s()) }
    #[inline] fn sub_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() - *other.s()) }
    #[inline] fn div_a(&self, other: Self) -> S { *self.s() / *other.s() }
    #[inline] fn rem_a(&self, other: Self) -> S { *self.s() % *other.s() }
    #[inline] fn mul_s(&self, s: S) -> Self { ScalarConv::from(*self.s() * s) }
    #[inline] fn div_s(&self, s: S) -> Self { ScalarConv::from(*self.s() / s) }
    #[inline] fn rem_s(&self, s: S) -> Self { ScalarConv::from(*self.s() % s) }

    #[inline] fn add_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() + *other.s() }
    #[inline] fn sub_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() - *other.s() }
    #[inline] fn mul_self_s(&mut self, s: S) { *self.mut_s() = *self.s() * s }
    #[inline] fn div_self_s(&mut self, s: S) { *self.mut_s() = *self.s() / s }
    #[inline] fn rem_self_s(&mut self, s: S) { *self.mut_s() = *self.s() % s }

    /// Return the angle, normalized to the range `[0, full_turn)`.
    #[inline]
    fn normalize(&self) -> Self {
        let mut a = self.clone();
        a.normalize_self();
        a
    }

    /// Normalize the angle to the range `[0, full_turn)`.
    #[inline]
    fn normalize_self(&mut self) {
        let full_turn: Self = Angle::full_turn();
        self.rem_self_s(full_turn.s().clone());
        if *self < zero() { self.add_self_a(full_turn) };
    }

    /// Return the angle rotated by half a turn
    #[inline]
    fn opposite(&self) -> Self {
        self.add_a(Angle::turn_div_2()).normalize()
    }

    /// Returns the interior bisector of the two angles
    #[inline]
    fn bisect(&self, other: Self) -> Self {
        self.add_a(self.sub_a(other).mul_s(cast(0.5))).normalize()
    }

    fn full_turn() -> Self;

    #[inline] fn turn_div_2() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(2)) }
    #[inline] fn turn_div_3() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(3)) }
    #[inline] fn turn_div_4() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(4)) }
    #[inline] fn turn_div_6() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(6)) }
}

#[inline] pub fn bisect<S: Float, A: Angle<S>>(a: A, b: A) -> A { a.bisect(b) }

impl<S: Float> Rad<S> {
    #[inline] pub fn zero() -> Rad<S> { zero() }
    #[inline] pub fn full_turn() -> Rad<S> { Angle::full_turn() }
    #[inline] pub fn turn_div_2() -> Rad<S> { Angle::turn_div_2() }
    #[inline] pub fn turn_div_3() -> Rad<S> { Angle::turn_div_3() }
    #[inline] pub fn turn_div_4() -> Rad<S> { Angle::turn_div_4() }
    #[inline] pub fn turn_div_6() -> Rad<S> { Angle::turn_div_6() }
}

impl<S: Float> Deg<S> {
    #[inline] pub fn zero() -> Deg<S> { zero() }
    #[inline] pub fn full_turn() -> Deg<S> { Angle::full_turn() }
    #[inline] pub fn turn_div_2() -> Deg<S> { Angle::turn_div_2() }
    #[inline] pub fn turn_div_3() -> Deg<S> { Angle::turn_div_3() }
    #[inline] pub fn turn_div_4() -> Deg<S> { Angle::turn_div_4() }
    #[inline] pub fn turn_div_6() -> Deg<S> { Angle::turn_div_6() }
}

impl<S: Float> Angle<S> for Rad<S> {
    #[inline] fn from<A: Angle<S>>(theta: A) -> Rad<S> { theta.to_rad() }
    #[inline] fn full_turn() -> Rad<S> { rad(Real::two_pi()) }
}

impl<S: Float> Angle<S> for Deg<S> {
    #[inline] fn from<A: Angle<S>>(theta: A) -> Deg<S> { theta.to_deg() }
    #[inline] fn full_turn() -> Deg<S> { deg(cast(360)) }
}

#[inline] pub fn sin<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.sin() }
#[inline] pub fn cos<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.cos() }
#[inline] pub fn tan<S: Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.tan() }
#[inline] pub fn sin_cos<S: Float, A: Angle<S>>(theta: A) -> (S, S) { theta.to_rad().s.sin_cos() }

#[inline] pub fn cot<S: Float, A: Angle<S>>(theta: A) -> S { tan(theta).recip() }
#[inline] pub fn sec<S: Float, A: Angle<S>>(theta: A) -> S { cos(theta).recip() }
#[inline] pub fn csc<S: Float, A: Angle<S>>(theta: A) -> S { sin(theta).recip() }

#[inline] pub fn asin<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.asin())) }
#[inline] pub fn acos<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.acos())) }
#[inline] pub fn atan<S: Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.atan())) }
#[inline] pub fn atan2<S: Float, A: Angle<S>>(a: S, b: S) -> A { Angle::from(rad(a.atan2(&b))) }

impl<S: Float> ToStr for Rad<S> { fn to_str(&self) -> ~str { fmt!("%? rad", self.s) } }
impl<S: Float> ToStr for Deg<S> { fn to_str(&self) -> ~str { fmt!("%?°", self.s) } }

impl<S: Float> ApproxEq<S> for Rad<S> {
    #[inline]
    fn approx_epsilon() -> S {
        // TODO: fix this after static methods are fixed in rustc
        fail!(~"Doesn't work!");
    }

    #[inline]
    fn approx_eq(&self, other: &Rad<S>) -> bool {
        self.s.approx_eq(&other.s)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Rad<S>, approx_epsilon: &S) -> bool {
        self.s.approx_eq_eps(&other.s, approx_epsilon)
    }
}

impl<S: Float> ApproxEq<S> for Deg<S> {
    #[inline]
    fn approx_epsilon() -> S {
        // TODO: fix this after static methods are fixed in rustc
        fail!(~"Doesn't work!");
    }

    #[inline]
    fn approx_eq(&self, other: &Deg<S>) -> bool {
        self.s.approx_eq(&other.s)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Deg<S>, approx_epsilon: &S) -> bool {
        self.s.approx_eq_eps(&other.s, approx_epsilon)
    }
}
<|endoftext|>