<commit_before>use proc_macro2::Span;
use regex::Regex;

use lazy_static::lazy_static;
use proc_macro_error::abort;
use syn::spanned::Spanned;

lazy_static! {
    pub static ref COW_TYPE: Regex = Regex::new(r"Cow<'[a-z]+,str>").unwrap();
}

static CUSTOM_ARG_LIFETIME: &str = "v_a";

static CUSTOM_ARG_ALLOWED_COPY_TYPES: [&str; 14] = [
    "usize",
    "u8",
    "u16",
    "u32",
    "u64",
    "u128",
    "isize",
    "i8",
    "i16",
    "i32",
    "i64",
    "i128",
    "f32",
    "f64",
];

pub static NUMBER_TYPES: [&str; 38] = [
    "usize",
    "u8",
    "u16",
    "u32",
    "u64",
    "u128",
    "isize",
    "i8",
    "i16",
    "i32",
    "i64",
    "i128",
    "f32",
    "f64",
    "Option<usize>",
    "Option<u8>",
    "Option<u16>",
    "Option<u32>",
    "Option<u64>",
    "Option<isize>",
    "Option<i8>",
    "Option<i16>",
    "Option<i32>",
    "Option<i64>",
    "Option<f32>",
    "Option<f64>",
    "Option<Option<usize>>",
    "Option<Option<u8>>",
    "Option<Option<u16>>",
    "Option<Option<u32>>",
    "Option<Option<u64>>",
    "Option<Option<isize>>",
    "Option<Option<i8>>",
    "Option<Option<i16>>",
    "Option<Option<i32>>",
    "Option<Option<i64>>",
    "Option<Option<f32>>",
    "Option<Option<f64>>",
];

pub fn assert_string_type(name: &str, type_name: &str, field_type: &syn::Type) {
    if type_name != "String"
        && type_name != "&str"
        && !COW_TYPE.is_match(type_name)
        && type_name != "Option<String>"
        && type_name != "Option<Option<String>>"
        && !(type_name.starts_with("Option<") && type_name.ends_with("str>"))
        && !(type_name.starts_with("Option<Option<") && type_name.ends_with("str>>"))
    {
        abort!(
            field_type.span(),
            "`{}` validator can only be used on String, &str, Cow<'_,str> or an Option of those",
            name
        );
    }
}

pub fn assert_type_matches(
    field_name: String,
    field_type: &str,
    field_type2: Option<&String>,
    field_attr: &syn::Attribute,
) {
    if let Some(t2) = field_type2 {
        if field_type != t2 {
            abort!(field_attr.span(), "Invalid argument for `must_match` validator of field `{}`: types of field can't match", field_name);
        }
    } else {
        abort!(field_attr.span(), "Invalid argument for `must_match` validator of field `{}`: the other field doesn't exist in struct", field_name);
    }
}

