<commit_before>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::*;

use cocoa::foundation::NSUInteger;

#[repr(u64)]
#[derive(Clone, Debug)]
pub enum MTLLoadAction {
    DontCare = 0,
    Load = 1,
    Clear = 2,
}

#[repr(u64)]
#[derive(Clone, Debug)]
pub enum MTLStoreAction {
    DontCare = 0,
    Store = 1,
    MultisampleResolve = 2,
    StoreAndMultisampleResolve = 3,
    Unknown = 4,
    CustomSampleDepthStore = 5,
}

#[repr(C)]
#[derive(Clone, Debug)]
pub struct MTLClearColor {
    red: f64,
    green: f64,
    blue: f64,
    alpha: f64
}

impl MTLClearColor {
    #[inline]
    pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
        MTLClearColor {
            red,
            green,
            blue,
            alpha
        }
    }
}

#[repr(u32)]
#[allow(non_camel_case_types)]
pub enum MTLMultisampleStencilResolveFilter {
    Sample0 = 0,
    DepthResolvedSample = 1,
}

pub enum MTLRenderPassAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptorRef;
}

impl RenderPassAttachmentDescriptorRef {
    pub fn texture(&self) -> Option<&TextureRef> {
        unsafe {
            msg_send![self, texture]
        }
    }

    pub fn set_texture(&self, texture: Option<&TextureRef>) {
        unsafe {
            msg_send![self, setTexture:texture];
        }
    }

    pub fn level(&self) -> NSUInteger {
        unsafe {
            msg_send![self, level]
        }
    }

    pub fn set_level(&self, level: NSUInteger) {
        unsafe {
            msg_send![self, setLevel:level]
        }
    }

    pub fn slice(&self) -> NSUInteger {
        unsafe {
            msg_send![self, slice]
        }
    }

    pub fn set_slice(&self, slice: NSUInteger) {
        unsafe {
            msg_send![self, setSlice:slice]
        }
    }

    pub fn depth_plane(&self) -> NSUInteger {
        unsafe {
            msg_send![self, depthPlane]
        }
    }

    pub fn set_depth_plane(&self, depth_plane: NSUInteger) {
        unsafe {
            msg_send![self, setDepthPlane:depth_plane]
        }
    }

    pub fn resolve_texture(&self) -> Option<&TextureRef> {
        unsafe {
            msg_send![self, resolveTexture]
        }
    }

    pub fn set_resolve_texture(&self, resolve_texture: Option<&TextureRef>) {
        unsafe {
            msg_send![self, setResolveTexture:resolve_texture]
        }
    }

    pub fn resolve_level(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveLevel]
        }
    }

    pub fn set_resolve_level(&self, resolve_level: NSUInteger) {
        unsafe {
            msg_send![self, setResolveLevel:resolve_level]
        }
    }

    pub fn resolve_slice(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveSlice]
        }
    }

    pub fn set_resolve_slice(&self, resolve_slice: NSUInteger) {
        unsafe {
            msg_send![self, setResolveSlice:resolve_slice]
        }
    }

    pub fn resolve_depth_plane(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveDepthPlane]
        }
    }

    pub fn set_resolve_depth_plane(&self, resolve_depth_plane: NSUInteger) {
        unsafe {
            msg_send![self, setResolveDepthPlane:resolve_depth_plane]
        }
    }

    pub fn load_action(&self) -> MTLLoadAction {
        unsafe {
            msg_send![self, loadAction]
        }
    }

    pub fn set_load_action(&self, load_action: MTLLoadAction) {
        unsafe {
            msg_send![self, setLoadAction:load_action]
        }
    }

    pub fn store_action(&self) -> MTLStoreAction {
        unsafe {
            msg_send![self, storeAction]
        }
    }

    pub fn set_store_action(&self, store_action: MTLStoreAction) {
        unsafe {
            msg_send![self, setStoreAction:store_action]
        }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassColorAttachmentDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLRenderPassColorAttachmentDescriptor);
            msg_send![class, new]
        }
    }
}

impl RenderPassColorAttachmentDescriptorRef {
    pub fn clear_color(&self) -> MTLClearColor {
        unsafe {
            msg_send![self, clearColor]
        }
    }

    pub fn set_clear_color(&self, clear_color: MTLClearColor) {
        unsafe {
            msg_send![self, setClearColor:clear_color]
        }
    }
}

pub enum MTLRenderPassDepthAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassDepthAttachmentDescriptorRef {
    pub fn clear_depth(&self) -> f64 {
        unsafe {
            msg_send![self, clearDepth]
        }
    }

    pub fn set_clear_depth(&self, clear_depth: f64) {
        unsafe {
            msg_send![self, setClearDepth:clear_depth]
        }
    }
}

pub enum MTLRenderPassStencilAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassStencilAttachmentDescriptorRef {
    pub fn clear_stencil(&self) -> u32 {
        unsafe {
            msg_send![self, clearStencil]
        }
    }

    pub fn set_clear_stencil(&self, clear_stencil: u32) {
        unsafe {
            msg_send![self, setClearStencil:clear_stencil]
        }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptorArray {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArrayRef;
}

impl RenderPassColorAttachmentDescriptorArrayRef {
    pub fn object_at(&self, index: usize) -> Option<&RenderPassColorAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, objectAtIndexedSubscript:index]
        }
    }

    pub fn set_object_at(&self, index: usize, attachment: Option<&RenderPassColorAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setObject:attachment
                     atIndexedSubscript:index]
        }
    }
}

pub enum MTLRenderPassDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDescriptor;
    pub struct RenderPassDescriptor;
    pub struct RenderPassDescriptorRef;
}

impl RenderPassDescriptor {
    pub fn new<'a>() -> &'a RenderPassDescriptorRef {
        unsafe {
            let class = class!(MTLRenderPassDescriptorInternal);
            msg_send![class, renderPassDescriptor]
        }
    }
}

impl RenderPassDescriptorRef {
    pub fn color_attachments(&self) -> &RenderPassColorAttachmentDescriptorArrayRef {
        unsafe {
            msg_send![self, colorAttachments]
        }
    }

    pub fn depth_attachment(&self) -> Option<&RenderPassDepthAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, depthAttachment]
        }
    }

    pub fn set_depth_attachment(&self, depth_attachment: Option<&RenderPassDepthAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setDepthAttachment:depth_attachment]
        }
    }

    pub fn stencil_attachment(&self) -> Option<&RenderPassStencilAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, stencilAttachment]
        }
    }

    pub fn set_stencil_attachment(&self, stencil_attachment: Option<&RenderPassStencilAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setStencilAttachment:stencil_attachment]
        }
    }

    pub fn visibility_result_buffer(&self) -> Option<&BufferRef> {
        unsafe {
            msg_send![self, visibilityResultBuffer]
        }
    }

    pub fn set_visibility_result_buffer(&self, buffer: Option<&BufferRef>) {
        unsafe {
            msg_send![self, setVisibilityResultBuffer:buffer]
        }
    }

    pub fn render_target_array_length(&self) -> NSUInteger {
        unsafe {
            msg_send![self, renderTargetArrayLength]
        }
    }

    pub fn set_render_target_array_length(&self, length: NSUInteger) {
        unsafe {
            msg_send![self, setRenderTargetArrayLength:length]
        }
    }
}
<commit_msg>[MTLRenderPassStencilAttachmentDescriptor] add stencilResolveFilter<commit_after>// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::*;

use cocoa::foundation::NSUInteger;

#[repr(u64)]
#[derive(Clone, Debug)]
pub enum MTLLoadAction {
    DontCare = 0,
    Load = 1,
    Clear = 2,
}

#[repr(u64)]
#[derive(Clone, Debug)]
pub enum MTLStoreAction {
    DontCare = 0,
    Store = 1,
    MultisampleResolve = 2,
    StoreAndMultisampleResolve = 3,
    Unknown = 4,
    CustomSampleDepthStore = 5,
}

#[repr(C)]
#[derive(Clone, Debug)]
pub struct MTLClearColor {
    red: f64,
    green: f64,
    blue: f64,
    alpha: f64
}

impl MTLClearColor {
    #[inline]
    pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
        MTLClearColor {
            red,
            green,
            blue,
            alpha
        }
    }
}

#[repr(u32)]
#[allow(non_camel_case_types)]
pub enum MTLMultisampleStencilResolveFilter {
    Sample0 = 0,
    DepthResolvedSample = 1,
}

pub enum MTLRenderPassAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptor;
    pub struct RenderPassAttachmentDescriptorRef;
}

impl RenderPassAttachmentDescriptorRef {
    pub fn texture(&self) -> Option<&TextureRef> {
        unsafe {
            msg_send![self, texture]
        }
    }

    pub fn set_texture(&self, texture: Option<&TextureRef>) {
        unsafe {
            msg_send![self, setTexture:texture];
        }
    }

    pub fn level(&self) -> NSUInteger {
        unsafe {
            msg_send![self, level]
        }
    }

    pub fn set_level(&self, level: NSUInteger) {
        unsafe {
            msg_send![self, setLevel:level]
        }
    }

    pub fn slice(&self) -> NSUInteger {
        unsafe {
            msg_send![self, slice]
        }
    }

    pub fn set_slice(&self, slice: NSUInteger) {
        unsafe {
            msg_send![self, setSlice:slice]
        }
    }

    pub fn depth_plane(&self) -> NSUInteger {
        unsafe {
            msg_send![self, depthPlane]
        }
    }

    pub fn set_depth_plane(&self, depth_plane: NSUInteger) {
        unsafe {
            msg_send![self, setDepthPlane:depth_plane]
        }
    }

    pub fn resolve_texture(&self) -> Option<&TextureRef> {
        unsafe {
            msg_send![self, resolveTexture]
        }
    }

    pub fn set_resolve_texture(&self, resolve_texture: Option<&TextureRef>) {
        unsafe {
            msg_send![self, setResolveTexture:resolve_texture]
        }
    }

