<commit_before>use std;
use sdl2;
use cgmath::*;
use std::rc::Rc;
use std::path::Path;
use sdl2_image::LoadSurface;

pub struct Surface {
    pub size_x: usize,
    pub size_y: usize,
    pub data: Vec<Vector3<f32>>,
}

pub struct Texture {
    levels: Vec<Rc<Surface>>,
    pub size: Vector2<f32>,
}

impl Surface {
    fn new(size_x: usize, size_y: usize) -> Surface {
        Surface {
            size_x: size_x,
            size_y: size_y,
            data: Vec::<Vector3<f32>>::with_capacity(size_x * size_y),
        }
    }

    #[allow(dead_code)]
    pub fn tex_2d(&self, tex: Vector2<f32>) -> Vector3<f32>
    {
        let x = (tex.x * (self.size_x as f32)) as usize % self.size_x;
        let y = (tex.y * (self.size_y as f32)) as usize % self.size_y;
        self.data[y * self.size_x + x]
    }

    #[allow(dead_code)]
    pub fn tex_2d_bilinear(&self, tex: Vector2<f32>) -> Vector3<f32>
    {
        let x = tex.x * (self.size_x as f32);
        let y = tex.y * (self.size_y as f32);

        let mut x_int = x as usize;
        let mut y_int = y as usize;

        let dx = x - (x_int as f32);
        let dy = y - (y_int as f32);

        x_int %= self.size_x;
        y_int %= self.size_y;

        let add_x = if x_int + 1 == self.size_x {0} else {1};
        let add_y = if y_int + 1 == self.size_y {0} else {self.size_x};

        let ind = y_int * self.size_x + x_int;

        self.data[ind].mul_s(1.0_f32 - dx).
            add_v(&self.data[ind + add_x].mul_s(dx)).
            mul_s(1.0_f32 - dy).
            add_v(&self.data[ind + add_y].mul_s(1.0_f32 - dx).
                  add_v(&self.data[ind + add_x + add_y].mul_s(dx)).
                  mul_s(dy))
    }
}

impl Texture {
    pub fn new(path: &Path) -> Result<Texture, String> {
        let surface = try!(Texture::load_surface(path));

        let size_x = surface.as_ref().width() as usize;
        let size_y = surface.as_ref().height() as usize;
        let data_u8: &[u8] = match surface.as_ref().without_lock() {
            Some(v) => v,
            None => return Err(format!("can't lock surface for texture {}", path.display()))
        };

        let mut lvl0 = Surface::new(size_x, size_y);
        for y in 0..size_y {
            for x in 0..size_x {
                let ind = ((size_y - y - 1) * size_x + x) * 4;
                lvl0.data.push(Vector3::new(
                    data_u8[ind + 2] as f32,
                    data_u8[ind + 1] as f32,
                    data_u8[ind + 0] as f32));
            }}

        let mut this = Texture {
            levels: vec![Rc::new(lvl0)],
            size: Vector2::new(size_x as f32, size_y as f32),
        };
        this.gen_mipmap();

        Ok(this)
    }

    pub fn get_surface(&self, mip_lvl: usize) -> Rc<Surface> {
        self.levels[std::cmp::min(mip_lvl, self.levels.len() - 1)].clone()
    }

    fn load_surface<'a>(path: &Path) -> Result<sdl2::surface::Surface<'a>, String> {
        println!("load texture: \"{}\"", path.display());

        let standart =
            match sdl2::surface::Surface::new(1, 1, sdl2::pixels::PixelFormatEnum::ARGB8888) {
                Ok(v) => v,
                Err(e) => return Err(format!("can't create standart surface for texture \"{}\", error = \"{}\"",
                                             path.display(), e))
            };

        let surface_load = match sdl2::surface::Surface::from_file(path) {
            Ok(v) => v,
            Err(e) => return Err(format!("can't load texture \"{}\", error = \"{}\"",
                                         path.display(), e))
        };

        match surface_load.as_ref().convert(&standart.as_ref().pixel_format()) {
            Ok(v) => Ok(v),
            Err(e) => return Err(format!("can't convert surface for texture \"{}\", error = \"{}\"",
                                         path.display(), e))
        }
    }

    #[inline]
    fn add_color(clr: &mut Vector3<f32>, src: &Surface, x: i32, y: i32, k: u32) -> u32 {
        if x >= 0 && y >= 0 && x < (src.size_x as i32) && y < (src.size_y as i32) {
            let ind = (y as usize) * src.size_x + x as usize;
            clr.add_self_v(&src.data[ind].mul_s(k as f32));
            k
        } else {
            0
        }
    }

    fn gen_mipmap(&mut self) {
        let mut surface_ind = 0;
        let mut size_x = self.levels[surface_ind].size_x as i32;
        let mut size_y = self.levels[surface_ind].size_y as i32;

        while std::cmp::min(size_x, size_y) != 1 {
            let next_size_x = size_x >> 1;
    let next_size_y = size_y >> 1;
            let mut s = Surface::new(next_size_x as usize, next_size_y as usize);
            {
                let src = &(self.levels[surface_ind]);
                let mut dst = &mut s.data;

                // koeff table
                // 1 2 1
                // 2 4 2
                // 1 2 1
                for y in 0..next_size_y {
                    for x in 0..next_size_x {
                        let mut clr = Vector3::zero();
                        let mut cnt: u32 = 0;
                        {
                            let mut f = |add_x: i32, add_y: i32, k: u32| {
                                Texture::add_color(&mut clr, src, x * 2 + add_x, y * 2 + add_y, k)
                            };

                            cnt += f(-1, -1, 1);
                            cnt += f( 0, -1, 2);
                            cnt += f( 1, -1, 1);
                            cnt += f(-1,  0, 2);
                            cnt += f( 0,  0, 4);
                            cnt += f( 1,  0, 2);
                            cnt += f(-1,  1, 1);
                            cnt += f( 0,  1, 2);
                            cnt += f( 1,  1, 1);
                        }
                        dst.push(clr.div_s(cnt as f32));
                    }
                }
            }

            self.levels.push(Rc::new(s));
            size_x = next_size_x;
            size_y = next_size_y;
            surface_ind += 1;
        }
    }
}
<commit_msg>форматирование<commit_after>use std;
use sdl2;
use cgmath::*;
use std::rc::Rc;
use std::path::Path;
use sdl2_image::LoadSurface;

pub struct Surface {
    pub size_x: usize,
    pub size_y: usize,
    pub data: Vec<Vector3<f32>>,
}

pub struct Texture {
    levels: Vec<Rc<Surface>>,
    pub size: Vector2<f32>,
}

impl Surface {
    fn new(size_x: usize, size_y: usize) -> Surface {
        Surface {
            size_x: size_x,
            size_y: size_y,
            data: Vec::<Vector3<f32>>::with_capacity(size_x * size_y),
        }
    }

    #[allow(dead_code)]
    pub fn tex_2d(&self, tex: Vector2<f32>) -> Vector3<f32>
    {
        let x = (tex.x * (self.size_x as f32)) as usize % self.size_x;
        let y = (tex.y * (self.size_y as f32)) as usize % self.size_y;
        self.data[y * self.size_x + x]
    }

    #[allow(dead_code)]
    pub fn tex_2d_bilinear(&self, tex: Vector2<f32>) -> Vector3<f32>
    {
        let x = tex.x * (self.size_x as f32);
        let y = tex.y * (self.size_y as f32);

        let mut x_int = x as usize;
        let mut y_int = y as usize;

        let dx = x - (x_int as f32);
        let dy = y - (y_int as f32);

        x_int %= self.size_x;
        y_int %= self.size_y;

        let add_x = if x_int + 1 == self.size_x {0} else {1};
        let add_y = if y_int + 1 == self.size_y {0} else {self.size_x};

        let ind = y_int * self.size_x + x_int;

        self.data[ind].mul_s(1.0_f32 - dx).
            add_v(&self.data[ind + add_x].mul_s(dx)).
            mul_s(1.0_f32 - dy).
            add_v(&self.data[ind + add_y].mul_s(1.0_f32 - dx).
                  add_v(&self.data[ind + add_x + add_y].mul_s(dx)).
                  mul_s(dy))
    }
}

impl Texture {
    pub fn new(path: &Path) -> Result<Texture, String> {
        let surface = try!(Texture::load_surface(path));

        let size_x = surface.as_ref().width() as usize;
        let size_y = surface.as_ref().height() as usize;
        let data_u8: &[u8] = match surface.as_ref().without_lock() {
            Some(v) => v,
            None => return Err(format!("can't lock surface for texture {}", path.display()))
        };

        let mut lvl0 = Surface::new(size_x, size_y);
        for y in 0..size_y {
            for x in 0..size_x {
                let ind = ((size_y - y - 1) * size_x + x) * 4;
                lvl0.data.push(Vector3::new(
                    data_u8[ind + 2] as f32,
                    data_u8[ind + 1] as f32,
                    data_u8[ind + 0] as f32));
            }}

        let mut this = Texture {
            levels: vec![Rc::new(lvl0)],
            size: Vector2::new(size_x as f32, size_y as f32),
        };
        this.gen_mipmap();

        Ok(this)
    }

    pub fn get_surface(&self, mip_lvl: usize) -> Rc<Surface> {
        self.levels[std::cmp::min(mip_lvl, self.levels.len() - 1)].clone()
    }

    fn load_surface<'a>(path: &Path) -> Result<sdl2::surface::Surface<'a>, String> {
        println!("load texture: \"{}\"", path.display());

        let standart =
            match sdl2::surface::Surface::new(1, 1, sdl2::pixels::PixelFormatEnum::ARGB8888) {
                Ok(v) => v,
                Err(e) => return Err(format!("can't create standart surface for texture \"{}\", error = \"{}\"",
                                             path.display(), e))
            };

        let surface_load = match sdl2::surface::Surface::from_file(path) {
            Ok(v) => v,
            Err(e) => return Err(format!("can't load texture \"{}\", error = \"{}\"",
                                         path.display(), e))
        };

        match surface_load.as_ref().convert(&standart.as_ref().pixel_format()) {
            Ok(v) => Ok(v),
            Err(e) => return Err(format!("can't convert surface for texture \"{}\", error = \"{}\"",
                                         path.display(), e))
        }
    }

    #[inline]
    fn add_color(clr: &mut Vector3<f32>, src: &Surface, x: i32, y: i32, k: u32) -> u32 {
        if x >= 0 && y >= 0 && x < (src.size_x as i32) && y < (src.size_y as i32) {
            let ind = (y as usize) * src.size_x + x as usize;
            clr.add_self_v(&src.data[ind].mul_s(k as f32));
            k
        } else {
            0
        }
    }

