<commit_before>//https://github.com/andelf/rust-postgis
use postgis as geom;
use postgis::{SRID,WGS84};
use core::screen;
use std::f64::consts;

#[allow(missing_copy_implementations)]
#[allow(non_camel_case_types)]
pub enum EPSG_3857 {}

impl SRID for EPSG_3857 {
    fn as_srid() -> Option<i32> { Some(3857) }
}

#[derive(PartialEq,Debug)]
pub struct LngLat {
    pub lon: f64,
    pub lat: f64,
}

#[derive(PartialEq,Debug)]
pub struct Extent {
    pub minx: f64,
    pub miny: f64,
    pub maxx: f64,
    pub maxy: f64,
}

impl Extent {
    /// Convert geometry to tile relative coordinates
    fn geom_in_tile_extent(&self, tile_size: u32, geom: geom::Point<EPSG_3857>) -> screen::Point {
        let x_span = self.maxx - self.minx;
        let y_span = self.maxy - self.miny;
        screen::Point {
            x: ((geom.x-self.minx) * tile_size as f64 / x_span) as i32,
            y: ((geom.y-self.miny) * tile_size as f64 / y_span) as i32 }
    }
}

#[test]
fn test_geom_in_tile_extent() {
    //let zh_mercator = geom::Point::<EPSG_3857>::new(949398.0, 6002729.0);
    let zh_mercator = geom::Point::<EPSG_3857>::new(960000.0, 6002729.0);
    //let zh_wgs84 = geom::Point::<WGS84>::new(47.3703149, 8.5285874);
    let tile_extent = Extent {minx: 958826.08, miny: 5987771.04, maxx: 978393.96, maxy: 6007338.92};
    let screen_pt = tile_extent.geom_in_tile_extent(
        4096, zh_mercator);
    assert_eq!(screen_pt, screen::Point { x: 245, y: 3131 });
    //assert_eq!(screen_pt.encode().0, &[9,490,6262]);
}

// Credits: MapCache by Thomas Bonfort (http://mapserver.org/mapcache/)
pub struct Grid {
    /// The width and height of an individual tile, in pixels. Must be specified as positive integers separated by a space character.
    width: u16,
    height: u16,
    /// The geographical extent covered by the grid, in ground units (e.g. meters, degrees, feet, etc.). Must be specified as 4 floating point numbers ordered as minx, miny, maxx, maxy.
    /// The (minx,miny) point defines the origin of the grid, i.e. the pixel at the bottom left of the bottom-left most tile is always placed on the (minx,miny) geographical point.
    /// The (maxx,maxy) point is used to determine how many tiles there are for each zoom level.
    extent: Extent,
    //srs: SRID,
    //units: m/dd/ft
    /// This is a list of resolutions for each of the zoom levels defined by the grid. This must be supplied as a list of positive floating point values, ordered from largest to smallest.
    /// The largest value will correspond to the grid’s zoom level 0. Resolutions are expressed in “units-per-pixel”, depending on the unit used by the grid (e.g. resolutions are in meters per pixel for most grids used in webmapping).
    resolutions: Vec<f64>
    //origin: top-left, bottom-left, top-right and bottom-right
}

/// Returns the upper left (lon, lat) of a tile
// Credits: Mercantile by Sean C. Gillies (https://github.com/mapbox/mercantile)
fn ul(xtile: u16, ytile: u16, zoom: u16) -> LngLat {
    let n = (zoom as f64).exp2();
    let lon_deg = xtile as f64 / n * 360.0 - 180.0;
    let lat_rad = (consts::PI * (1.0_f64 - 2.0_f64 * ytile as f64 / n)).sinh().atan();
    let lat_deg = lat_rad.to_degrees();
    LngLat {lon: lon_deg, lat: lat_deg}
}

/// Returns the Spherical Mercator (x, y) in meters
fn xy(lon: f64, lat: f64) -> (f64, f64) {
    //lng, lat = truncate_lnglat(lng, lat)
    let x = 6378137.0_f64 * lon.to_radians();
    let y = 6378137.0_f64 *
        ((consts::PI*0.25) + (0.5_f64 * lat.to_radians())).tan().ln();
    (x, y)
}

#[test]
fn test_ul() {
    let lnglat = ul(486, 332, 10);
    assert_eq!(lnglat, LngLat {lon: -9.140625, lat: 53.33087298301705});
}

#[test]
fn test_xy() {
    let ul = ul(486, 332, 10);
    let xy_ = xy(ul.lon, ul.lat);
    assert_eq!(xy_, (-1017529.7205322663, 7044436.526761846));
    assert_eq!(xy(0.0, 0.0), (0.0, -0.0000000007081154551613622));
}

impl Grid {
    /// Returns the (lon, lat) bounding box of a tile
    pub fn tile_bounds(&self, xtile: u16, ytile: u16, zoom: u16) -> Extent {
        let a = ul(xtile, ytile, zoom);
        let b = ul(xtile+1, ytile+1, zoom);
        Extent {minx: a.lon, miny: b.lat, maxx: b.lon, maxy: a.lat}
    }
    /// Returns the Spherical Mercator bounding box of a tile
    pub fn tile_extent(&self, xtile: u16, ytile: u16, zoom: u16) -> Extent {
        let a = ul(xtile, ytile, zoom);
        let (ax, ay) = xy(a.lon, a.lat);
        let b = ul(xtile+1, ytile+1, zoom);
        let (bx, by) = xy(b.lon, b.lat);
        Extent {minx: ax, miny: by, maxx: bx, maxy: ay}
    }
}

#[test]
fn test_bbox() {
    let grid = Grid {width: 256, height: 256, extent: Extent {minx: 0.0, miny: 0.0, maxx: 0.0, maxy: 0.0}, resolutions: Vec::new()};

    let bbox = grid.tile_bounds(486, 332, 10);
    assert_eq!(bbox, Extent {minx: -9.140625, miny: 53.120405283106564, maxx: -8.7890625, maxy: 53.33087298301705});
    //Mercantile: miny: 53.12040528310657

    let extent = grid.tile_extent(486, 332, 10);
    assert_eq!(extent, Extent {minx: -1017529.7205322663, miny: 7005300.768279833, maxx: -978393.962050256, maxy: 7044436.526761846});
}
<commit_msg>Tile bounds from grid resolutions<commit_after>//https://github.com/andelf/rust-postgis
use postgis as geom;
use postgis::{SRID,WGS84};
use core::screen;
use std::f64::consts;

#[allow(missing_copy_implementations)]
#[allow(non_camel_case_types)]
pub enum EPSG_3857 {}

impl SRID for EPSG_3857 {
    fn as_srid() -> Option<i32> { Some(3857) }
}

#[derive(PartialEq,Debug)]
pub struct LngLat {
    pub lon: f64,
    pub lat: f64,
}

#[derive(PartialEq,Debug)]
pub struct Extent {
    pub minx: f64,
    pub miny: f64,
    pub maxx: f64,
    pub maxy: f64,
}

impl Extent {
    /// Convert geometry to tile relative coordinates
    fn geom_in_tile_extent(&self, tile_size: u32, geom: geom::Point<EPSG_3857>) -> screen::Point {
        let x_span = self.maxx - self.minx;
        let y_span = self.maxy - self.miny;
        screen::Point {
            x: ((geom.x-self.minx) * tile_size as f64 / x_span) as i32,
            y: ((geom.y-self.miny) * tile_size as f64 / y_span) as i32 }
    }
}

#[test]
fn test_geom_in_tile_extent() {
    //let zh_mercator = geom::Point::<EPSG_3857>::new(949398.0, 6002729.0);
    let zh_mercator = geom::Point::<EPSG_3857>::new(960000.0, 6002729.0);
    //let zh_wgs84 = geom::Point::<WGS84>::new(47.3703149, 8.5285874);
    let tile_extent = Extent {minx: 958826.08, miny: 5987771.04, maxx: 978393.96, maxy: 6007338.92};
    let screen_pt = tile_extent.geom_in_tile_extent(
        4096, zh_mercator);
    assert_eq!(screen_pt, screen::Point { x: 245, y: 3131 });
    //assert_eq!(screen_pt.encode().0, &[9,490,6262]);
}

// Credits: MapCache by Thomas Bonfort (http://mapserver.org/mapcache/)
pub struct Grid {
    /// The width and height of an individual tile, in pixels. Must be specified as positive integers separated by a space character.
    width: u16,
    height: u16,
    /// The geographical extent covered by the grid, in ground units (e.g. meters, degrees, feet, etc.). Must be specified as 4 floating point numbers ordered as minx, miny, maxx, maxy.
    /// The (minx,miny) point defines the origin of the grid, i.e. the pixel at the bottom left of the bottom-left most tile is always placed on the (minx,miny) geographical point.
    /// The (maxx,maxy) point is used to determine how many tiles there are for each zoom level.
    extent: Extent,
    //srs: SRID,
    //units: m/dd/ft
    /// This is a list of resolutions for each of the zoom levels defined by the grid. This must be supplied as a list of positive floating point values, ordered from largest to smallest.
    /// The largest value will correspond to the grid’s zoom level 0. Resolutions are expressed in “units-per-pixel”, depending on the unit used by the grid (e.g. resolutions are in meters per pixel for most grids used in webmapping).
    resolutions: &'static[f64]
    //origin: top-left, bottom-left, top-right and bottom-right
}

// --- Predefined grids ---

