<commit_before>import platform::osmain;
import geom::*;
import comm::*;
import image::base::image;
import dl = layout::display_list;
import azure::*;
import azure::bindgen::*;

enum msg {
    render(dl::display_list),
    exit(comm::chan<()>)
}

#[doc = "
The interface used to by the renderer to aquire draw targets for
each rendered frame and submit them to be drawn to the display
"]
iface sink {
    fn begin_drawing(next_dt: chan<AzDrawTargetRef>);
    fn draw(next_dt: chan<AzDrawTargetRef>, draw_me: AzDrawTargetRef);
}

fn renderer<S: sink send copy>(sink: S) -> chan<msg> {
    task::spawn_listener::<msg> {|po|
        listen {|draw_target_ch|
            #debug("renderer: beginning rendering loop");
            sink.begin_drawing(draw_target_ch);

            loop {
                alt po.recv() {
                  render(display_list) {
                    #debug("renderer: got render request");
                    let draw_target = draw_target_ch.recv();
                    #debug("renderer: rendering");
                    clear(draw_target);
                    draw_display_list(draw_target, display_list);
                    draw_some_text(draw_target);
                    #debug("renderer: returning surface");
                    sink.draw(draw_target_ch, draw_target);
                  }
                  exit(response_ch) {
                    response_ch.send(());
                    break;
                  }
                }
            }
        }
    }
}

impl to_float for u8 {
    fn to_float() -> float {
        (self as float) / 255f
    }
}

fn draw_solid_color(draw_target: AzDrawTargetRef, item: dl::display_item,
                    r: u8, g: u8, b: u8) {
    let bounds = copy (*item).bounds;

    let red_color = {
        r: r.to_float() as AzFloat,
        g: g.to_float() as AzFloat,
        b: b.to_float() as AzFloat,
        a: 1f as AzFloat
    };
    let red_pattern = AzCreateColorPattern(ptr::addr_of(red_color));

    let red_rect = {
        x: au_to_px(bounds.origin.x) as AzFloat,
        y: au_to_px(bounds.origin.y) as AzFloat,
        width: au_to_px(bounds.size.width) as AzFloat,
        height: au_to_px(bounds.size.height) as AzFloat
    };
    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(red_rect),
        unsafe { unsafe::reinterpret_cast(red_pattern) }
    );

    AzReleaseColorPattern(red_pattern);
}

fn draw_image(draw_target: AzDrawTargetRef, item: dl::display_item,
              -image: ~image) {
    // FIXME: This is hideously inefficient.

    let bounds = copy (*item).bounds;

    if (image.depth < 3u) {
        #debug("TODO: can't draw images with depth less than 3 yet");
        ret;
    }

    let stride = image.width * image.depth;
    for uint::range(0u, image.height) {
        |y|
        for uint::range(0u, image.width) {
            |x|
            let color = {
                r: image.data[y * stride + x * image.depth].to_float()
                    as AzFloat,
                g: image.data[y * stride + x * image.depth + 1u].to_float()
                    as AzFloat,
                b: image.data[y * stride + x * image.depth + 2u].to_float()
                    as AzFloat,
                a: 1f as AzFloat
            };
            let pattern = AzCreateColorPattern(ptr::addr_of(color));

            let pixel_rect = {
                x: (au_to_px(bounds.origin.x) + (x as int)) as AzFloat,
                y: (au_to_px(bounds.origin.y) + (y as int)) as AzFloat,
                width: 1f as AzFloat,
                height: 1f as AzFloat
            };
            AzDrawTargetFillRect(
                draw_target,
                ptr::addr_of(pixel_rect),
                unsafe { unsafe::reinterpret_cast(pattern) }
            );

            AzReleaseColorPattern(pattern);
        }
    }
}

fn draw_display_list(
    draw_target: AzDrawTargetRef,
    display_list: dl::display_list
) {
    for display_list.each {|item|
        #debug["drawing %?", item];

        alt item.item_type {
            dl::display_item_solid_color(r, g, b) {
                draw_solid_color(draw_target, item, r, g, b);
            }
            dl::display_item_image(image) {
                draw_image(draw_target, item, image);
            }
            dl::padding(*) {
                fail "should never see padding";
            }
        }
    }
}

fn draw_some_text(draw_target: AzDrawTargetRef) {

    import az = azure;
    import azbg = azure::bindgen;
    import ft = azure::freetype;
    import ftbg = azure::freetype::bindgen;
    import cairo = azure::cairo;
    import cairobg = azure::cairo::bindgen;
    import cairoftbg = azure::cairo_ft::bindgen;
    import libc::types::common::c99::uint16_t;
    import libc::types::common::c99::uint32_t;

    impl methods for ft::FT_Error {
        fn for_sure() { assert self == 0 as ft::FT_Error }
    }

    let library: ft::FT_Library = ptr::null();
    ftbg::FT_Init_FreeType(ptr::addr_of(library)).for_sure();

    let fontbin = #include_bin("JosefinSans-SemiBold.ttf");

    let face: ft::FT_Face = ptr::null();
    vec::as_buf(fontbin) {|buf|
        ftbg::FT_New_Memory_Face(library, buf, fontbin.len() as ft::FT_Long,
                                 0, ptr::addr_of(face)).for_sure();
    }

    unsafe {
        #debug("num_glyphs %?", (*face).num_glyphs);
        #debug("family_name %?",
               str::unsafe::from_c_str((*face).family_name));
        #debug("style_name %?",
               str::unsafe::from_c_str((*face).style_name));
    }

    let cface = cairoftbg::cairo_ft_font_face_create_for_ft_face(
        face, 0 as libc::c_int);
    assert cface.is_not_null();

    let fontmatrix: cairo::cairo_matrix_t = {
        xx: 0 as libc::c_double,
        yx: 0 as libc::c_double,
        xy: 0 as libc::c_double,
        yy: 0 as libc::c_double,
        x0: 0 as libc::c_double,
        y0: 0 as libc::c_double
    };
    cairobg::cairo_matrix_init_identity(ptr::addr_of(fontmatrix));
    cairobg::cairo_matrix_scale(ptr::addr_of(fontmatrix), 300f as libc::c_double, 400f as libc::c_double);

    let idmatrix: cairo::cairo_matrix_t = {
        xx: 0 as libc::c_double,
        yx: 0 as libc::c_double,
        xy: 0 as libc::c_double,
        yy: 0 as libc::c_double,
        x0: 0 as libc::c_double,
        y0: 0 as libc::c_double
    };
    cairobg::cairo_matrix_init_identity(ptr::addr_of(idmatrix));

    let options = cairobg::cairo_font_options_create();

    let cfont = cairobg::cairo_scaled_font_create(
        cface, ptr::addr_of(fontmatrix), ptr::addr_of(idmatrix), options);
    assert cfont.is_not_null();
    assert cairobg::cairo_scaled_font_status(cfont) == 0 as cairo::cairo_status_t;
    cairobg::cairo_font_face_destroy(cface);
    cairobg::cairo_font_options_destroy(options);

    let nfont: az::AzNativeFont = {
        mType: az::AZ_NATIVE_FONT_CAIRO_FONT_FACE,
        mFont: ptr::null()
    };

    let azfont = azbg::AzCreateScaledFontWithCairo(
        ptr::addr_of(nfont),
        20f as az::AzFloat,
        cfont);
    assert azfont.is_not_null();
    cairobg::cairo_scaled_font_destroy(cfont);

    let color = {
        r: 1f as AzFloat,
        g: 0f as AzFloat,
        b: 0.5f as AzFloat,
        a: 1f as AzFloat
    };
    let pattern = AzCreateColorPattern(ptr::addr_of(color));
    assert pattern.is_not_null();

    let options: az::AzDrawOptions = {
        mAlpha: 1f as az::AzFloat,
        fields: 0 as uint16_t
    };

    let glyphidx = ftbg::FT_Get_Char_Index(face, 'w' as ft::FT_ULong);

    #debug("glyph: %?", glyphidx);

    for int::range(0, 3) {|i|
        let glyphs: [az::AzGlyph] = [
            {
                mIndex: glyphidx,
                mPosition: {
                    x: (100 + 250 * i) as az::AzFloat,
                    y: 600 as az::AzFloat
                }
            }
        ];

        let glyphbuf: az::AzGlyphBuffer = unsafe {{
            mGlyphs: vec::unsafe::to_ptr(glyphs),
            mNumGlyphs: 1 as uint32_t
        }};

        AzDrawTargetFillGlyphs(draw_target,
                               azfont,
                               ptr::addr_of(glyphbuf),
                               pattern,
                               ptr::addr_of(options),
                               ptr::null());
    }

    azbg::AzReleaseColorPattern(pattern);
    azbg::AzReleaseScaledFont(azfont);
    ftbg::FT_Done_Face(face).for_sure();
    ftbg::FT_Done_FreeType(library).for_sure();
}

