<commit_before>//! Bit level parsers and combinators
//!
//! Bit parsing is handled by tweaking the input in most macros.
//! In byte level parsing, the input is generally a `&[u8]` passed from combinator
//! to combinator until the slices are manipulated.
//!
//! Bit parsers take a `(&[u8], usize)` as input. The first part of the tuple is an byte slice,
//! the second part is a bit offset in the first byte of the slice.
//!
//! By passing a pair like this, we can leverage most of the combinators, and avoid
//! transforming the whole slice to a vector of booleans. This should make it easy
//! to see a byte slice as a bit stream, and parse code points of arbitrary bit length.

/// `bits!( parser ) => ( &[u8], (&[u8], usize) -> IResult<(&[u8], usize), T> ) -> IResult<&[u8], T>`
/// transforms its byte slice input in a bit stream for the underlying parsers
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( take_3_bits<u8>, bits!( take_bits!( u8, 3 ) ) );
///
///  let input = vec![0b10101010, 0b11110000, 0b00110011];
///  let sl    = &input[..];
///
///  assert_eq!(take_3_bits( sl ), Done(&sl[1..], 5) );
/// # }
#[macro_export]
macro_rules! bits (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    bits_impl!($i, $submac!($($args)*));
  );
  ($i:expr, $f:expr) => (
    bits_impl!($i, call!($f));
  );
);

/// Internal parser, do not use directly
#[doc(hidden)]
#[macro_export]
macro_rules! bits_impl (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    {
      let input = ($i, 0usize);
      match $submac!(input, $($args)*) {
        $crate::IResult::Error(e)                            => {
          let err = match e {
            $crate::Err::Code(k) | $crate::Err::Node(k, _) => $crate::Err::Code(k),
            $crate::Err::Position(k, (i,b)) | $crate::Err::NodePosition(k, (i,b), _) => {
              $crate::Err::Position(k, &i[b/8..])
            }
          };
          $crate::IResult::Error(err)
        }
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => {
          //println!("bits parser returned Needed::Size({})", i);
          $crate::IResult::Incomplete($crate::Needed::Size(i / 8 + 1))
        },
        $crate::IResult::Done((i, bit_index), o)             => {
          let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ;
          //println!("bit index=={} => byte index=={}", bit_index, byte_index);
          $crate::IResult::Done(&i[byte_index..], o)
        }
      }
    }
  );
);

/// `take_bits!(type, nb) => ( (&[T], usize), U, usize) -> IResult<(&[T], usize), U>`
/// generates a parser consuming the specified number of bytes
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( take_pair<(u8, u8)>, bits!( pair!( take_bits!( u8, 3 ), take_bits!(u8, 5) ) ) );
///
///  let input = vec![0b10101010, 0b11110000, 0b00110011];
///  let sl    = &input[..];
///
///  assert_eq!(take_pair( sl ),       Done(&sl[1..], (5, 10)) );
///  assert_eq!(take_pair( &sl[1..] ), Done(&sl[2..], (7, 16)) );
/// # }
/// ```
#[macro_export]
macro_rules! take_bits (
  ($i:expr, $t:ty, $count:expr) => (
    {
      use std::ops::Div;
      //println!("taking {} bits from {:?}", $count, $i);
      let (input, bit_offset) = $i;
      let res : $crate::IResult<(&[u8],usize), $t> = if $count == 0 {
        $crate::IResult::Done( (input, bit_offset), 0)
      } else {
        let cnt = ($count as usize + bit_offset).div(8);
        if input.len() * 8 < $count as usize + bit_offset {
          //println!("returning incomplete: {}", $count as usize + bit_offset);
          $crate::IResult::Incomplete($crate::Needed::Size($count as usize))
        } else {
          let mut acc:$t            = 0;
          let mut offset: usize     = bit_offset;
          let mut remaining: usize  = $count;
          let mut end_offset: usize = 0;

          for it in 0..cnt+1 {
            if remaining == 0 {
              break;
            }
            let val: $t = if offset == 0 {
              input[it] as $t
            } else {
              ((input[it] << offset) as u8 >> offset) as $t
            };

            if remaining < 8 - offset {
              acc += val >> (8 - offset - remaining);
              end_offset = remaining + offset;
              break;
            } else {
              acc += val << remaining - (8 - offset);
              remaining -= 8 - offset;
              offset = 0;
            }
          }
          $crate::IResult::Done( (&input[cnt..], end_offset) , acc)
        }
      };
      res
    }
  );
);

/// matches an integer pattern to a bitstream. The number of bits of the input to compare must be specified
#[macro_export]
macro_rules! tag_bits (
  ($i:expr, $t:ty, $count:expr, $p: pat) => (
    {
      match take_bits!($i, $t, $count) {
        $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
        $crate::IResult::Done(i, o)    => {
          if let $p = o {
            let res: $crate::IResult<(&[u8],usize),$t> = $crate::IResult::Done(i, o);
            res
          } else {
            $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i))
          }
        },
        _                              => {
          $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i))
        }
      }
    }
  )
);

#[cfg(test)]
mod tests {
  use internal::{IResult,Needed,Err};
  use ErrorKind;

  #[test]
  fn take_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(take_bits!( (sl, 0), u8,   0 ), IResult::Done((sl, 0), 0));
    assert_eq!(take_bits!( (sl, 0), u8,   8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 0), u8,   3 ), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(take_bits!( (sl, 0), u8,   6 ), IResult::Done((&sl[0..], 6), 42));
    assert_eq!(take_bits!( (sl, 1), u8,   1 ), IResult::Done((&sl[0..], 2), 0));
    assert_eq!(take_bits!( (sl, 1), u8,   2 ), IResult::Done((&sl[0..], 3), 1));
    assert_eq!(take_bits!( (sl, 1), u8,   3 ), IResult::Done((&sl[0..], 4), 2));
    assert_eq!(take_bits!( (sl, 6), u8,   3 ), IResult::Done((&sl[1..], 1), 5));
    assert_eq!(take_bits!( (sl, 0), u16, 10 ), IResult::Done((&sl[1..], 2), 683));
    assert_eq!(take_bits!( (sl, 0), u16,  8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 6), u16, 10 ), IResult::Done((&sl[2..], 0), 752));
    assert_eq!(take_bits!( (sl, 6), u16, 11 ), IResult::Done((&sl[2..], 1), 1504));
    assert_eq!(take_bits!( (sl, 0), u32, 20 ), IResult::Done((&sl[2..], 4), 700163));
    assert_eq!(take_bits!( (sl, 4), u32, 20 ), IResult::Done((&sl[3..], 0), 716851));
    assert_eq!(take_bits!( (sl, 4), u32, 22 ), IResult::Incomplete(Needed::Size(22)));
  }

  #[test]
  fn tag_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(tag_bits!( (sl, 0), u8,   3, 0b101), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(tag_bits!( (sl, 0), u8,   4, 0b1010), IResult::Done((&sl[0..], 4), 10));
  }

  named!(ch<(&[u8],usize),(u8,u8)>,
    chain!(
      tag_bits!(u8, 3, 0b101) ~
      x: take_bits!(u8, 4)    ~
      y: take_bits!(u8, 5)    ,
      || { (x,y) }
    )
  );

  #[test]
  fn chain_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(ch((&input[..],0)), IResult::Done((&sl[1..], 4), (5,15)));
    assert_eq!(ch((&input[..],4)), IResult::Done((&sl[2..], 0), (7,16)));
    assert_eq!(ch((&input[..1],0)), IResult::Incomplete(Needed::Size(12)));
  }

  named!(ch_bytes<(u8,u8)>, bits!(ch));
  #[test]
  fn bits_to_bytes() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    assert_eq!(ch_bytes(&input[..]), IResult::Done(&input[2..], (5,15)));
    assert_eq!(ch_bytes(&input[..1]), IResult::Incomplete(Needed::Size(2)));
    assert_eq!(ch_bytes(&input[1..]), IResult::Error(Err::Position(ErrorKind::TagBits, &input[1..])));
  }
}
<commit_msg>Fix invalid doc<commit_after>//! Bit level parsers and combinators
//!
//! Bit parsing is handled by tweaking the input in most macros.
//! In byte level parsing, the input is generally a `&[u8]` passed from combinator
//! to combinator until the slices are manipulated.
//!
//! Bit parsers take a `(&[u8], usize)` as input. The first part of the tuple is an byte slice,
//! the second part is a bit offset in the first byte of the slice.
//!
//! By passing a pair like this, we can leverage most of the combinators, and avoid
//! transforming the whole slice to a vector of booleans. This should make it easy
//! to see a byte slice as a bit stream, and parse code points of arbitrary bit length.

/// `bits!( parser ) => ( &[u8], (&[u8], usize) -> IResult<(&[u8], usize), T> ) -> IResult<&[u8], T>`
/// transforms its byte slice input in a bit stream for the underlying parsers
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( take_3_bits<u8>, bits!( take_bits!( u8, 3 ) ) );
///
///  let input = vec![0b10101010, 0b11110000, 0b00110011];
///  let sl    = &input[..];
///
///  assert_eq!(take_3_bits( sl ), Done(&sl[1..], 5) );
/// # }
#[macro_export]
macro_rules! bits (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    bits_impl!($i, $submac!($($args)*));
  );
  ($i:expr, $f:expr) => (
    bits_impl!($i, call!($f));
  );
);