    pub fn resolve_level(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveLevel]
        }
    }

    pub fn set_resolve_level(&self, resolve_level: NSUInteger) {
        unsafe {
            msg_send![self, setResolveLevel:resolve_level]
        }
    }

    pub fn resolve_slice(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveSlice]
        }
    }

    pub fn set_resolve_slice(&self, resolve_slice: NSUInteger) {
        unsafe {
            msg_send![self, setResolveSlice:resolve_slice]
        }
    }

    pub fn resolve_depth_plane(&self) -> NSUInteger {
        unsafe {
            msg_send![self, resolveDepthPlane]
        }
    }

    pub fn set_resolve_depth_plane(&self, resolve_depth_plane: NSUInteger) {
        unsafe {
            msg_send![self, setResolveDepthPlane:resolve_depth_plane]
        }
    }

    pub fn load_action(&self) -> MTLLoadAction {
        unsafe {
            msg_send![self, loadAction]
        }
    }

    pub fn set_load_action(&self, load_action: MTLLoadAction) {
        unsafe {
            msg_send![self, setLoadAction:load_action]
        }
    }

    pub fn store_action(&self) -> MTLStoreAction {
        unsafe {
            msg_send![self, storeAction]
        }
    }

    pub fn set_store_action(&self, store_action: MTLStoreAction) {
        unsafe {
            msg_send![self, setStoreAction:store_action]
        }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptor;
    pub struct RenderPassColorAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassColorAttachmentDescriptor {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLRenderPassColorAttachmentDescriptor);
            msg_send![class, new]
        }
    }
}

impl RenderPassColorAttachmentDescriptorRef {
    pub fn clear_color(&self) -> MTLClearColor {
        unsafe {
            msg_send![self, clearColor]
        }
    }

    pub fn set_clear_color(&self, clear_color: MTLClearColor) {
        unsafe {
            msg_send![self, setClearColor:clear_color]
        }
    }
}

pub enum MTLRenderPassDepthAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptor;
    pub struct RenderPassDepthAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassDepthAttachmentDescriptorRef {
    pub fn clear_depth(&self) -> f64 {
        unsafe {
            msg_send![self, clearDepth]
        }
    }

    pub fn set_clear_depth(&self, clear_depth: f64) {
        unsafe {
            msg_send![self, setClearDepth:clear_depth]
        }
    }
}

pub enum MTLRenderPassStencilAttachmentDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptor;
    pub struct RenderPassStencilAttachmentDescriptorRef;
    type ParentType = RenderPassAttachmentDescriptorRef;
}

impl RenderPassStencilAttachmentDescriptorRef {
    pub fn clear_stencil(&self) -> u32 {
        unsafe {
            msg_send![self, clearStencil]
        }
    }

    pub fn set_clear_stencil(&self, clear_stencil: u32) {
        unsafe {
            msg_send![self, setClearStencil:clear_stencil]
        }
    }

    pub fn stencil_resolve_filter(&self) -> MTLMultisampleStencilResolveFilter {
        unsafe {
            msg_send![self, stencilResolveFilter]
        }
    }

    pub fn set_stencil_resolve_filter(&self, stencil_resolve_filter: MTLMultisampleStencilResolveFilter) {
        unsafe {
            msg_send![self, setStencilResolveFilter: stencil_resolve_filter]
        }
    }
}

pub enum MTLRenderPassColorAttachmentDescriptorArray {}

foreign_obj_type! {
    type CType = MTLRenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArray;
    pub struct RenderPassColorAttachmentDescriptorArrayRef;
}

impl RenderPassColorAttachmentDescriptorArrayRef {
    pub fn object_at(&self, index: usize) -> Option<&RenderPassColorAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, objectAtIndexedSubscript:index]
        }
    }

    pub fn set_object_at(&self, index: usize, attachment: Option<&RenderPassColorAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setObject:attachment
                     atIndexedSubscript:index]
        }
    }
}

pub enum MTLRenderPassDescriptor {}

foreign_obj_type! {
    type CType = MTLRenderPassDescriptor;
    pub struct RenderPassDescriptor;
    pub struct RenderPassDescriptorRef;
}

impl RenderPassDescriptor {
    pub fn new<'a>() -> &'a RenderPassDescriptorRef {
        unsafe {
            let class = class!(MTLRenderPassDescriptorInternal);
            msg_send![class, renderPassDescriptor]
        }
    }
}

impl RenderPassDescriptorRef {
    pub fn color_attachments(&self) -> &RenderPassColorAttachmentDescriptorArrayRef {
        unsafe {
            msg_send![self, colorAttachments]
        }
    }

    pub fn depth_attachment(&self) -> Option<&RenderPassDepthAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, depthAttachment]
        }
    }

    pub fn set_depth_attachment(&self, depth_attachment: Option<&RenderPassDepthAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setDepthAttachment:depth_attachment]
        }
    }

    pub fn stencil_attachment(&self) -> Option<&RenderPassStencilAttachmentDescriptorRef> {
        unsafe {
            msg_send![self, stencilAttachment]
        }
    }

    pub fn set_stencil_attachment(&self, stencil_attachment: Option<&RenderPassStencilAttachmentDescriptorRef>) {
        unsafe {
            msg_send![self, setStencilAttachment:stencil_attachment]
        }
    }

    pub fn visibility_result_buffer(&self) -> Option<&BufferRef> {
        unsafe {
            msg_send![self, visibilityResultBuffer]
        }
    }

    pub fn set_visibility_result_buffer(&self, buffer: Option<&BufferRef>) {
        unsafe {
            msg_send![self, setVisibilityResultBuffer:buffer]
        }
    }

    pub fn render_target_array_length(&self) -> NSUInteger {
        unsafe {
            msg_send![self, renderTargetArrayLength]
        }
    }

    pub fn set_render_target_array_length(&self, length: NSUInteger) {
        unsafe {
            msg_send![self, setRenderTargetArrayLength:length]
        }
    }
}
<|endoftext|>


<commit_before>use cargotest::ChannelChanger;
use cargotest::support::{basic_bin_manifest, execs, main_file, project};
use hamcrest::{assert_that, existing_file, is_not};

#[test]
fn cargo_build_plan_simple() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
        .build();

    assert_that(
        p.cargo("build")
            .masquerade_as_nightly_cargo()
            .arg("--build-plan")
            .arg("-Zunstable-options"),
        execs().with_status(0).with_json(
            r#"
    {
        "inputs": [
            "[..][/]foo[/]Cargo.toml"
        ],
        "invocations": [
            {
                "args": "{...}",
                "cwd": "[..][/]target[/]cit[/][..][/]foo",
                "deps": [],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": "{...}",
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "rustc",
                "target_kind": ["bin"]
            }
        ]
    }
    "#,
        ),
    );
    assert_that(&p.bin("foo"), is_not(existing_file()));
}

#[test]
fn cargo_build_plan_single_dep() {
    let p = project("foo")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            authors = []
            version = "0.5.0"

            [dependencies]
            bar = { path = "bar" }
        "#,
        )
        .file(
            "src/lib.rs",
            r#"
            extern crate bar;
            pub fn foo() { bar::bar(); }

            #[test]
            fn test() { foo(); }
        "#,
        )
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []
        "#,
        )
        .file("bar/src/lib.rs", "pub fn bar() {}")
        .build();
    assert_that(
        p.cargo("build")
            .masquerade_as_nightly_cargo()
            .arg("--build-plan")
            .arg("-Zunstable-options"),
        execs().with_status(0).with_json(
            r#"
    {
        "inputs": [
            "[..][/]foo[/]Cargo.toml",
            "[..][/]foo[/]bar[/]Cargo.toml"
        ],
        "invocations": [
            {
                "args": "{...}",
                "cwd": "[..][/]target[/]cit[/][..][/]foo",
                "deps": [],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": [
                    "[..][/]foo[/]target[/]debug[/]deps[/]libbar-[..].rlib"
                ],
                "package_name": "bar",
                "package_version": "0.0.1",
                "program": "rustc",
                "target_kind": ["lib"]
            },
            {
                "args": "{...}",
                "cwd": "[..][/]target[/]cit[/][..][/]foo",
                "deps": [0],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": [
                    "[..][/]foo[/]target[/]debug[/]deps[/]libfoo-[..].rlib"
                ],
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "rustc",
                "target_kind": ["lib"]
            }
        ]
    }
    "#,
        ),
    );
}

#[test]
fn cargo_build_plan_build_script() {
    let p = project("foo")
        .file(
            "Cargo.toml",
            r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#,
        )
        .file("src/main.rs", r#"fn main() {}"#)
        .file("build.rs", r#"fn main() {}"#)
        .build();

    assert_that(
        p.cargo("build")
            .masquerade_as_nightly_cargo()
            .arg("--build-plan")
            .arg("-Zunstable-options"),
        execs().with_status(0).with_json(
            r#"
    {
        "inputs": [
            "[..][/]foo[/]Cargo.toml"
        ],
        "invocations": [
            {
                "args": "{...}",
                "cwd": "[..][/]target[/]cit[/][..][/]foo",
                "deps": [],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": [
                    "[..][/]foo[/]target[/]debug[/]build[/][..][/]build_script_build-[..]"
                ],
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "rustc",
                "target_kind": ["custom-build"]
            },
            {
                "args": "{...}",
                "cwd": "[..][/]target[/]cit[/][..][/]foo",
                "deps": [0],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": [],
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "[..][/]build-script-build",
                "target_kind": ["custom-build"]
            },
            {
                "args": "{...}",
                "cwd": "[..][/]target[/]cit[/][..][/]foo",
                "deps": [1],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": "{...}",
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "rustc",
                "target_kind": ["bin"]
            }
        ]
    }
    "#,
        ),
    );
}
<commit_msg>Fix tests when CARGO_TARGET_DIR is set.<commit_after>use cargotest::ChannelChanger;
use cargotest::support::{basic_bin_manifest, execs, main_file, project};
use hamcrest::{assert_that, existing_file, is_not};

#[test]
fn cargo_build_plan_simple() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
        .build();

    assert_that(
        p.cargo("build")
            .masquerade_as_nightly_cargo()
            .arg("--build-plan")
            .arg("-Zunstable-options"),
        execs().with_status(0).with_json(
            r#"
    {
        "inputs": [
            "[..][/]foo[/]Cargo.toml"
        ],
        "invocations": [
            {
                "args": "{...}",
                "cwd": "[..][/]cit[/][..][/]foo",
                "deps": [],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": "{...}",
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "rustc",
                "target_kind": ["bin"]
            }
        ]
    }
    "#,
        ),
    );
    assert_that(&p.bin("foo"), is_not(existing_file()));
}

