<commit_before>extern crate env_logger;
extern crate lapin_futures as lapin;
#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio;

use std::io;

use futures::future::Future;
use futures::{IntoFuture, Stream};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use tokio::runtime::Runtime;
use lapin::types::FieldTable;
use lapin::client::{Client, ConnectionOptions};
use lapin::channel::{BasicConsumeOptions, BasicProperties, BasicPublishOptions, ConfirmSelectOptions, QueueDeclareOptions};

const N_CONSUMERS : u8 = 8;
const N_MESSAGES  : u8 = 5;

fn create_consumer<T: AsyncRead + AsyncWrite + Sync + Send + 'static>(client: &Client<T>, n: u8) -> impl Future<Item = (), Error = ()> + Send + 'static {
    info!("will create consumer {}", n);

    let queue = format!("test-queue-{}", n);

    client.create_confirm_channel(ConfirmSelectOptions::default()).and_then(move |channel| {
        info!("creating queue {}", queue);
        channel.queue_declare(&queue, QueueDeclareOptions::default(), FieldTable::new()).map(move |queue| (channel, queue))
    }).and_then(move |(channel, queue)| {
        info!("creating consumer {}", n);
        channel.basic_consume(&queue, "", BasicConsumeOptions::default(), FieldTable::new()).map(move |stream| (channel, stream))
    }).and_then(move |(channel, stream)| {
        info!("got stream for consumer {}", n);
        stream.for_each(move |message| {
            println!("consumer '{}' got '{}'", n, std::str::from_utf8(&message.data).unwrap());
            channel.basic_ack(message.delivery_tag, false)
        })
    }).map(|_| ()).map_err(move |err| eprintln!("got error in consumer '{}': {:?}", n, err))
}

fn main() {
    env_logger::init();

    let addr        = std::env::var("AMQP_ADDR").unwrap_or_else(|_| "127.0.0.1:5672".to_string()).parse().unwrap();
    let mut runtime = Runtime::new().unwrap();
    // let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();

    runtime.block_on(
        TcpStream::connect(&addr).and_then(|stream| {
            Client::connect(stream, ConnectionOptions {
                frame_max: 65535,
                heartbeat: 10,
                ..Default::default()
            })
        }).and_then(|(client, heartbeat)| {
            tokio::spawn(heartbeat.map_err(|e| eprintln!("heartbeat error: {:?}", e)))
                .into_future().map(|_| client).map_err(|_| io::Error::new(io::ErrorKind::Other, "spawn error"))
        }).and_then(|client| {
            let _client = client.clone();
            futures::stream::iter_ok(0..N_CONSUMERS).for_each(move |n| tokio::spawn(create_consumer(&_client, n)))
                .into_future().map(move |_| client).map_err(|_| io::Error::new(io::ErrorKind::Other, "spawn error"))
        }).and_then(|client| {
            client.create_confirm_channel(ConfirmSelectOptions::default()).and_then(move |channel| {
                futures::stream::iter_ok((0..N_CONSUMERS).flat_map(|c| {
                    (0..N_MESSAGES).map(move |m| (c, m))
                })).for_each(move |(c, m)| {
                    let queue   = format!("test-queue-{}", c);
                    let message = format!("message {} for consumer {}", m, c);
                    let channel = channel.clone();

                    info!("will publish {}", message);

                    channel.queue_declare(&queue, QueueDeclareOptions::default(), FieldTable::new()).and_then(move |_| {
                        channel.basic_publish("", &queue, message.into_bytes(), BasicPublishOptions::default(), BasicProperties::default()).map(move |confirmation| {
                            println!("got confirmation (consumer {}, message {}): {:?}", c, m, confirmation);
                        })
                    })
                })
            })
        }).map_err(|err| eprintln!("error: {:?}", err))
    ).expect("runtime exited with failure");

    runtime.shutdown_on_idle().wait().expect("runtime shutdown exited with error");
}
<commit_msg>futures: bump consumers example heartbeat to 20<commit_after>extern crate env_logger;
extern crate lapin_futures as lapin;
#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio;

use std::io;

use futures::future::Future;
use futures::{IntoFuture, Stream};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use tokio::runtime::Runtime;
use lapin::types::FieldTable;
use lapin::client::{Client, ConnectionOptions};
use lapin::channel::{BasicConsumeOptions, BasicProperties, BasicPublishOptions, ConfirmSelectOptions, QueueDeclareOptions};

const N_CONSUMERS : u8 = 8;
const N_MESSAGES  : u8 = 5;

fn create_consumer<T: AsyncRead + AsyncWrite + Sync + Send + 'static>(client: &Client<T>, n: u8) -> impl Future<Item = (), Error = ()> + Send + 'static {
    info!("will create consumer {}", n);

    let queue = format!("test-queue-{}", n);

    client.create_confirm_channel(ConfirmSelectOptions::default()).and_then(move |channel| {
        info!("creating queue {}", queue);
        channel.queue_declare(&queue, QueueDeclareOptions::default(), FieldTable::new()).map(move |queue| (channel, queue))
    }).and_then(move |(channel, queue)| {
        info!("creating consumer {}", n);
        channel.basic_consume(&queue, "", BasicConsumeOptions::default(), FieldTable::new()).map(move |stream| (channel, stream))
    }).and_then(move |(channel, stream)| {
        info!("got stream for consumer {}", n);
        stream.for_each(move |message| {
            println!("consumer '{}' got '{}'", n, std::str::from_utf8(&message.data).unwrap());
            channel.basic_ack(message.delivery_tag, false)
        })
    }).map(|_| ()).map_err(move |err| eprintln!("got error in consumer '{}': {:?}", n, err))
}

fn main() {
    env_logger::init();

    let addr        = std::env::var("AMQP_ADDR").unwrap_or_else(|_| "127.0.0.1:5672".to_string()).parse().unwrap();
    let mut runtime = Runtime::new().unwrap();
    // let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();

    runtime.block_on(
        TcpStream::connect(&addr).and_then(|stream| {
            Client::connect(stream, ConnectionOptions {
                frame_max: 65535,
                heartbeat: 20,
                ..Default::default()
            })
        }).and_then(|(client, heartbeat)| {
            tokio::spawn(heartbeat.map_err(|e| eprintln!("heartbeat error: {:?}", e)))
                .into_future().map(|_| client).map_err(|_| io::Error::new(io::ErrorKind::Other, "spawn error"))
        }).and_then(|client| {
            let _client = client.clone();
            futures::stream::iter_ok(0..N_CONSUMERS).for_each(move |n| tokio::spawn(create_consumer(&_client, n)))
                .into_future().map(move |_| client).map_err(|_| io::Error::new(io::ErrorKind::Other, "spawn error"))
        }).and_then(|client| {
            client.create_confirm_channel(ConfirmSelectOptions::default()).and_then(move |channel| {
                futures::stream::iter_ok((0..N_CONSUMERS).flat_map(|c| {
                    (0..N_MESSAGES).map(move |m| (c, m))
                })).for_each(move |(c, m)| {
                    let queue   = format!("test-queue-{}", c);
                    let message = format!("message {} for consumer {}", m, c);
                    let channel = channel.clone();

                    info!("will publish {}", message);

                    channel.queue_declare(&queue, QueueDeclareOptions::default(), FieldTable::new()).and_then(move |_| {
                        channel.basic_publish("", &queue, message.into_bytes(), BasicPublishOptions::default(), BasicProperties::default()).map(move |confirmation| {
                            println!("got confirmation (consumer {}, message {}): {:?}", c, m, confirmation);
                        })
                    })
                })
            })
        }).map_err(|err| eprintln!("error: {:?}", err))
    ).expect("runtime exited with failure");

    runtime.shutdown_on_idle().wait().expect("runtime shutdown exited with error");
}
<|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::iter::Empty;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

use device::Device;
use device::Queue;
use format::ClearValue;
use format::Format;
use format::FormatDesc;
use format::FormatTy;
use image::Dimensions;
use image::ImageDimensions;
use image::ViewType;
use image::sys::ImageCreationError;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::traits::ImageAccess;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
use image::traits::ImageViewAccess;
use image::traits::Image;
use image::traits::ImageView;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPoolAlloc;
use sync::AccessError;
use sync::Sharing;

/// ImageAccess whose purpose is to be used as a framebuffer attachment.
///
/// The image is always two-dimensional and has only one mipmap, but it can have any kind of
/// format. Trying to use a format that the backend doesn't support for rendering will result in
/// an error being returned when creating the image. Once you have an `AttachmentImage`, you are
/// guaranteed that you will be able to draw on it.
///
/// The template parameter of `AttachmentImage` is a type that describes the format of the image.
///
/// # Regular vs transient
///
/// Calling `AttachmentImage::new` will create a regular image, while calling
/// `AttachmentImage::transient` will create a *transient* image. Transient image are only
/// relevant for images that serve as attachments, so `AttachmentImage` is the only type of
/// image in vulkano that provides a shortcut for this.
///
/// A transient image is a special kind of image whose content is undefined outside of render
/// passes. Once you finish drawing, reading from it will returned undefined data (which can be
/// either valid or garbage, depending on the implementation).
///
/// This gives a hint to the Vulkan implementation that it is possible for the image's content to
/// live exclusively in some cache memory, and that no real memory has to be allocated for it.
///
/// In other words, if you are going to read from the image after drawing to it, use a regular
/// image. If you don't need to read from it (for example if it's some kind of intermediary color,
/// or a depth buffer that is only used once) then use a transient image as it may improve
/// performances.
///
// TODO: forbid reading transient images outside render passes?
#[derive(Debug)]
pub struct AttachmentImage<F, A = StdMemoryPoolAlloc> {
    // Inner implementation.
    image: UnsafeImage,

    // We maintain a view of the whole image since we will need it when rendering.
    view: UnsafeImageView,

    // Memory used to back the image.
    memory: A,

    // Format.
    format: F,

    // Layout to use when the image is used as a framebuffer attachment.
    // Must be either "depth-stencil optimal" or "color optimal".
    attachment_layout: ImageLayout,

    // Number of times this image is locked on the GPU side.
    gpu_lock: AtomicUsize,
}