pub fn assert_has_len(field_name: String, type_name: &str, field_type: &syn::Type) {
    if let syn::Type::Reference(ref tref) = field_type {
        let elem = &tref.elem;
        let type_name = format!("{}", quote::quote! { #elem }).replace(' ', "");

        if type_name == "str" {
            return;
        }
        assert_has_len(field_name, &type_name, elem);
        return;
    }

    if type_name != "String"
        && !type_name.starts_with("Vec<")
        && !type_name.starts_with("Option<Vec<")
        && !type_name.starts_with("Option<Option<Vec<")
        && type_name != "Option<String>"
        && type_name != "Option<Option<String>>"
        // a bit ugly
        && !(type_name.starts_with("Option<") && type_name.ends_with("str>"))
        && !(type_name.starts_with("Option<Option<") && type_name.ends_with("str>>"))
        && !COW_TYPE.is_match(type_name)
        && type_name != "&str"
    {
        abort!(field_type.span(),
                "Validator `length` can only be used on types `String`, `&str`, Cow<'_,str> or `Vec` but found `{}` for field `{}`",
                type_name, field_name
            );
    }
}

pub fn assert_has_range(field_name: String, type_name: &str, field_type: &syn::Type) {
    if !NUMBER_TYPES.contains(&type_name) {
        abort!(
            field_type.span(),
            "Validator `range` can only be used on number types but found `{}` for field `{}`",
            type_name,
            field_name
        );
    }
}

pub fn assert_custom_arg_type(field_span: &Span, field_type: &syn::Type) {
    match field_type {
        syn::Type::Reference(reference) => {
            if let Some(lifetime) = &reference.lifetime {
                let lifetime_ident = lifetime.ident.to_string();
                if lifetime_ident != CUSTOM_ARG_LIFETIME {
                    abort!(
                        field_span,
                        "Invalid argument reference: The lifetime `'{}` is not supported. Please use the validator lifetime `'{}`",
                        lifetime_ident,
                        CUSTOM_ARG_LIFETIME
                    );
                }
            } else {
                abort!(
                    field_span,
                    "Invalid argument reference: All references need to use the validator lifetime `'{}`",
                    CUSTOM_ARG_LIFETIME
                );
            }
        }
        // trigger nested validation
        syn::Type::Paren(paren) => {
            assert_custom_arg_type(field_span, &paren.elem);
        }
        syn::Type::Tuple(tuple) => {
            tuple.elems.iter().for_each(|x| assert_custom_arg_type(field_span, x));
        }
        // assert idents
        syn::Type::Path(path) => {
            let segments = &path.path.segments;
            if segments.len() == 1 {
                let ident = &segments.first().unwrap().ident.to_string();
                if CUSTOM_ARG_ALLOWED_COPY_TYPES.contains(&ident.as_str()) {
                    // A known copy type that can be passed without a reference
                    return;
                }
            }

            abort!(
                field_span,
                "Invalid argument type: All types except numbers and tuples need be passed by reference using the lifetime `'{}`",
                CUSTOM_ARG_LIFETIME,
            );
        }
        // Not allows
        _ => {
            abort!(
                field_span,
                "Invalid argument type: Custom arguments only allow tuples, number types and references using the lifetime `'{}` ",
                CUSTOM_ARG_LIFETIME,
            );
        }
    }
}<commit_msg>allow any string value (#177)<commit_after>use proc_macro2::Span;
use regex::Regex;

use lazy_static::lazy_static;
use proc_macro_error::abort;
use syn::spanned::Spanned;

lazy_static! {
    pub static ref COW_TYPE: Regex = Regex::new(r"Cow<'[a-z]+,str>").unwrap();
}

static CUSTOM_ARG_LIFETIME: &str = "v_a";

static CUSTOM_ARG_ALLOWED_COPY_TYPES: [&str; 14] = [
    "usize",
    "u8",
    "u16",
    "u32",
    "u64",
    "u128",
    "isize",
    "i8",
    "i16",
    "i32",
    "i64",
    "i128",
    "f32",
    "f64",
];

pub static NUMBER_TYPES: [&str; 38] = [
    "usize",
    "u8",
    "u16",
    "u32",
    "u64",
    "u128",
    "isize",
    "i8",
    "i16",
    "i32",
    "i64",
    "i128",
    "f32",
    "f64",
    "Option<usize>",
    "Option<u8>",
    "Option<u16>",
    "Option<u32>",
    "Option<u64>",
    "Option<isize>",
    "Option<i8>",
    "Option<i16>",
    "Option<i32>",
    "Option<i64>",
    "Option<f32>",
    "Option<f64>",
    "Option<Option<usize>>",
    "Option<Option<u8>>",
    "Option<Option<u16>>",
    "Option<Option<u32>>",
    "Option<Option<u64>>",
    "Option<Option<isize>>",
    "Option<Option<i8>>",
    "Option<Option<i16>>",
    "Option<Option<i32>>",
    "Option<Option<i64>>",
    "Option<Option<f32>>",
    "Option<Option<f64>>",
];

pub fn assert_string_type(name: &str, type_name: &str, field_type: &syn::Type) {
    if !type_name.contains("String") && !type_name.contains("str") {
        abort!(
            field_type.span(),
            "`{}` validator can only be used on String, &str, Cow<'_,str> or an Option of those",
            name
        );
    }
}

pub fn assert_type_matches(
    field_name: String,
    field_type: &str,
    field_type2: Option<&String>,
    field_attr: &syn::Attribute,
) {
    if let Some(t2) = field_type2 {
        if field_type != t2 {
            abort!(field_attr.span(), "Invalid argument for `must_match` validator of field `{}`: types of field can't match", field_name);
        }
    } else {
        abort!(field_attr.span(), "Invalid argument for `must_match` validator of field `{}`: the other field doesn't exist in struct", field_name);
    }
}

pub fn assert_has_len(field_name: String, type_name: &str, field_type: &syn::Type) {
    if let syn::Type::Reference(ref tref) = field_type {
        let elem = &tref.elem;
        let type_name = format!("{}", quote::quote! { #elem }).replace(' ', "");

        if type_name == "str" {
            return;
        }
        assert_has_len(field_name, &type_name, elem);
        return;
    }

    if !type_name.contains("String")
        && !type_name.contains("str")
        && !type_name.starts_with("Vec<")
        && !type_name.starts_with("Option<Vec<")
        && !type_name.starts_with("Option<Option<Vec<")
        // a bit ugly
        && !COW_TYPE.is_match(type_name)
    {
        abort!(field_type.span(),
                "Validator `length` can only be used on types `String`, `&str`, Cow<'_,str> or `Vec` but found `{}` for field `{}`",
                type_name, field_name
            );
    }
}

pub fn assert_has_range(field_name: String, type_name: &str, field_type: &syn::Type) {
    if !NUMBER_TYPES.contains(&type_name) {
        abort!(
            field_type.span(),
            "Validator `range` can only be used on number types but found `{}` for field `{}`",
            type_name,
            field_name
        );
    }
}

pub fn assert_custom_arg_type(field_span: &Span, field_type: &syn::Type) {
    match field_type {
        syn::Type::Reference(reference) => {
            if let Some(lifetime) = &reference.lifetime {
                let lifetime_ident = lifetime.ident.to_string();
                if lifetime_ident != CUSTOM_ARG_LIFETIME {
                    abort!(
                        field_span,
                        "Invalid argument reference: The lifetime `'{}` is not supported. Please use the validator lifetime `'{}`",
                        lifetime_ident,
                        CUSTOM_ARG_LIFETIME
                    );
                }
            } else {
                abort!(
                    field_span,
                    "Invalid argument reference: All references need to use the validator lifetime `'{}`",
                    CUSTOM_ARG_LIFETIME
                );
            }
        }
        // trigger nested validation
        syn::Type::Paren(paren) => {
            assert_custom_arg_type(field_span, &paren.elem);
        }
        syn::Type::Tuple(tuple) => {
            tuple.elems.iter().for_each(|x| assert_custom_arg_type(field_span, x));
        }
        // assert idents
        syn::Type::Path(path) => {
            let segments = &path.path.segments;
            if segments.len() == 1 {
                let ident = &segments.first().unwrap().ident.to_string();
                if CUSTOM_ARG_ALLOWED_COPY_TYPES.contains(&ident.as_str()) {
                    // A known copy type that can be passed without a reference
                    return;
                }
            }

            abort!(
                field_span,
                "Invalid argument type: All types except numbers and tuples need be passed by reference using the lifetime `'{}`",
                CUSTOM_ARG_LIFETIME,
            );
        }
        // Not allows
        _ => {
            abort!(
                field_span,
                "Invalid argument type: Custom arguments only allow tuples, number types and references using the lifetime `'{}` ",
                CUSTOM_ARG_LIFETIME,
            );
        }
    }
}<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::sync::Arc;

use buffer::BufferResource;
use descriptor_set::layout_def::PipelineLayoutDesc;
use descriptor_set::layout_def::DescriptorSetDesc;
use descriptor_set::layout_def::DescriptorWrite;
use descriptor_set::layout_def::DescriptorBind;
use descriptor_set::pool::DescriptorPool;
use device::Device;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// An actual descriptor set with the resources that are binded to it.
pub struct DescriptorSet<S> {
    set: vk::DescriptorSet,
    pool: Arc<DescriptorPool>,
    layout: Arc<DescriptorSetLayout<S>>,
}

impl<S> DescriptorSet<S> where S: DescriptorSetDesc {
    ///
    /// # Panic
    ///
    /// - Panicks if the pool and the layout were not created from the same `Device`.
    ///
    pub fn new(pool: &Arc<DescriptorPool>, layout: &Arc<DescriptorSetLayout<S>>, init: S::Init)
               -> Result<Arc<DescriptorSet<S>>, OomError>
    {
        unsafe {
            let mut set = try!(DescriptorSet::uninitialized(pool, layout));
            Arc::get_mut(&mut set).unwrap().unchecked_write(layout.description().decode_init(init));
            Ok(set)
        }
    }

    ///
    /// # Panic
    ///
    /// - Panicks if the pool and the layout were not created from the same `Device`.
    ///
    // FIXME: this has to check whether there's still enough room in the pool
    pub unsafe fn uninitialized(pool: &Arc<DescriptorPool>, layout: &Arc<DescriptorSetLayout<S>>)
                                -> Result<Arc<DescriptorSet<S>>, OomError>
    {
        assert_eq!(&**pool.device() as *const Device, &*layout.device as *const Device);

        let vk = pool.device().pointers();

        let set = {
            let infos = vk::DescriptorSetAllocateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
                pNext: ptr::null(),
                descriptorPool: pool.internal_object(),
                descriptorSetCount: 1,
                pSetLayouts: &layout.layout,
            };

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

        Ok(Arc::new(DescriptorSet {
            set: set,
            pool: pool.clone(),
            layout: layout.clone(),
        }))
    }

    /// Modifies a descriptor set.
    ///
    /// The parameter depends on your implementation of `DescriptorSetDesc`.
    ///
    /// This function trusts the implementation of `DescriptorSetDesc` when it comes to making sure
    /// that the correct resource type is written to the correct descriptor.
    pub fn write(&mut self, write: S::Write) {
        let write = self.layout.description().decode_write(write);
        unsafe { self.unchecked_write(write); }
    }

    /// Modifies a descriptor set without checking that the writes are correct.
    pub unsafe fn unchecked_write(&mut self, write: Vec<DescriptorWrite>) {
        let vk = self.pool.device().pointers();

        // FIXME: store resources in the descriptor set so that they aren't destroyed

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let buffer_descriptors = write.iter().filter_map(|write| {
            match write.content {
                DescriptorBind::UniformBuffer(ref buffer) |
                DescriptorBind::StorageBuffer(ref buffer) |
                DescriptorBind::DynamicUniformBuffer(ref buffer) |
                DescriptorBind::DynamicStorageBuffer(ref buffer) => {
                    Some(vk::DescriptorBufferInfo {
                        buffer: buffer.internal_object(),
                        offset: 0,      // FIXME: allow buffer slices
                        range: buffer.size() as u64,       // FIXME: allow buffer slices
                    })
                },
                _ => None
            }
        }).collect::<Vec<_>>();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let image_descriptors = write.iter().filter_map(|write| {
            match write.content {
                DescriptorBind::Sampler(ref sampler) => {
                    Some(vk::DescriptorImageInfo {
                        sampler: sampler.internal_object(),
                        imageView: 0,
                        imageLayout: 0,
                    })
                },
                DescriptorBind::CombinedImageSampler(ref sampler, ref image, layout) => {
                    Some(vk::DescriptorImageInfo {
                        sampler: sampler.internal_object(),
                        imageView: image.internal_object(),
                        imageLayout: layout as u32,
                    })
                },
                DescriptorBind::StorageImage(ref image, layout) |
                DescriptorBind::SampledImage(ref image, layout) |
                DescriptorBind::InputAttachment(ref image, layout) => {
                    Some(vk::DescriptorImageInfo {
                        sampler: 0,
                        imageView: image.internal_object(),
                        imageLayout: layout as u32,
                    })
                },
                _ => None
            }
        }).collect::<Vec<_>>();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let mut next_buffer_desc = 0;
        let mut next_image_desc = 0;

        let vk_writes = write.iter().map(|write| {
            let (buffer_info, image_info) = match write.content {
                DescriptorBind::Sampler(_) | DescriptorBind::CombinedImageSampler(_, _ ,_) |
                DescriptorBind::SampledImage(_, _) | DescriptorBind::StorageImage(_, _) |
                DescriptorBind::InputAttachment(_, _) => {
                    let img = image_descriptors.as_ptr().offset(next_image_desc as isize);
                    next_image_desc += 1;
                    (ptr::null(), img)
                },
                //DescriptorBind::UniformTexelBuffer(_) | DescriptorBind::StorageTexelBuffer(_) =>
                DescriptorBind::UniformBuffer(_) | DescriptorBind::StorageBuffer(_) |
                DescriptorBind::DynamicUniformBuffer(_) |
                DescriptorBind::DynamicStorageBuffer(_) => {
                    let buf = buffer_descriptors.as_ptr().offset(next_buffer_desc as isize);
                    next_buffer_desc += 1;
                    (buf, ptr::null())
                },
            };

            vk::WriteDescriptorSet {
                sType: vk::STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
                pNext: ptr::null(),
                dstSet: self.set,
                dstBinding: write.binding,
                dstArrayElement: write.array_element,
                descriptorCount: 1,
                descriptorType: write.content.ty() as u32,
                pImageInfo: image_info,
                pBufferInfo: buffer_info,
                pTexelBufferView: ptr::null(),      // TODO:
            }
        }).collect::<Vec<_>>();

        debug_assert_eq!(next_buffer_desc, buffer_descriptors.len());
        debug_assert_eq!(next_image_desc, image_descriptors.len());

        if !vk_writes.is_empty() {
            vk.UpdateDescriptorSets(self.pool.device().internal_object(),
                                    vk_writes.len() as u32, vk_writes.as_ptr(), 0, ptr::null());
        }
    }
}

unsafe impl<S> VulkanObject for DescriptorSet<S> {
    type Object = vk::DescriptorSet;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSet {
        self.set
    }
}

impl<S> Drop for DescriptorSet<S> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.pool.device().pointers();
            vk.FreeDescriptorSets(self.pool.device().internal_object(),
                                  self.pool.internal_object(), 1, &self.set);
        }
    }
}

/// Implemented on all `DescriptorSet` objects. Hides the template parameters.
pub unsafe trait AbstractDescriptorSet: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSet for DescriptorSet<S> {}

/// Describes the layout of all descriptors within a descriptor set.
pub struct DescriptorSetLayout<S> {
    layout: vk::DescriptorSetLayout,
    device: Arc<Device>,
    description: S,
}

impl<S> DescriptorSetLayout<S> where S: DescriptorSetDesc {
    pub fn new(device: &Arc<Device>, description: S)
               -> Result<Arc<DescriptorSetLayout<S>>, OomError>
    {
        let vk = device.pointers();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let bindings = description.descriptors().into_iter().map(|desc| {
            vk::DescriptorSetLayoutBinding {
                binding: desc.binding,
                descriptorType: desc.ty.vk_enum(),
                descriptorCount: desc.array_count,
                stageFlags: desc.stages.into(),
                pImmutableSamplers: ptr::null(),        // FIXME: not yet implemented
            }
        }).collect::<Vec<_>>();

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

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

        Ok(Arc::new(DescriptorSetLayout {
            layout: layout,
            device: device.clone(),
            description: description,
        }))
    }

    #[inline]
    pub fn description(&self) -> &S {
        &self.description
    }
}

unsafe impl<S> VulkanObject for DescriptorSetLayout<S> {
    type Object = vk::DescriptorSetLayout;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSetLayout {
        self.layout
    }
}

impl<S> Drop for DescriptorSetLayout<S> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}

/// Implemented on all `DescriptorSetLayout` objects. Hides the template parameters.
pub unsafe trait AbstractDescriptorSetLayout: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSetLayout for DescriptorSetLayout<S> {}

/// A collection of `DescriptorSetLayout` structs.
// TODO: push constants.
pub struct PipelineLayout<P> {
    device: Arc<Device>,
    layout: vk::PipelineLayout,
    description: P,
    layouts: Vec<Arc<AbstractDescriptorSetLayout>>,     // TODO: is it necessary to keep the layouts alive? check the specs
}

impl<P> PipelineLayout<P> where P: PipelineLayoutDesc {
    /// Creates a new `PipelineLayout`.
    pub fn new(device: &Arc<Device>, description: P, layouts: P::DescriptorSetLayouts)
               -> Result<Arc<PipelineLayout<P>>, OomError>
    {
        let vk = device.pointers();

        let layouts = description.decode_descriptor_set_layouts(layouts);
        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let layouts_ids = layouts.iter().map(|l| {
            // FIXME: check that they belong to the same device
            ::VulkanObjectU64::internal_object(&**l)
        }).collect::<Vec<_>>();

        let layout = unsafe {
            let infos = vk::PipelineLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                setLayoutCount: layouts_ids.len() as u32,
                pSetLayouts: layouts_ids.as_ptr(),
                pushConstantRangeCount: 0,      // TODO: unimplemented
                pPushConstantRanges: ptr::null(),    // TODO: unimplemented
            };

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

        Ok(Arc::new(PipelineLayout {
            device: device.clone(),
            layout: layout,
            description: description,
            layouts: layouts,
        }))
    }

    #[inline]
    pub fn description(&self) -> &P {
        &self.description
    }
}

unsafe impl<P> VulkanObject for PipelineLayout<P> {
    type Object = vk::PipelineLayout;

    #[inline]
    fn internal_object(&self) -> vk::PipelineLayout {
        self.layout
    }
}

impl<P> Drop for PipelineLayout<P> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}
<commit_msg>Store the list of resources in the descriptor sets<commit_after>use std::mem;
use std::ptr;
use std::sync::Arc;