#[test]
fn cargo_build_plan_single_dep() {
    let p = project("foo")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            authors = []
            version = "0.5.0"

            [dependencies]
            bar = { path = "bar" }
        "#,
        )
        .file(
            "src/lib.rs",
            r#"
            extern crate bar;
            pub fn foo() { bar::bar(); }

            #[test]
            fn test() { foo(); }
        "#,
        )
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []
        "#,
        )
        .file("bar/src/lib.rs", "pub fn bar() {}")
        .build();
    assert_that(
        p.cargo("build")
            .masquerade_as_nightly_cargo()
            .arg("--build-plan")
            .arg("-Zunstable-options"),
        execs().with_status(0).with_json(
            r#"
    {
        "inputs": [
            "[..][/]foo[/]Cargo.toml",
            "[..][/]foo[/]bar[/]Cargo.toml"
        ],
        "invocations": [
            {
                "args": "{...}",
                "cwd": "[..][/]cit[/][..][/]foo",
                "deps": [],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": [
                    "[..][/]foo[/]target[/]debug[/]deps[/]libbar-[..].rlib"
                ],
                "package_name": "bar",
                "package_version": "0.0.1",
                "program": "rustc",
                "target_kind": ["lib"]
            },
            {
                "args": "{...}",
                "cwd": "[..][/]cit[/][..][/]foo",
                "deps": [0],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": [
                    "[..][/]foo[/]target[/]debug[/]deps[/]libfoo-[..].rlib"
                ],
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "rustc",
                "target_kind": ["lib"]
            }
        ]
    }
    "#,
        ),
    );
}

#[test]
fn cargo_build_plan_build_script() {
    let p = project("foo")
        .file(
            "Cargo.toml",
            r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#,
        )
        .file("src/main.rs", r#"fn main() {}"#)
        .file("build.rs", r#"fn main() {}"#)
        .build();

    assert_that(
        p.cargo("build")
            .masquerade_as_nightly_cargo()
            .arg("--build-plan")
            .arg("-Zunstable-options"),
        execs().with_status(0).with_json(
            r#"
    {
        "inputs": [
            "[..][/]foo[/]Cargo.toml"
        ],
        "invocations": [
            {
                "args": "{...}",
                "cwd": "[..][/]cit[/][..][/]foo",
                "deps": [],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": [
                    "[..][/]foo[/]target[/]debug[/]build[/][..][/]build_script_build-[..]"
                ],
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "rustc",
                "target_kind": ["custom-build"]
            },
            {
                "args": "{...}",
                "cwd": "[..][/]cit[/][..][/]foo",
                "deps": [0],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": [],
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "[..][/]build-script-build",
                "target_kind": ["custom-build"]
            },
            {
                "args": "{...}",
                "cwd": "[..][/]cit[/][..][/]foo",
                "deps": [1],
                "env": "{...}",
                "kind": "Host",
                "links": "{...}",
                "outputs": "{...}",
                "package_name": "foo",
                "package_version": "0.5.0",
                "program": "rustc",
                "target_kind": ["bin"]
            }
        ]
    }
    "#,
        ),
    );
}
<|endoftext|>


<commit_before>//! Implements the searching of the game tree.

pub mod alpha_beta;
pub mod threading;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use chess_move::*;
use position::Position;
use tt::*;
use self::threading::*;

/// The maximum search depth in half-moves.
pub const MAX_DEPTH: u8 = 63; // Should be less than 127.

/// The half-with of the initial aspiration window in centipawns.
pub const INITIAL_ASPIRATION_WINDOW: Value = 17; // 16;

/// The number of nodes that will be searched without reporting search
/// progress.
///
/// If this value is too small the engine may become slow, if this
/// value is too big the engine may become unresponsive.
pub const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}

/// Contains information about the current progress of a search.
pub struct SearchStatus {
    started_at: Option<SystemTime>,

    /// The starting position for the search.
    position: Position,

    /// `true` if the search is finished or has been stopped, `false`
    /// otherwise.
    pub done: bool,

    /// The reached search depth.
    pub depth: u8,

    pub variations: Vec<Variation>,

    /// Number of milliseconds since the beginning of the search.
    pub duration_millis: u64,

    /// Number of analyzed nodes since the beginning of the search.
    pub searched_nodes: NodeCount,

    /// Number of analyzed nodes per second.
    pub nps: NodeCount,
}

/// A thread that executes consecutive searches in different starting
/// positions.
pub struct SearchThread {
    tt: Arc<Tt>,
    status: SearchStatus,

    // A handle to the search thread.
    search_thread: Option<thread::JoinHandle<()>>,

    // A channel for sending commands to the search thread.
    commands: Sender<Command>,

    // A channel for receiving reports from the search thread.
    reports: Receiver<Report>,
}

impl SearchThread {
    /// Creates a new instance.
    pub fn new(tt: Arc<Tt>) -> SearchThread {

        // Spawn the search thread.
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt_clone = tt.clone();
        let search_thread = thread::spawn(move || {
            serve_deepening(tt_clone, commands_rx, reports_tx);
        });

        SearchThread {
            tt: tt,
            search_thread: Some(search_thread),
            commands: commands_tx,
            reports: reports_rx,
            status: SearchStatus {
                started_at: None,
                position: Position::from_fen(::STARTING_POSITION).ok().unwrap(),
                done: true,
                depth: 0,
                variations: vec![Variation {
                                     value: -19999,
                                     bound: BOUND_LOWER,
                                     moves: vec![],
                                 }],
                searched_nodes: 0,
                duration_millis: 0,
                nps: 0,
            },
        }
    }

    /// Stops the current search, starts a new search, updates the
    /// status.
    ///
    /// `position` is the starting position for the new
    /// search. `variation_count` specifies how many best lines to
    /// calculate (the first move in each best line will be
    /// different). `searchmoves` may restrict the analysis to the
    /// supplied subset of moves only. The move format is long
    /// algebraic notation. Examples: e2e4, e7e5, e1g1 (white short
    /// castling), e7e8q (for promotion).
    #[allow(unused_variables)]
    pub fn search(&mut self,
                  position: &Position,
                  variation_count: usize,
                  searchmoves: Option<Vec<String>>) {
        // TODO: We ignore the "variation_count" parameter.

        // TODO: We ignore the "searchmoves" parameter.

        // TODO: Add `self.legal_moves_count` filed.

        self.stop();
        self.commands
            .send(Command::Search {
                search_id: 0,
                position: position.clone(),
                depth: MAX_DEPTH,
                lower_bound: -29999,
                upper_bound: 29999,
            })
            .unwrap();
        self.status = SearchStatus {
            started_at: Some(SystemTime::now()),
            position: position.clone(),
            done: false,
            depth: 0,
            variations: vec![Variation {
                                 value: -19999,
                                 bound: BOUND_LOWER,
                                 moves: vec![],
                             }], // TODO: Set good initial value (vec![best_move]).
            searched_nodes: 0,
            duration_millis: 0,
            ..self.status
        };
    }

    /// Stops the current search, updates the status.
    ///
    /// Does nothing if the current search is already stopped.
    pub fn stop(&mut self) {
        self.commands.send(Command::Stop).unwrap();
        while !self.status().done {
            let r = self.reports.recv().unwrap();
            self.process_report(r);
        }
    }

    /// Updates the status of the current search.
    pub fn update_status(&mut self) {
        while let Ok(r) = self.reports.try_recv() {
            self.process_report(r)
        }
    }

    /// Returns the status of the current search.
    ///
    /// **Important note:** Consecutive calls to this method will
    /// return the same unchanged result. Only after calling `search`,
    /// `stop`, or `update_status`, the result returned by `status`
    /// may change.
    #[inline(always)]
    pub fn status(&self) -> &SearchStatus {
        &self.status
    }

    /// Stops the current search and joins the search thread.
    ///
    /// After calling `join`, no other methods on this instance should
    /// be called.
    pub fn join(&mut self) {
        self.stop();
        self.commands.send(Command::Exit).unwrap();
        self.search_thread.take().unwrap().join().unwrap();
    }

    // A helper method. It updates the current status according to the
    // received report message.
    pub fn process_report(&mut self, report: Report) {
        let duration = self.status.started_at.unwrap().elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        if self.status.depth < report.depth {
            self.status.depth = report.depth;
            self.status.variations = vec![extract_pv(&self.tt,
                                                     &self.status.position,
                                                     report.depth)];
        }
        self.status.done = report.done;
    }
}