impl<F> AttachmentImage<F> {
    /// Creates a new image with the given dimensions and format.
    ///
    /// Returns an error if the dimensions are too large or if the backend doesn't support this
    /// format as a framebuffer attachment.
    #[inline]
    pub fn new(device: Arc<Device>, dimensions: [u32; 2], format: F)
               -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        AttachmentImage::new_impl(device, dimensions, format, ImageUsage::none())
    }

    /// Same as `new`, but lets you specify additional usages.
    #[inline]
    pub fn with_usage(device: Arc<Device>, dimensions: [u32; 2], format: F, usage: ImageUsage)
                      -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        AttachmentImage::new_impl(device, dimensions, format, usage)
    }

    /// Same as `new`, except that the image will be transient.
    ///
    /// A transient image is special because its content is undefined outside of a render pass.
    /// This means that the implementation has the possibility to not allocate any memory for it.
    #[inline]
    pub fn transient(device: Arc<Device>, dimensions: [u32; 2], format: F)
                     -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        let base_usage = ImageUsage {
            transient_attachment: true,
            .. ImageUsage::none()
        };

        AttachmentImage::new_impl(device, dimensions, format, base_usage)
    }

    fn new_impl(device: Arc<Device>, dimensions: [u32; 2], format: F, base_usage: ImageUsage)
                -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        // TODO: check dimensions against the max_framebuffer_width/height/layers limits

        let is_depth = match format.format().ty() {
            FormatTy::Depth => true,
            FormatTy::DepthStencil => true,
            FormatTy::Stencil => true,
            FormatTy::Compressed => panic!(),
            _ => false
        };

        let usage = ImageUsage {
            color_attachment: !is_depth,
            depth_stencil_attachment: is_depth,
            .. base_usage
        };

        let (image, mem_reqs) = unsafe {
            try!(UnsafeImage::new(device.clone(), usage, format.format(),
                                  ImageDimensions::Dim2d { width: dimensions[0], height: dimensions[1], array_layers: 1, cubemap_compatible: false },
                                  1, 1, Sharing::Exclusive::<Empty<u32>>, false, false))
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment, AllocLayout::Optimal));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }

        let view = unsafe {
            try!(UnsafeImageView::raw(&image, ViewType::Dim2d, 0 .. 1, 0 .. 1))
        };

        Ok(Arc::new(AttachmentImage {
            image: image,
            view: view,
            memory: mem,
            format: format,
            attachment_layout: if is_depth { ImageLayout::DepthStencilAttachmentOptimal }
                               else { ImageLayout::ColorAttachmentOptimal },
            gpu_lock: AtomicUsize::new(0),
        }))
    }
}

impl<F, A> AttachmentImage<F, A> {
    /// Returns the dimensions of the image.
    #[inline]
    pub fn dimensions(&self) -> [u32; 2] {
        let dims = self.image.dimensions();
        [dims.width(), dims.height()]
    }
}

/// GPU access to an attachment image.
pub struct AttachmentImageAccess<F, A> {
    img: Arc<AttachmentImage<F, A>>,
    // True if `try_gpu_lock` was already called on it.
    already_locked: AtomicBool,
}

impl<F, A> Clone for AttachmentImageAccess<F, A> {
    #[inline]
    fn clone(&self) -> AttachmentImageAccess<F, A> {
        AttachmentImageAccess {
            img: self.img.clone(),
            already_locked: AtomicBool::new(self.already_locked.load(Ordering::SeqCst))
        }
    }
}

unsafe impl<F, A> ImageAccess for AttachmentImageAccess<F, A>
    where F: 'static + Send + Sync
{
    #[inline]
    fn inner(&self) -> &UnsafeImage {
        &self.img.image
    }

    #[inline]
    fn initial_layout_requirement(&self) -> ImageLayout {
        self.img.attachment_layout
    }

    #[inline]
    fn final_layout_requirement(&self) -> ImageLayout {
        self.img.attachment_layout
    }

    #[inline]
    fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 {
        self.img.image.key()
    }

    #[inline]
    fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
        // FIXME: uncomment when it's working
        //        the problem is in the submit sync layer which locks framebuffer attachments and
        //        keeps them locked even after destruction
        Ok(())
        /*if self.already_locked.swap(true, Ordering::SeqCst) == true {
            return false;
        }

        self.img.gpu_lock.compare_and_swap(0, 1, Ordering::SeqCst) == 0*/
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        // FIXME: uncomment when it's working
        //        the problem is in the submit sync layer which locks framebuffer attachments and
        //        keeps them locked even after destruction
        /*debug_assert!(self.already_locked.load(Ordering::SeqCst));
        let val = self.img.gpu_lock.fetch_add(1, Ordering::SeqCst);
        debug_assert!(val >= 1);*/
    }
}

impl<F, A> Drop for AttachmentImageAccess<F, A> {
    fn drop(&mut self) {
        if self.already_locked.load(Ordering::SeqCst) {
            let prev_val = self.img.gpu_lock.fetch_sub(1, Ordering::SeqCst);
            debug_assert!(prev_val >= 1);
        }
    }
}

unsafe impl<F, A> ImageClearValue<F::ClearValue> for AttachmentImageAccess<F, A>
    where F: FormatDesc + 'static + Send + Sync
{
    #[inline]
    fn decode(&self, value: F::ClearValue) -> Option<ClearValue> {
        Some(self.img.format.decode_clear_value(value))
    }
}

unsafe impl<P, F, A> ImageContent<P> for AttachmentImageAccess<F, A>
    where F: 'static + Send + Sync
{
    #[inline]
    fn matches_format(&self) -> bool {
        true        // FIXME:
    }
}

unsafe impl<F, A> Image for Arc<AttachmentImage<F, A>>
    where F: 'static + Send + Sync
{
    type Access = AttachmentImageAccess<F, A>;

    #[inline]
    fn access(self) -> AttachmentImageAccess<F, A> {
        AttachmentImageAccess {
            img: self,
            already_locked: AtomicBool::new(false),
        }
    }

    #[inline]
    fn format(&self) -> Format {
        self.image.format()
    }

    #[inline]
    fn samples(&self) -> u32 {
        self.image.samples()
    }

    #[inline]
    fn dimensions(&self) -> ImageDimensions {
        self.image.dimensions()
    }
}

unsafe impl<F, A> ImageView for Arc<AttachmentImage<F, A>>
    where F: 'static + Send + Sync
{
    type Access = AttachmentImageAccess<F, A>;

    #[inline]
    fn access(self) -> AttachmentImageAccess<F, A> {
        AttachmentImageAccess {
            img: self,
            already_locked: AtomicBool::new(false),
        }
    }
}

unsafe impl<F, A> ImageViewAccess for AttachmentImageAccess<F, A>
    where F: 'static + Send + Sync
{
    #[inline]
    fn parent(&self) -> &ImageAccess {
        self
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        let dims = self.img.image.dimensions();
        Dimensions::Dim2d { width: dims.width(), height: dims.height() }
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        &self.img.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
        ImageLayout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
        ImageLayout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
        ImageLayout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
        ImageLayout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}

#[cfg(test)]
mod tests {
    use super::AttachmentImage;
    use format::Format;

    #[test]
    fn create_regular() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
    }

    #[test]
    fn create_transient() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
    }

    #[test]
    fn d16_unorm_always_supported() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::new(device, [32, 32], Format::D16Unorm).unwrap();
    }
}
<commit_msg>Add default generic parameter for AttachmentImage<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::iter::Empty;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

use device::Device;
use device::Queue;
use format::ClearValue;
use format::Format;
use format::FormatDesc;
use format::FormatTy;
use image::Dimensions;
use image::ImageDimensions;
use image::ViewType;
use image::sys::ImageCreationError;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::traits::ImageAccess;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
use image::traits::ImageViewAccess;
use image::traits::Image;
use image::traits::ImageView;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPoolAlloc;
use sync::AccessError;
use sync::Sharing;

/// ImageAccess whose purpose is to be used as a framebuffer attachment.
///
/// The image is always two-dimensional and has only one mipmap, but it can have any kind of
/// format. Trying to use a format that the backend doesn't support for rendering will result in
/// an error being returned when creating the image. Once you have an `AttachmentImage`, you are
/// guaranteed that you will be able to draw on it.
///
/// The template parameter of `AttachmentImage` is a type that describes the format of the image.
///
/// # Regular vs transient
///
/// Calling `AttachmentImage::new` will create a regular image, while calling
/// `AttachmentImage::transient` will create a *transient* image. Transient image are only
/// relevant for images that serve as attachments, so `AttachmentImage` is the only type of
/// image in vulkano that provides a shortcut for this.
///
/// A transient image is a special kind of image whose content is undefined outside of render
/// passes. Once you finish drawing, reading from it will returned undefined data (which can be
/// either valid or garbage, depending on the implementation).
///
/// This gives a hint to the Vulkan implementation that it is possible for the image's content to
/// live exclusively in some cache memory, and that no real memory has to be allocated for it.
///
/// In other words, if you are going to read from the image after drawing to it, use a regular
/// image. If you don't need to read from it (for example if it's some kind of intermediary color,
/// or a depth buffer that is only used once) then use a transient image as it may improve
/// performances.
///
// TODO: forbid reading transient images outside render passes?
#[derive(Debug)]
pub struct AttachmentImage<F = Format, A = StdMemoryPoolAlloc> {
    // Inner implementation.
    image: UnsafeImage,

    // We maintain a view of the whole image since we will need it when rendering.
    view: UnsafeImageView,

    // Memory used to back the image.
    memory: A,

    // Format.
    format: F,

    // Layout to use when the image is used as a framebuffer attachment.
    // Must be either "depth-stencil optimal" or "color optimal".
    attachment_layout: ImageLayout,

    // Number of times this image is locked on the GPU side.
    gpu_lock: AtomicUsize,
}

