<commit_before>//! Contains types related to 2D image data.

use std::ops;
use std::mem;
use std::slice;
use gl;

/// A trait for types that that contain 2D image data, which can
/// be uploaded to a texture using a [`Texture2dBuilder`]
/// (../context/texture_context/struct.Texture2dBuilder)
/// or using the [`gl.image_2d`]
/// (../context/texture_context/trait.ContextTextureExt.html#method.image_2d)
/// method.
///
/// See [`Pixels`](struct.Pixels.html) for a simple `Image2d`.
pub trait Image2d {
    /// Get the width of the image, in texels.
    fn width(&self) -> usize;

    /// Get the height of the image, in texels.
    fn height(&self) -> usize;

    /// Get the format of the image data that is returned by the
    /// [`texel_bytes`](trait.Image2d.html#tymethod.texel_bytes) method.
    fn format(&self) -> ImageFormat;

    /// Get the raw texel data of the image data, as a `u8` slice.
    fn texel_bytes(&self) -> &[u8];
}

/// A single OpenGL color value, with `u8` components laid out
/// as a C struct in RGBA order. This type is the simplest implementation
/// of [`Image2d`](trait.Image2d.html), which allows it to be uploaded
/// to a texture.
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct Pixel {
    /// The red component.
    pub r: u8,

    /// The green component.
    pub g: u8,

    /// The blue component.
    pub b: u8,

    /// The alpha component.
    pub a: u8
}

impl Pixel {
    /// Create an RGBA color, provided each color component.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::r_g_b_a(0xAA, 0xBB, 0xCC, 0xDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn r_g_b_a(r: u8, g: u8, b: u8, a: u8) -> Self {
        Pixel { r: r, g: g, b: b, a: a }
    }

    /// Create an RGBA color, provided the RGB components and using
    /// `0xFF` as the A value.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::r_g_b(0xAA, 0xBB, 0xCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xFF);
    /// ```
    pub fn r_g_b(r: u8, g: u8, b: u8) -> Self {
        Pixel::r_g_b_a(r, g, b, 0xFF)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value. The `u32` value will be read as `0x00RRGGBB`.
    ///
    /// # Examples
    /// ```
    /// // The `0x55` component gets discared
    /// let pixel = glitter::Pixel::rgb(0x55AABBCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xFF);
    /// ```
    pub fn rgb(rgb: u32) -> Self {
        Pixel::rgb_a(rgb, 0xFF)
    }

    /// Create an RGBA color value, provided the components as a packed
    /// `u32` value. The `u32` value will be read as `0xAARRGGBB`.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::argb(0xDDAABBCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn argb(argb: u32) -> Self {
        let a = (argb & 0xFF000000) >> 24;
        Pixel::rgb_a(argb, a as u8)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value. The `u32` value will be read as `0xRRGGBBAA`.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::rgba(0xAABBCCDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn rgba(rgba: u32) -> Self {
        let r = (rgba & 0xFF000000) >> 24;
        let g = (rgba & 0x00FF0000) >> 16;
        let b = (rgba & 0x0000FF00) >> 8;
        let a =  rgba & 0x000000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a as u8)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value, and a separate A component. The `u32` value
    /// will be read as `0x00RRGGBB`.
    ///
    /// # Examples
    /// ```
    /// // The `0x55` component gets discarded
    /// let pixel = glitter::Pixel::rgb_a(0x55AABBCC, 0xDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn rgb_a(rgb: u32, a: u8) -> Self {
        let r = (rgb & 0xFF0000) >> 16;
        let g = (rgb & 0x00FF00) >> 8;
        let b =  rgb & 0x0000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a)
    }
}

/// A (heap-allocated) 2D image composed of a list of pixels.
///
/// # Example
///
/// ```
/// // Draw a red circle with a 50px radius in a 100px * 100px black image.
/// extern crate glitter;
///
/// let width = 100;
/// let height = 100;
/// let radius = 50;
///
/// let (center_x, center_y) = (width as f32/2.0, height as f32/2.0);
///
/// let mut pixels = glitter::Pixels::new(width, height);
/// for x in 0..width {
///     for y in 0..height {
///         let dx = center_x - x as f32;
///         let dy = center_y - y as f32;
///         let distance = (dx*dx + dy*dy).sqrt();
///
///         let color = if distance < radius {
///             // The point is within the circle, so it should be red
///             glitter::Pixel::rgb(0xFF0000)
///         }
///         else {
///             // The point is outside the circle, so it should be black
///             glitter::Pixel::rgb(0x000000)
///         };
///         pixels[y][x] = color;
///     }
/// }
/// ```
#[derive(Clone)]
pub struct Pixels {
    width: usize,
    height: usize,
    pixels: Vec<Pixel>
}

impl Pixels {
    /// Create a new image with the desired width and height. Pixels
    /// are initialized with [`Pixel::default()`]
    /// (https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default).
    pub fn new(width: usize, height: usize) -> Self {
        Pixels {
            width: width,
            height: height,
            pixels: vec![Pixel::default(); width * height]
        }
    }
}

impl ops::Index<usize> for Pixels {
    type Output = [Pixel];

    fn index(&self, row: usize) -> &[Pixel] {
        debug_assert!(row < self.height);

        &self.pixels[(row*self.width)..((row+1)*self.width)]
    }
}

impl ops::IndexMut<usize> for Pixels {
    fn index_mut(&mut self, row: usize) -> &mut [Pixel] {
        debug_assert!(row < self.height);

        &mut self.pixels[(row*self.width)..((row+1)*self.width)]
    }
}

impl Image2d for Pixels {
    fn width(&self) -> usize {
        self.width
    }

    fn height(&self) -> usize {
        self.height
    }

    fn format(&self) -> ImageFormat {
        ImageFormat::rgba8()
    }

    fn texel_bytes(&self) -> &[u8] {
        let len = self.pixels.len() * mem::size_of::<Pixel>();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self.pixels[0]), len)
        }
    }
}

gl_enum! {
    /// The data types for a texel.
    pub gl_enum TexelType {
        /// Each texel is 4 * 8 bits.
        pub const UnsignedByte as UNSIGNED_BYTE_TEXEL =
            gl::UNSIGNED_BYTE,

        /// Each texel is 16 bits, with 5-bit/6-bit/5-bit components.
        pub const UnsignedShort565 as UNSIGNED_SHORT_5_6_5 =
            gl::UNSIGNED_SHORT_5_6_5,

        /// Each texel is 16 bits, with 4, 4-bit components.
        pub const UnsignedShort4444 as UNSIGNED_SHORT_4_4_4_4 =
            gl::UNSIGNED_SHORT_4_4_4_4,

        /// Each texel is 16 bits, with 5-bit/5-bit/5-bit/1-bit components.
        pub const UnsignedShort5551 as UNSIGNED_SHORT_5_5_5_1 =
            gl::UNSIGNED_SHORT_5_5_5_1
    }
}

gl_enum! {
    /// The different texel formats.
    pub gl_enum TexelFormat {
        /// A texel contains only an alpha component.
        pub const Alpha as ALPHA = gl::ALPHA,

        /// A texel contains red, green, and blue components.
        pub const RGB as RGB = gl::RGB,

        /// A texel contains red, green, blue, and alpha components.
        pub const RGBA as RGBA = gl::RGBA
    }
}

gl_enum! {
    /// The various image formats of a renderbuffer.
    pub gl_enum RenderbufferFormat {
        /// The red, green, blue, and alpha channels are all stored with 4 bits.
        pub const RGBA4 as RGBA4 = gl::RGBA4,

        /// The red, green, and blue channels are stored with 5 bits, 6 bits,
        /// and 5 bits, respectively.
        pub const RGB565 as RGB565 = gl::RGB565,

        /// The red, green, and blue channels are stored with 5 bits, and the
        /// alpha channel is stored with 1 bit.
        pub const RGB5A1 as RGB5_A1 = gl::RGB5_A1,

        /// The renderbuffer stores a 16-bit depth component.
        pub const DepthComponent16 as DEPTH_COMPONENT16 = gl::DEPTH_COMPONENT16,

        /// The renderbuffer stores an 8-bit stencil component.
        pub const StencilIndex8 as STENCIL_INDEX8 = gl::STENCIL_INDEX8
    }
}

/// A type that contains the texel type and format that make up a 2D image.
#[derive(Debug, Clone, Copy)]
pub struct ImageFormat {
    /// The texel type of the image.
    pub texel_type: TexelType,

        /// The texel format of the image.
    pub texel_format: TexelFormat
}

impl ImageFormat {
    /// Returns the RGBA image format with 8 bits per component.
    pub fn rgba8() -> Self {
        ImageFormat {
            texel_type: TexelType::UnsignedByte,
            texel_format: TexelFormat::RGBA
        }
    }
}
<commit_msg>Docs: fix `Pixels` example<commit_after>//! Contains types related to 2D image data.

use std::ops;
use std::mem;
use std::slice;
use gl;

/// A trait for types that that contain 2D image data, which can
/// be uploaded to a texture using a [`Texture2dBuilder`]
/// (../context/texture_context/struct.Texture2dBuilder)
/// or using the [`gl.image_2d`]
/// (../context/texture_context/trait.ContextTextureExt.html#method.image_2d)
/// method.
///
/// See [`Pixels`](struct.Pixels.html) for a simple `Image2d`.
pub trait Image2d {
    /// Get the width of the image, in texels.
    fn width(&self) -> usize;

    /// Get the height of the image, in texels.
    fn height(&self) -> usize;

    /// Get the format of the image data that is returned by the
    /// [`texel_bytes`](trait.Image2d.html#tymethod.texel_bytes) method.
    fn format(&self) -> ImageFormat;

    /// Get the raw texel data of the image data, as a `u8` slice.
    fn texel_bytes(&self) -> &[u8];
}

