<commit_before>// Copyright (c) 2019-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use crate::cdef::*;
use crate::cpu_features::CpuFeatureLevel;
use crate::frame::*;
use crate::tiling::PlaneRegionMut;
use crate::util::*;

type CdefFilterFn = unsafe extern fn(
  dst: *mut u8,
  dst_stride: isize,
  tmp: *const u16,
  tmp_stride: isize,
  pri_strength: i32,
  sec_strength: i32,
  dir: i32,
  damping: i32,
);

type CdefFilterHBDFn = unsafe extern fn(
  dst: *mut u16,
  dst_stride: isize,
  tmp: *const u16,
  tmp_stride: isize,
  pri_strength: i32,
  sec_strength: i32,
  dir: i32,
  damping: i32,
  bitdepth_max: i32,
);

#[inline(always)]
const fn decimate_index(xdec: usize, ydec: usize) -> usize {
  ((ydec << 1) | xdec) & 3
}

pub(crate) unsafe fn cdef_filter_block<T: Pixel>(
  dst: &mut PlaneRegionMut<'_, T>, src: *const T, src_stride: isize,
  pri_strength: i32, sec_strength: i32, dir: usize, damping: i32,
  bit_depth: usize, xdec: usize, ydec: usize, edges: u8, cpu: CpuFeatureLevel,
) {
  let call_rust = |dst: &mut PlaneRegionMut<T>| {
    rust::cdef_filter_block(
      dst,
      src,
      src_stride,
      pri_strength,
      sec_strength,
      dir,
      damping,
      bit_depth,
      xdec,
      ydec,
      edges,
      cpu,
    );
  };

  // TODO: handle padding in the fast path
  if edges != CDEF_HAVE_ALL {
    call_rust(dst);
  } else {
    #[cfg(feature = "check_asm")]
    let ref_dst = {
      let mut copy = dst.scratch_copy();
      call_rust(&mut copy.as_region_mut());
      copy
    };
    match T::type_enum() {
      PixelType::U8 => {
        match CDEF_FILTER_FNS[cpu.as_index()][decimate_index(xdec, ydec)] {
          Some(func) => {
            // current cdef_filter_block asm does 16->8 for historical
            // reasons.  Copy into tmp space for now (also handling
            // padding) until asm is updated
            const TMPSTRIDE: isize =
              std::mem::align_of::<Aligned<u16>>() as isize;
            /* 256 or 512-bit alignment, greater than 2 * (8>>xdec) + 2 */
            const TMPSIZE: usize =
              ((2 + 8 + 2) * TMPSTRIDE + TMPSTRIDE) as usize;
            let mut tmp: Aligned<[u16; TMPSIZE]> =
              Aligned::new([CDEF_VERY_LARGE; TMPSIZE]);
            rust::pad_into_tmp16(
              tmp.data.as_mut_ptr().offset(TMPSTRIDE - 2), // points to
              // *padding* upper left; the -2 is to make sure the
              // block area is SIMD-aligned, not the padding
              TMPSTRIDE,
              src, // points to *block* upper left
              src_stride,
              8 >> xdec,
              8 >> ydec,
              edges,
            );
            (func)(
              dst.data_ptr_mut() as *mut _,
              T::to_asm_stride(dst.plane_cfg.stride),
              tmp.data.as_ptr().offset(3 * TMPSTRIDE) as *const u16,
              TMPSTRIDE,
              pri_strength,
              sec_strength,
              dir as i32,
              damping,
            );
          }
          None => call_rust(dst),
        }
      }
      PixelType::U16 => {
        match CDEF_FILTER_HBD_FNS[cpu.as_index()][decimate_index(xdec, ydec)] {
          Some(func) => {
            (func)(
              dst.data_ptr_mut() as *mut _,
              T::to_asm_stride(dst.plane_cfg.stride),
              src as *const _,
              src_stride,
              pri_strength,
              sec_strength,
              dir as i32,
              damping,
              (1 << bit_depth) - 1,
            );
          }
          None => call_rust(dst),
        }
      }
    }
    #[cfg(feature = "check_asm")]
    {
      for (dst_row, ref_row) in
        dst.rows_iter().zip(ref_dst.as_region().rows_iter())
      {
        for (dst, reference) in dst_row.iter().zip(ref_row) {
          assert_eq!(*dst, *reference);
        }
      }
    }
  }
}

extern {
  fn rav1e_cdef_filter_4x4_avx2(
    dst: *mut u8, dst_stride: isize, tmp: *const u16, tmp_stride: isize,
    pri_strength: i32, sec_strength: i32, dir: i32, damping: i32,
  );

  fn rav1e_cdef_filter_4x8_avx2(
    dst: *mut u8, dst_stride: isize, tmp: *const u16, tmp_stride: isize,
    pri_strength: i32, sec_strength: i32, dir: i32, damping: i32,
  );

  fn rav1e_cdef_filter_8x8_avx2(
    dst: *mut u8, dst_stride: isize, tmp: *const u16, tmp_stride: isize,
    pri_strength: i32, sec_strength: i32, dir: i32, damping: i32,
  );
}

static CDEF_FILTER_FNS_AVX2: [Option<CdefFilterFn>; 4] = {
  let mut out: [Option<CdefFilterFn>; 4] = [None; 4];
  out[decimate_index(1, 1)] = Some(rav1e_cdef_filter_4x4_avx2);
  out[decimate_index(1, 0)] = Some(rav1e_cdef_filter_4x8_avx2);
  out[decimate_index(0, 0)] = Some(rav1e_cdef_filter_8x8_avx2);
  out
};

cpu_function_lookup_table!(
  CDEF_FILTER_FNS: [[Option<CdefFilterFn>; 4]],
  default: [None; 4],
  [AVX2]
);

cpu_function_lookup_table!(
  CDEF_FILTER_HBD_FNS: [[Option<CdefFilterHBDFn>; 4]],
  default: [None; 4],
  []
);

type CdefDirLBDFn =
  unsafe extern fn(tmp: *const u8, tmp_stride: isize, var: *mut u32) -> i32;
type CdefDirHBDFn = unsafe extern fn(
  tmp: *const u16,
  tmp_stride: isize,
  var: *mut u32,
  bitdepth_max: i32,
) -> i32;

#[inline(always)]
#[allow(clippy::let_and_return)]
pub(crate) fn cdef_find_dir<T: Pixel>(
  img: &PlaneSlice<'_, T>, var: &mut u32, coeff_shift: usize,
  cpu: CpuFeatureLevel,
) -> i32 {
  let call_rust =
    |var: &mut u32| rust::cdef_find_dir::<T>(img, var, coeff_shift, cpu);

  #[cfg(feature = "check_asm")]
  let (ref_dir, ref_var) = {
    let mut var: u32 = 0;
    let dir = call_rust(&mut var);
    (dir, var)
  };

  let dir = match T::type_enum() {
    PixelType::U8 => {
      if let Some(func) = CDEF_DIR_LBD_FNS[cpu.as_index()] {
        unsafe {
          (func)(
            img.as_ptr() as *const _,
            T::to_asm_stride(img.plane.cfg.stride),
            var as *mut u32,
          )
        }
      } else {
        call_rust(var)
      }
    }
    PixelType::U16 => {
      if let Some(func) = CDEF_DIR_HBD_FNS[cpu.as_index()] {
        unsafe {
          (func)(
            img.as_ptr() as *const _,
            T::to_asm_stride(img.plane.cfg.stride),
            var as *mut u32,
            (1 << (coeff_shift + 8)) - 1,
          )
        }
      } else {
        call_rust(var)
      }
    }
  };

  #[cfg(feature = "check_asm")]
  {
    assert_eq!(dir, ref_dir);
    assert_eq!(*var, ref_var);
  }

  dir
}

extern {
  fn rav1e_cdef_dir_8bpc_avx2(
    tmp: *const u8, tmp_stride: isize, var: *mut u32,
  ) -> i32;
}

extern {
  fn rav1e_cdef_dir_16bpc_avx2(
    tmp: *const u16, tmp_stride: isize, var: *mut u32, bitdepth_max: i32,
  ) -> i32;
}

cpu_function_lookup_table!(
  CDEF_DIR_LBD_FNS: [Option<CdefDirLBDFn>],
  default: None,
  [(AVX2, Some(rav1e_cdef_dir_8bpc_avx2))]
);

cpu_function_lookup_table!(
  CDEF_DIR_HBD_FNS: [Option<CdefDirHBDFn>],
  default: None,
  [(AVX2, Some(rav1e_cdef_dir_16bpc_avx2))]
);

#[cfg(test)]
mod test {
  pub const CDEF_HAVE_NONE: u8 = 0;
  use super::*;
  use crate::frame::{AsRegion, Plane};
  use interpolate_name::interpolate_test;
  use rand::random;
  use std::str::FromStr;