impl<F> AttachmentImage<F> {
    /// Creates a new image with the given dimensions and format.
    ///
    /// Returns an error if the dimensions are too large or if the backend doesn't support this
    /// format as a framebuffer attachment.
    #[inline]
    pub fn new(device: Arc<Device>, dimensions: [u32; 2], format: F)
               -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        AttachmentImage::new_impl(device, dimensions, format, ImageUsage::none())
    }

    /// Same as `new`, but lets you specify additional usages.
    #[inline]
    pub fn with_usage(device: Arc<Device>, dimensions: [u32; 2], format: F, usage: ImageUsage)
                      -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        AttachmentImage::new_impl(device, dimensions, format, usage)
    }

    /// Same as `new`, except that the image will be transient.
    ///
    /// A transient image is special because its content is undefined outside of a render pass.
    /// This means that the implementation has the possibility to not allocate any memory for it.
    #[inline]
    pub fn transient(device: Arc<Device>, dimensions: [u32; 2], format: F)
                     -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        let base_usage = ImageUsage {
            transient_attachment: true,
            .. ImageUsage::none()
        };

        AttachmentImage::new_impl(device, dimensions, format, base_usage)
    }

    fn new_impl(device: Arc<Device>, dimensions: [u32; 2], format: F, base_usage: ImageUsage)
                -> Result<Arc<AttachmentImage<F>>, ImageCreationError>
        where F: FormatDesc
    {
        // TODO: check dimensions against the max_framebuffer_width/height/layers limits

        let is_depth = match format.format().ty() {
            FormatTy::Depth => true,
            FormatTy::DepthStencil => true,
            FormatTy::Stencil => true,
            FormatTy::Compressed => panic!(),
            _ => false
        };

        let usage = ImageUsage {
            color_attachment: !is_depth,
            depth_stencil_attachment: is_depth,
            .. base_usage
        };

        let (image, mem_reqs) = unsafe {
            try!(UnsafeImage::new(device.clone(), usage, format.format(),
                                  ImageDimensions::Dim2d { width: dimensions[0], height: dimensions[1], array_layers: 1, cubemap_compatible: false },
                                  1, 1, Sharing::Exclusive::<Empty<u32>>, false, false))
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&Device::standard_pool(&device), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment, AllocLayout::Optimal));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        unsafe { try!(image.bind_memory(mem.memory(), mem.offset())); }

        let view = unsafe {
            try!(UnsafeImageView::raw(&image, ViewType::Dim2d, 0 .. 1, 0 .. 1))
        };

        Ok(Arc::new(AttachmentImage {
            image: image,
            view: view,
            memory: mem,
            format: format,
            attachment_layout: if is_depth { ImageLayout::DepthStencilAttachmentOptimal }
                               else { ImageLayout::ColorAttachmentOptimal },
            gpu_lock: AtomicUsize::new(0),
        }))
    }
}

impl<F, A> AttachmentImage<F, A> {
    /// Returns the dimensions of the image.
    #[inline]
    pub fn dimensions(&self) -> [u32; 2] {
        let dims = self.image.dimensions();
        [dims.width(), dims.height()]
    }
}

/// GPU access to an attachment image.
pub struct AttachmentImageAccess<F, A> {
    img: Arc<AttachmentImage<F, A>>,
    // True if `try_gpu_lock` was already called on it.
    already_locked: AtomicBool,
}

impl<F, A> Clone for AttachmentImageAccess<F, A> {
    #[inline]
    fn clone(&self) -> AttachmentImageAccess<F, A> {
        AttachmentImageAccess {
            img: self.img.clone(),
            already_locked: AtomicBool::new(self.already_locked.load(Ordering::SeqCst))
        }
    }
}

unsafe impl<F, A> ImageAccess for AttachmentImageAccess<F, A>
    where F: 'static + Send + Sync
{
    #[inline]
    fn inner(&self) -> &UnsafeImage {
        &self.img.image
    }

    #[inline]
    fn initial_layout_requirement(&self) -> ImageLayout {
        self.img.attachment_layout
    }

    #[inline]
    fn final_layout_requirement(&self) -> ImageLayout {
        self.img.attachment_layout
    }

    #[inline]
    fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 {
        self.img.image.key()
    }

    #[inline]
    fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
        // FIXME: uncomment when it's working
        //        the problem is in the submit sync layer which locks framebuffer attachments and
        //        keeps them locked even after destruction
        Ok(())
        /*if self.already_locked.swap(true, Ordering::SeqCst) == true {
            return false;
        }

        self.img.gpu_lock.compare_and_swap(0, 1, Ordering::SeqCst) == 0*/
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        // FIXME: uncomment when it's working
        //        the problem is in the submit sync layer which locks framebuffer attachments and
        //        keeps them locked even after destruction
        /*debug_assert!(self.already_locked.load(Ordering::SeqCst));
        let val = self.img.gpu_lock.fetch_add(1, Ordering::SeqCst);
        debug_assert!(val >= 1);*/
    }
}

impl<F, A> Drop for AttachmentImageAccess<F, A> {
    fn drop(&mut self) {
        if self.already_locked.load(Ordering::SeqCst) {
            let prev_val = self.img.gpu_lock.fetch_sub(1, Ordering::SeqCst);
            debug_assert!(prev_val >= 1);
        }
    }
}

unsafe impl<F, A> ImageClearValue<F::ClearValue> for AttachmentImageAccess<F, A>
    where F: FormatDesc + 'static + Send + Sync
{
    #[inline]
    fn decode(&self, value: F::ClearValue) -> Option<ClearValue> {
        Some(self.img.format.decode_clear_value(value))
    }
}

unsafe impl<P, F, A> ImageContent<P> for AttachmentImageAccess<F, A>
    where F: 'static + Send + Sync
{
    #[inline]
    fn matches_format(&self) -> bool {
        true        // FIXME:
    }
}

unsafe impl<F, A> Image for Arc<AttachmentImage<F, A>>
    where F: 'static + Send + Sync
{
    type Access = AttachmentImageAccess<F, A>;

    #[inline]
    fn access(self) -> AttachmentImageAccess<F, A> {
        AttachmentImageAccess {
            img: self,
            already_locked: AtomicBool::new(false),
        }
    }

    #[inline]
    fn format(&self) -> Format {
        self.image.format()
    }

    #[inline]
    fn samples(&self) -> u32 {
        self.image.samples()
    }

    #[inline]
    fn dimensions(&self) -> ImageDimensions {
        self.image.dimensions()
    }
}

unsafe impl<F, A> ImageView for Arc<AttachmentImage<F, A>>
    where F: 'static + Send + Sync
{
    type Access = AttachmentImageAccess<F, A>;

    #[inline]
    fn access(self) -> AttachmentImageAccess<F, A> {
        AttachmentImageAccess {
            img: self,
            already_locked: AtomicBool::new(false),
        }
    }
}

unsafe impl<F, A> ImageViewAccess for AttachmentImageAccess<F, A>
    where F: 'static + Send + Sync
{
    #[inline]
    fn parent(&self) -> &ImageAccess {
        self
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        let dims = self.img.image.dimensions();
        Dimensions::Dim2d { width: dims.width(), height: dims.height() }
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        &self.img.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
        ImageLayout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
        ImageLayout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
        ImageLayout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
        ImageLayout::ShaderReadOnlyOptimal
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}

#[cfg(test)]
mod tests {
    use super::AttachmentImage;
    use format::Format;

    #[test]
    fn create_regular() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
    }

    #[test]
    fn create_transient() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
    }

    #[test]
    fn d16_unorm_always_supported() {
        let (device, _) = gfx_dev_and_queue!();
        let _img = AttachmentImage::new(device, [32, 32], Format::D16Unorm).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::{ffi::CString, os::unix::io::RawFd};

pub use wayland_sys::common::{wl_argument, wl_interface, wl_message};

/// Describes whether an argument may have a null value.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum AllowNull {
    /// Null values are allowed.
    Yes,
    /// Null values are forbidden.
    No,
}

/// Enum of possible argument types as recognized by the wire
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ArgumentType {
    /// An integer argument. Represented by a [`i32`].
    Int,
    /// An unsigned integer argument. Represented by a [`u32`].
    Uint,
    /// A signed fixed point number with 1/256 precision
    Fixed,
    /// A string. This is represented as a [`CString`] in a message.
    Str(AllowNull),
    /// Id of a wayland object
    Object(AllowNull),
    /// Id of a newly created wayland object
    NewId(AllowNull),
    /// Vec<u8>
    Array(AllowNull),
    /// A file descriptor argument. Represented by a [`RawFd`].
    Fd,
}

impl ArgumentType {
    /// Returns true if the type of the argument is the same.
    pub fn same_type(self, other: Self) -> bool {
        std::mem::discriminant(&self) == std::mem::discriminant(&other)
    }
}

/// Enum of possible argument of the protocol
#[derive(Clone, PartialEq, Eq, Debug)]
#[allow(clippy::box_vec)]
pub enum Argument<Id> {
    /// An integer argument. Represented by a [`i32`].
    Int(i32),
    /// An unsigned integer argument. Represented by a [`u32`].
    Uint(u32),
    /// A signed fixed point number with 1/256 precision
    Fixed(i32),
    /// CString
    ///
    /// The value is boxed to reduce the stack size of Argument. The performance
    /// impact is negligible as `string` arguments are pretty rare in the protocol.
    Str(Box<CString>),
    /// Id of a wayland object
    Object(Id),
    /// Id of a newly created wayland object
    NewId(Id),
    /// Vec<u8>
    ///
    /// The value is boxed to reduce the stack size of Argument. The performance
    /// impact is negligible as `array` arguments are pretty rare in the protocol.
    Array(Box<Vec<u8>>),
    /// A file descriptor argument. Represented by a [`RawFd`].
    Fd(RawFd),
}

impl<Id> Argument<Id> {
    /// Retrieve the type of a given argument instance
    pub fn get_type(&self) -> ArgumentType {
        match *self {
            Argument::Int(_) => ArgumentType::Int,
            Argument::Uint(_) => ArgumentType::Uint,
            Argument::Fixed(_) => ArgumentType::Fixed,
            Argument::Str(_) => ArgumentType::Str(AllowNull::Yes),
            Argument::Object(_) => ArgumentType::Object(AllowNull::Yes),
            Argument::NewId(_) => ArgumentType::NewId(AllowNull::Yes),
            Argument::Array(_) => ArgumentType::Array(AllowNull::Yes),
            Argument::Fd(_) => ArgumentType::Fd,
        }
    }
}

