<commit_before>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::File;
use std::sync::Arc;

use super::error::*;
use super::host_device::HostDevice;
use crate::usb::xhci::usb_hub::UsbHub;
use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
use crate::utils::AsyncJobQueue;
use crate::utils::{EventHandler, EventLoop, FailHandle};

use anyhow::Context;
use base::{error, AsRawDescriptor, Descriptor, RawDescriptor, Tube, WatchingEvents};
use std::collections::HashMap;
use std::mem;
use std::time::Duration;
use sync::Mutex;
use usb_util::Device;
use vm_control::{
    UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, USB_CONTROL_MAX_PORTS,
};

const SOCKET_TIMEOUT_MS: u64 = 2000;

/// Host backend device provider is a xhci backend device provider that would provide pass through
/// devices.
pub enum HostBackendDeviceProvider {
    // The provider is created but not yet started.
    Created { control_tube: Mutex<Tube> },
    // The provider is started on an event loop.
    Started { inner: Arc<ProviderInner> },
    // The provider has failed.
    Failed,
}

impl HostBackendDeviceProvider {
    pub fn new() -> Result<(Tube, HostBackendDeviceProvider)> {
        let (child_tube, control_tube) = Tube::pair().map_err(Error::CreateControlTube)?;
        control_tube
            .set_send_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
            .map_err(Error::SetupControlTube)?;
        control_tube
            .set_recv_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
            .map_err(Error::SetupControlTube)?;

        let provider = HostBackendDeviceProvider::Created {
            control_tube: Mutex::new(child_tube),
        };
        Ok((control_tube, provider))
    }

    fn start_helper(
        &mut self,
        fail_handle: Arc<dyn FailHandle>,
        event_loop: Arc<EventLoop>,
        hub: Arc<UsbHub>,
    ) -> Result<()> {
        match mem::replace(self, HostBackendDeviceProvider::Failed) {
            HostBackendDeviceProvider::Created { control_tube } => {
                let job_queue =
                    AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?;
                let inner = Arc::new(ProviderInner::new(
                    fail_handle,
                    job_queue,
                    event_loop.clone(),
                    control_tube,
                    hub,
                ));
                let handler: Arc<dyn EventHandler> = inner.clone();
                event_loop
                    .add_event(
                        &*inner.control_tube.lock(),
                        WatchingEvents::empty().set_read(),
                        Arc::downgrade(&handler),
                    )
                    .map_err(Error::AddToEventLoop)?;
                *self = HostBackendDeviceProvider::Started { inner };
                Ok(())
            }
            HostBackendDeviceProvider::Started { .. } => {
                error!("Host backend provider has already started");
                Err(Error::BadBackendProviderState)
            }
            HostBackendDeviceProvider::Failed => {
                error!("Host backend provider has already failed");
                Err(Error::BadBackendProviderState)
            }
        }
    }
}

impl XhciBackendDeviceProvider for HostBackendDeviceProvider {
    fn start(
        &mut self,
        fail_handle: Arc<dyn FailHandle>,
        event_loop: Arc<EventLoop>,
        hub: Arc<UsbHub>,
    ) -> Result<()> {
        self.start_helper(fail_handle, event_loop, hub)
    }

    fn keep_rds(&self) -> Vec<RawDescriptor> {
        match self {
            HostBackendDeviceProvider::Created { control_tube } => {
                vec![control_tube.lock().as_raw_descriptor()]
            }
            _ => {
                error!(
                    "Trying to get keepfds when HostBackendDeviceProvider is not in created state"
                );
                vec![]
            }
        }
    }
}

/// ProviderInner listens to control socket.
pub struct ProviderInner {
    fail_handle: Arc<dyn FailHandle>,
    job_queue: Arc<AsyncJobQueue>,
    event_loop: Arc<EventLoop>,
    control_tube: Mutex<Tube>,
    usb_hub: Arc<UsbHub>,

    // Map of USB hub port number to per-device context.
    devices: Mutex<HashMap<u8, HostDeviceContext>>,
}

struct HostDeviceContext {
    event_handler: Arc<dyn EventHandler>,
    device: Arc<Mutex<Device>>,
}

impl ProviderInner {
    fn new(
        fail_handle: Arc<dyn FailHandle>,
        job_queue: Arc<AsyncJobQueue>,
        event_loop: Arc<EventLoop>,
        control_tube: Mutex<Tube>,
        usb_hub: Arc<UsbHub>,
    ) -> ProviderInner {
        ProviderInner {
            fail_handle,
            job_queue,
            event_loop,
            control_tube,
            usb_hub,
            devices: Mutex::new(HashMap::new()),
        }
    }

    /// Open a usbdevfs file to create a host USB device object.
    /// `fd` should be an open file descriptor for a file in `/dev/bus/usb`.
    fn handle_attach_device(&self, usb_file: File) -> UsbControlResult {
        let device = match Device::new(usb_file) {
            Ok(d) => d,
            Err(e) => {
                error!("could not construct USB device from fd: {}", e);
                return UsbControlResult::NoSuchDevice;
            }
        };

        let device_descriptor = Descriptor(device.as_raw_descriptor());

        let arc_mutex_device = Arc::new(Mutex::new(device));

        let event_handler: Arc<dyn EventHandler> = Arc::new(UsbUtilEventHandler {
            device: arc_mutex_device.clone(),
        });

        if let Err(e) = self.event_loop.add_event(
            &device_descriptor,
            WatchingEvents::empty().set_read().set_write(),
            Arc::downgrade(&event_handler),
        ) {
            error!("failed to add USB device fd to event handler: {}", e);
            return UsbControlResult::FailedToOpenDevice;
        }

        let device_ctx = HostDeviceContext {
            event_handler,
            device: arc_mutex_device.clone(),
        };

        // Resetting the device is used to make sure it is in a known state, but it may
        // still function if the reset fails.
        if let Err(e) = arc_mutex_device.lock().reset() {
            error!("failed to reset device after attach: {:?}", e);
        }

        let host_device = match HostDevice::new(
            self.fail_handle.clone(),
            self.job_queue.clone(),
            arc_mutex_device,
        ) {
            Ok(host_device) => Box::new(host_device),
            Err(e) => {
                error!("failed to initialize HostDevice: {}", e);
                return UsbControlResult::FailedToInitHostDevice;
            }
        };

        let port = self.usb_hub.connect_backend(host_device);
        match port {
            Ok(port) => {
                self.devices.lock().insert(port, device_ctx);
                UsbControlResult::Ok { port }
            }
            Err(e) => {
                error!("failed to connect device to hub: {}", e);
                UsbControlResult::NoAvailablePort
            }
        }
    }

    fn handle_detach_device(&self, port: u8) -> UsbControlResult {
        match self.usb_hub.disconnect_port(port) {
            Ok(()) => {
                if let Some(device_ctx) = self.devices.lock().remove(&port) {
                    let _ = device_ctx.event_handler.on_event();
                    let device = device_ctx.device.lock();
                    let fd = device.fd();

                    if let Err(e) = self.event_loop.remove_event_for_fd(&*fd) {
                        error!(
                            "failed to remove poll change handler from event loop: {}",
                            e
                        );
                    }
                }
                UsbControlResult::Ok { port }
            }
            Err(e) => {
                error!("failed to disconnect device from port {}: {}", port, e);
                UsbControlResult::NoSuchDevice
            }
        }
    }

    fn handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult {
        let mut devices: [UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS] = Default::default();
        for (result_index, &port_id) in ports.iter().enumerate() {
            match self.usb_hub.get_port(port_id).and_then(|p| {
                p.get_backend_device()
                    .as_ref()
                    .map(|d| (d.get_vid(), d.get_pid()))
            }) {
                Some((vendor_id, product_id)) => {
                    devices[result_index] = UsbControlAttachedDevice {
                        port: port_id,
                        vendor_id,
                        product_id,
                    }
                }
                None => continue,
            }
        }
        UsbControlResult::Devices(devices)
    }

    fn on_event_helper(&self) -> Result<()> {
        let tube = self.control_tube.lock();
        let cmd = tube.recv().map_err(Error::ReadControlTube)?;
        let result = match cmd {
            UsbControlCommand::AttachDevice { file, .. } => self.handle_attach_device(file),
            UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port),
            UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports),
        };
        tube.send(&result).map_err(Error::WriteControlTube)?;
        Ok(())
    }
}

impl EventHandler for ProviderInner {
    fn on_event(&self) -> anyhow::Result<()> {
        self.on_event_helper()
            .context("host backend device provider failed")
    }
}

struct UsbUtilEventHandler {
    device: Arc<Mutex<Device>>,
}

impl EventHandler for UsbUtilEventHandler {
    fn on_event(&self) -> anyhow::Result<()> {
        self.device
            .lock()
            .poll_transfers()
            .context("UsbUtilEventHandler poll_transfers failed")
    }
}
<commit_msg>devices: usb: host: don't use Descriptor as temporary descriptor storage<commit_after>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::File;
use std::sync::Arc;

use super::error::*;
use super::host_device::HostDevice;
use crate::usb::xhci::usb_hub::UsbHub;
use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
use crate::utils::AsyncJobQueue;
use crate::utils::{EventHandler, EventLoop, FailHandle};