  macro_rules! test_cdef_fns {
    ($(($XDEC:expr, $YDEC:expr)),*, $OPT:ident, $OPTLIT:literal) => {
      $(
        paste::item! {
          #[interpolate_test(dir_0, 0)]
          #[interpolate_test(dir_1, 1)]
          #[interpolate_test(dir_2, 2)]
          #[interpolate_test(dir_3, 3)]
          #[interpolate_test(dir_4, 4)]
          #[interpolate_test(dir_5, 5)]
          #[interpolate_test(dir_6, 6)]
          #[interpolate_test(dir_7, 7)]
          fn [<cdef_filter_block_dec_ $XDEC _ $YDEC _ $OPT>](dir: usize) {
            if !is_x86_feature_detected!($OPTLIT) {
              eprintln!("Ignoring {} test, not supported on this machine!", $OPTLIT);
              return;
            }

            let width = 8 >> $XDEC;
            let height = 8 >> $YDEC;
            let area = width * height;
            // dynamic allocation: test
            let mut src = vec![0u8; area];
            // dynamic allocation: test
            let mut dst = Plane::from_slice(&vec![0u8; area], width);
            for (s, d) in src.iter_mut().zip(dst.data.iter_mut()) {
              *s = random::<u8>();
              *d = random::<u8>();
            }
            let mut rust_dst = dst.clone();

            let src_stride = width as isize;
            let pri_strength = 1;
            let sec_strength = 0;
            let damping = 2;
            let bit_depth = 8;

            unsafe {
              cdef_filter_block(&mut dst.as_region_mut(), src.as_ptr(), src_stride, pri_strength, sec_strength, dir, damping, bit_depth, $XDEC, $YDEC, CDEF_HAVE_NONE, CpuFeatureLevel::from_str($OPTLIT).unwrap());
              cdef_filter_block(&mut rust_dst.as_region_mut(), src.as_ptr(), src_stride, pri_strength, sec_strength, dir, damping, bit_depth, $XDEC, $YDEC, CDEF_HAVE_NONE, CpuFeatureLevel::RUST);
              assert_eq!(rust_dst.data_origin(), dst.data_origin());
            }
          }
        }
      )*
    }
  }

  test_cdef_fns!((1, 1), (1, 0), (0, 0), avx2, "avx2");
}
<commit_msg>Use the x86 8-bit CDEF assembly on edges<commit_after>// Copyright (c) 2019-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use crate::cdef::*;
use crate::cpu_features::CpuFeatureLevel;
use crate::frame::*;
use crate::tiling::PlaneRegionMut;
use crate::util::*;

type CdefFilterFn = unsafe extern fn(
  dst: *mut u8,
  dst_stride: isize,
  tmp: *const u16,
  tmp_stride: isize,
  pri_strength: i32,
  sec_strength: i32,
  dir: i32,
  damping: i32,
);

type CdefFilterHBDFn = unsafe extern fn(
  dst: *mut u16,
  dst_stride: isize,
  tmp: *const u16,
  tmp_stride: isize,
  pri_strength: i32,
  sec_strength: i32,
  dir: i32,
  damping: i32,
  bitdepth_max: i32,
);

#[inline(always)]
const fn decimate_index(xdec: usize, ydec: usize) -> usize {
  ((ydec << 1) | xdec) & 3
}

pub(crate) unsafe fn cdef_filter_block<T: Pixel>(
  dst: &mut PlaneRegionMut<'_, T>, src: *const T, src_stride: isize,
  pri_strength: i32, sec_strength: i32, dir: usize, damping: i32,
  bit_depth: usize, xdec: usize, ydec: usize, edges: u8, cpu: CpuFeatureLevel,
) {
  let call_rust = |dst: &mut PlaneRegionMut<T>| {
    rust::cdef_filter_block(
      dst,
      src,
      src_stride,
      pri_strength,
      sec_strength,
      dir,
      damping,
      bit_depth,
      xdec,
      ydec,
      edges,
      cpu,
    );
  };

  // TODO: handle padding in the fast path
  if edges != CDEF_HAVE_ALL && matches!(T::type_enum(), PixelType::U16) {
    call_rust(dst);
  } else {
    #[cfg(feature = "check_asm")]
    let ref_dst = {
      let mut copy = dst.scratch_copy();
      call_rust(&mut copy.as_region_mut());
      copy
    };
    match T::type_enum() {
      PixelType::U8 => {
        match CDEF_FILTER_FNS[cpu.as_index()][decimate_index(xdec, ydec)] {
          Some(func) => {
            // current cdef_filter_block asm does 16->8 for historical
            // reasons.  Copy into tmp space for now (also handling
            // padding) until asm is updated
            const TMPSTRIDE: isize =
              std::mem::align_of::<Aligned<u16>>() as isize;
            /* 256 or 512-bit alignment, greater than 2 * (8>>xdec) + 2 */
            const TMPSIZE: usize =
              ((2 + 8 + 2) * TMPSTRIDE + TMPSTRIDE) as usize;
            let mut tmp: Aligned<[u16; TMPSIZE]> =
              Aligned::new([CDEF_VERY_LARGE; TMPSIZE]);
            rust::pad_into_tmp16(
              tmp.data.as_mut_ptr().offset(TMPSTRIDE - 2), // points to
              // *padding* upper left; the -2 is to make sure the
              // block area is SIMD-aligned, not the padding
              TMPSTRIDE,
              src, // points to *block* upper left
              src_stride,
              8 >> xdec,
              8 >> ydec,
              edges,
            );
            (func)(
              dst.data_ptr_mut() as *mut _,
              T::to_asm_stride(dst.plane_cfg.stride),
              tmp.data.as_ptr().offset(3 * TMPSTRIDE) as *const u16,
              TMPSTRIDE,
              pri_strength,
              sec_strength,
              dir as i32,
              damping,
            );
          }
          None => call_rust(dst),
        }
      }
      PixelType::U16 => {
        match CDEF_FILTER_HBD_FNS[cpu.as_index()][decimate_index(xdec, ydec)] {
          Some(func) => {
            (func)(
              dst.data_ptr_mut() as *mut _,
              T::to_asm_stride(dst.plane_cfg.stride),
              src as *const _,
              src_stride,
              pri_strength,
              sec_strength,
              dir as i32,
              damping,
              (1 << bit_depth) - 1,
            );
          }
          None => call_rust(dst),
        }
      }
    }
    #[cfg(feature = "check_asm")]
    {
      for (dst_row, ref_row) in
        dst.rows_iter().zip(ref_dst.as_region().rows_iter())
      {
        for (dst, reference) in dst_row.iter().zip(ref_row) {
          assert_eq!(*dst, *reference);
        }
      }
    }
  }
}

extern {
  fn rav1e_cdef_filter_4x4_avx2(
    dst: *mut u8, dst_stride: isize, tmp: *const u16, tmp_stride: isize,
    pri_strength: i32, sec_strength: i32, dir: i32, damping: i32,
  );

  fn rav1e_cdef_filter_4x8_avx2(
    dst: *mut u8, dst_stride: isize, tmp: *const u16, tmp_stride: isize,
    pri_strength: i32, sec_strength: i32, dir: i32, damping: i32,
  );

  fn rav1e_cdef_filter_8x8_avx2(
    dst: *mut u8, dst_stride: isize, tmp: *const u16, tmp_stride: isize,
    pri_strength: i32, sec_strength: i32, dir: i32, damping: i32,
  );
}

static CDEF_FILTER_FNS_AVX2: [Option<CdefFilterFn>; 4] = {
  let mut out: [Option<CdefFilterFn>; 4] = [None; 4];
  out[decimate_index(1, 1)] = Some(rav1e_cdef_filter_4x4_avx2);
  out[decimate_index(1, 0)] = Some(rav1e_cdef_filter_4x8_avx2);
  out[decimate_index(0, 0)] = Some(rav1e_cdef_filter_8x8_avx2);
  out
};

cpu_function_lookup_table!(
  CDEF_FILTER_FNS: [[Option<CdefFilterFn>; 4]],
  default: [None; 4],
  [AVX2]
);

cpu_function_lookup_table!(
  CDEF_FILTER_HBD_FNS: [[Option<CdefFilterHBDFn>; 4]],
  default: [None; 4],
  []
);

type CdefDirLBDFn =
  unsafe extern fn(tmp: *const u8, tmp_stride: isize, var: *mut u32) -> i32;
type CdefDirHBDFn = unsafe extern fn(
  tmp: *const u16,
  tmp_stride: isize,
  var: *mut u32,
  bitdepth_max: i32,
) -> i32;

#[inline(always)]
#[allow(clippy::let_and_return)]
pub(crate) fn cdef_find_dir<T: Pixel>(
  img: &PlaneSlice<'_, T>, var: &mut u32, coeff_shift: usize,
  cpu: CpuFeatureLevel,
) -> i32 {
  let call_rust =
    |var: &mut u32| rust::cdef_find_dir::<T>(img, var, coeff_shift, cpu);

  #[cfg(feature = "check_asm")]
  let (ref_dir, ref_var) = {
    let mut var: u32 = 0;
    let dir = call_rust(&mut var);
    (dir, var)
  };

  let dir = match T::type_enum() {
    PixelType::U8 => {
      if let Some(func) = CDEF_DIR_LBD_FNS[cpu.as_index()] {
        unsafe {
          (func)(
            img.as_ptr() as *const _,
            T::to_asm_stride(img.plane.cfg.stride),
            var as *mut u32,
          )
        }
      } else {
        call_rust(var)
      }
    }
    PixelType::U16 => {
      if let Some(func) = CDEF_DIR_HBD_FNS[cpu.as_index()] {
        unsafe {
          (func)(
            img.as_ptr() as *const _,
            T::to_asm_stride(img.plane.cfg.stride),
            var as *mut u32,
            (1 << (coeff_shift + 8)) - 1,
          )
        }
      } else {
        call_rust(var)
      }
    }
  };

  #[cfg(feature = "check_asm")]
  {
    assert_eq!(dir, ref_dir);
    assert_eq!(*var, ref_var);
  }

  dir
}