fn clear(draw_target: AzDrawTargetRef) {

    let black_color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let black_pattern = AzCreateColorPattern(ptr::addr_of(black_color));

    let black_rect = {
        x: 0 as AzFloat,
        y: 0 as AzFloat,
        width: 800 as AzFloat,
        height: 600 as AzFloat,
    };

    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(black_rect),
        unsafe { unsafe::reinterpret_cast(black_pattern) }
    );

    AzReleaseColorPattern(black_pattern);
}
<commit_msg>Drawing text on mac doesn't work yet<commit_after>import platform::osmain;
import geom::*;
import comm::*;
import image::base::image;
import dl = layout::display_list;
import azure::*;
import azure::bindgen::*;

enum msg {
    render(dl::display_list),
    exit(comm::chan<()>)
}

#[doc = "
The interface used to by the renderer to aquire draw targets for
each rendered frame and submit them to be drawn to the display
"]
iface sink {
    fn begin_drawing(next_dt: chan<AzDrawTargetRef>);
    fn draw(next_dt: chan<AzDrawTargetRef>, draw_me: AzDrawTargetRef);
}

fn renderer<S: sink send copy>(sink: S) -> chan<msg> {
    task::spawn_listener::<msg> {|po|
        listen {|draw_target_ch|
            #debug("renderer: beginning rendering loop");
            sink.begin_drawing(draw_target_ch);

            loop {
                alt po.recv() {
                  render(display_list) {
                    #debug("renderer: got render request");
                    let draw_target = draw_target_ch.recv();
                    #debug("renderer: rendering");
                    clear(draw_target);
                    draw_display_list(draw_target, display_list);
                    draw_some_text(draw_target);
                    #debug("renderer: returning surface");
                    sink.draw(draw_target_ch, draw_target);
                  }
                  exit(response_ch) {
                    response_ch.send(());
                    break;
                  }
                }
            }
        }
    }
}

impl to_float for u8 {
    fn to_float() -> float {
        (self as float) / 255f
    }
}

fn draw_solid_color(draw_target: AzDrawTargetRef, item: dl::display_item,
                    r: u8, g: u8, b: u8) {
    let bounds = copy (*item).bounds;

    let red_color = {
        r: r.to_float() as AzFloat,
        g: g.to_float() as AzFloat,
        b: b.to_float() as AzFloat,
        a: 1f as AzFloat
    };
    let red_pattern = AzCreateColorPattern(ptr::addr_of(red_color));

    let red_rect = {
        x: au_to_px(bounds.origin.x) as AzFloat,
        y: au_to_px(bounds.origin.y) as AzFloat,
        width: au_to_px(bounds.size.width) as AzFloat,
        height: au_to_px(bounds.size.height) as AzFloat
    };
    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(red_rect),
        unsafe { unsafe::reinterpret_cast(red_pattern) }
    );

    AzReleaseColorPattern(red_pattern);
}

fn draw_image(draw_target: AzDrawTargetRef, item: dl::display_item,
              -image: ~image) {
    // FIXME: This is hideously inefficient.

    let bounds = copy (*item).bounds;

    if (image.depth < 3u) {
        #debug("TODO: can't draw images with depth less than 3 yet");
        ret;
    }

    let stride = image.width * image.depth;
    for uint::range(0u, image.height) {
        |y|
        for uint::range(0u, image.width) {
            |x|
            let color = {
                r: image.data[y * stride + x * image.depth].to_float()
                    as AzFloat,
                g: image.data[y * stride + x * image.depth + 1u].to_float()
                    as AzFloat,
                b: image.data[y * stride + x * image.depth + 2u].to_float()
                    as AzFloat,
                a: 1f as AzFloat
            };
            let pattern = AzCreateColorPattern(ptr::addr_of(color));

            let pixel_rect = {
                x: (au_to_px(bounds.origin.x) + (x as int)) as AzFloat,
                y: (au_to_px(bounds.origin.y) + (y as int)) as AzFloat,
                width: 1f as AzFloat,
                height: 1f as AzFloat
            };
            AzDrawTargetFillRect(
                draw_target,
                ptr::addr_of(pixel_rect),
                unsafe { unsafe::reinterpret_cast(pattern) }
            );

            AzReleaseColorPattern(pattern);
        }
    }
}

fn draw_display_list(
    draw_target: AzDrawTargetRef,
    display_list: dl::display_list
) {
    for display_list.each {|item|
        #debug["drawing %?", item];

        alt item.item_type {
            dl::display_item_solid_color(r, g, b) {
                draw_solid_color(draw_target, item, r, g, b);
            }
            dl::display_item_image(image) {
                draw_image(draw_target, item, image);
            }
            dl::padding(*) {
                fail "should never see padding";
            }
        }
    }
}

#[cfg(target_os = "macos")]
fn draw_some_text(_draw_target: AzDrawTargetRef) {
   // FIXME: Don't know how to draw text on mac yet
}

#[cfg(target_os = "linux")]
fn draw_some_text(draw_target: AzDrawTargetRef) {

    import az = azure;
    import azbg = azure::bindgen;
    import ft = azure::freetype;
    import ftbg = azure::freetype::bindgen;
    import cairo = azure::cairo;
    import cairobg = azure::cairo::bindgen;
    import cairoftbg = azure::cairo_ft::bindgen;
    import libc::types::common::c99::uint16_t;
    import libc::types::common::c99::uint32_t;

    impl methods for ft::FT_Error {
        fn for_sure() { assert self == 0 as ft::FT_Error }
    }

    let library: ft::FT_Library = ptr::null();
    ftbg::FT_Init_FreeType(ptr::addr_of(library)).for_sure();

    let fontbin = #include_bin("JosefinSans-SemiBold.ttf");

    let face: ft::FT_Face = ptr::null();
    vec::as_buf(fontbin) {|buf|
        ftbg::FT_New_Memory_Face(library, buf, fontbin.len() as ft::FT_Long,
                                 0, ptr::addr_of(face)).for_sure();
    }

    unsafe {
        #debug("num_glyphs %?", (*face).num_glyphs);
        #debug("family_name %?",
               str::unsafe::from_c_str((*face).family_name));
        #debug("style_name %?",
               str::unsafe::from_c_str((*face).style_name));
    }

    let cface = cairoftbg::cairo_ft_font_face_create_for_ft_face(
        face, 0 as libc::c_int);
    assert cface.is_not_null();

    let fontmatrix: cairo::cairo_matrix_t = {
        xx: 0 as libc::c_double,
        yx: 0 as libc::c_double,
        xy: 0 as libc::c_double,
        yy: 0 as libc::c_double,
        x0: 0 as libc::c_double,
        y0: 0 as libc::c_double
    };
    cairobg::cairo_matrix_init_identity(ptr::addr_of(fontmatrix));
    cairobg::cairo_matrix_scale(ptr::addr_of(fontmatrix), 300f as libc::c_double, 400f as libc::c_double);

    let idmatrix: cairo::cairo_matrix_t = {
        xx: 0 as libc::c_double,
        yx: 0 as libc::c_double,
        xy: 0 as libc::c_double,
        yy: 0 as libc::c_double,
        x0: 0 as libc::c_double,
        y0: 0 as libc::c_double
    };
    cairobg::cairo_matrix_init_identity(ptr::addr_of(idmatrix));

    let options = cairobg::cairo_font_options_create();

    let cfont = cairobg::cairo_scaled_font_create(
        cface, ptr::addr_of(fontmatrix), ptr::addr_of(idmatrix), options);
    assert cfont.is_not_null();
    assert cairobg::cairo_scaled_font_status(cfont) == 0 as cairo::cairo_status_t;
    cairobg::cairo_font_face_destroy(cface);
    cairobg::cairo_font_options_destroy(options);

    let nfont: az::AzNativeFont = {
        mType: az::AZ_NATIVE_FONT_CAIRO_FONT_FACE,
        mFont: ptr::null()
    };

    let azfont = azbg::AzCreateScaledFontWithCairo(
        ptr::addr_of(nfont),
        20f as az::AzFloat,
        cfont);
    assert azfont.is_not_null();
    cairobg::cairo_scaled_font_destroy(cfont);

    let color = {
        r: 1f as AzFloat,
        g: 0f as AzFloat,
        b: 0.5f as AzFloat,
        a: 1f as AzFloat
    };
    let pattern = AzCreateColorPattern(ptr::addr_of(color));
    assert pattern.is_not_null();

    let options: az::AzDrawOptions = {
        mAlpha: 1f as az::AzFloat,
        fields: 0 as uint16_t
    };

    let glyphidx = ftbg::FT_Get_Char_Index(face, 'w' as ft::FT_ULong);

    #debug("glyph: %?", glyphidx);

    for int::range(0, 3) {|i|
        let glyphs: [az::AzGlyph] = [
            {
                mIndex: glyphidx,
                mPosition: {
                    x: (100 + 250 * i) as az::AzFloat,
                    y: 600 as az::AzFloat
                }
            }
        ];

        let glyphbuf: az::AzGlyphBuffer = unsafe {{
            mGlyphs: vec::unsafe::to_ptr(glyphs),
            mNumGlyphs: 1 as uint32_t
        }};

        AzDrawTargetFillGlyphs(draw_target,
                               azfont,
                               ptr::addr_of(glyphbuf),
                               pattern,
                               ptr::addr_of(options),
                               ptr::null());
    }

    azbg::AzReleaseColorPattern(pattern);
    azbg::AzReleaseScaledFont(azfont);
    ftbg::FT_Done_Face(face).for_sure();
    ftbg::FT_Done_FreeType(library).for_sure();
}