use anyhow::Context;
use base::{error, AsRawDescriptor, RawDescriptor, Tube, WatchingEvents};
use std::collections::HashMap;
use std::mem;
use std::time::Duration;
use sync::Mutex;
use usb_util::Device;
use vm_control::{
    UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, USB_CONTROL_MAX_PORTS,
};

const SOCKET_TIMEOUT_MS: u64 = 2000;

/// Host backend device provider is a xhci backend device provider that would provide pass through
/// devices.
pub enum HostBackendDeviceProvider {
    // The provider is created but not yet started.
    Created { control_tube: Mutex<Tube> },
    // The provider is started on an event loop.
    Started { inner: Arc<ProviderInner> },
    // The provider has failed.
    Failed,
}

impl HostBackendDeviceProvider {
    pub fn new() -> Result<(Tube, HostBackendDeviceProvider)> {
        let (child_tube, control_tube) = Tube::pair().map_err(Error::CreateControlTube)?;
        control_tube
            .set_send_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
            .map_err(Error::SetupControlTube)?;
        control_tube
            .set_recv_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
            .map_err(Error::SetupControlTube)?;

        let provider = HostBackendDeviceProvider::Created {
            control_tube: Mutex::new(child_tube),
        };
        Ok((control_tube, provider))
    }

    fn start_helper(
        &mut self,
        fail_handle: Arc<dyn FailHandle>,
        event_loop: Arc<EventLoop>,
        hub: Arc<UsbHub>,
    ) -> Result<()> {
        match mem::replace(self, HostBackendDeviceProvider::Failed) {
            HostBackendDeviceProvider::Created { control_tube } => {
                let job_queue =
                    AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?;
                let inner = Arc::new(ProviderInner::new(
                    fail_handle,
                    job_queue,
                    event_loop.clone(),
                    control_tube,
                    hub,
                ));
                let handler: Arc<dyn EventHandler> = inner.clone();
                event_loop
                    .add_event(
                        &*inner.control_tube.lock(),
                        WatchingEvents::empty().set_read(),
                        Arc::downgrade(&handler),
                    )
                    .map_err(Error::AddToEventLoop)?;
                *self = HostBackendDeviceProvider::Started { inner };
                Ok(())
            }
            HostBackendDeviceProvider::Started { .. } => {
                error!("Host backend provider has already started");
                Err(Error::BadBackendProviderState)
            }
            HostBackendDeviceProvider::Failed => {
                error!("Host backend provider has already failed");
                Err(Error::BadBackendProviderState)
            }
        }
    }
}

impl XhciBackendDeviceProvider for HostBackendDeviceProvider {
    fn start(
        &mut self,
        fail_handle: Arc<dyn FailHandle>,
        event_loop: Arc<EventLoop>,
        hub: Arc<UsbHub>,
    ) -> Result<()> {
        self.start_helper(fail_handle, event_loop, hub)
    }

    fn keep_rds(&self) -> Vec<RawDescriptor> {
        match self {
            HostBackendDeviceProvider::Created { control_tube } => {
                vec![control_tube.lock().as_raw_descriptor()]
            }
            _ => {
                error!(
                    "Trying to get keepfds when HostBackendDeviceProvider is not in created state"
                );
                vec![]
            }
        }
    }
}

/// ProviderInner listens to control socket.
pub struct ProviderInner {
    fail_handle: Arc<dyn FailHandle>,
    job_queue: Arc<AsyncJobQueue>,
    event_loop: Arc<EventLoop>,
    control_tube: Mutex<Tube>,
    usb_hub: Arc<UsbHub>,

    // Map of USB hub port number to per-device context.
    devices: Mutex<HashMap<u8, HostDeviceContext>>,
}

struct HostDeviceContext {
    event_handler: Arc<dyn EventHandler>,
    device: Arc<Mutex<Device>>,
}

impl ProviderInner {
    fn new(
        fail_handle: Arc<dyn FailHandle>,
        job_queue: Arc<AsyncJobQueue>,
        event_loop: Arc<EventLoop>,
        control_tube: Mutex<Tube>,
        usb_hub: Arc<UsbHub>,
    ) -> ProviderInner {
        ProviderInner {
            fail_handle,
            job_queue,
            event_loop,
            control_tube,
            usb_hub,
            devices: Mutex::new(HashMap::new()),
        }
    }

    /// Open a usbdevfs file to create a host USB device object.
    /// `fd` should be an open file descriptor for a file in `/dev/bus/usb`.
    fn handle_attach_device(&self, usb_file: File) -> UsbControlResult {
        let device = match Device::new(usb_file) {
            Ok(d) => d,
            Err(e) => {
                error!("could not construct USB device from fd: {}", e);
                return UsbControlResult::NoSuchDevice;
            }
        };

        let arc_mutex_device = Arc::new(Mutex::new(device));

        let event_handler: Arc<dyn EventHandler> = Arc::new(UsbUtilEventHandler {
            device: arc_mutex_device.clone(),
        });

        if let Err(e) = self.event_loop.add_event(
            &*arc_mutex_device.lock(),
            WatchingEvents::empty().set_read().set_write(),
            Arc::downgrade(&event_handler),
        ) {
            error!("failed to add USB device fd to event handler: {}", e);
            return UsbControlResult::FailedToOpenDevice;
        }

        let device_ctx = HostDeviceContext {
            event_handler,
            device: arc_mutex_device.clone(),
        };

        // Resetting the device is used to make sure it is in a known state, but it may
        // still function if the reset fails.
        if let Err(e) = arc_mutex_device.lock().reset() {
            error!("failed to reset device after attach: {:?}", e);
        }

        let host_device = match HostDevice::new(
            self.fail_handle.clone(),
            self.job_queue.clone(),
            arc_mutex_device,
        ) {
            Ok(host_device) => Box::new(host_device),
            Err(e) => {
                error!("failed to initialize HostDevice: {}", e);
                return UsbControlResult::FailedToInitHostDevice;
            }
        };

        let port = self.usb_hub.connect_backend(host_device);
        match port {
            Ok(port) => {
                self.devices.lock().insert(port, device_ctx);
                UsbControlResult::Ok { port }
            }
            Err(e) => {
                error!("failed to connect device to hub: {}", e);
                UsbControlResult::NoAvailablePort
            }
        }
    }

    fn handle_detach_device(&self, port: u8) -> UsbControlResult {
        match self.usb_hub.disconnect_port(port) {
            Ok(()) => {
                if let Some(device_ctx) = self.devices.lock().remove(&port) {
                    let _ = device_ctx.event_handler.on_event();
                    let device = device_ctx.device.lock();
                    let fd = device.fd();

                    if let Err(e) = self.event_loop.remove_event_for_fd(&*fd) {
                        error!(
                            "failed to remove poll change handler from event loop: {}",
                            e
                        );
                    }
                }
                UsbControlResult::Ok { port }
            }
            Err(e) => {
                error!("failed to disconnect device from port {}: {}", port, e);
                UsbControlResult::NoSuchDevice
            }
        }
    }

    fn handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult {
        let mut devices: [UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS] = Default::default();
        for (result_index, &port_id) in ports.iter().enumerate() {
            match self.usb_hub.get_port(port_id).and_then(|p| {
                p.get_backend_device()
                    .as_ref()
                    .map(|d| (d.get_vid(), d.get_pid()))
            }) {
                Some((vendor_id, product_id)) => {
                    devices[result_index] = UsbControlAttachedDevice {
                        port: port_id,
                        vendor_id,
                        product_id,
                    }
                }
                None => continue,
            }
        }
        UsbControlResult::Devices(devices)
    }

    fn on_event_helper(&self) -> Result<()> {
        let tube = self.control_tube.lock();
        let cmd = tube.recv().map_err(Error::ReadControlTube)?;
        let result = match cmd {
            UsbControlCommand::AttachDevice { file, .. } => self.handle_attach_device(file),
            UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port),
            UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports),
        };
        tube.send(&result).map_err(Error::WriteControlTube)?;
        Ok(())
    }
}

impl EventHandler for ProviderInner {
    fn on_event(&self) -> anyhow::Result<()> {
        self.on_event_helper()
            .context("host backend device provider failed")
    }
}

struct UsbUtilEventHandler {
    device: Arc<Mutex<Device>>,
}

