<commit_before>
use gfx;
use gfx::DeviceHelper;
use graphics::BackEnd;
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
varying vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
out vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
"
    GLSL_150: b"
#version 150 core
in vec4 v_Color;
out vec4 o_Color;
void main() {
    o_Color = v_Color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
attribute vec2 uv;
uniform sampler2D s_texture;
varying vec4 v_Color;
varying vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
in vec2 uv;
uniform sampler2D s_texture;
out vec4 v_Color;
out vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
varying vec2 v_UV;
varying vec4 v_Color;
void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * v_Color;
}
"
    GLSL_150: b"
#version 150 core
out vec4 o_Color;
uniform sampler2D s_texture;
in vec2 v_UV;
in vec4 v_Color;
void main()
{
    o_Color = texture(s_texture, v_UV) * v_Color;
}
"
};

static POS_COMPONENTS: uint = 2;
static COLOR_COMPONENTS: uint = 4;
static UV_COMPONENTS: uint = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32, ..2] }

#[vertex_format]
struct ColorFormat { color: [f32, ..4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32, ..2] }

#[allow(unused_imports)]
#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct Gfx2d {
    buffer_pos: gfx::BufferHandle<f32>,
    buffer_color: gfx::BufferHandle<f32>,
    buffer_uv: gfx::BufferHandle<f32>,
    batch: gfx::batch::OwnedBatch<(), ()>,
    batch_uv: OwnedBatchUV,
}

impl Gfx2d {
    /// Creates a new Gfx2d object.
    pub fn new<D: gfx::Device<C>,
               C: gfx::CommandBuffer>(device: &mut D) -> Gfx2d {
        let program = device.link_program(
                VERTEX_SHADER.clone(),
                FRAGMENT_SHADER.clone()
            ).unwrap();
        let program_uv = device.link_program(
                VERTEX_SHADER_UV.clone(),
                FRAGMENT_SHADER_UV.clone()
            ).unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_color = device.create_buffer(
            COLOR_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ));
        mesh.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<ColorFormat>,
            buffer_color.raw()
        ));

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.push_all_move(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ));

        let batch = gfx::batch::OwnedBatch::new(mesh, program, ()).unwrap();

        let sampler = device.create_sampler(
                gfx::tex::SamplerInfo::new(gfx::tex::Trilinear,
                                           gfx::tex::Clamp)
            );

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
                [0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            s_texture: (texture, Some(sampler))
        };

        let batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv).unwrap();

        Gfx2d {
            buffer_pos: buffer_pos,
            buffer_color: buffer_color,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }
}

/// Used for rendering 2D graphics.
pub struct RenderContext<'a, C: 'a + gfx::CommandBuffer> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    gfx2d: &'a mut Gfx2d,
}

impl<'a, C: gfx::CommandBuffer> RenderContext<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               gfx2d: &'a mut Gfx2d) -> RenderContext<'a, C> {
        RenderContext {
            renderer: renderer,
            frame: frame,
            gfx2d: gfx2d,
        }
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for RenderContext<'a, C> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        let &RenderContext {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: [r, g, b, a],
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::Color,
                frame
            );
    }

    fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::{Normal, Inverse, Factor};

        self.gfx2d.batch.state.blend = Some(gfx::state::Blend {
                value: [1.0, 1.0, 1.0, 1.0],
                color: gfx::state::BlendChannel {
                        equation: gfx::state::FuncAdd,
                        source: Factor(Normal, gfx::state::SourceAlpha),
                        destination: Factor(Inverse, gfx::state::SourceAlpha)
                    },
                alpha: Default::default()
            })
    }

    fn disable_alpha_blend(&mut self) {
        self.gfx2d.batch.state.blend = None;
    }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let &RenderContext {
            ref mut renderer,
            ref frame,
            gfx2d: &Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut batch,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch.slice = gfx::VertexSlice(gfx::TriangleList, 0, n as u32);
        renderer.draw(&*batch, *frame);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let ParamsUV {
            s_texture: (ref mut s_texture, _)
        } = self.gfx2d.batch_uv.param;
        *s_texture = texture.handle;
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        let &RenderContext {
            ref mut renderer,
            ref frame,
            gfx2d: &Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        assert_eq!(
            vertices.len() * UV_COMPONENTS,
            texture_coords.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);
        renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch_uv.slice = gfx::VertexSlice(gfx::TriangleList, 0, n as u32);
        renderer.draw(&*batch_uv, *frame);
    }
}
<commit_msg>Upgraded to latest Gfx + Rust<commit_after>
use gfx;
use gfx::DeviceHelper;
use graphics::BackEnd;
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
varying vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
out vec4 v_Color;
void main() {
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
varying vec4 v_Color;
void main() {
    gl_FragColor = v_Color;
}
"
    GLSL_150: b"
#version 150 core
in vec4 v_Color;
out vec4 o_Color;
void main() {
    o_Color = v_Color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
attribute vec2 pos;
attribute vec4 color;
attribute vec2 uv;
uniform sampler2D s_texture;
varying vec4 v_Color;
varying vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
in vec2 pos;
in vec4 color;
in vec2 uv;
uniform sampler2D s_texture;
out vec4 v_Color;
out vec2 v_UV;
void main() {
    v_UV = uv;
    v_Color = color;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
varying vec2 v_UV;
varying vec4 v_Color;
void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * v_Color;
}
"
    GLSL_150: b"
#version 150 core
out vec4 o_Color;
uniform sampler2D s_texture;
in vec2 v_UV;
in vec4 v_Color;
void main()
{
    o_Color = texture(s_texture, v_UV) * v_Color;
}
"
};

static POS_COMPONENTS: uint = 2;
static COLOR_COMPONENTS: uint = 4;
static UV_COMPONENTS: uint = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32, ..2] }

#[vertex_format]
struct ColorFormat { color: [f32, ..4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32, ..2] }

#[allow(unused_imports)]
#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct Gfx2d {
    buffer_pos: gfx::BufferHandle<f32>,
    buffer_color: gfx::BufferHandle<f32>,
    buffer_uv: gfx::BufferHandle<f32>,
    batch: gfx::batch::OwnedBatch<(), ()>,
    batch_uv: OwnedBatchUV,
}

impl Gfx2d {
    /// Creates a new Gfx2d object.
    pub fn new<D: gfx::Device<C>,
               C: gfx::CommandBuffer>(device: &mut D) -> Gfx2d {
        let program = device.link_program(
                VERTEX_SHADER.clone(),
                FRAGMENT_SHADER.clone()
            ).unwrap();
        let program_uv = device.link_program(
                VERTEX_SHADER_UV.clone(),
                FRAGMENT_SHADER_UV.clone()
            ).unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_color = device.create_buffer(
            COLOR_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ).into_iter());
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<ColorFormat>,
            buffer_color.raw()
        ).into_iter());

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.extend(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ).into_iter());

        let batch = gfx::batch::OwnedBatch::new(mesh, program, ()).unwrap();

        let sampler = device.create_sampler(
                gfx::tex::SamplerInfo::new(gfx::tex::Trilinear,
                                           gfx::tex::Clamp)
            );

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
                [0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            s_texture: (texture, Some(sampler))
        };

        let batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv).unwrap();

        Gfx2d {
            buffer_pos: buffer_pos,
            buffer_color: buffer_color,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }
}

/// Used for rendering 2D graphics.
pub struct RenderContext<'a, C: 'a + gfx::CommandBuffer> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    gfx2d: &'a mut Gfx2d,
}

impl<'a, C: gfx::CommandBuffer> RenderContext<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               gfx2d: &'a mut Gfx2d) -> RenderContext<'a, C> {
        RenderContext {
            renderer: renderer,
            frame: frame,
            gfx2d: gfx2d,
        }
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for RenderContext<'a, C> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        let &RenderContext {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: [r, g, b, a],
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::Color,
                frame
            );
    }

    fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::{Normal, Inverse, Factor};

        self.gfx2d.batch.state.blend = Some(gfx::state::Blend {
                value: [1.0, 1.0, 1.0, 1.0],
                color: gfx::state::BlendChannel {
                        equation: gfx::state::FuncAdd,
                        source: Factor(Normal, gfx::state::SourceAlpha),
                        destination: Factor(Inverse, gfx::state::SourceAlpha)
                    },
                alpha: Default::default()
            })
    }

    fn disable_alpha_blend(&mut self) {
        self.gfx2d.batch.state.blend = None;
    }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        let &RenderContext {
            ref mut renderer,
            ref frame,
            gfx2d: &Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut batch,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch.slice = gfx::VertexSlice(gfx::TriangleList, 0, n as u32);
        renderer.draw(batch, *frame);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let ParamsUV {
            s_texture: (ref mut s_texture, _)
        } = self.gfx2d.batch_uv.param;
        *s_texture = texture.handle;
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        let &RenderContext {
            ref mut renderer,
            ref frame,
            gfx2d: &Gfx2d {
                ref mut buffer_pos,
                ref mut buffer_color,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * COLOR_COMPONENTS,
            colors.len() * POS_COMPONENTS
        );
        assert_eq!(
            vertices.len() * UV_COMPONENTS,
            texture_coords.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_color, colors, 0);
        renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch_uv.slice = gfx::VertexSlice(gfx::TriangleList, 0, n as u32);
        renderer.draw(batch_uv, *frame);
    }
}
<|endoftext|>