/// A single OpenGL color value, with `u8` components laid out
/// as a C struct in RGBA order. This type is the simplest implementation
/// of [`Image2d`](trait.Image2d.html), which allows it to be uploaded
/// to a texture.
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct Pixel {
    /// The red component.
    pub r: u8,

    /// The green component.
    pub g: u8,

    /// The blue component.
    pub b: u8,

    /// The alpha component.
    pub a: u8
}

impl Pixel {
    /// Create an RGBA color, provided each color component.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::r_g_b_a(0xAA, 0xBB, 0xCC, 0xDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn r_g_b_a(r: u8, g: u8, b: u8, a: u8) -> Self {
        Pixel { r: r, g: g, b: b, a: a }
    }

    /// Create an RGBA color, provided the RGB components and using
    /// `0xFF` as the A value.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::r_g_b(0xAA, 0xBB, 0xCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xFF);
    /// ```
    pub fn r_g_b(r: u8, g: u8, b: u8) -> Self {
        Pixel::r_g_b_a(r, g, b, 0xFF)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value. The `u32` value will be read as `0x00RRGGBB`.
    ///
    /// # Examples
    /// ```
    /// // The `0x55` component gets discared
    /// let pixel = glitter::Pixel::rgb(0x55AABBCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xFF);
    /// ```
    pub fn rgb(rgb: u32) -> Self {
        Pixel::rgb_a(rgb, 0xFF)
    }

    /// Create an RGBA color value, provided the components as a packed
    /// `u32` value. The `u32` value will be read as `0xAARRGGBB`.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::argb(0xDDAABBCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn argb(argb: u32) -> Self {
        let a = (argb & 0xFF000000) >> 24;
        Pixel::rgb_a(argb, a as u8)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value. The `u32` value will be read as `0xRRGGBBAA`.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::rgba(0xAABBCCDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn rgba(rgba: u32) -> Self {
        let r = (rgba & 0xFF000000) >> 24;
        let g = (rgba & 0x00FF0000) >> 16;
        let b = (rgba & 0x0000FF00) >> 8;
        let a =  rgba & 0x000000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a as u8)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value, and a separate A component. The `u32` value
    /// will be read as `0x00RRGGBB`.
    ///
    /// # Examples
    /// ```
    /// // The `0x55` component gets discarded
    /// let pixel = glitter::Pixel::rgb_a(0x55AABBCC, 0xDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn rgb_a(rgb: u32, a: u8) -> Self {
        let r = (rgb & 0xFF0000) >> 16;
        let g = (rgb & 0x00FF00) >> 8;
        let b =  rgb & 0x0000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a)
    }
}

/// A (heap-allocated) 2D image composed of a list of pixels.
///
/// # Example
///
/// ```
/// // Draw a red circle with a 50px radius in a 100px * 100px black image.
/// extern crate glitter;
///
/// let width = 100;
/// let height = 100;
/// let radius = 50.0;
///
/// let (center_x, center_y) = (width as f32/2.0, height as f32/2.0);
///
/// let mut pixels = glitter::Pixels::new(width, height);
/// for x in 0..width {
///     for y in 0..height {
///         let dx = center_x - x as f32;
///         let dy = center_y - y as f32;
///         let distance = (dx*dx + dy*dy).sqrt();
///
///         let color = if distance < radius {
///             // The point is within the circle, so it should be red
///             glitter::Pixel::rgb(0xFF0000)
///         }
///         else {
///             // The point is outside the circle, so it should be black
///             glitter::Pixel::rgb(0x000000)
///         };
///         pixels[y][x] = color;
///     }
/// }
/// ```
#[derive(Clone)]
pub struct Pixels {
    width: usize,
    height: usize,
    pixels: Vec<Pixel>
}

impl Pixels {
    /// Create a new image with the desired width and height. Pixels
    /// are initialized with [`Pixel::default()`]
    /// (https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default).
    pub fn new(width: usize, height: usize) -> Self {
        Pixels {
            width: width,
            height: height,
            pixels: vec![Pixel::default(); width * height]
        }
    }
}

impl ops::Index<usize> for Pixels {
    type Output = [Pixel];

    fn index(&self, row: usize) -> &[Pixel] {
        debug_assert!(row < self.height);

        &self.pixels[(row*self.width)..((row+1)*self.width)]
    }
}

impl ops::IndexMut<usize> for Pixels {
    fn index_mut(&mut self, row: usize) -> &mut [Pixel] {
        debug_assert!(row < self.height);

        &mut self.pixels[(row*self.width)..((row+1)*self.width)]
    }
}

impl Image2d for Pixels {
    fn width(&self) -> usize {
        self.width
    }

    fn height(&self) -> usize {
        self.height
    }

    fn format(&self) -> ImageFormat {
        ImageFormat::rgba8()
    }

    fn texel_bytes(&self) -> &[u8] {
        let len = self.pixels.len() * mem::size_of::<Pixel>();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self.pixels[0]), len)
        }
    }
}

gl_enum! {
    /// The data types for a texel.
    pub gl_enum TexelType {
        /// Each texel is 4 * 8 bits.
        pub const UnsignedByte as UNSIGNED_BYTE_TEXEL =
            gl::UNSIGNED_BYTE,

        /// Each texel is 16 bits, with 5-bit/6-bit/5-bit components.
        pub const UnsignedShort565 as UNSIGNED_SHORT_5_6_5 =
            gl::UNSIGNED_SHORT_5_6_5,

        /// Each texel is 16 bits, with 4, 4-bit components.
        pub const UnsignedShort4444 as UNSIGNED_SHORT_4_4_4_4 =
            gl::UNSIGNED_SHORT_4_4_4_4,

        /// Each texel is 16 bits, with 5-bit/5-bit/5-bit/1-bit components.
        pub const UnsignedShort5551 as UNSIGNED_SHORT_5_5_5_1 =
            gl::UNSIGNED_SHORT_5_5_5_1
    }
}

gl_enum! {
    /// The different texel formats.
    pub gl_enum TexelFormat {
        /// A texel contains only an alpha component.
        pub const Alpha as ALPHA = gl::ALPHA,

        /// A texel contains red, green, and blue components.
        pub const RGB as RGB = gl::RGB,

        /// A texel contains red, green, blue, and alpha components.
        pub const RGBA as RGBA = gl::RGBA
    }
}

gl_enum! {
    /// The various image formats of a renderbuffer.
    pub gl_enum RenderbufferFormat {
        /// The red, green, blue, and alpha channels are all stored with 4 bits.
        pub const RGBA4 as RGBA4 = gl::RGBA4,

        /// The red, green, and blue channels are stored with 5 bits, 6 bits,
        /// and 5 bits, respectively.
        pub const RGB565 as RGB565 = gl::RGB565,

        /// The red, green, and blue channels are stored with 5 bits, and the
        /// alpha channel is stored with 1 bit.
        pub const RGB5A1 as RGB5_A1 = gl::RGB5_A1,

        /// The renderbuffer stores a 16-bit depth component.
        pub const DepthComponent16 as DEPTH_COMPONENT16 = gl::DEPTH_COMPONENT16,

        /// The renderbuffer stores an 8-bit stencil component.
        pub const StencilIndex8 as STENCIL_INDEX8 = gl::STENCIL_INDEX8
    }
}

/// A type that contains the texel type and format that make up a 2D image.
#[derive(Debug, Clone, Copy)]
pub struct ImageFormat {
    /// The texel type of the image.
    pub texel_type: TexelType,

        /// The texel format of the image.
    pub texel_format: TexelFormat
}

impl ImageFormat {
    /// Returns the RGBA image format with 8 bits per component.
    pub fn rgba8() -> Self {
        ImageFormat {
            texel_type: TexelType::UnsignedByte,
            texel_format: TexelFormat::RGBA
        }
    }
}
<|endoftext|>


<commit_before>mod field_shape;
mod dictionary;
mod field;

const MAX_VAL: i32 = 9;
const MAX_SUM: i32 = MAX_VAL * (MAX_VAL + 1) / 2;
type Cand = u32;
const CAND_ALL: Cand = (1 << MAX_VAL) - 1;
const UNDECIDED: i32 = -1;

#[derive(Clone, Copy)]
pub enum Clue {
    NoClue,
    Clue { horizontal: i32, vertical: i32 },
}

pub use self::field_shape::*;
pub use self::dictionary::*;
pub use self::field::*;
<commit_msg>Kakuro: add answer_to_problem<commit_after>mod field_shape;
mod dictionary;
mod field;

const MAX_VAL: i32 = 9;
const MAX_SUM: i32 = MAX_VAL * (MAX_VAL + 1) / 2;
type Cand = u32;
const CAND_ALL: Cand = (1 << MAX_VAL) - 1;
const UNDECIDED: i32 = -1;

#[derive(Clone, Copy)]
pub enum Clue {
    NoClue,
    Clue { horizontal: i32, vertical: i32 },
}

pub use self::field_shape::*;
pub use self::dictionary::*;
pub use self::field::*;

use super::{Grid, Coord};
pub fn answer_to_problem(ans: &Grid<i32>) -> Grid<Clue> {
    let mut has_clue = Grid::new(ans.height(), ans.width(), false);
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let loc = Coord { y: y, x: x };
            has_clue[loc] = !(1 <= ans[loc] && ans[loc] <= MAX_VAL);
        }
    }
    let shape = FieldShape::new(&has_clue);
    let mut prob_base = Grid::new(ans.height(), ans.width(), (0, 0));
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let val = ans[Coord { y: y, x: x }];
            if !(1 <= val && val <= MAX_VAL) { continue; }

            let (g1, g2) = shape.cell_to_groups[Coord { y: y, x: x }];
            match shape.clue_locations[g1 as usize] {
                ClueLocation::Horizontal(h) => prob_base[h as usize].0 += val,
                ClueLocation::Vertical(v) => prob_base[v as usize].1 += val,
            }
            match shape.clue_locations[g2 as usize] {
                ClueLocation::Horizontal(h) => prob_base[h as usize].0 += val,
                ClueLocation::Vertical(v) => prob_base[v as usize].1 += val,
            }
        }
    }
    let mut ret = Grid::new(ans.height(), ans.width(), Clue::NoClue);
    for y in 0..ans.height() {
        for x in 0..ans.width() {
            let loc = Coord { y: y, x: x };
            let v = ans[loc];
            if (1 <= v && v <= MAX_VAL) { continue; }
            ret[loc] = Clue::Clue { horizontal: prob_base[loc].0, vertical: prob_base[loc].1 };
        }
    }
    ret
}
<|endoftext|>