impl EventHandler for UsbUtilEventHandler {
    fn on_event(&self) -> anyhow::Result<()> {
        self.device
            .lock()
            .poll_transfers()
            .context("UsbUtilEventHandler poll_transfers failed")
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use crossbeam::sync::TreiberStack;

use device::Device;
use device::Queue;
use format::FormatDesc;
use image::sys::Dimensions;
use image::sys::UnsafeImage;
use image::sys::Usage as ImageUsage;
use image::swapchain::SwapchainImage;
use swapchain::CompositeAlpha;
use swapchain::PresentMode;
use swapchain::Surface;
use swapchain::SurfaceTransform;
use sync::Semaphore;
use sync::SharingMode;

use check_errors;
use Error;
use OomError;
use Success;
use SynchronizedVulkanObject;
use VulkanObject;
use VulkanPointers;
use vk;

/// Contains the swapping system and the images that can be shown on a surface.
pub struct Swapchain {
    device: Arc<Device>,
    surface: Arc<Surface>,
    swapchain: vk::SwapchainKHR,

    /// Pool of semaphores from which a semaphore is retreived when acquiring an image.
    semaphores_pool: TreiberStack<Arc<Semaphore>>,

    images_semaphores: Mutex<Vec<Option<Arc<Semaphore>>>>,
}

impl Swapchain {
    /// Builds a new swapchain. Allocates images who content can be made visible on a surface.
    ///
    /// See also the `Surface::get_capabilities` function which returns the values that are
    /// supported by the implementation. All the parameters that you pass to `Swapchain::new`
    /// must be supported.
    ///
    /// The `clipped` parameter indicates whether the implementation is allowed to discard
    /// rendering operations that affect regions of the surface which aren't visible. This is
    /// important to take into account if your fragment shader has side-effects or if you want to
    /// read back the content of the image afterwards.
    ///
    /// This function returns the swapchain plus a list of the images that belong to the
    /// swapchain. The order in which the images are returned is important for the
    /// `acquire_next_image` and `present` functions.
    ///
    /// # Panic
    ///
    /// - Panicks if the device and the surface don't belong to the same instance.
    /// - Panicks if `color_attachment` is false in `usage`.
    ///
    pub fn new<F, S>(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: F,
                     dimensions: [u32; 2], layers: u32, usage: &ImageUsage, sharing: S,
                     transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode,
                     clipped: bool) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), OomError>
        where F: FormatDesc + Clone, S: Into<SharingMode>
    {
        Swapchain::new_inner(device, surface, num_images, format, dimensions, layers, usage,
                             sharing, transform, alpha, mode, clipped)
    }

    // TODO:
    //pub fn recreate() { ... }

    // TODO: images layouts should always be set to "PRESENT", since we have no way to switch the
    //       layout at present time
    fn new_inner<F, S>(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: F,
                       dimensions: [u32; 2], layers: u32, usage: &ImageUsage, sharing: S,
                       transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode,
                       clipped: bool) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), OomError>
        where F: FormatDesc + Clone, S: Into<SharingMode>
    {
        // FIXME: check that the parameters are supported

        // FIXME: check that the device and the surface belong to the same instance
        let vk = device.pointers();
        assert!(device.loaded_extensions().khr_swapchain);     // TODO: return error instead

        assert!(usage.color_attachment);
        let usage = usage.to_usage_bits();

        let sharing = sharing.into();

        let swapchain = unsafe {
            let (sh_mode, sh_count, sh_indices) = match sharing {
                SharingMode::Exclusive(id) => (vk::SHARING_MODE_EXCLUSIVE, 0, ptr::null()),
                SharingMode::Concurrent(ref ids) => (vk::SHARING_MODE_CONCURRENT, ids.len() as u32,
                                                     ids.as_ptr()),
            };

            let infos = vk::SwapchainCreateInfoKHR {
                sType: vk::STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
                pNext: ptr::null(),
                flags: 0,   // reserved
                surface: surface.internal_object(),
                minImageCount: num_images,
                imageFormat: format.format() as u32,
                imageColorSpace: vk::COLORSPACE_SRGB_NONLINEAR_KHR,     // only available value
                imageExtent: vk::Extent2D { width: dimensions[0], height: dimensions[1] },
                imageArrayLayers: layers,
                imageUsage: usage,
                imageSharingMode: sh_mode,
                queueFamilyIndexCount: sh_count,
                pQueueFamilyIndices: sh_indices,
                preTransform: transform as u32,
                compositeAlpha: alpha as u32,
                presentMode: mode as u32,
                clipped: if clipped { vk::TRUE } else { vk::FALSE },
                oldSwapchain: 0,      // TODO:
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSwapchainKHR(device.internal_object(), &infos,
                                                    ptr::null(), &mut output)));
            output
        };

        let swapchain = Arc::new(Swapchain {
            device: device.clone(),
            surface: surface.clone(),
            swapchain: swapchain,
            semaphores_pool: TreiberStack::new(),
            images_semaphores: Mutex::new(Vec::new()),
        });

        let images = unsafe {
            let mut num = 0;
            try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
                                                       swapchain.swapchain, &mut num,
                                                       ptr::null_mut())));

            let mut images = Vec::with_capacity(num as usize);
            try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
                                                       swapchain.swapchain, &mut num,
                                                       images.as_mut_ptr())));
            images.set_len(num as usize);
            images
        };

        let images = images.into_iter().enumerate().map(|(id, image)| unsafe {
            let unsafe_image = UnsafeImage::from_raw(device, image, usage, format.format(),
                                                     Dimensions::Dim2d { width: dimensions[0], height: dimensions[1] }, 1, 1);
            SwapchainImage::from_raw(unsafe_image, format.format(), &swapchain, id as u32).unwrap()     // TODO: propagate error
        }).collect::<Vec<_>>();

        {
            let mut semaphores = swapchain.images_semaphores.lock().unwrap();
            for _ in 0 .. images.len() {
                swapchain.semaphores_pool.push(try!(Semaphore::new(device)));
                semaphores.push(None);
            }
        }

        Ok((swapchain, images))
    }

    /// Tries to take ownership of an image in order to draw on it.
    ///
    /// The function returns the index of the image in the array of images that was returned
    /// when creating the swapchain.
    ///
    /// If you try to draw on an image without acquiring it first, the execution will block. (TODO
    /// behavior may change).
    pub fn acquire_next_image(&self, timeout_ns: u64) -> Result<usize, AcquireError> {
        let vk = self.device.pointers();

        unsafe {
            let semaphore = self.semaphores_pool.pop().expect("Failed to obtain a semaphore from \
                                                               the swapchain semaphores pool");

            let mut out = mem::uninitialized();
            let r = try!(check_errors(vk.AcquireNextImageKHR(self.device.internal_object(),
                                                             self.swapchain, timeout_ns,
                                                             semaphore.internal_object(), 0,     // TODO: timeout
                                                             &mut out)));

            let id = match r {
                Success::Success => out as usize,
                Success::Suboptimal => out as usize,        // TODO: give that info to the user
                Success::NotReady => return Err(AcquireError::Timeout),
                Success::Timeout => return Err(AcquireError::Timeout),
                s => panic!("unexpected success value: {:?}", s)
            };

            let mut images_semaphores = self.images_semaphores.lock().unwrap();
            images_semaphores[id] = Some(semaphore);

            Ok(id)
        }
    }

    /// Presents an image on the screen.
    ///
    /// The parameter is the same index as what `acquire_next_image` returned. The image must
    /// have been acquired first.
    ///
    /// The actual behavior depends on the present mode that you passed when creating the
    /// swapchain.
    pub fn present(&self, queue: &Arc<Queue>, index: usize) -> Result<(), OomError> {     // FIXME: wrong error
        let vk = self.device.pointers();

        let wait_semaphore = {
            let mut images_semaphores = self.images_semaphores.lock().unwrap();
            images_semaphores[index].take().expect("Trying to present an image that was \
                                                    not acquired")
        };

        // FIXME: the semaphore will be destroyed ; need to return it

        unsafe {
            let mut result = mem::uninitialized();

            let queue = queue.internal_object_guard();
            let index = index as u32;

            let infos = vk::PresentInfoKHR {
                sType: vk::STRUCTURE_TYPE_PRESENT_INFO_KHR,
                pNext: ptr::null(),
                waitSemaphoreCount: 1,
                pWaitSemaphores: &wait_semaphore.internal_object(),
                swapchainCount: 1,
                pSwapchains: &self.swapchain,
                pImageIndices: &index,
                pResults: &mut result,
            };

            try!(check_errors(vk.QueuePresentKHR(*queue, &infos)));
            //try!(check_errors(result));       // TODO: AMD driver doesn't seem to write the result
        }

        self.semaphores_pool.push(wait_semaphore);
        Ok(())
    }

    /// Returns the semaphore that is going to be signalled when the image is going to be ready
    /// to be drawn upon.
    ///
    /// Returns `None` if the image was not acquired first, or was already presented.
    // TODO: racy, as someone could present the image before using the semaphore
    #[inline]
    pub fn image_semaphore(&self, id: u32) -> Option<Arc<Semaphore>> {
        let semaphores = self.images_semaphores.lock().unwrap();
        semaphores[id as usize].as_ref().map(|s| s.clone())
    }
}

impl Drop for Swapchain {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySwapchainKHR(self.device.internal_object(), self.swapchain, ptr::null());
        }
    }
}

/// Error that can happen when calling `acquire_next_image`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum AcquireError {
    Timeout,
    SurfaceLost,
    OutOfDate,
}

impl error::Error for AcquireError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            AcquireError::Timeout => "no image is available for acquiring yet",
            AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
            AcquireError::OutOfDate => "the swapchain needs to be recreated",
        }
    }
}