    fn gen_mipmap(&mut self) {
        let mut surface_ind = 0;
        let mut size_x = self.levels[surface_ind].size_x as i32;
        let mut size_y = self.levels[surface_ind].size_y as i32;

        while std::cmp::min(size_x, size_y) != 1 {
            let next_size_x = size_x >> 1;
            let next_size_y = size_y >> 1;
            let mut s = Surface::new(next_size_x as usize, next_size_y as usize);
            {
                let src = &(self.levels[surface_ind]);
                let mut dst = &mut s.data;

                // koeff table
                // 1 2 1
                // 2 4 2
                // 1 2 1
                for y in 0..next_size_y {
                    for x in 0..next_size_x {
                        let mut clr = Vector3::zero();
                        let mut cnt: u32 = 0;
                        {
                            let mut f = |add_x: i32, add_y: i32, k: u32| {
                                Texture::add_color(&mut clr, src, x * 2 + add_x, y * 2 + add_y, k)
                            };

                            cnt += f(-1, -1, 1);
                            cnt += f( 0, -1, 2);
                            cnt += f( 1, -1, 1);
                            cnt += f(-1,  0, 2);
                            cnt += f( 0,  0, 4);
                            cnt += f( 1,  0, 2);
                            cnt += f(-1,  1, 1);
                            cnt += f( 0,  1, 2);
                            cnt += f( 1,  1, 1);
                        }
                        dst.push(clr.div_s(cnt as f32));
                    }
                }
            }

            self.levels.push(Rc::new(s));
            size_x = next_size_x;
            size_y = next_size_y;
            surface_ind += 1;
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use image_data::Image2d;
use types::GLError;

pub struct Texture<T: TextureType> {
    gl_id: GLuint,
    phantom: PhantomData<*mut T>
}
pub type Texture2d = Texture<Tx2d>;
pub type TextureCubeMap = Texture<TxCubeMap>;

impl<T: TextureType> Texture<T> {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl<T: TextureType> Drop for Texture<T> {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_texture<T: TextureType>(&self) -> Texture<T> {
        unsafe {
            let mut id : GLuint =  0;

            gl::GenTextures(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Texture {
                gl_id: id,
                phantom: PhantomData
            }
        }
    }
}

pub trait ImageTargetType {
    fn gl_enum(&self) -> GLenum;
}

pub trait TextureType {
    type ImageTargetType: ImageTargetType;

    fn target() -> TextureBindingTarget;
}

pub struct Tx2d;

gl_enum! {
    pub gl_enum Tx2dImageTarget {
        Texture2d as TEXTURE_2D_TARGET = gl::TEXTURE_2D
    }
}

impl ImageTargetType for Tx2dImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for Tx2d {
    type ImageTargetType = Tx2dImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

pub struct TxCubeMap;

gl_enum! {
    pub gl_enum TxCubeMapImageTarget {
        CubeMapPositiveX as TEXTURE_CUBE_MAP_POSITIVE_X =
            gl::TEXTURE_CUBE_MAP_POSITIVE_X,
        CubeMapNegativeX as TEXTURE_CUBE_MAP_NEGATIVE_X =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
        CubeMapPositiveY as TEXTURE_CUBE_MAP_POSITIVE_Y =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
        CubeMapNegativeY as TEXTURE_CUBE_MAP_NEGATIVE_Y =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
        CubeMapPositiveZ as TEXTURE_CUBE_MAP_POSITIVE_Z =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
        CubeMapNegativeZ as TEXTURE_CUBE_MAP_NEGATIVE_Z =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Z
    }
}

impl ImageTargetType for TxCubeMapImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for TxCubeMap {
    type ImageTargetType = TxCubeMapImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::TextureCubeMap
    }
}

gl_enum! {
    pub gl_enum TextureBindingTarget {
        Texture2d as TEXTURE_2D = gl::TEXTURE_2D,
        TextureCubeMap as TEXTURE_CUBE_MAP = gl::TEXTURE_CUBE_MAP
    }
}

// TODO: Use type refinements someday...
#[derive(Debug, Clone, Copy)]
pub enum TextureFilter {
    Nearest,
    Linear
}

#[derive(Debug, Clone, Copy)]
pub enum TextureMipmapFilter {
    Filter(TextureFilter),
    MipmapFilter { criterion: TextureFilter, mipmap: TextureFilter }
}

pub const NEAREST : TextureFilter = TextureFilter::Nearest;
pub const LINEAR : TextureFilter = TextureFilter::Linear;
pub const NEAREST_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Nearest
    };
pub const LINEAR_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Nearest
    };
pub const NEAREST_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Linear
    };
pub const LINEAR_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Linear
    };

#[allow(dead_code)]
impl TextureFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(self::NEAREST) },
            gl::LINEAR => { Ok(self::LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            self::NEAREST => gl::NEAREST,
            self::LINEAR => gl::LINEAR
        }
    }
}

#[allow(dead_code)]
impl TextureMipmapFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(TextureMipmapFilter::Filter(self::NEAREST)) },
            gl::LINEAR => { Ok(TextureMipmapFilter::Filter(self::LINEAR)) },
            gl::NEAREST_MIPMAP_NEAREST => { Ok(self::NEAREST_MIPMAP_NEAREST) },
            gl::LINEAR_MIPMAP_NEAREST => { Ok(self::LINEAR_MIPMAP_NEAREST) },
            gl::NEAREST_MIPMAP_LINEAR => { Ok(self::NEAREST_MIPMAP_LINEAR) },
            gl::LINEAR_MIPMAP_LINEAR => { Ok(self::LINEAR_MIPMAP_LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            TextureMipmapFilter::Filter(self::LINEAR) => { gl::LINEAR },
            TextureMipmapFilter::Filter(self::NEAREST) => { gl::NEAREST },
            self::NEAREST_MIPMAP_NEAREST => { gl::NEAREST_MIPMAP_NEAREST },
            self::LINEAR_MIPMAP_NEAREST => { gl::LINEAR_MIPMAP_NEAREST },
            self::NEAREST_MIPMAP_LINEAR => { gl::NEAREST_MIPMAP_LINEAR },
            self::LINEAR_MIPMAP_LINEAR => { gl::LINEAR_MIPMAP_LINEAR }
        }
    }
}

impl From<TextureFilter> for TextureMipmapFilter {
    fn from(filter: TextureFilter) -> TextureMipmapFilter {
        TextureMipmapFilter::Filter(filter)
    }
}

gl_enum! {
    pub gl_enum TextureWrapMode {
        ClampToEdge as CLAMP_TO_EDGE = gl::CLAMP_TO_EDGE,
        MirroredRepeat as MIRRORED_REPEAT = gl::MIRRORED_REPEAT,
        Repeat as REPEAT = gl::REPEAT
    }
}

pub trait TextureBinding {
    type TextureType: TextureType;

    fn target() -> TextureBindingTarget {
        Self::TextureType::target()
    }

    fn image_2d<I>(&mut self,
                   level: i32,
                   target: <Self::TextureType as TextureType>::ImageTargetType,
                   img: &I)
        where I: Image2d
    {
        unsafe {
            let ptr = mem::transmute(img.textel_bytes().as_ptr());
            gl::TexImage2D(target.gl_enum(),
                           level as GLint,
                           img.format().textel_format.gl_enum() as GLint,
                           img.width() as i32,
                           img.height() as i32,
                           0,
                           img.format().textel_format.gl_enum(),
                           img.format().textel_type.gl_enum(),
                           ptr);
            dbg_gl_error! {
                GLError::InvalidEnum => "`target`, `format`, or `type` is not an accepted value",
                GLError::InvalidValue => "`target`, `level`, `internalformat`, `width`, `height`, or `border` is an invalid value",
                GLError::InvalidOperation => "`format` conflicts with either `internalformat` or `type`",
                _ => "Unknown error"
            }
        }
    }
}

pub struct Texture2dBinding<'a> {
    phantom: PhantomData<&'a mut Texture2d>
}

impl<'a> TextureBinding for Texture2dBinding<'a> {
    type TextureType = Tx2d;
}

pub struct TextureCubeMapBinding<'a> {
    phantom: PhantomData<&'a mut TextureCubeMap>
}

impl<'a> TextureBinding for TextureCubeMapBinding<'a> {
    type TextureType = TxCubeMap;
}

unsafe fn _bind_texture<T: TextureType>(texture: &mut Texture<T>) {
    gl::BindTexture(T::target().gl_enum(), texture.gl_id());
    dbg_gl_error! {
        GLError::InvalidEnum => "`target` is not one of the allowed values",
        GLError::InvalidOperation => "`texture` was created with a target that doesn't match `target`",
        _ => "Unknown error"
    }
}

pub struct Texture2dBinder;
impl Texture2dBinder {
    pub fn bind<'a>(&'a mut self, texture: &mut Texture2d)
        -> Texture2dBinding<'a>
    {
        unsafe {
            _bind_texture(texture);
        }
        Texture2dBinding { phantom: PhantomData }
    }
}

pub struct TextureCubeMapBinder;
impl TextureCubeMapBinder {
    pub fn bind<'a>(&'a mut self, texture: &mut TextureCubeMap)
        -> TextureCubeMapBinding<'a>
    {
        unsafe {
            _bind_texture(texture);
        }
        TextureCubeMapBinding { phantom: PhantomData }
    }
}
<commit_msg>Add `TextureBinding` methods to wrap `glTexParameteriv()`<commit_after>use std::mem;
use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use image_data::Image2d;
use types::GLError;

pub struct Texture<T: TextureType> {
    gl_id: GLuint,
    phantom: PhantomData<*mut T>
}
pub type Texture2d = Texture<Tx2d>;
pub type TextureCubeMap = Texture<TxCubeMap>;

impl<T: TextureType> Texture<T> {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl<T: TextureType> Drop for Texture<T> {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_texture<T: TextureType>(&self) -> Texture<T> {
        unsafe {
            let mut id : GLuint =  0;

            gl::GenTextures(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Texture {
                gl_id: id,
                phantom: PhantomData
            }
        }
    }
}

pub trait ImageTargetType {
    fn gl_enum(&self) -> GLenum;
}

pub trait TextureType {
    type ImageTargetType: ImageTargetType;