const WGS84_RESOLUTIONS: [f64; 18] = [
    0.703125000000000,
    0.351562500000000,
    0.175781250000000,
    8.78906250000000e-2,
    4.39453125000000e-2,
    2.19726562500000e-2,
    1.09863281250000e-2,
    5.49316406250000e-3,
    2.74658203125000e-3,
    1.37329101562500e-3,
    6.86645507812500e-4,
    3.43322753906250e-4,
    1.71661376953125e-4,
    8.58306884765625e-5,
    4.29153442382812e-5,
    2.14576721191406e-5,
    1.07288360595703e-5,
    5.36441802978516e-6
];

const GOOGLE_RESOLUTIONS: [f64; 19] = [
    156543.0339280410,
    78271.51696402048,
    39135.75848201023,
    19567.87924100512,
    9783.939620502561,
    4891.969810251280,
    2445.984905125640,
    1222.992452562820,
    611.4962262814100,
    305.7481131407048,
    152.8740565703525,
    76.43702828517624,
    38.21851414258813,
    19.10925707129406,
    9.554628535647032,
    4.777314267823516,
    2.388657133911758,
    1.194328566955879,
    0.5971642834779395
];

static WGS84_GRID: Grid = Grid {
    width: 256, height: 256,
    extent: Extent {minx: -180.0, miny: -90.0, maxx: 180.0, maxy: 90.0},
    resolutions: &WGS84_RESOLUTIONS
};

static GOOGLE_GRID: Grid = Grid {
    width: 256, height: 256,
    extent: Extent {minx: -20037508.3427892480, miny: -20037508.3427892480,
                    maxx: 20037508.3427892480, maxy: 20037508.3427892480},
    resolutions: &GOOGLE_RESOLUTIONS
};

impl Grid {
    /// Extent of a given tile in the grid given its x, y, and z
    pub fn tile_extent(&self, xtile: u16, ytile: u16, zoom: u16) -> Extent {
        let res = self.resolutions[zoom as usize];
        let tile_sx = self.width as f64;
        let tile_sy = self.height as f64;
        Extent {
            minx: self.extent.minx + (res * xtile as f64 * tile_sx),
            miny: self.extent.miny + (res * ytile as f64 * tile_sy),
            maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
            maxy: self.extent.miny + (res * (ytile + 1) as f64 * tile_sy),
        }
        /* ORIGIN_TOP_LEFT:
            minx: self.extent.minx + (res * xtile as f64 * tile_sx),
            miny: self.extent.maxy - (res * (ytile + 1) as f64 * tile_sy),
            maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
            maxy: self.extent.maxy - (res * ytile as f64 * tile_sy)
        */
    }
    /// Extent of a given tile in GoogleMaps XYZ adressing scheme
    pub fn tile_extent_xyz(&self, xtile: u16, ytile: u16, zoom: u16) -> Extent {
        let res = self.resolutions[zoom as usize];
        let unitheight = self.height as f64 * res;
        let maxy = ((self.extent.maxy-self.extent.minx- 0.01* unitheight)/unitheight).ceil() as u16;
        let y = maxy-ytile-1;
        self.tile_extent(xtile, y, zoom)
    }
}

#[test]
fn test_bbox() {
    let grid = &GOOGLE_GRID;

    let extent000 = grid.tile_extent(0, 0, 0);
    assert_eq!(extent000, Extent {minx: -20037508.342789248, miny: -20037508.342789248, maxx: 20037508.342789248, maxy: 20037508.342789248});

    let extent = grid.tile_extent_xyz(486, 332, 10);
    assert_eq!(extent, Extent {minx: -1017529.7205322683, miny: 7005300.768279828, maxx: -978393.9620502591, maxy: 7044436.526761841});
}

// --- Google Mercator calculations ---
// Credits: Mercantile by Sean C. Gillies (https://github.com/mapbox/mercantile)

/// Returns the upper left (lon, lat) of a tile
fn ul(xtile: u16, ytile: u16, zoom: u16) -> LngLat {
    let n = (zoom as f64).exp2();
    let lon_deg = xtile as f64 / n * 360.0 - 180.0;
    let lat_rad = (consts::PI * (1.0_f64 - 2.0_f64 * ytile as f64 / n)).sinh().atan();
    let lat_deg = lat_rad.to_degrees();
    LngLat {lon: lon_deg, lat: lat_deg}
}

/// Returns the Spherical Mercator (x, y) in meters
fn xy(lon: f64, lat: f64) -> (f64, f64) {
    //lng, lat = truncate_lnglat(lng, lat)
    let x = 6378137.0_f64 * lon.to_radians();
    let y = 6378137.0_f64 *
        ((consts::PI*0.25) + (0.5_f64 * lat.to_radians())).tan().ln();
    (x, y)
}

/// Returns the Spherical Mercator bounding box of a tile
fn tile_extent(xtile: u16, ytile: u16, zoom: u16) -> Extent {
    let a = ul(xtile, ytile, zoom);
    let (ax, ay) = xy(a.lon, a.lat);
    let b = ul(xtile+1, ytile+1, zoom);
    let (bx, by) = xy(b.lon, b.lat);
    Extent {minx: ax, miny: by, maxx: bx, maxy: ay}
}

/// Returns the (lon, lat) bounding box of a tile
fn tile_bounds(xtile: u16, ytile: u16, zoom: u16) -> Extent {
    let a = ul(xtile, ytile, zoom);
    let b = ul(xtile+1, ytile+1, zoom);
    Extent {minx: a.lon, miny: b.lat, maxx: b.lon, maxy: a.lat}
}

#[test]
fn test_ul() {
    let lnglat = ul(486, 332, 10);
    assert_eq!(lnglat, LngLat {lon: -9.140625, lat: 53.33087298301705});
}

#[test]
fn test_xy() {
    let ul = ul(486, 332, 10);
    let xy_ = xy(ul.lon, ul.lat);
    assert_eq!(xy_, (-1017529.7205322663, 7044436.526761846));
    assert_eq!(xy(0.0, 0.0), (0.0, -0.0000000007081154551613622));
}

#[test]
fn test_merc_tile_extent() {
    let extent = tile_extent(486, 332, 10);
    assert_eq!(extent, Extent {minx: -1017529.7205322663, miny: 7005300.768279833, maxx: -978393.962050256, maxy: 7044436.526761846});
}