impl fmt::Display for AcquireError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for AcquireError {
    #[inline]
    fn from(err: Error) -> AcquireError {
        match err {
            Error::SurfaceLost => AcquireError::SurfaceLost,
            Error::OutOfDate => AcquireError::OutOfDate,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}
<commit_msg>Fix AMD kernel driver crash<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use crossbeam::sync::MsQueue;

use device::Device;
use device::Queue;
use format::FormatDesc;
use image::sys::Dimensions;
use image::sys::UnsafeImage;
use image::sys::Usage as ImageUsage;
use image::swapchain::SwapchainImage;
use swapchain::CompositeAlpha;
use swapchain::PresentMode;
use swapchain::Surface;
use swapchain::SurfaceTransform;
use sync::Semaphore;
use sync::SharingMode;

use check_errors;
use Error;
use OomError;
use Success;
use SynchronizedVulkanObject;
use VulkanObject;
use VulkanPointers;
use vk;

/// Contains the swapping system and the images that can be shown on a surface.
pub struct Swapchain {
    device: Arc<Device>,
    surface: Arc<Surface>,
    swapchain: vk::SwapchainKHR,

    /// Pool of semaphores from which a semaphore is retreived when acquiring an image.
    ///
    /// We need to use a queue so that we don't use the same semaphore twice in a row. The length
    /// of the queue is strictly superior to the number of images, in case the driver lets us
    /// acquire an image before it is presented.
    semaphores_pool: MsQueue<Arc<Semaphore>>,

    images_semaphores: Mutex<Vec<Option<Arc<Semaphore>>>>,
}

impl Swapchain {
    /// Builds a new swapchain. Allocates images who content can be made visible on a surface.
    ///
    /// See also the `Surface::get_capabilities` function which returns the values that are
    /// supported by the implementation. All the parameters that you pass to `Swapchain::new`
    /// must be supported.
    ///
    /// The `clipped` parameter indicates whether the implementation is allowed to discard
    /// rendering operations that affect regions of the surface which aren't visible. This is
    /// important to take into account if your fragment shader has side-effects or if you want to
    /// read back the content of the image afterwards.
    ///
    /// This function returns the swapchain plus a list of the images that belong to the
    /// swapchain. The order in which the images are returned is important for the
    /// `acquire_next_image` and `present` functions.
    ///
    /// # Panic
    ///
    /// - Panicks if the device and the surface don't belong to the same instance.
    /// - Panicks if `color_attachment` is false in `usage`.
    ///
    pub fn new<F, S>(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: F,
                     dimensions: [u32; 2], layers: u32, usage: &ImageUsage, sharing: S,
                     transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode,
                     clipped: bool) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), OomError>
        where F: FormatDesc + Clone, S: Into<SharingMode>
    {
        Swapchain::new_inner(device, surface, num_images, format, dimensions, layers, usage,
                             sharing, transform, alpha, mode, clipped)
    }

    // TODO:
    //pub fn recreate() { ... }

    // TODO: images layouts should always be set to "PRESENT", since we have no way to switch the
    //       layout at present time
    fn new_inner<F, S>(device: &Arc<Device>, surface: &Arc<Surface>, num_images: u32, format: F,
                       dimensions: [u32; 2], layers: u32, usage: &ImageUsage, sharing: S,
                       transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode,
                       clipped: bool) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), OomError>
        where F: FormatDesc + Clone, S: Into<SharingMode>
    {
        // FIXME: check that the parameters are supported

        // FIXME: check that the device and the surface belong to the same instance
        let vk = device.pointers();
        assert!(device.loaded_extensions().khr_swapchain);     // TODO: return error instead

        assert!(usage.color_attachment);
        let usage = usage.to_usage_bits();

        let sharing = sharing.into();

        let swapchain = unsafe {
            let (sh_mode, sh_count, sh_indices) = match sharing {
                SharingMode::Exclusive(id) => (vk::SHARING_MODE_EXCLUSIVE, 0, ptr::null()),
                SharingMode::Concurrent(ref ids) => (vk::SHARING_MODE_CONCURRENT, ids.len() as u32,
                                                     ids.as_ptr()),
            };

            let infos = vk::SwapchainCreateInfoKHR {
                sType: vk::STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
                pNext: ptr::null(),
                flags: 0,   // reserved
                surface: surface.internal_object(),
                minImageCount: num_images,
                imageFormat: format.format() as u32,
                imageColorSpace: vk::COLORSPACE_SRGB_NONLINEAR_KHR,     // only available value
                imageExtent: vk::Extent2D { width: dimensions[0], height: dimensions[1] },
                imageArrayLayers: layers,
                imageUsage: usage,
                imageSharingMode: sh_mode,
                queueFamilyIndexCount: sh_count,
                pQueueFamilyIndices: sh_indices,
                preTransform: transform as u32,
                compositeAlpha: alpha as u32,
                presentMode: mode as u32,
                clipped: if clipped { vk::TRUE } else { vk::FALSE },
                oldSwapchain: 0,      // TODO:
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSwapchainKHR(device.internal_object(), &infos,
                                                    ptr::null(), &mut output)));
            output
        };

        let swapchain = Arc::new(Swapchain {
            device: device.clone(),
            surface: surface.clone(),
            swapchain: swapchain,
            semaphores_pool: MsQueue::new(),
            images_semaphores: Mutex::new(Vec::new()),
        });

        let images = unsafe {
            let mut num = 0;
            try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
                                                       swapchain.swapchain, &mut num,
                                                       ptr::null_mut())));

            let mut images = Vec::with_capacity(num as usize);
            try!(check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
                                                       swapchain.swapchain, &mut num,
                                                       images.as_mut_ptr())));
            images.set_len(num as usize);
            images
        };

        let images = images.into_iter().enumerate().map(|(id, image)| unsafe {
            let unsafe_image = UnsafeImage::from_raw(device, image, usage, format.format(),
                                                     Dimensions::Dim2d { width: dimensions[0], height: dimensions[1] }, 1, 1);
            SwapchainImage::from_raw(unsafe_image, format.format(), &swapchain, id as u32).unwrap()     // TODO: propagate error
        }).collect::<Vec<_>>();

        {
            let mut semaphores = swapchain.images_semaphores.lock().unwrap();
            for _ in 0 .. images.len() {
                semaphores.push(None);
            }
        }

        for _ in 0 .. images.len() + 1 {
            swapchain.semaphores_pool.push(try!(Semaphore::new(device)));
        }

        Ok((swapchain, images))
    }

    /// Tries to take ownership of an image in order to draw on it.
    ///
    /// The function returns the index of the image in the array of images that was returned
    /// when creating the swapchain.
    ///
    /// If you try to draw on an image without acquiring it first, the execution will block. (TODO
    /// behavior may change).
    pub fn acquire_next_image(&self, timeout_ns: u64) -> Result<usize, AcquireError> {
        let vk = self.device.pointers();

        unsafe {
            let semaphore = self.semaphores_pool.try_pop().expect("Failed to obtain a semaphore from \
                                                                   the swapchain semaphores pool");

            let mut out = mem::uninitialized();
            let r = try!(check_errors(vk.AcquireNextImageKHR(self.device.internal_object(),
                                                             self.swapchain, timeout_ns,
                                                             semaphore.internal_object(), 0,     // TODO: timeout
                                                             &mut out)));

            let id = match r {
                Success::Success => out as usize,
                Success::Suboptimal => out as usize,        // TODO: give that info to the user
                Success::NotReady => return Err(AcquireError::Timeout),
                Success::Timeout => return Err(AcquireError::Timeout),
                s => panic!("unexpected success value: {:?}", s)
            };

            let mut images_semaphores = self.images_semaphores.lock().unwrap();
            images_semaphores[id] = Some(semaphore);

            Ok(id)
        }
    }

    /// Presents an image on the screen.
    ///
    /// The parameter is the same index as what `acquire_next_image` returned. The image must
    /// have been acquired first.
    ///
    /// The actual behavior depends on the present mode that you passed when creating the
    /// swapchain.
    pub fn present(&self, queue: &Arc<Queue>, index: usize) -> Result<(), OomError> {     // FIXME: wrong error
        let vk = self.device.pointers();

        let wait_semaphore = {
            let mut images_semaphores = self.images_semaphores.lock().unwrap();
            images_semaphores[index].take().expect("Trying to present an image that was \
                                                    not acquired")
        };

        // FIXME: the semaphore will be destroyed ; need to return it

        unsafe {
            let mut result = mem::uninitialized();

            let queue = queue.internal_object_guard();
            let index = index as u32;

            let infos = vk::PresentInfoKHR {
                sType: vk::STRUCTURE_TYPE_PRESENT_INFO_KHR,
                pNext: ptr::null(),
                waitSemaphoreCount: 1,
                pWaitSemaphores: &wait_semaphore.internal_object(),
                swapchainCount: 1,
                pSwapchains: &self.swapchain,
                pImageIndices: &index,
                pResults: &mut result,
            };

            try!(check_errors(vk.QueuePresentKHR(*queue, &infos)));
            //try!(check_errors(result));       // TODO: AMD driver doesn't seem to write the result
        }

        self.semaphores_pool.push(wait_semaphore);
        Ok(())
    }

    /// Returns the semaphore that is going to be signalled when the image is going to be ready
    /// to be drawn upon.
    ///
    /// Returns `None` if the image was not acquired first, or was already presented.
    // TODO: racy, as someone could present the image before using the semaphore
    #[inline]
    pub fn image_semaphore(&self, id: u32) -> Option<Arc<Semaphore>> {
        let semaphores = self.images_semaphores.lock().unwrap();
        semaphores[id as usize].as_ref().map(|s| s.clone())
    }
}