/// Internal parser, do not use directly
#[doc(hidden)]
#[macro_export]
macro_rules! bits_impl (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    {
      let input = ($i, 0usize);
      match $submac!(input, $($args)*) {
        $crate::IResult::Error(e)                            => {
          let err = match e {
            $crate::Err::Code(k) | $crate::Err::Node(k, _) => $crate::Err::Code(k),
            $crate::Err::Position(k, (i,b)) | $crate::Err::NodePosition(k, (i,b), _) => {
              $crate::Err::Position(k, &i[b/8..])
            }
          };
          $crate::IResult::Error(err)
        }
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => {
          //println!("bits parser returned Needed::Size({})", i);
          $crate::IResult::Incomplete($crate::Needed::Size(i / 8 + 1))
        },
        $crate::IResult::Done((i, bit_index), o)             => {
          let byte_index = bit_index / 8 + if bit_index % 8 == 0 { 0 } else { 1 } ;
          //println!("bit index=={} => byte index=={}", bit_index, byte_index);
          $crate::IResult::Done(&i[byte_index..], o)
        }
      }
    }
  );
);

/// `take_bits!(type, nb) => ( (&[T], usize), U, usize) -> IResult<(&[T], usize), U>`
/// generates a parser consuming the specified number of bits.
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  named!( take_pair<(u8, u8)>, bits!( pair!( take_bits!( u8, 3 ), take_bits!(u8, 5) ) ) );
///
///  let input = vec![0b10101010, 0b11110000, 0b00110011];
///  let sl    = &input[..];
///
///  assert_eq!(take_pair( sl ),       Done(&sl[1..], (5, 10)) );
///  assert_eq!(take_pair( &sl[1..] ), Done(&sl[2..], (7, 16)) );
/// # }
/// ```
#[macro_export]
macro_rules! take_bits (
  ($i:expr, $t:ty, $count:expr) => (
    {
      use std::ops::Div;
      //println!("taking {} bits from {:?}", $count, $i);
      let (input, bit_offset) = $i;
      let res : $crate::IResult<(&[u8],usize), $t> = if $count == 0 {
        $crate::IResult::Done( (input, bit_offset), 0)
      } else {
        let cnt = ($count as usize + bit_offset).div(8);
        if input.len() * 8 < $count as usize + bit_offset {
          //println!("returning incomplete: {}", $count as usize + bit_offset);
          $crate::IResult::Incomplete($crate::Needed::Size($count as usize))
        } else {
          let mut acc:$t            = 0;
          let mut offset: usize     = bit_offset;
          let mut remaining: usize  = $count;
          let mut end_offset: usize = 0;

          for it in 0..cnt+1 {
            if remaining == 0 {
              break;
            }
            let val: $t = if offset == 0 {
              input[it] as $t
            } else {
              ((input[it] << offset) as u8 >> offset) as $t
            };

            if remaining < 8 - offset {
              acc += val >> (8 - offset - remaining);
              end_offset = remaining + offset;
              break;
            } else {
              acc += val << remaining - (8 - offset);
              remaining -= 8 - offset;
              offset = 0;
            }
          }
          $crate::IResult::Done( (&input[cnt..], end_offset) , acc)
        }
      };
      res
    }
  );
);

/// matches an integer pattern to a bitstream. The number of bits of the input to compare must be specified
#[macro_export]
macro_rules! tag_bits (
  ($i:expr, $t:ty, $count:expr, $p: pat) => (
    {
      match take_bits!($i, $t, $count) {
        $crate::IResult::Incomplete(i) => $crate::IResult::Incomplete(i),
        $crate::IResult::Done(i, o)    => {
          if let $p = o {
            let res: $crate::IResult<(&[u8],usize),$t> = $crate::IResult::Done(i, o);
            res
          } else {
            $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i))
          }
        },
        _                              => {
          $crate::IResult::Error($crate::Err::Position($crate::ErrorKind::TagBits, $i))
        }
      }
    }
  )
);

#[cfg(test)]
mod tests {
  use internal::{IResult,Needed,Err};
  use ErrorKind;

  #[test]
  fn take_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(take_bits!( (sl, 0), u8,   0 ), IResult::Done((sl, 0), 0));
    assert_eq!(take_bits!( (sl, 0), u8,   8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 0), u8,   3 ), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(take_bits!( (sl, 0), u8,   6 ), IResult::Done((&sl[0..], 6), 42));
    assert_eq!(take_bits!( (sl, 1), u8,   1 ), IResult::Done((&sl[0..], 2), 0));
    assert_eq!(take_bits!( (sl, 1), u8,   2 ), IResult::Done((&sl[0..], 3), 1));
    assert_eq!(take_bits!( (sl, 1), u8,   3 ), IResult::Done((&sl[0..], 4), 2));
    assert_eq!(take_bits!( (sl, 6), u8,   3 ), IResult::Done((&sl[1..], 1), 5));
    assert_eq!(take_bits!( (sl, 0), u16, 10 ), IResult::Done((&sl[1..], 2), 683));
    assert_eq!(take_bits!( (sl, 0), u16,  8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 6), u16, 10 ), IResult::Done((&sl[2..], 0), 752));
    assert_eq!(take_bits!( (sl, 6), u16, 11 ), IResult::Done((&sl[2..], 1), 1504));
    assert_eq!(take_bits!( (sl, 0), u32, 20 ), IResult::Done((&sl[2..], 4), 700163));
    assert_eq!(take_bits!( (sl, 4), u32, 20 ), IResult::Done((&sl[3..], 0), 716851));
    assert_eq!(take_bits!( (sl, 4), u32, 22 ), IResult::Incomplete(Needed::Size(22)));
  }

  #[test]
  fn tag_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(tag_bits!( (sl, 0), u8,   3, 0b101), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(tag_bits!( (sl, 0), u8,   4, 0b1010), IResult::Done((&sl[0..], 4), 10));
  }

  named!(ch<(&[u8],usize),(u8,u8)>,
    chain!(
      tag_bits!(u8, 3, 0b101) ~
      x: take_bits!(u8, 4)    ~
      y: take_bits!(u8, 5)    ,
      || { (x,y) }
    )
  );

  #[test]
  fn chain_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(ch((&input[..],0)), IResult::Done((&sl[1..], 4), (5,15)));
    assert_eq!(ch((&input[..],4)), IResult::Done((&sl[2..], 0), (7,16)));
    assert_eq!(ch((&input[..1],0)), IResult::Incomplete(Needed::Size(12)));
  }

  named!(ch_bytes<(u8,u8)>, bits!(ch));
  #[test]
  fn bits_to_bytes() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    assert_eq!(ch_bytes(&input[..]), IResult::Done(&input[2..], (5,15)));
    assert_eq!(ch_bytes(&input[..1]), IResult::Incomplete(Needed::Size(2)));
    assert_eq!(ch_bytes(&input[1..]), IResult::Error(Err::Position(ErrorKind::TagBits, &input[1..])));
  }
}
<|endoftext|>


<commit_before>
//! Various utilities for rendering and resource management

pub mod graphics {
    //! Wrappers for unsafe OpenGL calls

    use gl;
    use gl::types::*;
    use color::Color;