extern {
  fn rav1e_cdef_dir_8bpc_avx2(
    tmp: *const u8, tmp_stride: isize, var: *mut u32,
  ) -> i32;
}

extern {
  fn rav1e_cdef_dir_16bpc_avx2(
    tmp: *const u16, tmp_stride: isize, var: *mut u32, bitdepth_max: i32,
  ) -> i32;
}

cpu_function_lookup_table!(
  CDEF_DIR_LBD_FNS: [Option<CdefDirLBDFn>],
  default: None,
  [(AVX2, Some(rav1e_cdef_dir_8bpc_avx2))]
);

cpu_function_lookup_table!(
  CDEF_DIR_HBD_FNS: [Option<CdefDirHBDFn>],
  default: None,
  [(AVX2, Some(rav1e_cdef_dir_16bpc_avx2))]
);

#[cfg(test)]
mod test {
  pub const CDEF_HAVE_NONE: u8 = 0;
  use super::*;
  use crate::frame::{AsRegion, Plane};
  use interpolate_name::interpolate_test;
  use rand::random;
  use std::str::FromStr;

  macro_rules! test_cdef_fns {
    ($(($XDEC:expr, $YDEC:expr)),*, $OPT:ident, $OPTLIT:literal) => {
      $(
        paste::item! {
          #[interpolate_test(dir_0, 0)]
          #[interpolate_test(dir_1, 1)]
          #[interpolate_test(dir_2, 2)]
          #[interpolate_test(dir_3, 3)]
          #[interpolate_test(dir_4, 4)]
          #[interpolate_test(dir_5, 5)]
          #[interpolate_test(dir_6, 6)]
          #[interpolate_test(dir_7, 7)]
          fn [<cdef_filter_block_dec_ $XDEC _ $YDEC _ $OPT>](dir: usize) {
            if !is_x86_feature_detected!($OPTLIT) {
              eprintln!("Ignoring {} test, not supported on this machine!", $OPTLIT);
              return;
            }

            let width = 8 >> $XDEC;
            let height = 8 >> $YDEC;
            let area = width * height;
            // dynamic allocation: test
            let mut src = vec![0u8; area];
            // dynamic allocation: test
            let mut dst = Plane::from_slice(&vec![0u8; area], width);
            for (s, d) in src.iter_mut().zip(dst.data.iter_mut()) {
              *s = random::<u8>();
              *d = random::<u8>();
            }
            let mut rust_dst = dst.clone();

            let src_stride = width as isize;
            let pri_strength = 1;
            let sec_strength = 0;
            let damping = 2;
            let bit_depth = 8;

            unsafe {
              cdef_filter_block(&mut dst.as_region_mut(), src.as_ptr(), src_stride, pri_strength, sec_strength, dir, damping, bit_depth, $XDEC, $YDEC, CDEF_HAVE_NONE, CpuFeatureLevel::from_str($OPTLIT).unwrap());
              cdef_filter_block(&mut rust_dst.as_region_mut(), src.as_ptr(), src_stride, pri_strength, sec_strength, dir, damping, bit_depth, $XDEC, $YDEC, CDEF_HAVE_NONE, CpuFeatureLevel::RUST);
              assert_eq!(rust_dst.data_origin(), dst.data_origin());
            }
          }
        }
      )*
    }
  }

  test_cdef_fns!((1, 1), (1, 0), (0, 0), avx2, "avx2");
}
<|endoftext|>


<commit_before>// NOTE: This may not work properly/at all. The compiler
// is the focus. It exist mainly for debugging: since it uses
// the same parser, it can separate parser/optimizer bugs from compiler
// bugs.

use std::env;
use std::io;
use std::io::prelude::*;
use std::fs::File;

extern crate isbfc;
use isbfc::Token;
use isbfc::Token::*;
use isbfc::parse;
use isbfc::optimize;

const BUFSIZE: usize = 8192;

fn interp_iter(mem: &mut [i32; BUFSIZE], cur: &mut usize, outbuff: &mut String, tokens: Vec<Token>) {
    for token in tokens {
        match token {
            Add(offset, value) => mem[(*cur as i32 + offset) as usize] += value,
            MulCopy(src, dest, mul) => {
                mem[(*cur as i32 + dest) as usize] += mem[(*cur as i32 + src) as usize] * mul
            }
            Set(offset, value) => mem[(*cur as i32 + offset) as usize] = value,
            Move(offset) => *cur = (*cur as i32 + offset) as usize,
            Loop(content) => {
                if mem[*cur] != 0 {
		    interp_iter(mem, cur, outbuff, content);
                }
            }
            If(offset, content) => {
                if mem[(*cur as i32 + offset) as usize] != 0 {
		    interp_iter(mem, cur, outbuff, content);
                }
            }
            Scan(offset) => {
                while mem[*cur] != 0 {
                    *cur = (*cur as i32 + offset) as usize;
                }
            }
            Input => {
                let mut buffer = [0; 1];
                io::stdin().take(1).read(&mut buffer).unwrap();
                mem[*cur] = buffer[0] as i32;
            }
            LoadOut(offset, add) => {
                outbuff.push((mem[(*cur as i32 + offset) as usize] + add) as u8 as char)
            }
            LoadOutSet(value) => outbuff.push(value as u8 as char),
            Output => {
                io::stdout().write(outbuff.as_bytes()).unwrap();
                io::stdout().flush().unwrap();
                outbuff.clear();
            }
        }
    }
}

fn main() {
    let path = env::args().nth(1).unwrap();
    let mut file = File::open(&path).unwrap();
    let mut code = String::new();
    file.read_to_string(&mut code).unwrap();

    let tokens = parse(code.as_str());
    let tokens = optimize(&tokens);

    let mut mem: [i32; BUFSIZE] = [0; BUFSIZE];
    let mut cur = BUFSIZE / 2;
    let mut outbuff = String::new();

    interp_iter(&mut mem, &mut cur, &mut outbuff, tokens);
}
<commit_msg>Fix loop in bfinterp<commit_after>// NOTE: This may not work properly/at all. The compiler
// is the focus. It exist mainly for debugging: since it uses
// the same parser, it can separate parser/optimizer bugs from compiler
// bugs.

use std::env;
use std::io;
use std::io::prelude::*;
use std::fs::File;

extern crate isbfc;
use isbfc::Token;
use isbfc::Token::*;
use isbfc::parse;
use isbfc::optimize;

const BUFSIZE: usize = 8192;

fn interp_iter(mem: &mut [i32; BUFSIZE], cur: &mut usize, outbuff: &mut String, tokens: &Vec<Token>) {
    for token in tokens {
        match *token {
            Add(offset, value) => mem[(*cur as i32 + offset) as usize] += value,
            MulCopy(src, dest, mul) => {
                mem[(*cur as i32 + dest) as usize] += mem[(*cur as i32 + src) as usize] * mul
            }
            Set(offset, value) => mem[(*cur as i32 + offset) as usize] = value,
            Move(offset) => *cur = (*cur as i32 + offset) as usize,
            Loop(ref content) => {
                while mem[*cur] != 0 {
		    interp_iter(mem, cur, outbuff, content);
                }
            }
            If(offset, ref content) => {
                if mem[(*cur as i32 + offset) as usize] != 0 {
		    interp_iter(mem, cur, outbuff, content);
                }
            }
            Scan(offset) => {
                while mem[*cur] != 0 {
                    *cur = (*cur as i32 + offset) as usize;
                }
            }
            Input => {
                let mut buffer = [0; 1];
                io::stdin().take(1).read(&mut buffer).unwrap();
                mem[*cur] = buffer[0] as i32;
            }
            LoadOut(offset, add) => {
                outbuff.push((mem[(*cur as i32 + offset) as usize] + add) as u8 as char)
            }
            LoadOutSet(value) => outbuff.push(value as u8 as char),
            Output => {
                io::stdout().write(outbuff.as_bytes()).unwrap();
                io::stdout().flush().unwrap();
                outbuff.clear();
            }
        }
    }
}

fn main() {
    let path = env::args().nth(1).unwrap();
    let mut file = File::open(&path).unwrap();
    let mut code = String::new();
    file.read_to_string(&mut code).unwrap();

    let tokens = parse(code.as_str());
    let tokens = optimize(&tokens);

    let mut mem: [i32; BUFSIZE] = [0; BUFSIZE];
    let mut cur = BUFSIZE / 2;
    let mut outbuff = String::new();

    interp_iter(&mut mem, &mut cur, &mut outbuff, &tokens);
}
<|endoftext|>


<commit_before>use std::cmp;
use std::io;
use std::io::BufRead;
use std::error::Error;