    fn target() -> TextureBindingTarget;
}

pub struct Tx2d;

gl_enum! {
    pub gl_enum Tx2dImageTarget {
        Texture2d as TEXTURE_2D_TARGET = gl::TEXTURE_2D
    }
}

impl ImageTargetType for Tx2dImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for Tx2d {
    type ImageTargetType = Tx2dImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

pub struct TxCubeMap;

gl_enum! {
    pub gl_enum TxCubeMapImageTarget {
        CubeMapPositiveX as TEXTURE_CUBE_MAP_POSITIVE_X =
            gl::TEXTURE_CUBE_MAP_POSITIVE_X,
        CubeMapNegativeX as TEXTURE_CUBE_MAP_NEGATIVE_X =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
        CubeMapPositiveY as TEXTURE_CUBE_MAP_POSITIVE_Y =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
        CubeMapNegativeY as TEXTURE_CUBE_MAP_NEGATIVE_Y =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
        CubeMapPositiveZ as TEXTURE_CUBE_MAP_POSITIVE_Z =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
        CubeMapNegativeZ as TEXTURE_CUBE_MAP_NEGATIVE_Z =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Z
    }
}

impl ImageTargetType for TxCubeMapImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for TxCubeMap {
    type ImageTargetType = TxCubeMapImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::TextureCubeMap
    }
}

gl_enum! {
    pub gl_enum TextureBindingTarget {
        Texture2d as TEXTURE_2D = gl::TEXTURE_2D,
        TextureCubeMap as TEXTURE_CUBE_MAP = gl::TEXTURE_CUBE_MAP
    }
}

// TODO: Use type refinements someday...
#[derive(Debug, Clone, Copy)]
pub enum TextureFilter {
    Nearest,
    Linear
}

#[derive(Debug, Clone, Copy)]
pub enum TextureMipmapFilter {
    Filter(TextureFilter),
    MipmapFilter { criterion: TextureFilter, mipmap: TextureFilter }
}

pub const NEAREST : TextureFilter = TextureFilter::Nearest;
pub const LINEAR : TextureFilter = TextureFilter::Linear;
pub const NEAREST_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Nearest
    };
pub const LINEAR_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Nearest
    };
pub const NEAREST_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Linear
    };
pub const LINEAR_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Linear
    };

#[allow(dead_code)]
impl TextureFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(self::NEAREST) },
            gl::LINEAR => { Ok(self::LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            self::NEAREST => gl::NEAREST,
            self::LINEAR => gl::LINEAR
        }
    }
}

#[allow(dead_code)]
impl TextureMipmapFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(TextureMipmapFilter::Filter(self::NEAREST)) },
            gl::LINEAR => { Ok(TextureMipmapFilter::Filter(self::LINEAR)) },
            gl::NEAREST_MIPMAP_NEAREST => { Ok(self::NEAREST_MIPMAP_NEAREST) },
            gl::LINEAR_MIPMAP_NEAREST => { Ok(self::LINEAR_MIPMAP_NEAREST) },
            gl::NEAREST_MIPMAP_LINEAR => { Ok(self::NEAREST_MIPMAP_LINEAR) },
            gl::LINEAR_MIPMAP_LINEAR => { Ok(self::LINEAR_MIPMAP_LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            TextureMipmapFilter::Filter(self::LINEAR) => { gl::LINEAR },
            TextureMipmapFilter::Filter(self::NEAREST) => { gl::NEAREST },
            self::NEAREST_MIPMAP_NEAREST => { gl::NEAREST_MIPMAP_NEAREST },
            self::LINEAR_MIPMAP_NEAREST => { gl::LINEAR_MIPMAP_NEAREST },
            self::NEAREST_MIPMAP_LINEAR => { gl::NEAREST_MIPMAP_LINEAR },
            self::LINEAR_MIPMAP_LINEAR => { gl::LINEAR_MIPMAP_LINEAR }
        }
    }
}

impl From<TextureFilter> for TextureMipmapFilter {
    fn from(filter: TextureFilter) -> TextureMipmapFilter {
        TextureMipmapFilter::Filter(filter)
    }
}

gl_enum! {
    pub gl_enum TextureWrapMode {
        ClampToEdge as CLAMP_TO_EDGE = gl::CLAMP_TO_EDGE,
        MirroredRepeat as MIRRORED_REPEAT = gl::MIRRORED_REPEAT,
        Repeat as REPEAT = gl::REPEAT
    }
}