    /// Sets the OpenGL viewport
    pub fn viewport(x: u32, y: u32, width: u32, height: u32) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, width as GLsizei, height as GLsizei);
        }
    }

    /// Enables the OpenGL scissor test, with the given area. Note that this region is specified in
    /// screen space.  That is, in the same coordinate system as [`viewport`]. Anything drawn
    /// outside this region will be discarded. Scissoring can be disabled with [`disable_scissor`].
    ///
    /// [`viewport`]: fn.viewport.html
    /// [`disable_scissor`]: fn.disable_scissor.html
    pub fn enable_scissor(x: u32, y: u32, width: u32, height: u32) {
        unsafe {
            gl::Enable(gl::SCISSOR_TEST);
            gl::Scissor(x as GLint, y as GLint, width as GLsizei, height as GLsizei);
        }
    }

    /// Disables the opengl scissor test, which can be enabled with [`enable_scissor`].
    ///
    /// [`enable_scissor`]: fn.enable_scissor.html
    pub fn disable_scissor() {
        unsafe {
            gl::Disable(gl::SCISSOR_TEST);
        }
    }

    /// Prints all OpenGL errors.
    pub fn print_errors() {
        unsafe {
            while let Some(error) = get_error_message(gl::GetError()) {
                println!("OpenGL error: {}", error);
            }
        }
    }
    fn get_error_message(error: GLenum) -> Option<String> {
        let value = match error {
            gl::INVALID_VALUE                   => "Invalid value",
            gl::INVALID_ENUM                    => "Invalid enum",
            gl::INVALID_OPERATION               => "Invalid operation",
            gl::INVALID_FRAMEBUFFER_OPERATION   => "Invalid framebuffer operation",
            gl::OUT_OF_MEMORY                   => "Out of memory",

            gl::NO_ERROR                        => return None,
            _                                   => return Some(format!("Invalid error code: {:x}", error)),
        };
        Some(String::from(value))
    }

    /// Sets which side of a face to treat as the front face and which side of a face to cull. If
    /// `None` is passed this disables culling.
    ///
    /// For simplicity, you can simply call `graphics::set_culling(Some(Default::default()))`,
    /// which will set the winding order to counter-clockwise and cull-face to the back face.
    pub fn set_culling(mode: Option<(WindingOrder, FaceSide)>) {
        unsafe { match mode {
            Some((winding_order, face_side)) => {
                gl::Enable(gl::CULL_FACE);
                match winding_order {
                    WindingOrder::Clockwise => gl::FrontFace(gl::CW),
                    WindingOrder::CounterClockwise => gl::FrontFace(gl::CCW),
                }
                match face_side {
                    FaceSide::Front => gl::CullFace(gl::FRONT),
                    FaceSide::Back => gl::CullFace(gl::BACK),
                }
            },
            None => {
                gl::Disable(gl::CULL_FACE);
            },
        } }
    }

    #[derive(Debug, Copy, Clone)]
    pub enum WindingOrder {
        Clockwise, CounterClockwise,
    }
    #[derive(Debug, Copy, Clone)]
    pub enum FaceSide {
        Front, Back
    }

    impl Default for WindingOrder {
        /// The default winding order is counter-clockwise.
        fn default() -> WindingOrder { WindingOrder::CounterClockwise }
    }
    impl Default for FaceSide {
        /// The default face side is back, as this is the face you want to cull by default.
        fn default() -> FaceSide { FaceSide::Back }
    }

    /// Enables/disables rasterization. If disabled, only the vertex shader will be run. This is
    /// useful when you are only interested in transform feedback. Keep in mind that rasterization
    /// has to be re-enabled before rendering, otherwise nothing will be shown.
    pub fn set_rasterization(discard: bool) {
        if discard {
            unsafe { gl::Enable(gl::RASTERIZER_DISCARD) };
        } else {
            unsafe { gl::Disable(gl::RASTERIZER_DISCARD) };
        }
    }

    /// Clears the currently bound framebuffer to the given color.
    pub fn clear(color: Option<Color>, depth: bool, stencil: bool) {
        unsafe {
            if let Some(color) = color {
                gl::ClearColor(color.r, color.g, color.b, color.a);
            }
            let mut mask = 0;
            if color.is_some() { mask |= gl::COLOR_BUFFER_BIT }
            if depth           { mask |= gl::DEPTH_BUFFER_BIT }
            if stencil         { mask |= gl::STENCIL_BUFFER_BIT }
            gl::Clear(mask);
        }
    }

    /// Toggles depth testing. This only has an effect if the currently bound framebuffer
    /// has a depthbuffer (The backbuffer always has a depthbuffer).
    pub fn set_depth_testing(enabled: bool) {
        unsafe {
            if enabled {
                gl::Enable(gl::DEPTH_TEST);
            } else {
                gl::Disable(gl::DEPTH_TEST);
            }
        }
    }

    /// If passed `Some` enables the given blend settings. If passed `None` disables
    /// blending.
    pub fn set_blending(blending: Option<BlendSettings>) {
        unsafe {
            if let Some(ref settings) = blending {
                settings.enable();
            } else {
                gl::Disable(gl::BLEND);
            }
        }
    }

    /// Settings used to define OpenGL blend state. You should create a pair of settings
    /// for every operation which uses blending, and apply those settings before rendering.
    /// Blending can be enabled either through
    /// [`enable()`](struct.BlendSettings.html#method.enable)
    /// or
    /// [`graphics::set_blending(Some(my_settings))`](fn.set_blending.html)
    /// and can be disabled wtih
    /// [`graphics::set_blending(None)`](fn.set_blending.html).
    ///
    /// Note that this struct implements `Default`, so default blend settings can be retrieved
    /// with `BlendSettings::default()`.
    #[derive(Debug, Clone, Copy)]
    pub struct BlendSettings {
        pub src_color: BlendFactor,
        pub src_alpha: BlendFactor,
        pub dst_color: BlendFactor,
        pub dst_alpha: BlendFactor,
        pub function: BlendFunction,
    }
    const DEFAULT_BLEND_SETTINGS: BlendSettings = BlendSettings {
        src_color: BlendFactor::SrcAlpha,
        dst_color: BlendFactor::OneMinusSrcAlpha,
        src_alpha: BlendFactor::One,
        dst_alpha: BlendFactor::Zero,
        function: BlendFunction::Add,
    };
    impl BlendSettings {
        /// Enables blending, and uses these blend settings
        pub fn enable(&self) {
            unsafe {
                gl::Enable(gl::BLEND);
                gl::BlendFuncSeparate(self.src_color as GLenum,
                                      self.dst_color as GLenum,
                                      self.src_alpha as GLenum,
                                      self.dst_alpha as GLenum);
                gl::BlendEquation(self.function as GLenum);
            }
        }
    }
    impl Default for BlendSettings {
        fn default() -> BlendSettings {
            DEFAULT_BLEND_SETTINGS
        }
    }

    #[repr(u32)] // GLenum is u32
    #[derive(Copy, Clone, Debug)]
    pub enum BlendFactor {
        Zero                    = gl::ZERO,
        One                     = gl::ONE,
        SrcColor                = gl::SRC_COLOR,
        OneMinusSrcColor        = gl::ONE_MINUS_SRC_COLOR,
        DstColor                = gl::DST_COLOR,
        OneMinusDstColor        = gl::ONE_MINUS_DST_COLOR,
        SrcAlpha                = gl::SRC_ALPHA,
        OneMinusSrcAlpha        = gl::ONE_MINUS_SRC_ALPHA,
        DstAlpha                = gl::DST_ALPHA,
        OneMinusDstAlpha        = gl::ONE_MINUS_DST_ALPHA,
        ConstantColor           = gl::CONSTANT_COLOR,
        OneMinusConstantColor   = gl::ONE_MINUS_CONSTANT_COLOR,
        ConstantAlpha           = gl::CONSTANT_ALPHA,
        OneMinusConstantAlpha   = gl::ONE_MINUS_CONSTANT_ALPHA,
    }

    #[repr(u32)] // GLenum is u32
    #[derive(Copy, Clone, Debug)]
    pub enum BlendFunction {
        /// `Src + Dst`
        Add             = gl::FUNC_ADD,
        /// `Src - Dst`
        Subtract        = gl::FUNC_SUBTRACT,
        /// `Dst - Src`
        ReverseSubtract = gl::FUNC_REVERSE_SUBTRACT,
        /// `min(Dst, Src)`
        Min             = gl::MIN,
        /// `max(Dst, Src)`
        Max             = gl::MAX,
    }
}

pub mod loading {
    //! Utilities for loading/reloading files

    use std::time::SystemTime;
    use std::fs;
    use std::io;
    use std::path::{PathBuf, Path};
    use std::collections::HashMap;

    /// A utility to execute some action when a file has been changed. Files are checked by
    /// periodically calling [`check(...)`](fn.modified_since.html) inside e.g. the main game
    /// loop.
    pub struct ResourceRefresher {
        last_load_times: HashMap<PathBuf, SystemTime>,
    }

    impl ResourceRefresher {
        pub fn new() -> ResourceRefresher {
            ResourceRefresher {
                last_load_times: HashMap::new(),
            }
        }

        /// Returns true if the given file has been modified since the last call to this function.
        /// If an error occurs while checking if the file has been modified this function prints a
        /// error and returns `false`.
        ///
        /// # Example
        /// ```rust,ignore
        /// use util::loading::ResourceRefresher;
        ///
        /// let mut refresher = ResourceRefresher::new();
        ///
        /// // In main loop
        /// if refresher.check("assets/basic.glsl") {
        ///     // Reload shader
        /// }
        /// ```
        pub fn check<P>(&mut self, path: P) -> bool where P: AsRef<Path> {
            let changed = {
                let key = path.as_ref().to_path_buf();
                let load_time = self.last_load_times.entry(key).or_insert(SystemTime::now());

                match modified_since(path.as_ref(), *load_time) {
                    Ok(value) => value,
                    Err(err) => {
                        println!("Failed to check \"{}\" for modification: {}", path.as_ref().to_string_lossy(), err);
                        false
                    }
                }
            };
            if changed {
                let key = path.as_ref().to_path_buf();
                self.last_load_times.insert(key, SystemTime::now());
            }
            changed
        }
    }

    /// Checks if the given file has been modified since the given time.
    pub fn modified_since(path: &Path, last_time: SystemTime) -> io::Result<bool> {
        let metadata = fs::metadata(&path)?;
        let last_modified = metadata.modified()?;

        if let Err(_) = last_time.duration_since(last_modified) {
            return Ok(true);
        } else {
            return Ok(false);
        }
    }
}

<commit_msg>Utility to change depth function<commit_after>
//! Various utilities for rendering and resource management

pub mod graphics {
    //! Wrappers for unsafe OpenGL calls

    use gl;
    use gl::types::*;
    use color::Color;