// A helper function. It extracts the primary variation (PV) from the
// transposition table (TT) and returns it.
//
// **Note:** Because the PV is a moving target (the search
// continues to run in parallel), imperfections in the reported
// PVs are unavoidable. To deal with this, we turn a blind eye if
// the value at the root of the PV differs from the value at the
// leaf by no more than `EPSILON`.
fn extract_pv(tt: &Tt, position: &Position, depth: u8) -> Variation {
    const EPSILON: Value = 8; // A sufficiently small value (in centipawns).

    // Extract the PV, the leaf value, the root value, and the bound
    // type from the TT.
    let mut p = position.clone();
    let mut our_turn = true;
    let mut prev_move = None;
    let mut moves = Vec::new();
    let mut leaf_value = -19999;
    let mut root_value = leaf_value;
    let mut bound = BOUND_LOWER;
    while let Some(entry) = tt.peek(p.hash()) {
        if entry.bound() != BOUND_NONE {
            // Get the value and the bound type. In half of the
            // cases the value stored in `entry` is from other
            // side's perspective.
            if our_turn {
                leaf_value = entry.value();
                bound = entry.bound();
            } else {
                leaf_value = -entry.value();
                bound = match entry.bound() {
                    BOUND_UPPER => BOUND_LOWER,
                    BOUND_LOWER => BOUND_UPPER,
                    x => x,
                };
            }

            // The values under -19999 and over 19999 carry
            // information about in how many moves is the
            // inevitable checkmate. However, do not show this to
            // the user, because it is sometimes incorrect.
            if leaf_value >= 20000 {
                leaf_value = 19999;
                if bound == BOUND_LOWER {
                    bound = BOUND_EXACT
                }
            }
            if leaf_value <= -20000 {
                leaf_value = -19999;
                if bound == BOUND_UPPER {
                    bound = BOUND_EXACT
                }
            }

            if let Some(m) = prev_move {
                // Extend the PV with the previous move.
                moves.push(m);
            } else {
                // We are at the root -- set the root value.
                root_value = leaf_value;
            }

            if moves.len() < depth as usize && (leaf_value - root_value).abs() <= EPSILON {
                if let Some(m) = p.try_move_digest(entry.move16()) {
                    if p.do_move(m) {
                        if bound == BOUND_EXACT {
                            // Extend the PV with one more move.
                            prev_move = Some(m);
                            our_turn = !our_turn;
                            continue;
                        } else {
                            // This is the last move in the PV.
                            moves.push(m);
                        }
                    }
                }
            }
        }
        break;
    }

    // Change the bound type if the leaf value in the PV differs too
    // much from the root value.
    bound = match leaf_value - root_value {
        x if x > EPSILON && bound != BOUND_UPPER => BOUND_LOWER,
        x if x < -EPSILON && bound != BOUND_LOWER => BOUND_UPPER,
        _ => bound,
    };

    Variation {
        value: root_value,
        bound: bound,
        moves: moves,
    }
}
<commit_msg>make method private<commit_after>//! Implements the searching of the game tree.

pub mod alpha_beta;
pub mod threading;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use chess_move::*;
use position::Position;
use tt::*;
use self::threading::*;

/// The maximum search depth in half-moves.
pub const MAX_DEPTH: u8 = 63; // Should be less than 127.

/// The half-with of the initial aspiration window in centipawns.
pub const INITIAL_ASPIRATION_WINDOW: Value = 17; // 16;

/// The number of nodes that will be searched without reporting search
/// progress.
///
/// If this value is too small the engine may become slow, if this
/// value is too big the engine may become unresponsive.
pub const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}

/// Contains information about the current progress of a search.
pub struct SearchStatus {
    started_at: Option<SystemTime>,

    /// The starting position for the search.
    position: Position,

    /// `true` if the search is finished or has been stopped, `false`
    /// otherwise.
    pub done: bool,

    /// The reached search depth.
    pub depth: u8,

    pub variations: Vec<Variation>,

    /// Number of milliseconds since the beginning of the search.
    pub duration_millis: u64,

    /// Number of analyzed nodes since the beginning of the search.
    pub searched_nodes: NodeCount,

    /// Number of analyzed nodes per second.
    pub nps: NodeCount,
}

/// A thread that executes consecutive searches in different starting
/// positions.
pub struct SearchThread {
    tt: Arc<Tt>,
    status: SearchStatus,

    // A handle to the search thread.
    search_thread: Option<thread::JoinHandle<()>>,

    // A channel for sending commands to the search thread.
    commands: Sender<Command>,

    // A channel for receiving reports from the search thread.
    reports: Receiver<Report>,
}

impl SearchThread {
    /// Creates a new instance.
    pub fn new(tt: Arc<Tt>) -> SearchThread {

        // Spawn the search thread.
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt_clone = tt.clone();
        let search_thread = thread::spawn(move || {
            serve_deepening(tt_clone, commands_rx, reports_tx);
        });

        SearchThread {
            tt: tt,
            search_thread: Some(search_thread),
            commands: commands_tx,
            reports: reports_rx,
            status: SearchStatus {
                started_at: None,
                position: Position::from_fen(::STARTING_POSITION).ok().unwrap(),
                done: true,
                depth: 0,
                variations: vec![Variation {
                                     value: -19999,
                                     bound: BOUND_LOWER,
                                     moves: vec![],
                                 }],
                searched_nodes: 0,
                duration_millis: 0,
                nps: 0,
            },
        }
    }

    /// Stops the current search, starts a new search, updates the
    /// status.
    ///
    /// `position` is the starting position for the new
    /// search. `variation_count` specifies how many best lines to
    /// calculate (the first move in each best line will be
    /// different). `searchmoves` may restrict the analysis to the
    /// supplied subset of moves only. The move format is long
    /// algebraic notation. Examples: e2e4, e7e5, e1g1 (white short
    /// castling), e7e8q (for promotion).
    #[allow(unused_variables)]
    pub fn search(&mut self,
                  position: &Position,
                  variation_count: usize,
                  searchmoves: Option<Vec<String>>) {
        // TODO: We ignore the "variation_count" parameter.

        // TODO: We ignore the "searchmoves" parameter.

        // TODO: Add `self.legal_moves_count` filed.

        self.stop();
        self.commands
            .send(Command::Search {
                search_id: 0,
                position: position.clone(),
                depth: MAX_DEPTH,
                lower_bound: -29999,
                upper_bound: 29999,
            })
            .unwrap();
        self.status = SearchStatus {
            started_at: Some(SystemTime::now()),
            position: position.clone(),
            done: false,
            depth: 0,
            variations: vec![Variation {
                                 value: -19999,
                                 bound: BOUND_LOWER,
                                 moves: vec![],
                             }], // TODO: Set good initial value (vec![best_move]).
            searched_nodes: 0,
            duration_millis: 0,
            ..self.status
        };
    }

    /// Stops the current search, updates the status.
    ///
    /// Does nothing if the current search is already stopped.
    pub fn stop(&mut self) {
        self.commands.send(Command::Stop).unwrap();
        while !self.status().done {
            let r = self.reports.recv().unwrap();
            self.process_report(r);
        }
    }

    /// Updates the status of the current search.
    pub fn update_status(&mut self) {
        while let Ok(r) = self.reports.try_recv() {
            self.process_report(r)
        }
    }

    /// Returns the status of the current search.
    ///
    /// **Important note:** Consecutive calls to this method will
    /// return the same unchanged result. Only after calling `search`,
    /// `stop`, or `update_status`, the result returned by `status`
    /// may change.
    #[inline(always)]
    pub fn status(&self) -> &SearchStatus {
        &self.status
    }

    /// Stops the current search and joins the search thread.
    ///
    /// After calling `join`, no other methods on this instance should
    /// be called.
    pub fn join(&mut self) {
        self.stop();
        self.commands.send(Command::Exit).unwrap();
        self.search_thread.take().unwrap().join().unwrap();
    }

    // A helper method. It updates the current status according to the
    // received report message.
    fn process_report(&mut self, report: Report) {
        let duration = self.status.started_at.unwrap().elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        if self.status.depth < report.depth {
            self.status.depth = report.depth;
            self.status.variations = vec![extract_pv(&self.tt,
                                                     &self.status.position,
                                                     report.depth)];
        }
        self.status.done = report.done;
    }
}

// A helper function. It extracts the primary variation (PV) from the
// transposition table (TT) and returns it.
//
// **Note:** Because the PV is a moving target (the search
// continues to run in parallel), imperfections in the reported
// PVs are unavoidable. To deal with this, we turn a blind eye if
// the value at the root of the PV differs from the value at the
// leaf by no more than `EPSILON`.
fn extract_pv(tt: &Tt, position: &Position, depth: u8) -> Variation {
    const EPSILON: Value = 8; // A sufficiently small value (in centipawns).

    // Extract the PV, the leaf value, the root value, and the bound
    // type from the TT.
    let mut p = position.clone();
    let mut our_turn = true;
    let mut prev_move = None;
    let mut moves = Vec::new();
    let mut leaf_value = -19999;
    let mut root_value = leaf_value;
    let mut bound = BOUND_LOWER;
    while let Some(entry) = tt.peek(p.hash()) {
        if entry.bound() != BOUND_NONE {
            // Get the value and the bound type. In half of the
            // cases the value stored in `entry` is from other
            // side's perspective.
            if our_turn {
                leaf_value = entry.value();
                bound = entry.bound();
            } else {
                leaf_value = -entry.value();
                bound = match entry.bound() {
                    BOUND_UPPER => BOUND_LOWER,
                    BOUND_LOWER => BOUND_UPPER,
                    x => x,
                };
            }

            // The values under -19999 and over 19999 carry
            // information about in how many moves is the
            // inevitable checkmate. However, do not show this to
            // the user, because it is sometimes incorrect.
            if leaf_value >= 20000 {
                leaf_value = 19999;
                if bound == BOUND_LOWER {
                    bound = BOUND_EXACT
                }
            }
            if leaf_value <= -20000 {
                leaf_value = -19999;
                if bound == BOUND_UPPER {
                    bound = BOUND_EXACT
                }
            }

            if let Some(m) = prev_move {
                // Extend the PV with the previous move.
                moves.push(m);
            } else {
                // We are at the root -- set the root value.
                root_value = leaf_value;
            }

            if moves.len() < depth as usize && (leaf_value - root_value).abs() <= EPSILON {
                if let Some(m) = p.try_move_digest(entry.move16()) {
                    if p.do_move(m) {
                        if bound == BOUND_EXACT {
                            // Extend the PV with one more move.
                            prev_move = Some(m);
                            our_turn = !our_turn;
                            continue;
                        } else {
                            // This is the last move in the PV.
                            moves.push(m);
                        }
                    }
                }
            }
        }
        break;
    }

    // Change the bound type if the leaf value in the PV differs too
    // much from the root value.
    bound = match leaf_value - root_value {
        x if x > EPSILON && bound != BOUND_UPPER => BOUND_LOWER,
        x if x < -EPSILON && bound != BOUND_LOWER => BOUND_UPPER,
        _ => bound,
    };

    Variation {
        value: root_value,
        bound: bound,
        moves: moves,
    }
}
<|endoftext|>