#[cfg(not(tarpaulin_include))]
impl<Id: std::fmt::Display> std::fmt::Display for Argument<Id> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Argument::Int(value) => write!(f, "{}", value),
            Argument::Uint(value) => write!(f, "{}", value),
            Argument::Fixed(value) => write!(f, "{}", value),
            Argument::Str(value) => write!(f, "{:?}", value),
            Argument::Object(value) => write!(f, "{}", value),
            Argument::NewId(value) => write!(f, "{}", value),
            Argument::Array(value) => write!(f, "{:?}", value),
            Argument::Fd(value) => write!(f, "{}", value),
        }
    }
}

/// Description of wayland interface.
///
/// An interface describes the possible requests and events that a wayland client and compositor use to
/// communicate.
#[derive(Debug)]
pub struct Interface {
    /// The name of the interface.
    pub name: &'static str,
    /// The maximum supported version of the interface.
    pub version: u32,
    /// A list that describes every request this interface supports.
    pub requests: &'static [MessageDesc],
    /// A list that describes every event this interface supports.
    pub events: &'static [MessageDesc],
    /// A C representation of this interface that may be used to interoperate with libwayland.
    pub c_ptr: Option<&'static wayland_sys::common::wl_interface>,
}

#[cfg(not(tarpaulin_include))]
impl std::fmt::Display for Interface {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.name)
    }
}

/// Wire metadata of a given message
#[derive(Copy, Clone, Debug)]
pub struct MessageDesc {
    /// Name of this message
    pub name: &'static str,
    /// Signature of the message
    pub signature: &'static [ArgumentType],
    /// Minimum required version of the interface
    pub since: u32,
    /// Whether this message is a destructor
    pub is_destructor: bool,
    /// The child interface created from this message.
    ///
    /// In the wayland xml format, this corresponds to the `new_id` type.
    pub child_interface: Option<&'static Interface>,
    /// The interfaces passed into this message as arguments.
    pub arg_interfaces: &'static [&'static Interface],
}

/// Special interface representing an anonymous object
pub static ANONYMOUS_INTERFACE: Interface =
    Interface { name: "<anonymous>", version: 0, requests: &[], events: &[], c_ptr: None };

/// Description of the protocol-level information of an object
#[derive(Copy, Clone, Debug)]
pub struct ObjectInfo {
    /// The protocol ID
    pub id: u32,
    /// The interface
    pub interface: &'static Interface,
    /// The version
    pub version: u32,
}

/// A protocol error
///
/// This kind of error is generated by the server if your client didn't respect
/// the protocol, after which the server will kill your connection.
#[derive(Clone, Debug)]
pub struct ProtocolError {
    /// The error code associated with the error
    ///
    /// It should be interpreted as an instance of the `Error` enum of the
    /// associated interface.
    pub code: u32,
    /// The id of the object that caused the error
    pub object_id: u32,
    /// The interface of the object that caused the error
    pub object_interface: String,
    /// The message sent by the server describing the error
    pub message: String,
}

pub const INLINE_ARGS: usize = 4;

/// Represents a message that has been sent from some object.
#[derive(Debug, Clone, PartialEq)]
pub struct Message<Id> {
    /// The id of the object that sent the message.
    pub sender_id: Id,
    /// The opcode of the message.
    pub opcode: u16,
    /// The arguments of the message.
    pub args: smallvec::SmallVec<[Argument<Id>; INLINE_ARGS]>,
}

impl std::error::Error for ProtocolError {}

#[cfg(not(tarpaulin_include))]
impl std::fmt::Display for ProtocolError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        write!(
            f,
            "Protocol error {} on object {}@{}: {}",
            self.code, self.object_interface, self.object_id, self.message
        )
    }
}

/// Returns true if the two interfaces are the same.
#[inline]
pub fn same_interface(a: &'static Interface, b: &'static Interface) -> bool {
    std::ptr::eq(a, b) || a.name == b.name
}

pub(crate) fn check_for_signature<Id>(signature: &[ArgumentType], args: &[Argument<Id>]) -> bool {
    if signature.len() != args.len() {
        return false;
    }
    for (typ, arg) in signature.iter().copied().zip(args.iter()) {
        if !arg.get_type().same_type(typ) {
            return false;
        }
    }
    true
}

#[inline]
#[allow(dead_code)]
pub(crate) fn same_interface_or_anonymous(a: &'static Interface, b: &'static Interface) -> bool {
    same_interface(a, b) || same_interface(a, &ANONYMOUS_INTERFACE)
}

/// An enum value in the protocol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WEnum<T> {
    Value(T),
    Unknown(u32),
}

impl<T: std::convert::TryFrom<u32>> From<u32> for WEnum<T> {
    /// Constructs an enum from the integer format used by the wayland protocol.
    fn from(v: u32) -> WEnum<T> {
        match T::try_from(v) {
            Ok(t) => WEnum::Value(t),
            Err(_) => WEnum::Unknown(v),
        }
    }
}

impl<T: Into<u32>> From<WEnum<T>> for u32 {
    /// Converts an enum into a numerical form used by the wayland protocol.
    fn from(enu: WEnum<T>) -> u32 {
        match enu {
            WEnum::Unknown(u) => u,
            WEnum::Value(t) => t.into(),
        }
    }
}
<commit_msg>clippy::box_vec -> clippy::box_collection<commit_after>use std::{ffi::CString, os::unix::io::RawFd};

pub use wayland_sys::common::{wl_argument, wl_interface, wl_message};

/// Describes whether an argument may have a null value.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum AllowNull {
    /// Null values are allowed.
    Yes,
    /// Null values are forbidden.
    No,
}

/// Enum of possible argument types as recognized by the wire
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ArgumentType {
    /// An integer argument. Represented by a [`i32`].
    Int,
    /// An unsigned integer argument. Represented by a [`u32`].
    Uint,
    /// A signed fixed point number with 1/256 precision
    Fixed,
    /// A string. This is represented as a [`CString`] in a message.
    Str(AllowNull),
    /// Id of a wayland object
    Object(AllowNull),
    /// Id of a newly created wayland object
    NewId(AllowNull),
    /// Vec<u8>
    Array(AllowNull),
    /// A file descriptor argument. Represented by a [`RawFd`].
    Fd,
}

impl ArgumentType {
    /// Returns true if the type of the argument is the same.
    pub fn same_type(self, other: Self) -> bool {
        std::mem::discriminant(&self) == std::mem::discriminant(&other)
    }
}

/// Enum of possible argument of the protocol
#[derive(Clone, PartialEq, Eq, Debug)]
#[allow(clippy::box_collection)]
pub enum Argument<Id> {
    /// An integer argument. Represented by a [`i32`].
    Int(i32),
    /// An unsigned integer argument. Represented by a [`u32`].
    Uint(u32),
    /// A signed fixed point number with 1/256 precision
    Fixed(i32),
    /// CString
    ///
    /// The value is boxed to reduce the stack size of Argument. The performance
    /// impact is negligible as `string` arguments are pretty rare in the protocol.
    Str(Box<CString>),
    /// Id of a wayland object
    Object(Id),
    /// Id of a newly created wayland object
    NewId(Id),
    /// Vec<u8>
    ///
    /// The value is boxed to reduce the stack size of Argument. The performance
    /// impact is negligible as `array` arguments are pretty rare in the protocol.
    Array(Box<Vec<u8>>),
    /// A file descriptor argument. Represented by a [`RawFd`].
    Fd(RawFd),
}

impl<Id> Argument<Id> {
    /// Retrieve the type of a given argument instance
    pub fn get_type(&self) -> ArgumentType {
        match *self {
            Argument::Int(_) => ArgumentType::Int,
            Argument::Uint(_) => ArgumentType::Uint,
            Argument::Fixed(_) => ArgumentType::Fixed,
            Argument::Str(_) => ArgumentType::Str(AllowNull::Yes),
            Argument::Object(_) => ArgumentType::Object(AllowNull::Yes),
            Argument::NewId(_) => ArgumentType::NewId(AllowNull::Yes),
            Argument::Array(_) => ArgumentType::Array(AllowNull::Yes),
            Argument::Fd(_) => ArgumentType::Fd,
        }
    }
}

#[cfg(not(tarpaulin_include))]
impl<Id: std::fmt::Display> std::fmt::Display for Argument<Id> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Argument::Int(value) => write!(f, "{}", value),
            Argument::Uint(value) => write!(f, "{}", value),
            Argument::Fixed(value) => write!(f, "{}", value),
            Argument::Str(value) => write!(f, "{:?}", value),
            Argument::Object(value) => write!(f, "{}", value),
            Argument::NewId(value) => write!(f, "{}", value),
            Argument::Array(value) => write!(f, "{:?}", value),
            Argument::Fd(value) => write!(f, "{}", value),
        }
    }
}

/// Description of wayland interface.
///
/// An interface describes the possible requests and events that a wayland client and compositor use to
/// communicate.
#[derive(Debug)]
pub struct Interface {
    /// The name of the interface.
    pub name: &'static str,
    /// The maximum supported version of the interface.
    pub version: u32,
    /// A list that describes every request this interface supports.
    pub requests: &'static [MessageDesc],
    /// A list that describes every event this interface supports.
    pub events: &'static [MessageDesc],
    /// A C representation of this interface that may be used to interoperate with libwayland.
    pub c_ptr: Option<&'static wayland_sys::common::wl_interface>,
}

#[cfg(not(tarpaulin_include))]
impl std::fmt::Display for Interface {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.name)
    }
}

/// Wire metadata of a given message
#[derive(Copy, Clone, Debug)]
pub struct MessageDesc {
    /// Name of this message
    pub name: &'static str,
    /// Signature of the message
    pub signature: &'static [ArgumentType],
    /// Minimum required version of the interface
    pub since: u32,
    /// Whether this message is a destructor
    pub is_destructor: bool,
    /// The child interface created from this message.
    ///
    /// In the wayland xml format, this corresponds to the `new_id` type.
    pub child_interface: Option<&'static Interface>,
    /// The interfaces passed into this message as arguments.
    pub arg_interfaces: &'static [&'static Interface],
}