    /// Sets the OpenGL viewport
    pub fn viewport(x: u32, y: u32, width: u32, height: u32) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, width as GLsizei, height as GLsizei);
        }
    }

    /// Enables the OpenGL scissor test, with the given area. Note that this region is specified in
    /// screen space.  That is, in the same coordinate system as [`viewport`]. Anything drawn
    /// outside this region will be discarded. Scissoring can be disabled with [`disable_scissor`].
    ///
    /// [`viewport`]: fn.viewport.html
    /// [`disable_scissor`]: fn.disable_scissor.html
    pub fn enable_scissor(x: u32, y: u32, width: u32, height: u32) {
        unsafe {
            gl::Enable(gl::SCISSOR_TEST);
            gl::Scissor(x as GLint, y as GLint, width as GLsizei, height as GLsizei);
        }
    }

    /// Disables the opengl scissor test, which can be enabled with [`enable_scissor`].
    ///
    /// [`enable_scissor`]: fn.enable_scissor.html
    pub fn disable_scissor() {
        unsafe {
            gl::Disable(gl::SCISSOR_TEST);
        }
    }

    /// Prints all OpenGL errors.
    pub fn print_errors() {
        unsafe {
            while let Some(error) = get_error_message(gl::GetError()) {
                println!("OpenGL error: {}", error);
            }
        }
    }
    fn get_error_message(error: GLenum) -> Option<String> {
        let value = match error {
            gl::INVALID_VALUE                   => "Invalid value",
            gl::INVALID_ENUM                    => "Invalid enum",
            gl::INVALID_OPERATION               => "Invalid operation",
            gl::INVALID_FRAMEBUFFER_OPERATION   => "Invalid framebuffer operation",
            gl::OUT_OF_MEMORY                   => "Out of memory",

            gl::NO_ERROR                        => return None,
            _                                   => return Some(format!("Invalid error code: {:x}", error)),
        };
        Some(String::from(value))
    }

    /// Sets which side of a face to treat as the front face and which side of a face to cull. If
    /// `None` is passed this disables culling.
    ///
    /// For simplicity, you can simply call `graphics::set_culling(Some(Default::default()))`,
    /// which will set the winding order to counter-clockwise and cull-face to the back face.
    pub fn set_culling(mode: Option<(WindingOrder, FaceSide)>) {
        unsafe { match mode {
            Some((winding_order, face_side)) => {
                gl::Enable(gl::CULL_FACE);
                match winding_order {
                    WindingOrder::Clockwise => gl::FrontFace(gl::CW),
                    WindingOrder::CounterClockwise => gl::FrontFace(gl::CCW),
                }
                match face_side {
                    FaceSide::Front => gl::CullFace(gl::FRONT),
                    FaceSide::Back => gl::CullFace(gl::BACK),
                }
            },
            None => {
                gl::Disable(gl::CULL_FACE);
            },
        } }
    }

    #[derive(Debug, Copy, Clone)]
    pub enum WindingOrder {
        Clockwise, CounterClockwise,
    }
    #[derive(Debug, Copy, Clone)]
    pub enum FaceSide {
        Front, Back
    }

    impl Default for WindingOrder {
        /// The default winding order is counter-clockwise.
        fn default() -> WindingOrder { WindingOrder::CounterClockwise }
    }
    impl Default for FaceSide {
        /// The default face side is back, as this is the face you want to cull by default.
        fn default() -> FaceSide { FaceSide::Back }
    }

    /// Enables/disables rasterization. If disabled, only the vertex shader will be run. This is
    /// useful when you are only interested in transform feedback. Keep in mind that rasterization
    /// has to be re-enabled before rendering, otherwise nothing will be shown.
    pub fn set_rasterization(discard: bool) {
        if discard {
            unsafe { gl::Enable(gl::RASTERIZER_DISCARD) };
        } else {
            unsafe { gl::Disable(gl::RASTERIZER_DISCARD) };
        }
    }

    /// Clears the currently bound framebuffer to the given color.
    pub fn clear(color: Option<Color>, depth: bool, stencil: bool) {
        unsafe {
            if let Some(color) = color {
                gl::ClearColor(color.r, color.g, color.b, color.a);
            }
            let mut mask = 0;
            if color.is_some() { mask |= gl::COLOR_BUFFER_BIT }
            if depth           { mask |= gl::DEPTH_BUFFER_BIT }
            if stencil         { mask |= gl::STENCIL_BUFFER_BIT }
            gl::Clear(mask);
        }
    }

    /// Toggles depth testing. This only has an effect if the currently bound framebuffer
    /// has a depthbuffer (The backbuffer always has a depthbuffer).
    pub fn set_depth_testing(enabled: bool) {
        unsafe {
            if enabled {
                gl::Enable(gl::DEPTH_TEST);
            } else {
                gl::Disable(gl::DEPTH_TEST);
            }
        }
    }

    /// Sets the function used to check if a fragment passes the depth test. The initial value is
    /// `Less`. See [`DepthFunction`] for more info.
    ///
    /// [`DepthFunction`]: enum.DepthFunction.html
    pub fn set_depth_function(depth_function: DepthFunction) {
        unsafe {
            gl::DepthFunc(depth_function as GLenum);
        }
    }

    #[repr(u32)] // GLenum is u32
    #[derive(Copy, Clone, Debug)]
    pub enum DepthFunction {
        /// The depth test never passes.
        Never           = gl::NEVER,
        /// The depth test always passes.
        Always         = gl::ALWAYS,
        /// Only passes if the new fragment is at exactly the same depth as the old fragment.
        Equal           = gl::EQUAL,
        /// Only passes if the new fragment is at a different depth from the old fragment.
        NotEqual        = gl::NOTEQUAL,

        /// Only passes if the new fragment is closer than the old fragment.
        Less            = gl::LESS,
        /// Only passes if the new fragment is closer than or at the same depth as the old fragment.
        LessOrEqual     = gl::LEQUAL,

        /// Only passes if the new fragment is further away than the old fragment.
        Greater         = gl::GREATER,
        /// Only passes if the new fragment is further away or at the same depth as the old fragment.
        GreaterOrEqual  = gl::GEQUAL,
    }

    /// If passed `Some` enables the given blend settings. If passed `None` disables
    /// blending.
    pub fn set_blending(blending: Option<BlendSettings>) {
        unsafe {
            if let Some(ref settings) = blending {
                settings.enable();
            } else {
                gl::Disable(gl::BLEND);
            }
        }
    }

    /// Settings used to define OpenGL blend state. You should create a pair of settings
    /// for every operation which uses blending, and apply those settings before rendering.
    /// Blending can be enabled either through
    /// [`enable()`](struct.BlendSettings.html#method.enable)
    /// or
    /// [`graphics::set_blending(Some(my_settings))`](fn.set_blending.html)
    /// and can be disabled wtih
    /// [`graphics::set_blending(None)`](fn.set_blending.html).
    ///
    /// Note that this struct implements `Default`, so default blend settings can be retrieved
    /// with `BlendSettings::default()`.
    #[derive(Debug, Clone, Copy)]
    pub struct BlendSettings {
        pub src_color: BlendFactor,
        pub src_alpha: BlendFactor,
        pub dst_color: BlendFactor,
        pub dst_alpha: BlendFactor,
        pub function: BlendFunction,
    }
    const DEFAULT_BLEND_SETTINGS: BlendSettings = BlendSettings {
        src_color: BlendFactor::SrcAlpha,
        dst_color: BlendFactor::OneMinusSrcAlpha,
        src_alpha: BlendFactor::One,
        dst_alpha: BlendFactor::Zero,
        function: BlendFunction::Add,
    };
    impl BlendSettings {
        /// Enables blending, and uses these blend settings
        pub fn enable(&self) {
            unsafe {
                gl::Enable(gl::BLEND);
                gl::BlendFuncSeparate(self.src_color as GLenum,
                                      self.dst_color as GLenum,
                                      self.src_alpha as GLenum,
                                      self.dst_alpha as GLenum);
                gl::BlendEquation(self.function as GLenum);
            }
        }
    }
    impl Default for BlendSettings {
        fn default() -> BlendSettings {
            DEFAULT_BLEND_SETTINGS
        }
    }

    #[repr(u32)] // GLenum is u32
    #[derive(Copy, Clone, Debug)]
    pub enum BlendFactor {
        Zero                    = gl::ZERO,
        One                     = gl::ONE,
        SrcColor                = gl::SRC_COLOR,
        OneMinusSrcColor        = gl::ONE_MINUS_SRC_COLOR,
        DstColor                = gl::DST_COLOR,
        OneMinusDstColor        = gl::ONE_MINUS_DST_COLOR,
        SrcAlpha                = gl::SRC_ALPHA,
        OneMinusSrcAlpha        = gl::ONE_MINUS_SRC_ALPHA,
        DstAlpha                = gl::DST_ALPHA,
        OneMinusDstAlpha        = gl::ONE_MINUS_DST_ALPHA,
        ConstantColor           = gl::CONSTANT_COLOR,
        OneMinusConstantColor   = gl::ONE_MINUS_CONSTANT_COLOR,
        ConstantAlpha           = gl::CONSTANT_ALPHA,
        OneMinusConstantAlpha   = gl::ONE_MINUS_CONSTANT_ALPHA,
    }

    #[repr(u32)] // GLenum is u32
    #[derive(Copy, Clone, Debug)]
    pub enum BlendFunction {
        /// `Src + Dst`
        Add             = gl::FUNC_ADD,
        /// `Src - Dst`
        Subtract        = gl::FUNC_SUBTRACT,
        /// `Dst - Src`
        ReverseSubtract = gl::FUNC_REVERSE_SUBTRACT,
        /// `min(Dst, Src)`
        Min             = gl::MIN,
        /// `max(Dst, Src)`
        Max             = gl::MAX,
    }
}

pub mod loading {
    //! Utilities for loading/reloading files

    use std::time::SystemTime;
    use std::fs;
    use std::io;
    use std::path::{PathBuf, Path};
    use std::collections::HashMap;

    /// A utility to execute some action when a file has been changed. Files are checked by
    /// periodically calling [`check(...)`](fn.modified_since.html) inside e.g. the main game
    /// loop.
    pub struct ResourceRefresher {
        last_load_times: HashMap<PathBuf, SystemTime>,
    }

    impl ResourceRefresher {
        pub fn new() -> ResourceRefresher {
            ResourceRefresher {
                last_load_times: HashMap::new(),
            }
        }

        /// Returns true if the given file has been modified since the last call to this function.
        /// If an error occurs while checking if the file has been modified this function prints a
        /// error and returns `false`.
        ///
        /// # Example
        /// ```rust,ignore
        /// use util::loading::ResourceRefresher;
        ///
        /// let mut refresher = ResourceRefresher::new();
        ///
        /// // In main loop
        /// if refresher.check("assets/basic.glsl") {
        ///     // Reload shader
        /// }
        /// ```
        pub fn check<P>(&mut self, path: P) -> bool where P: AsRef<Path> {
            let changed = {
                let key = path.as_ref().to_path_buf();
                let load_time = self.last_load_times.entry(key).or_insert(SystemTime::now());

                match modified_since(path.as_ref(), *load_time) {
                    Ok(value) => value,
                    Err(err) => {
                        println!("Failed to check \"{}\" for modification: {}", path.as_ref().to_string_lossy(), err);
                        false
                    }
                }
            };
            if changed {
                let key = path.as_ref().to_path_buf();
                self.last_load_times.insert(key, SystemTime::now());
            }
            changed
        }
    }

    /// Checks if the given file has been modified since the given time.
    pub fn modified_since(path: &Path, last_time: SystemTime) -> io::Result<bool> {
        let metadata = fs::metadata(&path)?;
        let last_modified = metadata.modified()?;

        if let Err(_) = last_time.duration_since(last_modified) {
            return Ok(true);
        } else {
            return Ok(false);
        }
    }
}

<|endoftext|>


<commit_before>use libc::timespec;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

#[inline]
pub fn duration_from_timeval(ts: timespec) -> Duration {
    Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
}