<commit_before>//! Incremental BLOB I/O.
//!
//! Note that SQLite does not provide API-level access to change the size of a BLOB; that must
//! be performed through SQL statements.
//!
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`, so it plays
//! nicely with other types that build on these (such as `std::io::BufReader` and
//! `std::io::BufWriter`). However, you must be careful with the size of the blob. For example,
//! when using a `BufWriter`, the `BufWriter` will accept more data than the `Blob` will allow,
//! so make sure to call `flush` and check for errors. (See the unit tests in this module for
//! an example.)
//!
//! ## Example
//!
//! ```rust
//! extern crate libsqlite3_sys;
//! extern crate rusqlite;
//!
//! use rusqlite::{Connection, DatabaseName};
//! use std::io::{Read, Write, Seek, SeekFrom};
//!
//! fn main() {
//!     let db = Connection::open_in_memory().unwrap();
//!     db.execute_batch("CREATE TABLE test (content BLOB);").unwrap();
//!     db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(10))", &[]).unwrap();
//!
//!     let rowid = db.last_insert_rowid();
//!     let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
//!
//!     // Make sure to test that the number of bytes written matches what you expect;
//!     // if you try to write too much, the data will be truncated to the size of the BLOB.
//!     let bytes_written = blob.write(b"01234567").unwrap();
//!     assert_eq!(bytes_written, 8);
//!
//!     // Same guidance - make sure you check the number of bytes read!
//!     blob.seek(SeekFrom::Start(0)).unwrap();
//!     let mut buf = [0u8; 20];
//!     let bytes_read = blob.read(&mut buf[..]).unwrap();
//!     assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
//!
//!     db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(64))", &[]).unwrap();
//!
//!     // given a new row ID, we can reopen the blob on that row
//!     let rowid = db.last_insert_rowid();
//!     blob.reopen(rowid).unwrap();
//!
//!     assert_eq!(blob.size(), 64);
//! }
//! ```
use std::io;
use std::cmp::min;
use std::mem;
use std::ptr;

use super::ffi;
use {Result, Connection, DatabaseName};

/// Handle to an open BLOB.
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

impl Connection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string
    /// or if the underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self,
                         db: DatabaseName,
                         table: &str,
                         column: &str,
                         row: i64,
                         read_only: bool)
                         -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(db.to_cstring());
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe {
            ffi::sqlite3_blob_open(c.db(),
                                   db.as_ptr(),
                                   table.as_ptr(),
                                   column.as_ptr(),
                                   row,
                                   if read_only {
                                       0
                                   } else {
                                       1
                                   },
                                   &mut blob)
        };
        c.decode_result(rc).map(|_| {
            Blob {
                conn: self,
                blob: blob,
                pos: 0,
            }
        })
    }
}

impl<'conn> Blob<'conn> {
    /// Move a BLOB handle to a new row.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB.
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Close a BLOB handle.
    ///
    /// Calling `close` explicitly is not required (the BLOB will be closed when the
    /// `Blob` is dropped), but it is available so you can get any errors that occur.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl<'conn> io::Read for Blob<'conn> {
    /// Read data from a BLOB incrementally. Will return Ok(0) if the end of the blob
    /// has been reached.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

impl<'conn> io::Write for Blob<'conn> {
    /// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of the blob
    /// has been reached.
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase
    /// the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite write call fails.
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl<'conn> io::Seek for Blob<'conn> {
    /// Seek to an offset, in bytes, in BLOB.
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        let pos = match pos {
            io::SeekFrom::Start(offset) => offset as i64,
            io::SeekFrom::Current(offset) => self.pos as i64 + offset,
            io::SeekFrom::End(offset) => self.size() as i64 + offset,
        };

        if pos < 0 {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "invalid seek to negative position"))
        } else if pos > self.size() as i64 {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "invalid seek to position past end of blob"))
        } else {
            self.pos = pos as i32;
            Ok(pos as u64)
        }
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for Blob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use std::io::{BufReader, BufRead, BufWriter, Read, Write, Seek, SeekFrom};
    use {Connection, DatabaseName, Result};

    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn db_with_test_blob() -> Result<(Connection, i64)> {
        let db = try!(Connection::open_in_memory());
        let sql = "BEGIN;
                   CREATE TABLE test (content BLOB);
                   INSERT INTO test VALUES (ZEROBLOB(10));
                   END;";
        try!(db.execute_batch(sql));
        let rowid = db.last_insert_rowid();
        Ok((db, rowid))
    }

    #[test]
    fn test_blob() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(4, blob.write(b"Clob").unwrap());
        assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10
        assert_eq!(0, blob.write(b"5678").unwrap());         // still cannot write past 10

        blob.reopen(rowid).unwrap();
        blob.close().unwrap();

        blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"67890");
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        blob.seek(SeekFrom::Start(2)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"ob567");

        // only first 4 bytes of `bytes` should be read into
        blob.seek(SeekFrom::Current(-1)).unwrap();
        assert_eq!(4, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"78907");

        blob.seek(SeekFrom::End(-6)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"56789");

        blob.reopen(rowid).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");

        // should not be able to seek negative or past end
        assert!(blob.seek(SeekFrom::Current(-20)).is_err());
        assert!(blob.seek(SeekFrom::End(0)).is_ok());
        assert!(blob.seek(SeekFrom::Current(1)).is_err());

        // write_all should detect when we return Ok(0) because there is no space left,
        // and return a write error
        blob.reopen(rowid).unwrap();
        assert!(blob.write_all(b"0123456789x").is_err());
    }

    #[test]
    fn test_blob_in_bufreader() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(8, blob.write(b"one\ntwo\n").unwrap());

        blob.reopen(rowid).unwrap();
        let mut reader = BufReader::new(blob);

        let mut line = String::new();
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("one\n", line);

        line.truncate(0);
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("two\n", line);

        line.truncate(0);
        assert_eq!(2, reader.read_line(&mut line).unwrap());
        assert_eq!("\0\0", line);
    }

    #[test]
    fn test_blob_in_bufwriter() {
        let (db, rowid) = db_with_test_blob().unwrap();

        {
            let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write too much and then flush should fail
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"0123456701", &bytes);
        }

        {
            let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write_all too much should fail
            writer.write_all(b"aaaaaaaaaabbbbb").unwrap();
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"aaaaaaaaaa", &bytes);
        }
    }
}
<commit_msg>Add comment to write recommending write_all.<commit_after>//! Incremental BLOB I/O.
//!
//! Note that SQLite does not provide API-level access to change the size of a BLOB; that must
//! be performed through SQL statements.
//!
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`, so it plays
//! nicely with other types that build on these (such as `std::io::BufReader` and
//! `std::io::BufWriter`). However, you must be careful with the size of the blob. For example,
//! when using a `BufWriter`, the `BufWriter` will accept more data than the `Blob` will allow,
//! so make sure to call `flush` and check for errors. (See the unit tests in this module for
//! an example.)
//!
//! ## Example
//!
//! ```rust
//! extern crate libsqlite3_sys;
//! extern crate rusqlite;
//!
//! use rusqlite::{Connection, DatabaseName};
//! use std::io::{Read, Write, Seek, SeekFrom};
//!
//! fn main() {
//!     let db = Connection::open_in_memory().unwrap();
//!     db.execute_batch("CREATE TABLE test (content BLOB);").unwrap();
//!     db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(10))", &[]).unwrap();
//!
//!     let rowid = db.last_insert_rowid();
//!     let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
//!
//!     // Make sure to test that the number of bytes written matches what you expect;
//!     // if you try to write too much, the data will be truncated to the size of the BLOB.
//!     let bytes_written = blob.write(b"01234567").unwrap();
//!     assert_eq!(bytes_written, 8);
//!
//!     // Same guidance - make sure you check the number of bytes read!
//!     blob.seek(SeekFrom::Start(0)).unwrap();
//!     let mut buf = [0u8; 20];
//!     let bytes_read = blob.read(&mut buf[..]).unwrap();
//!     assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
//!
//!     db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(64))", &[]).unwrap();
//!
//!     // given a new row ID, we can reopen the blob on that row
//!     let rowid = db.last_insert_rowid();
//!     blob.reopen(rowid).unwrap();
//!
//!     assert_eq!(blob.size(), 64);
//! }
//! ```
use std::io;
use std::cmp::min;
use std::mem;
use std::ptr;