fn clear(draw_target: AzDrawTargetRef) {

    let black_color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let black_pattern = AzCreateColorPattern(ptr::addr_of(black_color));

    let black_rect = {
        x: 0 as AzFloat,
        y: 0 as AzFloat,
        width: 800 as AzFloat,
        height: 600 as AzFloat,
    };

    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(black_rect),
        unsafe { unsafe::reinterpret_cast(black_pattern) }
    );

    AzReleaseColorPattern(black_pattern);
}
<|endoftext|>


<commit_before>use std::iter::repeat;

use Index;

pub const BITS: usize = 5;
pub const LAYERS: usize = 4;
pub const MAX: usize = BITS * LAYERS;
pub const MAX_EID: usize = 2 << MAX - 1;

/// A BitSet is a simple set designed for tracking entity indexes
/// are present or not. It does not track the `Generation` of the
/// entities that it contains.
///
/// Note, the BitSet is limited by design to only 1,048,576 indexs
/// adding beyond this will cause the BitSet to panic.
#[derive(Clone)]
pub struct BitSet {
    layer3: u32,
    layer2: Vec<u32>,
    layer1: Vec<u32>,
    layer0: Vec<u32>,
}

#[inline]
fn offsets(bit: Index) -> (usize, usize, usize) {
    (bit.offset::<Shift1>(), bit.offset::<Shift2>(), bit.offset::<Shift3>())
}

impl BitSet {
    /// Create an empty BitSet
    pub fn new() -> BitSet {
        BitSet {
            layer3: 0,
            layer2: Vec::new(),
            layer1: Vec::new(),
            layer0: Vec::new(),
        }
    }

    #[inline]
    fn valid_range(max: Index) {
        if (MAX_EID as u32) < max {
            panic!("Expected index to be less then {}, found {}", MAX_EID, max);
        }
    }

    /// Create an empty BitSet with up to max Index
    pub fn with_capacity(max: Index) -> BitSet {
        Self::valid_range(max);
        let mut value = BitSet::new();
        value.extend(max);
        value
    }

    #[inline(never)]
    fn extend(&mut self, id: Index) {
        Self::valid_range(id);
        let (p0, p1, p2) = offsets(id);

        if self.layer2.len() <= p2 {
            let count = p2 - self.layer2.len() + 1;
            self.layer2.extend(repeat(0).take(count));
        }
        if self.layer1.len() <= p1 {
            let count = p1 - self.layer1.len() + 1;
            self.layer1.extend(repeat(0).take(count));
        }
        if self.layer0.len() <= p0 {
            let count = p0 - self.layer0.len() + 1;
            self.layer0.extend(repeat(0).take(count));
        }
    }

    /// this is used to set the levels in the hierarchy
    /// when the lowest layer was set from 0
    fn add_slow(&mut self, id: Index) {
        let (_, p1, p2) = offsets(id);
        self.layer1[p1] |= id.mask::<Shift1>();
        self.layer2[p2] |= id.mask::<Shift2>();
        self.layer3 |= id.mask::<Shift3>();
    }

    /// Add `id` to the bitset. Returning if the value was
    /// already in the set before it was added
    #[inline]
    pub fn add(&mut self, id: Index) -> bool {
        let (p0, mask) = (id.offset::<Shift1>(), id.mask::<Shift0>());

        if p0 >= self.layer0.len() {
            self.extend(id);
        }

        if self.layer0[p0] & mask != 0 {
            return true;
        }

        // we need to set the bit on every layer to indicate
        // that the value can be found here.
        let old = self.layer0[p0];
        self.layer0[p0] |= mask;
        if old == 0 {
            self.add_slow(id);
        } else {
            self.layer0[p0] |= mask;
        }
        false
    }

    /// Remove `id` from the set, returns true if the value
    /// was removed, returns false if the value was not set
    /// to begin with
    #[inline]
    pub fn remove(&mut self, id: Index) -> bool {
        let (p0, p1, p2) = offsets(id);

        if p0 >= self.layer0.len() {
            return false;
        }

        if self.layer0[p0] & id.mask::<Shift0>() == 0 {
            return false;
        }

        // if the bitmask was set we need to clear
        // its bit from layer0 to 3. the layers abover only
        // should be cleared if the bit cleared was the last bit
        // in its set
        self.layer0[p0] &= !id.mask::<Shift0>();
        if self.layer0[p0] != 0 {
            return true;
        }

        self.layer1[p1] &= !id.mask::<Shift1>();
        if self.layer1[p1] != 0 {
            return true;
        }

        self.layer2[p2] &= !id.mask::<Shift2>();
        if self.layer2[p2] != 0 {
            return true;
        }

        self.layer3 &= !id.mask::<Shift3>();
        return true;
    }

    /// Check to see if `id` was included in the set
    /// return true if it was, false otherwise
    #[inline]
    pub fn contains(&self, bit: u32) -> bool {
        let p0 = bit.offset::<Shift1>();
        if p0 >= self.layer0.len() {
            return false;
        }
        (self.layer0[p0] & bit.mask::<Shift0>()) != 0
    }
}

pub trait Shift {
    fn shift() -> usize;
    fn bits() -> usize;

    #[inline]
    fn mask() -> usize {
        ((1 << Self::bits()) - 1) << Self::shift()
    }
}

pub trait Row: Sized + Copy {
    fn row<S>(self) -> usize where S: Shift;
    fn offset<S>(self) -> usize where S: Shift;

    #[inline(always)]
    fn mask<S: Shift>(self) -> u32 {
        1u32 << self.row::<S>()
    }
}

impl Row for Index {
    #[inline(always)]
    fn row<S>(self) -> usize
        where S: Shift
    {
        let size = S::bits();
        let shift = S::shift();

        ((self >> shift) as usize) & ((1 << size) - 1)
    }

    #[inline(always)]
    fn offset<S>(self) -> usize
        where S: Shift
    {
        self as usize / (1 << S::shift())
    }
}

#[derive(Copy, Clone)]
pub struct Shift0;
impl Shift for Shift0 {
    #[inline(always)]
    fn shift() -> usize {
        0
    }
    #[inline(always)]
    fn bits() -> usize {
        BITS
    }
}

#[derive(Copy, Clone)]
pub struct Shift1;
impl Shift for Shift1 {
    #[inline(always)]
    fn shift() -> usize {
        Shift0::bits()
    }
    #[inline(always)]
    fn bits() -> usize {
        BITS
    }
}

#[derive(Copy, Clone)]
pub struct Shift2;
impl Shift for Shift2 {
    #[inline(always)]
    fn shift() -> usize {
        Shift1::bits() + Shift1::shift()
    }
    #[inline(always)]
    fn bits() -> usize {
        BITS
    }
}

#[derive(Copy, Clone)]
pub struct Shift3;
impl Shift for Shift3 {
    #[inline(always)]
    fn shift() -> usize {
        Shift2::bits() + Shift2::shift()
    }
    #[inline(always)]
    fn bits() -> usize {
        BITS
    }
}

/// A generic interface for BitSet like type
/// A bitset in `specs` is hierarchal meaning that there
/// are multiple levels that branch out in a tree like structure
///
/// Layer0 has each bit representing one Index of the set
/// Layer1 each bit represents one u32 of Layer0, and will be
/// set only if the word below it is none zero.
/// Layer2 has the same arrangement but with Layer1, and Layer4 with Layer4
///
/// This arrangement allows for rapid jumps across the key-space
pub trait BitSetLike {
    /// Return a u32 where each bit represents if any word in layer2
    /// has been set.
    fn layer3(&self) -> u32;
    /// Return the u32 from the array of u32s that indicates if any
    /// bit has been set in layer1
    fn layer2(&self, i: usize) -> u32;
    /// Return the u32 from the array of u32s that indicates if any
    /// bit has been set in layer0
    fn layer1(&self, i: usize) -> u32;
    /// Return a u32 that maps to the direct 1:1 association with
    /// each index of the set
    fn layer0(&self, i: usize) -> u32;

    /// Create an iterator that will scan over the keyspace
    fn iter<'a>(&'a self) -> Iter<'a, Self>
        where Self: Sized
    {
        Iter{
            prefix: [0; 3],
            masks: [0, 0, 0, self.layer3()],
            set: self
        }
    }
}

impl<'a, T> BitSetLike for &'a T where T: BitSetLike
{
    #[inline] fn layer3(&self) -> u32 { (*self).layer3() }
    #[inline] fn layer2(&self, i: usize) -> u32 { (*self).layer2(i) }
    #[inline] fn layer1(&self, i: usize) -> u32 { (*self).layer1(i) }
    #[inline] fn layer0(&self, i: usize) -> u32 { (*self).layer0(i) }
}