#[test]
fn test_merc_tile_bounds() {
    let bbox = tile_bounds(486, 332, 10);
    assert_eq!(bbox, Extent {minx: -9.140625, miny: 53.120405283106564, maxx: -8.7890625, maxy: 53.33087298301705});
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::io::{self, Cursor, Read};
use std::marker::PhantomData;
use std::mem;

use crate::color::ColorType;
use crate::image::ImageDecoder;
use crate::error::{ImageError, ImageResult};

/// JPEG decoder
pub struct JpegDecoder<R> {
    decoder: jpeg::Decoder<R>,
    metadata: jpeg::ImageInfo,
}

impl<R: Read> JpegDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(r: R) -> ImageResult<JpegDecoder<R>> {
        let mut decoder = jpeg::Decoder::new(r);

        decoder.read_info().map_err(ImageError::from_jpeg)?;
        let mut metadata = decoder.info().unwrap();

        // We convert CMYK data to RGB before returning it to the user.
        if metadata.pixel_format == jpeg::PixelFormat::CMYK32 {
            metadata.pixel_format = jpeg::PixelFormat::RGB24;
        }

        Ok(JpegDecoder {
            decoder,
            metadata,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct JpegReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for JpegReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for JpegDecoder<R> {
    type Reader = JpegReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (u32::from(self.metadata.width), u32::from(self.metadata.height))
    }

    fn color_type(&self) -> ColorType {
        ColorType::from_jpeg(self.metadata.pixel_format)
    }

    fn into_reader(mut self) -> ImageResult<Self::Reader> {
        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        Ok(JpegReader(Cursor::new(data), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        buf.copy_from_slice(&data);
        Ok(())
    }
}

fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
    let size = input.len() - input.len() / 4;
    let mut output = Vec::with_capacity(size);

    let inv = 1.0 / 255.0;
    for pixel in input.chunks(4) {
        let c = f32::from(pixel[0]);
        let m = f32::from(pixel[1]);
        let y = f32::from(pixel[2]);
        let k = 255.0 - f32::from(pixel[3]);

        let k_sub = -k;
        let k = k * 255.0;
        // CMY -> RGB
        let r = (c * k_sub + k) * inv;
        let g = (y * k_sub + k) * inv;
        let b = (m * k_sub + k) * inv;

        output.push(r as u8);
        output.push(g as u8);
        output.push(b as u8);
    }

    output
}

impl ColorType {
    fn from_jpeg(pixel_format: jpeg::PixelFormat) -> ColorType {
        use jpeg::PixelFormat::*;
        match pixel_format {
            L8 => ColorType::L8,
            RGB24 => ColorType::Rgb8,
            CMYK32 => panic!(),
        }
    }
}

impl ImageError {
    fn from_jpeg(err: jpeg::Error) -> ImageError {
        use jpeg::Error::*;
        match err {
            Format(desc) => ImageError::FormatError(desc),
            Unsupported(desc) => ImageError::UnsupportedError(format!("{:?}", desc)),
            Io(err) => ImageError::IoError(err),
            Internal(err) => ImageError::FormatError(err.to_string()),
        }
    }
}

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

    #[test]
    fn cymk_to_rgb_correct() {
        // Based on R = 255 * (1-C/255) * (1-K/255)
        for c in 0..255 {
            for k in 0..255 {
                let r = (255.0 - f32::from(c)) * (255.0 - f32::from(k)) / 255.0;
                let r_u8 = r as u8;
                let convert_r = cmyk_to_rgb(&[c, 0, 0, k])[0];
                assert_eq!(convert_r, r_u8,
                           "c = {}, k = {}, cymk_to_rgb[0] = {}, should be {}", c, k, convert_r, r_u8);
            }
        }
    }
}

<commit_msg>Clean up cymk_to_rgb code.<commit_after>use std::convert::TryFrom;
use std::io::{self, Cursor, Read};
use std::marker::PhantomData;
use std::mem;

use crate::color::ColorType;
use crate::image::ImageDecoder;
use crate::error::{ImageError, ImageResult};

/// JPEG decoder
pub struct JpegDecoder<R> {
    decoder: jpeg::Decoder<R>,
    metadata: jpeg::ImageInfo,
}

impl<R: Read> JpegDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(r: R) -> ImageResult<JpegDecoder<R>> {
        let mut decoder = jpeg::Decoder::new(r);

        decoder.read_info().map_err(ImageError::from_jpeg)?;
        let mut metadata = decoder.info().unwrap();

        // We convert CMYK data to RGB before returning it to the user.
        if metadata.pixel_format == jpeg::PixelFormat::CMYK32 {
            metadata.pixel_format = jpeg::PixelFormat::RGB24;
        }

        Ok(JpegDecoder {
            decoder,
            metadata,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct JpegReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for JpegReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for JpegDecoder<R> {
    type Reader = JpegReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (u32::from(self.metadata.width), u32::from(self.metadata.height))
    }

    fn color_type(&self) -> ColorType {
        ColorType::from_jpeg(self.metadata.pixel_format)
    }

    fn into_reader(mut self) -> ImageResult<Self::Reader> {
        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        Ok(JpegReader(Cursor::new(data), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        buf.copy_from_slice(&data);
        Ok(())
    }
}

fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
    let size = input.len() - input.len() / 4;
    let mut output = Vec::with_capacity(size);

    let inv = 1.0 / 255.0;
    for pixel in input.chunks(4) {
        let c = f32::from(pixel[0]);
        let m = f32::from(pixel[1]);
        let y = f32::from(pixel[2]);
        let k = 255.0 - f32::from(pixel[3]);

        let k_mul = k * 255.0;
        // CMY -> RGB
        let r = (k_mul - c * k) * inv;
        let g = (k_mul - m * k) * inv;
        let b = (k_mul - y * k) * inv;

        output.push(r as u8);
        output.push(g as u8);
        output.push(b as u8);
    }

    output
}

impl ColorType {
    fn from_jpeg(pixel_format: jpeg::PixelFormat) -> ColorType {
        use jpeg::PixelFormat::*;
        match pixel_format {
            L8 => ColorType::L8,
            RGB24 => ColorType::Rgb8,
            CMYK32 => panic!(),
        }
    }
}

impl ImageError {
    fn from_jpeg(err: jpeg::Error) -> ImageError {
        use jpeg::Error::*;
        match err {
            Format(desc) => ImageError::FormatError(desc),
            Unsupported(desc) => ImageError::UnsupportedError(format!("{:?}", desc)),
            Io(err) => ImageError::IoError(err),
            Internal(err) => ImageError::FormatError(err.to_string()),
        }
    }
}

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

    #[test]
    fn cymk_to_rgb_correct() {
        // Based on R = 255 * (1-C/255) * (1-K/255)
        for c in 0..255 {
            for k in 0..255 {
                let r = (255.0 - f32::from(c)) * (255.0 - f32::from(k)) / 255.0;
                let r_u8 = r as u8;
                let convert_r = cmyk_to_rgb(&[c, 0, 0, k])[0];
                assert_eq!(convert_r, r_u8,
                           "c = {}, k = {}, cymk_to_rgb[0] = {}, should be {}", c, k, convert_r, r_u8);
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::io::{self, Write};
use termion::event::Key;

use KeyMap;
use Editor;

pub struct Emacs<'a, W: Write> {
    ed: Editor<'a, W>,
}

impl<'a, W: Write> Emacs<'a, W> {
    pub fn new(ed: Editor<'a, W>) -> Self {
        Emacs { ed: ed }
    }

    fn handle_ctrl_key(&mut self, c: char) -> io::Result<()> {
        match c {
            'l' => self.ed.clear(),
            'a' => self.ed.move_cursor_to_start_of_line(),
            'e' => self.ed.move_cursor_to_end_of_line(),
            'b' => self.ed.move_cursor_left(1),
            'f' => self.ed.move_cursor_right(1),
            'd' => self.ed.delete_after_cursor(),
            'p' => self.ed.move_up(),
            'n' => self.ed.move_down(),
            'u' => self.ed.delete_all_before_cursor(),
            'k' => self.ed.delete_all_after_cursor(),
            'w' => self.ed.delete_word_before_cursor(true),
            'x' => {
                try!(self.ed.undo());
                Ok(())
            }
            _ => Ok(()),
        }
    }

    fn handle_alt_key(&mut self, c: char) -> io::Result<()> {
        match c {
            '<' => self.ed.move_to_start_of_history(),
            '>' => self.ed.move_to_end_of_history(),
            '\x7F' => self.ed.delete_word_before_cursor(true),
            'f' => emacs_move_word(&mut self.ed, EmacsMoveDir::Right),
            'b' => emacs_move_word(&mut self.ed, EmacsMoveDir::Left),
            'r' => {
                try!(self.ed.revert());
                Ok(())
            }
            _ => Ok(()),
        }
    }
}

impl<'a, W: Write> KeyMap<'a, W, Emacs<'a, W>> for Emacs<'a, W> {
    fn handle_key_core(&mut self, key: Key) -> io::Result<()> {
        match key {
            Key::Char(c) => self.ed.insert_after_cursor(c),
            Key::Alt(c) => self.handle_alt_key(c),
            Key::Ctrl(c) => self.handle_ctrl_key(c),
            Key::Left => self.ed.move_cursor_left(1),
            Key::Right => self.ed.move_cursor_right(1),
            Key::Up => self.ed.move_up(),
            Key::Down => self.ed.move_down(),
            Key::Home => self.ed.move_cursor_to_start_of_line(),
            Key::End => self.ed.move_cursor_to_end_of_line(),
            Key::Backspace => self.ed.delete_before_cursor(),
            Key::Delete => self.ed.delete_after_cursor(),
            Key::Null => Ok(()),
            _ => Ok(()),
        }
    }

    fn editor_mut(&mut self) ->  &mut Editor<'a, W> {
        &mut self.ed
    }

    fn editor(&self) ->  &Editor<'a, W> {
        &self.ed
    }
}

impl<'a, W: Write> From<Emacs<'a, W>> for String {
    fn from(emacs: Emacs<'a, W>) -> String {
        emacs.ed.into()
    }
}

#[derive(PartialEq, Clone, Copy)]
enum EmacsMoveDir {
    Left,
    Right,
}

impl EmacsMoveDir {
    fn advance(&self, cursor: &mut usize, max: usize) -> bool {
        if *self == EmacsMoveDir::Right && *cursor == max {
            return false;
        }

        if *self == EmacsMoveDir::Left && *cursor == 0 {
            return false;
        }

        match *self {
            EmacsMoveDir::Right => *cursor += 1,
            EmacsMoveDir::Left => *cursor -= 1,
        }

        true
    }
}

fn emacs_move_word<W: Write>(ed: &mut Editor<W>, direction: EmacsMoveDir) -> io::Result<()> {
    enum State {
        Word,
        NonWord,
    }

    let mut cursor = ed.cursor();

    {
        let buf = ed.current_buffer();

        let next_char = |cursor| {
            match direction {
                EmacsMoveDir::Right => buf.char_after(cursor),
                EmacsMoveDir::Left => buf.char_before(cursor),
            }
        };

        let mut state = match next_char(cursor) {
            None => return Ok(()),
            Some(c) => {
                match c {
                    c if is_emacs_word(c) => State::Word,
                    _ => State::NonWord,
                }
            },
        };

        // Skip non-words until a word is found, then stop at the character after the word
        while direction.advance(&mut cursor, buf.num_chars()) {
            let c = match next_char(cursor) {
                Some(c) => c,
                _ => break,
            };

            match state {
                State::NonWord => match c {
                    c if is_emacs_word(c) => state = State::Word,
                    _ => {},
                },
                State::Word => match c {
                    c if !is_emacs_word(c) => break,
                    _ => {},
                },
            }
        }
    }

    ed.move_cursor_to(cursor)
}

fn is_emacs_word(c: char) -> bool {
    c.is_alphanumeric()
}

#[cfg(test)]
mod tests {
    use super::*;
    use termion::event::Key;
    use Context;
    use Editor;
    use KeyMap;
    use std::io::Write;

    macro_rules! simulate_keys {
        ($keymap:ident, $keys:expr) => {{
            simulate_keys(&mut $keymap, $keys.into_iter())
        }}
    }

    fn simulate_keys<'a, 'b, W: Write, T, M: KeyMap<'a, W, T>, I>(keymap: &mut M, keys: I) -> bool
        where I: Iterator<Item = &'b Key>
    {
        for k in keys {
            if keymap.handle_key(*k, &mut |_| {}).unwrap() {
                return true;
            }
        }

        false
    }

    #[test]
    fn enter_is_done() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = Emacs::new(ed);
        map.ed.insert_str_after_cursor("done").unwrap();
        assert_eq!(map.ed.cursor(), 4);

        assert!(simulate_keys!(map, [Key::Char('\n')]));

        assert_eq!(map.ed.cursor(), 4);
        assert_eq!(String::from(map), "done");
    }

    #[test]
    fn move_cursor_left() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = Emacs::new(ed);
        map.editor_mut().insert_str_after_cursor("let").unwrap();
        assert_eq!(map.ed.cursor(), 3);

        simulate_keys!(map, [Key::Left, Key::Char('f')]);

        assert_eq!(map.ed.cursor(), 3);
        assert_eq!(String::from(map), "left");
    }

    #[test]
    fn move_word() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = Emacs::new(ed);
        map.editor_mut().insert_str_after_cursor("abc def ghi").unwrap();
        assert_eq!(map.ed.cursor(), 11);

        simulate_keys!(map, [Key::Alt('b')]);

        // Move to `g`
        assert_eq!(map.ed.cursor(), 8);

        simulate_keys!(map, [Key::Alt('b'), Key::Alt('f')]);

        // Move to the char after `f`
        assert_eq!(map.ed.cursor(), 7);
    }

    #[test]
    fn cursor_movement() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = Emacs::new(ed);
        map.ed.insert_str_after_cursor("right").unwrap();
        assert_eq!(map.ed.cursor(), 5);

        simulate_keys!(map, [Key::Left, Key::Left, Key::Right]);

        assert_eq!(map.ed.cursor(), 4);
    }
}
<commit_msg>Rewrite emacs_move_word to use Editor::get_words_and_cursor_position<commit_after>use std::io::{self, Write};
use termion::event::Key;

use KeyMap;
use Editor;
use CursorPosition;

pub struct Emacs<'a, W: Write> {
    ed: Editor<'a, W>,
}

impl<'a, W: Write> Emacs<'a, W> {
    pub fn new(ed: Editor<'a, W>) -> Self {
        Emacs { ed: ed }
    }

    fn handle_ctrl_key(&mut self, c: char) -> io::Result<()> {
        match c {
            'l' => self.ed.clear(),
            'a' => self.ed.move_cursor_to_start_of_line(),
            'e' => self.ed.move_cursor_to_end_of_line(),
            'b' => self.ed.move_cursor_left(1),
            'f' => self.ed.move_cursor_right(1),
            'd' => self.ed.delete_after_cursor(),
            'p' => self.ed.move_up(),
            'n' => self.ed.move_down(),
            'u' => self.ed.delete_all_before_cursor(),
            'k' => self.ed.delete_all_after_cursor(),
            'w' => self.ed.delete_word_before_cursor(true),
            'x' => {
                try!(self.ed.undo());
                Ok(())
            }
            _ => Ok(()),
        }
    }

    fn handle_alt_key(&mut self, c: char) -> io::Result<()> {
        match c {
            '<' => self.ed.move_to_start_of_history(),
            '>' => self.ed.move_to_end_of_history(),
            '\x7F' => self.ed.delete_word_before_cursor(true),
            'f' => emacs_move_word(&mut self.ed, EmacsMoveDir::Right),
            'b' => emacs_move_word(&mut self.ed, EmacsMoveDir::Left),
            'r' => {
                try!(self.ed.revert());
                Ok(())
            }
            _ => Ok(()),
        }
    }
}

impl<'a, W: Write> KeyMap<'a, W, Emacs<'a, W>> for Emacs<'a, W> {
    fn handle_key_core(&mut self, key: Key) -> io::Result<()> {
        match key {
            Key::Char(c) => self.ed.insert_after_cursor(c),
            Key::Alt(c) => self.handle_alt_key(c),
            Key::Ctrl(c) => self.handle_ctrl_key(c),
            Key::Left => self.ed.move_cursor_left(1),
            Key::Right => self.ed.move_cursor_right(1),
            Key::Up => self.ed.move_up(),
            Key::Down => self.ed.move_down(),
            Key::Home => self.ed.move_cursor_to_start_of_line(),
            Key::End => self.ed.move_cursor_to_end_of_line(),
            Key::Backspace => self.ed.delete_before_cursor(),
            Key::Delete => self.ed.delete_after_cursor(),
            Key::Null => Ok(()),
            _ => Ok(()),
        }
    }

    fn editor_mut(&mut self) ->  &mut Editor<'a, W> {
        &mut self.ed
    }

    fn editor(&self) ->  &Editor<'a, W> {
        &self.ed
    }
}