impl Drop for Swapchain {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySwapchainKHR(self.device.internal_object(), self.swapchain, ptr::null());
        }
    }
}

/// Error that can happen when calling `acquire_next_image`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum AcquireError {
    Timeout,
    SurfaceLost,
    OutOfDate,
}

impl error::Error for AcquireError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            AcquireError::Timeout => "no image is available for acquiring yet",
            AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
            AcquireError::OutOfDate => "the swapchain needs to be recreated",
        }
    }
}

impl fmt::Display for AcquireError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for AcquireError {
    #[inline]
    fn from(err: Error) -> AcquireError {
        match err {
            Error::SurfaceLost => AcquireError::SurfaceLost,
            Error::OutOfDate => AcquireError::OutOfDate,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}
<|endoftext|>


<commit_before>//! Implements `StdTimeManager`.

use std::sync::RwLock;
use std::time::{SystemTime, Duration};
use std::cmp::min;
use board::*;
use depth::*;
use value::*;
use search_executor::*;
use hash_table::Variation;
use search_node::SearchNode;
use time_manager::{TimeManager, RemainingTime};
use uci::{SetOption, OptionDescription};

/// Implements the `TimeManager` trait.
pub struct StdTimeManager {
    started_at: SystemTime,
    depth: Depth,
    value: Value,
    data_points: Vec<(f64, f64)>,
    hard_limit: f64,
    allotted_time: f64,
    must_play: bool,
}

impl<T> TimeManager<T> for StdTimeManager
    where T: SearchExecutor<ReportData = Vec<Variation>>
{
    fn new(position: &T::SearchNode, time: &RemainingTime) -> StdTimeManager {
        // Get our remaining time and time increment (in milliseconds).
        let (t, inc) = if position.board().to_move == WHITE {
            (time.white_millis as f64, time.winc_millis as f64)
        } else {
            (time.black_millis as f64, time.binc_millis as f64)
        };

        // Get the number of moves until the next time control, or if
        // not available, guess the number of moves to the end of the
        // game.
        let n = time.movestogo.unwrap_or(40) as f64;
        debug_assert!(n >= 1.0);

        // Calculate the total time we have.
        let time_heap = t + inc * (n - 1.0);

        // Set a hard limit for the time we will spend on this
        // move. Thinking longer that that would be reckless.
        let hard_limit = (t / n.sqrt() + inc).min(t - 1000.0);

        StdTimeManager {
            started_at: SystemTime::now(),
            depth: 0,
            value: VALUE_UNKNOWN,
            data_points: Vec::with_capacity(32),
            hard_limit: if position.legal_moves().len() > 1 {
                hard_limit
            } else {
                // When there is only one legal move, the engine is
                // allowed to think just a fraction of a second in
                // order to find a good ponder move.
                hard_limit.min(500.0)
            },
            allotted_time: if *PONDERING_IS_ALLOWED.read().unwrap() {
                // Statistically, the move we ponder will be played in
                // 50% of the cases. Therefore, in principal we should
                // add half of opponent's thinking time to our time
                // heap. In reality we do not know how opponent's time
                // will be spend, so we speculatively increase our
                // time heap by 50%.
                1.5 * time_heap / n
            } else {
                time_heap / n
            },
            must_play: false,
        }
    }

    #[allow(unused_variables)]
    fn must_play(&mut self,
                 search_executor: &mut T,
                 report: Option<&SearchReport<Vec<Variation>>>)
                 -> bool {
        if !self.must_play {
            let mut is_finished = false;
            if let Some(r) = report {
                if r.depth > self.depth {
                    self.depth = r.depth;
                    let (target_depth, t_next) = self.target_depth(r);
                    let msg = format!("TARGET_DEPTH={}", target_depth);
                    search_executor.send_message(msg.as_str());
                    is_finished = r.depth >= target_depth || t_next > self.hard_limit
                }
            }
            self.must_play = is_finished || elapsed_millis(&self.started_at) > self.hard_limit;
        }
        self.must_play
    }
}

impl SetOption for StdTimeManager {
    fn options() -> Vec<(String, OptionDescription)> {
        vec![("Ponder".to_string(), OptionDescription::Check { default: false })]
    }

    fn set_option(name: &str, value: &str) {
        if name == "Ponder" {
            match value {
                "true" => *PONDERING_IS_ALLOWED.write().unwrap() = true,
                "false" => *PONDERING_IS_ALLOWED.write().unwrap() = false,
                _ => (),
            }
        }
    }
}

impl StdTimeManager {
    /// Guesses what target depth we will be able to reach, and how
    /// much time (milliseconds) it will take for the next search
    /// depth to complete.
    fn target_depth(&mut self, report: &SearchReport<Vec<Variation>>) -> (Depth, f64) {
        let t = elapsed_millis(&self.started_at);

        // Ignore the first 1-2 depths.
        if t < 0.001 || report.searched_nodes < 100 {
            return (DEPTH_MAX, t);
        }

        // Add (x, y) to the list of data points.
        let x = report.depth as f64;
        let y = t.ln();
        self.data_points.push((x, y));

        // Do a linear extrapolation based on the last `M` data points.
        const M: usize = 5;
        let y_max = self.allotted_time.max(0.001).ln();
        let x_max;
        let t_next;
        match self.data_points.len() {
            n if n >= M => {
                let last_m = &self.data_points[n - M..];
                let (slope, intercept) = linear_regression(last_m);
                debug_assert!(slope >= 0.001);
                if n == M {
                    let mut s = AVG_SLOPE.write().unwrap();
                    *s = (*s * 2.0 + slope) / 3.0;
                }
                x_max = (y_max - intercept) / slope;
                t_next = (slope * (x + 1.0) + intercept).exp();
            }
            _ => {
                // There are not enough data points yet -- use `AVG_SLOPE`.
                let s = AVG_SLOPE.read().unwrap();
                x_max = x + (y_max - y) / *s;
                t_next = t * s.exp();
            }
        };

        // Set the target depth as close as possible to `x_max`.
        let mut target_depth = x_max.round()
                                    .min(DEPTH_MAX as f64)
                                    .max(DEPTH_MIN as f64) as Depth;

        // Search one ply deeper if the target depth is reached, but
        // position's evaluation has changed a lot.
        //
        // TODO: `25` must be bound to pawn's value.
        if target_depth == report.depth &&
           (self.value != VALUE_UNKNOWN && report.value != VALUE_UNKNOWN) &&
           (self.value as isize - report.value as isize).abs() >= 25 {
            target_depth = min(target_depth + 1, DEPTH_MAX);
        }
        self.value = report.value;

        (target_depth, 1.5 * t_next)
    }
}

lazy_static! {
    static ref PONDERING_IS_ALLOWED: RwLock<bool> = RwLock::new(false);
    static ref AVG_SLOPE: RwLock<f64> = RwLock::new(0.7);
}

/// Calculates elapsed milliseconds since a given time.
fn elapsed_millis(since: &SystemTime) -> f64 {
    let d = since.elapsed().unwrap_or(Duration::from_millis(0));
    (1000 * d.as_secs()) as f64 + (d.subsec_nanos() / 1_000_000) as f64
}

/// Calculates a regression line that approximates `points`.
fn linear_regression(points: &[(f64, f64)]) -> (f64, f64) {
    debug_assert!(points.len() > 1);
    let sum_x = points.iter().fold(0.0, |acc, &p| acc + p.0);
    let sum_y = points.iter().fold(0.0, |acc, &p| acc + p.1);
    let sum_xx = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.0);
    let sum_xy = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.1);
    let n = points.len() as f64;
    let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
    let intercept = (sum_y - slope * sum_x) / n;
    (slope.max(0.001), intercept)
}

#[cfg(test)]
mod tests {
    #[test]
    fn linear_regression() {
        use super::linear_regression;
        let points = vec![(21.0, 1.0), (22.0, 2.0), (23.0, 3.0), (24.0, 4.0)];
        let x = 25.0;
        let (slope, intercept) = linear_regression(&points);
        let y = slope * x + intercept;
        assert!(4.99 < y && y < 5.01);
    }
}
<commit_msg>use t_pessimistic<commit_after>//! Implements `StdTimeManager`.

use std::sync::RwLock;
use std::time::{SystemTime, Duration};
use std::cmp::min;
use board::*;
use depth::*;
use value::*;
use search_executor::*;
use hash_table::Variation;
use search_node::SearchNode;
use time_manager::{TimeManager, RemainingTime};
use uci::{SetOption, OptionDescription};

/// Implements the `TimeManager` trait.
pub struct StdTimeManager {
    started_at: SystemTime,
    depth: Depth,
    value: Value,
    data_points: Vec<(f64, f64)>,
    hard_limit: f64,
    allotted_time: f64,
    must_play: bool,
}