impl BitSetLike for BitSet {
    #[inline] fn layer3(&self) -> u32 { self.layer3 }
    #[inline] fn layer2(&self, i: usize) -> u32 { self.layer2[i] }
    #[inline] fn layer1(&self, i: usize) -> u32 { self.layer1[i] }
    #[inline] fn layer0(&self, i: usize) -> u32 { self.layer0[i] }
}

/// BitSet and takes two BitSetLike items and merges the masks
/// returning a new virtual set.
pub struct BitSetAnd<A: BitSetLike, B: BitSetLike>(pub A, pub B);

impl<A: BitSetLike, B: BitSetLike> BitSetLike for BitSetAnd<A, B> {
    #[inline] fn layer3(&self) -> u32 { self.0.layer3() & self.1.layer3() }
    #[inline] fn layer2(&self, i: usize) -> u32 { self.0.layer2(i) & self.1.layer2(i) }
    #[inline] fn layer1(&self, i: usize) -> u32 { self.0.layer1(i) & self.1.layer1(i) }
    #[inline] fn layer0(&self, i: usize) -> u32 { self.0.layer0(i) & self.1.layer0(i) }
}

pub struct Iter<'a, T:'a> {
    set: &'a T,
    masks: [u32; 4],
    prefix: [u32; 3]
}

impl<'a, T> Iterator for Iter<'a, T>
    where T: BitSetLike+'a
{
    type Item = Index;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.masks[0] != 0 {
                let bit = self.masks[0].trailing_zeros();
                self.masks[0] &= !(1 << bit);
                return Some(self.prefix[0] | bit);
            }

            if self.masks[1] != 0 {
                let bit = self.masks[1].trailing_zeros();
                self.masks[1] &= !(1 << bit);
                let idx = self.prefix[1] | bit;
                self.masks[0] = self.set.layer0(idx as usize);
                self.prefix[0] = idx << BITS;
                continue;
            }

            if self.masks[2] != 0 {
                let bit = self.masks[2].trailing_zeros();
                self.masks[2] &= !(1 << bit);
                let idx = self.prefix[2] | bit;
                self.masks[1] = self.set.layer1(idx as usize);
                self.prefix[1] = idx << BITS;
                continue;
            }

            if self.masks[3] != 0 {
                let bit = self.masks[3].trailing_zeros();
                self.masks[3] &= !(1 << bit);
                self.masks[2] = self.set.layer2(bit as usize);
                self.prefix[2] = bit << BITS;
                continue;
            }
            return None;
        }
    }
}

#[cfg(test)]
mod set_test {
    use super::{BitSet, BitSetAnd, BitSetLike};

    #[test]
    fn insert() {
        let mut c = BitSet::new();
        for i in 0..1_000 {
            assert!(!c.add(i));
            assert!(c.add(i));
        }

        for i in 0..1_000 {
            assert!(c.contains(i));
        }
    }

    #[test]
    fn insert_100k() {
        let mut c = BitSet::new();
        for i in 0..100_000 {
            assert!(!c.add(i));
            assert!(c.add(i));
        }

        for i in 0..100_000 {
            assert!(c.contains(i));
        }
    }

    #[test]
    fn remove() {
        let mut c = BitSet::new();
        for i in 0..1_000 {
            assert!(!c.add(i));
        }

        for i in 0..1_000 {
            assert!(c.contains(i));
            assert!(c.remove(i));
            assert!(!c.contains(i));
            assert!(!c.remove(i));
        }
    }

    #[test]
    fn iter() {
        let mut c = BitSet::new();
        for i in 0..100_000 {
            c.add(i);
        }

        let mut count = 0;
        for (idx, i) in c.iter().enumerate() {
            count += 1;
            assert_eq!(idx, i as usize);
        }
        assert_eq!(count, 100_000);
    }

    #[test]
    fn iter_odd_even() {
        let mut odd = BitSet::new();
        let mut even = BitSet::new();
        for i in 0..100_000 {
            if i % 2 == 1 {
                odd.add(i);
            } else {
                even.add(i);
            }
        }

        assert_eq!(odd.iter().count(), 50_000);
        assert_eq!(even.iter().count(), 50_000);
        assert_eq!(BitSetAnd(&odd, &even).iter().count(), 0);
    }
}

<commit_msg>Remove shift trait<commit_after>use std::iter::repeat;

use Index;

pub const BITS: usize = 5;
pub const LAYERS: usize = 4;
pub const MAX: usize = BITS * LAYERS;
pub const MAX_EID: usize = 2 << MAX - 1;

pub const SHIFT0: usize = 0;
pub const SHIFT1: usize = SHIFT0 + BITS;
pub const SHIFT2: usize = SHIFT1 + BITS;
pub const SHIFT3: usize = SHIFT2 + BITS;

/// A BitSet is a simple set designed for tracking entity indexes
/// are present or not. It does not track the `Generation` of the
/// entities that it contains.
///
/// Note, the BitSet is limited by design to only 1,048,576 indexs
/// adding beyond this will cause the BitSet to panic.
#[derive(Clone)]
pub struct BitSet {
    layer3: u32,
    layer2: Vec<u32>,
    layer1: Vec<u32>,
    layer0: Vec<u32>,
}

#[inline]
fn offsets(bit: Index) -> (usize, usize, usize) {
    (bit.offset(SHIFT1), bit.offset(SHIFT2), bit.offset(SHIFT3))
}

impl BitSet {
    /// Create an empty BitSet
    pub fn new() -> BitSet {
        BitSet {
            layer3: 0,
            layer2: Vec::new(),
            layer1: Vec::new(),
            layer0: Vec::new(),
        }
    }

    #[inline]
    fn valid_range(max: Index) {
        if (MAX_EID as u32) < max {
            panic!("Expected index to be less then {}, found {}", MAX_EID, max);
        }
    }

    /// Create an empty BitSet with up to max Index
    pub fn with_capacity(max: Index) -> BitSet {
        Self::valid_range(max);
        let mut value = BitSet::new();
        value.extend(max);
        value
    }

    #[inline(never)]
    fn extend(&mut self, id: Index) {
        Self::valid_range(id);
        let (p0, p1, p2) = offsets(id);

        if self.layer2.len() <= p2 {
            let count = p2 - self.layer2.len() + 1;
            self.layer2.extend(repeat(0).take(count));
        }
        if self.layer1.len() <= p1 {
            let count = p1 - self.layer1.len() + 1;
            self.layer1.extend(repeat(0).take(count));
        }
        if self.layer0.len() <= p0 {
            let count = p0 - self.layer0.len() + 1;
            self.layer0.extend(repeat(0).take(count));
        }
    }

    /// this is used to set the levels in the hierarchy
    /// when the lowest layer was set from 0
    fn add_slow(&mut self, id: Index) {
        let (_, p1, p2) = offsets(id);
        self.layer1[p1] |= id.mask(SHIFT1);
        self.layer2[p2] |= id.mask(SHIFT2);
        self.layer3 |= id.mask(SHIFT3);
    }

    /// Add `id` to the bitset. Returning if the value was
    /// already in the set before it was added
    #[inline]
    pub fn add(&mut self, id: Index) -> bool {
        let (p0, mask) = (id.offset(SHIFT1), id.mask(SHIFT0));

        if p0 >= self.layer0.len() {
            self.extend(id);
        }

        if self.layer0[p0] & mask != 0 {
            return true;
        }

        // we need to set the bit on every layer to indicate
        // that the value can be found here.
        let old = self.layer0[p0];
        self.layer0[p0] |= mask;
        if old == 0 {
            self.add_slow(id);
        } else {
            self.layer0[p0] |= mask;
        }
        false
    }

    /// Remove `id` from the set, returns true if the value
    /// was removed, returns false if the value was not set
    /// to begin with
    #[inline]
    pub fn remove(&mut self, id: Index) -> bool {
        let (p0, p1, p2) = offsets(id);

        if p0 >= self.layer0.len() {
            return false;
        }

        if self.layer0[p0] & id.mask(SHIFT0) == 0 {
            return false;
        }

        // if the bitmask was set we need to clear
        // its bit from layer0 to 3. the layers abover only
        // should be cleared if the bit cleared was the last bit
        // in its set
        self.layer0[p0] &= !id.mask(SHIFT0);
        if self.layer0[p0] != 0 {
            return true;
        }

        self.layer1[p1] &= !id.mask(SHIFT1);
        if self.layer1[p1] != 0 {
            return true;
        }

        self.layer2[p2] &= !id.mask(SHIFT2);
        if self.layer2[p2] != 0 {
            return true;
        }

        self.layer3 &= !id.mask(SHIFT3);
        return true;
    }

    /// Check to see if `id` was included in the set
    /// return true if it was, false otherwise
    #[inline]
    pub fn contains(&self, bit: u32) -> bool {
        let p0 = bit.offset(SHIFT1);
        if p0 >= self.layer0.len() {
            return false;
        }
        (self.layer0[p0] & bit.mask(SHIFT0)) != 0
    }
}

pub trait Row: Sized + Copy {
    fn row(self, shift: usize) -> usize;
    fn offset(self, shift: usize) -> usize;