fn main() {
    let stdin = io::stdin();
    let mut ns: Vec<f64> = match read_floats(&mut stdin.lock()) {
        Ok(ns) => ns,
        Err(e) => panic!("failed to read numbers: {}", e),
    };

    ns.sort_by(|a, b| a.partial_cmp(b).unwrap_or(cmp::Ordering::Equal));

    let count = ns.len();

    let sum = ns.iter().fold(0.0, |a, &b| a + b);

    println!("count: {}", count);
    println!("sum:   {}", sum);

    if ns.is_empty() {
        println!("(empty set of numbers, remaining stats not available)");
    } else {
        println!("avg:   {}", sum/count as f64);
        println!("max:   {}", ns[count - 1]);
        println!("p999:  {}", ns[ns.len() * 999/1000]);
        println!("p99:   {}", ns[ns.len() * 99/100]);
        println!("p90:   {}", ns[ns.len() * 90/100]);
        println!("p50:   {}", ns[ns.len() * 50/100]);
        println!("min:   {}", ns[0]);
    }
}

fn read_floats(input: &mut io::BufRead) -> Result<Vec<f64>, Box<Error>> {
    let mut ns: Result<Vec<f64>, Box<Error>> = input
        .lines()
        .map(|line| -> Result<f64, Box<Error>> {
            Ok(line?.parse::<f64>()?)
        })
        .collect();

    ns
}
<commit_msg>Remove unnecessary mut.<commit_after>use std::cmp;
use std::io;
use std::io::BufRead;
use std::error::Error;

fn main() {
    let stdin = io::stdin();
    let mut ns: Vec<f64> = match read_floats(&mut stdin.lock()) {
        Ok(ns) => ns,
        Err(e) => panic!("failed to read numbers: {}", e),
    };

    ns.sort_by(|a, b| a.partial_cmp(b).unwrap_or(cmp::Ordering::Equal));

    let count = ns.len();

    let sum = ns.iter().fold(0.0, |a, &b| a + b);

    println!("count: {}", count);
    println!("sum:   {}", sum);

    if ns.is_empty() {
        println!("(empty set of numbers, remaining stats not available)");
    } else {
        println!("avg:   {}", sum/count as f64);
        println!("max:   {}", ns[count - 1]);
        println!("p999:  {}", ns[ns.len() * 999/1000]);
        println!("p99:   {}", ns[ns.len() * 99/100]);
        println!("p90:   {}", ns[ns.len() * 90/100]);
        println!("p50:   {}", ns[ns.len() * 50/100]);
        println!("min:   {}", ns[0]);
    }
}

fn read_floats(input: &mut io::BufRead) -> Result<Vec<f64>, Box<Error>> {
    let ns: Result<Vec<f64>, Box<Error>> = input
        .lines()
        .map(|line| -> Result<f64, Box<Error>> {
            Ok(line?.parse::<f64>()?)
        })
        .collect();

    ns
}
<|endoftext|>


<commit_before>extern crate arguments;
extern crate configuration;
extern crate random;
extern crate sql;
extern crate sqlite;
extern crate term;
extern crate time;

#[macro_use]
extern crate log;

#[macro_use]
extern crate streamer;

use configuration::format::TOML;
use log::LogLevel;
use streamer::{platform, schedule, system, traffic, workload};

pub use streamer::{Config, Error, Result};

pub type Data = (platform::Profile, platform::Profile);
pub type Event = system::Event;

pub type System = system::System<traffic::Fractal,
                                 workload::Random,
                                 platform::Thermal,
                                 schedule::Impartial>;

const USAGE: &'static str = "
Usage: streamer [options]

Options:
    --config <path>          Configuration file (required).
    --length <time>          Time span to synthesize in seconds [default: 10].
    --output <path>          Output file for power and temperature profiles.

    --verbose                Display progress information.
    --help                   Display this message.
";

mod logger;
mod output;

use output::Output;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = ok!(arguments::parse(std::env::args()));
    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }
    if arguments.get::<bool>("verbose").unwrap_or(false) {
        logger::setup(LogLevel::Info);
    } else {
        logger::setup(LogLevel::Warn);
    }

    let config = ok!(TOML::open(some!(arguments.get::<String>("config"),
                                      "a configuration file is required")));

    let mut system = try!(construct_system(&config));
    let mut output = try!(output::new(&system, arguments.get::<String>("output")));

    let length = arguments.get::<f64>("length").unwrap_or(10.0);
    info!(target: "Streamer", "Synthesizing {} seconds...", length);
    let start = time::now();

    while let Some((event, data)) = try!(system.next()) {
        display(&system, &event);
        try!(output.next(&event, &data));
        if event.time > length {
            break;
        }
    }

    let elapsed = time::now() - start;
    info!(target: "Streamer", "Well done in {:.2} seconds.",
          elapsed.num_milliseconds() as f64 / 1000.0);

    Ok(())
}

fn construct_system(config: &Config) -> Result<System> {
    let source = {
        let seed = config.get::<i64>("seed").map(|&seed| seed as u64).unwrap_or(0);
        let seed = if seed > 0 { seed } else { time::now().to_timespec().sec as u64 };
        let seed = [0x12345678 & seed, 0x87654321 & seed];
        random::default().seed(seed)
    };

    macro_rules! branch(($name:expr) => (config.branch($name).as_ref().unwrap_or(config)));

    let traffic = try!(traffic::Fractal::new(branch!("traffic"), &source));
    let workload = try!(workload::Random::new(branch!("workload"), &source));
    let platform = try!(platform::Thermal::new(branch!("platform")));
    let schedule = try!(schedule::Impartial::new(branch!("schedule"), &platform));

    System::new(traffic, workload, platform, schedule)
}

fn display(system: &System, event: &Event) {
    use streamer::system::EventKind;

    let (job, kind) = match &event.kind {
        &EventKind::Arrived(ref job) => (job, "arrived"),
        &EventKind::Started(ref job) => (job, "started"),
        &EventKind::Finished(ref job) => (job, "finished"),
    };
    info!(target: "Streamer",
          "{:7.2} s | job #{:4} ( {:20} | {:2} units | {:6.2} s ) {:8} | {:2} queued",
          event.time, job.id, job.name, job.units, job.duration(), kind,
          system.history().arrived - system.history().started);
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

#[allow(unused_must_use)]
fn fail(error: Error) -> ! {
    use std::io::Write;
    if let Some(mut output) = term::stderr() {
        output.fg(term::color::RED);
        output.write_all(format!("Error: {}.\n", error).as_bytes());
    }
    std::process::exit(1);
}
<commit_msg>bin: adjust --verbose’s output<commit_after>extern crate arguments;
extern crate configuration;
extern crate random;
extern crate sql;
extern crate sqlite;
extern crate term;
extern crate time;

#[macro_use]
extern crate log;

#[macro_use]
extern crate streamer;

use configuration::format::TOML;
use log::LogLevel;
use streamer::{platform, schedule, system, traffic, workload};

pub use streamer::{Config, Error, Result};

pub type Data = (platform::Profile, platform::Profile);
pub type Event = system::Event;

pub type System = system::System<traffic::Fractal,
                                 workload::Random,
                                 platform::Thermal,
                                 schedule::Impartial>;

const USAGE: &'static str = "
Usage: streamer [options]

Options:
    --config <path>          Configuration file (required).
    --length <time>          Time span to synthesize in seconds [default: 10].
    --output <path>          Output file for power and temperature profiles.

    --verbose                Display progress information.
    --help                   Display this message.
";

mod logger;
mod output;

use output::Output;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = ok!(arguments::parse(std::env::args()));
    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }
    if arguments.get::<bool>("verbose").unwrap_or(false) {
        logger::setup(LogLevel::Info);
    } else {
        logger::setup(LogLevel::Warn);
    }

    let config = ok!(TOML::open(some!(arguments.get::<String>("config"),
                                      "a configuration file is required")));

    let mut system = try!(construct_system(&config));
    let mut output = try!(output::new(&system, arguments.get::<String>("output")));

    let length = arguments.get::<f64>("length").unwrap_or(10.0);
    info!(target: "Streamer", "Synthesizing {} seconds...", length);
    let start = time::now();

    while let Some((event, data)) = try!(system.next()) {
        display(&system, &event);
        try!(output.next(&event, &data));
        if event.time > length {
            break;
        }
    }

    let elapsed = time::now() - start;
    info!(target: "Streamer", "Well done in {:.2} seconds.",
          elapsed.num_milliseconds() as f64 / 1000.0);

    Ok(())
}

fn construct_system(config: &Config) -> Result<System> {
    let source = {
        let seed = config.get::<i64>("seed").map(|&seed| seed as u64).unwrap_or(0);
        let seed = if seed > 0 { seed } else { time::now().to_timespec().sec as u64 };
        let seed = [0x12345678 & seed, 0x87654321 & seed];
        random::default().seed(seed)
    };

    macro_rules! branch(($name:expr) => (config.branch($name).as_ref().unwrap_or(config)));

    let traffic = try!(traffic::Fractal::new(branch!("traffic"), &source));
    let workload = try!(workload::Random::new(branch!("workload"), &source));
    let platform = try!(platform::Thermal::new(branch!("platform")));
    let schedule = try!(schedule::Impartial::new(branch!("schedule"), &platform));

    System::new(traffic, workload, platform, schedule)
}