<commit_before>use l2::ast::*;
use l2::iterators::{FactIterator, QueryIterator};

use std::cell::Cell;
use std::cmp::max;
use std::collections::HashMap;
use std::fmt;
use std::vec::Vec;

impl fmt::Display for FactInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
                write!(f, "get_structure {}/{}, {}", name, arity, r),
            &FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
                write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
            &FactInstruction::GetValue(ref x, ref a) =>
                write!(f, "get_value {}, A{}", x, a),
            &FactInstruction::GetVariable(ref x, ref a) =>
                write!(f, "get_variable {}, A{}", x, a),
            &FactInstruction::UnifyVariable(ref r) =>
                write!(f, "unify_variable {}", r),
            &FactInstruction::UnifyValue(ref r) =>
                write!(f, "unify_value {}", r)
        }
    }
}

impl fmt::Display for QueryInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
                write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
            &QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
                write!(f, "put_structure {}/{}, {}", name, arity, r),
            &QueryInstruction::PutValue(ref x, ref a) =>
                write!(f, "put_value {}, A{}", x, a),
            &QueryInstruction::PutVariable(ref x, ref a) =>
                write!(f, "put_variable {}, A{}", x, a),
            &QueryInstruction::SetVariable(ref r) =>
                write!(f, "set_variable {}", r),
            &QueryInstruction::SetValue(ref r) =>
                write!(f, "set_value {}", r),
        }
    }
}

impl fmt::Display for ControlInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ControlInstruction::Allocate(num_cells) =>
                write!(f, "allocate {}", num_cells),
            &ControlInstruction::Call(ref name, ref arity) =>
                write!(f, "call {}/{}", name, arity),
            &ControlInstruction::Deallocate =>
                write!(f, "deallocate"),
            &ControlInstruction::Proceed =>
                write!(f, "proceed")
        }
    }
}

trait CompilationTarget<'a> {
    type Iterator : Iterator<Item=TermRef<'a>>;

    fn iter(&'a Term) -> Self::Iterator;

    fn to_structure(Level, Atom, usize, RegType) -> Self;

    fn argument_to_variable(RegType, usize) -> Self;
    fn argument_to_value(RegType, usize) -> Self;
    fn subterm_to_variable(RegType) -> Self;
    fn subterm_to_value(RegType) -> Self;

    fn clause_arg_to_instr(RegType) -> Self;
}

impl<'a> CompilationTarget<'a> for FactInstruction {
    type Iterator = FactIterator<'a>;

    fn iter(term: &'a Term) -> Self::Iterator {
        term.breadth_first_iter()
    }

    fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
        FactInstruction::GetStructure(lvl, atom, arity, reg)
    }

    fn argument_to_variable(arg: RegType, val: usize) -> Self {
        FactInstruction::GetVariable(arg, val)
    }

    fn argument_to_value(arg: RegType, val: usize) -> Self {
        FactInstruction::GetValue(arg, val)
    }

    fn subterm_to_variable(val: RegType) -> Self {
        FactInstruction::UnifyVariable(val)
    }

    fn subterm_to_value(val: RegType) -> Self {
        FactInstruction::UnifyValue(val)
    }

    fn clause_arg_to_instr(val: RegType) -> Self {
        FactInstruction::UnifyVariable(val)
    }
}

impl<'a> CompilationTarget<'a> for QueryInstruction {
    type Iterator = QueryIterator<'a>;

    fn iter(term: &'a Term) -> Self::Iterator {
        term.post_order_iter()
    }

    fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
        QueryInstruction::PutStructure(lvl, atom, arity, reg)
    }

    fn argument_to_variable(arg: RegType, val: usize) -> Self {
        QueryInstruction::PutVariable(arg, val)
    }

    fn argument_to_value(arg: RegType, val: usize) -> Self {
        QueryInstruction::PutValue(arg, val)
    }

    fn subterm_to_variable(val: RegType) -> Self {
        QueryInstruction::SetVariable(val)
    }

    fn subterm_to_value(val: RegType) -> Self {
        QueryInstruction::SetValue(val)
    }

    fn clause_arg_to_instr(val: RegType) -> Self {
        QueryInstruction::SetValue(val)
    }
}

struct TermMarker<'a> {
    bindings: HashMap<&'a Var, VarReg>,
    arg_c:    usize,
    perm_c:   usize,
    temp_c:   usize
}

impl<'a> TermMarker<'a> {
    fn new() -> TermMarker<'a> {
        TermMarker { bindings: HashMap::new(),
                     arg_c:    1,
                     perm_c:   1,
                     temp_c:   1 }
    }

    fn contains_var(&self, var: &'a Var) -> bool {
        self.bindings.contains_key(var)
    }

    fn get(&self, var: &'a Var) -> VarReg {
        *self.bindings.get(var).unwrap()
    }

    fn insert(&mut self, var: &'a Var, r: VarReg) {
        self.bindings.insert(var, r);
    }

    fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
        let reg_type = cell.get();

        if reg_type.reg_num() == 0 {
            match lvl {
                Level::Deep if reg_type.is_perm() => {
                    let perm = self.perm_c;
                    self.perm_c += 1;
                    cell.set(RegType::Perm(perm));
                },
                Level::Deep => {
                    let temp = self.temp_c;
                    self.temp_c += 1;
                    cell.set(RegType::Temp(temp));
                },
                Level::Shallow if reg_type.is_perm() => {
                    let arg = self.arg_c;
                    self.arg_c += 1;
                    cell.set(RegType::Perm(arg));
                },
                Level::Shallow => {
                    let arg = self.arg_c;
                    self.arg_c += 1;
                    cell.set(RegType::Temp(arg));
                }
            };
        }
    }

    fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
    {
        let reg = self.get(var);

        match lvl {
            Level::Deep => VarReg::Norm(reg.norm()),
            Level::Shallow => {
                let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);

                self.arg_c += 1;
                self.insert(var, reg);

                reg
            }
        }
    }

    fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
    {
        let inner_reg = if reg.is_perm() {
            let perm = self.perm_c;
            self.perm_c += 1;
            RegType::Perm(perm)
        } else {
            let temp = self.temp_c;
            self.temp_c += 1;
            RegType::Temp(temp)
        };

        let reg = match lvl {
            Level::Deep => VarReg::Norm(inner_reg),
            Level::Shallow => {
                let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
                self.arg_c += 1;
                reg
            }
        };

        self.insert(var, reg);
        reg
    }

    fn advance_at_header(&mut self, term: &'a Term) {
        self.arg_c = 1;
        self.temp_c = max(term.subterms() + 1,
                          self.bindings.values()
                          .filter_map(|vr| {
                              match vr {
                                  &VarReg::Norm(RegType::Temp(reg)) |
                                  &VarReg::ArgAndNorm(RegType::Temp(reg), _) =>
                                      Some(reg),
                                  _ => None
                              }
                          })
                          .max().unwrap_or(0));
    }

    fn advance(&mut self, term: &'a Term) {
        self.arg_c = 1;
        self.temp_c = term.subterms() + 1;
    }
}

#[derive(Copy, Clone)]
enum TermStatus {
    New, Old, Recurrent
}

pub struct CodeGenerator<'a> {
    marker: TermMarker<'a>
}

type VariableFixture<'a>  = (TermStatus, Vec<&'a Cell<VarReg>>);
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;

impl<'a> CodeGenerator<'a> {
    pub fn new() -> Self {
        CodeGenerator { marker: TermMarker::new() }
    }

    pub fn vars(&self) -> &HashMap<&Var, VarReg> {
        &self.marker.bindings
    }

    fn to_structure<Target>(&mut self,
                            lvl: Level,
                            name: &'a Atom,
                            cell: &'a Cell<RegType>,
                            arity: usize)
                            -> Target
        where Target: CompilationTarget<'a>
    {
        self.marker.mark_non_var(lvl, cell);
        Target::to_structure(lvl, name.clone(), arity, cell.get())
    }

    fn var_term<Target>(&mut self,
                        lvl: Level,
                        cell: &'a Cell<VarReg>,
                        var: &'a Var)
                        -> Target
        where Target: CompilationTarget<'a>
    {
        if !self.marker.contains_var(var) {
            let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
            cell.set(reg);

            match reg {
                VarReg::ArgAndNorm(arg, norm) =>
                    Target::argument_to_variable(arg, norm),
                VarReg::Norm(norm) =>
                    Target::subterm_to_variable(norm)
            }
        } else {
            let reg = self.marker.mark_old_var(lvl, var);
            cell.set(reg);

            match reg {
                VarReg::ArgAndNorm(arg, norm) =>
                    Target::argument_to_value(arg, norm),
                VarReg::Norm(norm) =>
                    Target::subterm_to_value(norm)
            }
        }
    }

    fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
        where Target: CompilationTarget<'a>
    {
        self.marker.mark_non_var(Level::Deep, cell);
        Target::clause_arg_to_instr(cell.get())
    }

    fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
        where Target: CompilationTarget<'a>
    {
        match subterm {
            &Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
                self.non_var_subterm(cell),
            &Term::Var(ref cell, ref var) =>
                self.var_term(Level::Deep, cell, var)
        }
    }

    fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
        where Target: CompilationTarget<'a>
    {
        let iter       = Target::iter(term);
        let mut target = Vec::new();

        for term in iter {
            match term {
                TermRef::Atom(lvl, term, atom) =>
                    target.push(self.to_structure(lvl, atom, term, 0)),
                TermRef::Clause(lvl, term, atom, terms) => {
                    target.push(self.to_structure(lvl, atom, term, terms.len()));

                    for subterm in terms {
                        target.push(self.subterm_to_instr(subterm.as_ref()));
                    }
                },
                TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
                    target.push(self.var_term(lvl, cell, var)),
                _ => {}
            };
        }

        target
    }

    fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
        where Iter : Iterator<Item=TermRef<'a>>
    {
        for term in iter {
            if let TermRef::Var(_, reg_cell, var) = term {
                let mut status =
                    vs.entry(var)
                      .or_insert((TermStatus::New, Vec::new()));

                status.1.push(reg_cell);

                match status.0 {
                    TermStatus::Old | TermStatus::Recurrent =>
                        status.0 = TermStatus::Recurrent,
                    _ => {}
                };
            }
        }

        for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
            match *term_status {
                TermStatus::New => *term_status = TermStatus::Old,
                TermStatus::Recurrent => {
                    for cell_reg in cb.drain(0..) {
                        cell_reg.set(VarReg::Norm(RegType::Perm(0)));
                    }
                },
                _ => {}
            }
        }
    }

    fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
        let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
        let mut vfs = HashMap::new();

        let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());

        Self::mark_vars_in_term(iter, &mut vfs);

        for term in clauses {
            Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
        }

        vfs
    }

    //TODO: remove this if it proves to be unnecessary.
    fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
        match term {
            &Term::Atom(_, ref atom) => {
                let call = ControlInstruction::Call(atom.clone(), 0);
                compiled_query.push(Line::Control(call));
            },
            &Term::Clause(_, ref atom, ref terms) => {
                let call = ControlInstruction::Call(atom.clone(), terms.len());
                compiled_query.push(Line::Control(call));
            },
            _ => {}
        }
    }

    pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
        let vfs = Self::mark_perm_vars(&rule);
        let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
        let mut perm_vars = 0;

        for &(term_status, _) in vfs.values() {
            if let TermStatus::Recurrent = term_status {
                perm_vars += 1;
            }
        }

        let mut body = Vec::new();

        body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));

        self.marker.advance(p0);
        body.push(Line::Fact(self.compile_target(p0)));

        self.marker.advance_at_header(p1);
        body.push(Line::Query(self.compile_target(p1)));
        Self::add_conditional_call(&mut body, p1);

        body = clauses.iter()
            .map(|ref term| self.compile_query(term))
            .fold(body, |mut body, ref mut cqs| {
                body.append(cqs);
                body
            });

        body.push(Line::Control(ControlInstruction::Deallocate));

        body
    }

    pub fn compile_fact(&mut self, term: &'a Term) -> Code {
        self.marker.advance(term);

        let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
        let proceed = Line::Control(ControlInstruction::Proceed);

        compiled_fact.push(proceed);
        compiled_fact
    }

    pub fn compile_query(&mut self, term: &'a Term) -> Code {
        self.marker.advance(term);

        let mut compiled_query = vec![Line::Query(self.compile_target(term))];
        Self::add_conditional_call(&mut compiled_query, term);

        compiled_query
    }
}
<commit_msg>codegen tweak.<commit_after>use l2::ast::*;
use l2::iterators::{FactIterator, QueryIterator};

use std::cell::Cell;
use std::cmp::max;
use std::collections::HashMap;
use std::fmt;
use std::vec::Vec;

impl fmt::Display for FactInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
                write!(f, "get_structure {}/{}, {}", name, arity, r),
            &FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
                write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
            &FactInstruction::GetValue(ref x, ref a) =>
                write!(f, "get_value {}, A{}", x, a),
            &FactInstruction::GetVariable(ref x, ref a) =>
                write!(f, "get_variable {}, A{}", x, a),
            &FactInstruction::UnifyVariable(ref r) =>
                write!(f, "unify_variable {}", r),
            &FactInstruction::UnifyValue(ref r) =>
                write!(f, "unify_value {}", r)
        }
    }
}

impl fmt::Display for QueryInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
                write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
            &QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
                write!(f, "put_structure {}/{}, {}", name, arity, r),
            &QueryInstruction::PutValue(ref x, ref a) =>
                write!(f, "put_value {}, A{}", x, a),
            &QueryInstruction::PutVariable(ref x, ref a) =>
                write!(f, "put_variable {}, A{}", x, a),
            &QueryInstruction::SetVariable(ref r) =>
                write!(f, "set_variable {}", r),
            &QueryInstruction::SetValue(ref r) =>
                write!(f, "set_value {}", r),
        }
    }
}

impl fmt::Display for ControlInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ControlInstruction::Allocate(num_cells) =>
                write!(f, "allocate {}", num_cells),
            &ControlInstruction::Call(ref name, ref arity) =>
                write!(f, "call {}/{}", name, arity),
            &ControlInstruction::Deallocate =>
                write!(f, "deallocate"),
            &ControlInstruction::Proceed =>
                write!(f, "proceed")
        }
    }
}

trait CompilationTarget<'a> {
    type Iterator : Iterator<Item=TermRef<'a>>;

    fn iter(&'a Term) -> Self::Iterator;

    fn to_structure(Level, Atom, usize, RegType) -> Self;

    fn argument_to_variable(RegType, usize) -> Self;
    fn argument_to_value(RegType, usize) -> Self;
    fn subterm_to_variable(RegType) -> Self;
    fn subterm_to_value(RegType) -> Self;

    fn clause_arg_to_instr(RegType) -> Self;
}

impl<'a> CompilationTarget<'a> for FactInstruction {
    type Iterator = FactIterator<'a>;

    fn iter(term: &'a Term) -> Self::Iterator {
        term.breadth_first_iter()
    }

    fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
        FactInstruction::GetStructure(lvl, atom, arity, reg)
    }

    fn argument_to_variable(arg: RegType, val: usize) -> Self {
        FactInstruction::GetVariable(arg, val)
    }

    fn argument_to_value(arg: RegType, val: usize) -> Self {
        FactInstruction::GetValue(arg, val)
    }

    fn subterm_to_variable(val: RegType) -> Self {
        FactInstruction::UnifyVariable(val)
    }

    fn subterm_to_value(val: RegType) -> Self {
        FactInstruction::UnifyValue(val)
    }

    fn clause_arg_to_instr(val: RegType) -> Self {
        FactInstruction::UnifyVariable(val)
    }
}

impl<'a> CompilationTarget<'a> for QueryInstruction {
    type Iterator = QueryIterator<'a>;

    fn iter(term: &'a Term) -> Self::Iterator {
        term.post_order_iter()
    }

    fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
        QueryInstruction::PutStructure(lvl, atom, arity, reg)
    }

    fn argument_to_variable(arg: RegType, val: usize) -> Self {
        QueryInstruction::PutVariable(arg, val)
    }

    fn argument_to_value(arg: RegType, val: usize) -> Self {
        QueryInstruction::PutValue(arg, val)
    }

    fn subterm_to_variable(val: RegType) -> Self {
        QueryInstruction::SetVariable(val)
    }

    fn subterm_to_value(val: RegType) -> Self {
        QueryInstruction::SetValue(val)
    }

    fn clause_arg_to_instr(val: RegType) -> Self {
        QueryInstruction::SetValue(val)
    }
}

struct TermMarker<'a> {
    bindings: HashMap<&'a Var, VarReg>,
    arg_c:    usize,
    perm_c:   usize,
    temp_c:   usize
}

impl<'a> TermMarker<'a> {
    fn new() -> TermMarker<'a> {
        TermMarker { bindings: HashMap::new(),
                     arg_c:    1,
                     perm_c:   1,
                     temp_c:   1 }
    }

    fn contains_var(&self, var: &'a Var) -> bool {
        self.bindings.contains_key(var)
    }

    fn get(&self, var: &'a Var) -> VarReg {
        *self.bindings.get(var).unwrap()
    }

    fn insert(&mut self, var: &'a Var, r: VarReg) {
        self.bindings.insert(var, r);
    }

    fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
        let reg_type = cell.get();

        if reg_type.reg_num() == 0 {
            match lvl {
                Level::Deep if reg_type.is_perm() => {
                    let perm = self.perm_c;
                    self.perm_c += 1;
                    cell.set(RegType::Perm(perm));
                },
                Level::Deep => {
                    let temp = self.temp_c;
                    self.temp_c += 1;
                    cell.set(RegType::Temp(temp));
                },
                Level::Shallow if reg_type.is_perm() => {
                    let arg = self.arg_c;
                    self.arg_c += 1;
                    cell.set(RegType::Perm(arg));
                },
                Level::Shallow => {
                    let arg = self.arg_c;
                    self.arg_c += 1;
                    cell.set(RegType::Temp(arg));
                }
            };
        }
    }

    fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
    {
        let reg = self.get(var);

        match lvl {
            Level::Deep => VarReg::Norm(reg.norm()),
            Level::Shallow => {
                let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);

                self.arg_c += 1;
                self.insert(var, reg);

                reg
            }
        }
    }

    fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
    {
        let inner_reg = if reg.is_perm() {
            let perm = self.perm_c;
            self.perm_c += 1;
            RegType::Perm(perm)
        } else {
            let temp = self.temp_c;
            self.temp_c += 1;
            RegType::Temp(temp)
        };

        let reg = match lvl {
            Level::Deep => VarReg::Norm(inner_reg),
            Level::Shallow => {
                let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
                self.arg_c += 1;
                reg
            }
        };

        self.insert(var, reg);
        reg
    }

    fn advance_at_header(&mut self, term: &'a Term) {
        self.arg_c = 1;
        self.temp_c = max(term.subterms(),
                          self.bindings.values()
                          .filter_map(|vr| {
                              match vr {
                                  &VarReg::Norm(RegType::Temp(reg)) |
                                  &VarReg::ArgAndNorm(RegType::Temp(reg), _) =>
                                      Some(reg),
                                  _ => None
                              }
                          })
                          .max().unwrap_or(0)) + 1;
    }

    fn advance(&mut self, term: &'a Term) {
        self.arg_c = 1;
        self.temp_c = term.subterms() + 1;
    }
}