impl<'a, W: Write> From<Emacs<'a, W>> for String {
    fn from(emacs: Emacs<'a, W>) -> String {
        emacs.ed.into()
    }
}

#[derive(PartialEq, Clone, Copy)]
enum EmacsMoveDir {
    Left,
    Right,
}

fn emacs_move_word<W: Write>(ed: &mut Editor<W>, direction: EmacsMoveDir) -> io::Result<()> {
    let (words, pos) = ed.get_words_and_cursor_position();

    let word_index = match pos {
        CursorPosition::InWord(i) => {
            Some(i)
        },
        CursorPosition::OnWordLeftEdge(mut i) => {
            if i > 0 && direction == EmacsMoveDir::Left {
                i -= 1;
            }
            Some(i)
        },
        CursorPosition::OnWordRightEdge(mut i) => {
            if i < words.len() - 1 && direction == EmacsMoveDir::Right {
                i += 1;
            }
            Some(i)
        },
        CursorPosition::InSpace(left, right) => {
            match direction {
                EmacsMoveDir::Left => left,
                EmacsMoveDir::Right => right,
            }
        },
    };

    match word_index {
        None => Ok(()),
        Some(i) => {
            let (start, end) = words[i];

            let new_cursor_pos = match direction {
                EmacsMoveDir::Left => start,
                EmacsMoveDir::Right => end,
            };

            ed.move_cursor_to(new_cursor_pos)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use termion::event::Key;
    use Context;
    use Editor;
    use KeyMap;
    use std::io::Write;

    macro_rules! simulate_keys {
        ($keymap:ident, $keys:expr) => {{
            simulate_keys(&mut $keymap, $keys.into_iter())
        }}
    }

    fn simulate_keys<'a, 'b, W: Write, T, M: KeyMap<'a, W, T>, I>(keymap: &mut M, keys: I) -> bool
        where I: Iterator<Item = &'b Key>
    {
        for k in keys {
            if keymap.handle_key(*k, &mut |_| {}).unwrap() {
                return true;
            }
        }

        false
    }

    #[test]
    fn enter_is_done() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = Emacs::new(ed);
        map.ed.insert_str_after_cursor("done").unwrap();
        assert_eq!(map.ed.cursor(), 4);

        assert!(simulate_keys!(map, [Key::Char('\n')]));

        assert_eq!(map.ed.cursor(), 4);
        assert_eq!(String::from(map), "done");
    }

    #[test]
    fn move_cursor_left() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = Emacs::new(ed);
        map.editor_mut().insert_str_after_cursor("let").unwrap();
        assert_eq!(map.ed.cursor(), 3);

        simulate_keys!(map, [Key::Left, Key::Char('f')]);

        assert_eq!(map.ed.cursor(), 3);
        assert_eq!(String::from(map), "left");
    }

    #[test]
    fn move_word() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = Emacs::new(ed);
        map.editor_mut().insert_str_after_cursor("abc def ghi").unwrap();
        assert_eq!(map.ed.cursor(), 11);

        simulate_keys!(map, [Key::Alt('b')]);

        // Move to `g`
        assert_eq!(map.ed.cursor(), 8);

        simulate_keys!(map, [Key::Alt('b'), Key::Alt('f')]);

        // Move to the char after `f`
        assert_eq!(map.ed.cursor(), 7);
    }

    #[test]
    fn cursor_movement() {
        let mut context = Context::new();
        let out = Vec::new();
        let ed = Editor::new(out, "prompt".to_owned(), &mut context).unwrap();
        let mut map = Emacs::new(ed);
        map.ed.insert_str_after_cursor("right").unwrap();
        assert_eq!(map.ed.cursor(), 5);

        simulate_keys!(map, [Key::Left, Key::Left, Key::Right]);

        assert_eq!(map.ed.cursor(), 4);
    }
}
<|endoftext|>


<commit_before>use nom::{alphanumeric, digit, multispace};
use std::collections::{HashSet, VecDeque};
use std::str;

use column::Column;
use common::{binary_comparison_operator, binary_logical_operator, column_identifier,
             unary_negation_operator, Operator};