fn display(system: &System, event: &Event) {
    use streamer::system::EventKind;

    let (job, kind) = match &event.kind {
        &EventKind::Arrived(ref job) => (job, "arrived"),
        &EventKind::Started(ref job) => (job, "started"),
        &EventKind::Finished(ref job) => (job, "finished"),
    };
    info!(target: "Streamer",
          "{:8.2} s | job #{:4} ( {:20} | {:2} units | {:6.2} s ) {:8} | {:2} queued",
          event.time, job.id, job.name, job.units, job.duration(), kind,
          system.history().arrived - system.history().started);
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

#[allow(unused_must_use)]
fn fail(error: Error) -> ! {
    use std::io::Write;
    if let Some(mut output) = term::stderr() {
        output.fg(term::color::RED);
        output.write_all(format!("Error: {}.\n", error).as_bytes());
    }
    std::process::exit(1);
}
<|endoftext|>


<commit_before>use super::BrotliEncoderParams;
use std::io::{self, Error, ErrorKind, Read, Write};
use super::{Rebox, HeapAllocator, IoWriterWrapper};
use brotli::{DecompressorWriterCustomIo, CustomWrite};
use alloc_no_stdlib::{Allocator, SliceWrapper};

struct Tee<OutputA:Write, OutputB:Write>(OutputA, OutputB);
impl <OutputA:Write, OutputB:Write> Write for Tee<OutputA, OutputB> {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        match self.0.write(data) {
            Err(err) => return Err(err),
            Ok(size) => match self.1.write_all(&data[..size]) {
                Ok(_) => Ok(size),
                Err(err) => Err(err),
            }
        }
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        match self.0.flush() {
            Err(err) => return Err(err),
            Ok(_) => {
                loop {
                    match self.1.flush() {
                        Err(e) => match e.kind() {
                            ErrorKind::Interrupted => continue,
                            _ => return Err(e),
                        }
                        Ok(e) => return Ok(e),
                    }
                }
            },
        }
    }
}

struct DecompressAndValidate<'a, OutputType:Write+'a>(
    DecompressorWriterCustomIo<io::Error,
                               IoWriterWrapper<'a, OutputType>,
                               Rebox<u8>, // buffer type
                               HeapAllocator,
                               HeapAllocator,
                               HeapAllocator>
);

impl<'a, OutputType:Write> Write for DecompressAndValidate<'a, OutputType> {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        self.0.write(data)
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        self.0.flush()
    }
}

fn make_sha_writer() -> io::Sink {
    io::sink()
}

fn make_sha_reader<InputType:Read>(r:&mut InputType) -> &mut InputType {
    r
}

fn sha_ok<InputType:Read>(_writer: io::Sink, _reader: &mut InputType) -> bool {
    false
}

struct ShaReader<InputType:Read> {
    reader:InputType,
}

pub fn compress_validate<InputType:Read, OutputType: Write>(r: &mut InputType,
                                                            w: &mut OutputType,
                                                            buffer_size: usize,
                                                            params: &BrotliEncoderParams,
                                                            custom_dictionary:Rebox<u8>,
                                                            num_threads: usize) -> Result<(), io::Error> {
    let mut m8 = HeapAllocator::default();
    let buffer = <HeapAllocator as Allocator<u8>>::alloc_cell(&mut m8, buffer_size);
    // FIXME: could reuse the dictionary to seed the compressor, but that violates the abstraction right now
    // also dictionaries are not very popular since they are mostly an internal concept, given their deprecation in
    // the standard brotli spec
    let mut dict = Vec::<u8>::new();

    dict.extend_from_slice(custom_dictionary.slice());
    let mut sha_writer = make_sha_writer();
    let mut sha_reader = make_sha_reader(r);
    let ret;
    {
        let validate_writer = DecompressAndValidate(DecompressorWriterCustomIo::new_with_custom_dictionary(
            IoWriterWrapper(&mut sha_writer),
            buffer,
            m8,
            HeapAllocator::default(),
            HeapAllocator::default(),
            custom_dictionary,
            Error::new(ErrorKind::InvalidData,
                       "Invalid Data")));
        let mut overarching_writer = Tee(validate_writer, w);
        ret = super::compress(sha_reader, &mut overarching_writer, buffer_size, params, &dict[..], num_threads);
    }
    match ret {
        Ok(_ret) => {
            if sha_ok(sha_writer, sha_reader) {
                return Ok(());
            } else {
                return Err(Error::new(ErrorKind::InvalidData, "Validation failed"));
            }
        },
        Err(e) => Err(e),
    }
}
<commit_msg>validation phase complete<commit_after>use std::io::{self, Error, ErrorKind, Read, Write};
use super::{Rebox, HeapAllocator, IoWriterWrapper};
use brotli::{DecompressorWriterCustomIo, CustomWrite};
use alloc_no_stdlib::{Allocator, SliceWrapper};
use brotli::enc::BrotliEncoderParams;
#[cfg(feature="validation")]
use sha2::{Sha256, Digest};
#[cfg(feature="validation")]
type Checksum = Sha256;

struct Tee<OutputA:Write, OutputB:Write>(OutputA, OutputB);
impl <OutputA:Write, OutputB:Write> Write for Tee<OutputA, OutputB> {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        match self.0.write(data) {
            Err(err) => return Err(err),
            Ok(size) => match self.1.write_all(&data[..size]) {
                Ok(_) => Ok(size),
                Err(err) => Err(err),
            }
        }
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        match self.0.flush() {
            Err(err) => return Err(err),
            Ok(_) => {
                loop {
                    match self.1.flush() {
                        Err(e) => match e.kind() {
                            ErrorKind::Interrupted => continue,
                            _ => return Err(e),
                        },
                        Ok(e) => return Ok(e),
                    }
                }
            },
        }
    }
}

struct DecompressAndValidate<'a, OutputType:Write+'a>(
    DecompressorWriterCustomIo<io::Error,
                               IoWriterWrapper<'a, OutputType>,
                               Rebox<u8>, // buffer type
                               HeapAllocator,
                               HeapAllocator,
                               HeapAllocator>
);

impl<'a, OutputType:Write> Write for DecompressAndValidate<'a, OutputType> {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        self.0.write(data)
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        self.0.flush()
    }
}

#[cfg(not(feature="validation"))]
fn make_sha_writer() -> io::Sink {
    io::sink()
}
#[cfg(not(feature="validation"))]
fn make_sha_reader<InputType:Read>(r:&mut InputType) -> &mut InputType {
    r
}

#[cfg(not(feature="validation"))]
fn sha_ok<InputType:Read>(_writer: &mut io::Sink, _reader: &mut InputType) -> bool {
    false
}

#[cfg(feature="validation")]
struct ShaReader<'a, InputType:Read> {
    reader:&'a mut InputType,
    checksum:Checksum,
}
#[cfg(feature="validation")]
impl<'a, InputType:Read> Read for ShaReader<'a, InputType> {
    fn read(&mut self, data: &mut [u8]) -> Result<usize, io::Error> {
        match self.reader.read(data) {
            Err(e) => Err(e),
            Ok(size) => {
                self.checksum.input(&data[..size]);
                Ok(size)
            },
        }
    }
}
#[cfg(feature="validation")]
fn make_sha_reader<InputType:Read>(r:&mut InputType) -> ShaReader<InputType> {
    ShaReader{
        reader:r,
        checksum:Checksum::default(),
    }
}

#[cfg(feature="validation")]
fn sha_ok<InputType:Read>(writer: &mut ShaWriter, reader: &mut ShaReader<InputType>) -> bool {
    core::mem::replace(&mut writer.0,
                       Checksum::default()).result() == core::mem::replace(&mut reader.checksum,
                                                                           Checksum::default()).result()
}
#[cfg(feature="validation")]
#[derive(Default)]
struct ShaWriter(Checksum);
#[cfg(feature="validation")]
impl Write for ShaWriter {
    fn write(&mut self, data:&[u8]) -> Result<usize, io::Error> {
        self.0.input(data);
        Ok(data.len())
    }
    fn flush(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}
#[cfg(feature="validation")]
fn make_sha_writer() -> ShaWriter {
    ShaWriter::default()
}

pub fn compress_validate<InputType:Read, OutputType: Write>(r: &mut InputType,
                                                            w: &mut OutputType,
                                                            buffer_size: usize,
                                                            params: &BrotliEncoderParams,
                                                            custom_dictionary:Rebox<u8>,
                                                            num_threads: usize) -> Result<(), io::Error> {
    let mut m8 = HeapAllocator::default();
    let buffer = <HeapAllocator as Allocator<u8>>::alloc_cell(&mut m8, buffer_size);
    // FIXME: could reuse the dictionary to seed the compressor, but that violates the abstraction right now
    // also dictionaries are not very popular since they are mostly an internal concept, given their deprecation in
    // the standard brotli spec
    let mut dict = Vec::<u8>::new();

    dict.extend_from_slice(custom_dictionary.slice());
    let mut sha_writer = make_sha_writer();
    let mut sha_reader = make_sha_reader(r);
    let ret;
    {
        let validate_writer = DecompressAndValidate(DecompressorWriterCustomIo::new_with_custom_dictionary(
            IoWriterWrapper(&mut sha_writer),
            buffer,
            m8,
            HeapAllocator::default(),
            HeapAllocator::default(),
            custom_dictionary,
            Error::new(ErrorKind::InvalidData,
                       "Invalid Data")));
        let mut overarching_writer = Tee(validate_writer, w);
        ret = super::compress(&mut sha_reader, &mut overarching_writer, buffer_size, params, &dict[..], num_threads);
    }
    match ret {
        Ok(_ret) => {
            if sha_ok(&mut sha_writer, &mut sha_reader) {
                return Ok(());
            } else {
                return Err(Error::new(ErrorKind::InvalidData, "Validation failed"));
            }
        },
        Err(e) => Err(e),
    }
}
<|endoftext|>


<commit_before>#[feature(macro_rules)];
#[crate_id = "codegen#0.1"];

use std::os;
use std::io::buffered::BufferedWriter;
use std::io::File;
use std::io;
use std::io::stdio::println;
use std::io::fs::mkdir_recursive;
use std::path::GenericPath;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args[2].clone());
            // TODO: maybe not 0777?
            mkdir_recursive(&output_dir, 0b111_111_111);

            match args[1] {
                ~"keycode.rs" => keycode::generate(&output_dir),
                ~"scancode.rs" => scancode::generate(&output_dir),
                s => {
                    println!("unknown thing-to-generate '{}'", s);
                    os::set_exit_status(1);
                }
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args[0]);
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~BufferedWriter<File> {
    match File::open_mode(&output_dir.join(filename), io::Truncate, io::Write) {
        Some(writer) => ~BufferedWriter::new(writer),
        None => fail!("Unable to write file"),
    }
}
<commit_msg>println is not in prelude anymore, the println! macro should be used<commit_after>#[feature(macro_rules)];
#[crate_id = "codegen#0.1"];