    #[inline(always)]
    fn mask(self, shift: usize) -> u32 {
        1u32 << self.row(shift)
    }
}

impl Row for Index {
    #[inline(always)]
    fn row(self, shift: usize) -> usize {
        ((self >> shift) as usize) & ((1 << BITS) - 1)
    }

    #[inline(always)]
    fn offset(self, shift: usize) -> usize {
        self as usize / (1 << shift)
    }
}

/// A generic interface for BitSet like type
/// A bitset in `specs` is hierarchal meaning that there
/// are multiple levels that branch out in a tree like structure
///
/// Layer0 has each bit representing one Index of the set
/// Layer1 each bit represents one u32 of Layer0, and will be
/// set only if the word below it is none zero.
/// Layer2 has the same arrangement but with Layer1, and Layer4 with Layer4
///
/// This arrangement allows for rapid jumps across the key-space
pub trait BitSetLike {
    /// Return a u32 where each bit represents if any word in layer2
    /// has been set.
    fn layer3(&self) -> u32;
    /// Return the u32 from the array of u32s that indicates if any
    /// bit has been set in layer1
    fn layer2(&self, i: usize) -> u32;
    /// Return the u32 from the array of u32s that indicates if any
    /// bit has been set in layer0
    fn layer1(&self, i: usize) -> u32;
    /// Return a u32 that maps to the direct 1:1 association with
    /// each index of the set
    fn layer0(&self, i: usize) -> u32;

    /// Create an iterator that will scan over the keyspace
    fn iter<'a>(&'a self) -> Iter<'a, Self>
        where Self: Sized
    {
        Iter{
            prefix: [0; 3],
            masks: [0, 0, 0, self.layer3()],
            set: self
        }
    }
}

impl<'a, T> BitSetLike for &'a T where T: BitSetLike
{
    #[inline] fn layer3(&self) -> u32 { (*self).layer3() }
    #[inline] fn layer2(&self, i: usize) -> u32 { (*self).layer2(i) }
    #[inline] fn layer1(&self, i: usize) -> u32 { (*self).layer1(i) }
    #[inline] fn layer0(&self, i: usize) -> u32 { (*self).layer0(i) }
}

impl BitSetLike for BitSet {
    #[inline] fn layer3(&self) -> u32 { self.layer3 }
    #[inline] fn layer2(&self, i: usize) -> u32 { self.layer2[i] }
    #[inline] fn layer1(&self, i: usize) -> u32 { self.layer1[i] }
    #[inline] fn layer0(&self, i: usize) -> u32 { self.layer0[i] }
}

/// BitSet and takes two BitSetLike items and merges the masks
/// returning a new virtual set.
pub struct BitSetAnd<A: BitSetLike, B: BitSetLike>(pub A, pub B);

impl<A: BitSetLike, B: BitSetLike> BitSetLike for BitSetAnd<A, B> {
    #[inline] fn layer3(&self) -> u32 { self.0.layer3() & self.1.layer3() }
    #[inline] fn layer2(&self, i: usize) -> u32 { self.0.layer2(i) & self.1.layer2(i) }
    #[inline] fn layer1(&self, i: usize) -> u32 { self.0.layer1(i) & self.1.layer1(i) }
    #[inline] fn layer0(&self, i: usize) -> u32 { self.0.layer0(i) & self.1.layer0(i) }
}

pub struct Iter<'a, T:'a> {
    set: &'a T,
    masks: [u32; 4],
    prefix: [u32; 3]
}

impl<'a, T> Iterator for Iter<'a, T>
    where T: BitSetLike+'a
{
    type Item = Index;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.masks[0] != 0 {
                let bit = self.masks[0].trailing_zeros();
                self.masks[0] &= !(1 << bit);
                return Some(self.prefix[0] | bit);
            }

            if self.masks[1] != 0 {
                let bit = self.masks[1].trailing_zeros();
                self.masks[1] &= !(1 << bit);
                let idx = self.prefix[1] | bit;
                self.masks[0] = self.set.layer0(idx as usize);
                self.prefix[0] = idx << BITS;
                continue;
            }

            if self.masks[2] != 0 {
                let bit = self.masks[2].trailing_zeros();
                self.masks[2] &= !(1 << bit);
                let idx = self.prefix[2] | bit;
                self.masks[1] = self.set.layer1(idx as usize);
                self.prefix[1] = idx << BITS;
                continue;
            }

            if self.masks[3] != 0 {
                let bit = self.masks[3].trailing_zeros();
                self.masks[3] &= !(1 << bit);
                self.masks[2] = self.set.layer2(bit as usize);
                self.prefix[2] = bit << BITS;
                continue;
            }
            return None;
        }
    }
}

#[cfg(test)]
mod set_test {
    use super::{BitSet, BitSetAnd, BitSetLike};

    #[test]
    fn insert() {
        let mut c = BitSet::new();
        for i in 0..1_000 {
            assert!(!c.add(i));
            assert!(c.add(i));
        }

        for i in 0..1_000 {
            assert!(c.contains(i));
        }
    }

    #[test]
    fn insert_100k() {
        let mut c = BitSet::new();
        for i in 0..100_000 {
            assert!(!c.add(i));
            assert!(c.add(i));
        }

        for i in 0..100_000 {
            assert!(c.contains(i));
        }
    }

    #[test]
    fn remove() {
        let mut c = BitSet::new();
        for i in 0..1_000 {
            assert!(!c.add(i));
        }

        for i in 0..1_000 {
            assert!(c.contains(i));
            assert!(c.remove(i));
            assert!(!c.contains(i));
            assert!(!c.remove(i));
        }
    }

    #[test]
    fn iter() {
        let mut c = BitSet::new();
        for i in 0..100_000 {
            c.add(i);
        }

        let mut count = 0;
        for (idx, i) in c.iter().enumerate() {
            count += 1;
            assert_eq!(idx, i as usize);
        }
        assert_eq!(count, 100_000);
    }

    #[test]
    fn iter_odd_even() {
        let mut odd = BitSet::new();
        let mut even = BitSet::new();
        for i in 0..100_000 {
            if i % 2 == 1 {
                odd.add(i);
            } else {
                even.add(i);
            }
        }

        assert_eq!(odd.iter().count(), 50_000);
        assert_eq!(even.iter().count(), 50_000);
        assert_eq!(BitSetAnd(&odd, &even).iter().count(), 0);
    }
}

<|endoftext|>


<commit_before><commit_msg>compare_to_surface(): Print how many pixels were different, and add a tolerance<commit_after><|endoftext|>


<commit_before>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
// Packages required:
//
// - OpenGLES
// - GLFW
// - cgmath
//
//============================================================================

extern crate native;
extern crate num;

extern crate opengles;
extern crate glfw;
extern crate cgmath;

use opengles::gl2;

use cgmath::vector::Vec3;
use cgmath::aabb::Aabb3;

use std::str;
use std::libc;
use num::complex::Complex64;
use std::num::{sin};

// Make for platform==MacOSX
#[feature(link_args)]
#[link(name = "OpenGL")]

type Vec3f = Vec3<f32>;
type AABB3f = Aabb3<f32>;

static vertex_shader_source: &'static str = "";
/*
#version 150

in vec2 position;
in vec3 color;

out vec3 Color;

void main()
{
    Color = color;
    gl_Position = vec4(position, 0.0, 1.0);
}
";
*/

static fragment_shader_source: &'static str = "";
/*
#version 150

in vec3 Color;
out vec4 outColor;

void main()
{
    outColor = vec4(Color, 1.0);
}";
*/

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        println!("GLFW Error: {:s}", description);
    }
}

struct WindowController<'a> {
    window: &'a glfw::Window,
    vertices: ~[f32],
    vao: ~[gl2::GLuint],
    vbo: ~[gl2::GLuint],
    vertex_shader: gl2::GLuint,
    fragment_shader: gl2::GLuint,
    shader_program: gl2::GLuint,
    uni_color: gl2::GLint,
}

struct KeyController;

impl KeyController {
    fn call(&self, window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
        if action == glfw::Press && key == glfw::KeyEscape {
            window.set_should_close(true);
        }
    }
}

struct MandelEngine {
    re0: f32,
    re1: f32,
    im0: f32,
    im1: f32,
    delta: f32,
}

impl MandelEngine {

    fn new() -> MandelEngine {
        MandelEngine { re0: -2.0, re1: 2.0, im0: -2.0, im1: 2.0, delta: 1.0 }
    }

    // Evalute entire region
    fn process() {
    }

    // Evaluate a single point
    fn mandel(z: Complex64) -> int {
        let maxiter: int = 80;
        let mut c: Complex64 = z;
        for n in range(0, maxiter) {
            if c.norm() > 2.0 {
                return n;
            }
            c = c*c+z;
        }
        return maxiter;
    }
}