/// Special interface representing an anonymous object
pub static ANONYMOUS_INTERFACE: Interface =
    Interface { name: "<anonymous>", version: 0, requests: &[], events: &[], c_ptr: None };

/// Description of the protocol-level information of an object
#[derive(Copy, Clone, Debug)]
pub struct ObjectInfo {
    /// The protocol ID
    pub id: u32,
    /// The interface
    pub interface: &'static Interface,
    /// The version
    pub version: u32,
}

/// A protocol error
///
/// This kind of error is generated by the server if your client didn't respect
/// the protocol, after which the server will kill your connection.
#[derive(Clone, Debug)]
pub struct ProtocolError {
    /// The error code associated with the error
    ///
    /// It should be interpreted as an instance of the `Error` enum of the
    /// associated interface.
    pub code: u32,
    /// The id of the object that caused the error
    pub object_id: u32,
    /// The interface of the object that caused the error
    pub object_interface: String,
    /// The message sent by the server describing the error
    pub message: String,
}

pub const INLINE_ARGS: usize = 4;

/// Represents a message that has been sent from some object.
#[derive(Debug, Clone, PartialEq)]
pub struct Message<Id> {
    /// The id of the object that sent the message.
    pub sender_id: Id,
    /// The opcode of the message.
    pub opcode: u16,
    /// The arguments of the message.
    pub args: smallvec::SmallVec<[Argument<Id>; INLINE_ARGS]>,
}

impl std::error::Error for ProtocolError {}

#[cfg(not(tarpaulin_include))]
impl std::fmt::Display for ProtocolError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
        write!(
            f,
            "Protocol error {} on object {}@{}: {}",
            self.code, self.object_interface, self.object_id, self.message
        )
    }
}

/// Returns true if the two interfaces are the same.
#[inline]
pub fn same_interface(a: &'static Interface, b: &'static Interface) -> bool {
    std::ptr::eq(a, b) || a.name == b.name
}

pub(crate) fn check_for_signature<Id>(signature: &[ArgumentType], args: &[Argument<Id>]) -> bool {
    if signature.len() != args.len() {
        return false;
    }
    for (typ, arg) in signature.iter().copied().zip(args.iter()) {
        if !arg.get_type().same_type(typ) {
            return false;
        }
    }
    true
}

#[inline]
#[allow(dead_code)]
pub(crate) fn same_interface_or_anonymous(a: &'static Interface, b: &'static Interface) -> bool {
    same_interface(a, b) || same_interface(a, &ANONYMOUS_INTERFACE)
}

/// An enum value in the protocol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WEnum<T> {
    Value(T),
    Unknown(u32),
}

impl<T: std::convert::TryFrom<u32>> From<u32> for WEnum<T> {
    /// Constructs an enum from the integer format used by the wayland protocol.
    fn from(v: u32) -> WEnum<T> {
        match T::try_from(v) {
            Ok(t) => WEnum::Value(t),
            Err(_) => WEnum::Unknown(v),
        }
    }
}