impl<T> TimeManager<T> for StdTimeManager
    where T: SearchExecutor<ReportData = Vec<Variation>>
{
    fn new(position: &T::SearchNode, time: &RemainingTime) -> StdTimeManager {
        // Get our remaining time and time increment (in milliseconds).
        let (t, inc) = if position.board().to_move == WHITE {
            (time.white_millis as f64, time.winc_millis as f64)
        } else {
            (time.black_millis as f64, time.binc_millis as f64)
        };

        // Get the number of moves until the next time control, or if
        // not available, guess the number of moves to the end of the
        // game.
        let n = time.movestogo.unwrap_or(40) as f64;
        debug_assert!(n >= 1.0);

        // Calculate the total time we have.
        let time_heap = t + inc * (n - 1.0);

        // Set a hard limit for the time we will spend on this
        // move. Thinking longer that that would be reckless.
        let hard_limit = (t / n.sqrt() + inc).min(t - 1000.0);

        StdTimeManager {
            started_at: SystemTime::now(),
            depth: 0,
            value: VALUE_UNKNOWN,
            data_points: Vec::with_capacity(32),
            hard_limit: if position.legal_moves().len() > 1 {
                hard_limit
            } else {
                // When there is only one legal move, the engine is
                // allowed to think just a fraction of a second in
                // order to find a good ponder move.
                hard_limit.min(500.0)
            },
            allotted_time: if *PONDERING_IS_ALLOWED.read().unwrap() {
                // Statistically, the move we ponder will be played in
                // 50% of the cases. Therefore, in principal we should
                // add half of opponent's thinking time to our time
                // heap. In reality we do not know how opponent's time
                // will be spend, so we speculatively increase our
                // time heap by 50%.
                1.5 * time_heap / n
            } else {
                time_heap / n
            },
            must_play: false,
        }
    }

    #[allow(unused_variables)]
    fn must_play(&mut self,
                 search_executor: &mut T,
                 report: Option<&SearchReport<Vec<Variation>>>)
                 -> bool {
        if !self.must_play {
            let mut is_finished = false;
            if let Some(r) = report {
                if r.depth > self.depth {
                    self.depth = r.depth;
                    let (target_depth, t_next) = self.target_depth(r);
                    let t_pessimistic = t_next * AVG_SLOPE.read().unwrap().exp().sqrt();
                    let msg = format!("TARGET_DEPTH={}", target_depth);
                    search_executor.send_message(msg.as_str());
                    is_finished = r.depth >= target_depth || t_pessimistic > self.hard_limit
                }
            }
            self.must_play = is_finished || elapsed_millis(&self.started_at) > self.hard_limit;
        }
        self.must_play
    }
}

impl SetOption for StdTimeManager {
    fn options() -> Vec<(String, OptionDescription)> {
        vec![("Ponder".to_string(), OptionDescription::Check { default: false })]
    }

    fn set_option(name: &str, value: &str) {
        if name == "Ponder" {
            match value {
                "true" => *PONDERING_IS_ALLOWED.write().unwrap() = true,
                "false" => *PONDERING_IS_ALLOWED.write().unwrap() = false,
                _ => (),
            }
        }
    }
}

impl StdTimeManager {
    /// Guesses what target depth we will be able to reach, and how
    /// much time (milliseconds) it will take for the next search
    /// depth to complete.
    fn target_depth(&mut self, report: &SearchReport<Vec<Variation>>) -> (Depth, f64) {
        let t = elapsed_millis(&self.started_at);

        // Ignore the first 1-2 depths.
        if t < 0.001 || report.searched_nodes < 100 {
            return (DEPTH_MAX, t);
        }

        // Add (x, y) to the list of data points.
        let x = report.depth as f64;
        let y = t.ln();
        self.data_points.push((x, y));

        // Do a linear extrapolation based on the last `M` data points.
        const M: usize = 5;
        let y_max = self.allotted_time.max(0.001).ln();
        let x_max;
        let t_next;
        match self.data_points.len() {
            n if n >= M => {
                let last_m = &self.data_points[n - M..];
                let (slope, intercept) = linear_regression(last_m);
                debug_assert!(slope >= 0.001);
                if n == M {
                    let mut s = AVG_SLOPE.write().unwrap();
                    *s = (*s * 2.0 + slope) / 3.0;
                }
                x_max = (y_max - intercept) / slope;
                t_next = (slope * (x + 1.0) + intercept).exp();
            }
            _ => {
                // There are not enough data points yet -- use `AVG_SLOPE`.
                let s = AVG_SLOPE.read().unwrap();
                x_max = x + (y_max - y) / *s;
                t_next = t * s.exp();
            }
        };

        // Set the target depth as close as possible to `x_max`.
        let mut target_depth = x_max.round()
                                    .min(DEPTH_MAX as f64)
                                    .max(DEPTH_MIN as f64) as Depth;

        // Search one ply deeper if the target depth is reached, but
        // position's evaluation has changed a lot.
        //
        // TODO: `25` must be bound to pawn's value.
        if target_depth == report.depth &&
           (self.value != VALUE_UNKNOWN && report.value != VALUE_UNKNOWN) &&
           (self.value as isize - report.value as isize).abs() >= 25 {
            target_depth = min(target_depth + 1, DEPTH_MAX);
        }
        self.value = report.value;

        (target_depth, t_next)
    }
}

lazy_static! {
    static ref PONDERING_IS_ALLOWED: RwLock<bool> = RwLock::new(false);
    static ref AVG_SLOPE: RwLock<f64> = RwLock::new(0.7);
}

/// Calculates elapsed milliseconds since a given time.
fn elapsed_millis(since: &SystemTime) -> f64 {
    let d = since.elapsed().unwrap_or(Duration::from_millis(0));
    (1000 * d.as_secs()) as f64 + (d.subsec_nanos() / 1_000_000) as f64
}

/// Calculates a regression line that approximates `points`.
fn linear_regression(points: &[(f64, f64)]) -> (f64, f64) {
    debug_assert!(points.len() > 1);
    let sum_x = points.iter().fold(0.0, |acc, &p| acc + p.0);
    let sum_y = points.iter().fold(0.0, |acc, &p| acc + p.1);
    let sum_xx = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.0);
    let sum_xy = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.1);
    let n = points.len() as f64;
    let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
    let intercept = (sum_y - slope * sum_x) / n;
    (slope.max(0.001), intercept)
}

#[cfg(test)]
mod tests {
    #[test]
    fn linear_regression() {
        use super::linear_regression;
        let points = vec![(21.0, 1.0), (22.0, 2.0), (23.0, 3.0), (24.0, 4.0)];
        let x = 25.0;
        let (slope, intercept) = linear_regression(&points);
        let y = slope * x + intercept;
        assert!(4.99 < y && y < 5.01);
    }
}
<|endoftext|>


<commit_before>struct Parser {}

extern crate regex;
extern crate itertools;

use itertools::Itertools;
use regex::Regex;
use std::fs::File;
use std::path::Path;
use std::io::BufReader;
use std::io::BufRead;
use std::io;

struct Room {
    name: String,
    id: i32,
    checksum: String
}

impl Room {
    fn new(name: &str, id: i32, checksum: &str) -> Room {
        Room {name: name.to_string(), id: id, checksum: checksum.to_string()}
    }

    fn valid(&self) -> bool {
        let groups = self.name.chars().into_iter().group_by(|&x| x);
        for group in groups {
            println!("{}", group.sum::<i32>().abs());
        }

        self.name.len() > 0
    }
}

impl Parser {
    fn parse(str: &str, re: &Regex) -> Option<Room> {
        match re.captures(str) {
            Some(c) => {
                let name = c
                    .at(1)
                    .unwrap()
                    .chars()
                    .filter(|x| x != &'-')
                    .collect::<String>();
                let id = c.at(2).unwrap().parse::<i32>().unwrap();
                let checksum = c.at(3).unwrap();

                Some(Room::new(&name, id, checksum))
            }
            None => None
        }
    }

    fn load(src: &str) -> Result<Vec<Room>,io::Error> {
        let path = Path::new(src);
        let file = (File::open(path))?;
        let reader = BufReader::new(&file);
        let re = Regex::new(r"([a-z-]+)-([0-9]+)\[([a-z]+)\]").unwrap();

        let n = reader
            .lines()
            .map(|x| x.unwrap())
            .map(|x| Parser::parse(&x, &re))
            .filter(|x| x.is_some())
            .map(|x| x.unwrap())
            .collect();

        Ok(n)
    }
}

fn main() {
    let rooms = Parser::load("input.txt").unwrap_or(Vec::new());

    for i in rooms {
        println!("room: {} {} {} {}", i.name, i.id, i.checksum, i.valid());
    }
}
<commit_msg>Added day 4 solution<commit_after>struct Parser {}

extern crate regex;
extern crate itertools;

use itertools::Itertools;
use regex::Regex;
use std::fs::File;
use std::path::Path;
use std::io::BufReader;
use std::io::BufRead;
use std::io;

struct Room {
    name: String,
    raw_name: String,
    id: i32,
    checksum: String
}

impl Room {
    fn new(name: &str, raw_name: &str, id: i32, checksum: &str) -> Room {
        Room {name: name.to_string(), raw_name: raw_name.to_string(), id: id, checksum: checksum.to_string()}
    }