use buffer::BufferResource;
use descriptor_set::layout_def::PipelineLayoutDesc;
use descriptor_set::layout_def::DescriptorSetDesc;
use descriptor_set::layout_def::DescriptorWrite;
use descriptor_set::layout_def::DescriptorBind;
use descriptor_set::pool::DescriptorPool;
use device::Device;
use image::ImageViewResource;
use sampler::Sampler;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// An actual descriptor set with the resources that are binded to it.
pub struct DescriptorSet<S> {
    set: vk::DescriptorSet,
    pool: Arc<DescriptorPool>,
    layout: Arc<DescriptorSetLayout<S>>,

    // Here we store the resources used by the descriptor set.
    // TODO: for the moment even when a resource is overwritten it stays in these lists
    resources_samplers: Vec<Arc<Sampler>>,
    resources_image_views: Vec<Arc<ImageViewResource>>,
    resources_buffers: Vec<Arc<BufferResource>>,
}

impl<S> DescriptorSet<S> where S: DescriptorSetDesc {
    ///
    /// # Panic
    ///
    /// - Panicks if the pool and the layout were not created from the same `Device`.
    ///
    pub fn new(pool: &Arc<DescriptorPool>, layout: &Arc<DescriptorSetLayout<S>>, init: S::Init)
               -> Result<Arc<DescriptorSet<S>>, OomError>
    {
        unsafe {
            let mut set = try!(DescriptorSet::uninitialized(pool, layout));
            Arc::get_mut(&mut set).unwrap().unchecked_write(layout.description().decode_init(init));
            Ok(set)
        }
    }

    ///
    /// # Panic
    ///
    /// - Panicks if the pool and the layout were not created from the same `Device`.
    ///
    // FIXME: this has to check whether there's still enough room in the pool
    pub unsafe fn uninitialized(pool: &Arc<DescriptorPool>, layout: &Arc<DescriptorSetLayout<S>>)
                                -> Result<Arc<DescriptorSet<S>>, OomError>
    {
        assert_eq!(&**pool.device() as *const Device, &*layout.device as *const Device);

        let vk = pool.device().pointers();

        let set = {
            let infos = vk::DescriptorSetAllocateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
                pNext: ptr::null(),
                descriptorPool: pool.internal_object(),
                descriptorSetCount: 1,
                pSetLayouts: &layout.layout,
            };

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

        Ok(Arc::new(DescriptorSet {
            set: set,
            pool: pool.clone(),
            layout: layout.clone(),

            resources_samplers: Vec::new(),
            resources_image_views: Vec::new(),
            resources_buffers: Vec::new(),
        }))
    }

    /// Modifies a descriptor set.
    ///
    /// The parameter depends on your implementation of `DescriptorSetDesc`.
    ///
    /// This function trusts the implementation of `DescriptorSetDesc` when it comes to making sure
    /// that the correct resource type is written to the correct descriptor.
    pub fn write(&mut self, write: S::Write) {
        let write = self.layout.description().decode_write(write);
        unsafe { self.unchecked_write(write); }
    }

    /// Modifies a descriptor set without checking that the writes are correct.
    pub unsafe fn unchecked_write(&mut self, write: Vec<DescriptorWrite>) {
        let vk = self.pool.device().pointers();

        // TODO: how do we remove the existing resources that are overwritten?

        // This function uses multiple closures which all borrow `self`. In order to satisfy the
        // borrow checker, we extract references to the members here.
        let ref mut self_resources_buffers = self.resources_buffers;
        let ref mut self_resources_samplers = self.resources_samplers;
        let ref mut self_resources_image_views = self.resources_image_views;
        let self_set = self.set;

        // FIXME: store resources in the descriptor set so that they aren't destroyed

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let buffer_descriptors = write.iter().filter_map(|write| {
            match write.content {
                DescriptorBind::UniformBuffer(ref buffer) |
                DescriptorBind::StorageBuffer(ref buffer) |
                DescriptorBind::DynamicUniformBuffer(ref buffer) |
                DescriptorBind::DynamicStorageBuffer(ref buffer) => {
                    self_resources_buffers.push(buffer.clone());
                    Some(vk::DescriptorBufferInfo {
                        buffer: buffer.internal_object(),
                        offset: 0,      // FIXME: allow buffer slices
                        range: buffer.size() as u64,       // FIXME: allow buffer slices
                    })
                },
                _ => None
            }
        }).collect::<Vec<_>>();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let image_descriptors = write.iter().filter_map(|write| {
            match write.content {
                DescriptorBind::Sampler(ref sampler) => {
                    self_resources_samplers.push(sampler.clone());
                    Some(vk::DescriptorImageInfo {
                        sampler: sampler.internal_object(),
                        imageView: 0,
                        imageLayout: 0,
                    })
                },
                DescriptorBind::CombinedImageSampler(ref sampler, ref image, layout) => {
                    self_resources_samplers.push(sampler.clone());
                    self_resources_image_views.push(image.clone());
                    Some(vk::DescriptorImageInfo {
                        sampler: sampler.internal_object(),
                        imageView: image.internal_object(),
                        imageLayout: layout as u32,
                    })
                },
                DescriptorBind::StorageImage(ref image, layout) |
                DescriptorBind::SampledImage(ref image, layout) |
                DescriptorBind::InputAttachment(ref image, layout) => {
                    self_resources_image_views.push(image.clone());
                    Some(vk::DescriptorImageInfo {
                        sampler: 0,
                        imageView: image.internal_object(),
                        imageLayout: layout as u32,
                    })
                },
                _ => None
            }
        }).collect::<Vec<_>>();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let mut next_buffer_desc = 0;
        let mut next_image_desc = 0;

        let vk_writes = write.iter().map(|write| {
            let (buffer_info, image_info) = match write.content {
                DescriptorBind::Sampler(_) | DescriptorBind::CombinedImageSampler(_, _ ,_) |
                DescriptorBind::SampledImage(_, _) | DescriptorBind::StorageImage(_, _) |
                DescriptorBind::InputAttachment(_, _) => {
                    let img = image_descriptors.as_ptr().offset(next_image_desc as isize);
                    next_image_desc += 1;
                    (ptr::null(), img)
                },
                //DescriptorBind::UniformTexelBuffer(_) | DescriptorBind::StorageTexelBuffer(_) =>
                DescriptorBind::UniformBuffer(_) | DescriptorBind::StorageBuffer(_) |
                DescriptorBind::DynamicUniformBuffer(_) |
                DescriptorBind::DynamicStorageBuffer(_) => {
                    let buf = buffer_descriptors.as_ptr().offset(next_buffer_desc as isize);
                    next_buffer_desc += 1;
                    (buf, ptr::null())
                },
            };

            vk::WriteDescriptorSet {
                sType: vk::STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
                pNext: ptr::null(),
                dstSet: self_set,
                dstBinding: write.binding,
                dstArrayElement: write.array_element,
                descriptorCount: 1,
                descriptorType: write.content.ty() as u32,
                pImageInfo: image_info,
                pBufferInfo: buffer_info,
                pTexelBufferView: ptr::null(),      // TODO:
            }
        }).collect::<Vec<_>>();

        debug_assert_eq!(next_buffer_desc, buffer_descriptors.len());
        debug_assert_eq!(next_image_desc, image_descriptors.len());

        if !vk_writes.is_empty() {
            vk.UpdateDescriptorSets(self.pool.device().internal_object(),
                                    vk_writes.len() as u32, vk_writes.as_ptr(), 0, ptr::null());
        }
    }
}

unsafe impl<S> VulkanObject for DescriptorSet<S> {
    type Object = vk::DescriptorSet;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSet {
        self.set
    }
}

impl<S> Drop for DescriptorSet<S> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.pool.device().pointers();
            vk.FreeDescriptorSets(self.pool.device().internal_object(),
                                  self.pool.internal_object(), 1, &self.set);
        }
    }
}

/// Implemented on all `DescriptorSet` objects. Hides the template parameters.
pub unsafe trait AbstractDescriptorSet: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSet for DescriptorSet<S> {}

/// Describes the layout of all descriptors within a descriptor set.
pub struct DescriptorSetLayout<S> {
    layout: vk::DescriptorSetLayout,
    device: Arc<Device>,
    description: S,
}

impl<S> DescriptorSetLayout<S> where S: DescriptorSetDesc {
    pub fn new(device: &Arc<Device>, description: S)
               -> Result<Arc<DescriptorSetLayout<S>>, OomError>
    {
        let vk = device.pointers();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let bindings = description.descriptors().into_iter().map(|desc| {
            vk::DescriptorSetLayoutBinding {
                binding: desc.binding,
                descriptorType: desc.ty.vk_enum(),
                descriptorCount: desc.array_count,
                stageFlags: desc.stages.into(),
                pImmutableSamplers: ptr::null(),        // FIXME: not yet implemented
            }
        }).collect::<Vec<_>>();

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

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

        Ok(Arc::new(DescriptorSetLayout {
            layout: layout,
            device: device.clone(),
            description: description,
        }))
    }

    #[inline]
    pub fn description(&self) -> &S {
        &self.description
    }
}

unsafe impl<S> VulkanObject for DescriptorSetLayout<S> {
    type Object = vk::DescriptorSetLayout;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSetLayout {
        self.layout
    }
}

impl<S> Drop for DescriptorSetLayout<S> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}

/// Implemented on all `DescriptorSetLayout` objects. Hides the template parameters.
pub unsafe trait AbstractDescriptorSetLayout: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSetLayout for DescriptorSetLayout<S> {}

/// A collection of `DescriptorSetLayout` structs.
// TODO: push constants.
pub struct PipelineLayout<P> {
    device: Arc<Device>,
    layout: vk::PipelineLayout,
    description: P,
    layouts: Vec<Arc<AbstractDescriptorSetLayout>>,     // TODO: is it necessary to keep the layouts alive? check the specs
}

impl<P> PipelineLayout<P> where P: PipelineLayoutDesc {
    /// Creates a new `PipelineLayout`.
    pub fn new(device: &Arc<Device>, description: P, layouts: P::DescriptorSetLayouts)
               -> Result<Arc<PipelineLayout<P>>, OomError>
    {
        let vk = device.pointers();

        let layouts = description.decode_descriptor_set_layouts(layouts);
        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let layouts_ids = layouts.iter().map(|l| {
            // FIXME: check that they belong to the same device
            ::VulkanObjectU64::internal_object(&**l)
        }).collect::<Vec<_>>();

        let layout = unsafe {
            let infos = vk::PipelineLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                setLayoutCount: layouts_ids.len() as u32,
                pSetLayouts: layouts_ids.as_ptr(),
                pushConstantRangeCount: 0,      // TODO: unimplemented
                pPushConstantRanges: ptr::null(),    // TODO: unimplemented
            };

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

        Ok(Arc::new(PipelineLayout {
            device: device.clone(),
            layout: layout,
            description: description,
            layouts: layouts,
        }))
    }

    #[inline]
    pub fn description(&self) -> &P {
        &self.description
    }
}

unsafe impl<P> VulkanObject for PipelineLayout<P> {
    type Object = vk::PipelineLayout;

    #[inline]
    fn internal_object(&self) -> vk::PipelineLayout {
        self.layout
    }
}