use super::ffi;
use {Result, Connection, DatabaseName};

/// Handle to an open BLOB.
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

impl Connection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string
    /// or if the underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self,
                         db: DatabaseName,
                         table: &str,
                         column: &str,
                         row: i64,
                         read_only: bool)
                         -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(db.to_cstring());
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe {
            ffi::sqlite3_blob_open(c.db(),
                                   db.as_ptr(),
                                   table.as_ptr(),
                                   column.as_ptr(),
                                   row,
                                   if read_only {
                                       0
                                   } else {
                                       1
                                   },
                                   &mut blob)
        };
        c.decode_result(rc).map(|_| {
            Blob {
                conn: self,
                blob: blob,
                pos: 0,
            }
        })
    }
}

impl<'conn> Blob<'conn> {
    /// Move a BLOB handle to a new row.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB.
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Close a BLOB handle.
    ///
    /// Calling `close` explicitly is not required (the BLOB will be closed when the
    /// `Blob` is dropped), but it is available so you can get any errors that occur.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl<'conn> io::Read for Blob<'conn> {
    /// Read data from a BLOB incrementally. Will return Ok(0) if the end of the blob
    /// has been reached.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

impl<'conn> io::Write for Blob<'conn> {
    /// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of the blob
    /// has been reached; consider using `Write::write_all(buf)` if you want to get an
    /// error if the entirety of the buffer cannot be written.
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase
    /// the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite write call fails.
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl<'conn> io::Seek for Blob<'conn> {
    /// Seek to an offset, in bytes, in BLOB.
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        let pos = match pos {
            io::SeekFrom::Start(offset) => offset as i64,
            io::SeekFrom::Current(offset) => self.pos as i64 + offset,
            io::SeekFrom::End(offset) => self.size() as i64 + offset,
        };

        if pos < 0 {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "invalid seek to negative position"))
        } else if pos > self.size() as i64 {
            Err(io::Error::new(io::ErrorKind::InvalidInput,
                               "invalid seek to position past end of blob"))
        } else {
            self.pos = pos as i32;
            Ok(pos as u64)
        }
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for Blob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use std::io::{BufReader, BufRead, BufWriter, Read, Write, Seek, SeekFrom};
    use {Connection, DatabaseName, Result};

    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn db_with_test_blob() -> Result<(Connection, i64)> {
        let db = try!(Connection::open_in_memory());
        let sql = "BEGIN;
                   CREATE TABLE test (content BLOB);
                   INSERT INTO test VALUES (ZEROBLOB(10));
                   END;";
        try!(db.execute_batch(sql));
        let rowid = db.last_insert_rowid();
        Ok((db, rowid))
    }

    #[test]
    fn test_blob() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(4, blob.write(b"Clob").unwrap());
        assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10
        assert_eq!(0, blob.write(b"5678").unwrap());         // still cannot write past 10

        blob.reopen(rowid).unwrap();
        blob.close().unwrap();

        blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"67890");
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        blob.seek(SeekFrom::Start(2)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"ob567");

        // only first 4 bytes of `bytes` should be read into
        blob.seek(SeekFrom::Current(-1)).unwrap();
        assert_eq!(4, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"78907");

        blob.seek(SeekFrom::End(-6)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"56789");

        blob.reopen(rowid).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");

        // should not be able to seek negative or past end
        assert!(blob.seek(SeekFrom::Current(-20)).is_err());
        assert!(blob.seek(SeekFrom::End(0)).is_ok());
        assert!(blob.seek(SeekFrom::Current(1)).is_err());

        // write_all should detect when we return Ok(0) because there is no space left,
        // and return a write error
        blob.reopen(rowid).unwrap();
        assert!(blob.write_all(b"0123456789x").is_err());
    }

    #[test]
    fn test_blob_in_bufreader() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        assert_eq!(8, blob.write(b"one\ntwo\n").unwrap());

        blob.reopen(rowid).unwrap();
        let mut reader = BufReader::new(blob);

        let mut line = String::new();
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("one\n", line);

        line.truncate(0);
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("two\n", line);

        line.truncate(0);
        assert_eq!(2, reader.read_line(&mut line).unwrap());
        assert_eq!("\0\0", line);
    }

    #[test]
    fn test_blob_in_bufwriter() {
        let (db, rowid) = db_with_test_blob().unwrap();

        {
            let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write too much and then flush should fail
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"0123456701", &bytes);
        }

        {
            let blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write_all too much should fail
            writer.write_all(b"aaaaaaaaaabbbbb").unwrap();
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"aaaaaaaaaa", &bytes);
        }
    }
}
<|endoftext|>


<commit_before>use hb;
use std::os::raw::c_void;

use std;
use std::marker::PhantomData;

use std::fmt;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::ptr::NonNull;

use common::{HarfbuzzObject, Owned, Shared};

/// A `Blob` manages raw data like e.g. file contents. It refers to a slice of
/// bytes that can be either owned by the `Blob` or not.
///
/// Since it is a simple wrapper for `hb_blob_t` it can be used to construct
/// `Font`s and `Face`s directly from memory.
///
/// To enable shared usage of its data it uses a reference counting mechanism
/// making the `clone` operation very cheap as no data is cloned.
///
/// A `Blob` implements `Into` for every type that satisfies the `AsRef<[u8]>'
/// trait such as `Vec<u8>` and `Box<[u8]>` so owned blobs can be created easily
/// from standard Rust objects.
#[repr(C)]
pub struct Blob<'a> {
    raw: NonNull<hb::hb_blob_t>,
    marker: PhantomData<&'a [u8]>,
}
impl<'a> Blob<'a> {
    /// Create a new `Blob` from the slice `bytes`. The blob will not own the
    /// slice's data.
    pub fn with_bytes(bytes: &'a [u8]) -> Owned<Blob<'a>> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_READONLY,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Create a `Blob` from the contents of the file at `path` whose contents
    /// will be read into memory.
    ///
    /// The result will be either a `Blob` that owns the file's contents or an
    /// error that happened while trying to read the file.
    ///
    /// This can be a performance problem if the file is very big. If this turns
    /// out to be a problem consider `mmap`ing the file or splitting it into
    /// smaller chunks before creating a `Blob`.
    pub fn from_file<P: AsRef<Path>>(path: P) -> std::io::Result<Shared<Blob<'static>>> {
        let mut file = File::open(path)?;
        let mut vec = Vec::new();
        file.read_to_end(&mut vec)?;
        Ok(vec.into())
    }

    /// Create a new mutable `Blob` from a slice of bytes.
    pub fn with_mut_bytes(bytes: &mut [u8]) -> Owned<Blob> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_WRITABLE,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Get a slice of the `Blob`'s bytes.
    pub fn get_data(&self) -> &[u8] {
        unsafe {
            let mut length = hb::hb_blob_get_length(self.as_raw());
            let data_ptr = hb::hb_blob_get_data(self.as_raw(), &mut length as *mut _);
            std::slice::from_raw_parts(data_ptr as *const u8, length as usize)
        }
    }

    /// Creates an immutable `Blob` that contains part of the data of the parent
    /// `Blob`. The parent `Blob` will be immutable after this and the sub`Blob`
    /// cannot outlive its parent.
    ///
    /// ### Arguments
    /// * `offset`: Byte-offset of sub-blob within parent.
    /// * `length`: Length of the sub-blob.
    pub fn create_sub_blob(&self, offset: usize, length: usize) -> Shared<Blob<'a>> {
        let blob =
            unsafe { hb::hb_blob_create_sub_blob(self.as_raw(), offset as u32, length as u32) };
        unsafe { Shared::from_raw_owned(blob) }
    }

    /// Returns true if the blob is immutable.
    pub fn is_immutable(&self) -> bool {
        unsafe { hb::hb_blob_is_immutable(self.as_raw()) == 1 }
    }

    /// Makes this blob immutable so the bytes it refers to will never change
    /// during its lifetime.
    pub fn make_immutable(&mut self) {
        unsafe { hb::hb_blob_make_immutable(self.as_raw()) }
    }

    /// Try to get a mutable slice of the `Blob`'s bytes, possibly copying them.
    ///
    /// This returns `None` if the blob is immutable or memory allocation
    /// failed.
    pub fn try_get_mut_data(&mut self) -> Option<&'a mut [u8]> {
        unsafe {
            let mut length = hb::hb_blob_get_length(self.as_raw());
            let data_ptr = hb::hb_blob_get_data_writable(self.as_raw(), &mut length as *mut _);
            if data_ptr.is_null() {
                None
            } else {
                Some(std::slice::from_raw_parts_mut(
                    data_ptr as *mut u8,
                    length as usize,
                ))
            }
        }
    }
}