    fn valid(&self) -> bool {
        let c1 = self.name.chars()
            .sorted();
        let groups = c1
            .iter()
            .group_by(|&x| x);
        let chars = groups
            .into_iter()
            .map(|(c,n)| (-(n.count() as i32), c))
            .sorted();
        let c3 = chars.iter()
            .map(|&(_,c)|c)
            .cloned()
            .collect::<String>();
        let c4 = &c3[0..5];

        self.checksum == c4
    }

    fn decrypt(&self) -> String {
        let start = 'a' as i32;
        let stop = 'z' as i32;
        let c1 = self.raw_name.chars()
            .map(|c| {
                match c {
                    '-' => { ' ' }
                    c => ((start + (((c as i32)-start) + self.id) % (1 + (stop-start))) as u8) as char
                }
            })
            .collect::<String>();

        c1
    }
}

impl Parser {
    fn parse(str: &str, re: &Regex) -> Option<Room> {
        match re.captures(str) {
            Some(c) => {
                let name = c
                    .at(1)
                    .unwrap()
                    .chars()
                    .filter(|x| x != &'-')
                    .collect::<String>();
                let raw_name = c
                    .at(1)
                    .unwrap()
                    .chars()
                    .collect::<String>();
                let id = c.at(2).unwrap().parse::<i32>().unwrap();
                let checksum = c.at(3).unwrap();

                Some(Room::new(&name, &raw_name, id, checksum))
            }
            None => None
        }
    }

    fn load(src: &str) -> Result<Vec<Room>,io::Error> {
        let path = Path::new(src);
        let file = (File::open(path))?;
        let reader = BufReader::new(&file);
        let re = Regex::new(r"([a-z-]+)-([0-9]+)\[([a-z]+)\]").unwrap();

        let n = reader
            .lines()
            .map(|x| x.unwrap())
            .map(|x| Parser::parse(&x, &re))
            .filter(|x| x.is_some())
            .map(|x| x.unwrap())
            .collect();

        Ok(n)
    }
}

fn main() {
    let rooms = Parser::load("input.txt").unwrap_or(Vec::new());

    let sum = rooms.iter().filter(|&r| r.valid()).map(|ref r| r.id).sum::<i32>();

    println!("SUM {}", sum);

    match rooms.iter().find(|&r| r.valid() && r.decrypt() == "northpole object storage") {
        Some(room) => { println!("ROOM {}", room.id) }
        None => println!("NO ROOM")
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use rustc_target::spec::Target;
use std::any::Any;
use std::path::Path;

pub struct NoLlvmMetadataLoader;

impl MetadataLoader for NoLlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
        unreachable!("some_crate.rs shouldn't depend on any external crates");
    }

    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
        unreachable!("some_crate.rs shouldn't depend on any external crates");
    }
}

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        Box::new(NoLlvmMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {}
    fn provide_extern(&self, providers: &mut Providers) {}

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        use rustc_hir::def_id::LOCAL_CRATE;

        Box::new(CodegenResults {
            crate_name: tcx.crate_name(LOCAL_CRATE),
            modules: vec![],
            allocator_module: None,
            metadata_module: None,
            metadata,
            windows_subsystem: None,
            linker_info: LinkerInfo::new(tcx),
            crate_info: CrateInfo::new(tcx),
        })
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let codegen_results = ongoing_codegen
            .downcast::<CodegenResults>()
            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
        Ok((*codegen_results, FxHashMap::default()))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name = codegen_results.crate_name;
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<commit_msg>Fix hotplug codegen backend test<commit_after>#![feature(rustc_private)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use rustc_target::spec::Target;
use std::any::Any;
use std::path::Path;

pub struct NoLlvmMetadataLoader;

impl MetadataLoader for NoLlvmMetadataLoader {
    fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
        unreachable!("some_crate.rs shouldn't depend on any external crates");
    }

    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
        unreachable!("some_crate.rs shouldn't depend on any external crates");
    }
}

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        Box::new(NoLlvmMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {}
    fn provide_extern(&self, providers: &mut Providers) {}

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        use rustc_hir::def_id::LOCAL_CRATE;

        Box::new(CodegenResults {
            crate_name: tcx.crate_name(LOCAL_CRATE),
            modules: vec![],
            allocator_module: None,
            metadata_module: None,
            metadata,
            windows_subsystem: None,
            linker_info: LinkerInfo::new(tcx, "fake_target_cpu".to_string()),
            crate_info: CrateInfo::new(tcx),
        })
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let codegen_results = ongoing_codegen
            .downcast::<CodegenResults>()
            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
        Ok((*codegen_results, FxHashMap::default()))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name = codegen_results.crate_name;
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;

use syn;

use bindgen::config::{Config, Language};
use bindgen::writer::{Source, SourceWriter};

#[derive(Debug, Clone)]
pub struct Documentation {
    pub doc_comment: Vec<String>
}

impl Documentation {
    pub fn load(attrs: &Vec<syn::Attribute>) -> Self {
        let mut doc = Vec::new();

        for attr in attrs {
            if attr.style == syn::AttrStyle::Outer {
                // This requires a bit of explanation.  The syn intended way to
                // deal with doc strings is to use the is_sugared_doc attribute.
                // This however is not set when we go through the macro expansion
                // step through rust.  In that case they are stored as doc
                // attributes and the leading three slashes (and optional space)
                // are not included.
                if let syn::MetaItem::NameValue(
                    ref name, syn::Lit::Str(ref comment, _)) = attr.value
                {
                    if &*name == "doc" {
                        let line = if attr.is_sugared_doc {
                            comment
                                .trim_left_matches("/// ")
                                .trim_left_matches("///")
                                .trim_right()
                        } else {
                            comment.trim_left_matches(" ").trim_right()
                        };
                        if !line.starts_with("cbindgen:") {
                            doc.push(line.to_owned());
                        }
                    }
                }
            }
        }

        Documentation {
            doc_comment: doc,
        }
    }

    pub fn none() -> Self {
        Documentation {
            doc_comment: Vec::new(),
        }
    }
}

impl Source for Documentation {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        if self.doc_comment.is_empty() || !config.documentation {
            return;
        }

        if config.language == Language::C {
            out.write("/*");
            out.new_line();
        }
        for line in &self.doc_comment {
            if config.language != Language::C {
                out.write("// ");
            } else {
                out.write(" * ");
            }
            out.write(line);
            out.new_line();
        }
        if config.language == Language::C {
            out.write(" */");
            out.new_line();
        }
    }
}
<commit_msg>Avoid adding whitespace errors<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;

use syn;

use bindgen::config::{Config, Language};
use bindgen::writer::{Source, SourceWriter};

#[derive(Debug, Clone)]
pub struct Documentation {
    pub doc_comment: Vec<String>
}

impl Documentation {
    pub fn load(attrs: &Vec<syn::Attribute>) -> Self {
        let mut doc = Vec::new();

        for attr in attrs {
            if attr.style == syn::AttrStyle::Outer {
                // This requires a bit of explanation.  The syn intended way to
                // deal with doc strings is to use the is_sugared_doc attribute.
                // This however is not set when we go through the macro expansion
                // step through rust.  In that case they are stored as doc
                // attributes and the leading three slashes (and optional space)
                // are not included.
                if let syn::MetaItem::NameValue(
                    ref name, syn::Lit::Str(ref comment, _)) = attr.value
                {
                    if &*name == "doc" {
                        let line = if attr.is_sugared_doc {
                            comment
                                .trim_left_matches("/// ")
                                .trim_left_matches("///")
                                .trim_right()
                        } else {
                            comment.trim_left_matches(" ").trim_right()
                        };
                        if !line.starts_with("cbindgen:") {
                            doc.push(line.to_owned());
                        }
                    }
                }
            }
        }

        Documentation {
            doc_comment: doc,
        }
    }

    pub fn none() -> Self {
        Documentation {
            doc_comment: Vec::new(),
        }
    }
}

impl Source for Documentation {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        if self.doc_comment.is_empty() || !config.documentation {
            return;
        }

        if config.language == Language::C {
            out.write("/*");
            out.new_line();
        }
        for line in &self.doc_comment {
            if config.language != Language::C {
                out.write("//");
            } else {
                out.write(" *");
            }
            if line.len() != 0 {
                out.write(" ");
            }
            out.write(line);
            out.new_line();
        }
        if config.language == Language::C {
            out.write(" */");
            out.new_line();
        }
    }
}
<|endoftext|>


<commit_before>// xfail-fast - check-fast doesn't understand aux-build
// aux-build:trait_inheritance_overloading_xc.rs

extern mod trait_inheritance_overloading_xc;
use trait_inheritance_overloading_xc::{MyNum, MyInt};

fn f<T:Copy MyNum>(x: T, y: T) -> (T, T, T) {
    return (x + y, x - y, x * y);
}

pure fn mi(v: int) -> MyInt { MyInt { val: v } }

fn main() {
    let (x, y) = (mi(3), mi(5));
    let (a, b, c) = f(x, y);
    assert a == mi(8);
    assert b == mi(-2);
    assert c == mi(15);
}

<commit_msg>Xfail trait-inheritance-overloading-xc-exe<commit_after>// xfail-test
// xfail-fast - check-fast doesn't understand aux-build
// aux-build:trait_inheritance_overloading_xc.rs

extern mod trait_inheritance_overloading_xc;
use trait_inheritance_overloading_xc::{MyNum, MyInt};