impl<P> Drop for PipelineLayout<P> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate ai_behavior;
extern crate sprite;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::path::Path;
use std::cell::RefCell;
use std::rc::Rc;

use sprite::*;
use ai_behavior::{
    Action,
    Sequence,
    Wait,
    WaitForever,
    While,
};

use sdl2_window::Sdl2Window;
use opengl_graphics::{
    GlGraphics,
    OpenGL,
    Texture,
};

fn main() {
    let (width, height) = (300, 300);
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "piston-example-sprite".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let id;
    let mut scene = Scene::new();
    let tex = Path::new("./bin/assets/rust-logo.png");
    let tex = Rc::new(Texture::from_path(&tex).unwrap());
    let mut sprite = Sprite::from_texture(tex.clone());
    sprite.set_position(width as f64 / 2.0, height as f64 / 2.0);

    id = scene.add_child(sprite);

    // Run a sequence or animations.
    let seq = Sequence(vec![
        Action(Ease(EaseFunction::CubicOut, Box::new(ScaleTo(2.0, 0.5, 0.5)))),
        Action(Ease(EaseFunction::BounceOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Ease(EaseFunction::ElasticOut, Box::new(MoveBy(2.0, 0.0, -100.0)))),
        Action(Ease(EaseFunction::BackInOut, Box::new(MoveBy(1.0, 0.0, -100.0)))),
        Wait(0.5),
        Action(Ease(EaseFunction::ExponentialInOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Blink(1.0, 5)),
        While(Box::new(WaitForever), vec![
            Action(Ease(EaseFunction::QuadraticIn, Box::new(FadeOut(1.0)))),
            Action(Ease(EaseFunction::QuadraticOut, Box::new(FadeIn(1.0)))),
        ]),
    ]);
    scene.run(&id, &seq);

    // This animation and the one above can run in parallel.
    let rotate = Action(Ease(EaseFunction::ExponentialInOut,
        Box::new(RotateTo(2.0, 360.0))));
    scene.run(&id, &rotate);

    println!("Press any key to pause/resume the animation!");

    let ref mut gl = GlGraphics::new(opengl);
    let window = Rc::new(RefCell::new(window));
    for e in piston::events(window) {
        use piston::event::*;

        scene.event(&e);

        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0, 1.0, 1.0, 1.0], gl);
                scene.draw(c.transform, gl);
            });
        }
        if let Some(_) = e.press_args() {
            scene.toggle(&id, &seq);
            scene.toggle(&id, &rotate);
        }
    }
}
<commit_msg>Updated "sprite" example to latest Rust<commit_after>extern crate piston;
extern crate ai_behavior;
extern crate sprite;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::path::Path;
use std::cell::RefCell;
use std::rc::Rc;

use sprite::*;
use ai_behavior::{
    Action,
    Sequence,
    Wait,
    WaitForever,
    While,
};

use sdl2_window::Sdl2Window;
use opengl_graphics::{
    GlGraphics,
    OpenGL,
    Texture,
};
use piston::window::{ WindowSettings, Size };

fn main() {
    let (width, height) = (300, 300);
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        WindowSettings::new(
            "piston-example-sprite".to_string(),
            Size { width: width, height: height }
        )
        .exit_on_esc(true)
    );

    let id;
    let mut scene = Scene::new();
    let tex = Path::new("./bin/assets/rust-logo.png");
    let tex = Rc::new(Texture::from_path(&tex).unwrap());
    let mut sprite = Sprite::from_texture(tex.clone());
    sprite.set_position(width as f64 / 2.0, height as f64 / 2.0);

    id = scene.add_child(sprite);

    // Run a sequence or animations.
    let seq = Sequence(vec![
        Action(Ease(EaseFunction::CubicOut, Box::new(ScaleTo(2.0, 0.5, 0.5)))),
        Action(Ease(EaseFunction::BounceOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Ease(EaseFunction::ElasticOut, Box::new(MoveBy(2.0, 0.0, -100.0)))),
        Action(Ease(EaseFunction::BackInOut, Box::new(MoveBy(1.0, 0.0, -100.0)))),
        Wait(0.5),
        Action(Ease(EaseFunction::ExponentialInOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Blink(1.0, 5)),
        While(Box::new(WaitForever), vec![
            Action(Ease(EaseFunction::QuadraticIn, Box::new(FadeOut(1.0)))),
            Action(Ease(EaseFunction::QuadraticOut, Box::new(FadeIn(1.0)))),
        ]),
    ]);
    scene.run(&id, &seq);

    // This animation and the one above can run in parallel.
    let rotate = Action(Ease(EaseFunction::ExponentialInOut,
        Box::new(RotateTo(2.0, 360.0))));
    scene.run(&id, &rotate);

    println!("Press any key to pause/resume the animation!");

    let ref mut gl = GlGraphics::new(opengl);
    let window = Rc::new(RefCell::new(window));
    for e in piston::events(window) {
        use piston::event::*;

        scene.event(&e);

        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0, 1.0, 1.0, 1.0], gl);
                scene.draw(c.transform, gl);
            });
        }
        if let Some(_) = e.press_args() {
            scene.toggle(&id, &seq);
            scene.toggle(&id, &rotate);
        }
    }
}
<|endoftext|>


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

use std::collections::hash_map::IterMut;
use std::collections::HashMap;
use std::io;
use std::ops::{Index, IndexMut};
use std::slice::SliceIndex;

/// Trait that allows for checking if an implementor is dirty. Useful for types that are cached so
/// it can be checked if they need to be committed to disk.
pub trait Cacheable {
    /// Used to check if the item needs to be written out or if it can be discarded.
    fn dirty(&self) -> bool;
}

#[derive(Debug)]
/// Represents a vector that implements the `Cacheable` trait so it can be held in a cache.
pub struct VecCache<T: 'static + Copy + Default> {
    vec: Box<[T]>,
    dirty: bool,
}

impl<T: 'static + Copy + Default> VecCache<T> {
    /// Creates a `VecCache` that can hold `count` elements.
    pub fn new(count: usize) -> VecCache<T> {
        VecCache {
            vec: vec![Default::default(); count].into_boxed_slice(),
            dirty: true,
        }
    }

    /// Creates a `VecCache` from the passed in `vec`.
    pub fn from_vec(vec: Vec<T>) -> VecCache<T> {
        VecCache {
            vec: vec.into_boxed_slice(),
            dirty: false,
        }
    }

    pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
    where
        I: SliceIndex<[T]>,
    {
        self.vec.get(index)
    }

    /// Gets a reference to the underlying vector.
    pub fn get_values(&self) -> &[T] {
        &self.vec
    }

    /// Mark this cache element as clean.
    pub fn mark_clean(&mut self) {
        self.dirty = false;
    }

    /// Returns the number of elements in the vector.
    pub fn len(&self) -> usize {
        self.vec.len()
    }
}

impl<T: 'static + Copy + Default> Cacheable for VecCache<T> {
    fn dirty(&self) -> bool {
        self.dirty
    }
}

impl<T: 'static + Copy + Default> Index<usize> for VecCache<T> {
    type Output = T;

    fn index(&self, index: usize) -> &T {
        self.vec.index(index)
    }
}

impl<T: 'static + Copy + Default> IndexMut<usize> for VecCache<T> {
    fn index_mut(&mut self, index: usize) -> &mut T {
        self.dirty = true;
        self.vec.index_mut(index)
    }
}

#[derive(Debug)]
pub struct CacheMap<T: Cacheable> {
    capacity: usize,
    map: HashMap<usize, T>,
}

impl<T: Cacheable> CacheMap<T> {
    pub fn new(capacity: usize) -> Self {
        CacheMap {
            capacity,
            map: HashMap::with_capacity(capacity),
        }
    }

    pub fn contains_key(&self, key: &usize) -> bool {
        self.map.contains_key(key)
    }

    pub fn get(&self, index: &usize) -> Option<&T> {
        self.map.get(index)
    }

    pub fn get_mut(&mut self, index: &usize) -> Option<&mut T> {
        self.map.get_mut(index)
    }

    pub fn iter_mut(&mut self) -> IterMut<usize, T> {
        self.map.iter_mut()
    }

    // Check if the refblock cache is full and we need to evict.
    pub fn insert<F>(&mut self, index: usize, block: T, write_callback: F) -> io::Result<()>
    where
        F: FnOnce(usize, T) -> io::Result<()>,
    {
        if self.map.len() == self.capacity {
            // TODO(dgreid) - smarter eviction strategy.
            let to_evict = *self.map.iter().nth(0).unwrap().0;
            if let Some(evicted) = self.map.remove(&to_evict) {
                if evicted.dirty() {
                    write_callback(to_evict, evicted)?;
                }
            }
        }
        self.map.insert(index, block);
        Ok(())
    }
}

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

    struct NumCache(pub u64);
    impl Cacheable for NumCache {
        fn dirty(&self) -> bool {
            true
        }
    }

    #[test]
    fn evicts_when_full() {
        let mut cache = CacheMap::<NumCache>::new(3);
        let mut evicted = None;
        cache
            .insert(0, NumCache(5), |index, _| {
                evicted = Some(index);
                Ok(())
            })
            .unwrap();
        assert_eq!(evicted, None);
        cache
            .insert(1, NumCache(6), |index, _| {
                evicted = Some(index);
                Ok(())
            })
            .unwrap();
        assert_eq!(evicted, None);
        cache
            .insert(2, NumCache(7), |index, _| {
                evicted = Some(index);
                Ok(())
            })
            .unwrap();
        assert_eq!(evicted, None);
        cache
            .insert(3, NumCache(8), |index, _| {
                evicted = Some(index);
                Ok(())
            })
            .unwrap();
        assert!(evicted.is_some());

        // Check that three of the four items inserted are still there and that the most recently
        // inserted is one of them.
        let num_items = (0..=3).filter(|k| cache.contains_key(&k)).count();
        assert_eq!(num_items, 3);
        assert!(cache.contains_key(&3));
    }
}
<commit_msg>disk: resolve iter_nth_zero clippy warning<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::collections::hash_map::IterMut;
use std::collections::HashMap;
use std::io;
use std::ops::{Index, IndexMut};
use std::slice::SliceIndex;

/// Trait that allows for checking if an implementor is dirty. Useful for types that are cached so
/// it can be checked if they need to be committed to disk.
pub trait Cacheable {
    /// Used to check if the item needs to be written out or if it can be discarded.
    fn dirty(&self) -> bool;
}

#[derive(Debug)]
/// Represents a vector that implements the `Cacheable` trait so it can be held in a cache.
pub struct VecCache<T: 'static + Copy + Default> {
    vec: Box<[T]>,
    dirty: bool,
}