impl<'a> fmt::Debug for Blob<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Blob")
            .field("data", &self.get_data())
            .finish()
    }
}

unsafe impl<'a> HarfbuzzObject for Blob<'a> {
    type Raw = hb::hb_blob_t;

    unsafe fn from_raw(raw: *const hb::hb_blob_t) -> Self {
        Blob {
            raw: NonNull::new_unchecked(raw as *mut _),
            marker: PhantomData,
        }
    }

    fn as_raw(&self) -> *mut hb::hb_blob_t {
        self.raw.as_ptr()
    }

    unsafe fn reference(&self) {
        hb::hb_blob_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_blob_destroy(self.as_raw());
    }
}

use std::ops::Deref;
impl<'a> Deref for Blob<'a> {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.get_data()
    }
}

use std::convert::AsRef;
impl<'a> AsRef<[u8]> for Blob<'a> {
    fn as_ref(&self) -> &[u8] {
        self.get_data()
    }
}

use std::convert::From;

impl<'a, T> From<T> for Shared<Blob<'a>>
where
    T: 'a + Send + AsRef<[u8]>,
{
    fn from(container: T) -> Shared<Blob<'a>> {
        let len = container.as_ref().len();
        let ptr = container.as_ref().as_ptr();

        let data = Box::into_raw(Box::new(container));

        extern "C" fn destroy<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }

        let hb_blob = unsafe {
            hb::hb_blob_create(
                ptr as *const i8,
                len as u32,
                hb::HB_MEMORY_MODE_READONLY,
                data as *mut _,
                Some(destroy::<T>),
            )
        };
        unsafe { Shared::from_raw_owned(hb_blob) }
    }
}

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

    #[test]
    fn test_vec_to_blob_conversion() {
        let a_vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
        let blob: Shared<Blob> = a_vec.into();

        assert_eq!(blob.len(), 11);

        let mut counter: u8 = 1;
        for num in blob.iter() {
            assert_eq!(*num, counter);
            counter += 1;
        }
    }

    use std::sync::Arc;
    #[test]
    fn test_arc_to_blob_conversion() {
        let rc_slice: Arc<[u8]> = Arc::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
        let blob: Shared<Blob<'static>> = rc_slice.into();

        assert_eq!(blob.len(), 11);

        let mut counter: u8 = 1;
        for num in blob.iter() {
            assert_eq!(*num, counter);
            counter += 1;
        }
    }
}
<commit_msg>Add constructor for Blob from mutable slice<commit_after>use hb;
use std::os::raw::c_void;

use std;
use std::marker::PhantomData;

use std::fmt;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::ptr::NonNull;

use common::{HarfbuzzObject, Owned, Shared};

/// A `Blob` manages raw data like e.g. file contents. It refers to a slice of
/// bytes that can be either owned by the `Blob` or not.
///
/// Since it is a simple wrapper for `hb_blob_t` it can be used to construct
/// `Font`s and `Face`s directly from memory.
///
/// To enable shared usage of its data it uses a reference counting mechanism
/// making the `clone` operation very cheap as no data is cloned.
///
/// A `Blob` implements `Into` for every type that satisfies the `AsRef<[u8]>'
/// trait such as `Vec<u8>` and `Box<[u8]>` so owned blobs can be created easily
/// from standard Rust objects.
#[repr(C)]
pub struct Blob<'a> {
    raw: NonNull<hb::hb_blob_t>,
    marker: PhantomData<&'a [u8]>,
}
impl<'a> Blob<'a> {
    /// Create a new `Blob` from the slice `bytes`. The blob will not own the
    /// slice's data.
    pub fn with_bytes(bytes: &'a [u8]) -> Owned<Blob<'a>> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_READONLY,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Create a new `Blob` from the mutable slice `bytes`. The blob will not own the
    /// slice's data.
    pub fn with_bytes_mut(bytes: &'a mut [u8]) -> Owned<Blob<'a>> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_WRITABLE,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Create a `Blob` from the contents of the file at `path` whose contents
    /// will be read into memory.
    ///
    /// The result will be either a `Blob` that owns the file's contents or an
    /// error that happened while trying to read the file.
    ///
    /// This can be a performance problem if the file is very big. If this turns
    /// out to be a problem consider `mmap`ing the file or splitting it into
    /// smaller chunks before creating a `Blob`.
    pub fn from_file<P: AsRef<Path>>(path: P) -> std::io::Result<Shared<Blob<'static>>> {
        let mut file = File::open(path)?;
        let mut vec = Vec::new();
        file.read_to_end(&mut vec)?;
        Ok(vec.into())
    }

    /// Create a new mutable `Blob` from a slice of bytes.
    pub fn with_mut_bytes(bytes: &mut [u8]) -> Owned<Blob> {
        let hb_blob = unsafe {
            hb::hb_blob_create(
                bytes.as_ptr() as *const i8,
                bytes.len() as u32,
                hb::HB_MEMORY_MODE_WRITABLE,
                0 as *mut _,
                None,
            )
        };
        unsafe { Owned::from_raw(hb_blob) }
    }

    /// Get a slice of the `Blob`'s bytes.
    pub fn get_data(&self) -> &[u8] {
        unsafe {
            let mut length = hb::hb_blob_get_length(self.as_raw());
            let data_ptr = hb::hb_blob_get_data(self.as_raw(), &mut length as *mut _);
            std::slice::from_raw_parts(data_ptr as *const u8, length as usize)
        }
    }

    /// Creates an immutable `Blob` that contains part of the data of the parent
    /// `Blob`. The parent `Blob` will be immutable after this and the sub`Blob`
    /// cannot outlive its parent.
    ///
    /// ### Arguments
    /// * `offset`: Byte-offset of sub-blob within parent.
    /// * `length`: Length of the sub-blob.
    pub fn create_sub_blob(&self, offset: usize, length: usize) -> Shared<Blob<'a>> {
        let blob =
            unsafe { hb::hb_blob_create_sub_blob(self.as_raw(), offset as u32, length as u32) };
        unsafe { Shared::from_raw_owned(blob) }
    }

    /// Returns true if the blob is immutable.
    pub fn is_immutable(&self) -> bool {
        unsafe { hb::hb_blob_is_immutable(self.as_raw()) == 1 }
    }

    /// Makes this blob immutable so the bytes it refers to will never change
    /// during its lifetime.
    pub fn make_immutable(&mut self) {
        unsafe { hb::hb_blob_make_immutable(self.as_raw()) }
    }

    /// Try to get a mutable slice of the `Blob`'s bytes, possibly copying them.
    ///
    /// This returns `None` if the blob is immutable or memory allocation
    /// failed.
    pub fn try_get_mut_data(&mut self) -> Option<&'a mut [u8]> {
        unsafe {
            let mut length = hb::hb_blob_get_length(self.as_raw());
            let data_ptr = hb::hb_blob_get_data_writable(self.as_raw(), &mut length as *mut _);
            if data_ptr.is_null() {
                None
            } else {
                Some(std::slice::from_raw_parts_mut(
                    data_ptr as *mut u8,
                    length as usize,
                ))
            }
        }
    }
}

impl<'a> fmt::Debug for Blob<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Blob")
            .field("data", &self.get_data())
            .finish()
    }
}

unsafe impl<'a> HarfbuzzObject for Blob<'a> {
    type Raw = hb::hb_blob_t;

    unsafe fn from_raw(raw: *const hb::hb_blob_t) -> Self {
        Blob {
            raw: NonNull::new_unchecked(raw as *mut _),
            marker: PhantomData,
        }
    }

    fn as_raw(&self) -> *mut hb::hb_blob_t {
        self.raw.as_ptr()
    }

    unsafe fn reference(&self) {
        hb::hb_blob_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_blob_destroy(self.as_raw());
    }
}

use std::ops::Deref;
impl<'a> Deref for Blob<'a> {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.get_data()
    }
}

use std::convert::AsRef;
impl<'a> AsRef<[u8]> for Blob<'a> {
    fn as_ref(&self) -> &[u8] {
        self.get_data()
    }
}

use std::convert::From;