<commit_before>use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span;
use crate::utils::paths;
use crate::utils::{
    in_macro, match_trait_method, match_type,
    remove_blocks, snippet,
    span_lint_and_sugg,
};
use if_chain::if_chain;
use crate::syntax::ast::Ident;

#[derive(Clone)]
pub struct Pass;

/// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests
/// `iterator.cloned()` instead
///
/// **Why is this bad?** Readability, this can be written more concisely
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// let x = vec![42, 43];
/// let y = x.iter();
/// let z = y.map(|i| *i);
/// ```
///
/// The correct use would be:
///
/// ```rust
/// let x = vec![42, 43];
/// let y = x.iter();
/// let z = y.cloned();
/// ```
declare_clippy_lint! {
    pub MAP_CLONE,
    style,
    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
}

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

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) {
        if in_macro(e.span) {
            return;
        }

        if_chain! {
            if let hir::ExprKind::MethodCall(ref method, _, ref args) = e.node;
            if args.len() == 2;
            if method.ident.as_str() == "map";
            let ty = cx.tables.expr_ty(&args[0]);
            if match_type(cx, ty, &paths::OPTION) || match_trait_method(cx, e, &paths::ITERATOR);
            if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].node;
            let closure_body = cx.tcx.hir.body(body_id);
            let closure_expr = remove_blocks(&closure_body.value);
            then {
                match closure_body.arguments[0].pat.node {
                    hir::PatKind::Ref(ref inner, _) => if let hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) = inner.node {
                        lint(cx, e.span, args[0].span, name, closure_expr);
                    },
                    hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => match closure_expr.node {
                        hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => lint(cx, e.span, args[0].span, name, inner),
                        hir::ExprKind::MethodCall(ref method, _, ref obj) => if method.ident.as_str() == "clone" {
                            if match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
                                lint(cx, e.span, args[0].span, name, &obj[0]);
                            }
                        }
                        _ => {},
                    },
                    _ => {},
                }
            }
        }
    }
}

fn lint(cx: &LateContext<'_, '_>, replace: Span, root: Span, name: Ident, path: &hir::Expr) {
    if let hir::ExprKind::Path(hir::QPath::Resolved(None, ref path)) = path.node {
        if path.segments.len() == 1 && path.segments[0].ident == name {
            span_lint_and_sugg(
                cx,
                MAP_CLONE,
                replace,
                "You are using an explicit closure for cloning elements",
                "Consider calling the dedicated `cloned` method",
                format!("{}.cloned()", snippet(cx, root, "..")),
            )
        }
    }
}<commit_msg>FIx dogfood<commit_after>use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span;
use crate::utils::paths;
use crate::utils::{
    in_macro, match_trait_method, match_type,
    remove_blocks, snippet,
    span_lint_and_sugg,
};
use if_chain::if_chain;
use crate::syntax::ast::Ident;

#[derive(Clone)]
pub struct Pass;

/// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests
/// `iterator.cloned()` instead
///
/// **Why is this bad?** Readability, this can be written more concisely
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// let x = vec![42, 43];
/// let y = x.iter();
/// let z = y.map(|i| *i);
/// ```
///
/// The correct use would be:
///
/// ```rust
/// let x = vec![42, 43];
/// let y = x.iter();
/// let z = y.cloned();
/// ```
declare_clippy_lint! {
    pub MAP_CLONE,
    style,
    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
}

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

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) {
        if in_macro(e.span) {
            return;
        }

        if_chain! {
            if let hir::ExprKind::MethodCall(ref method, _, ref args) = e.node;
            if args.len() == 2;
            if method.ident.as_str() == "map";
            let ty = cx.tables.expr_ty(&args[0]);
            if match_type(cx, ty, &paths::OPTION) || match_trait_method(cx, e, &paths::ITERATOR);
            if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].node;
            let closure_body = cx.tcx.hir.body(body_id);
            let closure_expr = remove_blocks(&closure_body.value);
            then {
                match closure_body.arguments[0].pat.node {
                    hir::PatKind::Ref(ref inner, _) => if let hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) = inner.node {
                        lint(cx, e.span, args[0].span, name, closure_expr);
                    },
                    hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => match closure_expr.node {
                        hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => lint(cx, e.span, args[0].span, name, inner),
                        hir::ExprKind::MethodCall(ref method, _, ref obj) => if method.ident.as_str() == "clone" && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
                            lint(cx, e.span, args[0].span, name, &obj[0]);
                        }
                        _ => {},
                    },
                    _ => {},
                }
            }
        }
    }
}

fn lint(cx: &LateContext<'_, '_>, replace: Span, root: Span, name: Ident, path: &hir::Expr) {
    if let hir::ExprKind::Path(hir::QPath::Resolved(None, ref path)) = path.node {
        if path.segments.len() == 1 && path.segments[0].ident == name {
            span_lint_and_sugg(
                cx,
                MAP_CLONE,
                replace,
                "You are using an explicit closure for cloning elements",
                "Consider calling the dedicated `cloned` method",
                format!("{}.cloned()", snippet(cx, root, "..")),
            )
        }
    }
}<|endoftext|>


<commit_before>
extern crate clap;

// Time Start: Mon, 16 Dec 2019 07:42:46 -0500
// Time Finish 1: Mon, 16 Dec 2019 08:30:39 -0500 (47 minutes, 53 seconds)
// Time Finish 2:
// Time Total:

use std::fs;

use clap::{Arg, App};

const PAT1: [i32; 4] = [0,1,0,-1];

fn fft(vec: &Vec<i32>, pat: &[i32], n: u32, offset: usize) -> Vec<i32> {
    let len = vec.len();
    let mut new = vec.clone();
    let mut vec = Vec::with_capacity(len);
    for _ in 0..n {
        std::mem::swap(&mut vec, &mut new);
        new.clear();
        for place in 0..len {
            let mut val = 0;
            let mut pat_idx = 0;
            let mut repeat = place;
            for idx in 0..len {
                if repeat == 0 {
                    pat_idx = (pat_idx + 1) % pat.len();
                    repeat = place + offset + 1;
                }
                val += vec[idx] * pat[pat_idx];
                val = val.signum() * (val.abs() % 1_000_000);
                repeat -= 1;
            }
            new.push(val.abs() % 10);
        }
    }
    return new;
}

fn fft_tail(vec: &Vec<i32>, n: u32, tail_len: usize) -> i32 {
    let len = vec.len();
    let mut new = vec.clone();
    new.reverse();
    let mut vec = Vec::with_capacity(len);
    for _ in 0..n {
        std::mem::swap(&mut vec, &mut new);
        new.clear();
        let mut val = 0;
        for i in 0..len {
            val += vec[i];
            new.push(val % 10);
        }
    }
    new.reverse();
    return num_at(&new, 0, tail_len);
}

fn repeat<T: Clone>(vec: &Vec<T>, n: usize) -> Vec<T> {
    let mut rv = Vec::with_capacity(n * vec.len());
    for _ in 0..n {
        rv.extend_from_slice(&vec[0..vec.len()]);
    }
    return rv;
}

fn num_at(vec: &Vec<i32>, idx: usize, len: usize) -> i32 {
    let mut rv = 0;
    for i in 0..len {
        rv = 10*rv + vec[idx + i];
    }
    return rv;
}

fn load(fname: &str) -> Vec<i32> {
    let contents = fs::read_to_string(fname)
        .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));
    return contents.trim().chars().map(|c| c.to_digit(10).unwrap_or_else(|| panic!("Parse error")) as i32).collect();
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 16")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = matches.value_of("FILE").unwrap_or("16.in");
    let vec = load(&fname);
    println!("Part 1: {}", num_at(&fft(&vec, &PAT1, 100, 0), 0, 8));

    //    first 7 bits: 5973181
    // repeated length: 6500000
    // Thus, the "pattern" never applies to the relevant tail. Just the
    // +1's, but we MUST get the offset exactly right.
    let mut vec2 = repeat(&vec, 10000);
    let offset = num_at(&vec, 0, 7) as usize;
    let tail = vec2.split_off(offset);
    println!("Part 2: {}", fft_tail(&tail, 100, 8));
}

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

    #[test]
    fn example1() {
        assert_eq!(fft(&vec![1,2,3,4,5,6,7,8], &PAT1, 1, 0), vec![4,8,2,2,6,1,5,8]);
        assert_eq!(fft(&vec![4,8,2,2,6,1,5,8], &PAT1, 1, 0), vec![3,4,0,4,0,4,3,8]);
        assert_eq!(fft(&vec![3,4,0,4,0,4,3,8], &PAT1, 1, 0), vec![0,3,4,1,5,5,1,8]);
        assert_eq!(fft(&vec![0,3,4,1,5,5,1,8], &PAT1, 1, 0), vec![0,1,0,2,9,4,9,8]);
        assert_eq!(fft(&vec![8,0,8,7,1,2,2,4,5,8,5,9,1,4,5,4,6,6,1,9,0,8,3,2,1,8,6,4,5,5,9,5], &PAT1, 100, 0)[0..8], [2,4,1,7,6,1,7,6]);
        assert_eq!(fft(&vec![1,9,6,1,7,8,0,4,2,0,7,2,0,2,2,0,9,1,4,4,9,1,6,0,4,4,1,8,9,9,1,7], &PAT1, 100, 0)[0..8], [7,3,7,4,5,4,1,8]);
        assert_eq!(fft(&vec![6,9,3,1,7,1,6,3,4,9,2,9,4,8,6,0,6,3,3,5,9,9,5,9,2,4,3,1,9,8,7,3], &PAT1, 100, 0)[0..8], [5,2,4,3,2,1,3,3]);
        assert_eq!(num_at(&vec![9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1,0], 7, 8), 21098765);
    }

    #[test]
    fn tails() {
        assert_eq!(fft(&vec![5,6,7,8], &PAT1, 1, 4), vec![6,1,5,8]);
        assert_eq!(fft(&vec![6,1,5,8], &PAT1, 1, 4), vec![0,4,3,8]);
        assert_eq!(fft(&vec![0,4,3,8], &PAT1, 1, 4), vec![5,5,1,8]);
        assert_eq!(fft(&vec![5,5,1,8], &PAT1, 1, 4), vec![9,4,9,8]);

        assert_eq!(num_at(&fft(&vec![8,0,8,7,1,2,2,4,5,8,5,9,1,4,5,4,6,6,1,9,0, 8,3,2,1,8,6,4,5,5,9,5], &PAT1, 100, 0), 21, 8), fft_tail(&vec![8,3,2,1,8,6,4,5,5,9,5], 100, 8));
        assert_eq!(num_at(&fft(&vec![1,9,6,1,7,8,0,4,2,0,7,2,0,2,2,0,9,1,4,4,9, 1,6,0,4,4,1,8,9,9,1,7], &PAT1, 100, 0), 21, 8), fft_tail(&vec![1,6,0,4,4,1,8,9,9,1,7], 100, 8));
        assert_eq!(num_at(&fft(&vec![6,9,3,1,7,1,6,3,4,9,2,9,4,8,6,0,6,3,3,5,9, 9,5,9,2,4,3,1,9,8,7,3], &PAT1, 100, 0), 21, 8), fft_tail(&vec![9,5,9,2,4,3,1,9,8,7,3], 100, 8));
    }
}
<commit_msg>Day 16<commit_after>
extern crate clap;