impl<T: 'static + Copy + Default> VecCache<T> {
    /// Creates a `VecCache` that can hold `count` elements.
    pub fn new(count: usize) -> VecCache<T> {
        VecCache {
            vec: vec![Default::default(); count].into_boxed_slice(),
            dirty: true,
        }
    }

    /// Creates a `VecCache` from the passed in `vec`.
    pub fn from_vec(vec: Vec<T>) -> VecCache<T> {
        VecCache {
            vec: vec.into_boxed_slice(),
            dirty: false,
        }
    }

    pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
    where
        I: SliceIndex<[T]>,
    {
        self.vec.get(index)
    }

    /// Gets a reference to the underlying vector.
    pub fn get_values(&self) -> &[T] {
        &self.vec
    }

    /// Mark this cache element as clean.
    pub fn mark_clean(&mut self) {
        self.dirty = false;
    }

    /// Returns the number of elements in the vector.
    pub fn len(&self) -> usize {
        self.vec.len()
    }
}

impl<T: 'static + Copy + Default> Cacheable for VecCache<T> {
    fn dirty(&self) -> bool {
        self.dirty
    }
}

impl<T: 'static + Copy + Default> Index<usize> for VecCache<T> {
    type Output = T;

    fn index(&self, index: usize) -> &T {
        self.vec.index(index)
    }
}

impl<T: 'static + Copy + Default> IndexMut<usize> for VecCache<T> {
    fn index_mut(&mut self, index: usize) -> &mut T {
        self.dirty = true;
        self.vec.index_mut(index)
    }
}

#[derive(Debug)]
pub struct CacheMap<T: Cacheable> {
    capacity: usize,
    map: HashMap<usize, T>,
}

impl<T: Cacheable> CacheMap<T> {
    pub fn new(capacity: usize) -> Self {
        CacheMap {
            capacity,
            map: HashMap::with_capacity(capacity),
        }
    }

    pub fn contains_key(&self, key: &usize) -> bool {
        self.map.contains_key(key)
    }

    pub fn get(&self, index: &usize) -> Option<&T> {
        self.map.get(index)
    }

    pub fn get_mut(&mut self, index: &usize) -> Option<&mut T> {
        self.map.get_mut(index)
    }

    pub fn iter_mut(&mut self) -> IterMut<usize, T> {
        self.map.iter_mut()
    }

    // Check if the refblock cache is full and we need to evict.
    pub fn insert<F>(&mut self, index: usize, block: T, write_callback: F) -> io::Result<()>
    where
        F: FnOnce(usize, T) -> io::Result<()>,
    {
        if self.map.len() == self.capacity {
            // TODO(dgreid) - smarter eviction strategy.
            let to_evict = *self.map.iter().next().unwrap().0;
            if let Some(evicted) = self.map.remove(&to_evict) {
                if evicted.dirty() {
                    write_callback(to_evict, evicted)?;
                }
            }
        }
        self.map.insert(index, block);
        Ok(())
    }
}

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

    struct NumCache(pub u64);
    impl Cacheable for NumCache {
        fn dirty(&self) -> bool {
            true
        }
    }

    #[test]
    fn evicts_when_full() {
        let mut cache = CacheMap::<NumCache>::new(3);
        let mut evicted = None;
        cache
            .insert(0, NumCache(5), |index, _| {
                evicted = Some(index);
                Ok(())
            })
            .unwrap();
        assert_eq!(evicted, None);
        cache
            .insert(1, NumCache(6), |index, _| {
                evicted = Some(index);
                Ok(())
            })
            .unwrap();
        assert_eq!(evicted, None);
        cache
            .insert(2, NumCache(7), |index, _| {
                evicted = Some(index);
                Ok(())
            })
            .unwrap();
        assert_eq!(evicted, None);
        cache
            .insert(3, NumCache(8), |index, _| {
                evicted = Some(index);
                Ok(())
            })
            .unwrap();
        assert!(evicted.is_some());

        // Check that three of the four items inserted are still there and that the most recently
        // inserted is one of them.
        let num_items = (0..=3).filter(|k| cache.contains_key(&k)).count();
        assert_eq!(num_items, 3);
        assert!(cache.contains_key(&3));
    }
}
<|endoftext|>