use std::os;
use std::io::buffered::BufferedWriter;
use std::io::File;
use std::io;
use std::io::stdio::println;
use std::io::fs::mkdir_recursive;
use std::path::GenericPath;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println!("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args[2].clone());
            // TODO: maybe not 0777?
            mkdir_recursive(&output_dir, 0b111_111_111);

            match args[1] {
                ~"keycode.rs" => keycode::generate(&output_dir),
                ~"scancode.rs" => scancode::generate(&output_dir),
                s => {
                    println!("unknown thing-to-generate '{}'", s);
                    os::set_exit_status(1);
                }
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args[0]);
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~BufferedWriter<File> {
    match File::open_mode(&output_dir.join(filename), io::Truncate, io::Write) {
        Some(writer) => ~BufferedWriter::new(writer),
        None => fail!("Unable to write file"),
    }
}
<|endoftext|>


<commit_before>/// Asserts that constant expressions evaluate to `true`.
///
/// Constant expressions can be ensured to have certain properties via this
/// macro If the expression evaluates to `false`, the file will fail to compile.
/// This is synonymous to [`static_assert` in C++][static_assert].
///
/// # Alternatives
///
/// There also exists [`const_assert_eq`](macro.const_assert_eq.html) for
/// validating whether a sequence of expressions are equal to one another.
///
/// # Examples
///
/// A common use case is to guarantee properties about a constant value that's
/// generated via meta-programming.
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const VALUE: i32 = // ...
/// # 3;
///
/// const_assert!(VALUE >= 2);
/// ```
///
/// Inputs are type-checked as booleans:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert!(!0);
/// ```
///
/// Despite this being a macro, we see this produces a type error:
///
/// ```txt
///   | const_assert!(!0);
///   |               ^^ expected bool, found integral variable
///   |
///   = note: expected type `bool`
///              found type `{integer}`
/// ```
///
/// The following fails to compile because multiplying by 5 does not have an
/// identity property:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert!(5 * 5 == 5);
/// ```
///
/// [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
#[macro_export(local_inner_macros)]
macro_rules! const_assert {
    ($x:expr $(,)?) => {
        const _: $crate::True = _to_bool!($x);
    };
}

/// Asserts that constants are equal in value.
///
/// Use [`const_assert_eq_usize!`](macro.const_assert_eq_usize.html) for better
/// error messages when asserting
/// [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) equality.
///
/// # Examples
///
/// This works as a shorthand for `const_assert!(a == b)`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const TWO: i32 = 2;
///
/// const_assert_eq!(TWO * TWO, TWO + TWO);
/// ```
///
/// Just because 2 × 2 = 2 + 2 doesn't mean it holds true for other numbers:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert_eq!(4 + 4, 4 * 4);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! const_assert_eq {
    ($x:expr, $y:expr $(,)?) => {
        const_assert!($x == $y);
    };
}

/// Asserts that constants of type
/// [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) are equal in
/// value.
///
/// This is equivalent to [`const_assert_eq!`](macro.const_assert_eq.html) but
/// allows for inspecting the values in error messages.
#[macro_export]
macro_rules! const_assert_eq_usize {
    ($x:expr, $($y:expr),+ $(,)?) => {
        // Assigned instance must match the annotated type or else it will fail.
        $(const _: [(); $x] = [(); $y];)+
    };
}

/// Asserts that constants are **not** equal in value.
///
/// # Examples
///
/// This works as a shorthand for `const_assert!(a != b)`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const NUM: usize = 32;
///
/// const_assert_ne!(NUM * NUM, 64);
/// ```
///
/// The following example fails to compile because 2 is magic and 2 × 2 = 2 + 2:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert_ne!(2 + 2, 2 * 2);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! const_assert_ne {
    ($x:expr, $y:expr $(,)?) => {
        const_assert!($x != $y);
    };
}
<commit_msg>Allow `const_assert_{eq,ne}!` to take 2+ arguments<commit_after>/// Asserts that constant expressions evaluate to `true`.
///
/// Constant expressions can be ensured to have certain properties via this
/// macro If the expression evaluates to `false`, the file will fail to compile.
/// This is synonymous to [`static_assert` in C++][static_assert].
///
/// # Alternatives
///
/// There also exists [`const_assert_eq`](macro.const_assert_eq.html) for
/// validating whether a sequence of expressions are equal to one another.
///
/// # Examples
///
/// A common use case is to guarantee properties about a constant value that's
/// generated via meta-programming.
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const VALUE: i32 = // ...
/// # 3;
///
/// const_assert!(VALUE >= 2);
/// ```
///
/// Inputs are type-checked as booleans:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert!(!0);
/// ```
///
/// Despite this being a macro, we see this produces a type error:
///
/// ```txt
///   | const_assert!(!0);
///   |               ^^ expected bool, found integral variable
///   |
///   = note: expected type `bool`
///              found type `{integer}`
/// ```
///
/// The following fails to compile because multiplying by 5 does not have an
/// identity property:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert!(5 * 5 == 5);
/// ```
///
/// [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
#[macro_export(local_inner_macros)]
macro_rules! const_assert {
    ($x:expr $(,)?) => {
        const _: $crate::True = _to_bool!($x);
    };
}

/// Asserts that constants are equal in value.
///
/// Use [`const_assert_eq_usize!`](macro.const_assert_eq_usize.html) for better
/// error messages when asserting
/// [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) equality.
///
/// # Examples
///
/// This works as a shorthand for `const_assert!(a == b)`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const TWO: i32 = 2;
///
/// const_assert_eq!(TWO * TWO, TWO + TWO);
/// ```
///
/// Just because 2 × 2 = 2 + 2 doesn't mean it holds true for other numbers:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert_eq!(4 + 4, 4 * 4);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! const_assert_eq {
    ($x:expr, $($y:expr),+ $(,)?) => {
        const_assert!($($x == $y)&&+);
    };
}

/// Asserts that constants of type
/// [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) are equal in
/// value.
///
/// This is equivalent to [`const_assert_eq!`](macro.const_assert_eq.html) but
/// allows for inspecting the values in error messages.
#[macro_export]
macro_rules! const_assert_eq_usize {
    ($x:expr, $($y:expr),+ $(,)?) => {
        // Assigned instance must match the annotated type or else it will fail.
        $(const _: [(); $x] = [(); $y];)+
    };
}

/// Asserts that constants are **not** equal in value.
///
/// # Examples
///
/// This works as a shorthand for `const_assert!(a != b)`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const NUM: usize = 32;
///
/// const_assert_ne!(NUM * NUM, 64);
/// ```
///
/// The following example fails to compile because 2 is magic and 2 × 2 = 2 + 2:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// const_assert_ne!(2 + 2, 2 * 2);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! const_assert_ne {
    ($x:expr, $($y:expr),+ $(,)?) => {
        const_assert!($($x != $y)&&+);
    };
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// 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 uuid::Uuid;

use config::action::ActionType;
use conditions::Conditions;

pub struct BaseContext {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<ActionType>,
}

impl BaseContext {
    pub fn conditions(&self) -> &Conditions {
        &self.conditions
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn name(&self) -> Option<&String> {
        self.name.as_ref()
    }

    pub fn actions(&self) -> &[ActionType] {
        &self.actions
    }
}

pub struct BaseContextBuilder {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<ActionType>,
}

impl BaseContextBuilder {
    pub fn new(uuid: Uuid, conditions: Conditions) -> BaseContextBuilder {
        BaseContextBuilder {
            name: None,
            uuid: uuid,
            conditions: conditions,
            actions: Vec::new(),
        }
    }

    pub fn name(mut self, name: Option<String>) -> BaseContextBuilder {
        self.name = name;
        self
    }

    pub fn actions(mut self, actions: Vec<ActionType>) -> BaseContextBuilder {
        self.actions = actions;
        self
    }