// Time Start: Mon, 16 Dec 2019 07:42:46 -0500
// Time Finish 1: Mon, 16 Dec 2019 08:30:39 -0500 (47 minutes, 53 seconds)
// Time Finish 2: Mon, 16 Dec 2019 11:06:30 -0500 (2 hours, 35 minutes, 51 seconds)
// Time Total: 3 hours, 23 minutes, 44 seconds

use std::fs;

use clap::{Arg, App};

const PAT1: [i32; 4] = [0,1,0,-1];

fn fft(vec: &Vec<i32>, pat: &[i32], n: u32, offset: usize) -> Vec<i32> {
    let len = vec.len();
    let mut new = vec.clone();
    let mut vec = Vec::with_capacity(len);
    for _ in 0..n {
        std::mem::swap(&mut vec, &mut new);
        new.clear();
        for place in 0..len {
            let mut val = 0;
            let mut pat_idx = 0;
            let mut repeat = place;
            for idx in 0..len {
                if repeat == 0 {
                    pat_idx = (pat_idx + 1) % pat.len();
                    repeat = place + offset + 1;
                }
                val += vec[idx] * pat[pat_idx];
                val = val.signum() * (val.abs() % 1_000_000);
                repeat -= 1;
            }
            new.push(val.abs() % 10);
        }
    }
    return new;
}

// Part 2 is a significantly degenerate case of part 1. Calculating the
// tail end (over half-way through) is trivial.
fn fft_tail(vec: &Vec<i32>, n: u32, tail_len: usize) -> i32 {
    let len = vec.len();
    let mut new = vec.clone();
    new.reverse();
    let mut vec = Vec::with_capacity(len);
    for _ in 0..n {
        std::mem::swap(&mut vec, &mut new);
        new.clear();
        let mut val = 0;
        for i in 0..len {
            val += vec[i];
            new.push(val % 10);
        }
    }
    new.reverse();
    return num_at(&new, 0, tail_len);
}

fn repeat<T: Clone>(vec: &Vec<T>, n: usize) -> Vec<T> {
    let mut rv = Vec::with_capacity(n * vec.len());
    for _ in 0..n {
        rv.extend_from_slice(&vec[0..vec.len()]);
    }
    return rv;
}

fn num_at(vec: &Vec<i32>, idx: usize, len: usize) -> i32 {
    let mut rv = 0;
    for i in 0..len {
        rv = 10*rv + vec[idx + i];
    }
    return rv;
}

fn load(fname: &str) -> Vec<i32> {
    let contents = fs::read_to_string(fname)
        .unwrap_or_else(|err| panic!("Error reading {}: {}", fname, err));
    return contents.trim().chars().map(|c| c.to_digit(10).unwrap_or_else(|| panic!("Parse error")) as i32).collect();
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 16")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = matches.value_of("FILE").unwrap_or("16.in");
    let vec = load(&fname);
    println!("Part 1: {}", num_at(&fft(&vec, &PAT1, 100, 0), 0, 8));

    //    first 7 bits: 5973181
    // repeated length: 6500000
    // Thus, the "pattern" never applies to the relevant tail. Just the +1's
    let mut vec2 = repeat(&vec, 10000);
    let offset = num_at(&vec, 0, 7) as usize;
    let tail = vec2.split_off(offset);
    println!("Part 2: {}", fft_tail(&tail, 100, 8));
}

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

    #[test]
    fn example1() {
        assert_eq!(fft(&vec![1,2,3,4,5,6,7,8], &PAT1, 1, 0), vec![4,8,2,2,6,1,5,8]);
        assert_eq!(fft(&vec![4,8,2,2,6,1,5,8], &PAT1, 1, 0), vec![3,4,0,4,0,4,3,8]);
        assert_eq!(fft(&vec![3,4,0,4,0,4,3,8], &PAT1, 1, 0), vec![0,3,4,1,5,5,1,8]);
        assert_eq!(fft(&vec![0,3,4,1,5,5,1,8], &PAT1, 1, 0), vec![0,1,0,2,9,4,9,8]);
        assert_eq!(fft(&vec![8,0,8,7,1,2,2,4,5,8,5,9,1,4,5,4,6,6,1,9,0,8,3,2,1,8,6,4,5,5,9,5], &PAT1, 100, 0)[0..8], [2,4,1,7,6,1,7,6]);
        assert_eq!(fft(&vec![1,9,6,1,7,8,0,4,2,0,7,2,0,2,2,0,9,1,4,4,9,1,6,0,4,4,1,8,9,9,1,7], &PAT1, 100, 0)[0..8], [7,3,7,4,5,4,1,8]);
        assert_eq!(fft(&vec![6,9,3,1,7,1,6,3,4,9,2,9,4,8,6,0,6,3,3,5,9,9,5,9,2,4,3,1,9,8,7,3], &PAT1, 100, 0)[0..8], [5,2,4,3,2,1,3,3]);
        assert_eq!(num_at(&vec![9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1,0], 7, 8), 21098765);
    }

    #[test]
    fn tails() {
        assert_eq!(fft(&vec![5,6,7,8], &PAT1, 1, 4), vec![6,1,5,8]);
        assert_eq!(fft(&vec![6,1,5,8], &PAT1, 1, 4), vec![0,4,3,8]);
        assert_eq!(fft(&vec![0,4,3,8], &PAT1, 1, 4), vec![5,5,1,8]);
        assert_eq!(fft(&vec![5,5,1,8], &PAT1, 1, 4), vec![9,4,9,8]);

        assert_eq!(num_at(&fft(&vec![8,0,8,7,1,2,2,4,5,8,5,9,1,4,5,4,6,6,1,9,0, 8,3,2,1,8,6,4,5,5,9,5], &PAT1, 100, 0), 21, 8), fft_tail(&vec![8,3,2,1,8,6,4,5,5,9,5], 100, 8));
        assert_eq!(num_at(&fft(&vec![1,9,6,1,7,8,0,4,2,0,7,2,0,2,2,0,9,1,4,4,9, 1,6,0,4,4,1,8,9,9,1,7], &PAT1, 100, 0), 21, 8), fft_tail(&vec![1,6,0,4,4,1,8,9,9,1,7], 100, 8));
        assert_eq!(num_at(&fft(&vec![6,9,3,1,7,1,6,3,4,9,2,9,4,8,6,0,6,3,3,5,9, 9,5,9,2,4,3,1,9,8,7,3], &PAT1, 100, 0), 21, 8), fft_tail(&vec![9,5,9,2,4,3,1,9,8,7,3], 100, 8));
    }
}
<|endoftext|>


<commit_before>use std::iter::FusedIterator;
use std::mem;
use std::ops::Range;
use std::os::unix::io::RawFd;
use std::ptr::{null, null_mut};
use libc::{self, c_int};
use Result;
use errno::Errno;
use sys::signal::SigSet;
use sys::time::{TimeSpec, TimeVal};

pub use libc::FD_SETSIZE;

#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct FdSet(libc::fd_set);

impl FdSet {
    pub fn new() -> FdSet {
        let mut fdset = mem::MaybeUninit::uninit();
        unsafe {
            libc::FD_ZERO(fdset.as_mut_ptr());
            FdSet(fdset.assume_init())
        }
    }

    pub fn insert(&mut self, fd: RawFd) {
        unsafe { libc::FD_SET(fd, &mut self.0) };
    }

    pub fn remove(&mut self, fd: RawFd) {
        unsafe { libc::FD_CLR(fd, &mut self.0) };
    }

    pub fn contains(&mut self, fd: RawFd) -> bool {
        unsafe { libc::FD_ISSET(fd, &mut self.0) }
    }

    pub fn clear(&mut self) {
        unsafe { libc::FD_ZERO(&mut self.0) };
    }

    /// Finds the highest file descriptor in the set.
    ///
    /// Returns `None` if the set is empty.
    ///
    /// This can be used to calculate the `nfds` parameter of the [`select`] function.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate nix;
    /// # use nix::sys::select::FdSet;
    /// # fn main() {
    /// let mut set = FdSet::new();
    /// set.insert(4);
    /// set.insert(9);
    /// assert_eq!(set.highest(), Some(9));
    /// # }
    /// ```
    ///
    /// [`select`]: fn.select.html
    pub fn highest(&mut self) -> Option<RawFd> {
        self.fds(None).next_back()
    }

    /// Returns an iterator over the file descriptors in the set.
    ///
    /// For performance, it takes an optional higher bound: the iterator will
    /// not return any elements of the set greater than the given file
    /// descriptor.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate nix;
    /// # use nix::sys::select::FdSet;
    /// # use std::os::unix::io::RawFd;
    /// let mut set = FdSet::new();
    /// set.insert(4);
    /// set.insert(9);
    /// let fds: Vec<RawFd> = set.fds(None).collect();
    /// assert_eq!(fds, vec![4, 9]);
    /// ```
    #[inline]
    pub fn fds(&mut self, highest: Option<RawFd>) -> Fds {
        Fds {
            set: self,
            range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE),
        }
    }
}