#[derive(Clone, Debug, PartialEq)]
pub enum ConditionBase {
    Field(Column),
    Literal(String),
    Placeholder,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ConditionTree {
    pub operator: Operator,
    pub left: Option<Box<ConditionExpression>>,
    pub right: Option<Box<ConditionExpression>>,
}

impl<'a> ConditionTree {
    fn contained_columns(&self) -> HashSet<&'a Column> {
        let mut s = HashSet::new();
        let mut q = VecDeque::<&ConditionTree>::new();
        q.push_back(self);
        while let Some(ref ct) = q.pop_front() {
            match **ct.left.as_ref().unwrap() {
                ConditionExpression::Base(ConditionBase::Field(ref c)) => {
                    s.insert(c);
                }
                ConditionExpression::LogicalOp(ref ct) |
                ConditionExpression::ComparisonOp(ref ct) => q.push_back(ct),
                _ => (),
            }
        }
        s
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ConditionExpression {
    ComparisonOp(ConditionTree),
    LogicalOp(ConditionTree),
    Base(ConditionBase),
}

fn fold_cond_exprs(initial: ConditionExpression,
                   remainder: Vec<(Operator, ConditionExpression)>)
                   -> ConditionExpression {
    remainder.into_iter().fold(initial, |acc, pair| {
        let (oper, expr) = pair;
        match oper {
            Operator::Equal | Operator::Less | Operator::Greater | Operator::LessOrEqual |
            Operator::Like | Operator::GreaterOrEqual | Operator::NotEqual => {
                ConditionExpression::ComparisonOp(ConditionTree {
                    operator: oper.clone(),
                    left: Some(Box::new(acc)),
                    right: Some(Box::new(expr)),
                })
            }
            Operator::And | Operator::Or => {
                ConditionExpression::LogicalOp(ConditionTree {
                    operator: oper.clone(),
                    left: Some(Box::new(acc)),
                    right: Some(Box::new(expr)),
                })
            }
            o => {
                println!("unsupported op {:?}", o);
                unimplemented!()
            }
        }
    })
}

/// Parse a conditional expression into a condition tree structure
named!(pub condition_expr<&[u8], ConditionExpression>,
    chain!(
        neg_op: opt!(unary_negation_operator) ~
        initial: boolean_primary ~
        remainder: many0!(
            complete!(
                chain!(
                    log_op: delimited!(opt!(multispace),
                                       binary_logical_operator,
                                       opt!(multispace)) ~
                    right_expr: condition_expr,
                    || {
                        (log_op, right_expr)
                    }
                )
            )
        ),
        || {
            if let Some(Operator::Not) = neg_op {
                ConditionExpression::LogicalOp(
                    ConditionTree {
                        operator: Operator::Not,
                        left: Some(Box::new(fold_cond_exprs(initial, remainder))),
                        right: None,
                    }
                )
            } else {
                fold_cond_exprs(initial, remainder)
            }
        }
    )
);

named!(boolean_primary<&[u8], ConditionExpression>,
    chain!(
        initial: predicate ~
        remainder:
        many0!(
            complete!(
                chain!(
                    op: delimited!(opt!(multispace),
                                   binary_comparison_operator,
                                   opt!(multispace)) ~
                    right_expr: boolean_primary,
                    || {
                        (op, right_expr)
                    }
                )
            )
        ),
        || { fold_cond_exprs(initial, remainder) }
    )
);

named!(predicate<&[u8], ConditionExpression>,
    alt_complete!(
            chain!(
                delimited!(opt!(multispace), tag!("?"), opt!(multispace)),
                || {
                    ConditionExpression::Base(
                        ConditionBase::Placeholder
                    )
                }
            )
        |   chain!(
                field: delimited!(opt!(multispace), digit, opt!(multispace)),
                || {
                    ConditionExpression::Base(
                        ConditionBase::Literal(String::from(str::from_utf8(field).unwrap()))
                    )
                }
            )
        |   chain!(
                field: delimited!(opt!(multispace),
                                  alt_complete!(
                                        delimited!(tag!("\""), alphanumeric, tag!("\""))
                                      | delimited!(tag!("'"), alphanumeric, tag!("'"))
                                  ),
                                  opt!(multispace)),
                || {
                    ConditionExpression::Base(
                        ConditionBase::Literal(String::from(str::from_utf8(field).unwrap()))
                    )
                }
            )
        |   chain!(
                field: delimited!(opt!(multispace), column_identifier, opt!(multispace)),
                || {
                    ConditionExpression::Base(
                        ConditionBase::Field(field)
                    )
                }
            )
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use common::Operator;

    fn flat_condition_tree(op: Operator,
                           l: ConditionBase,
                           r: ConditionBase)
                           -> ConditionExpression {
        ConditionExpression::ComparisonOp(ConditionTree {
            operator: op,
            left: Some(Box::new(ConditionExpression::Base(l))),
            right: Some(Box::new(ConditionExpression::Base(r))),
        })
    }

    #[test]
    fn ct_contained_columns() {
        use std::collections::HashSet;

        let cond = "a.foo = ? and b.bar = 42";

        let res = condition_expr(cond.as_bytes());
        let expected_cols = HashSet::new();
        expected_cols.insert(&Column::from("a.foo"));
        expected_cols.insert(&Column::from("b.bar"));
        let cols = match res.unwrap().1 {
            ConditionExpression::LogicalOp(ref ct) => ct.contained_columns(),
            _ => panic!(),
        };
        assert_eq!(cols, expected_cols);
    }

    #[test]
    fn equality_placeholder() {
        let cond = "foo = ?";

        let res = condition_expr(cond.as_bytes());
        assert_eq!(res.unwrap().1,
                   flat_condition_tree(Operator::Equal,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Placeholder)
                  );
    }

    #[test]
    fn equality_literals() {
        let cond1 = "foo = 42";
        let cond2 = "foo = \"hello\"";

        let res1 = condition_expr(cond1.as_bytes());
        assert_eq!(res1.unwrap().1,
                   flat_condition_tree(Operator::Equal,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Literal(String::from("42"))
                                      )
                   );

        let res2 = condition_expr(cond2.as_bytes());
        assert_eq!(res2.unwrap().1,
                   flat_condition_tree(Operator::Equal,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Literal(String::from("hello"))
                                      )
                   );
    }

    #[test]
    fn inequality_literals() {
        let cond1 = "foo >= 42";
        let cond2 = "foo <= 5";

        let res1 = condition_expr(cond1.as_bytes());
        assert_eq!(res1.unwrap().1,
                   flat_condition_tree(Operator::GreaterOrEqual,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Literal(String::from("42"))
                                      )
                   );

        let res2 = condition_expr(cond2.as_bytes());
        assert_eq!(res2.unwrap().1,
                   flat_condition_tree(Operator::LessOrEqual,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Literal(String::from("5"))
                                      )
                   );
    }
}
<commit_msg>Fix several (!) bugs in previous commit<commit_after>use nom::{alphanumeric, digit, multispace};
use std::collections::{HashSet, VecDeque};
use std::str;

use column::Column;
use common::{binary_comparison_operator, binary_logical_operator, column_identifier,
             unary_negation_operator, Operator};

#[derive(Clone, Debug, PartialEq)]
pub enum ConditionBase {
    Field(Column),
    Literal(String),
    Placeholder,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ConditionTree {
    pub operator: Operator,
    pub left: Option<Box<ConditionExpression>>,
    pub right: Option<Box<ConditionExpression>>,
}

impl<'a> ConditionTree {
    fn contained_columns(&'a self) -> HashSet<&'a Column> {
        let mut s = HashSet::new();
        let mut q = VecDeque::<&'a ConditionTree>::new();
        q.push_back(self);
        while let Some(ref ct) = q.pop_front() {
            match **ct.left.as_ref().unwrap() {
                ConditionExpression::Base(ConditionBase::Field(ref c)) => {
                    s.insert(c);
                }
                ConditionExpression::LogicalOp(ref ct) |
                ConditionExpression::ComparisonOp(ref ct) => q.push_back(ct),
                _ => (),
            }
            match **ct.right.as_ref().unwrap() {
                ConditionExpression::Base(ConditionBase::Field(ref c)) => {
                    s.insert(c);
                }
                ConditionExpression::LogicalOp(ref ct) |
                ConditionExpression::ComparisonOp(ref ct) => q.push_back(ct),
                _ => (),
            }
        }
        s
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ConditionExpression {
    ComparisonOp(ConditionTree),
    LogicalOp(ConditionTree),
    Base(ConditionBase),
}

fn fold_cond_exprs(initial: ConditionExpression,
                   remainder: Vec<(Operator, ConditionExpression)>)
                   -> ConditionExpression {
    remainder.into_iter().fold(initial, |acc, pair| {
        let (oper, expr) = pair;
        match oper {
            Operator::Equal | Operator::Less | Operator::Greater | Operator::LessOrEqual |
            Operator::Like | Operator::GreaterOrEqual | Operator::NotEqual => {
                ConditionExpression::ComparisonOp(ConditionTree {
                    operator: oper.clone(),
                    left: Some(Box::new(acc)),
                    right: Some(Box::new(expr)),
                })
            }
            Operator::And | Operator::Or => {
                ConditionExpression::LogicalOp(ConditionTree {
                    operator: oper.clone(),
                    left: Some(Box::new(acc)),
                    right: Some(Box::new(expr)),
                })
            }
            o => {
                println!("unsupported op {:?}", o);
                unimplemented!()
            }
        }
    })
}

/// Parse a conditional expression into a condition tree structure
named!(pub condition_expr<&[u8], ConditionExpression>,
    chain!(
        neg_op: opt!(unary_negation_operator) ~
        initial: boolean_primary ~
        remainder: many0!(
            complete!(
                chain!(
                    log_op: delimited!(opt!(multispace),
                                       binary_logical_operator,
                                       opt!(multispace)) ~
                    right_expr: condition_expr,
                    || {
                        (log_op, right_expr)
                    }
                )
            )
        ),
        || {
            if let Some(Operator::Not) = neg_op {
                ConditionExpression::LogicalOp(
                    ConditionTree {
                        operator: Operator::Not,
                        left: Some(Box::new(fold_cond_exprs(initial, remainder))),
                        right: None,
                    }
                )
            } else {
                fold_cond_exprs(initial, remainder)
            }
        }
    )
);

named!(boolean_primary<&[u8], ConditionExpression>,
    chain!(
        initial: predicate ~
        remainder:
        many0!(
            complete!(
                chain!(
                    op: delimited!(opt!(multispace),
                                   binary_comparison_operator,
                                   opt!(multispace)) ~
                    right_expr: boolean_primary,
                    || {
                        (op, right_expr)
                    }
                )
            )
        ),
        || { fold_cond_exprs(initial, remainder) }
    )
);

named!(predicate<&[u8], ConditionExpression>,
    alt_complete!(
            chain!(
                delimited!(opt!(multispace), tag!("?"), opt!(multispace)),
                || {
                    ConditionExpression::Base(
                        ConditionBase::Placeholder
                    )
                }
            )
        |   chain!(
                field: delimited!(opt!(multispace), digit, opt!(multispace)),
                || {
                    ConditionExpression::Base(
                        ConditionBase::Literal(String::from(str::from_utf8(field).unwrap()))
                    )
                }
            )
        |   chain!(
                field: delimited!(opt!(multispace),
                                  alt_complete!(
                                        delimited!(tag!("\""), alphanumeric, tag!("\""))
                                      | delimited!(tag!("'"), alphanumeric, tag!("'"))
                                  ),
                                  opt!(multispace)),
                || {
                    ConditionExpression::Base(
                        ConditionBase::Literal(String::from(str::from_utf8(field).unwrap()))
                    )
                }
            )
        |   chain!(
                field: delimited!(opt!(multispace), column_identifier, opt!(multispace)),
                || {
                    ConditionExpression::Base(
                        ConditionBase::Field(field)
                    )
                }
            )
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use common::Operator;

    fn flat_condition_tree(op: Operator,
                           l: ConditionBase,
                           r: ConditionBase)
                           -> ConditionExpression {
        ConditionExpression::ComparisonOp(ConditionTree {
            operator: op,
            left: Some(Box::new(ConditionExpression::Base(l))),
            right: Some(Box::new(ConditionExpression::Base(r))),
        })
    }

    #[test]
    fn ct_contained_columns() {
        use std::collections::HashSet;

        let cond = "a.foo = ? and b.bar = 42";

        let res = condition_expr(cond.as_bytes());
        let c1 = Column::from("a.foo");
        let c2 = Column::from("b.bar");
        let mut expected_cols = HashSet::new();
        expected_cols.insert(&c1);
        expected_cols.insert(&c2);
        match res.unwrap().1 {
            ConditionExpression::LogicalOp(ct) => {
                assert_eq!(ct.contained_columns(), expected_cols);
            }
            _ => panic!(),
        }
    }

    #[test]
    fn equality_placeholder() {
        let cond = "foo = ?";

        let res = condition_expr(cond.as_bytes());
        assert_eq!(res.unwrap().1,
                   flat_condition_tree(Operator::Equal,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Placeholder)
                  );
    }

    #[test]
    fn equality_literals() {
        let cond1 = "foo = 42";
        let cond2 = "foo = \"hello\"";

        let res1 = condition_expr(cond1.as_bytes());
        assert_eq!(res1.unwrap().1,
                   flat_condition_tree(Operator::Equal,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Literal(String::from("42"))
                                      )
                   );

        let res2 = condition_expr(cond2.as_bytes());
        assert_eq!(res2.unwrap().1,
                   flat_condition_tree(Operator::Equal,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Literal(String::from("hello"))
                                      )
                   );
    }

    #[test]
    fn inequality_literals() {
        let cond1 = "foo >= 42";
        let cond2 = "foo <= 5";

        let res1 = condition_expr(cond1.as_bytes());
        assert_eq!(res1.unwrap().1,
                   flat_condition_tree(Operator::GreaterOrEqual,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Literal(String::from("42"))
                                      )
                   );

        let res2 = condition_expr(cond2.as_bytes());
        assert_eq!(res2.unwrap().1,
                   flat_condition_tree(Operator::LessOrEqual,
                                       ConditionBase::Field(Column::from("foo")),
                                       ConditionBase::Literal(String::from("5"))
                                      )
                   );
    }
}
<|endoftext|>


<commit_before>
import str::sbuf;
import vec::vbuf;

native "cdecl" mod libc = "" {
    fn open(sbuf s, int flags, uint mode) -> int = "_open";
    fn read(int fd, vbuf buf, uint count) -> int = "_read";
    fn write(int fd, vbuf buf, uint count) -> int = "_write";
    fn close(int fd) -> int = "_close";
    type FILE;
    fn fopen(sbuf path, sbuf mode) -> FILE;
    fn _fdopen(int fd, sbuf mode) -> FILE;
    fn fclose(FILE f);
    fn fgetc(FILE f) -> int;
    fn ungetc(int c, FILE f);
    fn feof(FILE f) -> int;
    fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fseek(FILE f, int offset, int whence) -> int;
    fn ftell(FILE f) -> int;
    fn _pipe(*mutable int fds, uint size, int mode) -> int;
}

native "cdecl" mod libc_ivec = "" {
    fn read(int fd, *u8 buf, uint count) -> int;
    fn write(int fd, *u8 buf, uint count) -> int;
    fn fread(*u8 buf, uint size, uint n, libc::FILE f) -> uint;
    fn fwrite(*u8 buf, uint size, uint n, libc::FILE f) -> uint;
}

mod libc_constants {
    fn O_RDONLY() -> int { ret 0; }
    fn O_WRONLY() -> int { ret 1; }
    fn O_RDWR() -> int { ret 2; }
    fn O_APPEND() -> int { ret 0x0008; }
    fn O_CREAT() -> int { ret 0x0100; }
    fn O_EXCL() -> int { ret 0x0400; }
    fn O_TRUNC() -> int { ret 0x0200; }
    fn O_TEXT() -> int { ret 0x4000; }
    fn O_BINARY() -> int { ret 0x8000; }
    fn S_IRUSR() -> uint {
        ret 256u; // really _S_IREAD  in win32

    }
    fn S_IWUSR() -> uint {
        ret 128u; // really _S_IWRITE in win32

    }
}

native "x86stdcall" mod kernel32 {
    fn GetEnvironmentVariableA(sbuf n, sbuf v, uint nsize) -> uint;
    fn SetEnvironmentVariableA(sbuf n, sbuf v) -> int;
}

fn exec_suffix() -> str { ret ".exe"; }

fn target_os() -> str { ret "win32"; }

fn dylib_filename(str base) -> str { ret base + ".dll"; }

fn pipe() -> rec(int in, int out) {
    auto fds = rec(mutable int=0, mutable out=0);
    assert (os::libc::_pipe(ptr::addr_of(fds.in), 1024u,
                            libc_constants::O_BINARY()) == 0);
    ret rec(in=fds.in, out=fds.out);
}

fn fd_FILE(int fd) -> libc::FILE { ret libc::_fdopen(fd, str::buf("r")); }

native "rust" mod rustrt {
    fn rust_process_wait(int handle) -> int;
    fn rust_getcwd() -> str;
}

fn waitpid(int pid) -> int { ret rustrt::rust_process_wait(pid); }

fn getcwd() -> str { ret rustrt::rust_getcwd(); }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Fix win tinderbox breaking typo<commit_after>
import str::sbuf;
import vec::vbuf;

native "cdecl" mod libc = "" {
    fn open(sbuf s, int flags, uint mode) -> int = "_open";
    fn read(int fd, vbuf buf, uint count) -> int = "_read";
    fn write(int fd, vbuf buf, uint count) -> int = "_write";
    fn close(int fd) -> int = "_close";
    type FILE;
    fn fopen(sbuf path, sbuf mode) -> FILE;
    fn _fdopen(int fd, sbuf mode) -> FILE;
    fn fclose(FILE f);
    fn fgetc(FILE f) -> int;
    fn ungetc(int c, FILE f);
    fn feof(FILE f) -> int;
    fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fseek(FILE f, int offset, int whence) -> int;
    fn ftell(FILE f) -> int;
    fn _pipe(*mutable int fds, uint size, int mode) -> int;
}

native "cdecl" mod libc_ivec = "" {
    fn read(int fd, *u8 buf, uint count) -> int;
    fn write(int fd, *u8 buf, uint count) -> int;
    fn fread(*u8 buf, uint size, uint n, libc::FILE f) -> uint;
    fn fwrite(*u8 buf, uint size, uint n, libc::FILE f) -> uint;
}

mod libc_constants {
    fn O_RDONLY() -> int { ret 0; }
    fn O_WRONLY() -> int { ret 1; }
    fn O_RDWR() -> int { ret 2; }
    fn O_APPEND() -> int { ret 0x0008; }
    fn O_CREAT() -> int { ret 0x0100; }
    fn O_EXCL() -> int { ret 0x0400; }
    fn O_TRUNC() -> int { ret 0x0200; }
    fn O_TEXT() -> int { ret 0x4000; }
    fn O_BINARY() -> int { ret 0x8000; }
    fn S_IRUSR() -> uint {
        ret 256u; // really _S_IREAD  in win32

    }
    fn S_IWUSR() -> uint {
        ret 128u; // really _S_IWRITE in win32

    }
}

native "x86stdcall" mod kernel32 {
    fn GetEnvironmentVariableA(sbuf n, sbuf v, uint nsize) -> uint;
    fn SetEnvironmentVariableA(sbuf n, sbuf v) -> int;
}

fn exec_suffix() -> str { ret ".exe"; }

fn target_os() -> str { ret "win32"; }

fn dylib_filename(str base) -> str { ret base + ".dll"; }

fn pipe() -> rec(int in, int out) {
    auto fds = rec(mutable in=0, mutable out=0);
    assert (os::libc::_pipe(ptr::addr_of(fds.in), 1024u,
                            libc_constants::O_BINARY()) == 0);
    ret rec(in=fds.in, out=fds.out);
}

fn fd_FILE(int fd) -> libc::FILE { ret libc::_fdopen(fd, str::buf("r")); }

native "rust" mod rustrt {
    fn rust_process_wait(int handle) -> int;
    fn rust_getcwd() -> str;
}

fn waitpid(int pid) -> int { ret rustrt::rust_process_wait(pid); }

fn getcwd() -> str { ret rustrt::rust_getcwd(); }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use bindings::*;
use compile::Compile;
use function::ABI;
use libc::c_uint;
use std::kinds::marker::{
    ContravariantLifetime,
    Managed
};
use std::mem::transmute;
use std::str::raw::from_c_str;
use std::c_str::ToCStr;
use util::NativeRef;
#[repr(i32)]
#[deriving(Eq, PartialEq, Show)]
pub enum TypeKind {
    Void         = 0,
    SByte        = 1,
    UByte        = 2,
    Short        = 3,
    UShort       = 4,
    Int          = 5,
    UInt         = 6,
    NInt         = 7,
    NUInt        = 8,
    Long         = 9,
    ULong        = 10,
    Float32      = 11,
    Float64      = 12,
    NFloat       = 13,
    Struct       = 14,
    Union        = 15,
    Signature    = 16,
    Pointer      = 17,
    FirstTagged  = 32,
    SysBool      = 10009,
    SysChar      = 10010
}
/// A single field of a struct
pub struct Field<'a> {
    /// The index of the field
    pub index: c_uint,
    _type: jit_type_t,
    marker: ContravariantLifetime<'a>
}
impl<'a> PartialEq for Field<'a> {
    fn eq(&self, other:&Field<'a>) -> bool {
        self.index == other.index && self._type == other._type
    }
}
impl<'a> Field<'a> {
    #[inline]
    /// Get the field's name or none if it lacks one
    pub fn get_name(&self) -> Option<String> {
        unsafe {
            let c_name = jit_type_get_name(self._type, self.index);
            if c_name.is_null() {
                None
            } else {
                Some(from_c_str(c_name))
            }
        }
    }
    #[inline(always)]
    /// Get the type of the field
    pub fn get_type(&self) -> Type {
        unsafe {
            NativeRef::from_ptr(jit_type_get_field(self._type, self.index))
        }
    }
    #[inline(always)]
    /// Get the offset of the field
    pub fn get_offset(&self) -> uint {
        unsafe {
            jit_type_get_offset(self._type, self.index) as uint
        }
    }
}
/// A type field iterator
pub struct Fields<'a> {
    _type: jit_type_t,
    index: c_uint,
    length: c_uint,
    marker: ContravariantLifetime<'a>
}
impl<'a> Fields<'a> {
    #[inline(always)]
    fn new(ty:Type) -> Fields<'a> {
        unsafe {
            Fields {
                _type: ty.as_ptr(),
                index: 0 as c_uint,
                length: jit_type_num_fields(ty.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
}
impl<'a> Iterator<Field<'a>> for Fields<'a> {
    fn next(&mut self) -> Option<Field<'a>> {
        let index = self.index;
        self.index += 1;
        if index < self.length {
            Some(Field {
                _type: self._type.clone(),
                index: index,
                marker: ContravariantLifetime::<'a>
            })
        } else {
            None
        }
    }
    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        ((self.length - self.index) as uint, None)
    }
    #[inline]
    fn count(&mut self) -> uint {
        let count = self.length - self.index;
        self.index = self.length;
        count as uint
    }
    #[inline]
    fn nth(&mut self, n:uint) -> Option<Field<'a>> {
        self.index += n as c_uint;
        self.next()
    }
}
pub struct Params<'a> {
    _type: jit_type_t,
    index: c_uint,
    length: c_uint,
    marker: ContravariantLifetime<'a>
}
impl<'a> Params<'a> {
    #[inline(always)]
    fn new(ty:Type) -> Params<'a> {
        unsafe {
            Params {
                _type: ty.as_ptr(),
                index: 0 as c_uint,
                length: jit_type_num_params(ty.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
}
impl<'a> Iterator<Type> for Params<'a> {
    fn next(&mut self) -> Option<Type> {
        let index = self.index;
        self.index += 1;
        if index < self.length {
            Some(unsafe {
                NativeRef::from_ptr(jit_type_get_param(self._type, index))
            })
        } else {
            None
        }
    }
    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        ((self.length - self.index) as uint, None)
    }
    #[inline]
    fn count(&mut self) -> uint {
        let count = self.length - self.index;
        self.index = self.length;
        count as uint
    }
    #[inline]
    fn nth(&mut self, n:uint) -> Option<Type> {
        self.index += n as c_uint;
        self.next()
    }
}
/// An object that represents a native system type.
/// Each `Type` represents a basic system type, be it a primitive, a struct, a
/// union, a pointer, or a function signature. The library uses this information
/// to lay out values in memory.
#[deriving(PartialEq)]
pub struct Type {
    _type: jit_type_t,
    marker: Managed
}
impl NativeRef for Type {
    #[inline(always)]
    unsafe fn as_ptr(&self) -> jit_type_t {
        self._type
    }
    #[inline(always)]
    unsafe fn from_ptr(ptr:jit_type_t) -> Type {
        Type {
            _type: ptr,
            marker: Managed
        }
    }
}
impl Clone for Type {
    #[inline]
    /// Make a copy of the type descriptor by increasing its reference count.
    fn clone(&self) -> Type {
        unsafe {
            NativeRef::from_ptr(jit_type_copy(self.as_ptr()))
        }
    }
}
#[unsafe_destructor]
impl Drop for Type {
    #[inline(always)]
    /// Free a type descriptor by decreasing its reference count.
    /// This function is safe to use on pre-defined types, which are never
    /// actually freed.
    fn drop(&mut self) {
        unsafe {
            jit_type_free(self.as_ptr());
        }
    }
}
impl Type {
    /// Create a type descriptor for a function signature.
    pub fn create_signature(abi: ABI, return_type: Type, params: &mut [Type]) -> Type {
        unsafe {
            let mut native_params:Vec<jit_type_t> = params.iter().map(|param| param.as_ptr()).collect();
            let signature = jit_type_create_signature(abi as jit_abi_t, return_type.as_ptr(), native_params.as_mut_ptr(), params.len() as c_uint, 1);
            NativeRef::from_ptr(signature)
        }
    }
    #[inline(always)]
    /// Create a type descriptor for a structure.
    pub fn create_struct(fields: &mut [Type]) -> Type {
        unsafe {
            let mut native_fields:Vec<_> = fields.iter().map(|field| field.as_ptr()).collect();
            NativeRef::from_ptr(jit_type_create_struct(native_fields.as_mut_ptr(), fields.len() as c_uint, 1))
        }
    }
    #[inline(always)]
    /// Create a type descriptor for a union.
    pub fn create_union(fields: &mut [Type]) -> Type {
        unsafe {
            let mut native_fields:Vec<_> = fields.iter().map(|field| field.as_ptr()).collect();
            NativeRef::from_ptr(jit_type_create_union(native_fields.as_mut_ptr(), fields.len() as c_uint, 1))
        }
    }
    #[inline(always)]
    /// Create a type descriptor for a pointer to another type.
    pub fn create_pointer(pointee: Type) -> Type {
        unsafe {
            let ptr = jit_type_create_pointer(pointee.as_ptr(), 1);
            NativeRef::from_ptr(ptr)
        }
    }
    #[inline(always)]
    /// Get the size of this type in bytes.
    pub fn get_size(&self) -> uint {
        unsafe {
            jit_type_get_size(self.as_ptr()) as uint
        }
    }
    #[inline]
    /// Get a value that indicates the kind of this type. This allows
    /// callers to quickly classify a type to determine how it should
    /// be handled further.
    pub fn get_kind(&self) -> TypeKind {
        unsafe {
            transmute(jit_type_get_kind(self.as_ptr()))
        }
    }
    #[inline(always)]
    /// Get the type that is referred to by this pointer type.
    pub fn get_ref(&self) -> Type {
        unsafe {
            NativeRef::from_ptr(jit_type_get_ref(self.as_ptr()))
        }
    }
    /// Set the field or parameter names of this type.
    pub fn set_names<T:ToCStr>(&self, names:&[T]) -> bool {
        unsafe {
            let native_names : Vec<*const i8> = names.iter().map(|name| name.to_c_str().unwrap()).collect();
            jit_type_set_names(self.as_ptr(), native_names.as_ptr() as *mut *mut i8, names.len() as u32) != 0
        }
    }
    #[inline(always)]
    /// Iterator over the type's fields
    pub fn fields<'a>(&'a self) -> Fields<'a> {
        Fields::new(self.clone())
    }
    #[inline(always)]
    /// Iterator over the function signature's parameters
    pub fn params<'a>(&'a self) -> Params<'a> {
        Params::new(self.clone())
    }
    #[inline]
    /// Find the field/parameter index for a particular name.
    pub fn find_name<'b, T:ToCStr>(&'b self, name:T) -> Field<'b> {
        name.with_c_str(|c_name| unsafe {
            Field {
                index: jit_type_find_name(self.as_ptr(), c_name),
                _type: self.as_ptr(),
                marker: ContravariantLifetime::<'b>
            }
        })
    }
    #[inline(always)]
    /// Check if this is a pointer
    pub fn is_pointer(&self) -> bool {
        unsafe {
            jit_type_is_pointer(self.as_ptr()) != 0
        }
    }
}
#[inline(always)]
/// Get the Rust type given as a type descriptor
pub fn get<T:Compile>() -> Type {
    Compile::jit_type(None::<T>)
}<commit_msg>Be more explicit about `Type`'s markers<commit_after>use bindings::*;
use compile::Compile;
use function::ABI;
use libc::c_uint;
use std::kinds::marker::{ContravariantLifetime, NoCopy};
use std::mem::transmute;
use std::str::raw::from_c_str;
use std::c_str::ToCStr;
use util::NativeRef;
#[repr(i32)]
#[deriving(Eq, PartialEq, Show)]
pub enum TypeKind {
    Void         = 0,
    SByte        = 1,
    UByte        = 2,
    Short        = 3,
    UShort       = 4,
    Int          = 5,
    UInt         = 6,
    NInt         = 7,
    NUInt        = 8,
    Long         = 9,
    ULong        = 10,
    Float32      = 11,
    Float64      = 12,
    NFloat       = 13,
    Struct       = 14,
    Union        = 15,
    Signature    = 16,
    Pointer      = 17,
    FirstTagged  = 32,
    SysBool      = 10009,
    SysChar      = 10010
}
/// A single field of a struct
pub struct Field<'a> {
    /// The index of the field
    pub index: c_uint,
    _type: jit_type_t,
    marker: ContravariantLifetime<'a>
}
impl<'a> PartialEq for Field<'a> {
    fn eq(&self, other:&Field<'a>) -> bool {
        self.index == other.index && self._type == other._type
    }
}
impl<'a> Field<'a> {
    #[inline]
    /// Get the field's name or none if it lacks one
    pub fn get_name(&self) -> Option<String> {
        unsafe {
            let c_name = jit_type_get_name(self._type, self.index);
            if c_name.is_null() {
                None
            } else {
                Some(from_c_str(c_name))
            }
        }
    }
    #[inline(always)]
    /// Get the type of the field
    pub fn get_type(&self) -> Type {
        unsafe {
            NativeRef::from_ptr(jit_type_get_field(self._type, self.index))
        }
    }
    #[inline(always)]
    /// Get the offset of the field
    pub fn get_offset(&self) -> uint {
        unsafe {
            jit_type_get_offset(self._type, self.index) as uint
        }
    }
}
/// A type field iterator
pub struct Fields<'a> {
    _type: jit_type_t,
    index: c_uint,
    length: c_uint,
    marker: ContravariantLifetime<'a>
}
impl<'a> Fields<'a> {
    #[inline(always)]
    fn new(ty:Type) -> Fields<'a> {
        unsafe {
            Fields {
                _type: ty.as_ptr(),
                index: 0 as c_uint,
                length: jit_type_num_fields(ty.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
}
impl<'a> Iterator<Field<'a>> for Fields<'a> {
    fn next(&mut self) -> Option<Field<'a>> {
        let index = self.index;
        self.index += 1;
        if index < self.length {
            Some(Field {
                _type: self._type.clone(),
                index: index,
                marker: ContravariantLifetime::<'a>
            })
        } else {
            None
        }
    }
    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        ((self.length - self.index) as uint, None)
    }
    #[inline]
    fn count(&mut self) -> uint {
        let count = self.length - self.index;
        self.index = self.length;
        count as uint
    }
    #[inline]
    fn nth(&mut self, n:uint) -> Option<Field<'a>> {
        self.index += n as c_uint;
        self.next()
    }
}
pub struct Params<'a> {
    _type: jit_type_t,
    index: c_uint,
    length: c_uint,
    marker: ContravariantLifetime<'a>
}
impl<'a> Params<'a> {
    #[inline(always)]
    fn new(ty:Type) -> Params<'a> {
        unsafe {
            Params {
                _type: ty.as_ptr(),
                index: 0 as c_uint,
                length: jit_type_num_params(ty.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
}
impl<'a> Iterator<Type> for Params<'a> {
    fn next(&mut self) -> Option<Type> {
        let index = self.index;
        self.index += 1;
        if index < self.length {
            Some(unsafe {
                NativeRef::from_ptr(jit_type_get_param(self._type, index))
            })
        } else {
            None
        }
    }
    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        ((self.length - self.index) as uint, None)
    }
    #[inline]
    fn count(&mut self) -> uint {
        let count = self.length - self.index;
        self.index = self.length;
        count as uint
    }
    #[inline]
    fn nth(&mut self, n:uint) -> Option<Type> {
        self.index += n as c_uint;
        self.next()
    }
}
/// An object that represents a native system type.
/// Each `Type` represents a basic system type, be it a primitive, a struct, a
/// union, a pointer, or a function signature. The library uses this information
/// to lay out values in memory.
/// Types are not attached to a context so they are reference-counted by LibJIT,
/// so internally they are represented as `Rc<TypeData>`.
#[deriving(PartialEq)]
pub struct Type {
    _type: jit_type_t,
    no_copy: NoCopy
}
impl NativeRef for Type {
    #[inline(always)]
    unsafe fn as_ptr(&self) -> jit_type_t {
        self._type
    }
    #[inline(always)]
    unsafe fn from_ptr(ptr:jit_type_t) -> Type {
        Type {
            _type: ptr,
            no_copy: NoCopy
        }
    }
}
impl Clone for Type {
    #[inline]
    /// Make a copy of the type descriptor by increasing its reference count.
    fn clone(&self) -> Type {
        unsafe {
            NativeRef::from_ptr(jit_type_copy(self.as_ptr()))
        }
    }
}
#[unsafe_destructor]
impl Drop for Type {
    #[inline(always)]
    /// Free a type descriptor by decreasing its reference count.
    /// This function is safe to use on pre-defined types, which are never
    /// actually freed.
    fn drop(&mut self) {
        unsafe {
            jit_type_free(self.as_ptr());
        }
    }
}
impl Type {
    /// Create a type descriptor for a function signature.
    pub fn create_signature(abi: ABI, return_type: Type, params: &mut [Type]) -> Type {
        unsafe {
            let mut native_params:Vec<jit_type_t> = params.iter().map(|param| param.as_ptr()).collect();
            let signature = jit_type_create_signature(abi as jit_abi_t, return_type.as_ptr(), native_params.as_mut_ptr(), params.len() as c_uint, 1);
            NativeRef::from_ptr(signature)
        }
    }
    #[inline(always)]
    /// Create a type descriptor for a structure.
    pub fn create_struct(fields: &mut [Type]) -> Type {
        unsafe {
            let mut native_fields:Vec<_> = fields.iter().map(|field| field.as_ptr()).collect();
            NativeRef::from_ptr(jit_type_create_struct(native_fields.as_mut_ptr(), fields.len() as c_uint, 1))
        }
    }
    #[inline(always)]
    /// Create a type descriptor for a union.
    pub fn create_union(fields: &mut [Type]) -> Type {
        unsafe {
            let mut native_fields:Vec<_> = fields.iter().map(|field| field.as_ptr()).collect();
            NativeRef::from_ptr(jit_type_create_union(native_fields.as_mut_ptr(), fields.len() as c_uint, 1))
        }
    }
    #[inline(always)]
    /// Create a type descriptor for a pointer to another type.
    pub fn create_pointer(pointee: Type) -> Type {
        unsafe {
            let ptr = jit_type_create_pointer(pointee.as_ptr(), 1);
            NativeRef::from_ptr(ptr)
        }
    }
    #[inline(always)]
    /// Get the size of this type in bytes.
    pub fn get_size(&self) -> uint {
        unsafe {
            jit_type_get_size(self.as_ptr()) as uint
        }
    }
    #[inline]
    /// Get a value that indicates the kind of this type. This allows callers to
    /// quickly classify a type to determine how it should be handled further.
    pub fn get_kind(&self) -> TypeKind {
        unsafe {
            transmute(jit_type_get_kind(self.as_ptr()))
        }
    }
    #[inline(always)]
    /// Get the type that is referred to by this pointer type.
    pub fn get_ref(&self) -> Type {
        unsafe {
            NativeRef::from_ptr(jit_type_get_ref(self.as_ptr()))
        }
    }
    /// Set the field or parameter names of this type.
    pub fn set_names<T:ToCStr>(&self, names:&[T]) -> bool {
        unsafe {
            let native_names : Vec<*const i8> = names.iter().map(|name| name.to_c_str().unwrap()).collect();
            jit_type_set_names(self.as_ptr(), native_names.as_ptr() as *mut *mut i8, names.len() as u32) != 0
        }
    }
    #[inline(always)]
    /// Iterator over the type's fields
    pub fn fields<'a>(&'a self) -> Fields<'a> {
        Fields::new(self.clone())
    }
    #[inline(always)]
    /// Iterator over the function signature's parameters
    pub fn params<'a>(&'a self) -> Params<'a> {
        Params::new(self.clone())
    }
    #[inline]
    /// Find the field/parameter index for a particular name.
    pub fn find_name<'b, T:ToCStr>(&'b self, name:T) -> Field<'b> {
        name.with_c_str(|c_name| unsafe {
            Field {
                index: jit_type_find_name(self.as_ptr(), c_name),
                _type: self.as_ptr(),
                marker: ContravariantLifetime::<'b>
            }
        })
    }
    #[inline(always)]
    /// Check if this is a pointer
    pub fn is_pointer(&self) -> bool {
        unsafe {
            jit_type_is_pointer(self.as_ptr()) != 0
        }
    }
}
#[inline(always)]
/// Get the Rust type given as a type descriptor
pub fn get<T:Compile>() -> Type {
    Compile::jit_type(None::<T>)
}<|endoftext|>