impl<'a, T> From<T> for Shared<Blob<'a>>
where
    T: 'a + Send + AsRef<[u8]>,
{
    fn from(container: T) -> Shared<Blob<'a>> {
        let len = container.as_ref().len();
        let ptr = container.as_ref().as_ptr();

        let data = Box::into_raw(Box::new(container));

        extern "C" fn destroy<U>(ptr: *mut c_void) {
            unsafe { Box::from_raw(ptr as *mut U) };
        }

        let hb_blob = unsafe {
            hb::hb_blob_create(
                ptr as *const i8,
                len as u32,
                hb::HB_MEMORY_MODE_READONLY,
                data as *mut _,
                Some(destroy::<T>),
            )
        };
        unsafe { Shared::from_raw_owned(hb_blob) }
    }
}

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

    #[test]
    fn test_vec_to_blob_conversion() {
        let a_vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
        let blob: Shared<Blob> = a_vec.into();

        assert_eq!(blob.len(), 11);

        let mut counter: u8 = 1;
        for num in blob.iter() {
            assert_eq!(*num, counter);
            counter += 1;
        }
    }

    use std::sync::Arc;
    #[test]
    fn test_arc_to_blob_conversion() {
        let rc_slice: Arc<[u8]> = Arc::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
        let blob: Shared<Blob<'static>> = rc_slice.into();

        assert_eq!(blob.len(), 11);

        let mut counter: u8 = 1;
        for num in blob.iter() {
            assert_eq!(*num, counter);
            counter += 1;
        }
    }
}
<|endoftext|>


<commit_before>use conrod::{color, Color};

pub const I: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:2, color: CYAN}, Block{x:1, y:2, color: CYAN}, Block{x:2, y:2, color: CYAN}, Block{x:3, y:2, color: CYAN}],
        [Block{x:2, y:0, color: CYAN}, Block{x:2, y:1, color: CYAN}, Block{x:2, y:2, color: CYAN}, Block{x:2, y:3, color: CYAN}],
        [Block{x:0, y:1, color: CYAN}, Block{x:1, y:1, color: CYAN}, Block{x:2, y:1, color: CYAN}, Block{x:3, y:1, color: CYAN}],
        [Block{x:1, y:0, color: CYAN}, Block{x:1, y:1, color: CYAN}, Block{x:1, y:2, color: CYAN}, Block{x:1, y:3, color: CYAN}]
    ]
};
pub const J: Tetromino = Tetromino {
    configurations: [
        [Block{x:1, y:3, color: BLUE}, Block{x:1, y:2, color: BLUE}, Block{x:1, y:1, color: BLUE}, Block{x:0, y:1, color: BLUE}],
        [Block{x:0, y:3, color: BLUE}, Block{x:0, y:2, color: BLUE}, Block{x:1, y:2, color: BLUE}, Block{x:2, y:2, color: BLUE}],
        [Block{x:1, y:3, color: BLUE}, Block{x:1, y:2, color: BLUE}, Block{x:1, y:1, color: BLUE}, Block{x:2, y:3, color: BLUE}],
        [Block{x:0, y:2, color: BLUE}, Block{x:1, y:2, color: BLUE}, Block{x:2, y:2, color: BLUE}, Block{x:2, y:1, color: BLUE}]
    ]
};
pub const L: Tetromino = Tetromino {
    configurations: [
        [Block{x:1, y:3, color: ORANGE}, Block{x:1, y:2, color: ORANGE}, Block{x:1, y:1, color: ORANGE}, Block{x:2, y:1, color: ORANGE}],
        [Block{x:0, y:1, color: ORANGE}, Block{x:0, y:2, color: ORANGE}, Block{x:1, y:2, color: ORANGE}, Block{x:2, y:2, color: ORANGE}],
        [Block{x:0, y:3, color: ORANGE}, Block{x:1, y:3, color: ORANGE}, Block{x:1, y:2, color: ORANGE}, Block{x:1, y:1, color: ORANGE}],
        [Block{x:0, y:2, color: ORANGE}, Block{x:1, y:2, color: ORANGE}, Block{x:2, y:2, color: ORANGE}, Block{x:2, y:3, color: ORANGE}]
    ]
};
pub const O: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:3, color: YELLOW}, Block{x:0, y:2, color: YELLOW}, Block{x:1, y:3, color: YELLOW}, Block{x:1, y:2, color: YELLOW}],
        [Block{x:0, y:3, color: YELLOW}, Block{x:0, y:2, color: YELLOW}, Block{x:1, y:3, color: YELLOW}, Block{x:1, y:2, color: YELLOW}],
        [Block{x:0, y:3, color: YELLOW}, Block{x:0, y:2, color: YELLOW}, Block{x:1, y:3, color: YELLOW}, Block{x:1, y:2, color: YELLOW}],
        [Block{x:0, y:3, color: YELLOW}, Block{x:0, y:2, color: YELLOW}, Block{x:1, y:3, color: YELLOW}, Block{x:1, y:2, color: YELLOW}]
    ]
};
pub const S: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:1, color: LIME}, Block{x:1, y:1, color: LIME}, Block{x:1, y:2, color: LIME}, Block{x:2, y:2, color: LIME}],
        [Block{x:0, y:3, color: LIME}, Block{x:0, y:2, color: LIME}, Block{x:1, y:2, color: LIME}, Block{x:1, y:1, color: LIME}],
        [Block{x:0, y:2, color: LIME}, Block{x:1, y:2, color: LIME}, Block{x:1, y:3, color: LIME}, Block{x:2, y:3, color: LIME}],
        [Block{x:1, y:3, color: LIME}, Block{x:1, y:2, color: LIME}, Block{x:2, y:2, color: LIME}, Block{x:2, y:1, color: LIME}]
    ]
};
pub const T: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:2, color: PURPLE}, Block{x:1, y:2, color: PURPLE}, Block{x:1, y:1, color: PURPLE}, Block{x:2, y:2, color: PURPLE}],
        [Block{x:0, y:2, color: PURPLE}, Block{x:1, y:3, color: PURPLE}, Block{x:1, y:2, color: PURPLE}, Block{x:1, y:1, color: PURPLE}],
        [Block{x:0, y:2, color: PURPLE}, Block{x:1, y:3, color: PURPLE}, Block{x:1, y:2, color: PURPLE}, Block{x:2, y:2, color: PURPLE}],
        [Block{x:1, y:3, color: PURPLE}, Block{x:1, y:2, color: PURPLE}, Block{x:1, y:1, color: PURPLE}, Block{x:2, y:2, color: PURPLE}]
    ]
};
pub const Z: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:2, color: RED}, Block{x:1, y:2, color: RED}, Block{x:1, y:1, color: RED}, Block{x:2, y:1, color: RED}],
        [Block{x:0, y:2, color: RED}, Block{x:0, y:1, color: RED}, Block{x:1, y:2, color: RED}, Block{x:1, y:3, color: RED}],
        [Block{x:0, y:3, color: RED}, Block{x:1, y:3, color: RED}, Block{x:1, y:2, color: RED}, Block{x:2, y:2, color: RED}],
        [Block{x:1, y:1, color: RED}, Block{x:1, y:2, color: RED}, Block{x:2, y:2, color: RED}, Block{x:2, y:3, color: RED}]
    ]
};

// Tetromino colors
const CYAN: Color = Color::Rgba(0x00 as f32, 0xFF as f32, 0xff as f32, 1.0);
const BLUE: Color = color::BLUE;
const ORANGE: Color = color::ORANGE;
const YELLOW: Color = color::YELLOW;
const LIME: Color = Color::Rgba(0x80 as f32, 0xFF as f32, 0x00 as f32, 1.0);
const PURPLE: Color = color::PURPLE;
const RED: Color = color::RED;

pub struct Piece {
    x: u32,
    y: u32,
    ptype: Tetromino,
    rotation: Rotation
}
impl Piece {
    fn get_blocks(&self) -> &Configuration {
        self.ptype.get_configuration(&self.rotation)
    }
    fn rotate(&mut self) {
        let new_rotation = match self.rotation {
            Rotation::R0 => Rotation::R1,
            Rotation::R1 => Rotation::R2,
            Rotation::R2 => Rotation::R3,
            Rotation::R3 => Rotation::R0
        };
	    self.rotation = new_rotation;
    }
}

enum Rotation {
    R0, R1, R2, R3
}

#[derive(Debug)]
pub struct Tetromino {
    configurations: [Configuration; 4]
}
impl Tetromino {
    fn get_configuration(&self, rotation: &Rotation) -> &Configuration {
        let index = match *rotation {
            Rotation::R0 => 0,
            Rotation::R1 => 1,
            Rotation::R2 => 2,
            Rotation::R3 => 3
        };
        &self.configurations[index]
    }
}

type Configuration = [Block; 4];

// Store the x and y position relative to local coordinates
#[derive(Debug)]
pub struct Block {
    x: u8,
    y: u8,
    color: Color
}
<commit_msg>added a test for rotate as well as started the transition to dealing with Position structs rather than x and y separately<commit_after>use conrod::{color, Color};

