<commit_before>use amq_protocol::types::*;
use amq_protocol::types::flags::*;
use amq_protocol::types::generation::*;
use amq_protocol::types::parsing::*;
use cookie_factory::*;
use nom::{be_i8,be_i16,be_i32,be_i64,be_u8,be_u16,be_u32,be_u64};

#[derive(Clone,Debug,PartialEq)]
pub enum Class {
  {{#each specs.classes as |class| ~}}
    {{camel class.name}}({{snake class.name}}::Methods),
  {{/each ~}}
  None,
}

macro_rules! call_path (
  ($i: expr, $p: path) => ($p($i))
);

named!(pub parse_class<Class>,
  switch!(be_u16,
    {{#each specs.classes as |class| ~}}
    {{class.id}} => call_path!({{snake class.name}}::parse) |
    {{/each ~}}
  _  => value!(Class::None)
  )
);

pub fn gen_class<'a>(input:(&'a mut [u8],usize), class: &Class) -> Result<(&'a mut [u8],usize),GenError> {
  match class {
    {{#each specs.classes as |class| ~}}
    &Class::{{camel class.name}}(ref {{snake class.name}}) => {
      {{snake class.name}}::gen(input, {{snake class.name}})
    },
    {{/each ~}}
    &Class::None => Err(GenError::CustomError(14)),
  }
}

{{#each specs.classes as |class|}}
  pub mod {{snake class.name}} {
    use super::Class;
    use amq_protocol::types::*;
    use amq_protocol::types::flags::*;
    use amq_protocol::types::generation::*;
    use amq_protocol::types::parsing::*;
    use cookie_factory::*;
    use nom::{be_i8,be_i16,be_i32,be_i64,be_u8,be_u16,be_u32,be_u64};

    #[derive(Clone,Debug,PartialEq)]
    pub enum Methods {
      {{#each class.methods as |method| ~}}
        {{camel method.name}}({{camel method.name}}),
      {{/each ~}}
      None,
    }

    named!(pub parse<Class>,
      switch!(be_u16,
        {{#each class.methods as |method| ~}}
        {{method.id}} => map!(call!(parse_{{snake method.name}}), |m| Class::{{camel class.name}}(m)) |
        {{/each ~}}
        _  => value!(Class::{{camel class.name}}(Methods::None))
      )
    );

    pub fn gen<'a>(input:(&'a mut [u8],usize), method: &Methods) -> Result<(&'a mut [u8],usize),GenError> {
      match method {
        {{#each class.methods as |method| ~}}
        &Methods::{{camel method.name}}(ref {{snake method.name}}) => {
          do_gen!(input,
            gen_be_u16!({{class.id}}u16) >>
            gen_{{snake method.name}}({{snake method.name}})
          )
        },
        {{/each ~}}
        &Methods::None => Err(GenError::CustomError(15)),
      }
    }

    {{#each class.methods as |method|}}
      #[derive(Clone,Debug,PartialEq)]
      pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
          {{#if argument_is_value ~}}
            pub {{snake argument.name}}: {{argument.type}},
          {{else}}
            {{#each_flag argument as |flag| ~}}
              pub {{snake flag.name}}: Boolean,
            {{/each_flag ~}}
          {{/if ~}}
        {{/each_argument ~}}
      }

      named!(parse_{{snake method.name}}<Methods>,
        do_parse!(
          {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
              {{snake argument.name}} : parse_{{snake_type argument.type}} >>
            {{else}}
              flags : apply!(parse_flags, &vec![
                {{#each_flag argument as |flag| ~}}
                  "{{flag.name}}",
                {{/each_flag ~}}
              ]) >>
            {{/if ~}}
          {{/each_argument ~}}

          (Methods::{{camel method.name}}({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
              {{#if argument_is_value ~}}
                {{snake argument.name}}: {{snake argument.name}},
              {{else}}
                {{#each_flag argument as |flag| ~}}
                  {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
                {{/each_flag ~}}
              {{/if ~}}
            {{/each_argument ~}}
          }))
        )
      );

      pub fn gen_{{snake method.name}}<'a>(input:(&'a mut [u8],usize), method: &{{camel method.name}}) -> Result<(&'a mut [u8],usize),GenError> {
        {{#if method.has_flags ~}}
          let mut flags = AMQPFlags::new();
          {{#each_argument method.arguments as |argument| ~}}
            {{#unless argument_is_value ~}}
              {{#each_flag argument as |flag| ~}}
                flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
              {{/each_flag ~}}
            {{/unless ~}}
          {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
          gen_be_u16!({{method.id}}u16)
          {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
              >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
              >> gen_flags(&flags)
            {{/if ~}}
          {{/each_argument ~}}
        )
      }
    {{/each}}
    {{#if class.has_properties ~}}
    #[derive(Clone,Debug,PartialEq)]
    pub struct Properties {
      {{#each class.properties as |property| ~}}
        {{snake property.name}}: Option<{{property.type}}>,
      {{/each ~}}
    }

    impl Default for Properties {
      fn default() -> Properties {
        Properties {
          {{#each class.properties as |property| ~}}
            {{snake property.name}}: None,
          {{/each ~}}
        }
      }
    }

    impl Properties {
      {{#each class.properties as |property| ~}}
        pub fn with_{{snake property.name}}(mut self, value: {{property.type}}) -> Properties {
          self.{{snake property.name}} = Some(value);
          self
        }
      {{/each ~}}

      pub fn bitmask(&self) -> ShortUInt {
        {{#each class.properties as |property| ~}}
          (if self.{{snake property.name}}.is_some() { {{bitmask 16 @index}} } else { 0 }) {{#unless @last ~}} + {{/unless ~}}
        {{/each ~}}
      }
    }

    named!(pub properties<Properties>, do_parse!(
      flags: parse_short_uint >>
      {{#each class.properties as |property| ~}}
        {{snake property.name}}: cond!(flags & (1 << (15 - {{@index}})) != 0, parse_{{snake_type property.type}}) >>
      {{/each ~}}
      (Properties {
        {{#each class.properties as |property| ~}}
          {{snake property.name}}: {{snake property.name}},
        {{/each ~}}
      })
    ));

    pub fn gen_properties<'a>(input:(&'a mut [u8],usize), props: &Properties) -> Result<(&'a mut [u8],usize),GenError> {
      do_gen!(input,
        gen_short_uint(&props.bitmask())
        {{#each class.properties as |property| ~}}
          >> gen_cond!(props.{{snake property.name}}.is_some(), gen_call!(gen_{{snake_type property.type}}, &props.{{snake property.name}}.as_ref().unwrap()))
        {{/each ~}}
      )
    }
    {{/if ~}}
  }
{{/each}}
<commit_msg>async: don't use bitmask helper<commit_after>use amq_protocol::types::*;
use amq_protocol::types::flags::*;
use amq_protocol::types::generation::*;
use amq_protocol::types::parsing::*;
use cookie_factory::*;
use nom::{be_i8,be_i16,be_i32,be_i64,be_u8,be_u16,be_u32,be_u64};

#[derive(Clone,Debug,PartialEq)]
pub enum Class {
  {{#each specs.classes as |class| ~}}
    {{camel class.name}}({{snake class.name}}::Methods),
  {{/each ~}}
  None,
}

macro_rules! call_path (
  ($i: expr, $p: path) => ($p($i))
);

named!(pub parse_class<Class>,
  switch!(be_u16,
    {{#each specs.classes as |class| ~}}
    {{class.id}} => call_path!({{snake class.name}}::parse) |
    {{/each ~}}
  _  => value!(Class::None)
  )
);

pub fn gen_class<'a>(input:(&'a mut [u8],usize), class: &Class) -> Result<(&'a mut [u8],usize),GenError> {
  match class {
    {{#each specs.classes as |class| ~}}
    &Class::{{camel class.name}}(ref {{snake class.name}}) => {
      {{snake class.name}}::gen(input, {{snake class.name}})
    },
    {{/each ~}}
    &Class::None => Err(GenError::CustomError(14)),
  }
}

{{#each specs.classes as |class|}}
  pub mod {{snake class.name}} {
    use super::Class;
    use amq_protocol::types::*;
    use amq_protocol::types::flags::*;
    use amq_protocol::types::generation::*;
    use amq_protocol::types::parsing::*;
    use cookie_factory::*;
    use nom::{be_i8,be_i16,be_i32,be_i64,be_u8,be_u16,be_u32,be_u64};

    #[derive(Clone,Debug,PartialEq)]
    pub enum Methods {
      {{#each class.methods as |method| ~}}
        {{camel method.name}}({{camel method.name}}),
      {{/each ~}}
      None,
    }

    named!(pub parse<Class>,
      switch!(be_u16,
        {{#each class.methods as |method| ~}}
        {{method.id}} => map!(call!(parse_{{snake method.name}}), |m| Class::{{camel class.name}}(m)) |
        {{/each ~}}
        _  => value!(Class::{{camel class.name}}(Methods::None))
      )
    );

    pub fn gen<'a>(input:(&'a mut [u8],usize), method: &Methods) -> Result<(&'a mut [u8],usize),GenError> {
      match method {
        {{#each class.methods as |method| ~}}
        &Methods::{{camel method.name}}(ref {{snake method.name}}) => {
          do_gen!(input,
            gen_be_u16!({{class.id}}u16) >>
            gen_{{snake method.name}}({{snake method.name}})
          )
        },
        {{/each ~}}
        &Methods::None => Err(GenError::CustomError(15)),
      }
    }

    {{#each class.methods as |method|}}
      #[derive(Clone,Debug,PartialEq)]
      pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
          {{#if argument_is_value ~}}
            pub {{snake argument.name}}: {{argument.type}},
          {{else}}
            {{#each_flag argument as |flag| ~}}
              pub {{snake flag.name}}: Boolean,
            {{/each_flag ~}}
          {{/if ~}}
        {{/each_argument ~}}
      }

      named!(parse_{{snake method.name}}<Methods>,
        do_parse!(
          {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
              {{snake argument.name}} : parse_{{snake_type argument.type}} >>
            {{else}}
              flags : apply!(parse_flags, &vec![
                {{#each_flag argument as |flag| ~}}
                  "{{flag.name}}",
                {{/each_flag ~}}
              ]) >>
            {{/if ~}}
          {{/each_argument ~}}

          (Methods::{{camel method.name}}({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
              {{#if argument_is_value ~}}
                {{snake argument.name}}: {{snake argument.name}},
              {{else}}
                {{#each_flag argument as |flag| ~}}
                  {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
                {{/each_flag ~}}
              {{/if ~}}
            {{/each_argument ~}}
          }))
        )
      );

      pub fn gen_{{snake method.name}}<'a>(input:(&'a mut [u8],usize), method: &{{camel method.name}}) -> Result<(&'a mut [u8],usize),GenError> {
        {{#if method.has_flags ~}}
          let mut flags = AMQPFlags::new();
          {{#each_argument method.arguments as |argument| ~}}
            {{#unless argument_is_value ~}}
              {{#each_flag argument as |flag| ~}}
                flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
              {{/each_flag ~}}
            {{/unless ~}}
          {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
          gen_be_u16!({{method.id}}u16)
          {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
              >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
              >> gen_flags(&flags)
            {{/if ~}}
          {{/each_argument ~}}
        )
      }
    {{/each}}
    {{#if class.has_properties ~}}
    #[derive(Clone,Debug,PartialEq)]
    pub struct Properties {
      {{#each class.properties as |property| ~}}
        {{snake property.name}}: Option<{{property.type}}>,
      {{/each ~}}
    }

    impl Default for Properties {
      fn default() -> Properties {
        Properties {
          {{#each class.properties as |property| ~}}
            {{snake property.name}}: None,
          {{/each ~}}
        }
      }
    }

    impl Properties {
      {{#each class.properties as |property| ~}}
        pub fn with_{{snake property.name}}(mut self, value: {{property.type}}) -> Properties {
          self.{{snake property.name}} = Some(value);
          self
        }
      {{/each ~}}

      pub fn bitmask(&self) -> ShortUInt {
        {{#each class.properties as |property| ~}}
          (if self.{{snake property.name}}.is_some() { 1 << (15 - {{@index}}) } else { 0 }) {{#unless @last ~}} + {{/unless ~}}
        {{/each ~}}
      }
    }

    named!(pub properties<Properties>, do_parse!(
      flags: parse_short_uint >>
      {{#each class.properties as |property| ~}}
        {{snake property.name}}: cond!(flags & (1 << (15 - {{@index}})) != 0, parse_{{snake_type property.type}}) >>
      {{/each ~}}
      (Properties {
        {{#each class.properties as |property| ~}}
          {{snake property.name}}: {{snake property.name}},
        {{/each ~}}
      })
    ));

    pub fn gen_properties<'a>(input:(&'a mut [u8],usize), props: &Properties) -> Result<(&'a mut [u8],usize),GenError> {
      do_gen!(input,
        gen_short_uint(&props.bitmask())
        {{#each class.properties as |property| ~}}
          >> gen_cond!(props.{{snake property.name}}.is_some(), gen_call!(gen_{{snake_type property.type}}, &props.{{snake property.name}}.as_ref().unwrap()))
        {{/each ~}}
      )
    }
    {{/if ~}}
  }
{{/each}}
<|endoftext|>


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

use std::ops::Range;

use buffer::BufferSlice;
use buffer::sys::UnsafeBuffer;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use memory::Content;

use SafeDeref;
use VulkanObject;

/// Trait for objects that represent either a buffer or a slice of a buffer.
pub unsafe trait Buffer {
    /// Object that represents a GPU access to the buffer.
    type Access: BufferAccess;

    /// Builds an object that represents a GPU access to the buffer.
    fn access(self) -> Self::Access;

    /// Returns the size of the buffer in bytes.
    fn size(&self) -> usize;

    /// Returns the length of the buffer in number of elements.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    #[inline]
    fn len(&self) -> usize where Self: TypedBuffer, Self::Content: Content {
        self.size() / <Self::Content as Content>::indiv_size()
    }

    /// Builds a `BufferSlice` object holding part of the buffer.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on some part of the buffer
    /// and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn slice<T>(self, range: Range<usize>) -> Option<BufferSlice<[T], Self>>
        where Self: Sized + TypedBuffer<Content = [T]>,
              T: 'static
    {
        BufferSlice::slice(self.into_buffer_slice(), range)
    }

    /// Builds a `BufferSlice` object holding the buffer by value.
    #[inline]
    fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self>
        where Self: Sized + TypedBuffer
    {
        BufferSlice::from_typed_buffer(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on a specific element of the
    /// buffer and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn index<T>(self, index: usize) -> Option<BufferSlice<[T], Self>>
        where Self: Sized + TypedBuffer<Content = [T]>,
              T: 'static
    {
        self.slice(index .. (index + 1))
    }
}

/// Trait for objects that represent a way for the GPU to have access to a buffer or a slice of a
/// buffer.
pub unsafe trait BufferAccess: DeviceOwned {
    /// Returns the inner information about this buffer.
    fn inner(&self) -> BufferInner;

    /// Returns the size of the buffer in bytes.
    // FIXME: don't provide by default, because can be wrong
    #[inline]
    fn size(&self) -> usize {
        self.inner().buffer.size()
    }

    /// Returns the length of the buffer in number of elements.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    #[inline]
    fn len(&self) -> usize where Self: TypedBufferAccess, Self::Content: Content {
        self.size() / <Self::Content as Content>::indiv_size()
    }

    /// Builds a `BufferSlice` object holding the buffer by reference.
    #[inline]
    fn as_buffer_slice(&self) -> BufferSlice<Self::Content, &Self>
        where Self: Sized + TypedBufferAccess
    {
        BufferSlice::from_typed_buffer_access(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer by reference.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on some part of the buffer
    /// and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn slice<T>(&self, range: Range<usize>) -> Option<BufferSlice<[T], &Self>>
        where Self: Sized + TypedBufferAccess<Content = [T]>,
              T: 'static
    {
        BufferSlice::slice(self.as_buffer_slice(), range)
    }

    /// Builds a `BufferSlice` object holding the buffer by value.
    #[inline]
    fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self>
        where Self: Sized + TypedBufferAccess
    {
        BufferSlice::from_typed_buffer_access(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer by reference.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on a specific element of the
    /// buffer and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn index<T>(&self, index: usize) -> Option<BufferSlice<[T], &Self>>
        where Self: Sized + TypedBufferAccess<Content = [T]>,
              T: 'static
    {
        self.slice(index .. (index + 1))
    }

    /// Returns true if an access to `self` (as defined by `self_offset` and `self_size`)
    /// potentially overlaps the same memory as an access to `other` (as defined by `other_offset`
    /// and `other_size`).
    ///
    /// If this function returns `false`, this means that we are allowed to access the offset/size
    /// of `self` at the same time as the offset/size of `other` without causing a data race.
    fn conflicts_buffer(&self, self_offset: usize, self_size: usize,
                        other: &BufferAccess, other_offset: usize, other_size: usize)
                        -> bool
    {
        // TODO: should we really provide a default implementation?

        debug_assert!(self_size <= self.size());

        if self.inner().buffer.internal_object() != other.inner().buffer.internal_object() {
            return false;
        }

        let self_offset = self_offset + self.inner().offset;
        let other_offset = other_offset + other.inner().offset;

        if self_offset < other_offset && self_offset + self_size <= other_offset {
            return false;
        }

        if other_offset < self_offset && other_offset + other_size <= self_offset {
            return false;
        }

        true
    }

    /// Returns true if an access to `self` (as defined by `self_offset` and `self_size`)
    /// potentially overlaps the same memory as an access to `other` (as defined by
    /// `other_first_layer`, `other_num_layers`, `other_first_mipmap` and `other_num_mipmaps`).
    ///
    /// If this function returns `false`, this means that we are allowed to access the offset/size
    /// of `self` at the same time as the offset/size of `other` without causing a data race.
    fn conflicts_image(&self, self_offset: usize, self_size: usize, other: &ImageAccess,
                       other_first_layer: u32, other_num_layers: u32, other_first_mipmap: u32,
                       other_num_mipmaps: u32) -> bool
    {
        let other_key = other.conflict_key(other_first_layer, other_num_layers, other_first_mipmap,
                                           other_num_mipmaps);
        self.conflict_key(self_offset, self_size) == other_key
    }

    /// Returns a key that uniquely identifies the range given by offset/size.
    ///
    /// Two ranges that potentially overlap in memory should return the same key.
    ///
    /// The key is shared amongst all buffers and images, which means that you can make several
    /// different buffer objects share the same memory, or make some buffer objects share memory
    /// with images, as long as they return the same key.
    ///
    /// Since it is possible to accidentally return the same key for memory ranges that don't
    /// overlap, the `conflicts_buffer` or `conflicts_image` function should always be called to
    /// verify whether they actually overlap.
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        // FIXME: remove implementation
        unimplemented!()
    }

    /// Locks the resource for usage on the GPU. Returns `false` if the lock was already acquired.
    ///
    /// This function implementation should remember that it has been called and return `false` if
    /// it gets called a second time.
    ///
    /// The only way to know that the GPU has stopped accessing a queue is when the buffer object
    /// gets destroyed. Therefore you are encouraged to use temporary objects or handles (similar
    /// to a lock) in order to represent a GPU access.
    // TODO: return Result?
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool;

    /// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
    /// simply increases the lock by one.
    ///
    /// Must only be called after `try_gpu_lock()` succeeded.
    unsafe fn increase_gpu_lock(&self);
}

/// Inner information about a buffer.
#[derive(Copy, Clone, Debug)]
pub struct BufferInner<'a> {
    /// The underlying buffer object.
    pub buffer: &'a UnsafeBuffer,
    /// The offset in bytes from the start of the underlying buffer object to the start of the
    /// buffer we're describing.
    pub offset: usize,
}

unsafe impl<T> BufferAccess for T where T: SafeDeref, T::Target: BufferAccess {
    #[inline]
    fn inner(&self) -> BufferInner {
        (**self).inner()
    }

    #[inline]
    fn size(&self) -> usize {
        (**self).size()
    }

    #[inline]
    fn conflicts_buffer(&self, self_offset: usize, self_size: usize,
                        other: &BufferAccess, other_offset: usize, other_size: usize) -> bool
    {
        (**self).conflicts_buffer(self_offset, self_size, other, other_offset, other_size)
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        (**self).conflict_key(self_offset, self_size)
    }

    #[inline]
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
        (**self).try_gpu_lock(exclusive_access, queue)
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        (**self).increase_gpu_lock()
    }
}

pub unsafe trait TypedBuffer: Buffer {
    type Content: ?Sized + 'static;
}

pub unsafe trait TypedBufferAccess: BufferAccess {
    type Content: ?Sized + 'static;
}

unsafe impl<T> TypedBufferAccess for T where T: SafeDeref, T::Target: TypedBufferAccess {
    type Content = <T::Target as TypedBufferAccess>::Content;
}
<commit_msg>Some documentation for TypedBuffer and TypedBufferAccess<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ops::Range;

use buffer::BufferSlice;
use buffer::sys::UnsafeBuffer;
use device::DeviceOwned;
use device::Queue;
use image::ImageAccess;
use memory::Content;

use SafeDeref;
use VulkanObject;

/// Trait for objects that represent either a buffer or a slice of a buffer.
///
/// See also `TypedBuffer`.
pub unsafe trait Buffer {
    /// Object that represents a GPU access to the buffer.
    type Access: BufferAccess;

    /// Builds an object that represents a GPU access to the buffer.
    fn access(self) -> Self::Access;

    /// Returns the size of the buffer in bytes.
    fn size(&self) -> usize;

    /// Returns the length of the buffer in number of elements.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    #[inline]
    fn len(&self) -> usize where Self: TypedBuffer, Self::Content: Content {
        self.size() / <Self::Content as Content>::indiv_size()
    }

    /// Builds a `BufferSlice` object holding part of the buffer.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on some part of the buffer
    /// and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn slice<T>(self, range: Range<usize>) -> Option<BufferSlice<[T], Self>>
        where Self: Sized + TypedBuffer<Content = [T]>,
              T: 'static
    {
        BufferSlice::slice(self.into_buffer_slice(), range)
    }

    /// Builds a `BufferSlice` object holding the buffer by value.
    #[inline]
    fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self>
        where Self: Sized + TypedBuffer
    {
        BufferSlice::from_typed_buffer(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on a specific element of the
    /// buffer and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn index<T>(self, index: usize) -> Option<BufferSlice<[T], Self>>
        where Self: Sized + TypedBuffer<Content = [T]>,
              T: 'static
    {
        self.slice(index .. (index + 1))
    }
}

/// Extension trait for `Buffer`. Indicates the type of the content of the buffer.
pub unsafe trait TypedBuffer: Buffer {
    /// The type of the content of the buffer.
    type Content: ?Sized + 'static;
}

/// Trait for objects that represent a way for the GPU to have access to a buffer or a slice of a
/// buffer.
///
/// See also `TypedBufferAccess`.
pub unsafe trait BufferAccess: DeviceOwned {
    /// Returns the inner information about this buffer.
    fn inner(&self) -> BufferInner;

    /// Returns the size of the buffer in bytes.
    // FIXME: don't provide by default, because can be wrong
    #[inline]
    fn size(&self) -> usize {
        self.inner().buffer.size()
    }

    /// Returns the length of the buffer in number of elements.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    #[inline]
    fn len(&self) -> usize where Self: TypedBufferAccess, Self::Content: Content {
        self.size() / <Self::Content as Content>::indiv_size()
    }

    /// Builds a `BufferSlice` object holding the buffer by reference.
    #[inline]
    fn as_buffer_slice(&self) -> BufferSlice<Self::Content, &Self>
        where Self: Sized + TypedBufferAccess
    {
        BufferSlice::from_typed_buffer_access(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer by reference.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on some part of the buffer
    /// and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn slice<T>(&self, range: Range<usize>) -> Option<BufferSlice<[T], &Self>>
        where Self: Sized + TypedBufferAccess<Content = [T]>,
              T: 'static
    {
        BufferSlice::slice(self.as_buffer_slice(), range)
    }

    /// Builds a `BufferSlice` object holding the buffer by value.
    #[inline]
    fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self>
        where Self: Sized + TypedBufferAccess
    {
        BufferSlice::from_typed_buffer_access(self)
    }

    /// Builds a `BufferSlice` object holding part of the buffer by reference.
    ///
    /// This method can only be called for buffers whose type is known to be an array.
    ///
    /// This method can be used when you want to perform an operation on a specific element of the
    /// buffer and not on the whole buffer.
    ///
    /// Returns `None` if out of range.
    #[inline]
    fn index<T>(&self, index: usize) -> Option<BufferSlice<[T], &Self>>
        where Self: Sized + TypedBufferAccess<Content = [T]>,
              T: 'static
    {
        self.slice(index .. (index + 1))
    }

    /// Returns true if an access to `self` (as defined by `self_offset` and `self_size`)
    /// potentially overlaps the same memory as an access to `other` (as defined by `other_offset`
    /// and `other_size`).
    ///
    /// If this function returns `false`, this means that we are allowed to access the offset/size
    /// of `self` at the same time as the offset/size of `other` without causing a data race.
    fn conflicts_buffer(&self, self_offset: usize, self_size: usize,
                        other: &BufferAccess, other_offset: usize, other_size: usize)
                        -> bool
    {
        // TODO: should we really provide a default implementation?

        debug_assert!(self_size <= self.size());

        if self.inner().buffer.internal_object() != other.inner().buffer.internal_object() {
            return false;
        }

        let self_offset = self_offset + self.inner().offset;
        let other_offset = other_offset + other.inner().offset;

        if self_offset < other_offset && self_offset + self_size <= other_offset {
            return false;
        }

        if other_offset < self_offset && other_offset + other_size <= self_offset {
            return false;
        }

        true
    }

    /// Returns true if an access to `self` (as defined by `self_offset` and `self_size`)
    /// potentially overlaps the same memory as an access to `other` (as defined by
    /// `other_first_layer`, `other_num_layers`, `other_first_mipmap` and `other_num_mipmaps`).
    ///
    /// If this function returns `false`, this means that we are allowed to access the offset/size
    /// of `self` at the same time as the offset/size of `other` without causing a data race.
    fn conflicts_image(&self, self_offset: usize, self_size: usize, other: &ImageAccess,
                       other_first_layer: u32, other_num_layers: u32, other_first_mipmap: u32,
                       other_num_mipmaps: u32) -> bool
    {
        let other_key = other.conflict_key(other_first_layer, other_num_layers, other_first_mipmap,
                                           other_num_mipmaps);
        self.conflict_key(self_offset, self_size) == other_key
    }

    /// Returns a key that uniquely identifies the range given by offset/size.
    ///
    /// Two ranges that potentially overlap in memory should return the same key.
    ///
    /// The key is shared amongst all buffers and images, which means that you can make several
    /// different buffer objects share the same memory, or make some buffer objects share memory
    /// with images, as long as they return the same key.
    ///
    /// Since it is possible to accidentally return the same key for memory ranges that don't
    /// overlap, the `conflicts_buffer` or `conflicts_image` function should always be called to
    /// verify whether they actually overlap.
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        // FIXME: remove implementation
        unimplemented!()
    }

    /// Locks the resource for usage on the GPU. Returns `false` if the lock was already acquired.
    ///
    /// This function implementation should remember that it has been called and return `false` if
    /// it gets called a second time.
    ///
    /// The only way to know that the GPU has stopped accessing a queue is when the buffer object
    /// gets destroyed. Therefore you are encouraged to use temporary objects or handles (similar
    /// to a lock) in order to represent a GPU access.
    // TODO: return Result?
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool;

    /// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
    /// simply increases the lock by one.
    ///
    /// Must only be called after `try_gpu_lock()` succeeded.
    unsafe fn increase_gpu_lock(&self);
}

/// Inner information about a buffer.
#[derive(Copy, Clone, Debug)]
pub struct BufferInner<'a> {
    /// The underlying buffer object.
    pub buffer: &'a UnsafeBuffer,
    /// The offset in bytes from the start of the underlying buffer object to the start of the
    /// buffer we're describing.
    pub offset: usize,
}

unsafe impl<T> BufferAccess for T where T: SafeDeref, T::Target: BufferAccess {
    #[inline]
    fn inner(&self) -> BufferInner {
        (**self).inner()
    }

    #[inline]
    fn size(&self) -> usize {
        (**self).size()
    }

    #[inline]
    fn conflicts_buffer(&self, self_offset: usize, self_size: usize,
                        other: &BufferAccess, other_offset: usize, other_size: usize) -> bool
    {
        (**self).conflicts_buffer(self_offset, self_size, other, other_offset, other_size)
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        (**self).conflict_key(self_offset, self_size)
    }

    #[inline]
    fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> bool {
        (**self).try_gpu_lock(exclusive_access, queue)
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        (**self).increase_gpu_lock()
    }
}

/// Extension trait for `BufferAccess`. Indicates the type of the content of the buffer.
pub unsafe trait TypedBufferAccess: BufferAccess {
    /// The type of the content.
    type Content: ?Sized + 'static;
}

unsafe impl<T> TypedBufferAccess for T where T: SafeDeref, T::Target: TypedBufferAccess {
    type Content = <T::Target as TypedBufferAccess>::Content;
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

include!(concat!(env!("OUT_DIR"), "/grr.rs"));

impl Into<DataBlob> for bool {

    fn into(self) -> DataBlob {
        DataBlob {
            boolean: Some(self),
            ..Default::default()
        }
    }
}

impl Into<DataBlob> for i64 {

    fn into(self) -> DataBlob {
        DataBlob {
            integer: Some(self),
            ..Default::default()
        }
    }
}

impl Into<DataBlob> for f32 {

    fn into(self) -> DataBlob {
        DataBlob {
            float: Some(self),
            ..Default::default()
        }
    }
}

impl Into<DataBlob> for Vec<u8> {

    fn into(self) -> DataBlob {
        DataBlob {
            data: Some(self),
            ..Default::default()
        }
    }
}

impl Into<DataBlob> for String {

    fn into(self) -> DataBlob {
        DataBlob {
            string: Some(self),
            ..Default::default()
        }
    }
}

/// An error type for failures of converting timestamps to microseconds.
#[derive(Clone, Debug)]
pub enum MicrosError {
    /// Attempted to convert pre-epoch system time.
    Epoch(std::time::SystemTimeError),
    /// Attempted to convert a value outside of 64-bit unsigned integer range.
    Overflow(std::num::TryFromIntError),
}

impl std::fmt::Display for MicrosError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use MicrosError::*;

        match *self {
            Epoch(ref error) => {
                write!(fmt, "pre-epoch system time: {}", error)
            }
            Overflow(ref error) => {
                write!(fmt, "system time value too big: {}", error)
            }
        }
    }
}

impl std::error::Error for MicrosError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use MicrosError::*;

        match *self {
            Epoch(ref error) => Some(error),
            Overflow(ref error) => Some(error),
        }
    }
}

impl From<std::time::SystemTimeError> for MicrosError {

    fn from(error: std::time::SystemTimeError) -> MicrosError {
        MicrosError::Epoch(error)
    }
}

impl From<std::num::TryFromIntError> for MicrosError {

    fn from(error: std::num::TryFromIntError) -> MicrosError {
        MicrosError::Overflow(error)
    }
}

/// Converts system time into epoch microseconds.
///
/// Because most GRR messages use epoch microseconds for representing timestamps
/// this function be be useful to convert from more idiomatic representations.
///
/// # Examples
///
/// ```
/// use rrg_proto::micros;
///
/// assert_eq!(micros(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn micros(time: std::time::SystemTime) -> Result<u64, MicrosError> {
    let time_micros = time.duration_since(std::time::UNIX_EPOCH)?.as_micros();
    Ok(std::convert::TryInto::try_into(time_micros)?)
}
<commit_msg>Create a helper for creating key-value objects.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

include!(concat!(env!("OUT_DIR"), "/grr.rs"));

impl Into<DataBlob> for bool {

    fn into(self) -> DataBlob {
        DataBlob {
            boolean: Some(self),
            ..Default::default()
        }
    }
}

impl Into<DataBlob> for i64 {

    fn into(self) -> DataBlob {
        DataBlob {
            integer: Some(self),
            ..Default::default()
        }
    }
}

impl Into<DataBlob> for f32 {

    fn into(self) -> DataBlob {
        DataBlob {
            float: Some(self),
            ..Default::default()
        }
    }
}

impl Into<DataBlob> for Vec<u8> {

    fn into(self) -> DataBlob {
        DataBlob {
            data: Some(self),
            ..Default::default()
        }
    }
}

impl Into<DataBlob> for String {

    fn into(self) -> DataBlob {
        DataBlob {
            string: Some(self),
            ..Default::default()
        }
    }
}

pub fn key_value<K, V>(key: K, value: V) -> KeyValue
where
    K: Into<DataBlob>,
    V: Into<DataBlob>,
{
    KeyValue {
        k: Some(key.into()),
        v: Some(value.into()),
    }
}

/// An error type for failures of converting timestamps to microseconds.
#[derive(Clone, Debug)]
pub enum MicrosError {
    /// Attempted to convert pre-epoch system time.
    Epoch(std::time::SystemTimeError),
    /// Attempted to convert a value outside of 64-bit unsigned integer range.
    Overflow(std::num::TryFromIntError),
}

impl std::fmt::Display for MicrosError {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use MicrosError::*;

        match *self {
            Epoch(ref error) => {
                write!(fmt, "pre-epoch system time: {}", error)
            }
            Overflow(ref error) => {
                write!(fmt, "system time value too big: {}", error)
            }
        }
    }
}

impl std::error::Error for MicrosError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use MicrosError::*;

        match *self {
            Epoch(ref error) => Some(error),
            Overflow(ref error) => Some(error),
        }
    }
}

impl From<std::time::SystemTimeError> for MicrosError {

    fn from(error: std::time::SystemTimeError) -> MicrosError {
        MicrosError::Epoch(error)
    }
}

impl From<std::num::TryFromIntError> for MicrosError {

    fn from(error: std::num::TryFromIntError) -> MicrosError {
        MicrosError::Overflow(error)
    }
}

/// Converts system time into epoch microseconds.
///
/// Because most GRR messages use epoch microseconds for representing timestamps
/// this function be be useful to convert from more idiomatic representations.
///
/// # Examples
///
/// ```
/// use rrg_proto::micros;
///
/// assert_eq!(micros(std::time::UNIX_EPOCH).unwrap(), 0);
/// ```
pub fn micros(time: std::time::SystemTime) -> Result<u64, MicrosError> {
    let time_micros = time.duration_since(std::time::UNIX_EPOCH)?.as_micros();
    Ok(std::convert::TryInto::try_into(time_micros)?)
}
<|endoftext|>


<commit_before>// Farbfeld filter that applies a cool blurring effect over images
// Usage: png2ff < greyscale.png | blur | ff2png > false-colored.png

use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::BufWriter;

extern crate byteorder;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};

#[derive (Clone, Copy)]
struct FfPixel {
	pub r: u16,
	pub g: u16,
	pub b: u16,
	pub a: u16,
}

#[derive (Clone, Copy)]
struct PlaneCoord {
	pub x: i32,
	pub y: i32,
}

impl PlaneCoord {
	pub fn contains (&self, x: i32, y: i32) -> bool {
		x >= 0 && x < self.x &&
		y >= 0 && y < self.y
	}

	pub fn clamp_x (&self, x: i32) -> i32 {
		return if x < 0 {
			0
		}
		else if x >= self.x {
			self.x - 1
		}
		else {
			x
		}
	}

	pub fn clamp_y (&self, y: i32) -> i32 {
		return if y < 0 {
			0
		}
		else if y >= self.y {
			self.y - 1
		}
		else {
			y
		}
	}

	pub fn clamp (&self, pc: &PlaneCoord) -> PlaneCoord {
		PlaneCoord {
			x: self.clamp_x (pc.x),
			y: self.clamp_y (pc.y),
		}
	}

	pub fn index (&self, pc: &PlaneCoord) -> i32 {
		let pc = self.clamp (pc);

		pc.y * self.x + pc.x
	}

	pub fn clamped_index (&self, pc: &PlaneCoord) -> i32 {
		self.index (&self.clamp (pc))
	}
}

struct HdrPlane {
	pub size: PlaneCoord,
	pub pixels: Vec <f64>,
}

fn read_pixel <T> (reader: &mut T) -> FfPixel where T: ReadBytesExt {
	FfPixel {
		r: reader.read_u16::<BigEndian> ().unwrap (),
		g: reader.read_u16::<BigEndian> ().unwrap (),
		b: reader.read_u16::<BigEndian> ().unwrap (),
		a: reader.read_u16::<BigEndian> ().unwrap (),
	}
}

fn write_pixel <T> (writer: &mut T, pix: &FfPixel) where T: WriteBytesExt {
	writer.write_u16::<BigEndian> (pix.r).unwrap ();
	writer.write_u16::<BigEndian> (pix.g).unwrap ();
	writer.write_u16::<BigEndian> (pix.b).unwrap ();
	writer.write_u16::<BigEndian> (pix.a).unwrap ();
}

fn pascal (n: u32) -> Vec <u32> {
	match n {
		0 => {
			vec! []
		}
		1 => {
			vec! [1]
		},
		2 => {
			vec! [1, 1]
		},
		3 => {
			vec! [1, 2, 1]
		},
		4 => {
			vec! [1, 3, 3, 1]
		}
		5 => {
			vec! [1, 4, 6, 4, 1]
		},
		_ => {
			let step = 5;
			let prev_row = pascal (n - step + 1);
			let step_row = pascal (step);

			let mut output = vec! [];
			for _ in 0..n {
				output.push (0);
			}

			for a in 0..prev_row.len () {
				for b in 0..step_row.len () {
					output [a + b] += prev_row [a] * step_row [b];
				}
			}

			output
		}
	}
}

fn blur_hor (input_plane: &HdrPlane, filter: &Vec <u32>) -> HdrPlane {
	let offset = -(filter.len () as i32 - 1) / 2;
	let filter_sum: u32 = filter.iter ().sum ();
	// Rust plz
	let filter_sum = filter_sum as f64;
	let filter_f: Vec <f64> = filter.iter ().map (|x| *x as f64 / filter_sum).collect ();

	let mut pixels = vec![];
	for y in 0..input_plane.size.y {
		for x in 0..input_plane.size.x {
			let dest_index = input_plane.size.clamped_index (&PlaneCoord {
				x: x,
				y: y
			});

			pixels.push (0.0f64);

			for i in 0..filter_f.len () {
				let src_index = input_plane.size.clamped_index (&PlaneCoord {
					x: x + i as i32 + offset,
					y: y
				});

				pixels [dest_index as usize] += filter_f [i] * input_plane.pixels [src_index as usize];
			}
		}
	}

	HdrPlane {
		size: input_plane.size,
		pixels: pixels,
	}
}

fn read_farbfeld_grey <T> (reader: &mut T) -> HdrPlane where T: ReadBytesExt {
	let mut magic = [0; 8];
	reader.read (&mut magic [..]).unwrap ();

	// TODO: Assert that magic == 'farbfeld'
	//assert_eq! (magic, &"farbfeld");

	let width = reader.read_u32::<BigEndian>().unwrap() as i32;
	let height = reader.read_u32::<BigEndian>().unwrap() as i32;

	writeln!(&mut io::stderr(), "{} x {}", width, height).expect("failed printing to stderr");

	let mut pixels = Vec::new ();

	for _ in 0 .. width * height {
		let gamma = read_pixel (reader).g as f64 / 65536.0;
		pixels.push (gamma * gamma);
	}

	HdrPlane {
		size: PlaneCoord {
			x: width,
			y: height,
		},
		pixels: pixels,
	}
}

fn write_farbfeld_plane <T> (writer: &mut T, plane: &HdrPlane) where T: WriteBytesExt
{
	writer.write ("farbfeld".as_bytes ()).expect ("printing farbfeld");

	writer.write_u32::<BigEndian> (plane.size.x as u32).unwrap ();
	writer.write_u32::<BigEndian> (plane.size.y as u32).unwrap ();

	for i in 0..plane.size.x * plane.size.y {
		let val = (plane.pixels [i as usize].sqrt () * 65535.0) as u16;

		write_pixel (writer, &FfPixel {
			r: val,
			g: val,
			b: val,
			a: 65535,
		});
	}
}

fn main () {
	// Reader
	let mut reader = BufReader::new (io::stdin ());

	let input_plane = read_farbfeld_grey (&mut reader);

	let filter = pascal (31);

	let input_plane = blur_hor (&input_plane, &filter);
	let input_plane = blur_hor (&input_plane, &filter);
	let input_plane = blur_hor (&input_plane, &filter);
	let input_plane = blur_hor (&input_plane, &filter);
	let input_plane = blur_hor (&input_plane, &filter);
	let input_plane = blur_hor (&input_plane, &filter);

	// Write
	{
		let mut writer = BufWriter::new (io::stdout ());

		write_farbfeld_plane (&mut writer, &input_plane);
	}

	writeln!(&mut io::stderr(), "filter {:?}", filter).expect("failed printing to stderr");
}
<commit_msg>Am I vaporwave yet?<commit_after>// Farbfeld filter that applies a cool blurring effect over images
// Usage: png2ff < greyscale.png | blur | ff2png > false-colored.png

use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::BufWriter;

extern crate byteorder;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};

#[derive (Clone, Copy)]
struct FfPixel {
	pub r: u16,
	pub g: u16,
	pub b: u16,
	pub a: u16,
}

#[derive (Clone, Copy, Debug, PartialEq)]
struct PlaneCoord {
	pub x: i32,
	pub y: i32,
}

impl PlaneCoord {
	pub fn contains_x (&self, x: i32) -> bool {
		x >= 0 && x < self.x
	}

	pub fn contains_y (&self, y: i32) -> bool {
		y >= 0 && y < self.y
	}

	pub fn contains (&self, x: i32, y: i32) -> bool {
		self.contains_x (x) &&
		self.contains_y (y)
	}

	pub fn clamp_x (&self, x: i32) -> i32 {
		return if x < 0 {
			0
		}
		else if x >= self.x {
			self.x - 1
		}
		else {
			x
		}
	}

	pub fn clamp_y (&self, y: i32) -> i32 {
		return if y < 0 {
			0
		}
		else if y >= self.y {
			self.y - 1
		}
		else {
			y
		}
	}

	pub fn clamp (&self, pc: &PlaneCoord) -> PlaneCoord {
		PlaneCoord {
			x: self.clamp_x (pc.x),
			y: self.clamp_y (pc.y),
		}
	}

	pub fn index (&self, pc: &PlaneCoord) -> i32 {
		let pc = self.clamp (pc);

		pc.y * self.x + pc.x
	}

	pub fn clamped_index (&self, pc: &PlaneCoord) -> i32 {
		self.index (&self.clamp (pc))
	}
}

struct HdrPlane {
	pub size: PlaneCoord,
	pub pixels: Vec <f64>,
}

impl HdrPlane {
	pub fn new (size: PlaneCoord) -> HdrPlane {
		HdrPlane {
			size: size,
			pixels: vec! [0.0; (size.x * size.y) as usize],
		}
	}
}

fn read_pixel <T> (reader: &mut T) -> FfPixel where T: ReadBytesExt {
	FfPixel {
		r: reader.read_u16::<BigEndian> ().unwrap (),
		g: reader.read_u16::<BigEndian> ().unwrap (),
		b: reader.read_u16::<BigEndian> ().unwrap (),
		a: reader.read_u16::<BigEndian> ().unwrap (),
	}
}

fn write_pixel <T> (writer: &mut T, pix: &FfPixel) where T: WriteBytesExt {
	writer.write_u16::<BigEndian> (pix.r).unwrap ();
	writer.write_u16::<BigEndian> (pix.g).unwrap ();
	writer.write_u16::<BigEndian> (pix.b).unwrap ();
	writer.write_u16::<BigEndian> (pix.a).unwrap ();
}

fn pascal (n: u32) -> Vec <u64> {
	match n {
		0 => {
			vec! []
		}
		1 => {
			vec! [1]
		},
		2 => {
			vec! [1, 1]
		},
		3 => {
			vec! [1, 2, 1]
		},
		4 => {
			vec! [1, 3, 3, 1]
		}
		5 => {
			vec! [1, 4, 6, 4, 1]
		},
		_ => {
			let step = 5;
			let prev_row = pascal (n - step + 1);
			let step_row = pascal (step);

			let mut output = vec! [];
			for _ in 0..n {
				output.push (0);
			}

			for a in 0..prev_row.len () {
				for b in 0..step_row.len () {
					output [a + b] += prev_row [a] * step_row [b];
				}
			}

			output
		}
	}
}

fn blur_hor (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	let offset = -(filter.len () as i32 - 1) / 2;
	let filter_sum: u64 = filter.iter ().sum ();
	// Rust plz
	let filter_sum = filter_sum as f64;
	let filter_f: Vec <f64> = filter.iter ().map (|x| *x as f64 / filter_sum).collect ();

	let sz = input_plane.size;

	let mut pixels = vec![];
	for y in 0..sz.y {
		for x in 0..sz.x {
			let dest_index = sz.clamped_index (&PlaneCoord {
				x: x,
				y: y
			});

			pixels.push (0.0f64);

			for src_x in sz.clamp_x (x + 0 + offset)..sz.clamp_x (x + filter_f.len () as i32 - 1 + offset)
			{
				let src_index = sz.clamped_index (&PlaneCoord {
					x: src_x,
					y: y
				});

				pixels [dest_index as usize] += filter_f [(src_x - x - offset) as usize] * input_plane.pixels [src_index as usize];
			}
		}
	}

	HdrPlane {
		size: sz,
		pixels: pixels,
	}
}

fn blur_vert (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	let offset = -(filter.len () as i32 - 1) / 2;
	let filter_sum: u64 = filter.iter ().sum ();
	// Rust plz
	let filter_sum = filter_sum as f64;
	let filter_f: Vec <f64> = filter.iter ().map (|x| *x as f64 / filter_sum).collect ();

	let sz = input_plane.size;

	let mut pixels = vec![];
	for y in 0..sz.y {
		for x in 0..sz.x {
			let dest_index = sz.clamped_index (&PlaneCoord {
				x: x,
				y: y
			});

			pixels.push (0.0f64);

			for src_y in sz.clamp_y (y + 0 + offset)..sz.clamp_y (y + filter_f.len () as i32 - 1 + offset)
			{
				let src_index = sz.clamped_index (&PlaneCoord {
					x: x,
					y: src_y,
				});

				pixels [dest_index as usize] += filter_f [(src_y - y - offset) as usize] * input_plane.pixels [src_index as usize];
			}
		}
	}

	HdrPlane {
		size: sz,
		pixels: pixels,
	}
}

fn read_farbfeld_grey <T> (reader: &mut T) -> HdrPlane where T: ReadBytesExt {
	let mut magic = [0; 8];
	reader.read (&mut magic [..]).unwrap ();

	// TODO: Assert that magic == 'farbfeld'
	//assert_eq! (magic, &"farbfeld");

	let width = reader.read_u32::<BigEndian>().unwrap() as i32;
	let height = reader.read_u32::<BigEndian>().unwrap() as i32;

	writeln!(&mut io::stderr(), "{} x {}", width, height).expect("failed printing to stderr");

	let mut pixels = vec![0.0; (width * height) as usize];

	for i in 0 .. width * height {
		let gamma = read_pixel (reader).g as f64 / 65536.0;
		pixels [i as usize] = gamma * gamma;
	}

	HdrPlane {
		size: PlaneCoord {
			x: width,
			y: height,
		},
		pixels: pixels,
	}
}

fn write_farbfeld_plane <T> (writer: &mut T, plane: &HdrPlane) where T: WriteBytesExt
{
	write_farbfeld (writer, &plane.size, plane.pixels.iter ().map (|x| {
		let val = (x.sqrt ().min (1.0) * 65535.0) as u16;

		FfPixel {
			r: val,
			g: val,
			b: val,
			a: 65535,
		}
	}));
}

fn double_to_ff (val: f64) -> u16 {
	(val.sqrt ().min (1.0) * 65535.0) as u16
}

fn write_farbfeld <T, I> (writer: &mut T, size: &PlaneCoord, pixels: I ) where T: WriteBytesExt, I: Iterator <Item = FfPixel>
{
	writer.write ("farbfeld".as_bytes ()).expect ("printing farbfeld");

	writer.write_u32::<BigEndian> (size.x as u32).unwrap ();
	writer.write_u32::<BigEndian> (size.y as u32).unwrap ();

	for pixel in pixels.take ((size.x * size.y) as usize) {
		write_pixel (writer, &pixel);
	}
}

fn blur (input_plane: &HdrPlane, filter: &Vec <u64>) -> HdrPlane {
	blur_vert (&blur_hor (input_plane, filter), filter)
}

fn blur_n (input_plane: &HdrPlane, filter: &Vec <u64>, n: u32) -> HdrPlane {
	match n {
		0 => {
			// I know this is dumb
			panic! ("Can't blur an image 0 times")
		},
		1 => {
			blur (input_plane, filter)
		},
		_ => {
			blur (&blur_n (input_plane, filter, n - 1), filter)
		},
	}
}

fn main () {
	// Reader
	let mut reader = BufReader::new (io::stdin ());

	let filter = pascal (41);

	let input_plane = read_farbfeld_grey (&mut reader);
	let blurry_10 = blur_n (&input_plane, &filter, 10);
	let blurry_20 = blur_n (&blurry_10, &filter, 10);

	let sum = [&input_plane, &blurry_20].iter ().fold (
	HdrPlane::new (input_plane.size),
	|accum, b| {
		assert_eq!(accum.size, b.size);
		HdrPlane {
			size: accum.size,
			pixels: accum.pixels.iter ().zip (b.pixels.iter ()).map (|(a, b)| a + b).collect (),
		}
	});

	let sum_iter = (0..(input_plane.size.x * input_plane.size.y) as usize).map (|i| FfPixel {
		r: double_to_ff (input_plane.pixels [i]),
		g: double_to_ff (blurry_10.pixels [i]),
		b: double_to_ff (blurry_20.pixels [i]),
		a: 65535,
	});

	// Write
	{
		let mut writer = BufWriter::new (io::stdout ());

		write_farbfeld (&mut writer, &input_plane.size, sum_iter);
	}

	writeln!(&mut io::stderr(), "filter {:?}", filter).expect("failed printing to stderr");
}
<|endoftext|>


<commit_before>//! Details of the `metadata` section of the procedural macro.

use std::convert::TryFrom;

use syn::{Expr, ExprLit, ExprPath, Ident, Lit, LitBool, LitStr, Member};

use crate::api::RawMetadata;

/// The result of processing the `metadata` section of the macro.
pub struct Metadata {
    /// The description field.
    pub description: LitStr,
    /// The method field.
    pub method: Ident,
    /// The name field.
    pub name: LitStr,
    /// The path field.
    pub path: LitStr,
    /// The rate_limited field.
    pub rate_limited: LitBool,
    /// The description field.
    pub requires_authentication: LitBool,
}

impl TryFrom<RawMetadata> for Metadata {
    type Error = syn::Error;

    fn try_from(raw: RawMetadata) -> syn::Result<Self> {
        let mut description = None;
        let mut method = None;
        let mut name = None;
        let mut path = None;
        let mut rate_limited = None;
        let mut requires_authentication = None;

        for field_value in raw.field_values {
            let identifier = match field_value.member.clone() {
                Member::Named(identifier) => identifier,
                _ => panic!("expected Member::Named"),
            };
            let expr = field_value.expr.clone();

            match &identifier.to_string()[..] {
                "description" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Str(literal),
                        ..
                    }) => {
                        description = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a string literal")),
                },
                "method" => match expr {
                    Expr::Path(ExprPath { path, .. }) if path.segments.len() == 1 => {
                        method = Some(path.segments[0].ident.clone());
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected an identifier")),
                },
                "name" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Str(literal),
                        ..
                    }) => {
                        name = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a string literal")),
                },
                "path" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Str(literal),
                        ..
                    }) => {
                        path = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a string literal")),
                },
                "rate_limited" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Bool(literal),
                        ..
                    }) => {
                        rate_limited = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a bool literal")),
                },
                "requires_authentication" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Bool(literal),
                        ..
                    }) => {
                        requires_authentication = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a bool literal")),
                },
                _ => return Err(syn::Error::new_spanned(field_value, "unexpected field")),
            }
        }

        let metadata_kw = raw.metadata_kw;
        let missing_field =
            |name| syn::Error::new_spanned(metadata_kw, format!("missing field `{}`", name));

        Ok(Self {
            description: description.ok_or_else(|| missing_field("description"))?,
            method: method.ok_or_else(|| missing_field("method"))?,
            name: name.ok_or_else(|| missing_field("name"))?,
            path: path.ok_or_else(|| missing_field("path"))?,
            rate_limited: rate_limited.ok_or_else(|| missing_field("rate_limited"))?,
            requires_authentication: requires_authentication
                .ok_or_else(|| missing_field("requires_authentication"))?,
        })
    }
}
<commit_msg>Fix 1.34.2 incompatibility from last commit<commit_after>//! Details of the `metadata` section of the procedural macro.

use std::convert::TryFrom;

use syn::{Expr, ExprLit, ExprPath, Ident, Lit, LitBool, LitStr, Member};

use crate::api::RawMetadata;

/// The result of processing the `metadata` section of the macro.
pub struct Metadata {
    /// The description field.
    pub description: LitStr,
    /// The method field.
    pub method: Ident,
    /// The name field.
    pub name: LitStr,
    /// The path field.
    pub path: LitStr,
    /// The rate_limited field.
    pub rate_limited: LitBool,
    /// The description field.
    pub requires_authentication: LitBool,
}

impl TryFrom<RawMetadata> for Metadata {
    type Error = syn::Error;

    fn try_from(raw: RawMetadata) -> syn::Result<Self> {
        let mut description = None;
        let mut method = None;
        let mut name = None;
        let mut path = None;
        let mut rate_limited = None;
        let mut requires_authentication = None;

        for field_value in raw.field_values {
            let identifier = match field_value.member.clone() {
                Member::Named(identifier) => identifier,
                _ => panic!("expected Member::Named"),
            };
            let expr = field_value.expr.clone();

            match &identifier.to_string()[..] {
                "description" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Str(literal),
                        ..
                    }) => {
                        description = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a string literal")),
                },
                "method" => match expr {
                    Expr::Path(ExprPath { ref path, .. }) if path.segments.len() == 1 => {
                        method = Some(path.segments[0].ident.clone());
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected an identifier")),
                },
                "name" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Str(literal),
                        ..
                    }) => {
                        name = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a string literal")),
                },
                "path" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Str(literal),
                        ..
                    }) => {
                        path = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a string literal")),
                },
                "rate_limited" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Bool(literal),
                        ..
                    }) => {
                        rate_limited = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a bool literal")),
                },
                "requires_authentication" => match expr {
                    Expr::Lit(ExprLit {
                        lit: Lit::Bool(literal),
                        ..
                    }) => {
                        requires_authentication = Some(literal);
                    }
                    _ => return Err(syn::Error::new_spanned(expr, "expected a bool literal")),
                },
                _ => return Err(syn::Error::new_spanned(field_value, "unexpected field")),
            }
        }

        let metadata_kw = raw.metadata_kw;
        let missing_field =
            |name| syn::Error::new_spanned(metadata_kw, format!("missing field `{}`", name));

        Ok(Self {
            description: description.ok_or_else(|| missing_field("description"))?,
            method: method.ok_or_else(|| missing_field("method"))?,
            name: name.ok_or_else(|| missing_field("name"))?,
            path: path.ok_or_else(|| missing_field("path"))?,
            rate_limited: rate_limited.ok_or_else(|| missing_field("rate_limited"))?,
            requires_authentication: requires_authentication
                .ok_or_else(|| missing_field("requires_authentication"))?,
        })
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs;
use std::io::{self, Write};
use std::mem::size_of;
use std::path::{Path, PathBuf};
use std::process;
use std::result;
use std::time::Instant;

use regex_automata::{DFA, Regex, RegexBuilder, DenseDFA, SparseDFA};

type Result<T> = result::Result<T, Box<dyn Error>>;

macro_rules! err {
    ($($tt:tt)*) => { Err(From::from(format!($($tt)*))) }
}

fn main() {
    if let Err(err) = try_main() {
        eprintln!("{}", err);
        process::exit(1);
    }
}

fn try_main() -> Result<()> {
    let mut stdout = io::stdout();

    let args = Args::parse()?;

    if args.debug {
        let start = Instant::now();
        let (debug, memory_usage) = args.debug()?;
        let compile_time = Instant::now().duration_since(start);
        writeln!(stdout, "compile time: {:?}", compile_time)?;
        writeln!(stdout, "      memory: {}", memory_usage)?;
        writeln!(stdout, "")?;
        writeln!(stdout, "{}", debug)?;
    } else {
        let start = Instant::now();
        let (finder, memory_usage) = args.finder()?;
        let compile_time = Instant::now().duration_since(start);
        writeln!(stdout, "compile time: {:?}", compile_time)?;
        writeln!(stdout, "      memory: {}", memory_usage)?;

        let start = Instant::now();
        let data = args.data()?;
        let read_time = Instant::now().duration_since(start);
        writeln!(stdout, "   read time: {:?}", read_time)?;

        let start = Instant::now();
        let matches = finder(&data);
        let match_time = Instant::now().duration_since(start);
        writeln!(stdout, "  match time: {:?}", match_time)?;

        writeln!(stdout, " match count: {}", matches)?;
    }
    Ok(())
}

#[derive(Debug)]
struct Args {
    file: PathBuf,
    pattern: String,
    debug: bool,
    sparse: bool,
    anchored: bool,
    minimize: bool,
    classes: bool,
    premultiply: bool,
    no_utf8: bool,
}

impl Args {
    fn parse() -> Result<Args> {
        use clap::{App, Arg, crate_authors, crate_version};

        let parsed = App::new("Search using regex-automata")
            .author(crate_authors!())
            .version(crate_version!())
            .max_term_width(100)
            .arg(Arg::with_name("path").required(true))
            .arg(Arg::with_name("pattern"))
            .arg(Arg::with_name("file").short("f").takes_value(true))
            .arg(Arg::with_name("debug").long("debug").short("d"))
            .arg(Arg::with_name("sparse").long("sparse").short("s"))
            .arg(Arg::with_name("anchored").long("anchored").short("a"))
            .arg(Arg::with_name("minimize").long("minimize").short("m"))
            .arg(Arg::with_name("classes").long("classes").short("c"))
            .arg(Arg::with_name("premultiply").long("premultiply").short("p"))
            .arg(Arg::with_name("no-utf8").long("no-utf8").short("u"))
            .get_matches();

        let pattern = match parsed.value_of("pattern") {
            Some(pattern) => pattern.to_string(),
            None => {
                let pattern_path = match parsed.value_of_os("file") {
                    None => return err!("no patterns found"),
                    Some(p) => Path::new(p),
                };
                let contents = fs::read_to_string(pattern_path)?;
                contents.lines().collect::<Vec<_>>().join("|")
            }
        };

        Ok(Args {
            file: PathBuf::from(parsed.value_of_os("path").unwrap()),
            pattern: pattern,
            debug: parsed.is_present("debug"),
            sparse: parsed.is_present("sparse"),
            anchored: parsed.is_present("anchored"),
            minimize: parsed.is_present("minimize"),
            classes: parsed.is_present("classes"),
            premultiply: parsed.is_present("premultiply"),
            no_utf8: parsed.is_present("no-utf8"),
        })
    }

    fn data(&self) -> Result<Vec<u8>> {
        Ok(fs::read(&self.file)?)
    }

    fn finder(&self) -> Result<(Box<dyn Fn(&[u8]) -> usize>, usize)> {
        let re = self.builder().build(&self.pattern)?;
        if self.sparse {
            let re = Regex::from_dfas(
                re.forward().to_sparse()?,
                re.reverse().to_sparse()?,
            );
            let m = re.forward().memory_usage() + re.reverse().memory_usage();
            Ok((counter(re), m))
        } else {
            let m = re.forward().memory_usage() + re.reverse().memory_usage();
            Ok((counter(re), m))
        }
    }

    fn debug(&self) -> Result<(String, usize)> {
        if self.sparse {
            let re = self.builder().build_sparse(&self.pattern)?;
            let m =
                re.forward().memory_usage()
                + re.reverse().memory_usage()
                + (2 * size_of::<SparseDFA<Vec<u8>, usize>>());
            Ok((format!("{:?}", re), m))
        } else {
            let re = self.builder().build(&self.pattern)?;
            let m =
                re.forward().memory_usage()
                + re.reverse().memory_usage()
                + (2 * size_of::<DenseDFA<Vec<usize>, usize>>());
            Ok((format!("{:?}", re), m))
        }
    }

    fn builder(&self) -> RegexBuilder {
        let mut builder = RegexBuilder::new();
        builder
            .minimize(self.minimize)
            .anchored(self.anchored)
            .byte_classes(self.classes)
            .premultiply(self.premultiply)
            .allow_invalid_utf8(self.no_utf8);
        builder
    }
}

fn counter<D: DFA + 'static>(re: Regex<D>) -> Box<dyn Fn(&[u8]) -> usize> {
    Box::new(move |bytes| re.find_iter(bytes).count())
}
<commit_msg>style: switch to rustfmt<commit_after>use std::error::Error;
use std::fs;
use std::io::{self, Write};
use std::mem::size_of;
use std::path::{Path, PathBuf};
use std::process;
use std::result;
use std::time::Instant;

use regex_automata::{DenseDFA, Regex, RegexBuilder, SparseDFA, DFA};

type Result<T> = result::Result<T, Box<dyn Error>>;

macro_rules! err {
    ($($tt:tt)*) => { Err(From::from(format!($($tt)*))) }
}

fn main() {
    if let Err(err) = try_main() {
        eprintln!("{}", err);
        process::exit(1);
    }
}

fn try_main() -> Result<()> {
    let mut stdout = io::stdout();

    let args = Args::parse()?;

    if args.debug {
        let start = Instant::now();
        let (debug, memory_usage) = args.debug()?;
        let compile_time = Instant::now().duration_since(start);
        writeln!(stdout, "compile time: {:?}", compile_time)?;
        writeln!(stdout, "      memory: {}", memory_usage)?;
        writeln!(stdout, "")?;
        writeln!(stdout, "{}", debug)?;
    } else {
        let start = Instant::now();
        let (finder, memory_usage) = args.finder()?;
        let compile_time = Instant::now().duration_since(start);
        writeln!(stdout, "compile time: {:?}", compile_time)?;
        writeln!(stdout, "      memory: {}", memory_usage)?;

        let start = Instant::now();
        let data = args.data()?;
        let read_time = Instant::now().duration_since(start);
        writeln!(stdout, "   read time: {:?}", read_time)?;

        let start = Instant::now();
        let matches = finder(&data);
        let match_time = Instant::now().duration_since(start);
        writeln!(stdout, "  match time: {:?}", match_time)?;

        writeln!(stdout, " match count: {}", matches)?;
    }
    Ok(())
}

#[derive(Debug)]
struct Args {
    file: PathBuf,
    pattern: String,
    debug: bool,
    sparse: bool,
    anchored: bool,
    minimize: bool,
    classes: bool,
    premultiply: bool,
    no_utf8: bool,
}

impl Args {
    fn parse() -> Result<Args> {
        use clap::{crate_authors, crate_version, App, Arg};

        let parsed = App::new("Search using regex-automata")
            .author(crate_authors!())
            .version(crate_version!())
            .max_term_width(100)
            .arg(Arg::with_name("path").required(true))
            .arg(Arg::with_name("pattern"))
            .arg(Arg::with_name("file").short("f").takes_value(true))
            .arg(Arg::with_name("debug").long("debug").short("d"))
            .arg(Arg::with_name("sparse").long("sparse").short("s"))
            .arg(Arg::with_name("anchored").long("anchored").short("a"))
            .arg(Arg::with_name("minimize").long("minimize").short("m"))
            .arg(Arg::with_name("classes").long("classes").short("c"))
            .arg(Arg::with_name("premultiply").long("premultiply").short("p"))
            .arg(Arg::with_name("no-utf8").long("no-utf8").short("u"))
            .get_matches();

        let pattern = match parsed.value_of("pattern") {
            Some(pattern) => pattern.to_string(),
            None => {
                let pattern_path = match parsed.value_of_os("file") {
                    None => return err!("no patterns found"),
                    Some(p) => Path::new(p),
                };
                let contents = fs::read_to_string(pattern_path)?;
                contents.lines().collect::<Vec<_>>().join("|")
            }
        };

        Ok(Args {
            file: PathBuf::from(parsed.value_of_os("path").unwrap()),
            pattern: pattern,
            debug: parsed.is_present("debug"),
            sparse: parsed.is_present("sparse"),
            anchored: parsed.is_present("anchored"),
            minimize: parsed.is_present("minimize"),
            classes: parsed.is_present("classes"),
            premultiply: parsed.is_present("premultiply"),
            no_utf8: parsed.is_present("no-utf8"),
        })
    }

    fn data(&self) -> Result<Vec<u8>> {
        Ok(fs::read(&self.file)?)
    }

    fn finder(&self) -> Result<(Box<dyn Fn(&[u8]) -> usize>, usize)> {
        let re = self.builder().build(&self.pattern)?;
        if self.sparse {
            let re = Regex::from_dfas(
                re.forward().to_sparse()?,
                re.reverse().to_sparse()?,
            );
            let m = re.forward().memory_usage() + re.reverse().memory_usage();
            Ok((counter(re), m))
        } else {
            let m = re.forward().memory_usage() + re.reverse().memory_usage();
            Ok((counter(re), m))
        }
    }

    fn debug(&self) -> Result<(String, usize)> {
        if self.sparse {
            let re = self.builder().build_sparse(&self.pattern)?;
            let m = re.forward().memory_usage()
                + re.reverse().memory_usage()
                + (2 * size_of::<SparseDFA<Vec<u8>, usize>>());
            Ok((format!("{:?}", re), m))
        } else {
            let re = self.builder().build(&self.pattern)?;
            let m = re.forward().memory_usage()
                + re.reverse().memory_usage()
                + (2 * size_of::<DenseDFA<Vec<usize>, usize>>());
            Ok((format!("{:?}", re), m))
        }
    }

    fn builder(&self) -> RegexBuilder {
        let mut builder = RegexBuilder::new();
        builder
            .minimize(self.minimize)
            .anchored(self.anchored)
            .byte_classes(self.classes)
            .premultiply(self.premultiply)
            .allow_invalid_utf8(self.no_utf8);
        builder
    }
}

fn counter<D: DFA + 'static>(re: Regex<D>) -> Box<dyn Fn(&[u8]) -> usize> {
    Box::new(move |bytes| re.find_iter(bytes).count())
}
<|endoftext|>


<commit_before>use std::u8;
use std::char::from_u32;
use std::char;
use std::u32;

// TODO: Fix this when the following issue is fixed:
//   https://github.com/mozilla/rust/issues/4334
static X_U8: u8 = 'x' as u8;
static A_U8: u8 = 'a' as u8;
static B_U8: u8 = 'b' as u8;
static F_U8: u8 = 'f' as u8;
static N_U8: u8 = 'n' as u8;
static R_U8: u8 = 'r' as u8;
static T_U8: u8 = 't' as u8;
static U_U8: u8 = 'u' as u8;
static V_U8: u8 = 'v' as u8;
static ZERO_U8: u8 = '0' as u8;
static SINGLE_QUOTE_U8: u8 = '\'' as u8;
static DOUBLE_QUOTE_U8: u8 = '"' as u8;
static NEWLINE_U8: u8 = '\n' as u8;
static SLASH_U8: u8 = '\\' as u8;

pub fn unescape( input: &[u8] ) -> ~[u8] {
  let mut final_bytes: ~[u8] = ~[];
  let mut index = 0;
  loop {
    // TODO: support \u12345678, not just \u1234
    match input.slice_from( index ) {
      [ SLASH_U8, U_U8, c1, c2, c3, c4, .. ]
          if isHex( c1 ) && isHex( c2 ) && isHex( c3 ) && isHex( c4 ) => {
        final_bytes = addFourBytesAsCodepoint( final_bytes, [c1, c2, c3, c4] );
        index += 6;
      }
      [ SLASH_U8, X_U8, c1, c2, .. ]
          if isHex( c1 ) && isHex( c2 ) => {
        final_bytes = addTwoBytesAsHex( final_bytes, [c1, c2] );
        index += 4;
      }
      [ SLASH_U8, c1, c2, c3, .. ]
          if isOctal( c1 ) && isOctal( c2 ) && isOctal( c3 ) => {
        final_bytes = addThreeBytesAsOctal( final_bytes, [c1, c2, c3] );
        index += 4;
      }
      [ SLASH_U8, c, .. ] => {
        final_bytes = addEscapedByte( final_bytes, c );
        index += 2;
      }
      [ c, .. ] => {
        final_bytes.push( c );
        index += 1;
      }
      [] => break,
    }
  }

  return final_bytes;
}

fn isOctal( byte: u8 ) -> bool {
  char::is_digit_radix( byte as char, 8 )
}

fn isHex( byte: u8 ) -> bool {
  char::is_digit_radix( byte as char, 16 )
}

fn addFourBytesAsCodepoint( mut input: ~[u8], bytes: [u8, ..4] ) -> ~[u8] {
  match u32::parse_bytes( bytes, 16 ) {
    Some( x ) => match from_u32( x ) {
      Some( character ) => {
        let utf8chars: &mut [u8] = [0, ..4];
        let num_written = character.encode_utf8( utf8chars );
        for i in range( 0, num_written ) {
          input.push( *utf8chars.get( i ).unwrap() );
        }
      },
      _ => fail!( "Invalid unicode code point: {}", x )
    },
    _ => fail!( "Invalid unicode escape sequence: \\\\u{}{}{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap(),
                bytes.get( 2 ).unwrap(),
                bytes.get( 3 ).unwrap() )
  }
  input
}

fn addTwoBytesAsHex( mut input: ~[u8], bytes: [u8, ..2] ) -> ~[u8] {
  match u8::parse_bytes( bytes, 16 ) {
    Some( byte ) => input.push( byte ),
    _ => fail!( "Invalid hex escape sequence: \\\\x{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap() )
  }
  input
}

fn addThreeBytesAsOctal( mut input: ~[u8], bytes: [u8, ..3] ) -> ~[u8] {
  match u8::parse_bytes( bytes, 8 ) {
    Some( byte ) => input.push( byte ),
    _ => fail!( "Invalid octal escape sequence: \\\\{}{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap(),
                bytes.get( 2 ).unwrap() )
  }
  input
}

fn addEscapedByte( mut input: ~[u8], byte: u8 ) -> ~[u8] {
  let unescaped_char = match byte {
    A_U8            => Some( '\x07' as u8 ),
    B_U8            => Some( '\x08' as u8 ),
    F_U8            => Some( '\x0c' as u8 ),
    N_U8            => Some( '\n' as u8   ),
    R_U8            => Some( '\r' as u8   ),
    T_U8            => Some( '\t' as u8   ),
    V_U8            => Some( '\x0b' as u8 ),
    ZERO_U8         => Some( '\0' as u8   ),
    SINGLE_QUOTE_U8 => Some( '\'' as u8   ),
    DOUBLE_QUOTE_U8 => Some( '"' as u8    ),
    SLASH_U8        => Some( '\\' as u8   ),
    _               => None
  };

  match unescaped_char {
    Some( x ) => input.push( x ),
    None => {
      input.push( '\\' as u8 );
      input.push( byte )
    }
  };
  input
}

#[cfg(test)]
mod tests {
  use super::unescape;
  use parser::test_utils::bytes;

  #[test]
  fn unescape_Nothing() {
    assert_eq!( unescape( bytes( "foobar" ) ), bytes( "foobar" ) );
    assert_eq!( unescape( bytes( "123" )    ), bytes( "123" )    );
    assert_eq!( unescape( bytes( "葉" )     ), bytes( "葉" )     );
    assert_eq!( unescape( bytes( "a葉8" )   ), bytes( "a葉8" )   );
  }

  #[test]
  fn unescape_LooksLikeEscapeButNot() {
    assert_eq!( unescape( bytes( "\\z" ) ), bytes( "\\z" ) );
    assert_eq!( unescape( bytes( "a\\zg" ) ), bytes( "a\\zg" ) );
  }

  #[test]
  fn unescape_SingleCharEscapeCodes() {
    assert_eq!( unescape( bytes( "\\a" )  ), bytes( "\x07" ) );
    assert_eq!( unescape( bytes( "\\b" )  ), bytes( "\x08" ) );
    assert_eq!( unescape( bytes( "\\f" )  ), bytes( "\x0c" ) );
    assert_eq!( unescape( bytes( "\\n" )  ), bytes( "\n" )   );
    assert_eq!( unescape( bytes( "\\r" )  ), bytes( "\r" )   );
    assert_eq!( unescape( bytes( "\\t" )  ), bytes( "\t" )   );
    assert_eq!( unescape( bytes( "\\v" )  ), bytes( "\x0b" ) );
    assert_eq!( unescape( bytes( "\\0" )  ), bytes( "\0" )   );
    assert_eq!( unescape( bytes( "\\'" )  ), bytes( "\'" )   );
    assert_eq!( unescape( bytes( "\\\"" ) ), bytes( "\"" )   );
    assert_eq!( unescape( bytes( "\\\\" ) ), bytes( "\\" )   );
  }

  #[test]
  fn unescape_MultipleSingleCharEscapeCodes() {
    assert_eq!( unescape( bytes( "\\r\\n" ) ), bytes( "\r\n" ) );
    assert_eq!( unescape( bytes( "\\\\\\\\" ) ), bytes( "\\\\" ) );
  }

  #[test]
  fn unescape_HexEscape() {
    assert_eq!( unescape( bytes( "\\x4E" ) ), bytes( "N" ) );
    assert_eq!( unescape( bytes( "\\x4e" ) ), bytes( "N" ) );
    assert_eq!( unescape( bytes( "\\x00\\x01" ) ), ~[0, 1] );
  }

  #[test]
  fn unescape_HexEscape_Bad() {
    assert_eq!( unescape( bytes( "\\x" ) ), bytes( "\\x" ) );
    assert_eq!( unescape( bytes( "\\xgg" ) ), bytes( "\\xgg" ) );
  }

  #[test]
  fn unescape_UnicodeEscape() {
    assert_eq!( unescape( bytes( "\\u0106" ) ), bytes( "Ć" ) );
    assert_eq!( unescape( bytes( "\\u0106\\u04E8" ) ), bytes( "ĆӨ" ) );
    assert_eq!( unescape( bytes( "\\u81EA\\u7531" ) ), bytes( "自由" ) );
  }

  #[test]
  fn unescape_UnicodeEscape_Bad() {
    assert_eq!( unescape( bytes( "\\u" ) ), bytes( "\\u" ) );
    assert_eq!( unescape( bytes( "\\u01x" ) ), bytes( "\\u01x" ) );
  }

  #[test]
  fn unescape_OctalEscape() {
    assert_eq!( unescape( bytes( "\\001" ) ), ~[1] );
    assert_eq!( unescape( bytes( "\\157" ) ), ~[111] );
  }
}
<commit_msg>Adding some comments for 'unescape'<commit_after>use std::u8;
use std::char::from_u32;
use std::char;
use std::u32;

// TODO: Fix this when the following issue is fixed:
//   https://github.com/mozilla/rust/issues/4334
static X_U8: u8 = 'x' as u8;
static A_U8: u8 = 'a' as u8;
static B_U8: u8 = 'b' as u8;
static F_U8: u8 = 'f' as u8;
static N_U8: u8 = 'n' as u8;
static R_U8: u8 = 'r' as u8;
static T_U8: u8 = 't' as u8;
static U_U8: u8 = 'u' as u8;
static V_U8: u8 = 'v' as u8;
static ZERO_U8: u8 = '0' as u8;
static SINGLE_QUOTE_U8: u8 = '\'' as u8;
static DOUBLE_QUOTE_U8: u8 = '"' as u8;
static NEWLINE_U8: u8 = '\n' as u8;
static SLASH_U8: u8 = '\\' as u8;

// See:
//   http://en.wikipedia.org/wiki/Escape_sequences_in_C
//   http://en.cppreference.com/w/cpp/language/escape
// No question mark escape supported because there are no trigraphs in PEG.
pub fn unescape( input: &[u8] ) -> ~[u8] {
  let mut final_bytes: ~[u8] = ~[];
  let mut index = 0;
  loop {
    // TODO: support \u12345678, not just \u1234
    match input.slice_from( index ) {
      [ SLASH_U8, U_U8, c1, c2, c3, c4, .. ]
          if isHex( c1 ) && isHex( c2 ) && isHex( c3 ) && isHex( c4 ) => {
        final_bytes = addFourBytesAsCodepoint( final_bytes, [c1, c2, c3, c4] );
        index += 6;
      }
      [ SLASH_U8, X_U8, c1, c2, .. ]
          if isHex( c1 ) && isHex( c2 ) => {
        final_bytes = addTwoBytesAsHex( final_bytes, [c1, c2] );
        index += 4;
      }
      [ SLASH_U8, c1, c2, c3, .. ]
          if isOctal( c1 ) && isOctal( c2 ) && isOctal( c3 ) => {
        final_bytes = addThreeBytesAsOctal( final_bytes, [c1, c2, c3] );
        index += 4;
      }
      [ SLASH_U8, c, .. ] => {
        final_bytes = addEscapedByte( final_bytes, c );
        index += 2;
      }
      [ c, .. ] => {
        final_bytes.push( c );
        index += 1;
      }
      [] => break,
    }
  }

  return final_bytes;
}

fn isOctal( byte: u8 ) -> bool {
  char::is_digit_radix( byte as char, 8 )
}

fn isHex( byte: u8 ) -> bool {
  char::is_digit_radix( byte as char, 16 )
}

fn addFourBytesAsCodepoint( mut input: ~[u8], bytes: [u8, ..4] ) -> ~[u8] {
  match u32::parse_bytes( bytes, 16 ) {
    Some( x ) => match from_u32( x ) {
      Some( character ) => {
        let utf8chars: &mut [u8] = [0, ..4];
        let num_written = character.encode_utf8( utf8chars );
        for i in range( 0, num_written ) {
          input.push( *utf8chars.get( i ).unwrap() );
        }
      },
      _ => fail!( "Invalid unicode code point: {}", x )
    },
    _ => fail!( "Invalid unicode escape sequence: \\\\u{}{}{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap(),
                bytes.get( 2 ).unwrap(),
                bytes.get( 3 ).unwrap() )
  }
  input
}

fn addTwoBytesAsHex( mut input: ~[u8], bytes: [u8, ..2] ) -> ~[u8] {
  match u8::parse_bytes( bytes, 16 ) {
    Some( byte ) => input.push( byte ),
    _ => fail!( "Invalid hex escape sequence: \\\\x{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap() )
  }
  input
}

fn addThreeBytesAsOctal( mut input: ~[u8], bytes: [u8, ..3] ) -> ~[u8] {
  match u8::parse_bytes( bytes, 8 ) {
    Some( byte ) => input.push( byte ),
    _ => fail!( "Invalid octal escape sequence: \\\\{}{}{}",
                bytes.get( 0 ).unwrap(),
                bytes.get( 1 ).unwrap(),
                bytes.get( 2 ).unwrap() )
  }
  input
}

fn addEscapedByte( mut input: ~[u8], byte: u8 ) -> ~[u8] {
  let unescaped_char = match byte {
    A_U8            => Some( '\x07' as u8 ),
    B_U8            => Some( '\x08' as u8 ),
    F_U8            => Some( '\x0c' as u8 ),
    N_U8            => Some( '\n' as u8   ),
    R_U8            => Some( '\r' as u8   ),
    T_U8            => Some( '\t' as u8   ),
    V_U8            => Some( '\x0b' as u8 ),
    ZERO_U8         => Some( '\0' as u8   ),
    SINGLE_QUOTE_U8 => Some( '\'' as u8   ),
    DOUBLE_QUOTE_U8 => Some( '"' as u8    ),
    SLASH_U8        => Some( '\\' as u8   ),
    _               => None
  };

  match unescaped_char {
    Some( x ) => input.push( x ),
    None => {
      input.push( '\\' as u8 );
      input.push( byte )
    }
  };
  input
}

#[cfg(test)]
mod tests {
  use super::unescape;
  use parser::test_utils::bytes;

  #[test]
  fn unescape_Nothing() {
    assert_eq!( unescape( bytes( "foobar" ) ), bytes( "foobar" ) );
    assert_eq!( unescape( bytes( "123" )    ), bytes( "123" )    );
    assert_eq!( unescape( bytes( "葉" )     ), bytes( "葉" )     );
    assert_eq!( unescape( bytes( "a葉8" )   ), bytes( "a葉8" )   );
  }

  #[test]
  fn unescape_LooksLikeEscapeButNot() {
    assert_eq!( unescape( bytes( "\\z" ) ), bytes( "\\z" ) );
    assert_eq!( unescape( bytes( "a\\zg" ) ), bytes( "a\\zg" ) );
  }

  #[test]
  fn unescape_SingleCharEscapeCodes() {
    assert_eq!( unescape( bytes( "\\a" )  ), bytes( "\x07" ) );
    assert_eq!( unescape( bytes( "\\b" )  ), bytes( "\x08" ) );
    assert_eq!( unescape( bytes( "\\f" )  ), bytes( "\x0c" ) );
    assert_eq!( unescape( bytes( "\\n" )  ), bytes( "\n" )   );
    assert_eq!( unescape( bytes( "\\r" )  ), bytes( "\r" )   );
    assert_eq!( unescape( bytes( "\\t" )  ), bytes( "\t" )   );
    assert_eq!( unescape( bytes( "\\v" )  ), bytes( "\x0b" ) );
    assert_eq!( unescape( bytes( "\\0" )  ), bytes( "\0" )   );
    assert_eq!( unescape( bytes( "\\'" )  ), bytes( "\'" )   );
    assert_eq!( unescape( bytes( "\\\"" ) ), bytes( "\"" )   );
    assert_eq!( unescape( bytes( "\\\\" ) ), bytes( "\\" )   );
  }

  #[test]
  fn unescape_MultipleSingleCharEscapeCodes() {
    assert_eq!( unescape( bytes( "\\r\\n" ) ), bytes( "\r\n" ) );
    assert_eq!( unescape( bytes( "\\\\\\\\" ) ), bytes( "\\\\" ) );
  }

  #[test]
  fn unescape_HexEscape() {
    assert_eq!( unescape( bytes( "\\x4E" ) ), bytes( "N" ) );
    assert_eq!( unescape( bytes( "\\x4e" ) ), bytes( "N" ) );
    assert_eq!( unescape( bytes( "\\x00\\x01" ) ), ~[0, 1] );
  }

  #[test]
  fn unescape_HexEscape_Bad() {
    assert_eq!( unescape( bytes( "\\x" ) ), bytes( "\\x" ) );
    assert_eq!( unescape( bytes( "\\xgg" ) ), bytes( "\\xgg" ) );
  }

  #[test]
  fn unescape_UnicodeEscape() {
    assert_eq!( unescape( bytes( "\\u0106" ) ), bytes( "Ć" ) );
    assert_eq!( unescape( bytes( "\\u0106\\u04E8" ) ), bytes( "ĆӨ" ) );
    assert_eq!( unescape( bytes( "\\u81EA\\u7531" ) ), bytes( "自由" ) );
  }

  #[test]
  fn unescape_UnicodeEscape_Bad() {
    assert_eq!( unescape( bytes( "\\u" ) ), bytes( "\\u" ) );
    assert_eq!( unescape( bytes( "\\u01x" ) ), bytes( "\\u01x" ) );
  }

  #[test]
  fn unescape_OctalEscape() {
    assert_eq!( unescape( bytes( "\\001" ) ), ~[1] );
    assert_eq!( unescape( bytes( "\\157" ) ), ~[111] );
  }
}
<|endoftext|>


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

#[derive(Debug)]
pub struct Stack<T: Clone> {
    ops: Vec<StackOp<T>>,
    cache: Vec<T>,
    snapshots: Vec<usize>
}

impl<T: Clone> Stack<T> {
    pub fn new() -> Self {
        Stack {
            ops: vec![],
            cache: vec![],
            snapshots: vec![]
        }
    }

    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }

    pub fn peek(&self) -> Option<&T> {
        self.cache.last()
    }

    pub fn push(&mut self, elem: T) {
        self.ops.push(StackOp::Push(elem.clone()));
        self.cache.push(elem);
    }

    pub fn pop(&mut self) -> Option<T> {
        self.ops.push(StackOp::Pop);
        self.cache.pop()
    }

    pub fn clear(&mut self) {
        self.ops.push(StackOp::Clear);
        self.cache.clear();
    }

    pub fn snapshot(&mut self) {
        self.snapshots.push(self.ops.len());
    }

    pub fn backtrack(&mut self) {
        match self.snapshots.pop() {
            Some(index) => {
                self.ops.truncate(index);
                self.recache();
            }
            None => {}
        }
    }

    fn recache(&mut self) {
        self.cache.clear();
        for op in self.ops.iter() {
            match op {
                &StackOp::Push(ref elem) => {
                    self.cache.push(elem.clone());
                },
                &StackOp::Pop => {
                    self.cache.pop();
                },
                &StackOp::Clear => {
                    self.cache.clear();
                }
            }
        }
    }
}

#[derive(Debug)]
enum StackOp<T> {
    Push(T),
    Pop,
    Clear
}

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

    #[test]
    fn stack_ops() {
        let mut stack = Stack::new();

        // []
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // [0]
        stack.push(0);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 1]
        stack.push(1);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&1));

        // [0]
        assert_eq!(stack.pop(), Some(1));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 2]
        stack.push(2);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // [0, 2, 3]
        stack.push(3);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&3));

        // Take a snapshot of the current stack
        // [0, 2, 3]
        stack.snapshot();

        // [0, 2]
        assert_eq!(stack.pop(), Some(3));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // Take a snapshot of the current stack
        // [0, 2]
        stack.snapshot();

        // [0]
        assert_eq!(stack.pop(), Some(2));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // []
        assert_eq!(stack.pop(), Some(0));
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2]
        stack.backtrack();
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2, 3]
        stack.backtrack();
        assert_eq!(stack.pop(), Some(3));
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);
    }
}
<commit_msg>add docstrings to the new Stack class<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

/// Implementation of a `Stack` which maintains an log of `StackOp`s in order to rewind the stack
/// to a previous state.
#[derive(Debug)]
pub struct Stack<T: Clone> {
    ops: Vec<StackOp<T>>,
    cache: Vec<T>,
    snapshots: Vec<usize>
}

impl<T: Clone> Stack<T> {
    /// Creates a new `Stack`.
    pub fn new() -> Self {
        Stack {
            ops: vec![],
            cache: vec![],
            snapshots: vec![]
        }
    }

    /// Returns `true` if the stack is currently empty.
    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }

    /// Returns the top-most `&T` in the `Stack`.
    pub fn peek(&self) -> Option<&T> {
        self.cache.last()
    }

    /// Pushes a `T` onto the `Stack`.
    pub fn push(&mut self, elem: T) {
        self.ops.push(StackOp::Push(elem.clone()));
        self.cache.push(elem);
    }

    /// Pops the top-most `T` from the `Stack`.
    pub fn pop(&mut self) -> Option<T> {
        self.ops.push(StackOp::Pop);
        self.cache.pop()
    }

    /// Clears all the values from the `Stack`.
    pub fn clear(&mut self) {
        self.ops.push(StackOp::Clear);
        self.cache.clear();
    }

    /// Takes a snapshot of the current `Stack`.
    pub fn snapshot(&mut self) {
        self.snapshots.push(self.ops.len());
    }

    /// Rewinds the `Stack` to the most `snapshot()`. If no `snapshot()` has been taken, this
    /// function will do nothing.
    pub fn backtrack(&mut self) {
        match self.snapshots.pop() {
            Some(index) => {
                self.ops.truncate(index);
                self.recache();
            }
            None => {}
        }
    }

    // Rebuilds the internal cache based on the previous operations stored.
    fn recache(&mut self) {
        self.cache.clear();
        for op in self.ops.iter() {
            match op {
                &StackOp::Push(ref elem) => {
                    self.cache.push(elem.clone());
                },
                &StackOp::Pop => {
                    self.cache.pop();
                },
                &StackOp::Clear => {
                    self.cache.clear();
                }
            }
        }
    }
}

#[derive(Debug)]
enum StackOp<T> {
    Push(T),
    Pop,
    Clear
}

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

    #[test]
    fn stack_ops() {
        let mut stack = Stack::new();

        // []
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // [0]
        stack.push(0);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 1]
        stack.push(1);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&1));

        // [0]
        assert_eq!(stack.pop(), Some(1));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 2]
        stack.push(2);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // [0, 2, 3]
        stack.push(3);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&3));

        // Take a snapshot of the current stack
        // [0, 2, 3]
        stack.snapshot();

        // [0, 2]
        assert_eq!(stack.pop(), Some(3));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // Take a snapshot of the current stack
        // [0, 2]
        stack.snapshot();

        // [0]
        assert_eq!(stack.pop(), Some(2));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // []
        assert_eq!(stack.pop(), Some(0));
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2]
        stack.backtrack();
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2, 3]
        stack.backtrack();
        assert_eq!(stack.pop(), Some(3));
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);
    }
}
<|endoftext|>


<commit_before>use screen::*;
use piston_window;

pub struct MainMenuScreen;

impl Screen for MainMenuScreen {
    fn on_input(&mut self, input: &piston_window::Input) -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new())));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0., 0., 1., 1.0], graphics);
        });
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
    }
}
<commit_msg>'new' method for MainMenuScreen<commit_after>use screen::*;
use piston_window;

pub struct MainMenuScreen;

impl MainMenuScreen {
    pub fn new() -> MainMenuScreen {
        MainMenuScreen
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self, input: &piston_window::Input) -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new())));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0., 0., 1., 1.0], graphics);
        });
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
    }
}
<|endoftext|>