impl<T: Into<u32>> From<WEnum<T>> for u32 {
    /// Converts an enum into a numerical form used by the wayland protocol.
    fn from(enu: WEnum<T>) -> u32 {
        match enu {
            WEnum::Unknown(u) => u,
            WEnum::Value(t) => t.into(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019, Mikhail Vorotilov
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use super::super::find_roots_quadratic;
use super::super::FloatType;
use super::Convergency;
use super::Interval;
use super::Sample;
use super::SearchError;

/// Definition of the quadratic equation a*x^2 + b*x + c
#[derive(Debug, PartialEq)]
pub struct Parabola<F>
where
    F: FloatType,
{
    a: F,
    b: F,
    c: F,
}

impl<F> Parabola<F>
where
    F: FloatType,
{
    /// Restore coefficients of the quadratic equation by 3 points
    fn from_three_points(p1: &Sample<F>, p2: &Sample<F>, p3: &Sample<F>) -> Self {
        let denom = (p1.x - p2.x) * (p1.x - p3.x) * (p2.x - p3.x);
        let a = (p3.x * (p2.y - p1.y) + p2.x * (p1.y - p3.y) + p1.x * (p3.y - p2.y)) / denom;
        let b = (p1.x * p1.x * (p2.y - p3.y) + p3.x * p3.x * (p1.y - p2.y) + p2.x * p2.x * (p3.y - p1.y)) / denom;
        let c = (p2.x * p2.x * (p3.x * p1.y - p1.x * p3.y)
            + p2.x * (p1.x * p1.x * p3.y - p3.x * p3.x * p1.y)
            + p1.x * p3.x * (p3.x - p1.x) * p2.y)
            / denom;

        Parabola { a: a, b: b, c: c }
    }
}

/// Find a root of the function f(x) = 0 using inverse quadratic approximation.
///
/// Pro
///
/// + Faster than linear approximation
/// + No need for derivative function
///
/// Contra
///
/// - sqrt is calculated on every step
/// - only works for polynomial-like functions
///
/// # Failures
/// ## NoBracketing
/// Initial values do not bracket the root.
/// ## NoConvergency
/// Algorithm cannot find a root within the given number of iterations.
/// # Examples
///
/// ```
/// use roots::SimpleConvergency;
/// use roots::find_root_inverse_quadratic;
///
/// let f = |x| { 1f64*x*x - 1f64 };
/// let mut convergency = SimpleConvergency { eps:1e-15f64, max_iter:30 };
///
/// let root1 = find_root_inverse_quadratic(10f64, 0f64, &f, &mut convergency);
/// // Returns approximately Ok(1);
///
/// let root2 = find_root_inverse_quadratic(-10f64, 0f64, &f, &mut 1e-15f64);
/// // Returns approximately Ok(-1);
/// ```
pub fn find_root_inverse_quadratic<F, Func>(a: F, b: F, f: Func, convergency: &mut dyn Convergency<F>) -> Result<F, SearchError>
where
    F: FloatType,
    Func: Fn(F) -> F,
{
    let (x1, x2) = if a > b { (b, a) } else { (a, b) };
    let sample1 = Sample { x: x1, y: f(x1) };
    if convergency.is_root_found(sample1.y) {
        return Ok(sample1.x);
    }
    let sample2 = Sample { x: x2, y: f(x2) };
    if convergency.is_root_found(sample2.y) {
        return Ok(sample2.x);
    }
    if !sample1.is_bracketed_with(&sample2) {
        return Err(SearchError::NoBracketing);
    }

    // Initially, find x3 using the regula falsi method
    let mut interval = Interval {
        begin: sample1,
        end: sample2,
    };
    let mut x3 = interval.middle();
    if interval.is_converged(convergency) {
        return Ok(x3);
    }
    let mut sample3 = Sample { x: x3, y: f(x3) };
    if convergency.is_root_found(sample3.y) {
        return Ok(sample3.x);
    }

    // Iterate quadratically
    let mut iter = 0;
    loop {
        let parabola = dbg!(Parabola::from_three_points(
            dbg!(&interval.begin),
            dbg!(&interval.end),
            dbg!(&sample3)
        ));

        // Find the new approximation quadratically
        x3 = if let Some(root) = find_roots_quadratic(parabola.a, parabola.b, parabola.c)
            .as_ref()
            .iter()
            .find(|x| interval.contains_x(x))
        {
            dbg!(*root)
        } else {
            // no roots inside interval, fallback to linear approximation
            dbg!(interval.middle())
        };

        // calculate the approximated value
        sample3 = Sample { x: x3, y: f(x3) };

        if convergency.is_root_found(sample3.y) {
            return Ok(sample3.x);
        }

        // Narrow down the search interval while keeping the root bracketed
        if sample3.is_bracketed_with(&interval.begin) {
            interval.end = Sample {
                x: sample3.x,
                y: sample3.y,
            };
        } else {
            interval.begin = Sample {
                x: sample3.x,
                y: sample3.y,
            };
        }

        if interval.is_converged(convergency) {
            return Ok(interval.middle());
        }

        iter = iter + 1;
        if convergency.is_iteration_limit_reached(iter) {
            return Err(SearchError::NoConvergency);
        }
    }
}

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

    #[test]
    fn test_find_root_inverse_quadratic() {
        let f = |x| 1f64 * x * x - 1f64;
        let mut conv = debug_convergency::DebugConvergency::new(1e-15f64, 30);

        conv.reset();
        assert_float_eq!(
            1e-15f64,
            find_root_inverse_quadratic(10f64, 0f64, &f, &mut conv).ok().unwrap(),
            1f64
        );
        assert_eq!(0, conv.get_iter_count());

        conv.reset();
        assert_float_eq!(
            1e-15f64,
            find_root_inverse_quadratic(-10f64, 0f64, &f, &mut conv).ok().unwrap(),
            -1f64
        );
        assert_eq!(0, conv.get_iter_count());

        conv.reset();
        assert_eq!(
            find_root_inverse_quadratic(10f64, 20f64, &f, &mut conv),
            Err(SearchError::NoBracketing)
        );
        let result = find_root_inverse_quadratic(10f64, 20f64, &f, &mut conv);
        assert_eq!(result.unwrap_err().to_string(), "Bracketing Error");
        assert_eq!(0, conv.get_iter_count());
    }

    #[test]
    fn test_from_three_points() {
        assert_eq!(
            Parabola {
                a: 1f64,
                b: 0f64,
                c: -1f64
            },
            Parabola::from_three_points(
                &Sample { x: -10f64, y: 99f64 },
                &Sample { x: -2f64, y: 3f64 },
                &Sample { x: 0f64, y: -1f64 }
            )
        );
        assert_eq!(
            Parabola {
                a: 1f64,
                b: 0f64,
                c: -1f64
            },
            Parabola::from_three_points(
                &Sample { x: 10f64, y: 99f64 },
                &Sample { x: 2f64, y: 3f64 },
                &Sample { x: 0f64, y: -1f64 }
            )
        );
        assert_eq!(
            Parabola {
                a: 1f64,
                b: 0f64,
                c: -1f64
            },
            Parabola::from_three_points(
                &Sample { x: -3f64, y: 8f64 },
                &Sample { x: 2f64, y: 3f64 },
                &Sample { x: 0f64, y: -1f64 }
            )
        );
    }
}
<commit_msg>Remove stray dbgs<commit_after>// Copyright (c) 2019, Mikhail Vorotilov
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use super::super::find_roots_quadratic;
use super::super::FloatType;
use super::Convergency;
use super::Interval;
use super::Sample;
use super::SearchError;

/// Definition of the quadratic equation a*x^2 + b*x + c
#[derive(Debug, PartialEq)]
pub struct Parabola<F>
where
    F: FloatType,
{
    a: F,
    b: F,
    c: F,
}

impl<F> Parabola<F>
where
    F: FloatType,
{
    /// Restore coefficients of the quadratic equation by 3 points
    fn from_three_points(p1: &Sample<F>, p2: &Sample<F>, p3: &Sample<F>) -> Self {
        let denom = (p1.x - p2.x) * (p1.x - p3.x) * (p2.x - p3.x);
        let a = (p3.x * (p2.y - p1.y) + p2.x * (p1.y - p3.y) + p1.x * (p3.y - p2.y)) / denom;
        let b = (p1.x * p1.x * (p2.y - p3.y) + p3.x * p3.x * (p1.y - p2.y) + p2.x * p2.x * (p3.y - p1.y)) / denom;
        let c = (p2.x * p2.x * (p3.x * p1.y - p1.x * p3.y)
            + p2.x * (p1.x * p1.x * p3.y - p3.x * p3.x * p1.y)
            + p1.x * p3.x * (p3.x - p1.x) * p2.y)
            / denom;

        Parabola { a: a, b: b, c: c }
    }
}

/// Find a root of the function f(x) = 0 using inverse quadratic approximation.
///
/// Pro
///
/// + Faster than linear approximation
/// + No need for derivative function
///
/// Contra
///
/// - sqrt is calculated on every step
/// - only works for polynomial-like functions
///
/// # Failures
/// ## NoBracketing
/// Initial values do not bracket the root.
/// ## NoConvergency
/// Algorithm cannot find a root within the given number of iterations.
/// # Examples
///
/// ```
/// use roots::SimpleConvergency;
/// use roots::find_root_inverse_quadratic;
///
/// let f = |x| { 1f64*x*x - 1f64 };
/// let mut convergency = SimpleConvergency { eps:1e-15f64, max_iter:30 };
///
/// let root1 = find_root_inverse_quadratic(10f64, 0f64, &f, &mut convergency);
/// // Returns approximately Ok(1);
///
/// let root2 = find_root_inverse_quadratic(-10f64, 0f64, &f, &mut 1e-15f64);
/// // Returns approximately Ok(-1);
/// ```
pub fn find_root_inverse_quadratic<F, Func>(a: F, b: F, f: Func, convergency: &mut dyn Convergency<F>) -> Result<F, SearchError>
where
    F: FloatType,
    Func: Fn(F) -> F,
{
    let (x1, x2) = if a > b { (b, a) } else { (a, b) };
    let sample1 = Sample { x: x1, y: f(x1) };
    if convergency.is_root_found(sample1.y) {
        return Ok(sample1.x);
    }
    let sample2 = Sample { x: x2, y: f(x2) };
    if convergency.is_root_found(sample2.y) {
        return Ok(sample2.x);
    }
    if !sample1.is_bracketed_with(&sample2) {
        return Err(SearchError::NoBracketing);
    }

    // Initially, find x3 using the regula falsi method
    let mut interval = Interval {
        begin: sample1,
        end: sample2,
    };
    let mut x3 = interval.middle();
    if interval.is_converged(convergency) {
        return Ok(x3);
    }
    let mut sample3 = Sample { x: x3, y: f(x3) };
    if convergency.is_root_found(sample3.y) {
        return Ok(sample3.x);
    }

    // Iterate quadratically
    let mut iter = 0;
    loop {
        let parabola = Parabola::from_three_points(&interval.begin, &interval.end, &sample3);

        // Find the new approximation quadratically
        x3 = if let Some(root) = find_roots_quadratic(parabola.a, parabola.b, parabola.c)
            .as_ref()
            .iter()
            .find(|x| interval.contains_x(x))
        {
            *root
        } else {
            // no roots inside interval, fallback to linear approximation
            interval.middle()
        };

        // calculate the approximated value
        sample3 = Sample { x: x3, y: f(x3) };

        if convergency.is_root_found(sample3.y) {
            return Ok(sample3.x);
        }

        // Narrow down the search interval while keeping the root bracketed
        if sample3.is_bracketed_with(&interval.begin) {
            interval.end = Sample {
                x: sample3.x,
                y: sample3.y,
            };
        } else {
            interval.begin = Sample {
                x: sample3.x,
                y: sample3.y,
            };
        }

        if interval.is_converged(convergency) {
            return Ok(interval.middle());
        }

        iter = iter + 1;
        if convergency.is_iteration_limit_reached(iter) {
            return Err(SearchError::NoConvergency);
        }
    }
}

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

    #[test]
    fn test_find_root_inverse_quadratic() {
        let f = |x| 1f64 * x * x - 1f64;
        let mut conv = debug_convergency::DebugConvergency::new(1e-15f64, 30);

        conv.reset();
        assert_float_eq!(
            1e-15f64,
            find_root_inverse_quadratic(10f64, 0f64, &f, &mut conv).ok().unwrap(),
            1f64
        );
        assert_eq!(0, conv.get_iter_count());

        conv.reset();
        assert_float_eq!(
            1e-15f64,
            find_root_inverse_quadratic(-10f64, 0f64, &f, &mut conv).ok().unwrap(),
            -1f64
        );
        assert_eq!(0, conv.get_iter_count());

        conv.reset();
        assert_eq!(
            find_root_inverse_quadratic(10f64, 20f64, &f, &mut conv),
            Err(SearchError::NoBracketing)
        );
        let result = find_root_inverse_quadratic(10f64, 20f64, &f, &mut conv);
        assert_eq!(result.unwrap_err().to_string(), "Bracketing Error");
        assert_eq!(0, conv.get_iter_count());
    }

    #[test]
    fn test_from_three_points() {
        assert_eq!(
            Parabola {
                a: 1f64,
                b: 0f64,
                c: -1f64
            },
            Parabola::from_three_points(
                &Sample { x: -10f64, y: 99f64 },
                &Sample { x: -2f64, y: 3f64 },
                &Sample { x: 0f64, y: -1f64 }
            )
        );
        assert_eq!(
            Parabola {
                a: 1f64,
                b: 0f64,
                c: -1f64
            },
            Parabola::from_three_points(
                &Sample { x: 10f64, y: 99f64 },
                &Sample { x: 2f64, y: 3f64 },
                &Sample { x: 0f64, y: -1f64 }
            )
        );
        assert_eq!(
            Parabola {
                a: 1f64,
                b: 0f64,
                c: -1f64
            },
            Parabola::from_three_points(
                &Sample { x: -3f64, y: 8f64 },
                &Sample { x: 2f64, y: 3f64 },
                &Sample { x: 0f64, y: -1f64 }
            )
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fs::{self, File};
/// Wrappers around the `zip-rs` library to compress and decompress zip
/// bzip2 archives.
use std::io;
use std::path::Path;
use walkdir::WalkDir;

use self::zip_rs::result::{ZipError, ZipResult};
use self::zip_rs::write::FileOptions;
use zip as zip_rs;

/// Compress a source directory recursively into a zip file using the
/// bzip2 format. Permissions are set to 644 by default to avoid any
/// unwanted execution bits.
pub fn compress(src_dir: &Path, dst_file: &File) -> ZipResult<()> {
	if !Path::new(src_dir).is_dir() {
		return Err(ZipError::Io(io::Error::new(
			io::ErrorKind::Other,
			"Source must be a directory.",
		)));
	}

	let options = FileOptions::default()
		.compression_method(zip_rs::CompressionMethod::Bzip2)
		.unix_permissions(0o644);

	let mut zip = zip_rs::ZipWriter::new(dst_file);
	let walkdir = WalkDir::new(src_dir.to_str().unwrap());
	let it = walkdir.into_iter();

	for dent in it.filter_map(|e| e.ok()) {
		let path = dent.path();
		let name = path
			.strip_prefix(Path::new(src_dir))
			.unwrap()
			.to_str()
			.unwrap();

		if path.is_file() {
			zip.start_file(name, options)?;
			let mut f = File::open(path)?;
			io::copy(&mut f, &mut zip)?;
		}
	}

	zip.finish()?;
	dst_file.sync_all()?;
	Ok(())
}

/// Decompress a source file into the provided destination path.
pub fn decompress<R>(src_file: R, dest: &Path) -> ZipResult<()>
where
	R: io::Read + io::Seek,
{
	let mut archive = zip_rs::ZipArchive::new(src_file)?;

	for i in 0..archive.len() {
		let mut file = archive.by_index(i)?;
		let file_path = dest.join(file.name());

		if (&*file.name()).ends_with('/') {
			fs::create_dir_all(&file_path)?;
		} else {
			if let Some(p) = file_path.parent() {
				if !p.exists() {
					fs::create_dir_all(&p)?;
				}
			}
			let mut outfile = fs::File::create(&file_path)?;
			io::copy(&mut file, &mut outfile)?;
		}

		// Get and Set permissions
		#[cfg(unix)]
		{
			use std::os::unix::fs::PermissionsExt;
			if let Some(mode) = file.unix_mode() {
				fs::set_permissions(
					&file_path.to_str().unwrap(),
					PermissionsExt::from_mode(mode),
				)?;
			}
		}
	}
	Ok(())
}
<commit_msg>Changing compression method to 'stored' instead of bzip2. (#2111)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fs::{self, File};
/// Wrappers around the `zip-rs` library to compress and decompress zip archives.
use std::io;
use std::path::Path;
use walkdir::WalkDir;

use self::zip_rs::result::{ZipError, ZipResult};
use self::zip_rs::write::FileOptions;
use zip as zip_rs;

/// Compress a source directory recursively into a zip file.
/// Permissions are set to 644 by default to avoid any
/// unwanted execution bits.
pub fn compress(src_dir: &Path, dst_file: &File) -> ZipResult<()> {
	if !Path::new(src_dir).is_dir() {
		return Err(ZipError::Io(io::Error::new(
			io::ErrorKind::Other,
			"Source must be a directory.",
		)));
	}

	let options = FileOptions::default()
		.compression_method(zip_rs::CompressionMethod::Stored)
		.unix_permissions(0o644);

	let mut zip = zip_rs::ZipWriter::new(dst_file);
	let walkdir = WalkDir::new(src_dir.to_str().unwrap());
	let it = walkdir.into_iter();

	for dent in it.filter_map(|e| e.ok()) {
		let path = dent.path();
		let name = path
			.strip_prefix(Path::new(src_dir))
			.unwrap()
			.to_str()
			.unwrap();

		if path.is_file() {
			zip.start_file(name, options)?;
			let mut f = File::open(path)?;
			io::copy(&mut f, &mut zip)?;
		}
	}

	zip.finish()?;
	dst_file.sync_all()?;
	Ok(())
}

/// Decompress a source file into the provided destination path.
pub fn decompress<R>(src_file: R, dest: &Path) -> ZipResult<()>
where
	R: io::Read + io::Seek,
{
	let mut archive = zip_rs::ZipArchive::new(src_file)?;

	for i in 0..archive.len() {
		let mut file = archive.by_index(i)?;
		let file_path = dest.join(file.name());

		if (&*file.name()).ends_with('/') {
			fs::create_dir_all(&file_path)?;
		} else {
			if let Some(p) = file_path.parent() {
				if !p.exists() {
					fs::create_dir_all(&p)?;
				}
			}
			let mut outfile = fs::File::create(&file_path)?;
			io::copy(&mut file, &mut outfile)?;
		}

		// Get and Set permissions
		#[cfg(unix)]
		{
			use std::os::unix::fs::PermissionsExt;
			if let Some(mode) = file.unix_mode() {
				fs::set_permissions(
					&file_path.to_str().unwrap(),
					PermissionsExt::from_mode(mode),
				)?;
			}
		}
	}
	Ok(())
}
<|endoftext|>


<commit_before>use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const FIREFOX_MEMORY_HIGH: i32 = 4420;
const FIREFOX_MEMORY_MAX: i32 = 5200;

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

#[derive(Debug)]
struct CgroupedFirejailedCommandOptions<'a> {
    bin_path: &'a str,
    memory_high: Option<i32>,
    memory_max: Option<i32>,
    firejail_profile: Option<&'a str>,
    implicit_extra_args: Option<&'a [&'a str]>,
    argv_remainder: Vec<String>,
}

fn cgrouped_firejail_command(options: CgroupedFirejailedCommandOptions) -> Command {
    let mut command = Command::new(SYSTEMD_RUN);
    command.args(&["--user", "--scope"]);
    command.args(&["-p", "MemorySwapMax=0"]);

    if let Some(memory_high) = options.memory_high {
        let memory_high_owned_string = format!("MemoryHigh={}M", memory_high);
        command.args(&["-p", memory_high_owned_string.as_str()]);
    }
    if let Some(memory_max) = options.memory_max {
        let memory_max_owned_string = format!("MemoryMax={}M", memory_max);
        command.args(&["-p", memory_max_owned_string.as_str()]);
    }

    if let Some(firejail_profile) = options.firejail_profile {
        command.arg(FIREJAIL);
        command.arg("--ignore=seccomp");
        command.arg(format!("--profile={}", firejail_profile));
    }

    command.arg(options.bin_path);

    if let Some(implicit_extra_args) = options.implicit_extra_args {
        command.args(implicit_extra_args);
    }

    command.args(options.argv_remainder);

    command
}

fn simple_firejail_command(target: &str, args: Vec<String>) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));
    command.args(args);

    command
}

fn init_command() -> Command {
    let mut args_less_the_first = std::env::args();
    // Pops the name of this executable.
    args_less_the_first.next();

    // Pops the name of the unner target.
    let target = args_less_the_first.next().unwrap();

    // Copies and collects the remaining argv.
    let args: Vec<String> = args_less_the_first.collect();

    match target.as_str() {
        "ff" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: FIREFOX,
                memory_high: Some(FIREFOX_MEMORY_HIGH),
                memory_max: Some(FIREFOX_MEMORY_MAX),
                firejail_profile: Some(FIREFOX_PROFILE),
                implicit_extra_args: Some(&["-P", FIREFOX_MOZILLA_SFW_PROFILE]),
                argv_remainder: args,
            });
        }
        "keira" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: KEIRA,
                memory_high: Some(FIREFOX_MEMORY_HIGH),
                memory_max: Some(FIREFOX_MEMORY_MAX),
                firejail_profile: Some(KEIRA_PROFILE),
                implicit_extra_args: Some(&["-P", "nightly"]),
                argv_remainder: args,
            });
        }
        "npv" => return simple_firejail_command("mpv", args),
        "t" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: TERM,
                memory_high: None,
                memory_max: None,
                firejail_profile: Some(TERM_PROFILE),
                implicit_extra_args: None,
                argv_remainder: args,
            })
        }
        "read" => {
            let formatted_args: Vec<String> = vec![format!("about:reader?url={}", args[0])];
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: FIREFOX,
                memory_high: Some(FIREFOX_MEMORY_HIGH),
                memory_max: Some(FIREFOX_MEMORY_MAX),
                firejail_profile: Some(FIREFOX_PROFILE),
                implicit_extra_args: Some(&["-P", FIREFOX_MOZILLA_SFW_PROFILE]),
                argv_remainder: formatted_args,
            });
        }
        "tbb" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: THUNDERBIRD,
                memory_high: None,
                memory_max: None,
                firejail_profile: Some(THUNDERBIRD_PROFILE),
                implicit_extra_args: None,
                argv_remainder: args,
            });
        }
        "vlk" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: "/usr/bin/vlc",
                memory_high: None,
                memory_max: None,
                firejail_profile: Some("/etc/firejail/vlc.profile"),
                implicit_extra_args: None,
                argv_remainder: args,
            })
        }
        "e" => return simple_firejail_command("evince", args),
        _ => panic!(format!("no handler for ``{}''", target)),
    }
}