// TODO: look into having a make-block! macro for when this inevitably needs to change
pub const I: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:2, color: CYAN}, Block{x:1, y:2, color: CYAN}, Block{x:2, y:2, color: CYAN}, Block{x:3, y:2, color: CYAN}],
        [Block{x:2, y:0, color: CYAN}, Block{x:2, y:1, color: CYAN}, Block{x:2, y:2, color: CYAN}, Block{x:2, y:3, color: CYAN}],
        [Block{x:0, y:1, color: CYAN}, Block{x:1, y:1, color: CYAN}, Block{x:2, y:1, color: CYAN}, Block{x:3, y:1, color: CYAN}],
        [Block{x:1, y:0, color: CYAN}, Block{x:1, y:1, color: CYAN}, Block{x:1, y:2, color: CYAN}, Block{x:1, y:3, color: CYAN}]
    ]
};
pub const J: Tetromino = Tetromino {
    configurations: [
        [Block{x:1, y:3, color: BLUE}, Block{x:1, y:2, color: BLUE}, Block{x:1, y:1, color: BLUE}, Block{x:0, y:1, color: BLUE}],
        [Block{x:0, y:3, color: BLUE}, Block{x:0, y:2, color: BLUE}, Block{x:1, y:2, color: BLUE}, Block{x:2, y:2, color: BLUE}],
        [Block{x:1, y:3, color: BLUE}, Block{x:1, y:2, color: BLUE}, Block{x:1, y:1, color: BLUE}, Block{x:2, y:3, color: BLUE}],
        [Block{x:0, y:2, color: BLUE}, Block{x:1, y:2, color: BLUE}, Block{x:2, y:2, color: BLUE}, Block{x:2, y:1, color: BLUE}]
    ]
};
pub const L: Tetromino = Tetromino {
    configurations: [
        [Block{x:1, y:3, color: ORANGE}, Block{x:1, y:2, color: ORANGE}, Block{x:1, y:1, color: ORANGE}, Block{x:2, y:1, color: ORANGE}],
        [Block{x:0, y:1, color: ORANGE}, Block{x:0, y:2, color: ORANGE}, Block{x:1, y:2, color: ORANGE}, Block{x:2, y:2, color: ORANGE}],
        [Block{x:0, y:3, color: ORANGE}, Block{x:1, y:3, color: ORANGE}, Block{x:1, y:2, color: ORANGE}, Block{x:1, y:1, color: ORANGE}],
        [Block{x:0, y:2, color: ORANGE}, Block{x:1, y:2, color: ORANGE}, Block{x:2, y:2, color: ORANGE}, Block{x:2, y:3, color: ORANGE}]
    ]
};
pub const O: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:3, color: YELLOW}, Block{x:0, y:2, color: YELLOW}, Block{x:1, y:3, color: YELLOW}, Block{x:1, y:2, color: YELLOW}],
        [Block{x:0, y:3, color: YELLOW}, Block{x:0, y:2, color: YELLOW}, Block{x:1, y:3, color: YELLOW}, Block{x:1, y:2, color: YELLOW}],
        [Block{x:0, y:3, color: YELLOW}, Block{x:0, y:2, color: YELLOW}, Block{x:1, y:3, color: YELLOW}, Block{x:1, y:2, color: YELLOW}],
        [Block{x:0, y:3, color: YELLOW}, Block{x:0, y:2, color: YELLOW}, Block{x:1, y:3, color: YELLOW}, Block{x:1, y:2, color: YELLOW}]
    ]
};
pub const S: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:1, color: LIME}, Block{x:1, y:1, color: LIME}, Block{x:1, y:2, color: LIME}, Block{x:2, y:2, color: LIME}],
        [Block{x:0, y:3, color: LIME}, Block{x:0, y:2, color: LIME}, Block{x:1, y:2, color: LIME}, Block{x:1, y:1, color: LIME}],
        [Block{x:0, y:2, color: LIME}, Block{x:1, y:2, color: LIME}, Block{x:1, y:3, color: LIME}, Block{x:2, y:3, color: LIME}],
        [Block{x:1, y:3, color: LIME}, Block{x:1, y:2, color: LIME}, Block{x:2, y:2, color: LIME}, Block{x:2, y:1, color: LIME}]
    ]
};
pub const T: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:2, color: PURPLE}, Block{x:1, y:2, color: PURPLE}, Block{x:1, y:1, color: PURPLE}, Block{x:2, y:2, color: PURPLE}],
        [Block{x:0, y:2, color: PURPLE}, Block{x:1, y:3, color: PURPLE}, Block{x:1, y:2, color: PURPLE}, Block{x:1, y:1, color: PURPLE}],
        [Block{x:0, y:2, color: PURPLE}, Block{x:1, y:3, color: PURPLE}, Block{x:1, y:2, color: PURPLE}, Block{x:2, y:2, color: PURPLE}],
        [Block{x:1, y:3, color: PURPLE}, Block{x:1, y:2, color: PURPLE}, Block{x:1, y:1, color: PURPLE}, Block{x:2, y:2, color: PURPLE}]
    ]
};
pub const Z: Tetromino = Tetromino {
    configurations: [
        [Block{x:0, y:2, color: RED}, Block{x:1, y:2, color: RED}, Block{x:1, y:1, color: RED}, Block{x:2, y:1, color: RED}],
        [Block{x:0, y:2, color: RED}, Block{x:0, y:1, color: RED}, Block{x:1, y:2, color: RED}, Block{x:1, y:3, color: RED}],
        [Block{x:0, y:3, color: RED}, Block{x:1, y:3, color: RED}, Block{x:1, y:2, color: RED}, Block{x:2, y:2, color: RED}],
        [Block{x:1, y:1, color: RED}, Block{x:1, y:2, color: RED}, Block{x:2, y:2, color: RED}, Block{x:2, y:3, color: RED}]
    ]
};

// Tetromino colors
pub const CYAN: Color = Color::Rgba(0x00 as f32, 0xFF as f32, 0xff as f32, 1.0);
pub const BLUE: Color = color::BLUE;
pub const ORANGE: Color = color::ORANGE;
pub const YELLOW: Color = color::YELLOW;
pub const LIME: Color = Color::Rgba(0x80 as f32, 0xFF as f32, 0x00 as f32, 1.0);
pub const PURPLE: Color = color::PURPLE;
pub const RED: Color = color::RED;

pub struct Piece {
    // TODO: Replace with position
    x: u8,
    y: u8,
    ptype: Tetromino,
    rotation: Rotation
}
impl Piece {
    fn new(position: Position, ptype: Tetromino, rotation: Rotation) -> Piece {
        Piece {
            x: position.x,
            y: position.y,
            ptype: ptype,
            rotation: rotation
        }
    }
    fn get_blocks(&self) -> &Configuration {
        self.ptype.get_configuration(&self.rotation)
    }
    fn rotate(&mut self) {
        let new_rotation = match self.rotation {
            Rotation::R0 => Rotation::R1,
            Rotation::R1 => Rotation::R2,
            Rotation::R2 => Rotation::R3,
            Rotation::R3 => Rotation::R0
        };
	    self.rotation = new_rotation;
    }
}

#[derive(Debug, PartialEq)]
pub enum Rotation {
    R0, R1, R2, R3
}

#[derive(Debug)]
pub struct Tetromino {
    configurations: [Configuration; 4]
}
impl Tetromino {
    fn get_configuration(&self, rotation: &Rotation) -> &Configuration {
        let index = match *rotation {
            Rotation::R0 => 0,
            Rotation::R1 => 1,
            Rotation::R2 => 2,
            Rotation::R3 => 3
        };
        &self.configurations[index]
    }
}

type Configuration = [Block; 4];

// Store the x and y position relative to local coordinates
#[derive(Debug, PartialEq)]
pub struct Block {
    x: u8,
    y: u8,
    color: Color
}

#[derive(Debug, PartialEq)]
pub struct Position {
    x: u8,
    y: u8
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_piece_rotation() {
        let position = Position{x:0, y:0};
        let mut p = Piece::new(position, I, Rotation::R0);
        p.rotate();
	    assert_eq!(p.rotation, Rotation::R1);
        p.rotate();
	    assert_eq!(p.rotation, Rotation::R2);
        p.rotate();
	    assert_eq!(p.rotation, Rotation::R3);
        p.rotate();
	    assert_eq!(p.rotation, Rotation::R0);
    }
}<|endoftext|>


<commit_before>use event::{Event, Entity, State, SassRule, SassVariable, SassComment, TopLevelEvent};
use std::borrow::Cow::Borrowed;

fn is_ascii_whitespace(c: u8) -> bool {
   is_newline(c) || is_ascii_whitespace_no_nl(c)
}

fn is_ascii_whitespace_no_nl(c: u8) -> bool {
    c == b'\t' || c == 0x0b || c == 0x0c || c == b' '
}

fn is_newline(c: u8) -> bool {
    c == b'\n' || c == b'\r'
}

fn isnt_newline(c: u8) -> bool {
    !is_newline(c)
}