    pub fn build(self) -> BaseContext {
        let BaseContextBuilder {name, uuid, conditions, actions} = self;
        BaseContext {
            name: name,
            uuid: uuid,
            conditions: conditions,
            actions: actions,
        }
    }
}
<commit_msg>BaseContext: add patterns field<commit_after>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// 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 uuid::Uuid;

use config::action::ActionType;
use conditions::Conditions;

pub struct BaseContext {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<ActionType>,
    patterns: Vec<String>,
}

impl BaseContext {
    pub fn conditions(&self) -> &Conditions {
        &self.conditions
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn name(&self) -> Option<&String> {
        self.name.as_ref()
    }

    pub fn actions(&self) -> &[ActionType] {
        &self.actions
    }
}

pub struct BaseContextBuilder {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<ActionType>,
    patterns: Vec<String>
}

impl BaseContextBuilder {
    pub fn new(uuid: Uuid, conditions: Conditions) -> BaseContextBuilder {
        BaseContextBuilder {
            name: None,
            uuid: uuid,
            conditions: conditions,
            actions: Vec::new(),
            patterns: Vec::new()
        }
    }

    pub fn name(mut self, name: Option<String>) -> BaseContextBuilder {
        self.name = name;
        self
    }

    pub fn actions(mut self, actions: Vec<ActionType>) -> BaseContextBuilder {
        self.actions = actions;
        self
    }

    pub fn patterns(mut self, patterns: Vec<String>) -> BaseContextBuilder {
        self.patterns = patterns;
        self
    }
    pub fn build(self) -> BaseContext {
        let BaseContextBuilder {name, uuid, conditions, actions, patterns} = self;
        BaseContext {
            name: name,
            uuid: uuid,
            conditions: conditions,
            actions: actions,
            patterns: patterns
        }
    }
}
<|endoftext|>


<commit_before>use crate::ops::Try;

/// Used to make try_fold closures more like normal loops
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<C, B> {
    /// Continue in the loop, using the given value for the next iteration
    Continue(C),
    /// Exit the loop, yielding the given value
    Break(B),
}

#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
impl<C, B> Try for ControlFlow<C, B> {
    type Ok = C;
    type Error = B;
    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            ControlFlow::Continue(y) => Ok(y),
            ControlFlow::Break(x) => Err(x),
        }
    }
    #[inline]
    fn from_error(v: Self::Error) -> Self {
        ControlFlow::Break(v)
    }
    #[inline]
    fn from_ok(v: Self::Ok) -> Self {
        ControlFlow::Continue(v)
    }
}

impl<C, B> ControlFlow<C, B> {
    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
    /// `ControlFlow` was `Break` and `None` otherwise.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn break_value(self) -> Option<B> {
        match self {
            ControlFlow::Continue(..) => None,
            ControlFlow::Break(x) => Some(x),
        }
    }
}

impl<R: Try> ControlFlow<R::Ok, R> {
    /// Create a `ControlFlow` from any type implementing `Try`.
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    #[inline]
    pub fn from_try(r: R) -> Self {
        match Try::into_result(r) {
            Ok(v) => ControlFlow::Continue(v),
            Err(v) => ControlFlow::Break(Try::from_error(v)),
        }
    }

    /// Convert a `ControlFlow` into any type implementing `Try`;
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    #[inline]
    pub fn into_try(self) -> R {
        match self {
            ControlFlow::Continue(v) => Try::from_ok(v),
            ControlFlow::Break(v) => v,
        }
    }
}

impl<B> ControlFlow<(), B> {
    /// It's frequently the case that there's no value needed with `Continue`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
    ///     partial_sum += x;
    ///     if partial_sum > 100 { ControlFlow::Break(x) }
    ///     else { ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(last_used.break_value(), Some(22));
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const CONTINUE: Self = ControlFlow::Continue(());
}

impl<C> ControlFlow<C, ()> {
    /// APIs like `try_for_each` don't need values with `Break`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// (1..10).chain(20..25).try_for_each(|x| {
    ///     if partial_sum > 100 { ControlFlow::BREAK }
    ///     else { partial_sum += x; ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(partial_sum, 108);
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const BREAK: Self = ControlFlow::Break(());
}
<commit_msg>Add `ControlFlow::is_{break,continue}` methods<commit_after>use crate::ops::Try;

/// Used to make try_fold closures more like normal loops
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<C, B> {
    /// Continue in the loop, using the given value for the next iteration
    Continue(C),
    /// Exit the loop, yielding the given value
    Break(B),
}

#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
impl<C, B> Try for ControlFlow<C, B> {
    type Ok = C;
    type Error = B;
    #[inline]
    fn into_result(self) -> Result<Self::Ok, Self::Error> {
        match self {
            ControlFlow::Continue(y) => Ok(y),
            ControlFlow::Break(x) => Err(x),
        }
    }
    #[inline]
    fn from_error(v: Self::Error) -> Self {
        ControlFlow::Break(v)
    }
    #[inline]
    fn from_ok(v: Self::Ok) -> Self {
        ControlFlow::Continue(v)
    }
}

impl<C, B> ControlFlow<C, B> {
    /// Returns `true` if this is a `Break` variant.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_break(&self) -> bool {
        matches!(*self, ControlFlow::Break(_))
    }

    /// Returns `true` if this is a `Continue` variant.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn is_continue(&self) -> bool {
        matches!(*self, ControlFlow::Continue(_))
    }

    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
    /// `ControlFlow` was `Break` and `None` otherwise.
    #[inline]
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub fn break_value(self) -> Option<B> {
        match self {
            ControlFlow::Continue(..) => None,
            ControlFlow::Break(x) => Some(x),
        }
    }
}

impl<R: Try> ControlFlow<R::Ok, R> {
    /// Create a `ControlFlow` from any type implementing `Try`.
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    #[inline]
    pub fn from_try(r: R) -> Self {
        match Try::into_result(r) {
            Ok(v) => ControlFlow::Continue(v),
            Err(v) => ControlFlow::Break(Try::from_error(v)),
        }
    }

    /// Convert a `ControlFlow` into any type implementing `Try`;
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    #[inline]
    pub fn into_try(self) -> R {
        match self {
            ControlFlow::Continue(v) => Try::from_ok(v),
            ControlFlow::Break(v) => v,
        }
    }
}

impl<B> ControlFlow<(), B> {
    /// It's frequently the case that there's no value needed with `Continue`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// let last_used = (1..10).chain(20..25).try_for_each(|x| {
    ///     partial_sum += x;
    ///     if partial_sum > 100 { ControlFlow::Break(x) }
    ///     else { ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(last_used.break_value(), Some(22));
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const CONTINUE: Self = ControlFlow::Continue(());
}

impl<C> ControlFlow<C, ()> {
    /// APIs like `try_for_each` don't need values with `Break`,
    /// so this provides a way to avoid typing `(())`, if you prefer it.
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(control_flow_enum)]
    /// use std::ops::ControlFlow;
    ///
    /// let mut partial_sum = 0;
    /// (1..10).chain(20..25).try_for_each(|x| {
    ///     if partial_sum > 100 { ControlFlow::BREAK }
    ///     else { partial_sum += x; ControlFlow::CONTINUE }
    /// });
    /// assert_eq!(partial_sum, 108);
    /// ```
    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
    pub const BREAK: Self = ControlFlow::Break(());
}
<|endoftext|>


<commit_before>use Value;

use util;
use ffi;
use libc;

struct Method {
    name: String,
    func: *mut extern fn() -> Value,
    arg_count: i8,
}

struct Constant(String, Value);

struct Alias {
    new_name: String,
    original_name: String,
}

struct Accessor {
    name: String,
    reader: bool,
    writer: bool,
}

/// A class builder.
pub struct Class
{
    name: String,
    base_class: Value,
    parent: Option<Value>,

    methods: Vec<Method>,
    singleton_methods: Vec<Method>,

    included_modules: Vec<Value>,
    prepended_modules: Vec<Value>,
    constants: Vec<Constant>,
    aliases: Vec<Alias>,
    accessors: Vec<Accessor>,
}

impl Class {
    pub fn new<S>(name: S) -> Self where S: Into<String> {
        Self::new_under(name, None)
    }

    pub fn new_under<S>(name: S, parent: Option<Value>) -> Self where S: Into<String> {
        Class {
            name: name.into(),
            base_class: ffi::rb_cObject.into(),
            parent: parent,

            methods: Vec::new(),
            singleton_methods: Vec::new(),

            included_modules: Vec::new(),
            prepended_modules: Vec::new(),
            constants: Vec::new(),
            aliases: Vec::new(),
            accessors: Vec::new(),
        }
    }

    /// Creates the class under a value.
    /// This may be a class, a module, etc.
    pub fn under(mut self, parent: Value) -> Self {
        self.parent = Some(parent);
        self
    }

    /// Sets the base class.
    pub fn extend(mut self, base_class: Value) -> Self {
        self.base_class = base_class;
        self
    }

    /// Includes a module.
    pub fn include(mut self, module: Value) -> Self {
        self.included_modules.push(module);
        self
    }

    /// Prepends a module.
    pub fn prepend(mut self, module: Value) -> Self {
        self.prepended_modules.push(module);
        self
    }