fn main() {
    let mut command = init_command();
    println!("{:#?}", command);
    command.exec();
}
<commit_msg>unner: implement display control<commit_after>use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const FIREFOX_MEMORY_HIGH: i32 = 4420;
const FIREFOX_MEMORY_MAX: i32 = 5200;

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

const SWAYMSG: &'static str = "/usr/bin/swaymsg";
const SWAY_EXTERNAL_DISPLAY: &'static str = "HDMI-A-1";

#[derive(Debug)]
struct CgroupedFirejailedCommandOptions<'a> {
    bin_path: &'a str,
    memory_high: Option<i32>,
    memory_max: Option<i32>,
    firejail_profile: Option<&'a str>,
    implicit_extra_args: Option<&'a [&'a str]>,
    argv_remainder: Vec<String>,
}

fn cgrouped_firejail_command(options: CgroupedFirejailedCommandOptions) -> Command {
    let mut command = Command::new(SYSTEMD_RUN);
    command.args(&["--user", "--scope"]);
    command.args(&["-p", "MemorySwapMax=0"]);

    if let Some(memory_high) = options.memory_high {
        let memory_high_owned_string = format!("MemoryHigh={}M", memory_high);
        command.args(&["-p", memory_high_owned_string.as_str()]);
    }
    if let Some(memory_max) = options.memory_max {
        let memory_max_owned_string = format!("MemoryMax={}M", memory_max);
        command.args(&["-p", memory_max_owned_string.as_str()]);
    }

    if let Some(firejail_profile) = options.firejail_profile {
        command.arg(FIREJAIL);
        command.arg("--ignore=seccomp");
        command.arg(format!("--profile={}", firejail_profile));
    }

    command.arg(options.bin_path);

    if let Some(implicit_extra_args) = options.implicit_extra_args {
        command.args(implicit_extra_args);
    }

    command.args(options.argv_remainder);

    command
}

fn simple_firejail_command(target: &str, args: Vec<String>) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));
    command.args(args);

    command
}

fn swaymsg_display_command(args: Vec<String>) -> Command {
    let mut command = Command::new(SWAYMSG);
    command.arg(format!(
        "output {} {}",
        SWAY_EXTERNAL_DISPLAY,
        match args[0].as_str() {
            "e" => "enable",
            "d" => "disable",
            _ => panic!(
                "bad argument for swaymsg ``output'' command: ``{}''",
                args[0].as_str()
            ),
        }
    ));

    command
}

fn init_command() -> Command {
    let mut args_less_the_first = std::env::args();
    // Pops the name of this executable.
    args_less_the_first.next();

    // Pops the name of the unner target.
    let target = args_less_the_first.next().unwrap();

    // Copies and collects the remaining argv.
    let args: Vec<String> = args_less_the_first.collect();

    match target.as_str() {
        "d" => return swaymsg_display_command(args),
        "ff" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: FIREFOX,
                memory_high: Some(FIREFOX_MEMORY_HIGH),
                memory_max: Some(FIREFOX_MEMORY_MAX),
                firejail_profile: Some(FIREFOX_PROFILE),
                implicit_extra_args: Some(&["-P", FIREFOX_MOZILLA_SFW_PROFILE]),
                argv_remainder: args,
            });
        }
        "keira" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: KEIRA,
                memory_high: Some(FIREFOX_MEMORY_HIGH),
                memory_max: Some(FIREFOX_MEMORY_MAX),
                firejail_profile: Some(KEIRA_PROFILE),
                implicit_extra_args: Some(&["-P", "nightly"]),
                argv_remainder: args,
            });
        }
        "npv" => return simple_firejail_command("mpv", args),
        "t" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: TERM,
                memory_high: None,
                memory_max: None,
                firejail_profile: Some(TERM_PROFILE),
                implicit_extra_args: None,
                argv_remainder: args,
            })
        }
        "read" => {
            let formatted_args: Vec<String> = vec![format!("about:reader?url={}", args[0])];
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: FIREFOX,
                memory_high: Some(FIREFOX_MEMORY_HIGH),
                memory_max: Some(FIREFOX_MEMORY_MAX),
                firejail_profile: Some(FIREFOX_PROFILE),
                implicit_extra_args: Some(&["-P", FIREFOX_MOZILLA_SFW_PROFILE]),
                argv_remainder: formatted_args,
            });
        }
        "tbb" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: THUNDERBIRD,
                memory_high: None,
                memory_max: None,
                firejail_profile: Some(THUNDERBIRD_PROFILE),
                implicit_extra_args: None,
                argv_remainder: args,
            });
        }
        "vlk" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: "/usr/bin/vlc",
                memory_high: None,
                memory_max: None,
                firejail_profile: Some("/etc/firejail/vlc.profile"),
                implicit_extra_args: None,
                argv_remainder: args,
            })
        }
        "e" => return simple_firejail_command("evince", args),
        _ => panic!(format!("no handler for ``{}''", target)),
    }
}