#[derive(Copy, Clone)]
enum TermStatus {
    New, Old, Recurrent
}

pub struct CodeGenerator<'a> {
    marker: TermMarker<'a>
}

type VariableFixture<'a>  = (TermStatus, Vec<&'a Cell<VarReg>>);
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;

impl<'a> CodeGenerator<'a> {
    pub fn new() -> Self {
        CodeGenerator { marker: TermMarker::new() }
    }

    pub fn vars(&self) -> &HashMap<&Var, VarReg> {
        &self.marker.bindings
    }

    fn to_structure<Target>(&mut self,
                            lvl: Level,
                            name: &'a Atom,
                            cell: &'a Cell<RegType>,
                            arity: usize)
                            -> Target
        where Target: CompilationTarget<'a>
    {
        self.marker.mark_non_var(lvl, cell);
        Target::to_structure(lvl, name.clone(), arity, cell.get())
    }

    fn var_term<Target>(&mut self,
                        lvl: Level,
                        cell: &'a Cell<VarReg>,
                        var: &'a Var)
                        -> Target
        where Target: CompilationTarget<'a>
    {
        if !self.marker.contains_var(var) {
            let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
            cell.set(reg);

            match reg {
                VarReg::ArgAndNorm(arg, norm) =>
                    Target::argument_to_variable(arg, norm),
                VarReg::Norm(norm) =>
                    Target::subterm_to_variable(norm)
            }
        } else {
            let reg = self.marker.mark_old_var(lvl, var);
            cell.set(reg);

            match reg {
                VarReg::ArgAndNorm(arg, norm) =>
                    Target::argument_to_value(arg, norm),
                VarReg::Norm(norm) =>
                    Target::subterm_to_value(norm)
            }
        }
    }

    fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
        where Target: CompilationTarget<'a>
    {
        self.marker.mark_non_var(Level::Deep, cell);
        Target::clause_arg_to_instr(cell.get())
    }

    fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
        where Target: CompilationTarget<'a>
    {
        match subterm {
            &Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
                self.non_var_subterm(cell),
            &Term::Var(ref cell, ref var) =>
                self.var_term(Level::Deep, cell, var)
        }
    }

    fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
        where Target: CompilationTarget<'a>
    {
        let iter       = Target::iter(term);
        let mut target = Vec::new();

        for term in iter {
            match term {
                TermRef::Atom(lvl, term, atom) =>
                    target.push(self.to_structure(lvl, atom, term, 0)),
                TermRef::Clause(lvl, term, atom, terms) => {
                    target.push(self.to_structure(lvl, atom, term, terms.len()));

                    for subterm in terms {
                        target.push(self.subterm_to_instr(subterm.as_ref()));
                    }
                },
                TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
                    target.push(self.var_term(lvl, cell, var)),
                _ => {}
            };
        }

        target
    }

    fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
        where Iter : Iterator<Item=TermRef<'a>>
    {
        for term in iter {
            if let TermRef::Var(_, reg_cell, var) = term {
                let mut status =
                    vs.entry(var)
                      .or_insert((TermStatus::New, Vec::new()));

                status.1.push(reg_cell);

                match status.0 {
                    TermStatus::Old | TermStatus::Recurrent =>
                        status.0 = TermStatus::Recurrent,
                    _ => {}
                };
            }
        }

        for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
            match *term_status {
                TermStatus::New => *term_status = TermStatus::Old,
                TermStatus::Recurrent => {
                    for cell_reg in cb.drain(0..) {
                        cell_reg.set(VarReg::Norm(RegType::Perm(0)));
                    }
                },
                _ => {}
            }
        }
    }

    fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
        let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
        let mut vfs = HashMap::new();

        let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());

        Self::mark_vars_in_term(iter, &mut vfs);

        for term in clauses {
            Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
        }

        vfs
    }

    //TODO: remove this if it proves to be unnecessary.
    fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
        match term {
            &Term::Atom(_, ref atom) => {
                let call = ControlInstruction::Call(atom.clone(), 0);
                compiled_query.push(Line::Control(call));
            },
            &Term::Clause(_, ref atom, ref terms) => {
                let call = ControlInstruction::Call(atom.clone(), terms.len());
                compiled_query.push(Line::Control(call));
            },
            _ => {}
        }
    }

    pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
        let vfs = Self::mark_perm_vars(&rule);
        let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
        let mut perm_vars = 0;

        for &(term_status, _) in vfs.values() {
            if let TermStatus::Recurrent = term_status {
                perm_vars += 1;
            }
        }

        let mut body = Vec::new();

        body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));

        self.marker.advance(p0);
        body.push(Line::Fact(self.compile_target(p0)));

        self.marker.advance_at_header(p1);
        body.push(Line::Query(self.compile_target(p1)));
        Self::add_conditional_call(&mut body, p1);

        body = clauses.iter()
            .map(|ref term| self.compile_query(term))
            .fold(body, |mut body, ref mut cqs| {
                body.append(cqs);
                body
            });

        body.push(Line::Control(ControlInstruction::Deallocate));

        body
    }

    pub fn compile_fact(&mut self, term: &'a Term) -> Code {
        self.marker.advance(term);

        let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
        let proceed = Line::Control(ControlInstruction::Proceed);

        compiled_fact.push(proceed);
        compiled_fact
    }

    pub fn compile_query(&mut self, term: &'a Term) -> Code {
        self.marker.advance(term);

        let mut compiled_query = vec![Line::Query(self.compile_target(term))];
        Self::add_conditional_call(&mut compiled_query, term);

        compiled_query
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate regex;
extern crate toml;

use self::chrono::{Duration, NaiveTime};
use self::regex::Regex;
use self::toml::Value as Toml;

use error::{CannotHappenError, CliError, ConfigError, ConfigErrorKind};
use lib::setting;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;

pub enum KeyKind {
    BurnAfter,
    SweepPeriod,
    SweepTime,
}

impl KeyKind {
    pub fn from<S: AsRef<str>>(key: S) -> Result<KeyKind, ConfigError> {
        match key.as_ref().trim() {
            "burn.after"   => Ok(KeyKind::BurnAfter),
            "sweep.period" => Ok(KeyKind::SweepPeriod),
            "sweep.time"   => Ok(KeyKind::SweepTime),
            _              => Err(ConfigError::new(ConfigErrorKind::InvalidKey)),
        }
    }

    fn to_str(&self) -> &str {
        match *self {
            KeyKind::BurnAfter   => "burn.after",
            KeyKind::SweepPeriod => "sweep.period",
            KeyKind::SweepTime   => "sweep.time",
        }
    }

    fn to_pair(&self) -> (&str, &str) {
        let key = self
            .to_str()
            .split('.')
            .collect::<Vec<&str>>();
        (key[0], key[1]) // unsafe!
    }
}

pub struct Config {
    toml: Toml,
}

impl Config {
    fn insert_deeply(table: &mut BTreeMap<String, BTreeMap<String, String>>, key: &KeyKind, value: String) {
        let (first, second) = key.to_pair();

        let second = second.to_string();

        if table.contains_key(first) {
            table.get_mut(first).map(|e| e.insert(second, value));
        } else {
            let mut entry = BTreeMap::new();
            entry.insert(second, value);

            table.insert(first.to_string(), entry);
        }
    }

    fn new(toml: Toml) -> Self {
        Config { toml: toml }
    }

    pub fn default() -> Self {
        let mut config = BTreeMap::new();
        Self::insert_deeply(&mut config, &KeyKind::BurnAfter  , "2 weeks".to_string());
        Self::insert_deeply(&mut config, &KeyKind::SweepPeriod, "daily"  .to_string());
        Self::insert_deeply(&mut config, &KeyKind::SweepTime  , "00:00"  .to_string());

        Self::new(toml::encode(&config))
    }

    pub fn read() -> Result<Self, CliError> {
        let mut f = try!(File::open(setting::config_file()));

        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));

        let result = contents
            .parse()
            .map_err(|e: Vec<_>| e.into_iter().find(|_| true));
        let toml = match result {
            Ok(toml)    => toml,
            Err(option) => match option {
                Some(e) => return Err(From::from(e)),
                None    => return Err(From::from(CannotHappenError)),
            },
        };

        Ok(Self::new(toml))
    }

    pub fn set(mut self, key: &KeyKind, value: String) -> Result<Self, ConfigError> {
        let mut config = match toml::decode::<BTreeMap<String, BTreeMap<String, String>>>(self.toml) {
            Some(decoded) => decoded,
            None          => return Err(ConfigError::new(ConfigErrorKind::Something)),
        };

        Self::insert_deeply(&mut config, key, value);

        self.toml = toml::encode(&config);

        Ok(self)
    }

    pub fn to_string(&self) -> String {
        toml::encode_str(&self.toml)
    }

    fn get(key: &KeyKind) -> Result<String, CliError> {
        let config = try!(Self::read()).toml;

        let result = config
            .lookup(key.to_str())
            .ok_or(ConfigError::new(match *key {
                KeyKind::BurnAfter   => ConfigErrorKind::NotFoundBurnAfter,
                KeyKind::SweepPeriod => unimplemented!(),
                KeyKind::SweepTime   => unimplemented!(),
            }));
        let value = try!(result).to_string(); // This to_string() is not documented.

        Ok(value)
    }

    pub fn validate<S: AsRef<str>>(key: &KeyKind, value: S) -> Result<String, CliError> {
        let value = value.as_ref().trim();

        match *key {
            KeyKind::BurnAfter => {
                let pair = try!(Regex::new(r"(?P<num>\d+)\s?(?P<unit>days?|weeks?)"))
                    .captures(value)
                    .map_or((None, None), |caps| (caps.name("num"), caps.name("unit")));
                let (num, unit) = match pair {
                    (Some(num), Some(unit)) => (num, unit),
                    _                       => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
                };
                Ok(format!("{} {}", num, unit))
            },
            KeyKind::SweepPeriod => {
                match value {
                    "daily" | "weekly" => Ok(value.to_string()),
                    _                  => return Err(From::from(ConfigError::new(ConfigErrorKind::SweepPeriod))),
                }
            },
            KeyKind::SweepTime => {
                match NaiveTime::from_str(format!("{}:00", value).as_ref()) {
                    Ok(_)  => Ok(value.to_string()),
                    // should set Err(e) to Error::cause()
                    Err(_) => return Err(From::from(ConfigError::new(ConfigErrorKind::SweepTime))),
                }
            },
        }
    }

    pub fn extract_burn_after() -> Result<Duration, CliError> {
        let key = KeyKind::BurnAfter;

        let after       = try!(Self::get(&key));
        let after       = try!(Self::validate(&key, after));
        let after       = after.split(' ').collect::<Vec<&str>>();
        let (num, unit) = (after[0], after[1]);                    // unsafe!
        let num         = try!(num.parse::<u32>()) as i64;

        let duration = match unit {
            "day"  | "days"  => Duration::days(num),
            "week" | "weeks" => Duration::weeks(num),
            _                => return Err(From::from(CannotHappenError)),
        };

        Ok(duration)
    }
}
<commit_msg>Revert "[Bug] Fix incorrect regular expression"<commit_after>extern crate chrono;
extern crate regex;
extern crate toml;