impl<'a> WindowController<'a> {
    fn new(window: &'a glfw::Window) -> WindowController<'a> {
        let mut wc = WindowController { window: window,
                                        vao: ~[0],
                                        vbo: ~[0],
                                        vertices: ~[],
                                        vertex_shader: 0,
                                        fragment_shader: 0,
                                        shader_program: 0,
                                        uni_color: 0,
        };

        let (width, height) =  wc.window.get_framebuffer_size();

        gl2::viewport(0, 0, width as i32, height as i32);

        println!("Viewport: {} x {}", width, height);

        wc.vertices = ~[
            0.0,  0.5, 1.0, 0.0, 0.0,
            0.5, -0.5, 0.0, 1.0, 0.0,
            -0.5, -0.5, 0.0, 0.0, 1.0,
            ];

        // VAO

        wc.vao = gl2::gen_vertex_arrays(1);
        gl2::bind_vertex_array(wc.vao[0]);

        // VBO

        wc.vbo = gl2::gen_buffers(1);
        gl2::bind_buffer(gl2::ARRAY_BUFFER, wc.vbo[0]);
        gl2::buffer_data(gl2::ARRAY_BUFFER, wc.vertices, gl2::STATIC_DRAW);

        // Vertex Shader

        wc.vertex_shader = gl2::create_shader(gl2::VERTEX_SHADER);
        gl2::shader_source(wc.vertex_shader, ~[vertex_shader_source.to_owned().as_bytes()]);

        gl2::compile_shader(wc.vertex_shader);

        let status = gl2::get_shader_iv(wc.vertex_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.vertex_shader);
            println!("vertex_shader compile error {} = {}", status, log);
        }

        // Fragment Shader

        wc.fragment_shader = gl2::create_shader(gl2::FRAGMENT_SHADER);
        gl2::shader_source(wc.fragment_shader, ~[fragment_shader_source.to_owned().as_bytes()]);
        gl2::compile_shader(wc.fragment_shader);

        let status = gl2::get_shader_iv(wc.fragment_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.fragment_shader);
            println!("fragment_shader compile error {} = {}", status, log);
        }

        // Link

        wc.shader_program = gl2::create_program();

        gl2::attach_shader(wc.shader_program, wc.vertex_shader);
        gl2::attach_shader(wc.shader_program, wc.fragment_shader);

        gl2::link_program(wc.shader_program);