fn main() {
    let mut command = init_command();
    println!("{:#?}", command);
    command.exec();
}
<|endoftext|>


<commit_before>#![allow(deprecated)]
#![feature(test)]

extern crate test;
extern crate futures;
#[macro_use]
extern crate tokio_core;

use std::io;
use std::net::SocketAddr;
use std::thread;

use futures::sync::oneshot;
use futures::sync::mpsc;
use futures::{Future, Poll, Sink, Stream};
use test::Bencher;
use tokio_core::channel::Sender;
use tokio_core::net::UdpSocket;
use tokio_core::reactor::Core;

/// UDP echo server
struct EchoServer {
    socket: UdpSocket,
    buf: Vec<u8>,
    to_send: Option<(usize, SocketAddr)>,
}

impl EchoServer {
    fn new(s: UdpSocket) -> Self {
        EchoServer {
            socket: s,
            to_send: None,
            buf: vec![0u8; 1600],
        }
    }
}

impl Future for EchoServer {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<(), io::Error> {
        loop {
            if let Some(&(size, peer)) = self.to_send.as_ref() {
                try_nb!(self.socket.send_to(&self.buf[..size], &peer));
                self.to_send = None;
            }
            self.to_send = Some(try_nb!(self.socket.recv_from(&mut self.buf)));
        }
    }
}

#[bench]
fn udp_echo_latency(b: &mut Bencher) {
    let any_addr = "127.0.0.1:0".to_string();
    let any_addr = any_addr.parse::<SocketAddr>().unwrap();

    let (stop_c, stop_p) = oneshot::channel::<()>();
    let (tx, rx) = oneshot::channel();

    let child = thread::spawn(move || {
        let mut l = Core::new().unwrap();
        let handle = l.handle();

        let socket = tokio_core::net::UdpSocket::bind(&any_addr, &handle).unwrap();
        tx.complete(socket.local_addr().unwrap());

        let server = EchoServer::new(socket);
        let server = server.select(stop_p.map_err(|_| panic!()));
        let server = server.map_err(|_| ());
        l.run(server).unwrap()
    });

    let client = std::net::UdpSocket::bind(&any_addr).unwrap();

    let server_addr = rx.wait().unwrap();
    let mut buf = [0u8; 1000];

    // warmup phase; for some reason initial couple of
    // runs are much slower
    //
    // TODO: Describe the exact reasons; caching? branch predictor? lazy closures?
    for _ in 0..8 {
        client.send_to(&buf, &server_addr).unwrap();
        let _ = client.recv_from(&mut buf).unwrap();
    }

    b.iter(|| {
        client.send_to(&buf, &server_addr).unwrap();
        let _ = client.recv_from(&mut buf).unwrap();
    });

    stop_c.complete(());
    child.join().unwrap();
}

#[bench]
fn tokio_channel_latency(b: &mut Bencher) {
    let (tx, rx) = oneshot::channel();

    let child = thread::spawn(move || {
        let mut l = Core::new().unwrap();
        let handle = l.handle();

        let (in_tx, in_rx) = tokio_core::channel::channel(&handle).unwrap();
        let (out_tx, out_rx) = tokio_core::channel::channel(&handle).unwrap();
        tx.complete((in_tx, out_rx));

        let server = out_tx.send_all(in_rx);

        l.run(server).unwrap();
    });

    let (in_tx, out_rx) = rx.wait().unwrap();
    let mut rx_iter = out_rx.wait();

    // warmup phase; for some reason initial couple of runs are much slower
    //
    // TODO: Describe the exact reasons; caching? branch predictor? lazy closures?
    for _ in 0..8 {
        Sender::send(&in_tx, 1usize).unwrap();
        let _ = rx_iter.next();
    }

    b.iter(|| {
        Sender::send(&in_tx, 1usize).unwrap();
        let _ = rx_iter.next();
    });

    drop(in_tx);
    child.join().unwrap();
}

#[bench]
fn futures_channel_latency(b: &mut Bencher) {
    let (mut in_tx, in_rx) = mpsc::channel(32);
    let (out_tx, out_rx) = mpsc::channel::<_>(32);

    let child = thread::spawn(|| out_tx.send_all(in_rx.then(|r| r.unwrap())).wait());
    let mut rx_iter = out_rx.wait();

    // warmup phase; for some reason initial couple of runs are much slower
    //
    // TODO: Describe the exact reasons; caching? branch predictor? lazy closures?
    for _ in 0..8 {
        in_tx.start_send(Ok(1usize)).unwrap();
        let _ = rx_iter.next();
    }

    b.iter(|| {
        in_tx.start_send(Ok(1usize)).unwrap();
        let _ = rx_iter.next();
    });

    drop(in_tx);
    child.join().unwrap().unwrap();
}
<commit_msg>Remove deprecated benchmark<commit_after>#![allow(deprecated)]
#![feature(test)]

extern crate test;
extern crate futures;
#[macro_use]
extern crate tokio_core;

use std::io;
use std::net::SocketAddr;
use std::thread;

use futures::sync::oneshot;
use futures::sync::mpsc;
use futures::{Future, Poll, Sink, Stream};
use test::Bencher;
use tokio_core::net::UdpSocket;
use tokio_core::reactor::Core;

/// UDP echo server
struct EchoServer {
    socket: UdpSocket,
    buf: Vec<u8>,
    to_send: Option<(usize, SocketAddr)>,
}

impl EchoServer {
    fn new(s: UdpSocket) -> Self {
        EchoServer {
            socket: s,
            to_send: None,
            buf: vec![0u8; 1600],
        }
    }
}

impl Future for EchoServer {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<(), io::Error> {
        loop {
            if let Some(&(size, peer)) = self.to_send.as_ref() {
                try_nb!(self.socket.send_to(&self.buf[..size], &peer));
                self.to_send = None;
            }
            self.to_send = Some(try_nb!(self.socket.recv_from(&mut self.buf)));
        }
    }
}

#[bench]
fn udp_echo_latency(b: &mut Bencher) {
    let any_addr = "127.0.0.1:0".to_string();
    let any_addr = any_addr.parse::<SocketAddr>().unwrap();

    let (stop_c, stop_p) = oneshot::channel::<()>();
    let (tx, rx) = oneshot::channel();

    let child = thread::spawn(move || {
        let mut l = Core::new().unwrap();
        let handle = l.handle();

        let socket = tokio_core::net::UdpSocket::bind(&any_addr, &handle).unwrap();
        tx.complete(socket.local_addr().unwrap());

        let server = EchoServer::new(socket);
        let server = server.select(stop_p.map_err(|_| panic!()));
        let server = server.map_err(|_| ());
        l.run(server).unwrap()
    });

    let client = std::net::UdpSocket::bind(&any_addr).unwrap();

    let server_addr = rx.wait().unwrap();
    let mut buf = [0u8; 1000];

    // warmup phase; for some reason initial couple of
    // runs are much slower
    //
    // TODO: Describe the exact reasons; caching? branch predictor? lazy closures?
    for _ in 0..8 {
        client.send_to(&buf, &server_addr).unwrap();
        let _ = client.recv_from(&mut buf).unwrap();
    }

    b.iter(|| {
        client.send_to(&buf, &server_addr).unwrap();
        let _ = client.recv_from(&mut buf).unwrap();
    });

    stop_c.complete(());
    child.join().unwrap();
}

#[bench]
fn futures_channel_latency(b: &mut Bencher) {
    let (mut in_tx, in_rx) = mpsc::channel(32);
    let (out_tx, out_rx) = mpsc::channel::<_>(32);

    let child = thread::spawn(|| out_tx.send_all(in_rx.then(|r| r.unwrap())).wait());
    let mut rx_iter = out_rx.wait();

    // warmup phase; for some reason initial couple of runs are much slower
    //
    // TODO: Describe the exact reasons; caching? branch predictor? lazy closures?
    for _ in 0..8 {
        in_tx.start_send(Ok(1usize)).unwrap();
        let _ = rx_iter.next();
    }

    b.iter(|| {
        in_tx.start_send(Ok(1usize)).unwrap();
        let _ = rx_iter.next();
    });

    drop(in_tx);
    child.join().unwrap().unwrap();
}
<|endoftext|>


<commit_before>#![feature(
    async_await,
    await_macro,
)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = await!(async { *y + *z });
    let a = 10;
    let a = &a;
    *x + y + *a
}

fn raw_waker_clone(_this: *const ()) -> RawWaker {
    panic!("unimplemented");
}
fn raw_waker_wake(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_wake_by_ref(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_drop(_this: *const ()) {}

static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
    raw_waker_clone,
    raw_waker_wake,
    raw_waker_wake_by_ref,
    raw_waker_drop,
);

fn main() {
    let x = 5;
    let mut fut = foo(&x, 7);
    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31));
}
<commit_msg>Remove await_macro<commit_after>#![feature(async_await)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = async { *y + *z }.await;
    let a = 10;
    let a = &a;
    *x + y + *a
}

fn raw_waker_clone(_this: *const ()) -> RawWaker {
    panic!("unimplemented");
}
fn raw_waker_wake(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_wake_by_ref(_this: *const ()) {
    panic!("unimplemented");
}
fn raw_waker_drop(_this: *const ()) {}

static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
    raw_waker_clone,
    raw_waker_wake,
    raw_waker_wake_by_ref,
    raw_waker_drop,
);

fn main() {
    let x = 5;
    let mut fut = foo(&x, 7);
    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31));
}
<|endoftext|>