<commit_before>fn main() {
    for c in 1 .. 51 {
        for b in 1 .. c {
            for a in 1 .. b {
                if a * a + b * b == c * c {
                    println!("{}, {}, {}", a, b, c)
                }
            }
        }
    }
}
<commit_msg>Using 40 not 50 for triples<commit_after>fn main() {
    for c in 1 .. 41 {
        for b in 1 .. c {
            for a in 1 .. b {
                if a * a + b * b == c * c {
                    println!("{}, {}, {}", a, b, c)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{self, ErrorKind, Read};
use std::string::FromUtf8Error;

use rmp::Marker;
use rmp::decode::{read_marker, read_data_u8, read_data_u16, read_data_u32, read_data_u64,
                  read_data_i8, read_data_i16, read_data_i32, read_data_i64, read_data_f32,
                  read_data_f64, MarkerReadError, ValueReadError};

use Value;

/// This type represents all possible errors that can occur when deserializing a value.
#[derive(Debug)]
pub enum Error {
    /// Error while reading marker byte.
    InvalidMarkerRead(io::Error),
    /// Error while reading data.
    InvalidDataRead(io::Error),
    /// Decoded value type isn't equal with the expected one.
    TypeMismatch(Marker),
    /// Failed to properly decode UTF8.
    FromUtf8Error(FromUtf8Error),
}

impl Error {
    pub fn insufficient_bytes(&self) -> bool {
        match *self {
            Error::InvalidMarkerRead(ref err) if err.kind() == ErrorKind::UnexpectedEof => true,
            Error::InvalidDataRead(ref err) if err.kind() == ErrorKind::UnexpectedEof => true,
            _ => false,
        }
    }
}

impl From<MarkerReadError> for Error {
    fn from(err: MarkerReadError) -> Error {
        Error::InvalidMarkerRead(err.0)
    }
}

impl From<ValueReadError> for Error {
    fn from(err: ValueReadError) -> Error {
        match err {
            ValueReadError::InvalidMarkerRead(err) => Error::InvalidMarkerRead(err),
            ValueReadError::InvalidDataRead(err) => Error::InvalidDataRead(err),
            ValueReadError::TypeMismatch(marker) => Error::TypeMismatch(marker),
        }
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::FromUtf8Error(err)
    }
}

fn read_array_data<R: Read>(rd: &mut R, mut len: usize) -> Result<Vec<Value>, Error> {
    let mut vec = Vec::with_capacity(len);

    while len > 0 {
        vec.push(read_value(rd)?);
        len -= 1;
    }

    Ok(vec)
}

fn read_map_data<R: Read>(rd: &mut R, mut len: usize) -> Result<Vec<(Value, Value)>, Error> {
    let mut vec = Vec::with_capacity(len);

    while len > 0 {
        vec.push((read_value(rd)?, read_value(rd)?));
        len -= 1;
    }

    Ok(vec)
}

fn read_str_data<R: Read>(rd: &mut R, len: usize) -> Result<String, Error> {
    String::from_utf8(read_bin_data(rd, len)?).map_err(From::from)
}

fn read_bin_data<R: Read>(rd: &mut R, len: usize) -> Result<Vec<u8>, Error> {
    let mut buf = Vec::with_capacity(len);
    buf.resize(len as usize, 0u8);
    rd.read_exact(&mut buf[..]).map_err(Error::InvalidDataRead)?;

    Ok(buf)
}

fn read_ext_body<R: Read>(rd: &mut R, len: usize) -> Result<(i8, Vec<u8>), Error> {
    let ty = read_data_i8(rd)?;
    let vec = read_bin_data(rd, len)?;

    Ok((ty, vec))
}

/// Attempts to read bytes from the given reader and interpret them as a `Value`.
///
/// # Errors
///
/// This function will return `Error` on any I/O error while either reading or decoding a `Value`.
/// All instances of `ErrorKind::Interrupted` are handled by this function and the underlying
/// operation is retried.
pub fn read_value<R>(rd: &mut R) -> Result<Value, Error>
    where R: Read
{
    let val = match read_marker(rd)? {
        Marker::Null => Value::Nil,
        Marker::True => Value::Boolean(true),
        Marker::False => Value::Boolean(false),
        Marker::FixPos(val) => Value::U64(val as u64),
        Marker::FixNeg(val) => Value::I64(val as i64),
        Marker::U8 => Value::U64(read_data_u8(rd)? as u64),
        Marker::U16 => Value::U64(read_data_u16(rd)? as u64),
        Marker::U32 => Value::U64(read_data_u32(rd)? as u64),
        Marker::U64 => Value::U64(read_data_u64(rd)?),
        Marker::I8 => Value::I64(read_data_i8(rd)? as i64),
        Marker::I16 => Value::I64(read_data_i16(rd)? as i64),
        Marker::I32 => Value::I64(read_data_i32(rd)? as i64),
        Marker::I64 => Value::I64(read_data_i64(rd)?),
        Marker::F32 => Value::F32(read_data_f32(rd)?),
        Marker::F64 => Value::F64(read_data_f64(rd)?),
        Marker::FixStr(len) => {
            let res = read_str_data(rd, len as usize)?;
            Value::String(res)
        }
        Marker::Str8 => {
            let len = read_data_u8(rd)?;
            let res = read_str_data(rd, len as usize)?;
            Value::String(res)
        }
        Marker::Str16 => {
            let len = read_data_u16(rd)?;
            let res = read_str_data(rd, len as usize)?;
            Value::String(res)
        }
        Marker::Str32 => {
            let len = read_data_u32(rd)?;
            let res = read_str_data(rd, len as usize)?;
            Value::String(res)
        }
        Marker::FixArray(len) => {
            let vec = read_array_data(rd, len as usize)?;
            Value::Array(vec)
        }
        Marker::Array16 => {
            let len = read_data_u16(rd)?;
            let vec = read_array_data(rd, len as usize)?;
            Value::Array(vec)
        }
        Marker::Array32 => {
            let len = read_data_u32(rd)?;
            let vec = read_array_data(rd, len as usize)?;
            Value::Array(vec)
        }
        Marker::FixMap(len) => {
            let map = read_map_data(rd, len as usize)?;
            Value::Map(map)
        }
        Marker::Map16 => {
            let len = read_data_u16(rd)?;
            let map = read_map_data(rd, len as usize)?;
            Value::Map(map)
        }
        Marker::Map32 => {
            let len = read_data_u32(rd)?;
            let map = read_map_data(rd, len as usize)?;
            Value::Map(map)
        }
        Marker::Bin8 => {
            let len = read_data_u8(rd)?;
            let vec = read_bin_data(rd, len as usize)?;
            Value::Binary(vec)
        }
        Marker::Bin16 => {
            let len = read_data_u16(rd)?;
            let vec = read_bin_data(rd, len as usize)?;
            Value::Binary(vec)
        }
        Marker::Bin32 => {
            let len = read_data_u32(rd)?;
            let vec = read_bin_data(rd, len as usize)?;
            Value::Binary(vec)
        }
        Marker::FixExt1 => {
            let len = 1 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::FixExt2 => {
            let len = 2 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::FixExt4 => {
            let len = 4 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::FixExt8 => {
            let len = 8 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::FixExt16 => {
            let len = 16 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::Ext8 => {
            let len = read_data_u8(rd)? as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::Ext16 => {
            let len = read_data_u16(rd)? as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::Ext32 => {
            let len = read_data_u32(rd)? as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::Reserved => return Err(Error::TypeMismatch(Marker::Reserved)),
    };

    Ok(val)
}
<commit_msg>refactor: explicit matching<commit_after>use std::io::{self, ErrorKind, Read};
use std::string::FromUtf8Error;

use rmp::Marker;
use rmp::decode::{read_marker, read_data_u8, read_data_u16, read_data_u32, read_data_u64,
                  read_data_i8, read_data_i16, read_data_i32, read_data_i64, read_data_f32,
                  read_data_f64, MarkerReadError, ValueReadError};

use Value;

/// This type represents all possible errors that can occur when deserializing a value.
#[derive(Debug)]
pub enum Error {
    /// Error while reading marker byte.
    InvalidMarkerRead(io::Error),
    /// Error while reading data.
    InvalidDataRead(io::Error),
    /// Decoded value type isn't equal with the expected one.
    TypeMismatch(Marker),
    /// Failed to properly decode UTF8.
    FromUtf8Error(FromUtf8Error),
}

impl Error {
    pub fn insufficient_bytes(&self) -> bool {
        match *self {
            Error::InvalidMarkerRead(ref err) if err.kind() == ErrorKind::UnexpectedEof => true,
            Error::InvalidDataRead(ref err) if err.kind() == ErrorKind::UnexpectedEof => true,
            Error::InvalidMarkerRead(..) |
            Error::InvalidDataRead(..) |
            Error::TypeMismatch(..) |
            Error::FromUtf8Error(..) => false,
        }
    }
}

impl From<MarkerReadError> for Error {
    fn from(err: MarkerReadError) -> Error {
        Error::InvalidMarkerRead(err.0)
    }
}

impl From<ValueReadError> for Error {
    fn from(err: ValueReadError) -> Error {
        match err {
            ValueReadError::InvalidMarkerRead(err) => Error::InvalidMarkerRead(err),
            ValueReadError::InvalidDataRead(err) => Error::InvalidDataRead(err),
            ValueReadError::TypeMismatch(marker) => Error::TypeMismatch(marker),
        }
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::FromUtf8Error(err)
    }
}

fn read_array_data<R: Read>(rd: &mut R, mut len: usize) -> Result<Vec<Value>, Error> {
    let mut vec = Vec::with_capacity(len);

    while len > 0 {
        vec.push(read_value(rd)?);
        len -= 1;
    }

    Ok(vec)
}

fn read_map_data<R: Read>(rd: &mut R, mut len: usize) -> Result<Vec<(Value, Value)>, Error> {
    let mut vec = Vec::with_capacity(len);

    while len > 0 {
        vec.push((read_value(rd)?, read_value(rd)?));
        len -= 1;
    }

    Ok(vec)
}

fn read_str_data<R: Read>(rd: &mut R, len: usize) -> Result<String, Error> {
    String::from_utf8(read_bin_data(rd, len)?).map_err(From::from)
}

fn read_bin_data<R: Read>(rd: &mut R, len: usize) -> Result<Vec<u8>, Error> {
    let mut buf = Vec::with_capacity(len);
    buf.resize(len as usize, 0u8);
    rd.read_exact(&mut buf[..]).map_err(Error::InvalidDataRead)?;

    Ok(buf)
}

fn read_ext_body<R: Read>(rd: &mut R, len: usize) -> Result<(i8, Vec<u8>), Error> {
    let ty = read_data_i8(rd)?;
    let vec = read_bin_data(rd, len)?;

    Ok((ty, vec))
}

/// Attempts to read bytes from the given reader and interpret them as a `Value`.
///
/// # Errors
///
/// This function will return `Error` on any I/O error while either reading or decoding a `Value`.
/// All instances of `ErrorKind::Interrupted` are handled by this function and the underlying
/// operation is retried.
pub fn read_value<R>(rd: &mut R) -> Result<Value, Error>
    where R: Read
{
    let val = match read_marker(rd)? {
        Marker::Null => Value::Nil,
        Marker::True => Value::Boolean(true),
        Marker::False => Value::Boolean(false),
        Marker::FixPos(val) => Value::U64(val as u64),
        Marker::FixNeg(val) => Value::I64(val as i64),
        Marker::U8 => Value::U64(read_data_u8(rd)? as u64),
        Marker::U16 => Value::U64(read_data_u16(rd)? as u64),
        Marker::U32 => Value::U64(read_data_u32(rd)? as u64),
        Marker::U64 => Value::U64(read_data_u64(rd)?),
        Marker::I8 => Value::I64(read_data_i8(rd)? as i64),
        Marker::I16 => Value::I64(read_data_i16(rd)? as i64),
        Marker::I32 => Value::I64(read_data_i32(rd)? as i64),
        Marker::I64 => Value::I64(read_data_i64(rd)?),
        Marker::F32 => Value::F32(read_data_f32(rd)?),
        Marker::F64 => Value::F64(read_data_f64(rd)?),
        Marker::FixStr(len) => {
            let res = read_str_data(rd, len as usize)?;
            Value::String(res)
        }
        Marker::Str8 => {
            let len = read_data_u8(rd)?;
            let res = read_str_data(rd, len as usize)?;
            Value::String(res)
        }
        Marker::Str16 => {
            let len = read_data_u16(rd)?;
            let res = read_str_data(rd, len as usize)?;
            Value::String(res)
        }
        Marker::Str32 => {
            let len = read_data_u32(rd)?;
            let res = read_str_data(rd, len as usize)?;
            Value::String(res)
        }
        Marker::FixArray(len) => {
            let vec = read_array_data(rd, len as usize)?;
            Value::Array(vec)
        }
        Marker::Array16 => {
            let len = read_data_u16(rd)?;
            let vec = read_array_data(rd, len as usize)?;
            Value::Array(vec)
        }
        Marker::Array32 => {
            let len = read_data_u32(rd)?;
            let vec = read_array_data(rd, len as usize)?;
            Value::Array(vec)
        }
        Marker::FixMap(len) => {
            let map = read_map_data(rd, len as usize)?;
            Value::Map(map)
        }
        Marker::Map16 => {
            let len = read_data_u16(rd)?;
            let map = read_map_data(rd, len as usize)?;
            Value::Map(map)
        }
        Marker::Map32 => {
            let len = read_data_u32(rd)?;
            let map = read_map_data(rd, len as usize)?;
            Value::Map(map)
        }
        Marker::Bin8 => {
            let len = read_data_u8(rd)?;
            let vec = read_bin_data(rd, len as usize)?;
            Value::Binary(vec)
        }
        Marker::Bin16 => {
            let len = read_data_u16(rd)?;
            let vec = read_bin_data(rd, len as usize)?;
            Value::Binary(vec)
        }
        Marker::Bin32 => {
            let len = read_data_u32(rd)?;
            let vec = read_bin_data(rd, len as usize)?;
            Value::Binary(vec)
        }
        Marker::FixExt1 => {
            let len = 1 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::FixExt2 => {
            let len = 2 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::FixExt4 => {
            let len = 4 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::FixExt8 => {
            let len = 8 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::FixExt16 => {
            let len = 16 as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::Ext8 => {
            let len = read_data_u8(rd)? as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::Ext16 => {
            let len = read_data_u16(rd)? as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::Ext32 => {
            let len = read_data_u32(rd)? as usize;
            let (ty, vec) = read_ext_body(rd, len)?;
            Value::Ext(ty, vec)
        }
        Marker::Reserved => return Err(Error::TypeMismatch(Marker::Reserved)),
    };

    Ok(val)
}
<|endoftext|>


<commit_before>use iron::IronError;
use iron::prelude::*;
use iron::status;
use iron::headers::Cookie;
use hyper::header::{ContentType, SetCookie};
use cookie::Cookie as CookiePair;
use router::Router;
use serde_json;
use serde::{Serialize, Serializer};
use serde::de::{self, Visitor, Deserialize, Deserializer};

use std::ops::Deref;
use std::marker::PhantomData;
use std::io;
use std::collections::BTreeMap;
use std::fmt;

use events::Error as EventsError;
use crypto::{PublicKey, SecretKey, HexValue, FromHexError, Hash};
use serialize::ToHex;
use storage::{Result as StorageResult, Error as StorageError};

#[derive(Debug)]
pub enum ApiError {
    Service(Box<::std::error::Error + Send + Sync>),
    Storage(StorageError),
    Events(EventsError),
    FromHex(FromHexError),
    Io(::std::io::Error),
    FileNotFound(Hash),
    NotFound,
    FileTooBig,
    FileExists(Hash),
    IncorrectRequest(Box<::std::error::Error + Send + Sync>),
    Unauthorized,
}

impl ::std::fmt::Display for ApiError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl ::std::error::Error for ApiError {
    fn description(&self) -> &str {
        match *self {
            ApiError::Service(ref error) |
            ApiError::IncorrectRequest(ref error) => error.description(),
            ApiError::Storage(ref error) => error.description(),
            ApiError::Events(ref error) => error.description(),
            ApiError::FromHex(ref error) => error.description(),
            ApiError::Io(ref error) => error.description(),
            ApiError::FileNotFound(_) => "FileNotFound",
            ApiError::NotFound => "NotFound",
            ApiError::FileTooBig => "FileToBig",
            ApiError::FileExists(_) => "FileExists",
            ApiError::Unauthorized => "Unauthorized",
        }
    }
}

impl From<io::Error> for ApiError {
    fn from(e: io::Error) -> ApiError {
        ApiError::Io(e)
    }
}

impl From<StorageError> for ApiError {
    fn from(e: StorageError) -> ApiError {
        ApiError::Storage(e)
    }
}

impl From<EventsError> for ApiError {
    fn from(e: EventsError) -> ApiError {
        ApiError::Events(e)
    }
}

impl From<FromHexError> for ApiError {
    fn from(e: FromHexError) -> ApiError {
        ApiError::FromHex(e)
    }
}

impl From<ApiError> for IronError {
    fn from(e: ApiError) -> IronError {
        use std::error::Error;

        let mut body = BTreeMap::new();
        let description = format!("{:?}; description: {:?}", e, e.description());
        body.insert("type", description);
        let code = match e {
            ApiError::FileExists(hash) |
            ApiError::FileNotFound(hash) => {
                body.insert("hash", ToHex::to_hex(&hash));
                status::Conflict
            }
            _ => status::Conflict,
        };
        IronError {
            error: Box::new(e),
            response: Response::with((code, ::serde_json::to_string_pretty(&body).unwrap())),
        }
    }
}

#[derive(Clone, Debug)]
pub struct HexField<T: AsRef<[u8]> + Clone>(pub T);

impl<T> Deref for HexField<T>
    where T: AsRef<[u8]> + Clone
{
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> Serialize for HexField<T>
    where T: AsRef<[u8]> + Clone
{
    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        ser.serialize_str(&self.0.as_ref().to_hex())
    }
}

struct HexVisitor<T>
    where T: AsRef<[u8]> + HexValue
{
    _p: PhantomData<T>,
}

impl<'v, T> Visitor<'v> for HexVisitor<T>
    where T: AsRef<[u8]> + HexValue + Clone
{
    type Value = HexField<T>;

    fn expecting(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "expected hex represented string")
    }

    fn visit_str<E>(self, s: &str) -> Result<HexField<T>, E>
        where E: de::Error
    {
        let v = T::from_hex(s)
            .map_err(|_| de::Error::custom("Invalid hex"))?;
        Ok(HexField(v))
    }
}

impl<'de, T> Deserialize<'de> for HexField<T>
    where T: AsRef<[u8]> + HexValue + Clone
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_str(HexVisitor { _p: PhantomData })
    }
}

pub trait Api {
    fn load_hex_value_from_cookie<'a>(&self,
                                      request: &'a Request,
                                      key: &str)
                                      -> StorageResult<Vec<u8>> {
        if let Some(&Cookie(ref cookies)) = request.headers.get() {
            for cookie in cookies.iter() {
                if let Ok(c) = CookiePair::parse(cookie.as_str()) {
                    if c.name() == key {
                        if let Ok(value) = HexValue::from_hex(c.value()) {
                            return Ok(value);
                        }
                    }
                }
            }
        }
        Err(StorageError::new(format!("Unable to find value with given key {}", key)))
    }

    fn load_keypair_from_cookies(&self,
                                 request: &Request)
                                 -> Result<(PublicKey, SecretKey), ApiError> {
        let public_key = PublicKey::from_slice(self.load_hex_value_from_cookie(request,
                                                                               "public_key")?
                                                   .as_ref());
        let secret_key = SecretKey::from_slice(self.load_hex_value_from_cookie(request,
                                                                               "secret_key")?
                                                   .as_ref());

        let public_key = public_key.ok_or(ApiError::Unauthorized)?;
        let secret_key = secret_key.ok_or(ApiError::Unauthorized)?;
        Ok((public_key, secret_key))
    }

    fn ok_response_with_cookies(&self,
                                json: &serde_json::Value,
                                cookies: Option<Vec<String>>)
                                -> IronResult<Response> {
        let mut resp = Response::with((status::Ok, serde_json::to_string_pretty(json).unwrap()));
        resp.headers.set(ContentType::json());
        if let Some(cookies) = cookies {
            resp.headers.set(SetCookie(cookies));
        }
        Ok(resp)
    }

    fn ok_response(&self, json: &serde_json::Value) -> IronResult<Response> {
        self.ok_response_with_cookies(json, None)
    }

    fn wire<'b>(&self, router: &'b mut Router);
}

#[cfg(test)]
mod tests {
    use router::Router;
    use serde_json;

    use blockchain::Block;
    use crypto::Hash;

    use super::*;

    #[test]
    fn test_json_response_for_complex_val() {
        let str_val = "sghdkgskgskldghshgsd";
        let complex_val = Block::new(24,
                                     2,
                                     &Hash::new([24; 32]),
                                     &Hash::new([34; 32]),
                                     &Hash::new([38; 32]));
        struct SampleAPI;
        impl Api for SampleAPI {
            fn wire<'b>(&self, _: &'b mut Router) {
                return;
            }
        }
        let stub = SampleAPI;
        let result = stub.ok_response(&serde_json::to_value(str_val).unwrap());
        assert!(result.is_ok());
        let result = stub.ok_response(&serde_json::to_value(&complex_val).unwrap());
        assert!(result.is_ok());
        print!("{:?}", result);
    }
}
<commit_msg>Error body layout in response<commit_after>use iron::IronError;
use iron::prelude::*;
use iron::status;
use iron::headers::Cookie;
use hyper::header::{ContentType, SetCookie};
use cookie::Cookie as CookiePair;
use router::Router;
use serde_json;
use serde::{Serialize, Serializer};
use serde::de::{self, Visitor, Deserialize, Deserializer};

use std::ops::Deref;
use std::marker::PhantomData;
use std::io;
use std::collections::BTreeMap;
use std::fmt;

use events::Error as EventsError;
use crypto::{PublicKey, SecretKey, HexValue, FromHexError, Hash};
use serialize::ToHex;
use storage::{Result as StorageResult, Error as StorageError};

#[derive(Debug)]
pub enum ApiError {
    Service(Box<::std::error::Error + Send + Sync>),
    Storage(StorageError),
    Events(EventsError),
    FromHex(FromHexError),
    Io(::std::io::Error),
    FileNotFound(Hash),
    NotFound,
    FileTooBig,
    FileExists(Hash),
    IncorrectRequest(Box<::std::error::Error + Send + Sync>),
    Unauthorized,
}

impl ::std::fmt::Display for ApiError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl ::std::error::Error for ApiError {
    fn description(&self) -> &str {
        match *self {
            ApiError::Service(ref error) |
            ApiError::IncorrectRequest(ref error) => error.description(),
            ApiError::Storage(ref error) => error.description(),
            ApiError::Events(ref error) => error.description(),
            ApiError::FromHex(ref error) => error.description(),
            ApiError::Io(ref error) => error.description(),
            ApiError::FileNotFound(_) => "FileNotFound",
            ApiError::NotFound => "NotFound",
            ApiError::FileTooBig => "FileToBig",
            ApiError::FileExists(_) => "FileExists",
            ApiError::Unauthorized => "Unauthorized",
        }
    }
}

impl From<io::Error> for ApiError {
    fn from(e: io::Error) -> ApiError {
        ApiError::Io(e)
    }
}

impl From<StorageError> for ApiError {
    fn from(e: StorageError) -> ApiError {
        ApiError::Storage(e)
    }
}

impl From<EventsError> for ApiError {
    fn from(e: EventsError) -> ApiError {
        ApiError::Events(e)
    }
}

impl From<FromHexError> for ApiError {
    fn from(e: FromHexError) -> ApiError {
        ApiError::FromHex(e)
    }
}

impl From<ApiError> for IronError {
    fn from(e: ApiError) -> IronError {
        use std::error::Error;

        let mut body = BTreeMap::new();
        body.insert("debug", format!("{:?}", e));
        body.insert("description", e.description().to_string());
        let code = match e {
            ApiError::FileExists(hash) |
            ApiError::FileNotFound(hash) => {
                body.insert("hash", ToHex::to_hex(&hash));
                status::Conflict
            }
            _ => status::Conflict,
        };
        IronError {
            error: Box::new(e),
            response: Response::with((code, ::serde_json::to_string_pretty(&body).unwrap())),
        }
    }
}

#[derive(Clone, Debug)]
pub struct HexField<T: AsRef<[u8]> + Clone>(pub T);

impl<T> Deref for HexField<T>
    where T: AsRef<[u8]> + Clone
{
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> Serialize for HexField<T>
    where T: AsRef<[u8]> + Clone
{
    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        ser.serialize_str(&self.0.as_ref().to_hex())
    }
}

struct HexVisitor<T>
    where T: AsRef<[u8]> + HexValue
{
    _p: PhantomData<T>,
}

impl<'v, T> Visitor<'v> for HexVisitor<T>
    where T: AsRef<[u8]> + HexValue + Clone
{
    type Value = HexField<T>;

    fn expecting(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "expected hex represented string")
    }

    fn visit_str<E>(self, s: &str) -> Result<HexField<T>, E>
        where E: de::Error
    {
        let v = T::from_hex(s)
            .map_err(|_| de::Error::custom("Invalid hex"))?;
        Ok(HexField(v))
    }
}

impl<'de, T> Deserialize<'de> for HexField<T>
    where T: AsRef<[u8]> + HexValue + Clone
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_str(HexVisitor { _p: PhantomData })
    }
}

pub trait Api {
    fn load_hex_value_from_cookie<'a>(&self,
                                      request: &'a Request,
                                      key: &str)
                                      -> StorageResult<Vec<u8>> {
        if let Some(&Cookie(ref cookies)) = request.headers.get() {
            for cookie in cookies.iter() {
                if let Ok(c) = CookiePair::parse(cookie.as_str()) {
                    if c.name() == key {
                        if let Ok(value) = HexValue::from_hex(c.value()) {
                            return Ok(value);
                        }
                    }
                }
            }
        }
        Err(StorageError::new(format!("Unable to find value with given key {}", key)))
    }

    fn load_keypair_from_cookies(&self,
                                 request: &Request)
                                 -> Result<(PublicKey, SecretKey), ApiError> {
        let public_key = PublicKey::from_slice(self.load_hex_value_from_cookie(request,
                                                                               "public_key")?
                                                   .as_ref());
        let secret_key = SecretKey::from_slice(self.load_hex_value_from_cookie(request,
                                                                               "secret_key")?
                                                   .as_ref());

        let public_key = public_key.ok_or(ApiError::Unauthorized)?;
        let secret_key = secret_key.ok_or(ApiError::Unauthorized)?;
        Ok((public_key, secret_key))
    }

    fn ok_response_with_cookies(&self,
                                json: &serde_json::Value,
                                cookies: Option<Vec<String>>)
                                -> IronResult<Response> {
        let mut resp = Response::with((status::Ok, serde_json::to_string_pretty(json).unwrap()));
        resp.headers.set(ContentType::json());
        if let Some(cookies) = cookies {
            resp.headers.set(SetCookie(cookies));
        }
        Ok(resp)
    }

    fn ok_response(&self, json: &serde_json::Value) -> IronResult<Response> {
        self.ok_response_with_cookies(json, None)
    }

    fn wire<'b>(&self, router: &'b mut Router);
}

#[cfg(test)]
mod tests {
    use router::Router;
    use serde_json;

    use blockchain::Block;
    use crypto::Hash;

    use super::*;

    #[test]
    fn test_json_response_for_complex_val() {
        let str_val = "sghdkgskgskldghshgsd";
        let complex_val = Block::new(24,
                                     2,
                                     &Hash::new([24; 32]),
                                     &Hash::new([34; 32]),
                                     &Hash::new([38; 32]));
        struct SampleAPI;
        impl Api for SampleAPI {
            fn wire<'b>(&self, _: &'b mut Router) {
                return;
            }
        }
        let stub = SampleAPI;
        let result = stub.ok_response(&serde_json::to_value(str_val).unwrap());
        assert!(result.is_ok());
        let result = stub.ok_response(&serde_json::to_value(&complex_val).unwrap());
        assert!(result.is_ok());
        print!("{:?}", result);
    }
}
<|endoftext|>


<commit_before>extern mod cairo;

use azure_hl::{BackendType, CairoBackend, CoreGraphicsAcceleratedBackend, CoreGraphicsBackend};
use azure_hl::{Direct2DBackend, NoBackend, RecordingBackend, SkiaBackend};
use bindgen::{AzCreateScaledFontForNativeFont, AzReleaseScaledFont};
use cairo::{cairo_font_face_t, cairo_matrix_t, cairo_scaled_font_t};
use cairo::bindgen::{cairo_font_face_destroy, cairo_font_options_create};
use cairo::bindgen::{cairo_font_options_destroy, cairo_matrix_init_identity, cairo_matrix_scale};
use cairo::bindgen::{cairo_scaled_font_create};

#[cfg(target_os="macos")]
priv mod macos {
    extern mod core_graphics;
    extern mod core_text;
    use core_graphics::font::CGFontRef;
    use core_text::font::{CTFont, CTFontRef};
    use cairo::cairo_quartz::bindgen::cairo_quartz_font_face_create_for_cgfont;

    type NativeFont = CTFont;
}
#[cfg(target_os="macos")]
priv use macos::*;

#[cfg(target_os="linux")]
priv mod linux {
    extern mod freetype;
    use cairo::cairo_ft::bindgen::cairo_ft_font_face_create_for_ft_face;
    use freetype::freetype::{FT_Face, FT_LOAD_DEFAULT};
}
#[cfg(target_os="linux")]
priv use linux::*;

type SkTypeface = *c_void;

pub struct ScaledFont {
    azure_scaled_font: AzScaledFontRef,

    drop {
        AzReleaseScaledFont(self.azure_scaled_font);
    }
}

impl ScaledFont {
    static priv fn create_cairo_font(face: *cairo_font_face_t, size: AzFloat)
                                  -> *cairo_scaled_font_t {
        // FIXME: error handling

        let idmatrix: cairo_matrix_t = {
            xx: 0 as c_double,
            yx: 0 as c_double,
            xy: 0 as c_double,
            yy: 0 as c_double,
            x0: 0 as c_double,
            y0: 0 as c_double
        };
        cairo_matrix_init_identity(ptr::to_unsafe_ptr(&idmatrix));

        let fontmatrix = idmatrix;
        cairo_matrix_scale(ptr::to_unsafe_ptr(&fontmatrix), size as c_double, size as c_double);
        let options = cairo_font_options_create();
        let cfont = cairo_scaled_font_create(face,
                                             ptr::to_unsafe_ptr(&fontmatrix),
                                             ptr::to_unsafe_ptr(&idmatrix),
                                             options);
        cairo_font_options_destroy(options);

        return cfont;
    }

    #[cfg(target_os="linux")]
    static pub fn new(backend: BackendType, native_font: FT_Face, size: AzFloat)
        -> ScaledFont {
        let mut azure_native_font = {
            mType: 0,
            mFont: ptr::null()
        };

        match backend {
            CairoBackend => {
                azure_native_font.mType = AZ_NATIVE_FONT_CAIRO_FONT_FACE;

                unsafe {
                    let cairo_face = cairo_ft_font_face_create_for_ft_face(native_font, FT_LOAD_DEFAULT as c_int);
                    if cairo_face.is_null() { fail; }

                    let cairo_font = ScaledFont::create_cairo_font(cairo_face, size);
                    cairo_font_face_destroy(cairo_face);

                    unsafe {
                        azure_native_font.mFont = cast::transmute(cairo_font);
                    }
                }
            },
            _ => { fail ~"don't know how to make a scaled font for this backend"; }
        }

        let azure_native_font_ptr = ptr::to_unsafe_ptr(&azure_native_font);
        let azure_scaled_font = AzCreateScaledFontForNativeFont(azure_native_font_ptr, size);
        ScaledFont { azure_scaled_font: move azure_scaled_font }
    }

    /// Mac-specific function to create a font for the given backend.
    #[cfg(target_os="macos")]
    static pub fn new(backend: BackendType, native_font: &const CTFont, size: AzFloat)
                   -> ScaledFont {
        let mut azure_native_font = {
            mType: 0,
            mFont: ptr::null()
        };

        match backend {
            CoreGraphicsBackend | CoreGraphicsAcceleratedBackend | SkiaBackend => {
                azure_native_font.mType = AZ_NATIVE_FONT_MAC_FONT_FACE;

                unsafe {
                    azure_native_font.mFont = cast::transmute(native_font.copy_to_CGFont());
                }
            }
            CairoBackend => {
                azure_native_font.mType = AZ_NATIVE_FONT_CAIRO_FONT_FACE;

                // TODO(Issue #184): may want to just reuse CGFont stored in servo's QuartzFontHandle.
                // This would require creating some trait like CGFontProvider with .get_CGFont().
                let cg_font = native_font.copy_to_CGFont();
                let face = cairo_quartz_font_face_create_for_cgfont(cg_font);
                if face == ptr::null() { fail; }

                let cairo_font = ScaledFont::create_cairo_font(face, size);
                cairo_font_face_destroy(face);

                unsafe {
                    azure_native_font.mFont = cast::transmute(cairo_font);
                }
            }
            NoBackend | Direct2DBackend | RecordingBackend => {
                fail ~"don't know how to make a scaled font for this backend";
            }
        }

        let azure_native_font_ptr = ptr::to_unsafe_ptr(&azure_native_font);
        let azure_scaled_font = AzCreateScaledFontForNativeFont(azure_native_font_ptr, size);
        ScaledFont { azure_scaled_font: move azure_scaled_font }
    }
}

// FIXME: Move this stuff to a rust-skia?
// FIXME: Demangle the names!!!
#[link_args="-lskia"]
extern {
    #[cfg(target_os="macos")]
    pub fn _Z26SkCreateTypefaceFromCTFontPK8__CTFont(font: CTFontRef) -> *SkTypeface;
}

<commit_msg>Add ScaledFont.get_ref().<commit_after>extern mod cairo;

use azure_hl::{BackendType, CairoBackend, CoreGraphicsAcceleratedBackend, CoreGraphicsBackend};
use azure_hl::{Direct2DBackend, NoBackend, RecordingBackend, SkiaBackend};
use bindgen::{AzCreateScaledFontForNativeFont, AzReleaseScaledFont};
use cairo::{cairo_font_face_t, cairo_matrix_t, cairo_scaled_font_t};
use cairo::bindgen::{cairo_font_face_destroy, cairo_font_options_create};
use cairo::bindgen::{cairo_font_options_destroy, cairo_matrix_init_identity, cairo_matrix_scale};
use cairo::bindgen::{cairo_scaled_font_create};

#[cfg(target_os="macos")]
priv mod macos {
    extern mod core_graphics;
    extern mod core_text;
    use core_graphics::font::CGFontRef;
    use core_text::font::{CTFont, CTFontRef};
    use cairo::cairo_quartz::bindgen::cairo_quartz_font_face_create_for_cgfont;

    type NativeFont = CTFont;
}
#[cfg(target_os="macos")]
priv use macos::*;

#[cfg(target_os="linux")]
priv mod linux {
    extern mod freetype;
    use cairo::cairo_ft::bindgen::cairo_ft_font_face_create_for_ft_face;
    use freetype::freetype::{FT_Face, FT_LOAD_DEFAULT};
}
#[cfg(target_os="linux")]
priv use linux::*;

type SkTypeface = *c_void;

pub struct ScaledFont {
    azure_scaled_font: AzScaledFontRef,

    drop {
        AzReleaseScaledFont(self.azure_scaled_font);
    }
}

impl ScaledFont {
    pub pure fn get_ref() -> AzScaledFontRef {
        self.azure_scaled_font
    }

    static priv fn create_cairo_font(face: *cairo_font_face_t, size: AzFloat)
                                  -> *cairo_scaled_font_t {
        // FIXME: error handling

        let idmatrix: cairo_matrix_t = {
            xx: 0 as c_double,
            yx: 0 as c_double,
            xy: 0 as c_double,
            yy: 0 as c_double,
            x0: 0 as c_double,
            y0: 0 as c_double
        };
        cairo_matrix_init_identity(ptr::to_unsafe_ptr(&idmatrix));

        let fontmatrix = idmatrix;
        cairo_matrix_scale(ptr::to_unsafe_ptr(&fontmatrix), size as c_double, size as c_double);
        let options = cairo_font_options_create();
        let cfont = cairo_scaled_font_create(face,
                                             ptr::to_unsafe_ptr(&fontmatrix),
                                             ptr::to_unsafe_ptr(&idmatrix),
                                             options);
        cairo_font_options_destroy(options);

        return cfont;
    }

    #[cfg(target_os="linux")]
    static pub fn new(backend: BackendType, native_font: FT_Face, size: AzFloat)
        -> ScaledFont {
        let mut azure_native_font = {
            mType: 0,
            mFont: ptr::null()
        };

        match backend {
            CairoBackend => {
                azure_native_font.mType = AZ_NATIVE_FONT_CAIRO_FONT_FACE;

                unsafe {
                    let cairo_face = cairo_ft_font_face_create_for_ft_face(native_font, FT_LOAD_DEFAULT as c_int);
                    if cairo_face.is_null() { fail; }

                    let cairo_font = ScaledFont::create_cairo_font(cairo_face, size);
                    cairo_font_face_destroy(cairo_face);

                    unsafe {
                        azure_native_font.mFont = cast::transmute(cairo_font);
                    }
                }
            },
            _ => { fail ~"don't know how to make a scaled font for this backend"; }
        }

        let azure_native_font_ptr = ptr::to_unsafe_ptr(&azure_native_font);
        let azure_scaled_font = AzCreateScaledFontForNativeFont(azure_native_font_ptr, size);
        ScaledFont { azure_scaled_font: move azure_scaled_font }
    }

    /// Mac-specific function to create a font for the given backend.
    #[cfg(target_os="macos")]
    static pub fn new(backend: BackendType, native_font: &const CTFont, size: AzFloat)
                   -> ScaledFont {
        let mut azure_native_font = {
            mType: 0,
            mFont: ptr::null()
        };

        match backend {
            CoreGraphicsBackend | CoreGraphicsAcceleratedBackend | SkiaBackend => {
                azure_native_font.mType = AZ_NATIVE_FONT_MAC_FONT_FACE;

                unsafe {
                    azure_native_font.mFont = cast::transmute(native_font.copy_to_CGFont());
                }
            }
            CairoBackend => {
                azure_native_font.mType = AZ_NATIVE_FONT_CAIRO_FONT_FACE;

                // TODO(Issue #184): may want to just reuse CGFont stored in servo's QuartzFontHandle.
                // This would require creating some trait like CGFontProvider with .get_CGFont().
                let cg_font = native_font.copy_to_CGFont();
                let face = cairo_quartz_font_face_create_for_cgfont(cg_font);
                if face == ptr::null() { fail; }

                let cairo_font = ScaledFont::create_cairo_font(face, size);
                cairo_font_face_destroy(face);

                unsafe {
                    azure_native_font.mFont = cast::transmute(cairo_font);
                }
            }
            NoBackend | Direct2DBackend | RecordingBackend => {
                fail ~"don't know how to make a scaled font for this backend";
            }
        }

        let azure_native_font_ptr = ptr::to_unsafe_ptr(&azure_native_font);
        let azure_scaled_font = AzCreateScaledFontForNativeFont(azure_native_font_ptr, size);
        ScaledFont { azure_scaled_font: move azure_scaled_font }
    }
}

// FIXME: Move this stuff to a rust-skia?
// FIXME: Demangle the names!!!
#[link_args="-lskia"]
extern {
    #[cfg(target_os="macos")]
    pub fn _Z26SkCreateTypefaceFromCTFontPK8__CTFont(font: CTFontRef) -> *SkTypeface;
}

<|endoftext|>