        gl2::use_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            println!("after link err1 = 0x{:x}", err);
        }

        // Attributes

        let pos_attrib = gl2::get_attrib_location(wc.shader_program, "position");
        gl2::enable_vertex_attrib_array(pos_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(pos_attrib as gl2::GLuint, 2, false, 5*4, 0);

        let col_attrib = gl2::get_attrib_location(wc.shader_program, "color");
        gl2::enable_vertex_attrib_array(col_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(col_attrib as gl2::GLuint, 3, false, 5*4, 2*4);

        // Uniforms

        wc.uni_color = gl2::get_uniform_location(wc.shader_program, "triangleColor");

        let err = gl2::get_error();
        if err != 0 {
            println!("attrib err = {:x}", err);
        }

        wc
    }

    fn draw(&self) {

        // Clear

        gl2::clear_color(0.4, 0.4, 0.4, 1.0);
        gl2::clear(gl2::COLOR_BUFFER_BIT);

        // Animate

        let time = glfw::get_time();
//        gl2::uniform_3f(wc.uni_color, (sin(time * 4.0) + 1.0) / 2.0, 0.0, 0.0);

        // Draw!

        gl2::draw_arrays(gl2::TRIANGLES, 0, 3);

        let err = gl2::get_error();
        if err != 0 {
            println!("draw err = 0x{:x}", err);
        }

        self.window.swap_buffers();
    }

    fn uninit(&mut self) {

        // Cleanup

        gl2::delete_program(self.shader_program);
        gl2::delete_shader(self.fragment_shader);
        gl2::delete_shader(self.vertex_shader);

        gl2::delete_buffers(self.vbo);

        // @todo Missing from bindings
        //gl2::delete_vertex_arrays(vao);
    }

    fn handle_window_event(&self, window: &glfw::Window, (time, event): (f64, glfw::WindowEvent)) {
        match event {
            glfw::CloseEvent                    => println!("Time: {}, Window close requested.", time),
            glfw::KeyEvent(key, scancode, action, mods) => {
                println!("Time: {}, Key: {}, ScanCode: {}, Action: {}, Modifiers: [{}]", time, key, scancode, action, mods);
                match (key, action) {
                    (glfw::KeyEscape, glfw::Press) => window.set_should_close(true),
                    (glfw::KeyR, glfw::Press) => {
                        // Resize should cause the window to "refresh"
                        let (window_width, window_height) = window.get_size();
                        window.set_size(window_width + 1, window_height);
                        window.set_size(window_width, window_height);
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

fn main() {

    println!("{}", glfw::get_version().to_str());
    println!("GLFW version: {:s}", glfw::get_version_string());

    glfw::start(proc() {

        glfw::window_hint::context_version_major(3);
        glfw::window_hint::context_version_minor(2);
        glfw::window_hint::opengl_forward_compat(true);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);

        glfw::window_hint::resizable(false);

        let window = glfw::Window::create(640, 480,
                                          "MandelRust",
                                          glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.make_context_current();

        let win_ctrl = ~WindowController::new(&window);

        while !window.should_close() {
            glfw::poll_events();
            for event in window.flush_events() {
                win_ctrl.handle_window_event(&window, event);
            }
        }
    });
}
<commit_msg>Add lots of error checking, get shaders compiling<commit_after>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
// Packages required:
//
// - OpenGLES
// - GLFW
// - cgmath
//
//============================================================================

extern crate native;
extern crate num;

extern crate opengles;
extern crate glfw;
extern crate cgmath;

use opengles::gl2;

use cgmath::vector::Vec3;
use cgmath::aabb::Aabb3;

use std::str;
use std::libc;
use num::complex::Complex64;
use std::num::{sin};

type Vec3f = Vec3<f32>;
type AABB3f = Aabb3<f32>;

//----------------------------------------------------------------------------

static vertex_shader_source: &'static str = "

#version 150

in vec2 position;
in vec3 color;

out vec3 Color;

void main()
{
    Color = color;
    gl_Position = vec4(position, 0.0, 1.0);
}
";

static fragment_shader_source: &'static str = "

#version 150

in vec3 Color;
out vec4 outColor;

void main()
{
    outColor = vec4(Color, 1.0);
}
";

//----------------------------------------------------------------------------

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        println!("GLFW Error: {:s}", description);
    }
}

struct WindowController<'a> {
    window: &'a glfw::Window,
    vertices: ~[f32],
    vao: ~[gl2::GLuint],
    vbo: ~[gl2::GLuint],
    vertex_shader: gl2::GLuint,
    fragment_shader: gl2::GLuint,
    shader_program: gl2::GLuint,
    uni_color: gl2::GLint,
}

struct KeyController;

impl KeyController {
    fn call(&self, window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
        if action == glfw::Press && key == glfw::KeyEscape {
            window.set_should_close(true);
        }
    }
}

struct MandelEngine {
    re0: f32,
    re1: f32,
    im0: f32,
    im1: f32,
    delta: f32,
}

impl MandelEngine {

    fn new() -> MandelEngine {
        MandelEngine { re0: -2.0, re1: 2.0, im0: -2.0, im1: 2.0, delta: 1.0 }
    }

    // Evalute entire region
    fn process() {
    }

    // Evaluate a single point
    fn mandel(z: Complex64) -> int {
        let maxiter: int = 80;
        let mut c: Complex64 = z;
        for n in range(0, maxiter) {
            if c.norm() > 2.0 {
                return n;
            }
            c = c*c+z;
        }
        return maxiter;
    }
}

impl<'a> WindowController<'a> {
    fn new(window: &'a glfw::Window) -> WindowController<'a> {
        let mut wc = WindowController { window: window,
                                        vao: ~[0],
                                        vbo: ~[0],
                                        vertices: ~[],
                                        vertex_shader: 0,
                                        fragment_shader: 0,
                                        shader_program: 0,
                                        uni_color: 0,
        };

        let (width, height) =  wc.window.get_framebuffer_size();

        gl2::viewport(0, 0, width as i32, height as i32);

        println!("Viewport: {} x {}", width, height);

        wc.vertices = ~[
            0.0,  0.5, 1.0, 0.0, 0.0,
            0.5, -0.5, 0.0, 1.0, 0.0,
            -0.5, -0.5, 0.0, 0.0, 1.0,
            ];

        // VAO

        wc.vao = gl2::gen_vertex_arrays(1);
        gl2::bind_vertex_array(wc.vao[0]);

        // VBO

        wc.vbo = gl2::gen_buffers(1);
        gl2::bind_buffer(gl2::ARRAY_BUFFER, wc.vbo[0]);
        gl2::buffer_data(gl2::ARRAY_BUFFER, wc.vertices, gl2::STATIC_DRAW);

        // Vertex Shader

        wc.vertex_shader = gl2::create_shader(gl2::VERTEX_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create v.shader failed");
        }

        gl2::shader_source(wc.vertex_shader, ~[vertex_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.v err 0x{:x}", err);
        }

        gl2::compile_shader(wc.vertex_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.f err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.vertex_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.vertex_shader);
            fail!("glCompileShader.v err 0x{:x}: {}", status, log);
        }

        // Fragment Shader

        wc.fragment_shader = gl2::create_shader(gl2::FRAGMENT_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create f.shader failed");
        }

        gl2::shader_source(wc.fragment_shader, ~[fragment_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.f -> 0x{:x}", err);
        }

        gl2::compile_shader(wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.v err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.fragment_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.fragment_shader);
            fail!("glCompileShader.f err 0x{:x}: {}", status, log);
        }

        // Link

        wc.shader_program = gl2::create_program();

        if wc.shader_program == 0 {
            fail!("glCreateProgram failed");
        }

        gl2::attach_shader(wc.shader_program, wc.vertex_shader);
        gl2::attach_shader(wc.shader_program, wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glAttachShader err 0x{:x}", err);
        }

        gl2::link_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glLinkProgram err 0x{:x}", err);
        }

        let status = gl2::get_program_iv(wc.shader_program, gl2::LINK_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.shader_program);
            fail!("glLinkProgram err {}: {}", status, log);
        }

        gl2::use_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            let log = gl2::get_program_info_log(wc.shader_program);
            fail!("glUseProgram error: {}", log);
        }

        // Attributes

        let pos_attrib = gl2::get_attrib_location(wc.shader_program, "position");
        gl2::enable_vertex_attrib_array(pos_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(pos_attrib as gl2::GLuint, 2, false, 5*4, 0);

        let col_attrib = gl2::get_attrib_location(wc.shader_program, "color");
        gl2::enable_vertex_attrib_array(col_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(col_attrib as gl2::GLuint, 3, false, 5*4, 2*4);

        // Uniforms

        wc.uni_color = gl2::get_uniform_location(wc.shader_program, "triangleColor");

        let err = gl2::get_error();
        if err != 0 {
            fail!("attrib err = {:x}", err);
        }

        wc
    }

    fn draw(&self) {

        // Clear

        gl2::clear_color(0.4, 0.4, 0.4, 1.0);
        gl2::clear(gl2::COLOR_BUFFER_BIT);

        // Animate

        let time = glfw::get_time();
//        gl2::uniform_3f(wc.uni_color, (sin(time * 4.0) + 1.0) / 2.0, 0.0, 0.0);

        // Draw!

        gl2::draw_arrays(gl2::TRIANGLES, 0, 3);

        let err = gl2::get_error();
        if err != 0 {
            println!("draw err = 0x{:x}", err);
        }

        self.window.swap_buffers();
    }

    fn uninit(&mut self) {

        // Cleanup

        gl2::delete_program(self.shader_program);
        gl2::delete_shader(self.fragment_shader);
        gl2::delete_shader(self.vertex_shader);

        gl2::delete_buffers(self.vbo);

        // @todo Missing from bindings
        //gl2::delete_vertex_arrays(vao);
    }

    fn handle_window_event(&self, window: &glfw::Window, (time, event): (f64, glfw::WindowEvent)) {
        match event {

            glfw::CloseEvent => println!("Time: {}, Window close requested.", time),

            glfw::KeyEvent(key, scancode, action, mods) => {
                println!("Time: {}, Key: {}, ScanCode: {}, Action: {}, Modifiers: [{}]", time, key, scancode, action, mods);
                match (key, action) {
                    (glfw::KeyEscape, glfw::Press) => window.set_should_close(true),
                    (glfw::KeyR, glfw::Press) => {
                        // Resize should cause the window to "refresh"
                        let (window_width, window_height) = window.get_size();
                        window.set_size(window_width + 1, window_height);
                        window.set_size(window_width, window_height);
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

fn main() {

    println!("GLFW version: {:s}", glfw::get_version_string());

    glfw::start(proc() {

        glfw::window_hint::context_version_major(3);
        glfw::window_hint::context_version_minor(2);
        glfw::window_hint::opengl_forward_compat(true);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);

        glfw::window_hint::resizable(false);

        let window = glfw::Window::create(640, 480,
                                          "MandelRust",
                                          glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.make_context_current();

        let win_ctrl = ~WindowController::new(&window);

        while !window.should_close() {
            glfw::poll_events();
            for event in window.flush_events() {
                win_ctrl.handle_window_event(&window, event);
            }
        }
    });
}
<|endoftext|>


<commit_before>use std::marker::MarkerTrait;
use std::mem;

use runtime::{Class, Method, Object, Sel, self};
use {encode, Encode};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message : MarkerTrait { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to a pointer to a type that may be sent Objective-C
/// messages.
pub trait ToMessage {
    fn as_id_ptr(&self) -> *mut Object;

    fn is_nil(&self) -> bool {
        self.as_id_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut Object
    }
}

impl<T> ToMessage for *mut T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut Object
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *const T as *mut Object
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut T as *mut Object
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

pub trait MessageArguments {
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_id_ptr();
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[allow(dead_code)]
fn verify_message_arguments(types: &[&str], method: &Method) -> Result<(), String> {
    let count = 2 + types.len();
    let expected_count = method.arguments_count();
    if count != expected_count {
        return Err(format!("Method {:?} accepts {} arguments, but {} were given",
            method.name(), expected_count, count));
    }

    let expected_types = (2..expected_count).map(|i| method.argument_type(i));
    for (&arg, expected) in types.iter().zip(expected_types) {
        let expected = match expected {
            Some(s) => s,
            None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                method.name(), arg)),
        };
        if arg != &*expected {
            return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                method.name(), &*expected, arg));
        }
    }

    Ok(())
}

#[allow(dead_code)]
fn verify_message_signature<A, R>(obj: Option<&Object>, sel: Sel, _args: &A) ->
        Result<(), String> where A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = obj.class();
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if &*expected_ret != ret && !(&*expected_ret == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, &*expected_ret, sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => &*s == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => &*s == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    Ok(())
}

#[cfg(any(ndebug, not(feature = "verify_message_encode")))]
pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

/// Sends a message to an object with selector `sel` and arguments `args`.
/// This function will choose the correct version of `objc_msgSend` based on the
/// return type. For more information, see Apple's documenation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
///
/// When the verify_message_encode feature is defined, at runtime in debug
/// builds this function will verify that the encoding of the return type
/// matches the encoding of the method.
#[cfg(all(not(ndebug), feature = "verify_message_encode"))]
pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_id_ptr().as_ref();
    match verify_message_signature::<_, R>(obj_ref, sel, &args) {
        Err(s) => panic!("Verify message failed: {}", s),
        Ok(_) => args.send(obj, sel),
    }
}

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;
    use super::send_message;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            send_message(&obj, sel!(self), ())
        };
        assert!(&*obj as *const Object == result);
    }

    #[test]
    fn test_send_message_stret() {
        let obj = test_utils::custom_object();
        let result: test_utils::CustomStruct = unsafe {
            send_message(&obj, sel!(customStruct), ())
        };
        let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
        assert!(result == expected);
    }
}
<commit_msg>Improved some message documentation.<commit_after>use std::marker::MarkerTrait;
use std::mem;

use runtime::{Class, Method, Object, Sel, self};
use {encode, Encode};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message : MarkerTrait { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to an `id` pointer that may be sent Objective-C
/// messages.
pub trait ToMessage {
    fn as_id_ptr(&self) -> *mut Object;

    fn is_nil(&self) -> bool {
        self.as_id_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut Object
    }
}

impl<T> ToMessage for *mut T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut Object
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *const T as *mut Object
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut T as *mut Object
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

/// Types that may be used as the arguments of an Objective-C message.
pub trait MessageArguments {
    /// Sends a message to the given obj with the given selector and self as
    /// the arguments.
    ///
    /// It is recommended to use the `msg_send!` macro rather than calling this
    /// method directly.
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_id_ptr();
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[allow(dead_code)]
fn verify_message_arguments(types: &[&str], method: &Method) -> Result<(), String> {
    let count = 2 + types.len();
    let expected_count = method.arguments_count();
    if count != expected_count {
        return Err(format!("Method {:?} accepts {} arguments, but {} were given",
            method.name(), expected_count, count));
    }

    let expected_types = (2..expected_count).map(|i| method.argument_type(i));
    for (&arg, expected) in types.iter().zip(expected_types) {
        let expected = match expected {
            Some(s) => s,
            None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                method.name(), arg)),
        };
        if arg != &*expected {
            return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                method.name(), &*expected, arg));
        }
    }

    Ok(())
}

#[allow(dead_code)]
fn verify_message_signature<A, R>(obj: Option<&Object>, sel: Sel, _args: &A) ->
        Result<(), String> where A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = obj.class();
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if &*expected_ret != ret && !(&*expected_ret == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, &*expected_ret, sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => &*s == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => &*s == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    Ok(())
}

#[cfg(any(ndebug, not(feature = "verify_message_encode")))]
pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

/// Sends a message to an object with selector `sel` and arguments `args`.
/// This function will choose the correct version of `objc_msgSend` based on the
/// return type. For more information, see Apple's documenation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
///
/// When the verify_message_encode feature is defined, at runtime in debug
/// builds this function will verify that the encoding of the return type
/// matches the encoding of the method.
///
/// # Example
/// ``` ignore
/// use objc::send_message;
/// let _: () = send_message(dict, sel!(setObject:forKey:), (obj, key));
/// let obj = send_message(dict, sel!(objectForKey:), (key,));
/// ```
#[cfg(all(not(ndebug), feature = "verify_message_encode"))]
pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_id_ptr().as_ref();
    match verify_message_signature::<_, R>(obj_ref, sel, &args) {
        Err(s) => panic!("Verify message failed: {}", s),
        Ok(_) => args.send(obj, sel),
    }
}

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;
    use super::send_message;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            send_message(&obj, sel!(self), ())
        };
        assert!(&*obj as *const Object == result);
    }

    #[test]
    fn test_send_message_stret() {
        let obj = test_utils::custom_object();
        let result: test_utils::CustomStruct = unsafe {
            send_message(&obj, sel!(customStruct), ())
        };
        let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
        assert!(result == expected);
    }
}
<|endoftext|>