fn f<T:Copy MyNum>(x: T, y: T) -> (T, T, T) {
    return (x + y, x - y, x * y);
}

pure fn mi(v: int) -> MyInt { MyInt { val: v } }

fn main() {
    let (x, y) = (mi(3), mi(5));
    let (a, b, c) = f(x, y);
    assert a == mi(8);
    assert b == mi(-2);
    assert c == mi(15);
}

<|endoftext|>


<commit_before>extern mod extra;

use std::os;
use std::path;
#[feature(globs)]
use extra::getopts::{getopts, reqopt, optflag, Opt};
use grid::{Grid, Printable};
use util::console;
use util::thread;

mod util;
mod grid;

fn print_usage(program_name: &str, _opts: &[Opt]) {
	println!("Usage: {:s} [options]", program_name);
	println("  -i\t\t-> Path to input file");
	println("  -h | -help\t-> Print this help message");
}

fn main() {

	let args : ~[~str] = os::args();

	let opts = ~[
		reqopt("i"),
		optflag("h"),
		optflag("help")
	];

	let program_name: ~str = args[0].clone();

	let opt_matches = match getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => {
			print_usage(program_name, opts);
			println("");
			fail!(f.to_err_msg());
		}
	};

	if opt_matches.opt_present("h") ||
	   opt_matches.opt_present("help") {
		print_usage(program_name, opts);
		return;
	}

	let input: &str = match opt_matches.opt_str("i") {
		Some(s) => s,
		None => fail!("Option -i not provided a value.")
	};

	let input_path = ~path::Path(input);
	let mut g: ~Grid = Grid::load(input_path);

	console::clear();
	g.print();
	thread::sleep(500);

	loop {
		console::clear();
		g.step();
		g.print();
		thread::sleep(500);
	}
}
<commit_msg>removed #[feature(glob)] from using statements<commit_after>extern mod extra;

use std::os;
use std::path;
use extra::getopts::{getopts, reqopt, optflag, Opt};
use grid::{Grid, Printable};
use util::console;
use util::thread;

mod util;
mod grid;

fn print_usage(program_name: &str, _opts: &[Opt]) {
	println!("Usage: {:s} [options]", program_name);
	println("  -i\t\t-> Path to input file");
	println("  -h | -help\t-> Print this help message");
}

fn main() {

	let args : ~[~str] = os::args();

	let opts = ~[
		reqopt("i"),
		optflag("h"),
		optflag("help")
	];

	let program_name: ~str = args[0].clone();

	let opt_matches = match getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => {
			print_usage(program_name, opts);
			println("");
			fail!(f.to_err_msg());
		}
	};

	if opt_matches.opt_present("h") ||
	   opt_matches.opt_present("help") {
		print_usage(program_name, opts);
		return;
	}

	let input: &str = match opt_matches.opt_str("i") {
		Some(s) => s,
		None => fail!("Option -i not provided a value.")
	};

	let input_path = ~path::Path(input);
	let mut g: ~Grid = Grid::load(input_path);

	console::clear();
	g.print();
	thread::sleep(500);

	loop {
		console::clear();
		g.step();
		g.print();
		thread::sleep(500);
	}
}
<|endoftext|>


<commit_before>use sdl2::pixels::Color;
use sdl2::render::Renderer;
use sdl2_gfx::primitives::DrawRenderer;

use graphics::primitives::*;
use graphics::math::matrix::*;

pub struct Line {
    p1:      Point2D,
    p2:      Point2D,
    anchor:  Point2D,
    color:   Color
}

#[allow(dead_code)]
impl Line {
    pub fn new(point1: &Point2D, point2: &Point2D, color: Color) -> Line {
        let average = Point2D::new(
            (point2.x + point1.x) / 2.0,
            (point2.y + point1.y) / 2.0,
        );

        Line {
            p1:      point1.clone(),
            p2:      point2.clone(),
            anchor:  average,
            color:   color,
        }
    }

    fn draw_bresenham_line(&self, renderer: &Renderer) {
        use std::mem::swap;

        let mut x1 = self.p1.x as i16;
        let mut y1 = self.p1.y as i16;
        let mut x2 = self.p2.x as i16;
        let mut y2 = self.p2.y as i16;

        let steep = (y2 - y1).abs() > (x2 - x1).abs();
        if steep {
            swap(&mut x1, &mut y1);
            swap(&mut x2, &mut y2);
        }

        if x1 > x2 {
            swap(&mut x1, &mut x2);
            swap(&mut y1, &mut y2);
        }

        let dx =  x2 - x1;
        let dy = (y2 - y1).abs();

        let mut error = dx / 2;
        let mut y = y1;

        let ystep = if y1 < y2 { 1 } else { -1 };

        for x in x1..x2 {
            renderer.pixel(
                if steep { y } else { x },
                if steep { x } else { y },
                self.color
            ).unwrap();

            error -= dy;
            if error < 0 {
                y     += ystep;
                error += dx;
            }
        }
    }

    pub fn draw_builtin_line(&self, renderer: &Renderer) {
        renderer.line(
            self.p1.x as i16,
            self.p1.y as i16,
            self.p2.x as i16,
            self.p2.y as i16,
            self.color
        ).unwrap();
    }
}

impl Primitive2D for Line {
    fn to_matrix(&self) -> Matrix {
        Matrix::new(
            vec![[self.p1.x,      self.p1.y,      1.0],
                 [self.p2.x,      self.p2.y,      1.0],
                 [1.0,            1.0,            1.0]]
        )
    }

    fn from_matrix(&mut self, m: &Matrix) {
        self.p1 = Point2D::new(m.matrix[0][0], m.matrix[0][1]);
        self.p2 = Point2D::new(m.matrix[1][0], m.matrix[1][1]);
    }

    fn anchor_point(&self) -> Point2D {
        self.anchor.clone()
    }

    fn set_anchor_point(&mut self, anchor: &Point2D) {
        self.anchor = anchor.clone();
    }

    #[inline]
    fn draw(&self, renderer: &Renderer) {
        self.draw_bresenham_line(renderer);
    }

    fn fill(&self, renderer: &Renderer) {
        self.draw_bresenham_line(renderer);
    }
}
<commit_msg>Removed unnecessaty matrix line<commit_after>use sdl2::pixels::Color;
use sdl2::render::Renderer;
use sdl2_gfx::primitives::DrawRenderer;

use graphics::primitives::*;
use graphics::math::matrix::*;

pub struct Line {
    p1:      Point2D,
    p2:      Point2D,
    anchor:  Point2D,
    color:   Color
}

#[allow(dead_code)]
impl Line {
    pub fn new(point1: &Point2D, point2: &Point2D, color: Color) -> Line {
        let average = Point2D::new(
            (point2.x + point1.x) / 2.0,
            (point2.y + point1.y) / 2.0,
        );

        Line {
            p1:      point1.clone(),
            p2:      point2.clone(),
            anchor:  average,
            color:   color,
        }
    }

    fn draw_bresenham_line(&self, renderer: &Renderer) {
        use std::mem::swap;

        let mut x1 = self.p1.x as i16;
        let mut y1 = self.p1.y as i16;
        let mut x2 = self.p2.x as i16;
        let mut y2 = self.p2.y as i16;

        let steep = (y2 - y1).abs() > (x2 - x1).abs();
        if steep {
            swap(&mut x1, &mut y1);
            swap(&mut x2, &mut y2);
        }

        if x1 > x2 {
            swap(&mut x1, &mut x2);
            swap(&mut y1, &mut y2);
        }

        let dx =  x2 - x1;
        let dy = (y2 - y1).abs();

        let mut error = dx / 2;
        let mut y = y1;

        let ystep = if y1 < y2 { 1 } else { -1 };

        for x in x1..x2 {
            renderer.pixel(
                if steep { y } else { x },
                if steep { x } else { y },
                self.color
            ).unwrap();

            error -= dy;
            if error < 0 {
                y     += ystep;
                error += dx;
            }
        }
    }

    pub fn draw_builtin_line(&self, renderer: &Renderer) {
        renderer.line(
            self.p1.x as i16,
            self.p1.y as i16,
            self.p2.x as i16,
            self.p2.y as i16,
            self.color
        ).unwrap();
    }
}

impl Primitive2D for Line {
    fn to_matrix(&self) -> Matrix {
        Matrix::new(
            vec![[self.p1.x,      self.p1.y,      1.0],
                 [self.p2.x,      self.p2.y,      1.0]]
        )
    }

    fn from_matrix(&mut self, m: &Matrix) {
        self.p1 = Point2D::new(m.matrix[0][0], m.matrix[0][1]);
        self.p2 = Point2D::new(m.matrix[1][0], m.matrix[1][1]);
    }

    fn anchor_point(&self) -> Point2D {
        self.anchor.clone()
    }

    fn set_anchor_point(&mut self, anchor: &Point2D) {
        self.anchor = anchor.clone();
    }

    #[inline]
    fn draw(&self, renderer: &Renderer) {
        self.draw_bresenham_line(renderer);
    }

    fn fill(&self, renderer: &Renderer) {
        self.draw_bresenham_line(renderer);
    }
}
<|endoftext|>