impl Default for FdSet {
    fn default() -> Self {
        Self::new()
    }
}

/// Iterator over `FdSet`.
#[derive(Debug)]
pub struct Fds<'a> {
    set: &'a mut FdSet,
    range: Range<usize>,
}

impl<'a> Iterator for Fds<'a> {
    type Item = RawFd;

    fn next(&mut self) -> Option<RawFd> {
        while let Some(i) = self.range.next() {
            if self.set.contains(i as RawFd) {
                return Some(i as RawFd);
            }
        }
        None
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.range.size_hint();
        (0, upper)
    }
}

impl<'a> DoubleEndedIterator for Fds<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<RawFd> {
        while let Some(i) = self.range.next_back() {
            if self.set.contains(i as RawFd) {
                return Some(i as RawFd);
            }
        }
        None
    }
}

impl<'a> FusedIterator for Fds<'a> {}

/// Monitors file descriptors for readiness
///
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
/// file descriptors that are ready for the given operation are set.
///
/// When this function returns, `timeout` has an implementation-defined value.
///
/// # Parameters
///
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
///   to the maximum of that.
/// * `readfds`: File descriptors to check for being ready to read.
/// * `writefds`: File descriptors to check for being ready to write.
/// * `errorfds`: File descriptors to check for pending error conditions.
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
///   indefinitely).
///
/// # References
///
/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
pub fn select<'a, N, R, W, E, T>(nfds: N,
    readfds: R,
    writefds: W,
    errorfds: E,
                                 timeout: T) -> Result<c_int>
where
    N: Into<Option<c_int>>,
    R: Into<Option<&'a mut FdSet>>,
    W: Into<Option<&'a mut FdSet>>,
    E: Into<Option<&'a mut FdSet>>,
    T: Into<Option<&'a mut TimeVal>>,
{
    let mut readfds = readfds.into();
    let mut writefds = writefds.into();
    let mut errorfds = errorfds.into();
    let timeout = timeout.into();

    let nfds = nfds.into().unwrap_or_else(|| {
        readfds.iter_mut()
            .chain(writefds.iter_mut())
            .chain(errorfds.iter_mut())
            .map(|set| set.highest().unwrap_or(-1))
            .max()
            .unwrap_or(-1) + 1
    });

    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
        .unwrap_or(null_mut());

    let res = unsafe {
        libc::select(nfds, readfds, writefds, errorfds, timeout)
    };

    Errno::result(res)
}

/// Monitors file descriptors for readiness with an altered signal mask.
///
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
/// file descriptors that are ready for the given operation are set.
///
/// When this function returns, the original signal mask is restored.
///
/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
///
/// # Parameters
///
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
///   to the maximum of that.
/// * `readfds`: File descriptors to check for read readiness
/// * `writefds`: File descriptors to check for write readiness
/// * `errorfds`: File descriptors to check for pending error conditions.
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
///   indefinitely).
/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
///    ready (`None` to set no alternative signal mask).
///
/// # References
///
/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
///
/// [The new pselect() system call](https://lwn.net/Articles/176911/)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
    readfds: R,
    writefds: W,
    errorfds: E,
    timeout: T,
                                     sigmask: S) -> Result<c_int>
where
    N: Into<Option<c_int>>,
    R: Into<Option<&'a mut FdSet>>,
    W: Into<Option<&'a mut FdSet>>,
    E: Into<Option<&'a mut FdSet>>,
    T: Into<Option<&'a TimeSpec>>,
    S: Into<Option<&'a SigSet>>,
{
    let mut readfds = readfds.into();
    let mut writefds = writefds.into();
    let mut errorfds = errorfds.into();
    let sigmask = sigmask.into();
    let timeout = timeout.into();

    let nfds = nfds.into().unwrap_or_else(|| {
        readfds.iter_mut()
            .chain(writefds.iter_mut())
            .chain(errorfds.iter_mut())
            .map(|set| set.highest().unwrap_or(-1))
            .max()
            .unwrap_or(-1) + 1
    });

    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
    let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());

    let res = unsafe {
        libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
    };

    Errno::result(res)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::os::unix::io::RawFd;
    use sys::time::{TimeVal, TimeValLike};
    use unistd::{write, pipe};

    #[test]
    fn fdset_insert() {
        let mut fd_set = FdSet::new();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }

        fd_set.insert(7);

        assert!(fd_set.contains(7));
    }

    #[test]
    fn fdset_remove() {
        let mut fd_set = FdSet::new();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }

        fd_set.insert(7);
        fd_set.remove(7);

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }
    }

    #[test]
    fn fdset_clear() {
        let mut fd_set = FdSet::new();
        fd_set.insert(1);
        fd_set.insert((FD_SETSIZE / 2) as RawFd);
        fd_set.insert((FD_SETSIZE - 1) as RawFd);

        fd_set.clear();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }
    }

    #[test]
    fn fdset_highest() {
        let mut set = FdSet::new();
        assert_eq!(set.highest(), None);
        set.insert(0);
        assert_eq!(set.highest(), Some(0));
        set.insert(90);
        assert_eq!(set.highest(), Some(90));
        set.remove(0);
        assert_eq!(set.highest(), Some(90));
        set.remove(90);
        assert_eq!(set.highest(), None);

        set.insert(4);
        set.insert(5);
        set.insert(7);
        assert_eq!(set.highest(), Some(7));
    }

    #[test]
    fn test_select() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(None,
                             &mut fd_set,
                             None,
                             None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }

    #[test]
    fn test_select_nfds() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
                &mut fd_set,
                None,
                None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }

    #[test]
    fn test_select_nfds2() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
                &mut fd_set,
                None,
                None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }
}
<commit_msg>Added fds test<commit_after>use std::iter::FusedIterator;
use std::mem;
use std::ops::Range;
use std::os::unix::io::RawFd;
use std::ptr::{null, null_mut};
use libc::{self, c_int};
use Result;
use errno::Errno;
use sys::signal::SigSet;
use sys::time::{TimeSpec, TimeVal};

pub use libc::FD_SETSIZE;

#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct FdSet(libc::fd_set);

impl FdSet {
    pub fn new() -> FdSet {
        let mut fdset = mem::MaybeUninit::uninit();
        unsafe {
            libc::FD_ZERO(fdset.as_mut_ptr());
            FdSet(fdset.assume_init())
        }
    }

    pub fn insert(&mut self, fd: RawFd) {
        unsafe { libc::FD_SET(fd, &mut self.0) };
    }

    pub fn remove(&mut self, fd: RawFd) {
        unsafe { libc::FD_CLR(fd, &mut self.0) };
    }

    pub fn contains(&mut self, fd: RawFd) -> bool {
        unsafe { libc::FD_ISSET(fd, &mut self.0) }
    }

    pub fn clear(&mut self) {
        unsafe { libc::FD_ZERO(&mut self.0) };
    }

    /// Finds the highest file descriptor in the set.
    ///
    /// Returns `None` if the set is empty.
    ///
    /// This can be used to calculate the `nfds` parameter of the [`select`] function.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate nix;
    /// # use nix::sys::select::FdSet;
    /// # fn main() {
    /// let mut set = FdSet::new();
    /// set.insert(4);
    /// set.insert(9);
    /// assert_eq!(set.highest(), Some(9));
    /// # }
    /// ```
    ///
    /// [`select`]: fn.select.html
    pub fn highest(&mut self) -> Option<RawFd> {
        self.fds(None).next_back()
    }

    /// Returns an iterator over the file descriptors in the set.
    ///
    /// For performance, it takes an optional higher bound: the iterator will
    /// not return any elements of the set greater than the given file
    /// descriptor.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate nix;
    /// # use nix::sys::select::FdSet;
    /// # use std::os::unix::io::RawFd;
    /// let mut set = FdSet::new();
    /// set.insert(4);
    /// set.insert(9);
    /// let fds: Vec<RawFd> = set.fds(None).collect();
    /// assert_eq!(fds, vec![4, 9]);
    /// ```
    #[inline]
    pub fn fds(&mut self, highest: Option<RawFd>) -> Fds {
        Fds {
            set: self,
            range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE),
        }
    }
}

impl Default for FdSet {
    fn default() -> Self {
        Self::new()
    }
}

/// Iterator over `FdSet`.
#[derive(Debug)]
pub struct Fds<'a> {
    set: &'a mut FdSet,
    range: Range<usize>,
}

impl<'a> Iterator for Fds<'a> {
    type Item = RawFd;

    fn next(&mut self) -> Option<RawFd> {
        while let Some(i) = self.range.next() {
            if self.set.contains(i as RawFd) {
                return Some(i as RawFd);
            }
        }
        None
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.range.size_hint();
        (0, upper)
    }
}

impl<'a> DoubleEndedIterator for Fds<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<RawFd> {
        while let Some(i) = self.range.next_back() {
            if self.set.contains(i as RawFd) {
                return Some(i as RawFd);
            }
        }
        None
    }
}

impl<'a> FusedIterator for Fds<'a> {}

/// Monitors file descriptors for readiness
///
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
/// file descriptors that are ready for the given operation are set.
///
/// When this function returns, `timeout` has an implementation-defined value.
///
/// # Parameters
///
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
///   to the maximum of that.
/// * `readfds`: File descriptors to check for being ready to read.
/// * `writefds`: File descriptors to check for being ready to write.
/// * `errorfds`: File descriptors to check for pending error conditions.
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
///   indefinitely).
///
/// # References
///
/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
pub fn select<'a, N, R, W, E, T>(nfds: N,
    readfds: R,
    writefds: W,
    errorfds: E,
                                 timeout: T) -> Result<c_int>