use self::chrono::{Duration, NaiveTime};
use self::regex::Regex;
use self::toml::Value as Toml;

use error::{CannotHappenError, CliError, ConfigError, ConfigErrorKind};
use lib::setting;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;

pub enum KeyKind {
    BurnAfter,
    SweepPeriod,
    SweepTime,
}

impl KeyKind {
    pub fn from<S: AsRef<str>>(key: S) -> Result<KeyKind, ConfigError> {
        match key.as_ref().trim() {
            "burn.after"   => Ok(KeyKind::BurnAfter),
            "sweep.period" => Ok(KeyKind::SweepPeriod),
            "sweep.time"   => Ok(KeyKind::SweepTime),
            _              => Err(ConfigError::new(ConfigErrorKind::InvalidKey)),
        }
    }

    fn to_str(&self) -> &str {
        match *self {
            KeyKind::BurnAfter   => "burn.after",
            KeyKind::SweepPeriod => "sweep.period",
            KeyKind::SweepTime   => "sweep.time",
        }
    }

    fn to_pair(&self) -> (&str, &str) {
        let key = self
            .to_str()
            .split('.')
            .collect::<Vec<&str>>();
        (key[0], key[1]) // unsafe!
    }
}

pub struct Config {
    toml: Toml,
}

impl Config {
    fn insert_deeply(table: &mut BTreeMap<String, BTreeMap<String, String>>, key: &KeyKind, value: String) {
        let (first, second) = key.to_pair();

        let second = second.to_string();

        if table.contains_key(first) {
            table.get_mut(first).map(|e| e.insert(second, value));
        } else {
            let mut entry = BTreeMap::new();
            entry.insert(second, value);

            table.insert(first.to_string(), entry);
        }
    }

    fn new(toml: Toml) -> Self {
        Config { toml: toml }
    }

    pub fn default() -> Self {
        let mut config = BTreeMap::new();
        Self::insert_deeply(&mut config, &KeyKind::BurnAfter  , "2 weeks".to_string());
        Self::insert_deeply(&mut config, &KeyKind::SweepPeriod, "daily"  .to_string());
        Self::insert_deeply(&mut config, &KeyKind::SweepTime  , "00:00"  .to_string());

        Self::new(toml::encode(&config))
    }

    pub fn read() -> Result<Self, CliError> {
        let mut f = try!(File::open(setting::config_file()));

        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));

        let result = contents
            .parse()
            .map_err(|e: Vec<_>| e.into_iter().find(|_| true));
        let toml = match result {
            Ok(toml)    => toml,
            Err(option) => match option {
                Some(e) => return Err(From::from(e)),
                None    => return Err(From::from(CannotHappenError)),
            },
        };

        Ok(Self::new(toml))
    }

    pub fn set(mut self, key: &KeyKind, value: String) -> Result<Self, ConfigError> {
        let mut config = match toml::decode::<BTreeMap<String, BTreeMap<String, String>>>(self.toml) {
            Some(decoded) => decoded,
            None          => return Err(ConfigError::new(ConfigErrorKind::Something)),
        };

        Self::insert_deeply(&mut config, key, value);

        self.toml = toml::encode(&config);

        Ok(self)
    }

    pub fn to_string(&self) -> String {
        toml::encode_str(&self.toml)
    }

    fn get(key: &KeyKind) -> Result<String, CliError> {
        let config = try!(Self::read()).toml;

        let result = config
            .lookup(key.to_str())
            .ok_or(ConfigError::new(match *key {
                KeyKind::BurnAfter   => ConfigErrorKind::NotFoundBurnAfter,
                KeyKind::SweepPeriod => unimplemented!(),
                KeyKind::SweepTime   => unimplemented!(),
            }));
        let value = try!(result).to_string(); // This to_string() is not documented.

        Ok(value)
    }

    pub fn validate<S: AsRef<str>>(key: &KeyKind, value: S) -> Result<String, CliError> {
        let value = value.as_ref().trim();

        match *key {
            KeyKind::BurnAfter => {
                let pair = try!(Regex::new(r"^(?P<num>\d+)\s?(?P<unit>days?|weeks?)$"))
                    .captures(value)
                    .map_or((None, None), |caps| (caps.name("num"), caps.name("unit")));
                let (num, unit) = match pair {
                    (Some(num), Some(unit)) => (num, unit),
                    _                       => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
                };
                Ok(format!("{} {}", num, unit))
            },
            KeyKind::SweepPeriod => {
                match value {
                    "daily" | "weekly" => Ok(value.to_string()),
                    _                  => return Err(From::from(ConfigError::new(ConfigErrorKind::SweepPeriod))),
                }
            },
            KeyKind::SweepTime => {
                match NaiveTime::from_str(format!("{}:00", value).as_ref()) {
                    Ok(_)  => Ok(value.to_string()),
                    // should set Err(e) to Error::cause()
                    Err(_) => return Err(From::from(ConfigError::new(ConfigErrorKind::SweepTime))),
                }
            },
        }
    }

    pub fn extract_burn_after() -> Result<Duration, CliError> {
        let key = KeyKind::BurnAfter;

        let after       = try!(Self::get(&key));
        let after       = try!(Self::validate(&key, after));
        let after       = after.split(' ').collect::<Vec<&str>>();
        let (num, unit) = (after[0], after[1]);                    // unsafe!
        let num         = try!(num.parse::<u32>()) as i64;

        let duration = match unit {
            "day"  | "days"  => Duration::days(num),
            "week" | "weeks" => Duration::weeks(num),
            _                => return Err(From::from(CannotHappenError)),
        };

        Ok(duration)
    }
}
<|endoftext|>


<commit_before>/*
Module: map

A hashmap
*/

/* Section: Types */

/*
Type: hashfn

A function that returns a hash of a value
*/
type hashfn<K> = fn(K) -> uint;

/*
Type: eqfn

Equality
*/
type eqfn<K> = fn(K, K) -> bool;

/*
Type: hashset

A convenience type to treat a hashmap as a set
*/
type hashset<K> = hashmap<K, ()>;

/*
Obj: hashmap
*/
type hashmap<K, V> = obj {
    /*
    Method: size

    Return the number of elements in the map
    */
    fn size() -> uint;
    /*
    Method: insert

    Add a value to the map. If the map already contains a value for
    the specified key then the original value is replaced.

    Returns:

    True if the key did not already exist in the map
    */
    fn insert(K, V) -> bool;
    /*
    Method: contains_key

    Returns true if the map contains a value for the specified key
    */
    fn contains_key(K) -> bool;
    /*
    Method: get

    Get the value for the specified key

    Failure:

    If the key does not exist in the map
    */
    fn get(K) -> V;
    /*
    Method: find

    Get the value for the specified key. If the key does not exist
    in the map then returns none.
    */
    fn find(K) -> option::t<V>;
    /*
    Method: remove

    Remove and return a value from the map. If the key does not exist
    in the map then returns none.
    */
    fn remove(K) -> option::t<V>;
    /*
    Method: rehash

    Force map growth and rehashing
    */
    fn rehash();
    /*
    Method: items

    Iterate over all the key/value pairs in the map
    */
    fn items(block(K, V));
    /*
    Method: keys

    Iterate over all the keys in the map
    */
    fn keys(block(K));
    /*
    Iterate over all the values in the map
    */
    fn values(block(V));
};

/* Section: Operations */