#[inline]
pub fn system_time_from_timespec(ts: timespec) -> SystemTime {
    UNIX_EPOCH + duration_from_timeval(ts)
}
<commit_msg>Added set_socket_option function.<commit_after>use libc::{c_int, c_void, setsockopt, socklen_t, timespec};
use std::io;
use std::mem::size_of;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

/// `setsockopt` wrapper
///
/// The libc `setsockopt` function is set to set various options on a socket.
/// `set_socket_option` offers a somewhat type-safe wrapper that does not
/// require messing around with `*const c_void`s.
///
/// A proper `std::io::Error` will be returned on failure.
///
/// Example use:
///
/// ```text
/// let fd = ...;  // some file descriptor, this will be stdout
/// set_socket_option(fd, SOL_TCP, TCP_NO_DELAY, 1 as c_int)
/// ```
///
/// Note that the `val` parameter must be specified correctly; if an option
/// expects an integer, it is advisable to pass in a `c_int`, not the default
/// of `i32`.
#[inline]
pub fn set_socket_option<T>(fd: c_int, level: c_int, name: c_int, val: &T) -> io::Result<()> {
    let rv = unsafe {
        let val_ptr: *const T = val as *const T;

        setsockopt(fd,
                   level,
                   name,
                   val_ptr as *const c_void,
                   size_of::<T>() as socklen_t)
    };

    if rv != 0 {
        return Err(io::Error::last_os_error());
    }

    Ok(())
}

#[inline]
pub fn duration_from_timeval(ts: timespec) -> Duration {
    Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
}

#[inline]
pub fn system_time_from_timespec(ts: timespec) -> SystemTime {
    UNIX_EPOCH + duration_from_timeval(ts)
}
<|endoftext|>


<commit_before>use native::task;
use std::comm::channel;

struct WorkUnit<ARG, RV> {
    arg: ARG,
    rv: Sender<RV>,
}

enum MessageToWorker<ARG, RV> {
    Work(WorkUnit<ARG, RV>),
    Halt,
}

enum MessageToDispatcher<ARG, RV> {
    Dispatch(WorkUnit<ARG, RV>),
    HaltAll,
    RegisterWorker(Sender<Sender<Sender<MessageToWorker<ARG, RV>>>>),
}

struct WorkQueue<ARG, RV> {
    dispatcher: Sender<MessageToDispatcher<ARG, RV>>,
}

struct WorkQueueProxy<ARG, RV> {
    dispatcher: Sender<MessageToDispatcher<ARG, RV>>,
}

impl<ARG:Send, RV:Send> WorkQueue<ARG, RV> {
    pub fn create() -> WorkQueue<ARG, RV> {
        let (dispatcher, dispatcher_inbox) = channel::<MessageToDispatcher<ARG, RV>>();

        // dispatcher
        task::spawn(proc() {
            let (want_work, idle_worker) = channel::<Sender<MessageToWorker<ARG, RV>>>();
            let mut worker_count = 0;
            let inbox = dispatcher_inbox;
            let idle_worker = idle_worker;
            loop {
                match inbox.recv() {
                    Dispatch(work_item) => {
                        idle_worker.recv().send(Work(work_item));
                    },
                    RegisterWorker(want_idle_sender) => {
                        worker_count += 1;
                        want_idle_sender.send(want_work.clone());
                    }
                    HaltAll => {
                        while worker_count > 0 {
                            idle_worker.recv().send(Halt);
                            worker_count -= 1;
                        }
                        return;
                    },
                };
            }
        });
        return WorkQueue{dispatcher: dispatcher};
    }

    pub fn proxy(&self) -> WorkQueueProxy<ARG, RV> {
        return WorkQueueProxy{dispatcher: self.dispatcher.clone()};
    }

    pub fn register_worker(&self) -> Sender<Sender<MessageToWorker<ARG, RV>>> {
        let (reg_s, reg_r) = channel::<Sender<Sender<MessageToWorker<ARG, RV>>>>();
        self.dispatcher.send(RegisterWorker(reg_s));
        return reg_r.recv();
    }

    pub fn execute(&self, arg: ARG) -> Receiver<RV> {
        let (rv, wait_for_rv) = channel::<RV>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, rv: rv}));
        return wait_for_rv;
    }
}

// rustc complais "cannot implement a destructor on a structure with
// type parameters", but our destruction is safe, we only send
// a simple message on a channel.
#[unsafe_destructor]
impl<ARG:Send, RV:Send> Drop for WorkQueue<ARG, RV> {
    fn drop(&mut self) {
        self.dispatcher.send(HaltAll);
    }
}

impl<ARG:Send, RV:Send> WorkQueueProxy<ARG, RV> {
    pub fn execute(&self, arg: ARG) -> Receiver<RV> {
        let (rv, wait_for_rv) = channel::<RV>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, rv: rv}));
        return wait_for_rv;
    }
}

fn spawn_test_worker(queue: &WorkQueue<int, int>) {
    let want_work = queue.register_worker();
    task::spawn(proc() {
        let want_work = want_work;
        loop {
            let (idle, get_work_unit) = channel::<MessageToWorker<int, int>>();
            want_work.send(idle);
            let work_unit = match get_work_unit.recv() {
                Work(wu) => wu,
                Halt     => return
            };
            let rv = work_unit.arg * 2;
            work_unit.rv.send(rv);
        }
    });
}

#[test]
fn test_queue() {
    let queue = WorkQueue::<int, int>::create();
    for _ in range(0, 3) {
        spawn_test_worker(&queue);
    }
    let mut promise_list: ~[Receiver<int>] = ~[];
    for c in range(0, 10) {
        let rv = queue.execute(c);
        promise_list.push(rv);
    }
    let return_list = promise_list.map(|promise| promise.recv());
    assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}

#[test]
fn test_enqueue_from_tasks() {
    let queue = WorkQueue::<int, int>::create();
    for _ in range(0, 3) {
        spawn_test_worker(&queue);
    }
    let mut promise_list: ~[Receiver<int>] = ~[];
    for c in range(0, 10) {
        let queue_proxy = queue.proxy();
        let (done, promise) = channel::<int>();
        promise_list.push(promise);
        task::spawn(proc() {
            let done = done;
            let queue = queue_proxy;
            let rv = queue.execute(c);
            done.send(rv.recv());
        });
    }
    let return_list = promise_list.map(|promise| promise.recv());
    assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
<commit_msg>WorkQueueProxy is cloneable<commit_after>use native::task;
use std::comm::channel;

struct WorkUnit<ARG, RV> {
    arg: ARG,
    rv: Sender<RV>,
}

enum MessageToWorker<ARG, RV> {
    Work(WorkUnit<ARG, RV>),
    Halt,
}

enum MessageToDispatcher<ARG, RV> {
    Dispatch(WorkUnit<ARG, RV>),
    HaltAll,
    RegisterWorker(Sender<Sender<Sender<MessageToWorker<ARG, RV>>>>),
}

struct WorkQueue<ARG, RV> {
    dispatcher: Sender<MessageToDispatcher<ARG, RV>>,
}

struct WorkQueueProxy<ARG, RV> {
    dispatcher: Sender<MessageToDispatcher<ARG, RV>>,
}

impl<ARG:Send, RV:Send> WorkQueue<ARG, RV> {
    pub fn create() -> WorkQueue<ARG, RV> {
        let (dispatcher, dispatcher_inbox) = channel::<MessageToDispatcher<ARG, RV>>();

        // dispatcher
        task::spawn(proc() {
            let (want_work, idle_worker) = channel::<Sender<MessageToWorker<ARG, RV>>>();
            let mut worker_count = 0;
            let inbox = dispatcher_inbox;
            let idle_worker = idle_worker;
            loop {
                match inbox.recv() {
                    Dispatch(work_item) => {
                        idle_worker.recv().send(Work(work_item));
                    },
                    RegisterWorker(want_idle_sender) => {
                        worker_count += 1;
                        want_idle_sender.send(want_work.clone());
                    }
                    HaltAll => {
                        while worker_count > 0 {
                            idle_worker.recv().send(Halt);
                            worker_count -= 1;
                        }
                        return;
                    },
                };
            }
        });
        return WorkQueue{dispatcher: dispatcher};
    }

    pub fn proxy(&self) -> WorkQueueProxy<ARG, RV> {
        return WorkQueueProxy{dispatcher: self.dispatcher.clone()};
    }

    pub fn register_worker(&self) -> Sender<Sender<MessageToWorker<ARG, RV>>> {
        let (reg_s, reg_r) = channel::<Sender<Sender<MessageToWorker<ARG, RV>>>>();
        self.dispatcher.send(RegisterWorker(reg_s));
        return reg_r.recv();
    }

    pub fn execute(&self, arg: ARG) -> Receiver<RV> {
        let (rv, wait_for_rv) = channel::<RV>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, rv: rv}));
        return wait_for_rv;
    }
}

// rustc complais "cannot implement a destructor on a structure with
// type parameters", but our destruction is safe, we only send
// a simple message on a channel.
#[unsafe_destructor]
impl<ARG:Send, RV:Send> Drop for WorkQueue<ARG, RV> {
    fn drop(&mut self) {
        self.dispatcher.send(HaltAll);
    }
}

impl<ARG:Send, RV:Send> WorkQueueProxy<ARG, RV> {
    pub fn execute(&self, arg: ARG) -> Receiver<RV> {
        let (rv, wait_for_rv) = channel::<RV>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, rv: rv}));
        return wait_for_rv;
    }
}

impl<ARG:Send, RV:Send> Clone for WorkQueueProxy<ARG, RV> {
    fn clone(&self) -> WorkQueueProxy<ARG, RV> {
        return WorkQueueProxy{dispatcher: self.dispatcher.clone()};
    }
}