    /// Defines a method.
    pub fn method<S>(mut self, name: S, func_addr: *mut extern fn() -> Value, arg_count: i8) -> Self
        where S: Into<String> {
        self.methods.push(Method {
            name: name.into(),
            func: func_addr,
            arg_count: arg_count,
        });
        self
    }

    /// Defines a singleton method.
    pub fn singleton_method<S>(mut self, name: S, func_addr: *mut extern fn() -> Value, arg_count: i8) -> Self
        where S: Into<String> {
        self.singleton_methods.push(Method {
            name: name.into(),
            func: func_addr,
            arg_count: arg_count,
        });
        self
    }

    /// Defines a constant.
    pub fn constant<S>(mut self, name: S, value: Value) -> Self
        where S: Into<String> {
        self.constants.push(Constant(name.into(), value));
        self
    }

    /// Creates an alias method.
    pub fn alias<S1, S2>(mut self, new_name: S1, original_name: S2) -> Self
        where S1: Into<String>, S2: Into<String> {
        self.aliases.push(Alias {
            new_name: new_name.into(),
            original_name: original_name.into(),
        });
        self
    }

    /// Creates getter and setter methods for an ivar.
    pub fn attr_accessor<S>(self, name: S) -> Self
        where S: Into<String> {
        self.define_accessor(name, true, true)
    }

    /// Creates a getter method for an ivar.
    pub fn attr_reader<S>(self, name: S) -> Self
        where S: Into<String> {
        self.define_accessor(name, true, false)
    }

    /// Creates a setter method for an ivar.
    pub fn attr_writer<S>(self, name: S) -> Self
        where S: Into<String> {
        self.define_accessor(name, false, true)
    }

    /// Builds the class.
    pub fn build(self) -> Value {
        let name = util::c_string(&self.name);

        let value = Value::from(unsafe {
            if let Some(parent) = self.parent {
                ffi::rb_define_class_under(parent.0, name.as_ptr(), self.base_class.0)
            } else {
                ffi::rb_define_class(name.as_ptr(), self.base_class.0)
            }
        });

        for method in self.methods {
            Self::define_method(false, value, method);
        }

        for method in self.singleton_methods {
            Self::define_method(true, value, method);
        }

        for module in self.included_modules {
            unsafe { ffi::rb_include_module(value.0, module.0) };
        }

        for module in self.prepended_modules {
            unsafe { ffi::rb_prepend_module(value.0, module.0) };
        }

        for constant in self.constants {
            unsafe {
                ffi::rb_define_const(
                    value.0,
                    util::c_string(&constant.0).as_ptr(),
                    (constant.1).0,
                );
            }
        }

        for alias in self.aliases {
            unsafe {
                ffi::rb_define_alias(
                    value.0,
                    util::c_string(&alias.new_name).as_ptr(),
                    util::c_string(&alias.original_name).as_ptr(),
                );
            }
        }

        for accessor in self.accessors {
            unsafe {
                ffi::rb_define_attr(
                    value.0,
                    util::c_string(&accessor.name).as_ptr(),
                    if accessor.reader { 1 } else { 0 },
                    if accessor.writer { 1 } else { 0 },
                );
            }
        }

        value
    }

    fn define_accessor<S>(mut self, name: S, reader: bool, writer: bool) -> Self
        where S: Into<String> {
        self.accessors.push(Accessor {
            name: name.into(),
            reader: reader,
            writer: writer,
        });
        self
    }

    fn define_method(is_singleton: bool, value: Value, method: Method) {
        let f = if is_singleton {
            ffi::rb_define_module_function
        } else {
            ffi::rb_define_method
        };

        unsafe {
            f(value.0, util::c_string(&method.name).as_ptr(),
              method.func as *mut _, method.arg_count as libc::c_int);
        }
    }
}
<commit_msg>Wrap C FFI constant in unsafe<commit_after>use Value;

use util;
use ffi;
use libc;

struct Method {
    name: String,
    func: *mut extern fn() -> Value,
    arg_count: i8,
}

struct Constant(String, Value);

struct Alias {
    new_name: String,
    original_name: String,
}

struct Accessor {
    name: String,
    reader: bool,
    writer: bool,
}

/// A class builder.
pub struct Class
{
    name: String,
    base_class: Value,
    parent: Option<Value>,

    methods: Vec<Method>,
    singleton_methods: Vec<Method>,

    included_modules: Vec<Value>,
    prepended_modules: Vec<Value>,
    constants: Vec<Constant>,
    aliases: Vec<Alias>,
    accessors: Vec<Accessor>,
}

impl Class {
    pub fn new<S>(name: S) -> Self where S: Into<String> {
        Self::new_under(name, None)
    }

    pub fn new_under<S>(name: S, parent: Option<Value>) -> Self where S: Into<String> {
        Class {
            name: name.into(),
            base_class: unsafe { ffi::rb_cObject.into() },
            parent: parent,

            methods: Vec::new(),
            singleton_methods: Vec::new(),

            included_modules: Vec::new(),
            prepended_modules: Vec::new(),
            constants: Vec::new(),
            aliases: Vec::new(),
            accessors: Vec::new(),
        }
    }

    /// Creates the class under a value.
    /// This may be a class, a module, etc.
    pub fn under(mut self, parent: Value) -> Self {
        self.parent = Some(parent);
        self
    }

    /// Sets the base class.
    pub fn extend(mut self, base_class: Value) -> Self {
        self.base_class = base_class;
        self
    }

    /// Includes a module.
    pub fn include(mut self, module: Value) -> Self {
        self.included_modules.push(module);
        self
    }

    /// Prepends a module.
    pub fn prepend(mut self, module: Value) -> Self {
        self.prepended_modules.push(module);
        self
    }

    /// Defines a method.
    pub fn method<S>(mut self, name: S, func_addr: *mut extern fn() -> Value, arg_count: i8) -> Self
        where S: Into<String> {
        self.methods.push(Method {
            name: name.into(),
            func: func_addr,
            arg_count: arg_count,
        });
        self
    }

    /// Defines a singleton method.
    pub fn singleton_method<S>(mut self, name: S, func_addr: *mut extern fn() -> Value, arg_count: i8) -> Self
        where S: Into<String> {
        self.singleton_methods.push(Method {
            name: name.into(),
            func: func_addr,
            arg_count: arg_count,
        });
        self
    }

    /// Defines a constant.
    pub fn constant<S>(mut self, name: S, value: Value) -> Self
        where S: Into<String> {
        self.constants.push(Constant(name.into(), value));
        self
    }

    /// Creates an alias method.
    pub fn alias<S1, S2>(mut self, new_name: S1, original_name: S2) -> Self
        where S1: Into<String>, S2: Into<String> {
        self.aliases.push(Alias {
            new_name: new_name.into(),
            original_name: original_name.into(),
        });
        self
    }

    /// Creates getter and setter methods for an ivar.
    pub fn attr_accessor<S>(self, name: S) -> Self
        where S: Into<String> {
        self.define_accessor(name, true, true)
    }

    /// Creates a getter method for an ivar.
    pub fn attr_reader<S>(self, name: S) -> Self
        where S: Into<String> {
        self.define_accessor(name, true, false)
    }

    /// Creates a setter method for an ivar.
    pub fn attr_writer<S>(self, name: S) -> Self
        where S: Into<String> {
        self.define_accessor(name, false, true)
    }

    /// Builds the class.
    pub fn build(self) -> Value {
        let name = util::c_string(&self.name);

        let value = Value::from(unsafe {
            if let Some(parent) = self.parent {
                ffi::rb_define_class_under(parent.0, name.as_ptr(), self.base_class.0)
            } else {
                ffi::rb_define_class(name.as_ptr(), self.base_class.0)
            }
        });

        for method in self.methods {
            Self::define_method(false, value, method);
        }

        for method in self.singleton_methods {
            Self::define_method(true, value, method);
        }

        for module in self.included_modules {
            unsafe { ffi::rb_include_module(value.0, module.0) };
        }

        for module in self.prepended_modules {
            unsafe { ffi::rb_prepend_module(value.0, module.0) };
        }

        for constant in self.constants {
            unsafe {
                ffi::rb_define_const(
                    value.0,
                    util::c_string(&constant.0).as_ptr(),
                    (constant.1).0,
                );
            }
        }

        for alias in self.aliases {
            unsafe {
                ffi::rb_define_alias(
                    value.0,
                    util::c_string(&alias.new_name).as_ptr(),
                    util::c_string(&alias.original_name).as_ptr(),
                );
            }
        }

        for accessor in self.accessors {
            unsafe {
                ffi::rb_define_attr(
                    value.0,
                    util::c_string(&accessor.name).as_ptr(),
                    if accessor.reader { 1 } else { 0 },
                    if accessor.writer { 1 } else { 0 },
                );
            }
        }

        value
    }

    fn define_accessor<S>(mut self, name: S, reader: bool, writer: bool) -> Self
        where S: Into<String> {
        self.accessors.push(Accessor {
            name: name.into(),
            reader: reader,
            writer: writer,
        });
        self
    }

    fn define_method(is_singleton: bool, value: Value, method: Method) {
        let f = if is_singleton {
            ffi::rb_define_module_function
        } else {
            ffi::rb_define_method
        };

        unsafe {
            f(value.0, util::c_string(&method.name).as_ptr(),
              method.func as *mut _, method.arg_count as libc::c_int);
        }
    }
}
<|endoftext|>