unsafe fn _tex_parameter_iv(target: TextureBindingTarget,
                            pname: GLenum,
                            params: *const GLint)
{
    gl::TexParameteriv(target.gl_enum(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target` or `pname` is not an accepted defined value, or `params` should have defined a symbolic constant and does not",
        _ => "Unknown error"
    }
}

pub trait TextureBinding {
    type TextureType: TextureType;

    fn target() -> TextureBindingTarget {
        Self::TextureType::target()
    }

    fn set_min_filter<F: Into<TextureMipmapFilter>>(&mut self, filter: F) {
        let gl_int = filter.into().gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MIN_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_mag_filter(&mut self, filter: TextureFilter) {
        let gl_int = filter.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MAG_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_s(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_S,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_t(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_T,
                              &gl_int as *const GLint);
        }
    }

    fn image_2d<I>(&mut self,
                   level: i32,
                   target: <Self::TextureType as TextureType>::ImageTargetType,
                   img: &I)
        where I: Image2d
    {
        unsafe {
            let ptr = mem::transmute(img.textel_bytes().as_ptr());
            gl::TexImage2D(target.gl_enum(),
                           level as GLint,
                           img.format().textel_format.gl_enum() as GLint,
                           img.width() as i32,
                           img.height() as i32,
                           0,
                           img.format().textel_format.gl_enum(),
                           img.format().textel_type.gl_enum(),
                           ptr);
            dbg_gl_error! {
                GLError::InvalidEnum => "`target`, `format`, or `type` is not an accepted value",
                GLError::InvalidValue => "`target`, `level`, `internalformat`, `width`, `height`, or `border` is an invalid value",
                GLError::InvalidOperation => "`format` conflicts with either `internalformat` or `type`",
                _ => "Unknown error"
            }
        }
    }
}

pub struct Texture2dBinding<'a> {
    phantom: PhantomData<&'a mut Texture2d>
}

impl<'a> TextureBinding for Texture2dBinding<'a> {
    type TextureType = Tx2d;
}

pub struct TextureCubeMapBinding<'a> {
    phantom: PhantomData<&'a mut TextureCubeMap>
}

impl<'a> TextureBinding for TextureCubeMapBinding<'a> {
    type TextureType = TxCubeMap;
}

unsafe fn _bind_texture<T: TextureType>(texture: &mut Texture<T>) {
    gl::BindTexture(T::target().gl_enum(), texture.gl_id());
    dbg_gl_error! {
        GLError::InvalidEnum => "`target` is not one of the allowed values",
        GLError::InvalidOperation => "`texture` was created with a target that doesn't match `target`",
        _ => "Unknown error"
    }
}

pub struct Texture2dBinder;
impl Texture2dBinder {
    pub fn bind<'a>(&'a mut self, texture: &mut Texture2d)
        -> Texture2dBinding<'a>
    {
        unsafe {
            _bind_texture(texture);
        }
        Texture2dBinding { phantom: PhantomData }
    }
}

pub struct TextureCubeMapBinder;
impl TextureCubeMapBinder {
    pub fn bind<'a>(&'a mut self, texture: &mut TextureCubeMap)
        -> TextureCubeMapBinding<'a>
    {
        unsafe {
            _bind_texture(texture);
        }
        TextureCubeMapBinding { phantom: PhantomData }
    }
}
<|endoftext|>


<commit_before>pub use luminance::pixel::{Depth32F, R32F, RGBA32F};
pub use luminance::texture::{Dim2, Flat, MagFilter, MinFilter, Sampler, Texture, Wrap};
use image;
use std::ops::Deref;
use std::path::Path;

use resource::{Load, LoadError, Reload, ResCache, Result};

// Common texture aliases.
pub type TextureRGBA32F = Texture<Flat, Dim2, RGBA32F>;
pub type TextureDepth32F = Texture<Flat, Dim2, Depth32F>;

/// Load an RGBA texture from an image at a path.
///
/// The `linearizer` argument is an option that gives the factor to apply to linearize if needed. Pass
/// `None` if the texture is already linearized.
pub fn load_rgba_texture<P, L>(path: P, sampler: &Sampler, linearizer: L) -> Result<TextureRGBA32F> where P: AsRef<Path>, L: Into<Option<f32>> {
  info!("loading texture image: \x1b[35m{:?}", path.as_ref());

  let img = image::open(path).map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))?.flipv().to_rgba();
  let dim = img.dimensions();
  let linearizer = linearizer.into();
  let raw: Vec<f32> = img.into_raw().into_iter().map(|x| {
    let y = x as f32 / 255.;
    linearizer.map_or(y, |factor| y.powf(1. / factor))
  }).collect();

  let tex = Texture::new(dim, 0, sampler).map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))?;
  tex.upload_raw(false, &raw);

  Ok(tex)
}

/// Save an RGBA image on disk.
pub fn save_rgba_texture<P>(texture: &TextureRGBA32F, path: P) where P: AsRef<Path> {
  info!("saving texture image to: \x1b[35m{:?}", path.as_ref());

  let texels = texture.get_raw_texels();
  let (w, h) = texture.size();
  let mut output = Vec::with_capacity((w * h) as usize);

  for texel in &texels {
    output.push((texel * 255.) as u8);
  }

  let _ = image::save_buffer(path, &output, w, h, image::ColorType::RGBA(8));
}

pub struct TextureImage {
  pub texture: TextureRGBA32F,
  sampler: Sampler,
  linearizer: Option<f32>,
}

impl Deref for TextureImage {
  type Target = TextureRGBA32F;

  fn deref(&self) -> &Self::Target {
    &self.texture
  }
}

impl Load for TextureImage {
  type Args = (Sampler, Option<f32>);

  const TY_STR: &'static str = "textures";

  fn load<P>(path: P, _: &mut ResCache, (sampler, linearizer): Self::Args) -> Result<Self> where P: AsRef<Path> {
    load_rgba_texture(path, &sampler, linearizer)
      .map(|tex| TextureImage {
        texture: tex,
        sampler: sampler,
        linearizer: linearizer
      })
  }
}

impl Reload for TextureImage {
  fn reload_args(&self) -> Self::Args {
    (self.sampler, self.linearizer)
  }
}
<commit_msg>Export Unit from texture.rs.<commit_after>pub use luminance::pixel::{Depth32F, R32F, RGBA32F};
pub use luminance::texture::{Dim2, Flat, MagFilter, MinFilter, Sampler, Texture, Unit, Wrap};
use image;
use std::ops::Deref;
use std::path::Path;

use resource::{Load, LoadError, Reload, ResCache, Result};

// Common texture aliases.
pub type TextureRGBA32F = Texture<Flat, Dim2, RGBA32F>;
pub type TextureDepth32F = Texture<Flat, Dim2, Depth32F>;

/// Load an RGBA texture from an image at a path.
///
/// The `linearizer` argument is an option that gives the factor to apply to linearize if needed. Pass
/// `None` if the texture is already linearized.
pub fn load_rgba_texture<P, L>(path: P, sampler: &Sampler, linearizer: L) -> Result<TextureRGBA32F> where P: AsRef<Path>, L: Into<Option<f32>> {
  info!("loading texture image: \x1b[35m{:?}", path.as_ref());

  let img = image::open(path).map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))?.flipv().to_rgba();
  let dim = img.dimensions();
  let linearizer = linearizer.into();
  let raw: Vec<f32> = img.into_raw().into_iter().map(|x| {
    let y = x as f32 / 255.;
    linearizer.map_or(y, |factor| y.powf(1. / factor))
  }).collect();

  let tex = Texture::new(dim, 0, sampler).map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))?;
  tex.upload_raw(false, &raw);

  Ok(tex)
}

/// Save an RGBA image on disk.
pub fn save_rgba_texture<P>(texture: &TextureRGBA32F, path: P) where P: AsRef<Path> {
  info!("saving texture image to: \x1b[35m{:?}", path.as_ref());

  let texels = texture.get_raw_texels();
  let (w, h) = texture.size();
  let mut output = Vec::with_capacity((w * h) as usize);

  for texel in &texels {
    output.push((texel * 255.) as u8);
  }

  let _ = image::save_buffer(path, &output, w, h, image::ColorType::RGBA(8));
}

pub struct TextureImage {
  pub texture: TextureRGBA32F,
  sampler: Sampler,
  linearizer: Option<f32>,
}

impl Deref for TextureImage {
  type Target = TextureRGBA32F;

  fn deref(&self) -> &Self::Target {
    &self.texture
  }
}

impl Load for TextureImage {
  type Args = (Sampler, Option<f32>);

  const TY_STR: &'static str = "textures";

  fn load<P>(path: P, _: &mut ResCache, (sampler, linearizer): Self::Args) -> Result<Self> where P: AsRef<Path> {
    load_rgba_texture(path, &sampler, linearizer)
      .map(|tex| TextureImage {
        texture: tex,
        sampler: sampler,
        linearizer: linearizer
      })
  }
}

impl Reload for TextureImage {
  fn reload_args(&self) -> Self::Args {
    (self.sampler, self.linearizer)
  }
}
<|endoftext|>


<commit_before>use luminance::{Dim2, Flat, Sampler};
use luminance_gl::gl33::Texture;
use image::{self, ImageResult};
use std::path::Path;

pub use luminance::RGBA32F;

/// Load an RGBA texture from an image at a path.
pub fn load_rgba_texture<P>(path: P, sampler: &Sampler, linear: bool) -> ImageResult<Texture<Flat, Dim2, RGBA32F>> where P: AsRef<Path> {
  info!("loading texture image: \x1b[35m{:?}", path.as_ref());

  let image = try!(image::open(path)).to_rgba();
  let dim = image.dimensions();
  let raw: Vec<f32> = image.into_raw().into_iter().map(|x| {
    let y = x as f32 / 255.;

    if linear {
      y
    } else {
      y.powf(1. / 2.2)
    }
  }).collect();

  let tex = Texture::new(dim, 0, sampler);
  tex.upload_raw(false, &raw);

  Ok(tex)
}

/// Save an RGBA image on disk.
pub fn save_rgba_texture<P>(texture: &Texture<Flat, Dim2, RGBA32F>, path: P) where P: AsRef<Path> {
  info!("saving texture image to: \x1b[35m{:?}", path.as_ref());

  let texels = texture.get_raw_texels();
  let (w, h) = texture.size;
  let mut output = Vec::with_capacity((w * h) as usize);

  for texel in &texels {
    output.push((texel * 255.) as u8);
  }

  let _ = image::save_buffer(path, &output, w, h, image::ColorType::RGBA(8));
}

#[derive(Clone, Debug)]
pub enum TextureError {
  LoadingFailed(String)
}

#[cfg(feature = "hot-resource")]
mod hot {
  use luminance::{Dim2, Flat, Sampler};
  use luminance_gl::gl33::Texture;
  use std::ops::Deref;
  use std::path::{Path, PathBuf};
  use std::sync::mpsc;

  use resource::ResourceManager;

  use super::*;

  pub struct TextureImage {
    rx: mpsc::Receiver<()>,
    last_update_time: Option<f64>,
    texture: Texture<Flat, Dim2, RGBA32F>,
    sampler: Sampler,
    linear: bool,
    path: PathBuf
  }

  impl TextureImage {
    pub fn load<P>(manager: &mut ResourceManager, path: P, sampler: &Sampler, linear: bool) -> Result<Self, TextureError> where P: AsRef<Path> {
      let path = path.as_ref();

      let tex = load_rgba_texture(path, sampler, linear);

      match tex {
        Ok(tex) => {
          // monitor that texture
          let (sx, rx) = mpsc::channel();

          manager.monitor(path, sx);

          Ok(TextureImage {
            rx: rx,
            last_update_time: None,
            texture: tex,
            sampler: *sampler,
            linear: linear,
            path: path.to_path_buf()
          })
        },
        Err(e) => {
          Err(TextureError::LoadingFailed(format!("{:?}", e)))
        }
      }
    }

    fn reload(&mut self) {
      let path = self.path.as_path();
      let tex = load_rgba_texture(path, &self.sampler, self.linear);

      match tex {
        Ok(tex) => {
          self.texture = tex;
          info!("reloaded texture {:?}", path);
        },
        Err(e) => {
          err!("reloading texture {:?} has failed: {:?}", path, e);
        }
      }
    }

    decl_sync_hot!();
  }

  impl Deref for TextureImage {
    type Target = Texture<Flat, Dim2, RGBA32F>;

    fn deref(&self) -> &Self::Target {
      &self.texture
    }
  }
}

#[cfg(not(feature = "hot-resource"))]
mod cold {
  use luminance::{Dim2, Flat, Sampler};
  use luminance_gl::gl33::Texture;
  use std::ops::Deref;
  use std::path::Path;

  use resource::ResourceManager;

  use super::*;

  pub struct TextureImage(Texture<Flat, Dim2, RGBA32F>);

  impl TextureImage {
    pub fn load<P>(_: &mut ResourceManager, path: P, sampler: &Sampler, linear: bool) -> Result<Self, TextureError> where P: AsRef<Path> {
      let tex = load_rgba_texture(path, sampler, linear);

      match tex {
        Ok(tex) => {
          Ok(TextureImage(tex))
        },
        Err(e) => {
          Err(TextureError::LoadingFailed(format!("{:?}", e)))
        }
      }
    }

    pub fn sync(&mut self) {}
  }

  impl Deref for TextureImage {
    type Target = Texture<Flat, Dim2, RGBA32F>;

    fn deref(&self) -> &Self::Target {
      &self.0
    }
  }
}

#[cfg(feature = "hot-resource")]
pub use self::hot::*;
#[cfg(not(feature = "hot-resource"))]
pub use self::cold::*;
<commit_msg>Migrated Texture to Load+Reload!<commit_after>use luminance::{Dim2, Flat, Sampler};
use luminance_gl::gl33::Texture;
use image::{self, ImageResult};
use std::ops::Deref;
use std::path::Path;

pub use luminance::RGBA32F;

use resource::{Load, LoadError, Reload};

/// Load an RGBA texture from an image at a path.
pub fn load_rgba_texture<P>(path: P, sampler: &Sampler, linear: bool) -> ImageResult<Texture<Flat, Dim2, RGBA32F>> where P: AsRef<Path> {
  info!("loading texture image: \x1b[35m{:?}", path.as_ref());

  let image = try!(image::open(path)).to_rgba();
  let dim = image.dimensions();
  let raw: Vec<f32> = image.into_raw().into_iter().map(|x| {
    let y = x as f32 / 255.;

    if linear {
      y
    } else {
      y.powf(1. / 2.2)
    }
  }).collect();

  let tex = Texture::new(dim, 0, sampler);
  tex.upload_raw(false, &raw);

  Ok(tex)
}

/// Save an RGBA image on disk.
pub fn save_rgba_texture<P>(texture: &Texture<Flat, Dim2, RGBA32F>, path: P) where P: AsRef<Path> {
  info!("saving texture image to: \x1b[35m{:?}", path.as_ref());

  let texels = texture.get_raw_texels();
  let (w, h) = texture.size;
  let mut output = Vec::with_capacity((w * h) as usize);

  for texel in &texels {
    output.push((texel * 255.) as u8);
  }

  let _ = image::save_buffer(path, &output, w, h, image::ColorType::RGBA(8));
}

pub struct TextureImage {
  pub texture: Texture<Flat, Dim2, RGBA32F>,
  sampler: Sampler,
  linear: bool,
}

impl Deref for TextureImage {
  type Target = Texture<Flat, Dim2, RGBA32F>;

  fn deref(&self) -> &Self::Target {
    &self.texture
  }
}

impl Load for TextureImage {
  type Args = (Sampler, bool);

  fn load<P>(path: P, (sampler, linear): Self::Args) -> Result<Self, LoadError> where P: AsRef<Path> {
    load_rgba_texture(path, &sampler, linear)
      .map(|tex| TextureImage {
        texture: tex,
        sampler: sampler,
        linear: linear
        })
      .map_err(|e| LoadError::ConversionFailed(format!("{:?}", e)))
  }
}

impl Reload for TextureImage {
  fn reload<P>(&self, path :P) -> Result<Self, LoadError> where P: AsRef<Path> {
    Self::load(path, (self.sampler, self.linear))
  }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use super::phrase::*;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;
<commit_msg>Work on using the phrase type to declare a ‘IntoPattern’ trait<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use super::phrase::*;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<'a, Symbol: Clone, Iterator: PhraseIterator<Symbol>> IntoPattern<Symbol> for &'a Phrase<Symbol, PhraseIterator=Iterator> {
    ///
    /// Phrases can be turned into a literal matching pattern
    ///
    fn into_pattern(self) -> Pattern<Symbol> {
        let mut result = vec![];
        let mut reader = self.get_symbols();

        loop {
            match reader.next_symbol() {
                Some(symbol)    => result.push(symbol.clone()),
                None            => break
            }
        }

        Match(result)
    }
}

impl<Symbol> Pattern<Symbol> {

}

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

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }
}<|endoftext|>


<commit_before>// Copyright 2013 The Servo 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.

use point::Point2D;
use size::Size2D;
use std::cmp::{Eq, Ord};

#[deriving(Eq, Clone)]
pub struct Rect<T> {
    origin: Point2D<T>,
    size: Size2D<T>,
}

pub fn Rect<T:Clone + Ord + Add<T,T> + Sub<T,T>>(origin: Point2D<T>,
                                                 size: Size2D<T>)
        -> Rect<T> {
    return Rect {
        origin: origin,
        size: size
    }
}

impl<T: Clone + Ord + Add<T,T> + Sub<T,T>> Rect<T> {
    pub fn intersects(&self, other: &Rect<T>) -> bool {
        self.origin.x < other.origin.x + other.size.width &&
       other.origin.x <  self.origin.x + self.size.width &&
        self.origin.y < other.origin.y + other.size.height &&
       other.origin.y <  self.origin.y + self.size.height
    }

    pub fn intersection(&self, other: &Rect<T>) -> Option<Rect<T>> {
        if !self.intersects(other) {
            return None;
        }

        let upper_left = Point2D(max(self.origin.x.clone(), other.origin.x.clone()),
                                 max(self.origin.y.clone(), other.origin.y.clone()));

        let lower_right = Point2D(min(self.origin.x + self.size.width,
                                      other.origin.x + other.size.width),
                                  min(self.origin.y + self.size.height,
                                      other.origin.y + other.size.height));

        Some(Rect(upper_left.clone(), Size2D(lower_right.x - upper_left.x,
                                             lower_right.y - upper_left.y)))
    }

    pub fn union(&self, other: &Rect<T>) -> Rect<T> {
        let upper_left = Point2D(min(self.origin.x.clone(), other.origin.x.clone()),
                                 min(self.origin.y.clone(), other.origin.y.clone()));

        let lower_right = Point2D(max(self.origin.x + self.size.width,
                                      other.origin.x + other.size.width),
                                  max(self.origin.y + self.size.height,
                                      other.origin.y + other.size.height));

        Rect {
            origin: upper_left.clone(),
            size: Size2D(lower_right.x - upper_left.x, lower_right.y - upper_left.y)
        }
    }

    pub fn translate(&self, other: &Point2D<T>) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x + other.x, self.origin.y + other.y),
            size: self.size.clone()
        }
    }
}

pub fn min<T:Clone + Ord>(x: T, y: T) -> T {
    if x <= y { x } else { y }
}

pub fn max<T:Clone + Ord>(x: T, y: T) -> T {
    if x >= y { x } else { y }
}

#[test]
fn test_min_max() {
    assert!(min(0, 1) == 0);
    assert!(min(-1.0, 0.0) == -1.0);

    assert!(max(0, 1) == 1);
    assert!(max(-1.0, 0.0) == 0.0);
}

#[test]
fn test_translate() {
    let p = Rect(Point2D(0, 0), Size2D(50, 40));
    let pp = p.translate(&Point2D(10,15));

    assert!(pp.size.width == 50);
    assert!(pp.size.height == 40);
    assert!(pp.origin.x == 10);
    assert!(pp.origin.y == 15);

    let r = Rect(Point2D(-10, -5), Size2D(50, 40));
    let rr = r.translate(&Point2D(0,-10));

    assert!(rr.size.width == 50);
    assert!(rr.size.height == 40);
    assert!(rr.origin.x == -10);
    assert!(rr.origin.y == -15);
}

#[test]
fn test_union() {
    let p = Rect(Point2D(0,0), Size2D(50, 40));
    let q = Rect(Point2D(20,20), Size2D(5, 5));
    let r = Rect(Point2D(-15, -30), Size2D(200, 15));
    let s = Rect(Point2D(20, -15), Size2D(250, 200));

    let pq = p.union(&q);
    assert!(pq.origin == Point2D(0, 0));
    assert!(pq.size == Size2D(50, 40));

    let pr = p.union(&r);
    assert!(pr.origin == Point2D(-15, -30));
    assert!(pr.size == Size2D(200, 70));

    let ps = p.union(&s);
    assert!(ps.origin == Point2D(0, -15));
    assert!(ps.size == Size2D(270, 200));

}

#[test]
fn test_intersection() {
    let p = Rect(Point2D(0, 0), Size2D(10, 20));
    let q = Rect(Point2D(5, 15), Size2D(10, 10));
    let r = Rect(Point2D(-5, -5), Size2D(8, 8));

    let pq = p.intersection(&q);
    assert!(pq.is_some());
    let pq = pq.unwrap();
    assert!(pq.origin == Point2D(5, 15));
    assert!(pq.size == Size2D(5, 5));

    let pr = p.intersection(&r);
    assert!(pr.is_some());
    let pr = pr.unwrap();
    assert!(pr.origin == Point2D(0, 0));
    assert!(pr.size == Size2D(3, 3));

    let qr = q.intersection(&r);
    assert!(qr.is_none());
}
<commit_msg>Inline union and translate. This is important to make overflow computation fast.<commit_after>// Copyright 2013 The Servo 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.

use point::Point2D;
use size::Size2D;
use std::cmp::{Eq, Ord};

#[deriving(Eq, Clone)]
pub struct Rect<T> {
    origin: Point2D<T>,
    size: Size2D<T>,
}

pub fn Rect<T:Clone + Ord + Add<T,T> + Sub<T,T>>(origin: Point2D<T>,
                                                 size: Size2D<T>)
        -> Rect<T> {
    return Rect {
        origin: origin,
        size: size
    }
}

impl<T: Clone + Ord + Add<T,T> + Sub<T,T>> Rect<T> {
    #[inline]
    pub fn intersects(&self, other: &Rect<T>) -> bool {
        self.origin.x < other.origin.x + other.size.width &&
       other.origin.x <  self.origin.x + self.size.width &&
        self.origin.y < other.origin.y + other.size.height &&
       other.origin.y <  self.origin.y + self.size.height
    }

    #[inline]
    pub fn intersection(&self, other: &Rect<T>) -> Option<Rect<T>> {
        if !self.intersects(other) {
            return None;
        }

        let upper_left = Point2D(max(self.origin.x.clone(), other.origin.x.clone()),
                                 max(self.origin.y.clone(), other.origin.y.clone()));

        let lower_right = Point2D(min(self.origin.x + self.size.width,
                                      other.origin.x + other.size.width),
                                  min(self.origin.y + self.size.height,
                                      other.origin.y + other.size.height));

        Some(Rect(upper_left.clone(), Size2D(lower_right.x - upper_left.x,
                                             lower_right.y - upper_left.y)))
    }

    #[inline]
    pub fn union(&self, other: &Rect<T>) -> Rect<T> {
        let upper_left = Point2D(min(self.origin.x.clone(), other.origin.x.clone()),
                                 min(self.origin.y.clone(), other.origin.y.clone()));

        let lower_right = Point2D(max(self.origin.x + self.size.width,
                                      other.origin.x + other.size.width),
                                  max(self.origin.y + self.size.height,
                                      other.origin.y + other.size.height));

        Rect {
            origin: upper_left.clone(),
            size: Size2D(lower_right.x - upper_left.x, lower_right.y - upper_left.y)
        }
    }

    #[inline]
    pub fn translate(&self, other: &Point2D<T>) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x + other.x, self.origin.y + other.y),
            size: self.size.clone()
        }
    }
}

pub fn min<T:Clone + Ord>(x: T, y: T) -> T {
    if x <= y { x } else { y }
}

pub fn max<T:Clone + Ord>(x: T, y: T) -> T {
    if x >= y { x } else { y }
}

#[test]
fn test_min_max() {
    assert!(min(0, 1) == 0);
    assert!(min(-1.0, 0.0) == -1.0);

    assert!(max(0, 1) == 1);
    assert!(max(-1.0, 0.0) == 0.0);
}

#[test]
fn test_translate() {
    let p = Rect(Point2D(0, 0), Size2D(50, 40));
    let pp = p.translate(&Point2D(10,15));

    assert!(pp.size.width == 50);
    assert!(pp.size.height == 40);
    assert!(pp.origin.x == 10);
    assert!(pp.origin.y == 15);

    let r = Rect(Point2D(-10, -5), Size2D(50, 40));
    let rr = r.translate(&Point2D(0,-10));

    assert!(rr.size.width == 50);
    assert!(rr.size.height == 40);
    assert!(rr.origin.x == -10);
    assert!(rr.origin.y == -15);
}

#[test]
fn test_union() {
    let p = Rect(Point2D(0,0), Size2D(50, 40));
    let q = Rect(Point2D(20,20), Size2D(5, 5));
    let r = Rect(Point2D(-15, -30), Size2D(200, 15));
    let s = Rect(Point2D(20, -15), Size2D(250, 200));

    let pq = p.union(&q);
    assert!(pq.origin == Point2D(0, 0));
    assert!(pq.size == Size2D(50, 40));

    let pr = p.union(&r);
    assert!(pr.origin == Point2D(-15, -30));
    assert!(pr.size == Size2D(200, 70));

    let ps = p.union(&s);
    assert!(ps.origin == Point2D(0, -15));
    assert!(ps.size == Size2D(270, 200));

}

#[test]
fn test_intersection() {
    let p = Rect(Point2D(0, 0), Size2D(10, 20));
    let q = Rect(Point2D(5, 15), Size2D(10, 10));
    let r = Rect(Point2D(-5, -5), Size2D(8, 8));

    let pq = p.intersection(&q);
    assert!(pq.is_some());
    let pq = pq.unwrap();
    assert!(pq.origin == Point2D(5, 15));
    assert!(pq.size == Size2D(5, 5));

    let pr = p.intersection(&r);
    assert!(pr.is_some());
    let pr = pr.unwrap();
    assert!(pr.origin == Point2D(0, 0));
    assert!(pr.size == Size2D(3, 3));

    let qr = q.intersection(&r);
    assert!(qr.is_none());
}
<|endoftext|>


<commit_before>use {gfx, graphics};

use ui::{BB, Px};
use ui::text;

pub struct DrawCx<'a> {
    gfx: gfx::BackEnd<'a>,
    pub fonts: &'a mut text::FontFaces,
    pub cursor: gfx::MouseCursor,
    transform: gfx::Mat2
}

impl<'a> DrawCx<'a> {
    pub fn new(g2d: &'a mut gfx::G2d,
               renderer: &'a mut gfx::Renderer,
               output: &'a gfx::Output,
               viewport: gfx::Viewport,
               fonts: &'a mut text::FontFaces) -> DrawCx<'a> {
        renderer.reset();
        DrawCx {
            gfx: gfx::BackEnd::new(renderer, output, g2d),
            fonts: fonts,
            cursor: gfx::MouseCursor::Default,
            transform: graphics::Context::new_viewport(viewport).transform
        }
    }

    pub fn draw<T: Draw>(&mut self, x: &T) {
        x.draw(self);
        }
    }

    pub fn with_gfx<F, T>(&mut self, f: F) -> T where F: FnOnce(&mut gfx::BackEnd) -> T {
        f(&mut self.gfx)
    }

    pub fn clear(&mut self, color: gfx::Color) {
        self.with_gfx(|gfx| graphics::clear(color, gfx));
    }

    pub fn rect(&mut self, bb: BB<Px>, color: gfx::Color) {
        let transform = self.transform;
        self.with_gfx(|gfx| {
            graphics::rectangle(color,
                [bb.x1 as f64, bb.y1 as f64,
                 (bb.x2 - bb.x1)  as f64, (bb.y2 - bb.y1)  as f64],
                transform, gfx);
        });
    }

    pub fn text<F: text::FontFace>(&mut self, font: F, [x, y]: [Px; 2], color: gfx::Color, text: &str) {
        use graphics::*;

        let cache = font.cache(self.fonts);
        let y = y + cache.metrics(font.size()).baseline;
        text::Text::colored(color, font.size()).draw(
            text,
            cache,
            default_draw_state(),
            self.transform.trans(x as f64, y as f64),
            &mut self.gfx
        );
    }
}

pub trait Draw {
    fn draw(&self, cx: &mut DrawCx);
}

impl<A, B> Draw for (A, B) where
        A: Draw,
        B: Draw {
    fn draw(&self, cx: &mut DrawCx) {
        self.0.draw(cx);
        self.1.draw(cx);
    }
}
<commit_msg>draw: add overlay support with a simple multi-pass traversal.<commit_after>use {gfx, graphics};

use ui::{BB, Px};
use ui::text;

pub struct DrawCx<'a> {
    gfx: gfx::BackEnd<'a>,
    pub fonts: &'a mut text::FontFaces,
    pub cursor: gfx::MouseCursor,
    transform: gfx::Mat2,
    overlay_requested: bool,
    overlay_drawing: bool,
    inside_overlay: bool
}

impl<'a> DrawCx<'a> {
    pub fn new(g2d: &'a mut gfx::G2d,
               renderer: &'a mut gfx::Renderer,
               output: &'a gfx::Output,
               viewport: gfx::Viewport,
               fonts: &'a mut text::FontFaces) -> DrawCx<'a> {
        renderer.reset();
        DrawCx {
            gfx: gfx::BackEnd::new(renderer, output, g2d),
            fonts: fonts,
            cursor: gfx::MouseCursor::Default,
            transform: graphics::Context::new_viewport(viewport).transform,
            overlay_requested: false,
            overlay_drawing: false,
            inside_overlay: false
        }
    }

    pub fn draw<T: Draw>(&mut self, x: &T) {
        x.draw(self);
        if self.overlay_requested {
            self.overlay_drawing = true;
            x.draw(self);
            self.overlay_drawing = false;
            self.overlay_requested = false;
        }
    }

    pub fn draw_overlay<F, T>(&mut self, f: F) -> T where F: FnOnce(&mut DrawCx) -> T {
        assert!(!self.inside_overlay);
        self.inside_overlay = true;
        let r = f(self);
        self.inside_overlay = false;
        self.overlay_requested = true;
        r
    }

    pub fn with_gfx<F, T>(&mut self, f: F) -> Option<T> where F: FnOnce(&mut gfx::BackEnd) -> T {
        if self.inside_overlay == self.overlay_drawing {
            Some(f(&mut self.gfx))
        } else {
            None
        }
    }

    pub fn clear(&mut self, color: gfx::Color) {
        self.with_gfx(|gfx| graphics::clear(color, gfx));
    }

    pub fn rect(&mut self, bb: BB<Px>, color: gfx::Color) {
        let transform = self.transform;
        self.with_gfx(|gfx| {
            graphics::rectangle(color,
                [bb.x1 as f64, bb.y1 as f64,
                 (bb.x2 - bb.x1)  as f64, (bb.y2 - bb.y1)  as f64],
                transform, gfx);
        });
    }

    pub fn text<F: text::FontFace>(&mut self, font: F, [x, y]: [Px; 2], color: gfx::Color, text: &str) {
        use graphics::*;

        if self.inside_overlay != self.overlay_drawing {
            return;
        }

        let cache = font.cache(self.fonts);
        let y = y + cache.metrics(font.size()).baseline;
        text::Text::colored(color, font.size()).draw(
            text,
            cache,
            default_draw_state(),
            self.transform.trans(x as f64, y as f64),
            &mut self.gfx
        );
    }
}

pub trait Draw {
    fn draw(&self, cx: &mut DrawCx);
}

impl<A, B> Draw for (A, B) where
        A: Draw,
        B: Draw {
    fn draw(&self, cx: &mut DrawCx) {
        self.0.draw(cx);
        self.1.draw(cx);
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#[derive(Deserialize, Debug)]
pub struct Error {
    pub code: i64,
    pub message: String,
}
#[derive(Deserialize, Debug)]
pub struct ErrorConsignmentSet {
    pub error: Error
}
#[derive(Deserialize, Debug)]
pub struct Json {
    pub consignmentSet: Vec<ErrorConsignmentSet>,
}
#[derive(Deserialize, Debug)]
pub struct Senderaddress {
    pub addressLine1: Option<String>,
    pub addressLine2: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Recipientsignature {
    pub name: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct EventsetDefinition {
    pub term: Option<String>,
    pub explanation: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Eventset {
    pub description: String,
    pub status: String,
    pub recipientSignature: Option<Recipientsignature>,
    pub unitId: Option<String>,
    pub unitInformationUrl: Option<String>,
    pub unitType: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
    pub dateIso: Option<String>,
    pub displayDate: Option<String>,
    pub displayTime: Option<String>,
    pub consignmentEvent: bool,
    pub definitions: Option<Vec<EventsetDefinition>>
}
#[derive(Deserialize, Debug)]
pub struct Packageset {
    pub statusDescription: String,
    pub descriptions: Vec<String>,
    pub packageNumber: String,
    pub previousPackageNumber: Option<String>,
    pub productName: Option<String>,
    pub productCode: Option<String>,
    pub brand: Option<String>,
    pub lengthInCm: Option<i64>,
    pub widthInCm: Option<i64>,
    pub heightInCm: Option<i64>,
    pub volumeInDm3: Option<f64>,
    pub weightInKgs: Option<f64>,
    pub pickupCode: Option<String>,
    pub dateOfReturn: Option<String>,
    pub senderName: String,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub eventSet: Vec<Eventset>,
}
#[derive(Deserialize, Debug)]
pub struct Consignmentset {
    pub consignmentId: Option<String>,
    pub previousConsignmentId: Option<String>,
    pub packageSet: Vec<Packageset>,
    pub senderName: Option<String>,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub senderReference: Option<String>,
    pub totalWeightInKgs: Option<f64>,
    pub totalVolumeInDm3: Option<f64>,
}
#[derive(Deserialize, Debug)]
pub struct BringResponse {
    pub consignmentSet: Vec<Consignmentset>,
}
<commit_msg>add TODO<commit_after>// TODO Rename structs to snake_case
// TODO serde code_gen for backwards compatibility
#![allow(non_snake_case)]
#[derive(Deserialize, Debug)]
pub struct Error {
    pub code: i64,
    pub message: String,
}
#[derive(Deserialize, Debug)]
pub struct ErrorConsignmentSet {
    pub error: Error
}
#[derive(Deserialize, Debug)]
pub struct Json {
    pub consignmentSet: Vec<ErrorConsignmentSet>,
}
#[derive(Deserialize, Debug)]
pub struct Senderaddress {
    pub addressLine1: Option<String>,
    pub addressLine2: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Recipientsignature {
    pub name: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct EventsetDefinition {
    pub term: Option<String>,
    pub explanation: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Eventset {
    pub description: String,
    pub status: String,
    pub recipientSignature: Option<Recipientsignature>,
    pub unitId: Option<String>,
    pub unitInformationUrl: Option<String>,
    pub unitType: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
    pub dateIso: Option<String>,
    pub displayDate: Option<String>,
    pub displayTime: Option<String>,
    pub consignmentEvent: bool,
    pub definitions: Option<Vec<EventsetDefinition>>
}
#[derive(Deserialize, Debug)]
pub struct Packageset {
    pub statusDescription: String,
    pub descriptions: Vec<String>,
    pub packageNumber: String,
    pub previousPackageNumber: Option<String>,
    pub productName: Option<String>,
    pub productCode: Option<String>,
    pub brand: Option<String>,
    pub lengthInCm: Option<i64>,
    pub widthInCm: Option<i64>,
    pub heightInCm: Option<i64>,
    pub volumeInDm3: Option<f64>,
    pub weightInKgs: Option<f64>,
    pub pickupCode: Option<String>,
    pub dateOfReturn: Option<String>,
    pub senderName: String,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub eventSet: Vec<Eventset>,
}
#[derive(Deserialize, Debug)]
pub struct Consignmentset {
    pub consignmentId: Option<String>,
    pub previousConsignmentId: Option<String>,
    pub packageSet: Vec<Packageset>,
    pub senderName: Option<String>,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub senderReference: Option<String>,
    pub totalWeightInKgs: Option<f64>,
    pub totalVolumeInDm3: Option<f64>,
}
#[derive(Deserialize, Debug)]
pub struct BringResponse {
    pub consignmentSet: Vec<Consignmentset>,
}
<|endoftext|>


<commit_before>use std::mem;
use std::collections::HashMap;

use super::lexer::{Lexer, LexError};
use super::token::{TokenSpan, Token, Lit};
use super::ast::*; // TODO: remove * import

pub struct Parser<'a> {
    lexer: Lexer<'a>,

    curr: Option<TokenSpan>,
    last: Option<TokenSpan>,
    peek: Option<TokenSpan>,
}

impl<'a> Parser<'a> {
    pub fn from_query(q: &'a str) -> Parser<'a> {
        let lex = Lexer::from_query(q);
        Parser {
            lexer: lex,
            curr: None,
            last: None,
            peek: None,
        }
    }

    pub fn parse(&mut self) -> Result<Query, ParserError> {
        // TODO: handle this with a better error message
        try!(self.bump());
        try!(self.bump());

        self.parse_commands()
    }

    fn bump(&mut self) -> Result<(), ParserError> {
        // do stuff. Mainly swap last = curr, curr = peek, then peek = next_real
        mem::swap(&mut self.last, &mut self.curr);
        mem::swap(&mut self.curr, &mut self.peek);
        self.peek = try!(self.lexer.next_real());
        Ok(())
    }

    // SQL Commands

    fn parse_commands(&mut self) -> Result<Query, ParserError> {
        let curr = self.curr.clone();

        // Parse first word that
        match curr.unwrap().token {
            Token::Word(val) => self.run_major_command(val),
            _ => Err(ParserError::FirstCmdNotWord),
        }
    }

    fn run_major_command(&mut self, cmd: String) -> Result<Query, ParserError> {
        match Keyword::from_str(&*cmd).unwrap() { // TODO: clean up unwrap
            Keyword::Select => self.parse_select(),
            Keyword::Insert => self.parse_insert(),

            _ => Err(ParserError::FirstCmdNotMajor),
        }
    }

    fn parse_select(&mut self) -> Result<Query, ParserError> {
        // TODO: impl parse_select

        Ok(Query::Table(TableStmt::Select(SelectStmt {
            cols: vec![Col { name: "id".to_owned() }],
            table: Table {
                name: "user_v1".to_owned(),
                alias: None,
            },
        })))
    }

    fn parse_insert(&mut self) -> Result<Query, ParserError> {
        // TODO: impl parse_insert
        try!(self.expect_keyword(Keyword::Into));

        let table = {
            let name = try!(self.expect_word());
            Table {
                name: name,
                alias: None,
            }
        };

        let cols = try!(self.expect_comma_dil_word());

        try!(self.expect_keyword(Keyword::Values));

        let mut values = try!(self.expect_comma_dil_lit());

        if cols.capacity() != values.capacity() {
            return Err(ParserError::ColumsDoNotMatchValues);
        }

        let mut cols_map = HashMap::new();
        for col in cols {
            let col = Col { name: col };
            cols_map.insert(col, values.remove(0));
        }

        try!(self.expect_token(Token::Semi));
        Ok(Query::Table(TableStmt::Insert(InsertStmt {
            table: table,
            cols: cols_map,
        })))
    }
}

// Helper function
impl<'a> Parser<'a> {
    fn expect_keyword(&mut self, exp: Keyword) -> Result<Keyword, ParserError> {
        // TODO: clean up unwrap but they should be safe for the moment

        try!(self.bump());
        let curr = {
            let token = &self.curr.clone().unwrap();

            match &token.token {
                &Token::Word(ref word) => word.clone(),
                t => return Err(ParserError::ExpectedKeyword(exp, format!("{:?}", t))),
            }
        };

        let actual = try!(Keyword::from_str(&curr));

        if actual == exp {
            Ok(actual)
        } else {
            Err(ParserError::ExpectedKeyword(exp, curr))
        }
    }

    fn expect_token(&mut self, exp: Token)  -> Result<Token, ParserError> {
        try!(self.bump());

        let token = self.curr.clone().unwrap();
        let actual = token.token.clone();

        if actual == exp {
            Ok(actual)
        } else {
            Err(ParserError::ExpectedToken(exp, format!("{:?}", actual)))
        }
    }

    // expect word case insensitive.
    fn expect_word(&mut self) -> Result<String, ParserError> {
        try!(self.bump());

        let token = match self.curr.clone() {
            Some(t) => t,
            None => return Err(ParserError::ExpectedTokenButGotNone),
        };
        let actual = token.token.clone();

        let word = match actual {
            Token::Word(ref word) => word.to_lowercase(), // always lowercase
            t => return Err(ParserError::ExpectedToken(Token::Word(String::new()), format!("{:?}", t))),
        };

        Ok(word)
    }

    fn expect_lit(&mut self) -> Result<Lit, ParserError> {
        try!(self.bump());

        let token = self.curr.clone().unwrap();
        let actual = token.token.clone();

        match actual {
            Token::Literal(lit) => Ok(lit),
            t => Err(ParserError::ExpectedToken(Token::Literal(Lit::String(String::new())), format!("{:?}", t))),
        }
    }

    fn expect_comma_dil_lit(&mut self) -> Result<Vec<Lit>, ParserError> {
        try!(self.expect_token(Token::ParentOP));

        let mut cols = Vec::new();

        loop {
            match self.expect_lit() {
                Ok(ref lit) => {
                    cols.push(lit.clone());
                    match try!(self.peek_clone()) {
                        Token::Comma => try!(self.bump()),
                        Token::ParentCL => {
                            try!(self.bump());
                            break;
                        },
                        token => return Err(ParserError::ExpectedToken(Token::Comma, format!("{:?}", token))),
                    }
                },
                Err(err) => return Err(err),
            }
        }

        Ok(cols)
    }

    fn expect_comma_dil_word(&mut self) -> Result<Vec<String>, ParserError> {
        try!(self.expect_token(Token::ParentOP));

        let mut cols = Vec::new();

        loop {
            match self.expect_word() {
                Ok(ref word) => {
                    cols.push(word.to_owned());
                    match try!(self.peek_clone()) {
                        Token::Comma => try!(self.bump()),
                        Token::ParentCL => {
                            try!(self.bump());
                            break;
                        },
                        token => return Err(ParserError::ExpectedToken(Token::Comma, format!("{:?}", token))),
                    }
                },
                Err(err) => return Err(err),
            }
        }

        Ok(cols)
    }

    fn peek_clone(&mut self) -> Result<Token, ParserError> {
        let peek = try!(Self::unwrap_tokenspan(self.peek.clone()));

        Ok(peek.token)
    }

    fn unwrap_tokenspan(t: Option<TokenSpan>) -> Result<TokenSpan, ParserError> {
        match t {
            Some(val) =>  Ok(val),
            None => Err(ParserError::ExpectedTokenButGotNone),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Keyword {
    // Major
    Select,
    Insert,

    // Minor
    From,
    Into,
    Values,
}

impl Keyword {
    pub fn from_str(k: &str) -> Result<Keyword, ParserError> {
        let keyword = match &*k.to_lowercase() {
            "select" => Keyword::Select,
            "insert" => Keyword::Insert,

            "from" => Keyword::From,
            "into" => Keyword::Into,
            "values" => Keyword::Values,

            // Keyword not found
            keyword => return Err(ParserError::UnexpectedKeyword(keyword.to_owned())), // TODO: clean up panic
        };

        Ok(keyword)
    }
}

#[derive(Debug)]
pub enum ParserError {
    InvalidCommand,
    LexerError(LexError),

    FirstCmdNotWord,
    FirstCmdNotMajor,

    ColumsDoNotMatchValues,

    ExpectedKeyword(Keyword, String), // exp, actual
    ExpectedToken(Token, String), // exp, actual
    ExpectedTokenButGotNone,

    UnexpectedKeyword(String),
}

impl From<LexError> for ParserError {
    fn from(e: LexError) -> ParserError {
        ParserError::LexerError(e)
    }
}

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

    #[test]
    fn select() {
        let mut p = Parser::from_query("select");
        p.parse().unwrap();
    }

    #[test]
    fn insert() {
        let mut p = Parser::from_query("INSERT INTO users (name, email) VALUES (\"first last\", \"first.last@example.com\");");
        let q = p.parse().unwrap();

    }

    #[test]
    #[should_panic]
    fn insert_no_table_name() {
        Parser::from_query("insert into (asdf aslkdfhjahh dsfkjals)").parse().unwrap();
    }

    #[test]
    #[should_panic]
    fn insert_non_proper_col_list() {
        Parser::from_query("insert into users (asdf aslkdfhjahh dsfkjals)").parse().unwrap();
    }

    #[test]
    #[should_panic]
    fn first_non_major() {
        let err = Parser::from_query("alskdfj").parse();
        assert!(err.is_err());
    }
}
<commit_msg>added commented out test code for insert stmt<commit_after>use std::mem;
use std::collections::HashMap;

use super::lexer::{Lexer, LexError};
use super::token::{TokenSpan, Token, Lit};
use super::ast::*; // TODO: remove * import

pub struct Parser<'a> {
    lexer: Lexer<'a>,

    curr: Option<TokenSpan>,
    last: Option<TokenSpan>,
    peek: Option<TokenSpan>,
}

impl<'a> Parser<'a> {
    pub fn from_query(q: &'a str) -> Parser<'a> {
        let lex = Lexer::from_query(q);
        Parser {
            lexer: lex,
            curr: None,
            last: None,
            peek: None,
        }
    }

    pub fn parse(&mut self) -> Result<Query, ParserError> {
        // TODO: handle this with a better error message
        try!(self.bump());
        try!(self.bump());

        self.parse_commands()
    }

    fn bump(&mut self) -> Result<(), ParserError> {
        // do stuff. Mainly swap last = curr, curr = peek, then peek = next_real
        mem::swap(&mut self.last, &mut self.curr);
        mem::swap(&mut self.curr, &mut self.peek);
        self.peek = try!(self.lexer.next_real());
        Ok(())
    }

    // SQL Commands

    fn parse_commands(&mut self) -> Result<Query, ParserError> {
        let curr = self.curr.clone();

        // Parse first word that
        match curr.unwrap().token {
            Token::Word(val) => self.run_major_command(val),
            _ => Err(ParserError::FirstCmdNotWord),
        }
    }

    fn run_major_command(&mut self, cmd: String) -> Result<Query, ParserError> {
        match Keyword::from_str(&*cmd).unwrap() { // TODO: clean up unwrap
            Keyword::Select => self.parse_select(),
            Keyword::Insert => self.parse_insert(),

            _ => Err(ParserError::FirstCmdNotMajor),
        }
    }

    fn parse_select(&mut self) -> Result<Query, ParserError> {
        // TODO: impl parse_select

        Ok(Query::Table(TableStmt::Select(SelectStmt {
            cols: vec![Col { name: "id".to_owned() }],
            table: Table {
                name: "user_v1".to_owned(),
                alias: None,
            },
        })))
    }

    fn parse_insert(&mut self) -> Result<Query, ParserError> {
        // TODO: impl parse_insert
        try!(self.expect_keyword(Keyword::Into));

        let table = {
            let name = try!(self.expect_word());
            Table {
                name: name,
                alias: None,
            }
        };

        let cols = try!(self.expect_comma_dil_word());

        try!(self.expect_keyword(Keyword::Values));

        let mut values = try!(self.expect_comma_dil_lit());

        if cols.capacity() != values.capacity() {
            return Err(ParserError::ColumsDoNotMatchValues);
        }

        let mut cols_map = HashMap::new();
        for col in cols {
            let col = Col { name: col };
            cols_map.insert(col, values.remove(0));
        }

        try!(self.expect_token(Token::Semi));
        Ok(Query::Table(TableStmt::Insert(InsertStmt {
            table: table,
            cols: cols_map,
        })))
    }
}

// Helper function
impl<'a> Parser<'a> {
    fn expect_keyword(&mut self, exp: Keyword) -> Result<Keyword, ParserError> {
        // TODO: clean up unwrap but they should be safe for the moment

        try!(self.bump());
        let curr = {
            let token = &self.curr.clone().unwrap();

            match &token.token {
                &Token::Word(ref word) => word.clone(),
                t => return Err(ParserError::ExpectedKeyword(exp, format!("{:?}", t))),
            }
        };

        let actual = try!(Keyword::from_str(&curr));

        if actual == exp {
            Ok(actual)
        } else {
            Err(ParserError::ExpectedKeyword(exp, curr))
        }
    }

    fn expect_token(&mut self, exp: Token)  -> Result<Token, ParserError> {
        try!(self.bump());

        let token = self.curr.clone().unwrap();
        let actual = token.token.clone();

        if actual == exp {
            Ok(actual)
        } else {
            Err(ParserError::ExpectedToken(exp, format!("{:?}", actual)))
        }
    }

    // expect word case insensitive.
    fn expect_word(&mut self) -> Result<String, ParserError> {
        try!(self.bump());

        let token = match self.curr.clone() {
            Some(t) => t,
            None => return Err(ParserError::ExpectedTokenButGotNone),
        };
        let actual = token.token.clone();

        let word = match actual {
            Token::Word(ref word) => word.to_lowercase(), // always lowercase
            t => return Err(ParserError::ExpectedToken(Token::Word(String::new()), format!("{:?}", t))),
        };

        Ok(word)
    }

    fn expect_lit(&mut self) -> Result<Lit, ParserError> {
        try!(self.bump());

        let token = self.curr.clone().unwrap();
        let actual = token.token.clone();

        match actual {
            Token::Literal(lit) => Ok(lit),
            t => Err(ParserError::ExpectedToken(Token::Literal(Lit::String(String::new())), format!("{:?}", t))),
        }
    }

    fn expect_comma_dil_lit(&mut self) -> Result<Vec<Lit>, ParserError> {
        try!(self.expect_token(Token::ParentOP));

        let mut cols = Vec::new();

        loop {
            match self.expect_lit() {
                Ok(ref lit) => {
                    cols.push(lit.clone());
                    match try!(self.peek_clone()) {
                        Token::Comma => try!(self.bump()),
                        Token::ParentCL => {
                            try!(self.bump());
                            break;
                        },
                        token => return Err(ParserError::ExpectedToken(Token::Comma, format!("{:?}", token))),
                    }
                },
                Err(err) => return Err(err),
            }
        }

        Ok(cols)
    }

    fn expect_comma_dil_word(&mut self) -> Result<Vec<String>, ParserError> {
        try!(self.expect_token(Token::ParentOP));

        let mut cols = Vec::new();

        loop {
            match self.expect_word() {
                Ok(ref word) => {
                    cols.push(word.to_owned());
                    match try!(self.peek_clone()) {
                        Token::Comma => try!(self.bump()),
                        Token::ParentCL => {
                            try!(self.bump());
                            break;
                        },
                        token => return Err(ParserError::ExpectedToken(Token::Comma, format!("{:?}", token))),
                    }
                },
                Err(err) => return Err(err),
            }
        }

        Ok(cols)
    }

    fn peek_clone(&mut self) -> Result<Token, ParserError> {
        let peek = try!(Self::unwrap_tokenspan(self.peek.clone()));

        Ok(peek.token)
    }

    fn unwrap_tokenspan(t: Option<TokenSpan>) -> Result<TokenSpan, ParserError> {
        match t {
            Some(val) =>  Ok(val),
            None => Err(ParserError::ExpectedTokenButGotNone),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Keyword {
    // Major
    Select,
    Insert,

    // Minor
    From,
    Into,
    Values,
}

impl Keyword {
    pub fn from_str(k: &str) -> Result<Keyword, ParserError> {
        let keyword = match &*k.to_lowercase() {
            "select" => Keyword::Select,
            "insert" => Keyword::Insert,

            "from" => Keyword::From,
            "into" => Keyword::Into,
            "values" => Keyword::Values,

            // Keyword not found
            keyword => return Err(ParserError::UnexpectedKeyword(keyword.to_owned())), // TODO: clean up panic
        };

        Ok(keyword)
    }
}

#[derive(Debug)]
pub enum ParserError {
    InvalidCommand,
    LexerError(LexError),

    FirstCmdNotWord,
    FirstCmdNotMajor,

    ColumsDoNotMatchValues,

    ExpectedKeyword(Keyword, String), // exp, actual
    ExpectedToken(Token, String), // exp, actual
    ExpectedTokenButGotNone,

    UnexpectedKeyword(String),
}

impl From<LexError> for ParserError {
    fn from(e: LexError) -> ParserError {
        ParserError::LexerError(e)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::token::*;
    use super::super::ast::*;
    use std::collections::HashMap;

    #[test]
    fn select() {
        let mut p = Parser::from_query("select");
        p.parse().unwrap();
    }

    #[test]
    fn insert() {
        let mut p = Parser::from_query("INSERT INTO users (name, email) VALUES (\"first last\", \"first.last@example.com\");");
        let q = p.parse().unwrap();

        // let mut cols = HashMap::new();
        // cols.insert(Col { name: "name".to_owned() }, Lit::String("first last".to_owned()));
        // cols.insert(Col { name: "email".to_owned() }, Lit::String("first.last@example.com".to_owned()));
        //
        //
        //
        // let q_exp = Query::Table(TableStmt::Insert(InsertStmt {
        //     table: Table {
        //         name: "users".to_owned(),
        //         alias: None,
        //     },
        //     cols: cols,
        // }));
    }

    #[test]
    #[should_panic]
    fn insert_no_table_name() {
        Parser::from_query("insert into (asdf aslkdfhjahh dsfkjals)").parse().unwrap();
    }

    #[test]
    #[should_panic]
    fn insert_non_proper_col_list() {
        Parser::from_query("insert into users (asdf aslkdfhjahh dsfkjals)").parse().unwrap();
    }

    #[test]
    #[should_panic]
    fn first_non_major() {
        let err = Parser::from_query("alskdfj").parse();
        assert!(err.is_err());
    }
}
<|endoftext|>


<commit_before>use parser::combinators::{Parser, StrParser, ParseTo, Consumer, string, character};
use self::Token::{LParen, RParen, Whitespace, Identifier};

#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Token<'a> {
    LParen,
    RParen,
    Whitespace,
    Identifier(&'a str),
}

pub trait LexerConsumer<D> where D: for<'a> Consumer<Token<'a>> {
    fn accept<L>(self, lexer: L) where L: for<'a> ParseTo<&'a str,D>;
}

fn mk_identifier<'a>(s: &'a str) -> Token<'a> { Identifier(s) }

#[allow(non_snake_case)]
pub fn lexer<C,D>(consumer: C) where C: LexerConsumer<D>, D: for<'a> Consumer<Token<'a>> {
    let LPAREN = string("(").map(|_| LParen);
    let RPAREN = string(")").map(|_| RParen);
    let WHITESPACE = character(char::is_whitespace).map(|_| Whitespace);
    let IDENTIFIER = character(char::is_alphabetic).and_then(character(char::is_alphanumeric).star())
                                                   .buffer().map(mk_identifier);
    let TOKEN = LPAREN.or_else(RPAREN).or_else(WHITESPACE).or_else(IDENTIFIER);
    consumer.accept(TOKEN.star())
}

#[test]
fn test_lexer() {
    impl<'a> Consumer<Token<'a>> for Vec<Token<'static>> {
        fn accept(&mut self, token: Token<'a>) {
            assert_eq!(self.remove(0), token);
        }
    }
    struct TestConsumer;
    impl<'a> LexerConsumer<Vec<Token<'static>>> for TestConsumer {
        fn accept<P>(self, mut lex: P) where P: ParseTo<&'a str,Vec<Token<'static>>> {
            let mut tokens = vec![LParen, Identifier("a123"), Whitespace, Whitespace, Identifier("bcd"), RParen];
            lex.push_to("(a123  bcd)", &mut tokens);
            assert_eq!(tokens, []);
        }
    }
    lexer(TestConsumer);
}
<commit_msg>Added impl of PartialEq<Token<'b>> to Token<'a><commit_after>use parser::combinators::{Parser, StrParser, ParseTo, Consumer, string, character};
use self::Token::{LParen, RParen, Whitespace, Identifier};

#[derive(Copy, Clone, Eq, Hash, Ord, PartialOrd, Debug)]
pub enum Token<'a> {
    LParen,
    RParen,
    Whitespace,
    Identifier(&'a str),
}

impl<'a,'b> PartialEq<Token<'b>> for Token<'a> {
    fn eq(&self, rhs: &Token<'b>) -> bool {
        match (*self, *rhs) {
            (LParen, LParen)                       => true,
            (RParen, RParen)                       => true,
            (Whitespace, Whitespace)               => true,
            (Identifier(ref x), Identifier(ref y)) => x == y,
            _                                      => false
        }
    }
}

pub trait LexerConsumer<D> where D: for<'a> Consumer<Token<'a>> {
    fn accept<L>(self, lexer: L) where L: for<'a> ParseTo<&'a str,D>;
}

fn mk_identifier<'a>(s: &'a str) -> Token<'a> { Identifier(s) }

#[allow(non_snake_case)]
pub fn lexer<C,D>(consumer: C) where C: LexerConsumer<D>, D: for<'a> Consumer<Token<'a>> {
    let LPAREN = string("(").map(|_| LParen);
    let RPAREN = string(")").map(|_| RParen);
    let WHITESPACE = character(char::is_whitespace).map(|_| Whitespace);
    let IDENTIFIER = character(char::is_alphabetic).and_then(character(char::is_alphanumeric).star())
                                                   .buffer().map(mk_identifier);
    let TOKEN = LPAREN.or_else(RPAREN).or_else(WHITESPACE).or_else(IDENTIFIER);
    consumer.accept(TOKEN.star())
}

#[test]
fn test_lexer() {
    impl<'a> Consumer<Token<'a>> for Vec<Token<'static>> {
        fn accept(&mut self, token: Token<'a>) {
            assert_eq!(self.remove(0), token);
        }
    }
    struct TestConsumer;
    impl<'a> LexerConsumer<Vec<Token<'static>>> for TestConsumer {
        fn accept<P>(self, mut lex: P) where P: ParseTo<&'a str,Vec<Token<'static>>> {
            let mut tokens = vec![LParen, Identifier("a123"), Whitespace, Whitespace, Identifier("bcd"), RParen];
            lex.push_to("(a123  bcd)", &mut tokens);
            assert_eq!(tokens, []);
        }
    }
    lexer(TestConsumer);
}

#[test]
fn test_partial_eq() {
    use std::fmt::Debug;
    fn foo<T,U>(lhs: T, rhs: U) where T: Debug+PartialEq<U>, U: Debug{
        assert_eq!(lhs, rhs)
    }
    fn bar<'b,T>(lhs: T, rhs: Token<'b>) where T: Debug+for<'a> PartialEq<Token<'a>> {
        foo(lhs, rhs)
    }
    let hi = String::from("hi");
    bar(Identifier("hi"),Identifier(&*hi));
    bar(Identifier(&*hi),Identifier("hi"));
}
<|endoftext|>