where
    N: Into<Option<c_int>>,
    R: Into<Option<&'a mut FdSet>>,
    W: Into<Option<&'a mut FdSet>>,
    E: Into<Option<&'a mut FdSet>>,
    T: Into<Option<&'a mut TimeVal>>,
{
    let mut readfds = readfds.into();
    let mut writefds = writefds.into();
    let mut errorfds = errorfds.into();
    let timeout = timeout.into();

    let nfds = nfds.into().unwrap_or_else(|| {
        readfds.iter_mut()
            .chain(writefds.iter_mut())
            .chain(errorfds.iter_mut())
            .map(|set| set.highest().unwrap_or(-1))
            .max()
            .unwrap_or(-1) + 1
    });

    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
        .unwrap_or(null_mut());

    let res = unsafe {
        libc::select(nfds, readfds, writefds, errorfds, timeout)
    };

    Errno::result(res)
}

/// Monitors file descriptors for readiness with an altered signal mask.
///
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
/// file descriptors that are ready for the given operation are set.
///
/// When this function returns, the original signal mask is restored.
///
/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
///
/// # Parameters
///
/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
///   to the maximum of that.
/// * `readfds`: File descriptors to check for read readiness
/// * `writefds`: File descriptors to check for write readiness
/// * `errorfds`: File descriptors to check for pending error conditions.
/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
///   indefinitely).
/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
///    ready (`None` to set no alternative signal mask).
///
/// # References
///
/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
///
/// [The new pselect() system call](https://lwn.net/Articles/176911/)
///
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
    readfds: R,
    writefds: W,
    errorfds: E,
    timeout: T,
                                     sigmask: S) -> Result<c_int>
where
    N: Into<Option<c_int>>,
    R: Into<Option<&'a mut FdSet>>,
    W: Into<Option<&'a mut FdSet>>,
    E: Into<Option<&'a mut FdSet>>,
    T: Into<Option<&'a TimeSpec>>,
    S: Into<Option<&'a SigSet>>,
{
    let mut readfds = readfds.into();
    let mut writefds = writefds.into();
    let mut errorfds = errorfds.into();
    let sigmask = sigmask.into();
    let timeout = timeout.into();

    let nfds = nfds.into().unwrap_or_else(|| {
        readfds.iter_mut()
            .chain(writefds.iter_mut())
            .chain(errorfds.iter_mut())
            .map(|set| set.highest().unwrap_or(-1))
            .max()
            .unwrap_or(-1) + 1
    });

    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
    let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
    let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());

    let res = unsafe {
        libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
    };

    Errno::result(res)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::os::unix::io::RawFd;
    use sys::time::{TimeVal, TimeValLike};
    use unistd::{write, pipe};

    #[test]
    fn fdset_insert() {
        let mut fd_set = FdSet::new();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }

        fd_set.insert(7);

        assert!(fd_set.contains(7));
    }

    #[test]
    fn fdset_remove() {
        let mut fd_set = FdSet::new();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }

        fd_set.insert(7);
        fd_set.remove(7);

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }
    }

    #[test]
    fn fdset_clear() {
        let mut fd_set = FdSet::new();
        fd_set.insert(1);
        fd_set.insert((FD_SETSIZE / 2) as RawFd);
        fd_set.insert((FD_SETSIZE - 1) as RawFd);

        fd_set.clear();

        for i in 0..FD_SETSIZE {
            assert!(!fd_set.contains(i as RawFd));
        }
    }

    #[test]
    fn fdset_highest() {
        let mut set = FdSet::new();
        assert_eq!(set.highest(), None);
        set.insert(0);
        assert_eq!(set.highest(), Some(0));
        set.insert(90);
        assert_eq!(set.highest(), Some(90));
        set.remove(0);
        assert_eq!(set.highest(), Some(90));
        set.remove(90);
        assert_eq!(set.highest(), None);

        set.insert(4);
        set.insert(5);
        set.insert(7);
        assert_eq!(set.highest(), Some(7));
    }

    #[test]
    fn fdset_fds() {
        let mut set = FdSet::new();
        assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]);
        set.insert(0);
        assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]);
        set.insert(90);
        assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]);

        // highest limit
        assert_eq!(set.fds(Some(89)).collect::<Vec<_>>(), vec![0]);
        assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]);
    }

    #[test]
    fn test_select() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(None,
                             &mut fd_set,
                             None,
                             None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }

    #[test]
    fn test_select_nfds() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
                &mut fd_set,
                None,
                None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }

    #[test]
    fn test_select_nfds2() {
        let (r1, w1) = pipe().unwrap();
        write(w1, b"hi!").unwrap();
        let (r2, _w2) = pipe().unwrap();

        let mut fd_set = FdSet::new();
        fd_set.insert(r1);
        fd_set.insert(r2);

        let mut timeout = TimeVal::seconds(10);
        assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
                &mut fd_set,
                None,
                None,
                             &mut timeout).unwrap());
        assert!(fd_set.contains(r1));
        assert!(!fd_set.contains(r2));
    }
}
<|endoftext|>


<commit_before>
pub fn parse_testfn_list(files: &Vec<String>) -> Vec<String> {
    files.iter()
        .map(|file| parse_testfn_labels(file))
        .fold(Vec::new(), |mut a, b| { a.extend(b); a })
}

fn parse_testfn_labels(file: &String) -> Vec<String> {
    let mut result: Vec<String> = Vec::new();

    let test_fn_regex = regex!(r"(?xm)
        ///             #c-style comment with extra slash
        .*              #any number of non-newlines
        \[test\].*      #test tag
        \s*void\s+      #require void return type
        (\w+)           #capture function identifier
        \s*\(\s*        #start of parameter list
        (\s*|void)      #match void or empty parameters
        \s*\)\s*        #end of parameter list
        \{.*            #require open brace (only match definitions)
        ");

    for regex_match in test_fn_regex.captures_iter(file) {
        println!("match {}", regex_match.at(0).unwrap());
        println!("cap {}", regex_match.at(1).unwrap());
        result.push(String::from(regex_match.at(1).unwrap()));
    }

    result
}

#[cfg(test)]
mod test {
    #[test]
    fn parse_testfn_list() {
        let source: Vec<String> = vec!["
            void some_function(void) {
            }

            void other_function () {
            }

            ///[test]
            void test_function() {
            }

            ///[test]
            void other_test_function (void) {
            }

            ///[test]
            void inner_scope() {
                does stuff;
                other stuff;

                if (something) {
                    more stuff;
                }

            }

            ///[test]
            void incorrect_brace_style()
            {
            }

            ///[test]
            void missing_close_delim() {

            ///[test]
            int bad_test_function() {
            }

            ///[test]
            void bad_args(thing) {
            }

            ".to_owned()];

        let actual_labels = super::parse_testfn_list(&source);

        let expected_labels = vec!["test_function".to_owned(),
                                   "other_test_function".to_owned(),
                                   "incorrect_brace_style".to_owned(),
                                   "inner_scope".to_owned(),
                                   "missing_close_delim".to_owned()];

        assert_eq!(expected_labels.len(), actual_labels.len());
        for label in expected_labels {
            assert!(actual_labels.contains(&label));
        }
    }
}

<commit_msg>refactor parse<commit_after>use regex;

pub fn parse_testfn_list(files: &Vec<String>) -> Vec<String> {
    let parser = Parser::new();

    files.iter()
        .map(|file| parser.parse_labels(file))
        .fold(Vec::new(), |mut a, b| { a.extend(b); a })
}

struct Parser {
    fn_label_regex: regex::Regex
}

impl Parser {
    pub fn new() -> Parser {
        Parser {
            fn_label_regex: Self::label_regex()
        }
    }

    fn label_regex() -> regex::Regex {
        regex!(r"(?x) #set ignore-whitespace mode
            ///             #c-style comment with extra slash
            .*              #any number of non-newlines
            \[test\].*      #test tag
            \s*void\s+      #require void return type
            (\w+)           #capture function identifier
            \s*\(\s*        #start of parameter list
            (\s*|void)      #match void or empty parameters
            \s*\)\s*        #end of parameter list
            \{.*            #require open brace (only match definitions)
            ")
    }

    pub fn parse_labels(&self, file: &String) -> Vec<String> {
        self.fn_label_regex.captures_iter(file)
            .map(|regex_match| String::from(regex_match.at(1).unwrap()))
            .collect::<Vec<_>>()
    }
}

#[cfg(test)]
mod test {
    trait ToOwnedStringVec {
        fn to_owned_vec(&self) -> Vec<String>;
    }

    impl ToOwnedStringVec for Vec<&'static str> {
        fn to_owned_vec(&self) -> Vec<String> {
            self.iter()
                .map(|&item| item.to_owned())
                .collect()
        }
    }

    #[test]
    fn good_fn() {
        assert_correct_labels_generated(
            vec![
                "test_function",
                "inner_scope",
                "brace_style",
                "no_close_delim",
                "void_arg"
            ],
            vec!["
                void some_function(void) {
                }

                void other_function () {
                }

                ///[test]
                void test_function() {
                }

                ///[test]
                void inner_scope() {
                    { }
                }

                ///[test]
                void brace_style()
                {
                }

                ///[test]
                void no_close_delim() {
                }

                ///[test]
                void void_arg(void) {
                }
            "]
            );
    }

    fn assert_correct_labels_generated(expected: Vec<&'static str>, actual: Vec<&'static str>) {
        let actual_labels = super::parse_testfn_list(&actual.to_owned_vec());
        let expected_labels = expected.to_owned_vec();

        assert_eq!(expected_labels.len(), actual_labels.len());
        for label in expected_labels {
            assert!(actual_labels.contains(&label));
        }

    }

    #[test]
    fn bad_fn() {
        assert_correct_labels_generated(
            vec![],
            vec!["
                void normal_fn() {
                }

                ///[test]
                int non_void() {
                }

                ///[test]
                void parameters(thing) {
                }
            "]
            );
    }

    #[test]
    fn multi_source() {
        assert_correct_labels_generated(
            vec![
                "source1_fn1",
                "source1_fn2",
                "source2_fn1",
                "source2_fn2"
            ],
            vec![
                "
                    ///[test]
                    void source1_fn1() {}
                    ///[test]
                    void source1_fn2() {}
                ",
                "
                    ///[test]
                    void source2_fn1() {}
                    ///[test]
                    void source2_fn2() {}
                "
            ]
            );
    }
}

<|endoftext|>