fn spawn_test_worker(queue: &WorkQueue<int, int>) {
    let want_work = queue.register_worker();
    task::spawn(proc() {
        let want_work = want_work;
        loop {
            let (idle, get_work_unit) = channel::<MessageToWorker<int, int>>();
            want_work.send(idle);
            let work_unit = match get_work_unit.recv() {
                Work(wu) => wu,
                Halt     => return
            };
            let rv = work_unit.arg * 2;
            work_unit.rv.send(rv);
        }
    });
}

#[test]
fn test_queue() {
    let queue = WorkQueue::<int, int>::create();
    for _ in range(0, 3) {
        spawn_test_worker(&queue);
    }
    let mut promise_list: ~[Receiver<int>] = ~[];
    for c in range(0, 10) {
        let rv = queue.execute(c);
        promise_list.push(rv);
    }
    let return_list = promise_list.map(|promise| promise.recv());
    assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}

#[test]
fn test_enqueue_from_tasks() {
    let queue = WorkQueue::<int, int>::create();
    for _ in range(0, 3) {
        spawn_test_worker(&queue);
    }
    let mut promise_list: ~[Receiver<int>] = ~[];
    let queue_proxy = queue.proxy();
    for c in range(0, 10) {
        let queue_proxy_clone = queue_proxy.clone();
        let (done, promise) = channel::<int>();
        promise_list.push(promise);
        task::spawn(proc() {
            let done = done;
            let queue = queue_proxy_clone;
            let rv = queue.execute(c);
            done.send(rv.recv());
        });
    }
    let return_list = promise_list.map(|promise| promise.recv());
    assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use inotify::wrapper::{INotify, Watch, Event};
use futures::{Async, Poll};
use futures::stream::Stream;
use mio::deprecated::unix::Io;
use tokio_core::reactor::{Handle, PollEvented};

use std::path::Path;
use std::io;

/// Wraps an INotify object and provides asynchronous methods based on the inner object.
pub struct AsyncINotify {
    inner: INotify,
    io: PollEvented<Io>,

    cached_events: Vec<Event>,
}

impl AsyncINotify {
    pub fn init(handle: &Handle) -> io::Result<AsyncINotify> {
        AsyncINotify::init_with_flags(handle, 0)
    }

    pub fn init_with_flags(handle: &Handle, flags: isize) -> io::Result<AsyncINotify> {
        let inotify = try!(INotify::init_with_flags(flags));
        let evfd = Io::from_raw_fd(inotify.fd);

        let pollev = try!(PollEvented::new(evfd, handle));

        Ok(AsyncINotify {
            inner: inotify,
            io: pollev,
            cached_events: Vec::new(),
        })
    }

    pub fn add_watch(&self, path: &Path, mask: u32) -> io::Result<Watch> {
        self.inner.add_watch(path, mask)
    }

    pub fn rm_watch(&self, watch: Watch) -> io::Result<()> {
        self.inner.rm_watch(watch)
    }

    pub fn close(self) -> io::Result<()> {
        self.inner.close()
    }

    fn available_events(&mut self) -> io::Result<&[Event]> {
        self.inner.available_events()
    }
}

impl Stream for AsyncINotify {
    type Item = Event;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // BUG-ish: This returns cached events in a reversed order. Usually, that shouldn't be a
        // problem though.
        if self.cached_events.len() > 0 {
            return Ok(Async::Ready(self.cached_events.pop()));
        }

        // the inner fd is non-blocking by default (set in the inotify crate)
        let events = try!(self.inner.available_events());

        // Only do vec operations if there are many events
        if events.len() < 1 {
            Ok(Async::NotReady)
        } else if events.len() == 1 {
            Ok(Async::Ready(Some(events[0].clone())))
        } else {
            // events.len() > 1
            self.cached_events.extend_from_slice(&events[1..]);
            Ok(Async::Ready(Some(events[0].clone())))
        }
    }
}
<commit_msg>Actually schedule future polls<commit_after>#![allow(dead_code)]

use inotify::wrapper::{INotify, Watch, Event};
use futures::{Async, Poll};
use futures::stream::Stream;
use mio::deprecated::unix::Io;
use tokio_core::reactor::{Handle, PollEvented};

use std::path::Path;
use std::io;

/// Wraps an INotify object and provides asynchronous methods based on the inner object.
pub struct AsyncINotify {
    inner: INotify,
    io: PollEvented<Io>,

    cached_events: Vec<Event>,
}

impl AsyncINotify {
    pub fn init(handle: &Handle) -> io::Result<AsyncINotify> {
        AsyncINotify::init_with_flags(handle, 0)
    }

    pub fn init_with_flags(handle: &Handle, flags: isize) -> io::Result<AsyncINotify> {
        let inotify = try!(INotify::init_with_flags(flags));
        let evfd = Io::from_raw_fd(inotify.fd);

        let pollev = try!(PollEvented::new(evfd, handle));

        Ok(AsyncINotify {
            inner: inotify,
            io: pollev,
            cached_events: Vec::new(),
        })
    }

    pub fn add_watch(&self, path: &Path, mask: u32) -> io::Result<Watch> {
        self.inner.add_watch(path, mask)
    }

    pub fn rm_watch(&self, watch: Watch) -> io::Result<()> {
        self.inner.rm_watch(watch)
    }

    pub fn close(self) -> io::Result<()> {
        // FD is removed from loop by PollEvented::drop()
        self.inner.close()
    }
}

impl Stream for AsyncINotify {
    type Item = Event;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // BUG-ish: This returns cached events in a reversed order. Usually, that shouldn't be a
        // problem though.
        if self.cached_events.len() > 0 {
            return Ok(Async::Ready(self.cached_events.pop()));
        }

        match self.io.poll_read() {
            Async::NotReady => return Ok(Async::NotReady),
            Async::Ready(_) => (), // proceed
        }

        // the inner fd is non-blocking by default (set in the inotify crate)
        let events_try = self.inner.available_events();

        if is_wouldblock(&events_try) {
            self.io.need_read();
            return Ok(Async::NotReady);
        }

        let events = try!(events_try);
        // Only do vec operations if there are many events
        if events.len() < 1 {
            Ok(Async::NotReady)
        } else if events.len() == 1 {
            Ok(Async::Ready(Some(events[0].clone())))
        } else {
            // events.len() > 1
            self.cached_events.extend_from_slice(&events[1..]);
            Ok(Async::Ready(Some(events[0].clone())))
        }
    }
}

// Stolen from tokio-sore: src/reactor/poll_evented.rs:250
fn is_wouldblock<T>(r: &io::Result<T>) -> bool {
    match *r {
        Ok(_) => false,
        Err(ref e) => e.kind() == io::ErrorKind::WouldBlock,
    }
}
<|endoftext|>


<commit_before>use std::process::Command;
use XML;