/*
Function: mk_hashmap

Construct a hashmap

Parameters:

hasher - The hash function for key type K
eqer - The equality function for key type K
*/
fn mk_hashmap<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>)
    -> hashmap<K, V> {
    let initial_capacity: uint = 32u; // 2^5

    let load_factor: util::rational = {num: 3, den: 4};
    tag bucket<copy K, copy V> { nil; deleted; some(K, V); }
    fn make_buckets<copy K, copy V>(nbkts: uint) -> [mutable bucket<K, V>] {
        ret vec::init_elt_mut::<bucket<K, V>>(nil::<K, V>, nbkts);
    }
    // Derive two hash functions from the one given by taking the upper
    // half and lower half of the uint bits.  Our bucket probing
    // sequence is then defined by
    //
    //   hash(key, i) := hashl(key) * i + hashr(key)   for i = 0, 1, 2, ...
    //
    // Tearing the hash function apart this way is kosher in practice
    // as, assuming 32-bit uints, the table would have to be at 2^32
    // buckets before the resulting pair of hash functions no longer
    // probes all buckets for a fixed key.  Note that hashl is made to
    // output odd numbers (hence coprime to the number of nbkts, which
    // is always a power of 2), so that all buckets are probed for a
    // fixed key.

    fn hashl(n: uint, _nbkts: uint) -> uint { ret (n >>> 16u) * 2u + 1u; }
    fn hashr(n: uint, _nbkts: uint) -> uint { ret 0x0000_ffff_u & n; }
    fn hash(h: uint, nbkts: uint, i: uint) -> uint {
        ret (hashl(h, nbkts) * i + hashr(h, nbkts)) % nbkts;
    }
    /**
     * We attempt to never call this with a full table.  If we do, it
     * will fail.
     */

    fn insert_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
                                     bkts: [mutable bucket<K, V>],
                                     nbkts: uint, key: K, val: V) -> bool {
        let i: uint = 0u;
        let h: uint = hasher(key);
        while i < nbkts {
            let j: uint = hash(h, nbkts, i);
            alt bkts[j] {
              some(k, _) {
                // Copy key to please alias analysis.

                let k_ = k;
                if eqer(key, k_) { bkts[j] = some(k_, val); ret false; }
                i += 1u;
              }
              _ { bkts[j] = some(key, val); ret true; }
            }
        }
        fail; // full table
    }
    fn find_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
                                   bkts: [mutable bucket<K, V>],
                                   nbkts: uint, key: K) -> option::t<V> {
        let i: uint = 0u;
        let h: uint = hasher(key);
        while i < nbkts {
            let j: uint = hash(h, nbkts, i);
            alt bkts[j] {
              some(k, v) {
                // Copy to please alias analysis.
                let k_ = k;
                let v_ = v;
                if eqer(key, k_) { ret option::some(v_); }
              }
              nil. { ret option::none; }
              deleted. { }
            }
            i += 1u;
        }
        ret option::none;
    }
    fn rehash<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
                              oldbkts: [mutable bucket<K, V>],
                              _noldbkts: uint,
                              newbkts: [mutable bucket<K, V>],
                              nnewbkts: uint) {
        for b: bucket<K, V> in oldbkts {
            alt b {
              some(k_, v_) {
                let k = k_;
                let v = v_;
                insert_common(hasher, eqer, newbkts, nnewbkts, k, v);
              }
              _ { }
            }
        }
    }
    obj hashmap<copy K, copy V>(hasher: hashfn<K>,
                                eqer: eqfn<K>,
                                mutable bkts: [mutable bucket<K, V>],
                                mutable nbkts: uint,
                                mutable nelts: uint,
                                lf: util::rational) {
        fn size() -> uint { ret nelts; }
        fn insert(key: K, val: V) -> bool {
            let load: util::rational =
                {num: nelts + 1u as int, den: nbkts as int};
            if !util::rational_leq(load, lf) {
                let nnewbkts: uint = uint::next_power_of_two(nbkts + 1u);
                let newbkts = make_buckets(nnewbkts);
                rehash(hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
                bkts = newbkts;
                nbkts = nnewbkts;
            }
            if insert_common(hasher, eqer, bkts, nbkts, key, val) {
                nelts += 1u;
                ret true;
            }
            ret false;
        }
        fn contains_key(key: K) -> bool {
            ret alt find_common(hasher, eqer, bkts, nbkts, key) {
                  option::some(_) { true }
                  _ { false }
                };
        }
        fn get(key: K) -> V {
            ret alt find_common(hasher, eqer, bkts, nbkts, key) {
                  option::some(val) { val }
                  _ { fail }
                };
        }
        fn find(key: K) -> option::t<V> {
            be find_common(hasher, eqer, bkts, nbkts, key);
        }
        fn remove(key: K) -> option::t<V> {
            let i: uint = 0u;
            let h: uint = hasher(key);
            while i < nbkts {
                let j: uint = hash(h, nbkts, i);
                alt bkts[j] {
                  some(k, v) {
                    let k_ = k;
                    let vo = option::some(v);
                    if eqer(key, k_) {
                        bkts[j] = deleted;
                        nelts -= 1u;
                        ret vo;
                    }
                  }
                  deleted. { }
                  nil. { ret option::none; }
                }
                i += 1u;
            }
            ret option::none;
        }
        fn rehash() {
            let newbkts = make_buckets(nbkts);
            rehash(hasher, eqer, bkts, nbkts, newbkts, nbkts);
            bkts = newbkts;
        }
        fn items(it: block(K, V)) {
            for b in bkts {
                alt b { some(k, v) { it(copy k, copy v); } _ { } }
            }
        }
        fn keys(it: block(K)) {
            for b in bkts {
                alt b { some(k, _) { it(copy k); } _ { } }
            }
        }
        fn values(it: block(V)) {
            for b in bkts {
                alt b { some(_, v) { it(copy v); } _ { } }
            }
        }
    }
    let bkts = make_buckets(initial_capacity);
    ret hashmap(hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}

/*
Function: new_str_hash

Construct a hashmap for string keys
*/
fn new_str_hash<copy V>() -> hashmap<str, V> {
    ret mk_hashmap(str::hash, str::eq);
}

/*
Function: new_int_hash

Construct a hashmap for int keys
*/
fn new_int_hash<copy V>() -> hashmap<int, V> {
    fn hash_int(&&x: int) -> uint { ret x as uint; }
    fn eq_int(&&a: int, &&b: int) -> bool { ret a == b; }
    ret mk_hashmap(hash_int, eq_int);
}

/*
Function: new_uint_hash

Construct a hashmap for uint keys
*/
fn new_uint_hash<copy V>() -> hashmap<uint, V> {
    fn hash_uint(&&x: uint) -> uint { ret x; }
    fn eq_uint(&&a: uint, &&b: uint) -> bool { ret a == b; }
    ret mk_hashmap(hash_uint, eq_uint);
}

/*
Function: set_add

Convenience function for adding keys to a hashmap with nil type keys
*/
fn set_add<K>(set: hashset<K>, key: K) -> bool { ret set.insert(key, ()); }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>hack for now: map uint hashes into a u32, which helps x86_64 perf.<commit_after>/*
Module: map

A hashmap
*/

/* Section: Types */

/*
Type: hashfn

A function that returns a hash of a value
*/
type hashfn<K> = fn(K) -> uint;

/*
Type: eqfn

Equality
*/
type eqfn<K> = fn(K, K) -> bool;

/*
Type: hashset

A convenience type to treat a hashmap as a set
*/
type hashset<K> = hashmap<K, ()>;

/*
Obj: hashmap
*/
type hashmap<K, V> = obj {
    /*
    Method: size

    Return the number of elements in the map
    */
    fn size() -> uint;
    /*
    Method: insert

    Add a value to the map. If the map already contains a value for
    the specified key then the original value is replaced.

    Returns:

    True if the key did not already exist in the map
    */
    fn insert(K, V) -> bool;
    /*
    Method: contains_key

    Returns true if the map contains a value for the specified key
    */
    fn contains_key(K) -> bool;
    /*
    Method: get

    Get the value for the specified key

    Failure:

    If the key does not exist in the map
    */
    fn get(K) -> V;
    /*
    Method: find

    Get the value for the specified key. If the key does not exist
    in the map then returns none.
    */
    fn find(K) -> option::t<V>;
    /*
    Method: remove

    Remove and return a value from the map. If the key does not exist
    in the map then returns none.
    */
    fn remove(K) -> option::t<V>;
    /*
    Method: rehash

    Force map growth and rehashing
    */
    fn rehash();
    /*
    Method: items

    Iterate over all the key/value pairs in the map
    */
    fn items(block(K, V));
    /*
    Method: keys

    Iterate over all the keys in the map
    */
    fn keys(block(K));
    /*
    Iterate over all the values in the map
    */
    fn values(block(V));
};

/* Section: Operations */

/*
Function: mk_hashmap

Construct a hashmap

Parameters:

hasher - The hash function for key type K
eqer - The equality function for key type K
*/
fn mk_hashmap<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>)
    -> hashmap<K, V> {
    let initial_capacity: uint = 32u; // 2^5

    let load_factor: util::rational = {num: 3, den: 4};
    tag bucket<copy K, copy V> { nil; deleted; some(K, V); }
    fn make_buckets<copy K, copy V>(nbkts: uint) -> [mutable bucket<K, V>] {
        ret vec::init_elt_mut::<bucket<K, V>>(nil::<K, V>, nbkts);
    }
    // Derive two hash functions from the one given by taking the upper
    // half and lower half of the uint bits.  Our bucket probing
    // sequence is then defined by
    //
    //   hash(key, i) := hashl(key) * i + hashr(key)   for i = 0, 1, 2, ...
    //
    // Tearing the hash function apart this way is kosher in practice
    // as, assuming 32-bit uints, the table would have to be at 2^32
    // buckets before the resulting pair of hash functions no longer
    // probes all buckets for a fixed key.  Note that hashl is made to
    // output odd numbers (hence coprime to the number of nbkts, which
    // is always a power of 2), so that all buckets are probed for a
    // fixed key.

    fn hashl(n: u32) -> u32 { ret (n >>> 16u32) * 2u32 + 1u32; }
    fn hashr(n: u32) -> u32 { ret 0x0000_ffff_u32 & n; }
    fn hash(h: u32, nbkts: uint, i: uint) -> uint {
        ret ((hashl(h) as uint) * i + (hashr(h) as uint)) % nbkts;
    }

    fn to_u64(h: uint) -> u32 {
        ret (h as u32) ^ ((h >>> 16u) as u32);
    }

    /**
     * We attempt to never call this with a full table.  If we do, it
     * will fail.
     */
    fn insert_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
                                     bkts: [mutable bucket<K, V>],
                                     nbkts: uint, key: K, val: V) -> bool {
        let i: uint = 0u;
        let h = to_u64(hasher(key));
        while i < nbkts {
            let j: uint = hash(h, nbkts, i);
            alt bkts[j] {
              some(k, _) {
                // Copy key to please alias analysis.

                let k_ = k;
                if eqer(key, k_) { bkts[j] = some(k_, val); ret false; }
                i += 1u;
              }
              _ { bkts[j] = some(key, val); ret true; }
            }
        }
        fail; // full table
    }
    fn find_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
                                   bkts: [mutable bucket<K, V>],
                                   nbkts: uint, key: K) -> option::t<V> {
        let i: uint = 0u;
        let h = to_u64(hasher(key));
        while i < nbkts {
            let j: uint = hash(h, nbkts, i);
            alt bkts[j] {
              some(k, v) {
                // Copy to please alias analysis.
                let k_ = k;
                let v_ = v;
                if eqer(key, k_) { ret option::some(v_); }
              }
              nil. { ret option::none; }
              deleted. { }
            }
            i += 1u;
        }
        ret option::none;
    }
    fn rehash<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
                              oldbkts: [mutable bucket<K, V>],
                              _noldbkts: uint,
                              newbkts: [mutable bucket<K, V>],
                              nnewbkts: uint) {
        for b: bucket<K, V> in oldbkts {
            alt b {
              some(k_, v_) {
                let k = k_;
                let v = v_;
                insert_common(hasher, eqer, newbkts, nnewbkts, k, v);
              }
              _ { }
            }
        }
    }
    obj hashmap<copy K, copy V>(hasher: hashfn<K>,
                                eqer: eqfn<K>,
                                mutable bkts: [mutable bucket<K, V>],
                                mutable nbkts: uint,
                                mutable nelts: uint,
                                lf: util::rational) {
        fn size() -> uint { ret nelts; }
        fn insert(key: K, val: V) -> bool {
            let load: util::rational =
                {num: nelts + 1u as int, den: nbkts as int};
            if !util::rational_leq(load, lf) {
                let nnewbkts: uint = uint::next_power_of_two(nbkts + 1u);
                let newbkts = make_buckets(nnewbkts);
                rehash(hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
                bkts = newbkts;
                nbkts = nnewbkts;
            }
            if insert_common(hasher, eqer, bkts, nbkts, key, val) {
                nelts += 1u;
                ret true;
            }
            ret false;
        }
        fn contains_key(key: K) -> bool {
            ret alt find_common(hasher, eqer, bkts, nbkts, key) {
                  option::some(_) { true }
                  _ { false }
                };
        }
        fn get(key: K) -> V {
            ret alt find_common(hasher, eqer, bkts, nbkts, key) {
                  option::some(val) { val }
                  _ { fail }
                };
        }
        fn find(key: K) -> option::t<V> {
            be find_common(hasher, eqer, bkts, nbkts, key);
        }
        fn remove(key: K) -> option::t<V> {
            let i: uint = 0u;
            let h = to_u64(hasher(key));
            while i < nbkts {
                let j: uint = hash(h, nbkts, i);
                alt bkts[j] {
                  some(k, v) {
                    let k_ = k;
                    let vo = option::some(v);
                    if eqer(key, k_) {
                        bkts[j] = deleted;
                        nelts -= 1u;
                        ret vo;
                    }
                  }
                  deleted. { }
                  nil. { ret option::none; }
                }
                i += 1u;
            }
            ret option::none;
        }
        fn rehash() {
            let newbkts = make_buckets(nbkts);
            rehash(hasher, eqer, bkts, nbkts, newbkts, nbkts);
            bkts = newbkts;
        }
        fn items(it: block(K, V)) {
            for b in bkts {
                alt b { some(k, v) { it(copy k, copy v); } _ { } }
            }
        }
        fn keys(it: block(K)) {
            for b in bkts {
                alt b { some(k, _) { it(copy k); } _ { } }
            }
        }
        fn values(it: block(V)) {
            for b in bkts {
                alt b { some(_, v) { it(copy v); } _ { } }
            }
        }
    }
    let bkts = make_buckets(initial_capacity);
    ret hashmap(hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}

/*
Function: new_str_hash

Construct a hashmap for string keys
*/
fn new_str_hash<copy V>() -> hashmap<str, V> {
    ret mk_hashmap(str::hash, str::eq);
}

/*
Function: new_int_hash

Construct a hashmap for int keys
*/
fn new_int_hash<copy V>() -> hashmap<int, V> {
    fn hash_int(&&x: int) -> uint { ret x as uint; }
    fn eq_int(&&a: int, &&b: int) -> bool { ret a == b; }
    ret mk_hashmap(hash_int, eq_int);
}

/*
Function: new_uint_hash

Construct a hashmap for uint keys
*/
fn new_uint_hash<copy V>() -> hashmap<uint, V> {
    fn hash_uint(&&x: uint) -> uint { ret x; }
    fn eq_uint(&&a: uint, &&b: uint) -> bool { ret a == b; }
    ret mk_hashmap(hash_uint, eq_uint);
}

/*
Function: set_add

Convenience function for adding keys to a hashmap with nil type keys
*/
fn set_add<K>(set: hashset<K>, key: K) -> bool { ret set.insert(key, ()); }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

//! [`Uuid`] parsing constructs and utilities.
//!
//! [`Uuid`]: ../struct.Uuid.html

use core::fmt;

mod core_support;
#[cfg(feature = "std")]
mod std_support;

/// The expected value.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Expected<T>
where
    T: AsRef<[usize]> + fmt::Debug,
{
    /// Expected any one of the given values.
    Any(T),
    /// Expected the given value.
    Exact(usize),
    /// Expected any values in the given range.
    Range {
        /// The minimum expected value.
        min: usize,
        /// The maximum expected value.
        max: usize,
    },
}

/// An error that can occur while parsing a [`Uuid`] string.
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum UuidParseError<'chars, T>
where
    T: AsRef<[usize]> + fmt::Debug,
{
    /// Invalid character in the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    InvalidCharacter {
        /// The expected characters.
        expected: &'chars str,
        /// The invalid character found.
        found: char,
        /// The invalid character position.
        index: usize,
    },
    /// Invalid number of segments in the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    InvalidGroupCount {
        /// The expected number of segments.
        // TODO: explain multiple segment count.
        // BODY: Parsers can expect a range of Uuid segment count.
        //       This needs to be expanded on.
        expected: T,
        /// The number of segments found.
        found: usize,
    },
    /// Invalid length of a segment in a [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    InvalidGroupLength {
        /// The expected length of the segment.
        expected: T,
        /// The length of segment found.
        found: usize,
        /// The segment with invalid length.
        group: usize,
    },
    /// Invalid length of the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    InvalidLength {
        /// The expected length(s).
        // TODO: explain multiple lengths.
        // BODY: Parsers can expect a range of Uuid lenghts.
        //       This needs to be expanded on.
        expected: T,
        /// The invalid length found.
        found: usize,
    },
}