// unusual among "scan" functions in that it scans from the _back_ of the string
// TODO: should also scan unicode whitespace?
fn scan_trailing_whitespace(data: &str) -> usize {
    match data.as_bytes().iter().rev().position(|&c| !is_ascii_whitespace_no_nl(c)) {
        Some(i) => i,
        None => data.len()
    }
}

#[derive(Debug)]
pub struct Tokenizer<'a> {
    sass: &'a str,
    bytes: &'a [u8],
    offset: usize,
    stack: Vec<Entity>,
    state: State,
    sass_rule_stack: Vec<SassRule<'a>>,
    current_sass_rule: SassRule<'a>,
}

impl<'a> Tokenizer<'a> {
    pub fn new(sass: &'a str) -> Tokenizer<'a> {
        Tokenizer {
            sass: &sass,
            bytes: &sass.as_bytes(),
            offset: 0,
            stack: Vec::new(),
            state: State::OutsideRules,
            sass_rule_stack: Vec::new(),
            current_sass_rule: SassRule::new(),
        }
    }

    fn start_something(&mut self) -> Option<TopLevelEvent<'a>> {
        self.current_sass_rule = SassRule::new();

        self.pick_something();
        while self.state != State::OutsideRules {
            let curr_state = self.state.clone();
            match curr_state {
                State::Eof => {
                    return None
                },
                State::InSelectors => {
                    let sel = self.next_selector();
                    println!("next sel = {:?}", sel);
                    if sel.is_some() {
                        self.current_sass_rule.selectors.push(sel.unwrap());
                    }
                },
                State::InProperties => {
                    let prop = self.next_property();
                    if prop.is_some() {
                        self.current_sass_rule.children.push(prop.unwrap());
                    }
                },
                State::EndRule => {
                    println!("in endrule");
                    // consume '}', should probably be checking that's what we actually have
                    self.offset += 1;

                    match self.sass_rule_stack.pop() {
                        Some(ref mut rule) => {
                            rule.children.push(Event::ChildRule(self.current_sass_rule.clone()));
                            self.current_sass_rule = (*rule).clone();
                            self.pick_something();
                        },
                        None => self.state = State::OutsideRules,
                    }
                },
                State::InRule => {
                    self.sass_rule_stack.push(self.current_sass_rule.clone());
                    self.current_sass_rule = SassRule::new();
                    self.pick_something();
                },
                State::InVariable => {
                    let var = self.next_variable();
                    if var.is_some() {
                        return Some(TopLevelEvent::Variable(SassVariable { variable: var.unwrap() }))
                    } else {
                        // is this really what we should be doing here? reachable?
                        self.state = State::Eof;
                    }
                },
                State::InComment => {
                    let comment = self.next_comment();
                    if comment.is_some() {
                        if self.sass_rule_stack.len() == 0 &&
                           self.current_sass_rule.selectors.len() == 0 &&
                           self.current_sass_rule.children.len() == 0 {
                               return Some(TopLevelEvent::Comment(SassComment { comment: comment.unwrap() }))
                        } else {
                            self.current_sass_rule.children.push(comment.unwrap());
                            self.pick_something();
                        }
                    } else {
                        // is this really what we should be doing here? reachable?
                        self.state = State::Eof;
                    }
                }
                unknown_state => {
                    println!("i dont know what to do for {:?}", unknown_state);
                    println!("current sass rule = {:?}", self.current_sass_rule);
                    self.state = State::Eof;
                },
            }
        }
        //
        //     State::OutsideRules => {
        //         println!("picked {:?}", self.state);
        //         return self.start_something();
        //     },
        //     State::InRule => return Some(self.next_rule()),
        //     State::InProperties => return Some(self.next_property()),
        //     State::InVariable => return Some(self.next_variable()),
        //     State::InComment => return Some(self.next_comment()),
        //     State::Eof => return None,
        // }

        Some(TopLevelEvent::Rule(self.current_sass_rule.clone()))
    }

    fn pick_something(&mut self) {
        self.skip_leading_whitespace();

        if self.offset == self.sass.len() {
            self.state = State::Eof;
            println!("picked eof");
            return
        }

        let c = self.bytes[self.offset];

        if c == b'}' {
            self.state = State::EndRule;
            println!("picked endrule");
            return
        }

        if c == b'$' {
            self.state = State::InVariable;
            println!("picked variable");
            return
        }

        if c == b'/' && (self.offset + 1) < self.sass.len() {
            let d = self.bytes[self.offset + 1];
            if d == b'*' {
                self.state = State::InComment;
                println!("picked comment");
                return
            }
        }

        println!("picked selectors");

        self.state = State::InSelectors;
    }

    fn scan_while<F>(&mut self, data: &str, f: F) -> usize
            where F: Fn(u8) -> bool {
        match data.as_bytes().iter().position(|&c| !f(c)) {
            Some(i) => i,
            None => data.len()
        }
    }

    fn skip_leading_whitespace(&mut self) {
        let mut i = self.offset;
        let limit = self.sass.len();

        while i < limit {
            let c = self.bytes[i];
            if is_ascii_whitespace(c) {
                i += self.scan_while(&self.sass[i..self.sass.len()], is_ascii_whitespace);
            } else if c == b'/' && i + 1 < limit && self.bytes[i + 1] == b'/' {
                i += self.scan_while(&self.sass[i..self.sass.len()], isnt_newline);
            } else {
                self.offset = i;
                return
            }
        }
        self.offset = limit;
    }

    fn next_comment(&mut self) -> Option<Event<'a>> {
        let comment_body_beginning = self.offset;
        let mut i = comment_body_beginning + 2;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b'*' ) {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            if self.bytes[i+1] == b'/' {
                self.offset = i + 2;
                return Some(Event::Comment(Borrowed(&self.sass[comment_body_beginning..i + 2])))
            } else {
                i += 1;
            }
        }
        None
    }

    fn next_variable(&mut self) -> Option<Event<'a>> {
        // TODO: can parts of this be deduplicated with properties?
        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b':' ) {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match self.bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                return Some(Event::Variable(
                    Borrowed(&self.sass[name_beginning..name_end]),
                    Borrowed(&self.sass[value_beginning..value_end])
                ))
            }
        }
        self.offset = self.sass.len();
        None
    }

    fn next_property(&mut self) -> Option<Event<'a>> {
        self.skip_leading_whitespace();

        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        let c = self.bytes[i];
        if c == b'}' {
            self.state = State::EndRule;
            return None
        }

        let d = self.bytes[i + 1];
        if c == b'/' && d == b'*' {
            self.state = State::InComment;
            return None
        }

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b':' || c == b'{') {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            // Inefficient since we already skipped the whitespace and we'll have to
            // do it again but oh well
            let c = self.bytes[i];
            if c == b'{' {
                self.state = State::InRule;
                return None
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match self.bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                return Some(Event::Property(
                    Borrowed(&self.sass[name_beginning..name_end]),
                    Borrowed(&self.sass[value_beginning..value_end])
                ))

            }
        }
        self.offset = self.sass.len();
        None
    }

    fn next_selector(&mut self) -> Option<Event<'a>> {
        let beginning = self.offset;
        let mut i = beginning;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b',' || c == b'{' || c == b':') {
                Some(pos) => { i += pos; },
                None => { i = limit; break; },
            }

            let c = self.bytes[i];

            if c == b':' {
                self.state = State::InProperties;
                return None
            }

            if c == b',' || c == b'{' {
                let n = scan_trailing_whitespace(&self.sass[beginning..i]);
                let end = i - n;
                if end > beginning {
                    if c == b'{' {
                        if self.current_sass_rule.selectors_done {
                            self.state = State::InRule;
                            return None
                        } else {
                            self.current_sass_rule.selectors_done = true;
                            self.state = State::InProperties;
                        }
                    }
                    self.offset = i + 1;
                    return Some(Event::Selector(Borrowed(&self.sass[beginning..end])))
                }
            }

            self.offset = i;
            if i > beginning {
                return Some(Event::Selector(Borrowed(&self.sass[beginning..i])))
            }
            i += 1;
        }

        if i > beginning {
            self.offset = i;
            Some(Event::Selector(Borrowed(&self.sass[beginning..i])))
        } else {
            self.state = State::Eof;
            None
        }
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        if self.offset < self.sass.len() {
            return self.start_something()
        }
        None
    }
}
<commit_msg>Remove commented-out code and prints<commit_after>use event::{Event, Entity, State, SassRule, SassVariable, SassComment, TopLevelEvent};
use std::borrow::Cow::Borrowed;

fn is_ascii_whitespace(c: u8) -> bool {
   is_newline(c) || is_ascii_whitespace_no_nl(c)
}

fn is_ascii_whitespace_no_nl(c: u8) -> bool {
    c == b'\t' || c == 0x0b || c == 0x0c || c == b' '
}