pub fn panel_xslt() -> String {
    let scss = Command::new("/usr/local/bin/sassc").arg("/Users/jadencarver/dev/superconductor/assets/__pm.scss").output().unwrap();
    let css = String::from_utf8(scss.stdout).unwrap();

    let markup = html! {
        xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" {
            xsl:output method="html" indent="yes" {}

            xsl:template match="/" {
                div#__pm__panel {
                    style type="text/css" (css)
                    style type="text/css" "@import url('//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/styles/agate.min.css');"
                    form#__pm__commit method="post" name="commit" {
                        input type="hidden" id="__pm__commit__task" name="task" value="{/state/task/name}" {}
                        ul#__pm__commits {
                            xsl:apply-templates select="/state/log/commit" {}
                        }
                        hr {}
                        dl.properties {
                            xsl:apply-templates select="/state/properties/property" {}
                        }
                        textarea id="__pm__commit__message" tabindex="1" name="message" placeholder="Add a Comment" {
                            xsl:value-of select="/state/message" {}
                        }
                        div#__pm__new_commit {
                            input type="submit" tabindex="4" name="save_update" value="Save Update" {}
                            xsl:if test="/state/changes/change" {
                                fieldset#__pm__commit__changes.details {
                                    legend#__pm__commit__changes_legend tabindex="2" role="button" {
                                        "Include Changes"
                                        span#__pm__commit__changes__statistics.token {
                                            xsl:if test="/state/changes/statistics/files != 0" {
                                                span {
                                                    xsl:value-of select="format-number(/state/changes/statistics/files, '#,###.##')" {}
                                                    " file"
                                                    xsl:if test="/state/changes/statistics/files != 1" {
                                                        "s"
                                                    }
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/insertions != 0" {
                                                span.token--positive {
                                                    "+"
                                                    xsl:value-of select="format-number(/state/changes/statistics/insertions, '#,###.##')" {}
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/deletions != 0" {
                                                span.token--negative {
                                                    "-"
                                                    xsl:value-of select="format-number(/state/changes/statistics/deletions, '#,###.##')" {}
                                                }
                                            }
                                        }
                                    }
                                    ul {
                                        xsl:apply-templates select="/state/changes/change" {}
                                    }
                                }
                            }
                        }
                    }
                    xsl:choose {
                        xsl:when test="/state/diffs/*" {
                            xsl:apply-templates select="/state/diffs" {}
                        }
                        xsl:otherwise {
                            xsl:apply-templates select="/state/tasks" {}
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property" {
                div.property {
                    xsl:choose {
                        xsl:when test="name = 'Status'" {
                            dt { label for="__pm__commit__properties--status" "Status" }
                            dd.select tabindex="1" {
                                xsl:value-of select="/state/task/property[name[text()='Status']]/value" {}
                                select id="__pm__commit__properties--status" name="property" data-name="Status" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Developer'" {
                            dt { label for="__pm__commit__properties--developer" "Developer" }
                            dd.select {
                                input type="text" id="__pm__commit__properties--developer" value="{/state/task/property[name[text()='Developer']]/value}" {}
                                select name="property" data-name="Developer" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Description'" {
                            dt { label for="__pm__commit__properties--description" "Description" }
                            dd {
                                textarea id="__pm__commit__properties--description" name="property" data-name="Description" {
                                    xsl:value-of select="/state/task/property[name[text()='Description']]/value" {}
                                }
                            }
                        }
                        xsl:otherwise {
                            dt { label for="__pm__commit__properties--estimate" "Estimate" }
                            dd.input {
                                input type="text" id="__pm__commit__properties--estimate" name="property" data-name="Estimate" value="{/state/task/property[name[text()='Estimate']]/value}" {}
                            }
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property/options/option" {
                xsl:variable name="name" select="./parent::options/parent::property/name" {}
                xsl:element name="option" {
                    xsl:attribute name="value" {
                        xsl:value-of select="." {}
                    }
                    xsl:if test="/state/task/property[name[text()=$name]]/value = ." {
                        xsl:attribute name="selected" "selected"
                    }
                    xsl:value-of select="." {}
                }
            }
            xsl:template match="/state/diffs" {
                div.diff {
                    pre {
                        code {
                            xsl:copy-of select="*" {}
                        }
                    }
                }
            }
            xsl:template name="diff-lines" {
                xsl:param name="limit" select="1" {}
                xsl:param name="count" select="1" {}
                xsl:if test="$count <= $limit" {
                    li {
                        xsl:value-of select="$count" {}
                    }
                    xsl:call-template name="diff-lines" {
                        xsl:with-param name="limit" select="$limit" {}
                        xsl:with-param name="count" select="$count + 1" {}
                    }
                }
            }
            xsl:template match="task" {
                li {
                    xsl:element name="div" {
                        xsl:attribute name="draggable" "true"
                        xsl:attribute name="class" {
                            "task "
                            xsl:if test="/state/task/name = name" "selected"
                        }
                        xsl:attribute name="data-name" {
                            xsl:value-of select="name" {}
                        }
                        strong {
                            xsl:value-of select="name" {}
                        }
                        xsl:value-of select="property[name[text()='Description']]/value" {}
                    }
                }
            }
            xsl:template match="/state/tasks" {
                ul.tiles {
                    header "Sprint"
                    xsl:apply-templates select="task" {}
                }
                ul.tiles {
                    header {
                        "In Progress"
                    }
                    xsl:apply-templates select="/state/task" {}
                }
                ul.tiles {
                    header "In Review"
                }
                ul.tiles {
                    header "Blocked"
                }
                ul.tiles {
                    header "Done"
                }
            }
            xsl:template match="/state/log/commit" {
                li {
                    xsl:if test="./preceding-sibling::commit[1]/user/email=user/email and ./preceding-sibling::commit[1]/timestamp - timestamp > -7200" {
                        xsl:attribute name="class" "continuous"
                    }
                    img src="{user/image}" alt="{user/name} <{user/email}>" {}
                    xsl:if test="changes" {
                        button.button--medium.attachments {
                            svg id="i-paperclip" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="20" height="20" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" {
                                path d="M10 9 L10 24 C10 28 13 30 16 30 19 30 22 28 22 24 L22 6 C22 3 20 2 18 2 16 2 14 3 14 6 L14 23 C14 24 15 25 16 25 17 25 18 24 18 23 L18 9" {}
                            }
                        }
                    }
                    blockquote {
                        a.user__name href="#" {
                            xsl:value-of select="user/name" {}
                        }
                        xsl:value-of select="message" {}
                    }
                    xsl:if test="task" {
                        dl.tasks {
                            xsl:apply-templates select="task[property]" {}
                        }
                    }
                    div {
                        time datetime="{localtime}" {
                            xsl:value-of select="localtime" {}
                        }
                    }
                }
            }
            xsl:template match="/state/log/commit/task" {
                dt { xsl:value-of select="name" {} }
                dd {
                    ul.properties {
                        xsl:apply-templates select="property" {}
                    }
                }
            }
            xsl:template match="/state/log/commit/task/property" {
                li.token {
                    span.name { xsl:value-of select="name" {} }
                    xsl:if test="before" {
                        span.before.token--neutral { xsl:value-of select="before" {} }
                    }
                    span.after.token--positive { xsl:value-of select="value" {} }
                }
            }
            xsl:template match="/state/changes/change" {
                li tabindex="3" id="{concat('__pm__changes__checkbox--', @id)}" {
                    xsl:element name="input" {
                        xsl:attribute name="name" { "include" }
                        xsl:attribute name="id" {
                            xsl:value-of select="concat('__pm__changes--', @id)" {}
                        }
                        xsl:attribute name="value" {
                            xsl:value-of select="path" {}
                        }
                        xsl:attribute name="tabindex" "-1"
                        xsl:attribute name="type" "checkbox"
                        xsl:if test="included='true'" {
                            xsl:attribute name="checked" {}
                        }
                        xsl:if test="removal='true'" {
                            xsl:attribute name="class" { "delete" }
                        }
                    }
                    label for="__pm__changes--{@id}" {
                        xsl:value-of select="path" {}
                    }
                    button.button--tiny name="diff" value="{path}" { " +10 -10" }
                }
            }
        }
    };
    format!("{}{}", XML, markup.into_string())
}

<commit_msg>tests moving tiles --- master:    Description: ""   Developer: Bob Dole   Estimate: "3"   Status: In Review<commit_after>use std::process::Command;
use XML;

pub fn panel_xslt() -> String {
    let scss = Command::new("/usr/local/bin/sassc").arg("/Users/jadencarver/dev/superconductor/assets/__pm.scss").output().unwrap();
    let css = String::from_utf8(scss.stdout).unwrap();

    let markup = html! {
        xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" {
            xsl:output method="html" indent="yes" {}

            xsl:template match="/" {
                div#__pm__panel {
                    style type="text/css" (css)
                    style type="text/css" "@import url('//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/styles/agate.min.css');"
                    form#__pm__commit method="post" name="commit" {
                        input type="hidden" id="__pm__commit__task" name="task" value="{/state/task/name}" {}
                        ul#__pm__commits {
                            xsl:apply-templates select="/state/log/commit" {}
                        }
                        hr {}
                        dl.properties {
                            xsl:apply-templates select="/state/properties/property" {}
                        }
                        textarea id="__pm__commit__message" tabindex="1" name="message" placeholder="Add a Comment" {
                            xsl:value-of select="/state/message" {}
                        }
                        div#__pm__new_commit {
                            input type="submit" tabindex="4" name="save_update" value="Save Update" {}
                            xsl:if test="/state/changes/change" {
                                fieldset#__pm__commit__changes.details {
                                    legend#__pm__commit__changes_legend tabindex="2" role="button" {
                                        "Include Changes"
                                        span#__pm__commit__changes__statistics.token {
                                            xsl:if test="/state/changes/statistics/files != 0" {
                                                span {
                                                    xsl:value-of select="format-number(/state/changes/statistics/files, '#,###.##')" {}
                                                    " file"
                                                    xsl:if test="/state/changes/statistics/files != 1" {
                                                        "s"
                                                    }
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/insertions != 0" {
                                                span.token--positive {
                                                    "+"
                                                    xsl:value-of select="format-number(/state/changes/statistics/insertions, '#,###.##')" {}
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/deletions != 0" {
                                                span.token--negative {
                                                    "-"
                                                    xsl:value-of select="format-number(/state/changes/statistics/deletions, '#,###.##')" {}
                                                }
                                            }
                                        }
                                    }
                                    ul {
                                        xsl:apply-templates select="/state/changes/change" {}
                                    }
                                }
                            }
                        }
                    }
                    xsl:choose {
                        xsl:when test="/state/diffs/*" {
                            xsl:apply-templates select="/state/diffs" {}
                        }
                        xsl:otherwise {
                            xsl:apply-templates select="/state/tasks" {}
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property" {
                div.property {
                    xsl:choose {
                        xsl:when test="name = 'Status'" {
                            dt { label for="__pm__commit__properties--status" "Status" }
                            dd.select tabindex="1" {
                                xsl:value-of select="/state/task/property[name[text()='Status']]/value" {}
                                select id="__pm__commit__properties--status" name="property" data-name="Status" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Developer'" {
                            dt { label for="__pm__commit__properties--developer" "Developer" }
                            dd.select {
                                input type="text" id="__pm__commit__properties--developer" value="{/state/task/property[name[text()='Developer']]/value}" {}
                                select name="property" data-name="Developer" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Description'" {
                            dt { label for="__pm__commit__properties--description" "Description" }
                            dd {
                                textarea id="__pm__commit__properties--description" name="property" data-name="Description" {
                                    xsl:value-of select="/state/task/property[name[text()='Description']]/value" {}
                                }
                            }
                        }
                        xsl:otherwise {
                            dt { label for="__pm__commit__properties--estimate" "Estimate" }
                            dd.input {
                                input type="text" id="__pm__commit__properties--estimate" name="property" data-name="Estimate" value="{/state/task/property[name[text()='Estimate']]/value}" {}
                            }
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property/options/option" {
                xsl:variable name="name" select="./parent::options/parent::property/name" {}
                xsl:element name="option" {
                    xsl:attribute name="value" {
                        xsl:value-of select="." {}
                    }
                    xsl:if test="/state/task/property[name[text()=$name]]/value = ." {
                        xsl:attribute name="selected" "selected"
                    }
                    xsl:value-of select="." {}
                }
            }
            xsl:template match="/state/diffs" {
                div.diff {
                    pre {
                        code {
                            xsl:copy-of select="*" {}
                        }
                    }
                }
            }
            xsl:template name="diff-lines" {
                xsl:param name="limit" select="1" {}
                xsl:param name="count" select="1" {}
                xsl:if test="$count <= $limit" {
                    li {
                        xsl:value-of select="$count" {}
                    }
                    xsl:call-template name="diff-lines" {
                        xsl:with-param name="limit" select="$limit" {}
                        xsl:with-param name="count" select="$count + 1" {}
                    }
                }
            }
            xsl:template match="task" {
                li {
                    xsl:element name="div" {
                        xsl:attribute name="draggable" "true"
                        xsl:attribute name="class" {
                            "task "
                            xsl:if test="/state/task/name = name" "selected"
                        }
                        xsl:attribute name="data-name" {
                            xsl:value-of select="name" {}
                        }
                        strong {
                            xsl:value-of select="name" {}
                        }
                        xsl:value-of select="property[name[text()='Description']]/value" {}
                    }
                }
            }
            xsl:template match="/state/tasks" {
                ul.tiles {
                    header "Sprint"
                    xsl:apply-templates select="task[property[name='Status']/value='Sprint']" {}
                }
                ul.tiles {
                    header {
                        "In Progress"
                    }
                    xsl:apply-templates select="task[property[name='Status']/value='In Progress']" {}
                }
                ul.tiles {
                    header "In Review"
                    xsl:apply-templates select="task[property[name='Status']/value='In Review']" {}
                }
                ul.tiles {
                    header "Blocked"
                    xsl:apply-templates select="task[property[name='Status']/value='Blocked']" {}
                }
                ul.tiles {
                    header "Done"
                    xsl:apply-templates select="task[property[name='Status']/value='Done']" {}
                }
            }
            xsl:template match="/state/log/commit" {
                li {
                    xsl:if test="./preceding-sibling::commit[1]/user/email=user/email and ./preceding-sibling::commit[1]/timestamp - timestamp > -7200" {
                        xsl:attribute name="class" "continuous"
                    }
                    img src="{user/image}" alt="{user/name} <{user/email}>" {}
                    xsl:if test="changes" {
                        button.button--medium.attachments {
                            svg id="i-paperclip" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="20" height="20" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" {
                                path d="M10 9 L10 24 C10 28 13 30 16 30 19 30 22 28 22 24 L22 6 C22 3 20 2 18 2 16 2 14 3 14 6 L14 23 C14 24 15 25 16 25 17 25 18 24 18 23 L18 9" {}
                            }
                        }
                    }
                    blockquote {
                        a.user__name href="#" {
                            xsl:value-of select="user/name" {}
                        }
                        xsl:value-of select="message" {}
                    }
                    xsl:if test="task" {
                        dl.tasks {
                            xsl:apply-templates select="task[property]" {}
                        }
                    }
                    div {
                        time datetime="{localtime}" {
                            xsl:value-of select="localtime" {}
                        }
                    }
                }
            }
            xsl:template match="/state/log/commit/task" {
                dt { xsl:value-of select="name" {} }
                dd {
                    ul.properties {
                        xsl:apply-templates select="property" {}
                    }
                }
            }
            xsl:template match="/state/log/commit/task/property" {
                li.token {
                    span.name { xsl:value-of select="name" {} }
                    xsl:if test="before" {
                        span.before.token--neutral { xsl:value-of select="before" {} }
                    }
                    span.after.token--positive { xsl:value-of select="value" {} }
                }
            }
            xsl:template match="/state/changes/change" {
                li tabindex="3" id="{concat('__pm__changes__checkbox--', @id)}" {
                    xsl:element name="input" {
                        xsl:attribute name="name" { "include" }
                        xsl:attribute name="id" {
                            xsl:value-of select="concat('__pm__changes--', @id)" {}
                        }
                        xsl:attribute name="value" {
                            xsl:value-of select="path" {}
                        }
                        xsl:attribute name="tabindex" "-1"
                        xsl:attribute name="type" "checkbox"
                        xsl:if test="included='true'" {
                            xsl:attribute name="checked" {}
                        }
                        xsl:if test="removal='true'" {
                            xsl:attribute name="class" { "delete" }
                        }
                    }
                    label for="__pm__changes--{@id}" {
                        xsl:value-of select="path" {}
                    }
                    button.button--tiny name="diff" value="{path}" { " +10 -10" }
                }
            }
        }
    };
    format!("{}{}", XML, markup.into_string())
}

<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fs::File;
use std::io::Read;
use toml;

const DEFAULT_HERBIE_SEED : &'static str = "#(1461197085 2376054483 1553562171 1611329376 2497620867 2308122621)";
const DEFAULT_DB_PATH : &'static str = "Herbie.db";
const DEFAULT_TIMEOUT : u64 = 120;

#[derive(Debug, RustcDecodable)]
pub struct UxConf {
    /// Path to the database.
    pub db_path: Option<String>,
    /// Maximum time in seconds that Herbie is allowed to play with an expression. If null, allow
    /// The seed use by Herbie. If not provided, a fixed seed will be used. Fixing the seed ensure
    /// deterministic builds.
    pub herbie_seed: Option<String>,
    /// Herbie to run indefinitely. Default is two minutes.
    pub timeout: Option<u64>,
    /// Allow the plugin to call Herbie on unknown expressions.
    /// If ‘true’, the plugin will fail if it cannot find the executable.
    /// If ‘false’, the plugin will not try to run Herbie.
    /// By default, the plugin will call the executable only if it's found, but won't complain
    /// otherwise.
    pub use_herbie: Option<bool>,
}

#[derive(Debug)]
pub enum UseHerbieConf {
    Default,
    No,
    Yes,
}

#[derive(Debug)]
pub struct Conf {
    pub db_path: Cow<'static, str>,
    pub herbie_seed: Cow<'static, str>,
    pub timeout: Option<u64>,
    pub use_herbie: UseHerbieConf,
}

impl Default for Conf {

    fn default() -> Conf {
        Conf {
            db_path: DEFAULT_DB_PATH.into(),
            herbie_seed: DEFAULT_HERBIE_SEED.into(),
            timeout: Some(DEFAULT_TIMEOUT),
            use_herbie: UseHerbieConf::Default,
        }
    }

}

impl From<UxConf> for Conf {

    fn from(ux: UxConf) -> Conf {
        Conf {
            db_path: ux.db_path.map_or(DEFAULT_DB_PATH.into(), Into::into),
            herbie_seed: ux.herbie_seed.map_or(DEFAULT_HERBIE_SEED.into(), Into::into),
            timeout: ux.timeout.map_or(Some(DEFAULT_TIMEOUT), |t| if t == 0 { None } else { Some(t) }),
            use_herbie: ux.use_herbie.map_or(UseHerbieConf::Default, |u| {
                if u {
                    UseHerbieConf::Yes
                }
                else {
                    UseHerbieConf::No
                }
            }),
        }
    }

}

pub fn read_conf() -> Conf {
    let conf = {
        let mut conf = if let Ok(conf) = File::open("Herbie.toml") {
            conf
        }
        else {
            return Conf::default();
        };
        let mut buffer = String::new();
        conf.read_to_string(&mut buffer).unwrap();
        buffer
    };

    let conf : UxConf = toml::decode_str(&conf).unwrap();
    let conf = conf.into();
    println!("{:?}", conf);
    conf
}
<commit_msg>Small conf tweaks<commit_after>use std::borrow::Cow;
use std::fs::File;
use std::io::Read;
use toml;

const DEFAULT_HERBIE_SEED : &'static str = "#(1461197085 2376054483 1553562171 1611329376 2497620867 2308122621)";
const DEFAULT_DB_PATH : &'static str = "Herbie.db";
const DEFAULT_TIMEOUT : u32 = 120;

#[derive(Debug, RustcDecodable)]
pub struct UxConf {
    /// Path to the database.
    pub db_path: Option<String>,
    /// Maximum time in seconds that Herbie is allowed to play with an expression. If null, allow
    /// The seed use by Herbie. If not provided, a fixed seed will be used. Fixing the seed ensures
    /// deterministic builds.
    pub herbie_seed: Option<String>,
    /// Herbie to run indefinitely. Default is two minutes.
    pub timeout: Option<u32>,
    /// Allow the plugin to call Herbie on unknown expressions. Positive results from Herbie will
    /// be cached in the database.
    /// If ‘true’, the plugin will fail if it cannot find the executable.
    /// If ‘false’, the plugin will not try to run Herbie.
    /// By default, the plugin will call the executable only if it's found, but won't complain
    /// otherwise.
    pub use_herbie: Option<bool>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum UseHerbieConf {
    Default,
    No,
    Yes,
}

#[derive(Debug)]
pub struct Conf {
    pub db_path: Cow<'static, str>,
    pub herbie_seed: Cow<'static, str>,
    pub timeout: Option<u32>,
    pub use_herbie: UseHerbieConf,
}

impl Default for Conf {

    fn default() -> Conf {
        Conf {
            db_path: DEFAULT_DB_PATH.into(),
            herbie_seed: DEFAULT_HERBIE_SEED.into(),
            timeout: Some(DEFAULT_TIMEOUT),
            use_herbie: UseHerbieConf::Default,
        }
    }

}

impl From<UxConf> for Conf {

    fn from(ux: UxConf) -> Conf {
        Conf {
            db_path: ux.db_path.map_or(DEFAULT_DB_PATH.into(), Into::into),
            herbie_seed: ux.herbie_seed.map_or(DEFAULT_HERBIE_SEED.into(), Into::into),
            timeout: ux.timeout.map_or(Some(DEFAULT_TIMEOUT), |t| if t == 0 { None } else { Some(t) }),
            use_herbie: ux.use_herbie.map_or(UseHerbieConf::Default, |u| {
                if u {
                    UseHerbieConf::Yes
                }
                else {
                    UseHerbieConf::No
                }
            }),
        }
    }

}

pub fn read_conf() -> Conf {
    let conf = {
        let mut conf = if let Ok(conf) = File::open("Herbie.toml") {
            conf
        }
        else {
            return Conf::default();
        };
        let mut buffer = String::new();
        conf.read_to_string(&mut buffer).unwrap();
        buffer
    };

    let conf : UxConf = toml::decode_str(&conf).unwrap();
    conf.into()
}
<|endoftext|>