<commit_before>use self::memory::EngineBtree;
use std::{error, result};
use std::fmt::{self, Display, Formatter};
use self::rocksdb::EngineRocksdb;

mod memory;
mod rocksdb;

#[derive(Debug)]
pub enum Modify<'a> {
    Delete(&'a [u8]),
    Put((&'a [u8], &'a [u8])),
}

pub trait Engine {
    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;
    fn seek(&self, key: &[u8]) -> Result<Option<(Vec<u8>, Vec<u8>)>>;
    fn write(&mut self, batch: Vec<Modify>) -> Result<()>;

    fn put(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
        self.write(vec![Modify::Put((key, value))])
    }

    fn delete(&mut self, key: &[u8]) -> Result<()> {
        self.write(vec![Modify::Delete(key)])
    }
}

#[derive(Debug)]
pub enum Dsn<'a> {
    Memory,
    RocksDBPath(&'a str),
}

pub fn new_engine(desc: Dsn) -> Result<Box<Engine>> {
    match desc {
        Dsn::Memory => Ok(Box::new(EngineBtree::new())),
        Dsn::RocksDBPath(path) => {
            EngineRocksdb::new(path).map(|engine| -> Box<Engine> { Box::new(engine) })
        }
    }
}

#[derive(Debug)]
pub enum Error {
    Other(Box<error::Error + Send + Sync>),
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Error::Other(ref error) => Display::fmt(error, f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::Other(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::Other(ref e) => e.cause(),
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

#[cfg(test)]
mod tests {
    use super::{Dsn, Engine, Modify};

    #[test]
    fn memory() {
        let mut e = super::new_engine(Dsn::Memory).unwrap();
        get_put(&mut *e);
        batch(&mut *e);
        seek(&mut *e);
    }

    #[test]
    fn rocksdb() {
        let mut e = super::new_engine(Dsn::RocksDBPath("/tmp/rocks")).unwrap();
        get_put(&mut *e);
        batch(&mut *e);
        seek(&mut *e);
    }

    fn assert_has(engine: &Engine, key: &[u8], value: &[u8]) {
        assert_eq!(engine.get(key).unwrap().unwrap(), value);
    }

    fn assert_none(engine: &Engine, key: &[u8]) {
        assert_eq!(engine.get(key).unwrap(), None);
    }

    fn assert_seek(engine: &Engine, key: &[u8], pair: (&[u8], &[u8])) {
        let (k, v) = engine.seek(key).unwrap().unwrap();
        assert_eq!(k, pair.0);
        assert_eq!(v, pair.1);
    }

    fn get_put(engine: &mut Engine) {
        assert_none(engine, b"x");
        engine.put(b"x", b"1").unwrap();
        assert_has(engine, b"x", b"1");
        engine.put(b"x", b"2").unwrap();
        assert_has(engine, b"x", b"2");
        engine.delete(b"x").unwrap();
        assert_none(engine, b"x");
    }

    fn batch(engine: &mut Engine) {
        engine.write(vec![Modify::Put((b"x", b"1")), Modify::Put((b"y", b"2"))]).unwrap();
        assert_has(engine, b"x", b"1");
        assert_has(engine, b"y", b"2");

        engine.write(vec![Modify::Delete(b"x"), Modify::Delete(b"y")]).unwrap();
        assert_none(engine, b"y");
        assert_none(engine, b"y");
    }

    fn seek(engine: &mut Engine) {
        engine.put(b"x", b"1").unwrap();
        assert_seek(engine, b"x", (b"x", b"1"));
        assert_seek(engine, b"a", (b"x", b"1"));
        engine.put(b"z", b"2").unwrap();
        assert_seek(engine, b"y", (b"z", b"2"));
        assert_seek(engine, b"x\x00", (b"z", b"2"));
        assert_eq!(engine.seek(b"z\x00").unwrap(), None);
        engine.delete(b"x").unwrap();
        engine.delete(b"z").unwrap();
    }
}
<commit_msg>storage: simplify engine test as well<commit_after>use self::memory::EngineBtree;
use std::{error, result};
use std::fmt::{self, Display, Formatter};
use self::rocksdb::EngineRocksdb;

mod memory;
mod rocksdb;

#[derive(Debug)]
pub enum Modify<'a> {
    Delete(&'a [u8]),
    Put((&'a [u8], &'a [u8])),
}

pub trait Engine {
    fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;
    fn seek(&self, key: &[u8]) -> Result<Option<(Vec<u8>, Vec<u8>)>>;
    fn write(&mut self, batch: Vec<Modify>) -> Result<()>;

    fn put(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
        self.write(vec![Modify::Put((key, value))])
    }

    fn delete(&mut self, key: &[u8]) -> Result<()> {
        self.write(vec![Modify::Delete(key)])
    }
}

#[derive(Debug)]
pub enum Dsn<'a> {
    Memory,
    RocksDBPath(&'a str),
}

pub fn new_engine(desc: Dsn) -> Result<Box<Engine>> {
    match desc {
        Dsn::Memory => Ok(Box::new(EngineBtree::new())),
        Dsn::RocksDBPath(path) => {
            EngineRocksdb::new(path).map(|engine| -> Box<Engine> { Box::new(engine) })
        }
    }
}

#[derive(Debug)]
pub enum Error {
    Other(Box<error::Error + Send + Sync>),
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Error::Other(ref error) => Display::fmt(error, f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::Other(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::Other(ref e) => e.cause(),
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

#[cfg(test)]
mod tests {
    use super::{Dsn, Engine, Modify};

    #[test]
    fn memory() {
        let mut e = super::new_engine(Dsn::Memory).unwrap();
        get_put(e.as_mut());
        batch(e.as_mut());
        seek(e.as_mut());
    }

    #[test]
    fn rocksdb() {
        let mut e = super::new_engine(Dsn::RocksDBPath("/tmp/rocks")).unwrap();
        get_put(e.as_mut());
        batch(e.as_mut());
        seek(e.as_mut());
    }

    fn assert_has<T: Engine + ?Sized>(engine: &T, key: &[u8], value: &[u8]) {
        assert_eq!(engine.get(key).unwrap().unwrap(), value);
    }

    fn assert_none<T: Engine + ?Sized>(engine: &T, key: &[u8]) {
        assert_eq!(engine.get(key).unwrap(), None);
    }

    fn assert_seek<T: Engine + ?Sized>(engine: &T, key: &[u8], pair: (&[u8], &[u8])) {
        let (k, v) = engine.seek(key).unwrap().unwrap();
        assert_eq!(k, pair.0);
        assert_eq!(v, pair.1);
    }

    fn get_put<T: Engine + ?Sized>(engine: &mut T) {
        assert_none(engine, b"x");
        engine.put(b"x", b"1").unwrap();
        assert_has(engine, b"x", b"1");
        engine.put(b"x", b"2").unwrap();
        assert_has(engine, b"x", b"2");
        engine.delete(b"x").unwrap();
        assert_none(engine, b"x");
    }

    fn batch<T: Engine + ?Sized>(engine: &mut T) {
        engine.write(vec![Modify::Put((b"x", b"1")), Modify::Put((b"y", b"2"))]).unwrap();
        assert_has(engine, b"x", b"1");
        assert_has(engine, b"y", b"2");

        engine.write(vec![Modify::Delete(b"x"), Modify::Delete(b"y")]).unwrap();
        assert_none(engine, b"y");
        assert_none(engine, b"y");
    }

    fn seek<T: Engine + ?Sized>(engine: &mut T) {
        engine.put(b"x", b"1").unwrap();
        assert_seek(engine, b"x", (b"x", b"1"));
        assert_seek(engine, b"a", (b"x", b"1"));
        engine.put(b"z", b"2").unwrap();
        assert_seek(engine, b"y", (b"z", b"2"));
        assert_seek(engine, b"x\x00", (b"z", b"2"));
        assert_eq!(engine.seek(b"z\x00").unwrap(), None);
        engine.delete(b"x").unwrap();
        engine.delete(b"z").unwrap();
    }
}
<|endoftext|>