fn is_newline(c: u8) -> bool {
    c == b'\n' || c == b'\r'
}

fn isnt_newline(c: u8) -> bool {
    !is_newline(c)
}

// unusual among "scan" functions in that it scans from the _back_ of the string
// TODO: should also scan unicode whitespace?
fn scan_trailing_whitespace(data: &str) -> usize {
    match data.as_bytes().iter().rev().position(|&c| !is_ascii_whitespace_no_nl(c)) {
        Some(i) => i,
        None => data.len()
    }
}

#[derive(Debug)]
pub struct Tokenizer<'a> {
    sass: &'a str,
    bytes: &'a [u8],
    offset: usize,
    stack: Vec<Entity>,
    state: State,
    sass_rule_stack: Vec<SassRule<'a>>,
    current_sass_rule: SassRule<'a>,
}

impl<'a> Tokenizer<'a> {
    pub fn new(sass: &'a str) -> Tokenizer<'a> {
        Tokenizer {
            sass: &sass,
            bytes: &sass.as_bytes(),
            offset: 0,
            stack: Vec::new(),
            state: State::OutsideRules,
            sass_rule_stack: Vec::new(),
            current_sass_rule: SassRule::new(),
        }
    }

    fn start_something(&mut self) -> Option<TopLevelEvent<'a>> {
        self.current_sass_rule = SassRule::new();

        self.pick_something();
        while self.state != State::OutsideRules {
            let curr_state = self.state.clone();
            match curr_state {
                State::Eof => {
                    return None
                },
                State::InSelectors => {
                    let sel = self.next_selector();
                    if sel.is_some() {
                        self.current_sass_rule.selectors.push(sel.unwrap());
                    }
                },
                State::InProperties => {
                    let prop = self.next_property();
                    if prop.is_some() {
                        self.current_sass_rule.children.push(prop.unwrap());
                    }
                },
                State::EndRule => {
                    // consume '}', should probably be checking that's what we actually have
                    self.offset += 1;

                    match self.sass_rule_stack.pop() {
                        Some(ref mut rule) => {
                            rule.children.push(Event::ChildRule(self.current_sass_rule.clone()));
                            self.current_sass_rule = (*rule).clone();
                            self.pick_something();
                        },
                        None => self.state = State::OutsideRules,
                    }
                },
                State::InRule => {
                    self.sass_rule_stack.push(self.current_sass_rule.clone());
                    self.current_sass_rule = SassRule::new();
                    self.pick_something();
                },
                State::InVariable => {
                    let var = self.next_variable();
                    if var.is_some() {
                        return Some(TopLevelEvent::Variable(SassVariable { variable: var.unwrap() }))
                    } else {
                        // is this really what we should be doing here? reachable?
                        self.state = State::Eof;
                    }
                },
                State::InComment => {
                    let comment = self.next_comment();
                    if comment.is_some() {
                        if self.sass_rule_stack.len() == 0 &&
                           self.current_sass_rule.selectors.len() == 0 &&
                           self.current_sass_rule.children.len() == 0 {
                               return Some(TopLevelEvent::Comment(SassComment { comment: comment.unwrap() }))
                        } else {
                            self.current_sass_rule.children.push(comment.unwrap());
                            self.pick_something();
                        }
                    } else {
                        // is this really what we should be doing here? reachable?
                        self.state = State::Eof;
                    }
                }
                unknown_state => {
                    println!("i dont know what to do for {:?}", unknown_state);
                    println!("current sass rule = {:?}", self.current_sass_rule);
                    self.state = State::Eof;
                },
            }
        }

        Some(TopLevelEvent::Rule(self.current_sass_rule.clone()))
    }

    fn pick_something(&mut self) {
        self.skip_leading_whitespace();

        if self.offset == self.sass.len() {
            self.state = State::Eof;
            return
        }

        let c = self.bytes[self.offset];

        if c == b'}' {
            self.state = State::EndRule;
            return
        }

        if c == b'$' {
            self.state = State::InVariable;
            return
        }

        if c == b'/' && (self.offset + 1) < self.sass.len() {
            let d = self.bytes[self.offset + 1];
            if d == b'*' {
                self.state = State::InComment;
                return
            }
        }

        self.state = State::InSelectors;
    }

    fn scan_while<F>(&mut self, data: &str, f: F) -> usize
            where F: Fn(u8) -> bool {
        match data.as_bytes().iter().position(|&c| !f(c)) {
            Some(i) => i,
            None => data.len()
        }
    }

    fn skip_leading_whitespace(&mut self) {
        let mut i = self.offset;
        let limit = self.sass.len();

        while i < limit {
            let c = self.bytes[i];
            if is_ascii_whitespace(c) {
                i += self.scan_while(&self.sass[i..self.sass.len()], is_ascii_whitespace);
            } else if c == b'/' && i + 1 < limit && self.bytes[i + 1] == b'/' {
                i += self.scan_while(&self.sass[i..self.sass.len()], isnt_newline);
            } else {
                self.offset = i;
                return
            }
        }
        self.offset = limit;
    }

    fn next_comment(&mut self) -> Option<Event<'a>> {
        let comment_body_beginning = self.offset;
        let mut i = comment_body_beginning + 2;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b'*' ) {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            if self.bytes[i+1] == b'/' {
                self.offset = i + 2;
                return Some(Event::Comment(Borrowed(&self.sass[comment_body_beginning..i + 2])))
            } else {
                i += 1;
            }
        }
        None
    }

    fn next_variable(&mut self) -> Option<Event<'a>> {
        // TODO: can parts of this be deduplicated with properties?
        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b':' ) {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match self.bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                return Some(Event::Variable(
                    Borrowed(&self.sass[name_beginning..name_end]),
                    Borrowed(&self.sass[value_beginning..value_end])
                ))
            }
        }
        self.offset = self.sass.len();
        None
    }

    fn next_property(&mut self) -> Option<Event<'a>> {
        self.skip_leading_whitespace();

        let name_beginning = self.offset;
        let mut i = name_beginning;
        let limit = self.sass.len();

        let c = self.bytes[i];
        if c == b'}' {
            self.state = State::EndRule;
            return None
        }

        let d = self.bytes[i + 1];
        if c == b'/' && d == b'*' {
            self.state = State::InComment;
            return None
        }

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b':' || c == b'{') {
                Some(pos) => { i += pos; },
                None => { break; },
            }

            // Inefficient since we already skipped the whitespace and we'll have to
            // do it again but oh well
            let c = self.bytes[i];
            if c == b'{' {
                self.state = State::InRule;
                return None
            }

            let name_end = i;

            i += 1;
            self.offset = i;
            self.skip_leading_whitespace();

            let value_beginning = self.offset;
            i = value_beginning;

            while i < limit {
                match self.bytes[i..limit].iter().position(|&c| c == b';') {
                    Some(pos) => { i += pos; },
                    None => { i = limit; break; },
                }

                let value_end = i;
                self.offset = i + 1;

                self.skip_leading_whitespace();

                return Some(Event::Property(
                    Borrowed(&self.sass[name_beginning..name_end]),
                    Borrowed(&self.sass[value_beginning..value_end])
                ))

            }
        }
        self.offset = self.sass.len();
        None
    }

    fn next_selector(&mut self) -> Option<Event<'a>> {
        let beginning = self.offset;
        let mut i = beginning;
        let limit = self.sass.len();

        while i < limit {
            match self.bytes[i..limit].iter().position(|&c| c == b',' || c == b'{' || c == b':') {
                Some(pos) => { i += pos; },
                None => { i = limit; break; },
            }

            let c = self.bytes[i];

            if c == b':' {
                self.state = State::InProperties;
                return None
            }

            if c == b',' || c == b'{' {
                let n = scan_trailing_whitespace(&self.sass[beginning..i]);
                let end = i - n;
                if end > beginning {
                    if c == b'{' {
                        if self.current_sass_rule.selectors_done {
                            self.state = State::InRule;
                            return None
                        } else {
                            self.current_sass_rule.selectors_done = true;
                            self.state = State::InProperties;
                        }
                    }
                    self.offset = i + 1;
                    return Some(Event::Selector(Borrowed(&self.sass[beginning..end])))
                }
            }

            self.offset = i;
            if i > beginning {
                return Some(Event::Selector(Borrowed(&self.sass[beginning..i])))
            }
            i += 1;
        }

        if i > beginning {
            self.offset = i;
            Some(Event::Selector(Borrowed(&self.sass[beginning..i])))
        } else {
            self.state = State::Eof;
            None
        }
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = TopLevelEvent<'a>;

    fn next(&mut self) -> Option<TopLevelEvent<'a>> {
        if self.offset < self.sass.len() {
            return self.start_something()
        }
        None
    }
}
<|endoftext|>