/// Check if the length matches the given criterion length.
// TODO: Find another way handling this.
// BODY: This is not idiomatic.
#[inline]
pub fn len_matches(len: usize, crit: usize) -> bool {
    len == crit
}

/// Check if the length matches any of the given criteria lengths.
pub fn len_matches_any(len: usize, crits: &[usize]) -> bool {
    for crit in crits {
        if let true = len_matches(len, *crit) {
            return true;
        }
    }

    false
}
<commit_msg>fix UuidParseError to use Expected<T> instead of T<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

//! [`Uuid`] parsing constructs and utilities.
//!
//! [`Uuid`]: ../struct.Uuid.html

use core::fmt;

mod core_support;
#[cfg(feature = "std")]
mod std_support;

/// The expected value.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Expected<T>
where
    T: AsRef<[usize]> + fmt::Debug,
{
    /// Expected any one of the given values.
    Any(T),
    /// Expected the given value.
    Exact(usize),
    /// Expected any values in the given range.
    Range {
        /// The minimum expected value.
        min: usize,
        /// The maximum expected value.
        max: usize,
    },
}

/// An error that can occur while parsing a [`Uuid`] string.
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum UuidParseError<'chars, T>
where
    T: AsRef<[usize]> + fmt::Debug,
{
    /// Invalid character in the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    InvalidCharacter {
        /// The expected characters.
        expected: &'chars str,
        /// The invalid character found.
        found: char,
        /// The invalid character position.
        index: usize,
    },
    /// Invalid number of segments in the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    InvalidGroupCount {
        /// The expected number of segments.
        // TODO: explain multiple segment count.
        // BODY: Parsers can expect a range of Uuid segment count.
        //       This needs to be expanded on.
        expected: Expected<T>,
        /// The number of segments found.
        found: usize,
    },
    /// Invalid length of a segment in a [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    InvalidGroupLength {
        /// The expected length of the segment.
        expected: Expected<T>,
        /// The length of segment found.
        found: usize,
        /// The segment with invalid length.
        group: usize,
    },
    /// Invalid length of the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    InvalidLength {
        /// The expected length(s).
        // TODO: explain multiple lengths.
        // BODY: Parsers can expect a range of Uuid lenghts.
        //       This needs to be expanded on.
        expected: Expected<T>,
        /// The invalid length found.
        found: usize,
    },
}

/// Check if the length matches the given criterion length.
// TODO: Find another way handling this.
// BODY: This is not idiomatic.
#[inline]
pub fn len_matches(len: usize, crit: usize) -> bool {
    len == crit
}

/// Check if the length matches any of the given criteria lengths.
pub fn len_matches_any(len: usize, crits: &[usize]) -> bool {
    for crit in crits {
        if let true = len_matches(len, *crit) {
            return true;
        }
    }

    false
}
<|endoftext|>