<commit_before>//////////// Brush cache boilerplate ////////////

use std::cell::{RefCell};
use calx::{ImageStore, IndexCache};
use calx::backend::{CanvasBuilder, Image};

cache_key!(Brush);

impl Brush {
    /// Get the sprite image.
    pub fn get(self, idx: usize) -> Image {
        BRUSH_CACHE.with(|c| c.borrow().get(self).expect("Brush not found")[idx])
    }

    /// Build the actual sprites in a canvas for the enum set.
    pub fn init(builder: &mut CanvasBuilder) {
        BRUSH_CACHE.with(|c| { *c.borrow_mut() = build_brushes(builder); });
    }
}

thread_local!(static BRUSH_CACHE: RefCell<IndexCache<Brush, Vec<Image>>> = RefCell::new(IndexCache::new()));

//////////// Custom definitions start here ////////////

#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
pub enum Brush {
    Logo,

    IconHeart,
    IconHalfHeart,
    IconNoHeart,
    IconShard,
    IconHalfShard,
    IconNoShard,

    BlockRear,
    BlockRock,

    BrickWall,
    BrickWindowWall,
    BrickOpenWall,
    DoorWall,
    BarsWall,
    FenceWall,
    HouseWall,
    RockWall,

    BlankFloor,
    Floor,
    Grass,
    Water,
    Shallows,

    Human,
    Snake,
    Dreg,
    Ogre,
    Wraith,
    Octopus,
    Bug,
    Ooze,
    Efreet,
    Serpent,
    SerpentMound,

    CursorBottom,
    CursorTop,
    Table,
    Stone,
    Fountain,
    Altar,
    Barrell,
    Stalagmite,
    Pillar,
    Grave,
    Crystal,
    Menhir,
    Sword,
    Helmet,
    Potion,
    Wand,
    Health,
    Knives,
    Armor,
    Ring,
    StairsDown,
    TreeTrunk,
    TreeFoliage,
}

fn build_brushes(builder: &mut CanvasBuilder) -> IndexCache<Brush, Vec<Image>> {
    use image;
    use calx::{V2, IterTiles, color_key, color, Rgba};
    use self::Brush::*;

    fn load(data: &'static [u8]) -> image::ImageBuffer<image::Rgba<u8>, Vec<u8>> {
        color_key(&image::load_from_memory(data).unwrap(), color::CYAN)
    }

    let offset = V2(-16, -16);
    let size = V2(32, 32);

    let mut ret = IndexCache::new();

    for (k, img) in vec![
        BlankFloor,
        Floor,
        Grass,
        Water,
        Shallows,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/floors.png")))) {
        ret.insert(k, vec![img]);
    }

    for (k, img) in vec![
        Human,
        Snake,
        Dreg,
        Ogre,
        Wraith,
        Octopus,
        Bug,
        Ooze,
        Efreet,
        Serpent,
        SerpentMound,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/mobs.png")))) {
        ret.insert(k, vec![img]);
    }

    for (k, img) in vec![
        CursorBottom,
        CursorTop,
        Table,
        Stone,
        Fountain,
        Altar,
        Barrell,
        Stalagmite,
        Pillar,
        Grave,
        Crystal,
        Menhir,
        Sword,
        Helmet,
        Potion,
        Wand,
        Health,
        Knives,
        Armor,
        Ring,
        StairsDown,
        TreeTrunk,
        TreeFoliage,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/props.png")))) {
        ret.insert(k, vec![img]);
    }

    // Wall tiles.
    {
        let mut wall_images = Vec::new();
        let mut wall_sheet = load(include_bytes!("../assets/walls.png"));
        // Can't use batch_add for walls because the offsets alternate.
        for (i, rect) in wall_sheet.tiles(V2(16, 32)).take(28).enumerate() {
            let offset = V2(if i % 2 == 0 { -16 } else { 0 }, -16);
            let image = image::SubImage::new(&mut wall_sheet, rect.mn().0, rect.mn().1, rect.dim().0, rect.dim().1);
            wall_images.push(builder.add_image(offset, &image));
        }

        // Also I'm reusing the center wall piece a bit so I can't generalize
        // these either.

        ret.insert(BrickWall, vec![0, 1, 2, 3]          .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BrickWindowWall, vec![0, 1, 4, 5]    .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BrickOpenWall, vec![0, 1, 6, 7]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(DoorWall, vec![8, 9, 10, 11]         .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BarsWall, vec![12, 13, 14, 15]       .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(FenceWall, vec![16, 17, 18, 19]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(HouseWall, vec![20, 21, 22, 23]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(RockWall, vec![24, 25, 26, 27]       .into_iter().map(|x| wall_images[x]).collect());
    }

    // Block tiles
    {
        let mut block_sheet = load(include_bytes!("../assets/blocks.png"));

        for (y, brush) in vec![
            BlockRear,
            BlockRock,
        ].into_iter().enumerate() {
            // Another tricky setup. The first three tiles are 32x32 brushes,
            // the last four are 16x32.
            let mut frames = Vec::new();
            let y = y as u32;
            let mut x = 0u32;
            for &width in &[32, 32, 32, 16, 16, 16, 16] {
                let offset = (x as i32 % 32) - 16;
                frames.push(builder.add_image(V2(offset, -16),
                    &image::SubImage::new(&mut block_sheet, x, y * 32, width, 32)));
                x += width;
            }

            ret.insert(brush, frames)
        }
    }

    ret.insert(Logo, vec![builder.add_image(V2(0, 0), &load(include_bytes!("../assets/logo.png")))]);

    for (k, img) in vec![
        IconHeart,
        IconHalfHeart,
        IconNoHeart,
        IconShard,
        IconHalfShard,
        IconNoShard,
    ].into_iter().zip(
        builder.batch_add(V2(0, -8), V2(8, 8), &mut load(include_bytes!("../assets/icon.png")))) {
        ret.insert(k, vec![img]);
    }

    ret
}
<commit_msg>WIP (a lot) dead simple macro sprite entry<commit_after>//////////// Brush cache boilerplate ////////////

use std::cell::{RefCell};
use calx::{ImageStore, IndexCache};
use calx::backend::{CanvasBuilder, Image};

#[macro_export]
macro_rules! brush {
    {
        $enumname:ident {
            // Image file to load brushes from.
            $([$filename:expr]
              // Named brushes
              $($brushname:ident:
                  // Frames for the named brush as rectangles in the current
                  // image file.
                  $($xoff:expr, $yoff:expr, $xdim:expr, $ydim:expr, $x:expr, $y:expr;)+
              )+
            )+
        }
    } =>
    {
#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
        pub enum $enumname {
            $(
                $($brushname,)*
            )*
        }

        cache_key!($enumname);

        impl $enumname {
            /// Get the sprite image.
            pub fn get(self, idx: usize) -> Image {
                BRUSH_CACHE.with(|c| c.borrow().get(self).expect("Brush not initialized")[idx])
            }

            /// Build the actual sprites in a canvas for the enum set.
            pub fn init(builder: &mut CanvasBuilder) {
                BRUSH_CACHE.with(|c| { *c.borrow_mut() = build_brushes(builder); });
            }
        }

        thread_local!(static BRUSH_CACHE: RefCell<IndexCache<Brush, Vec<Image>>> = RefCell::new(IndexCache::new()));

        fn build_brushes(builder: &mut CanvasBuilder) -> IndexCache<Brush, Vec<Image>> {
            use image;
            use calx::{V2, color_key, color, Rgba};

            let mut ret = IndexCache::new();

            fn load(data: &'static [u8]) -> image::ImageBuffer<image::Rgba<u8>, Vec<u8>> {
                // XXX: Shouldn't hardcode the color::CYAN part, factor out
                // the loader?
                color_key(&image::load_from_memory(data).unwrap(), color::CYAN)
            }

            $({
                let mut sheet = load(include_bytes!($filename));

                $({
                    let mut frames = Vec::new();

                    $({
                        frames.push(builder.add_image(
                                V2($xoff, $yoff),
                                &image::SubImage::new(&mut sheet, $x, $y, $xdim, $ydim)));
                    })*

                    ret.insert($enumname::$brushname, frames);
                })*

            })*

            ret
        }
    }
}

/*
cache_key!(Brush);

impl Brush {
    /// Get the sprite image.
    pub fn get(self, idx: usize) -> Image {
        BRUSH_CACHE.with(|c| c.borrow().get(self).expect("Brush not found")[idx])
    }

    /// Build the actual sprites in a canvas for the enum set.
    pub fn init(builder: &mut CanvasBuilder) {
        BRUSH_CACHE.with(|c| { *c.borrow_mut() = build_brushes(builder); });
    }
}

thread_local!(static BRUSH_CACHE: RefCell<IndexCache<Brush, Vec<Image>>> = RefCell::new(IndexCache::new()));
*/

brush!(Brush {
    ["../assets/logo.png"]
    Logo:
        0, 0, 92, 24, 0, 0;

    /*
    IconHeart,
    IconHalfHeart,
    IconNoHeart,
    IconShard,
    IconHalfShard,
    IconNoShard,

    BlockRear,
    BlockRock,

    BrickWall,
    BrickWindowWall,
    BrickOpenWall,
    DoorWall,
    BarsWall,
    FenceWall,
    HouseWall,
    RockWall,

    BlankFloor,
    Floor,
    Grass,
    Water,
    Shallows,

    Human,
    Snake,
    Dreg,
    Ogre,
    Wraith,
    Octopus,
    Bug,
    Ooze,
    Efreet,
    Serpent,
    SerpentMound,

    CursorBottom,
    CursorTop,
    Table,
    Stone,
    Fountain,
    Altar,
    Barrell,
    Stalagmite,
    Pillar,
    Grave,
    Crystal,
    Menhir,
    Sword,
    Helmet,
    Potion,
    Wand,
    Health,
    Knives,
    Armor,
    Ring,
    StairsDown,
    TreeTrunk,
    TreeFoliage,
    */
});

//////////// Custom definitions start here ////////////

/*
#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
pub enum Brush {
    Logo,

    IconHeart,
    IconHalfHeart,
    IconNoHeart,
    IconShard,
    IconHalfShard,
    IconNoShard,

    BlockRear,
    BlockRock,

    BrickWall,
    BrickWindowWall,
    BrickOpenWall,
    DoorWall,
    BarsWall,
    FenceWall,
    HouseWall,
    RockWall,

    BlankFloor,
    Floor,
    Grass,
    Water,
    Shallows,

    Human,
    Snake,
    Dreg,
    Ogre,
    Wraith,
    Octopus,
    Bug,
    Ooze,
    Efreet,
    Serpent,
    SerpentMound,

    CursorBottom,
    CursorTop,
    Table,
    Stone,
    Fountain,
    Altar,
    Barrell,
    Stalagmite,
    Pillar,
    Grave,
    Crystal,
    Menhir,
    Sword,
    Helmet,
    Potion,
    Wand,
    Health,
    Knives,
    Armor,
    Ring,
    StairsDown,
    TreeTrunk,
    TreeFoliage,
}

fn build_brushes(builder: &mut CanvasBuilder) -> IndexCache<Brush, Vec<Image>> {
    use image;
    use calx::{V2, IterTiles, color_key, color, Rgba};
    use self::Brush::*;

    fn load(data: &'static [u8]) -> image::ImageBuffer<image::Rgba<u8>, Vec<u8>> {
        color_key(&image::load_from_memory(data).unwrap(), color::CYAN)
    }

    let offset = V2(-16, -16);
    let size = V2(32, 32);

    let mut ret = IndexCache::new();

    for (k, img) in vec![
        BlankFloor,
        Floor,
        Grass,
        Water,
        Shallows,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/floors.png")))) {
        ret.insert(k, vec![img]);
    }

    for (k, img) in vec![
        Human,
        Snake,
        Dreg,
        Ogre,
        Wraith,
        Octopus,
        Bug,
        Ooze,
        Efreet,
        Serpent,
        SerpentMound,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/mobs.png")))) {
        ret.insert(k, vec![img]);
    }

    for (k, img) in vec![
        CursorBottom,
        CursorTop,
        Table,
        Stone,
        Fountain,
        Altar,
        Barrell,
        Stalagmite,
        Pillar,
        Grave,
        Crystal,
        Menhir,
        Sword,
        Helmet,
        Potion,
        Wand,
        Health,
        Knives,
        Armor,
        Ring,
        StairsDown,
        TreeTrunk,
        TreeFoliage,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/props.png")))) {
        ret.insert(k, vec![img]);
    }

    // Wall tiles.
    {
        let mut wall_images = Vec::new();
        let mut wall_sheet = load(include_bytes!("../assets/walls.png"));
        // Can't use batch_add for walls because the offsets alternate.
        for (i, rect) in wall_sheet.tiles(V2(16, 32)).take(28).enumerate() {
            let offset = V2(if i % 2 == 0 { -16 } else { 0 }, -16);
            let image = image::SubImage::new(&mut wall_sheet, rect.mn().0, rect.mn().1, rect.dim().0, rect.dim().1);
            wall_images.push(builder.add_image(offset, &image));
        }

        // Also I'm reusing the center wall piece a bit so I can't generalize
        // these either.

        ret.insert(BrickWall, vec![0, 1, 2, 3]          .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BrickWindowWall, vec![0, 1, 4, 5]    .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BrickOpenWall, vec![0, 1, 6, 7]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(DoorWall, vec![8, 9, 10, 11]         .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BarsWall, vec![12, 13, 14, 15]       .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(FenceWall, vec![16, 17, 18, 19]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(HouseWall, vec![20, 21, 22, 23]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(RockWall, vec![24, 25, 26, 27]       .into_iter().map(|x| wall_images[x]).collect());
    }

    // Block tiles
    {
        let mut block_sheet = load(include_bytes!("../assets/blocks.png"));

        for (y, brush) in vec![
            BlockRear,
            BlockRock,
        ].into_iter().enumerate() {
            // Another tricky setup. The first three tiles are 32x32 brushes,
            // the last four are 16x32.
            let mut frames = Vec::new();
            let y = y as u32;
            let mut x = 0u32;
            for &width in &[32, 32, 32, 16, 16, 16, 16] {
                let offset = (x as i32 % 32) - 16;
                frames.push(builder.add_image(V2(offset, -16),
                    &image::SubImage::new(&mut block_sheet, x, y * 32, width, 32)));
                x += width;
            }

            ret.insert(brush, frames)
        }
    }

    ret.insert(Logo, vec![builder.add_image(V2(0, 0), &load(include_bytes!("../assets/logo.png")))]);

    for (k, img) in vec![
        IconHeart,
        IconHalfHeart,
        IconNoHeart,
        IconShard,
        IconHalfShard,
        IconNoShard,
    ].into_iter().zip(
        builder.batch_add(V2(0, -8), V2(8, 8), &mut load(include_bytes!("../assets/icon.png")))) {
        ret.insert(k, vec![img]);
    }

    ret
}
*/
<|endoftext|>


<commit_before>use cairo::{self, MatrixTrait};
use cairo_sys;
use glib::translate::*;
use libc;
use std::cell::Cell;

use attributes::Attribute;
use coord_units::CoordUnits;
use draw;
use drawing_ctx::{self, RsvgDrawingCtx};
use handle::RsvgHandle;
use length::{LengthDir, RsvgLength};
use node::{boxed_node_new, NodeResult, NodeTrait, NodeType, RsvgCNodeImpl, RsvgNode};
use parsers::{parse, Parse};
use property_bag::PropertyBag;
use state::{ComputedValues, Opacity};

coord_units!(MaskUnits, CoordUnits::ObjectBoundingBox);
coord_units!(MaskContentUnits, CoordUnits::UserSpaceOnUse);

// remove this once cairo-rs has this mask_surface()
fn cairo_mask_surface(cr: &cairo::Context, surface: &cairo::Surface, x: f64, y: f64) {
    unsafe {
        let raw_cr = cr.to_glib_none().0;

        cairo_sys::cairo_mask_surface(raw_cr, surface.to_raw_none(), x, y);
    }
}

pub struct NodeMask {
    x: Cell<RsvgLength>,
    y: Cell<RsvgLength>,
    width: Cell<RsvgLength>,
    height: Cell<RsvgLength>,

    units: Cell<MaskUnits>,
    content_units: Cell<MaskContentUnits>,
}

impl NodeMask {
    fn new() -> NodeMask {
        NodeMask {
            x: Cell::new(NodeMask::get_default_pos(LengthDir::Horizontal)),
            y: Cell::new(NodeMask::get_default_pos(LengthDir::Vertical)),

            width: Cell::new(NodeMask::get_default_size(LengthDir::Horizontal)),
            height: Cell::new(NodeMask::get_default_size(LengthDir::Vertical)),

            units: Cell::new(MaskUnits::default()),
            content_units: Cell::new(MaskContentUnits::default()),
        }
    }

    fn get_default_pos(dir: LengthDir) -> RsvgLength {
        RsvgLength::parse("-10%", dir).unwrap()
    }

    fn get_default_size(dir: LengthDir) -> RsvgLength {
        RsvgLength::parse("120%", dir).unwrap()
    }

    pub fn generate_cairo_mask(&self, node: &RsvgNode, draw_ctx: *mut RsvgDrawingCtx) {
        let values = &node.get_computed_values();

        let width = drawing_ctx::get_width(draw_ctx) as i32;
        let height = drawing_ctx::get_height(draw_ctx) as i32;

        let mut surface = match cairo::ImageSurface::create(cairo::Format::ARgb32, width, height) {
            Ok(surface) => surface,
            Err(_) => return,
        };

        let mask_units = CoordUnits::from(self.units.get());
        let content_units = CoordUnits::from(self.content_units.get());

        if mask_units == CoordUnits::ObjectBoundingBox {
            drawing_ctx::push_view_box(draw_ctx, 1.0, 1.0);
        }

        let x = self.x.get().normalize(values, draw_ctx);
        let y = self.y.get().normalize(values, draw_ctx);
        let w = self.width.get().normalize(values, draw_ctx);
        let h = self.height.get().normalize(values, draw_ctx);

        if mask_units == CoordUnits::ObjectBoundingBox {
            drawing_ctx::pop_view_box(draw_ctx);
        }

        // Use a scope because mask_cr needs to release the
        // reference to the surface before we access the pixels
        {
            let save_cr = drawing_ctx::get_cairo_context(draw_ctx);

            let mask_cr = cairo::Context::new(&surface);
            mask_cr.set_matrix(save_cr.get_matrix());

            drawing_ctx::set_cairo_context(draw_ctx, &mask_cr);

            if mask_units == CoordUnits::ObjectBoundingBox {
                let bbox = drawing_ctx::get_bbox(draw_ctx);
                let rect = bbox.rect.unwrap();

                draw::add_clipping_rect(
                    draw_ctx,
                    &node.get_transform(),
                    x * rect.width + rect.x,
                    y * rect.height + rect.y,
                    w * rect.width,
                    h * rect.height,
                );
            } else {
                draw::add_clipping_rect(draw_ctx, &node.get_transform(), x, y, w, h);
            }

            if content_units == CoordUnits::ObjectBoundingBox {
                let bbox = drawing_ctx::get_bbox(draw_ctx);
                let rect = bbox.rect.unwrap();
                let bbtransform =
                    cairo::Matrix::new(rect.width, 0.0, 0.0, rect.height, rect.x, rect.y);

                mask_cr.transform(bbtransform);

                drawing_ctx::push_view_box(draw_ctx, 1.0, 1.0);
            }

            drawing_ctx::state_push(draw_ctx);
            node.draw_children(values, draw_ctx, 0, false);
            drawing_ctx::state_pop(draw_ctx);

            if content_units == CoordUnits::ObjectBoundingBox {
                drawing_ctx::pop_view_box(draw_ctx);
            }

            drawing_ctx::set_cairo_context(draw_ctx, &save_cr);
        }

        {
            let rowstride = surface.get_stride() as usize;
            let mut pixels = surface.get_data().unwrap();
            let opacity = {
                let Opacity(o) = values.opacity;
                u8::from(o)
            };

            for row in pixels.chunks_mut(rowstride) {
                for p in row[..4 * width as usize].chunks_mut(4) {
                    //  Assuming, the pixel is linear RGB (not sRGB)
                    //  y = luminance
                    //  Y = 0.2126 R + 0.7152 G + 0.0722 B
                    //  1.0 opacity = 255
                    //
                    //  When Y = 1.0, pixel for mask should be 0xFFFFFFFF
                    //    (you get 1.0 luminance from 255 from R, G and B)
                    //
                    // r_mult = 0xFFFFFFFF / (255.0 * 255.0) * .2126 = 14042.45  ~= 14042
                    // g_mult = 0xFFFFFFFF / (255.0 * 255.0) * .7152 = 47239.69  ~= 47240
                    // b_mult = 0xFFFFFFFF / (255.0 * 255.0) * .0722 =  4768.88  ~= 4769
                    //
                    // This allows for the following expected behaviour:
                    //    (we only care about the most sig byte)
                    // if pixel = 0x00FFFFFF, pixel' = 0xFF......
                    // if pixel = 0x00020202, pixel' = 0x02......
                    // if pixel = 0x00000000, pixel' = 0x00......
                    //
                    // NOTE: the following assumes little-endian
                    let (r, g, b, o) = (p[2] as u32, p[1] as u32, p[0] as u32, opacity as u32);
                    p[3] = (((r * 14042 + g * 47240 + b * 4769) * o) >> 24) as u8;
                }
            }
        }

        let cr = drawing_ctx::get_cairo_context(draw_ctx);
        cr.save();
        cr.identity_matrix();

        let (xofs, yofs) = drawing_ctx::get_offset(draw_ctx);
        cairo_mask_surface(&cr, &surface, xofs, yofs);
        cr.restore();
    }
}

impl NodeTrait for NodeMask {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal, None)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical, None)?),
                Attribute::Width => self.width.set(parse(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    Some(RsvgLength::check_nonnegative),
                )?),
                Attribute::Height => self.height.set(parse(
                    "height",
                    value,
                    LengthDir::Vertical,
                    Some(RsvgLength::check_nonnegative),
                )?),

                Attribute::MaskUnits => self.units.set(parse("maskUnits", value, (), None)?),

                Attribute::MaskContentUnits => {
                    self.content_units
                        .set(parse("maskContentUnits", value, (), None)?)
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(&self, _: &RsvgNode, _: &ComputedValues, _: *mut RsvgDrawingCtx, _: i32, _: bool) {
        // nothing; masks are handled specially
    }

    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        unreachable!();
    }
}

#[no_mangle]
pub extern "C" fn rsvg_node_mask_new(
    _: *const libc::c_char,
    raw_parent: *const RsvgNode,
) -> *const RsvgNode {
    boxed_node_new(NodeType::Mask, raw_parent, Box::new(NodeMask::new()))
}
<commit_msg>mask.rs: Remove unnecessary cr.save()/restore()<commit_after>use cairo::{self, MatrixTrait};
use cairo_sys;
use glib::translate::*;
use libc;
use std::cell::Cell;

use attributes::Attribute;
use coord_units::CoordUnits;
use draw;
use drawing_ctx::{self, RsvgDrawingCtx};
use handle::RsvgHandle;
use length::{LengthDir, RsvgLength};
use node::{boxed_node_new, NodeResult, NodeTrait, NodeType, RsvgCNodeImpl, RsvgNode};
use parsers::{parse, Parse};
use property_bag::PropertyBag;
use state::{ComputedValues, Opacity};

coord_units!(MaskUnits, CoordUnits::ObjectBoundingBox);
coord_units!(MaskContentUnits, CoordUnits::UserSpaceOnUse);

// remove this once cairo-rs has this mask_surface()
fn cairo_mask_surface(cr: &cairo::Context, surface: &cairo::Surface, x: f64, y: f64) {
    unsafe {
        let raw_cr = cr.to_glib_none().0;

        cairo_sys::cairo_mask_surface(raw_cr, surface.to_raw_none(), x, y);
    }
}

pub struct NodeMask {
    x: Cell<RsvgLength>,
    y: Cell<RsvgLength>,
    width: Cell<RsvgLength>,
    height: Cell<RsvgLength>,

    units: Cell<MaskUnits>,
    content_units: Cell<MaskContentUnits>,
}

impl NodeMask {
    fn new() -> NodeMask {
        NodeMask {
            x: Cell::new(NodeMask::get_default_pos(LengthDir::Horizontal)),
            y: Cell::new(NodeMask::get_default_pos(LengthDir::Vertical)),

            width: Cell::new(NodeMask::get_default_size(LengthDir::Horizontal)),
            height: Cell::new(NodeMask::get_default_size(LengthDir::Vertical)),

            units: Cell::new(MaskUnits::default()),
            content_units: Cell::new(MaskContentUnits::default()),
        }
    }

    fn get_default_pos(dir: LengthDir) -> RsvgLength {
        RsvgLength::parse("-10%", dir).unwrap()
    }

    fn get_default_size(dir: LengthDir) -> RsvgLength {
        RsvgLength::parse("120%", dir).unwrap()
    }

    pub fn generate_cairo_mask(&self, node: &RsvgNode, draw_ctx: *mut RsvgDrawingCtx) {
        let values = &node.get_computed_values();

        let width = drawing_ctx::get_width(draw_ctx) as i32;
        let height = drawing_ctx::get_height(draw_ctx) as i32;

        let mut surface = match cairo::ImageSurface::create(cairo::Format::ARgb32, width, height) {
            Ok(surface) => surface,
            Err(_) => return,
        };

        let mask_units = CoordUnits::from(self.units.get());
        let content_units = CoordUnits::from(self.content_units.get());

        if mask_units == CoordUnits::ObjectBoundingBox {
            drawing_ctx::push_view_box(draw_ctx, 1.0, 1.0);
        }

        let x = self.x.get().normalize(values, draw_ctx);
        let y = self.y.get().normalize(values, draw_ctx);
        let w = self.width.get().normalize(values, draw_ctx);
        let h = self.height.get().normalize(values, draw_ctx);

        if mask_units == CoordUnits::ObjectBoundingBox {
            drawing_ctx::pop_view_box(draw_ctx);
        }

        // Use a scope because mask_cr needs to release the
        // reference to the surface before we access the pixels
        {
            let save_cr = drawing_ctx::get_cairo_context(draw_ctx);

            let mask_cr = cairo::Context::new(&surface);
            mask_cr.set_matrix(save_cr.get_matrix());

            drawing_ctx::set_cairo_context(draw_ctx, &mask_cr);

            if mask_units == CoordUnits::ObjectBoundingBox {
                let bbox = drawing_ctx::get_bbox(draw_ctx);
                let rect = bbox.rect.unwrap();

                draw::add_clipping_rect(
                    draw_ctx,
                    &node.get_transform(),
                    x * rect.width + rect.x,
                    y * rect.height + rect.y,
                    w * rect.width,
                    h * rect.height,
                );
            } else {
                draw::add_clipping_rect(draw_ctx, &node.get_transform(), x, y, w, h);
            }

            if content_units == CoordUnits::ObjectBoundingBox {
                let bbox = drawing_ctx::get_bbox(draw_ctx);
                let rect = bbox.rect.unwrap();
                let bbtransform =
                    cairo::Matrix::new(rect.width, 0.0, 0.0, rect.height, rect.x, rect.y);

                mask_cr.transform(bbtransform);

                drawing_ctx::push_view_box(draw_ctx, 1.0, 1.0);
            }

            drawing_ctx::state_push(draw_ctx);
            node.draw_children(values, draw_ctx, 0, false);
            drawing_ctx::state_pop(draw_ctx);

            if content_units == CoordUnits::ObjectBoundingBox {
                drawing_ctx::pop_view_box(draw_ctx);
            }

            drawing_ctx::set_cairo_context(draw_ctx, &save_cr);
        }

        {
            let rowstride = surface.get_stride() as usize;
            let mut pixels = surface.get_data().unwrap();
            let opacity = {
                let Opacity(o) = values.opacity;
                u8::from(o)
            };

            for row in pixels.chunks_mut(rowstride) {
                for p in row[..4 * width as usize].chunks_mut(4) {
                    //  Assuming, the pixel is linear RGB (not sRGB)
                    //  y = luminance
                    //  Y = 0.2126 R + 0.7152 G + 0.0722 B
                    //  1.0 opacity = 255
                    //
                    //  When Y = 1.0, pixel for mask should be 0xFFFFFFFF
                    //    (you get 1.0 luminance from 255 from R, G and B)
                    //
                    // r_mult = 0xFFFFFFFF / (255.0 * 255.0) * .2126 = 14042.45  ~= 14042
                    // g_mult = 0xFFFFFFFF / (255.0 * 255.0) * .7152 = 47239.69  ~= 47240
                    // b_mult = 0xFFFFFFFF / (255.0 * 255.0) * .0722 =  4768.88  ~= 4769
                    //
                    // This allows for the following expected behaviour:
                    //    (we only care about the most sig byte)
                    // if pixel = 0x00FFFFFF, pixel' = 0xFF......
                    // if pixel = 0x00020202, pixel' = 0x02......
                    // if pixel = 0x00000000, pixel' = 0x00......
                    //
                    // NOTE: the following assumes little-endian
                    let (r, g, b, o) = (p[2] as u32, p[1] as u32, p[0] as u32, opacity as u32);
                    p[3] = (((r * 14042 + g * 47240 + b * 4769) * o) >> 24) as u8;
                }
            }
        }

        let cr = drawing_ctx::get_cairo_context(draw_ctx);

        cr.identity_matrix();

        let (xofs, yofs) = drawing_ctx::get_offset(draw_ctx);
        cairo_mask_surface(&cr, &surface, xofs, yofs);
    }
}

impl NodeTrait for NodeMask {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::X => self.x.set(parse("x", value, LengthDir::Horizontal, None)?),
                Attribute::Y => self.y.set(parse("y", value, LengthDir::Vertical, None)?),
                Attribute::Width => self.width.set(parse(
                    "width",
                    value,
                    LengthDir::Horizontal,
                    Some(RsvgLength::check_nonnegative),
                )?),
                Attribute::Height => self.height.set(parse(
                    "height",
                    value,
                    LengthDir::Vertical,
                    Some(RsvgLength::check_nonnegative),
                )?),

                Attribute::MaskUnits => self.units.set(parse("maskUnits", value, (), None)?),

                Attribute::MaskContentUnits => {
                    self.content_units
                        .set(parse("maskContentUnits", value, (), None)?)
                }

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(&self, _: &RsvgNode, _: &ComputedValues, _: *mut RsvgDrawingCtx, _: i32, _: bool) {
        // nothing; masks are handled specially
    }

    fn get_c_impl(&self) -> *const RsvgCNodeImpl {
        unreachable!();
    }
}

#[no_mangle]
pub extern "C" fn rsvg_node_mask_new(
    _: *const libc::c_char,
    raw_parent: *const RsvgNode,
) -> *const RsvgNode {
    boxed_node_new(NodeType::Mask, raw_parent, Box::new(NodeMask::new()))
}
<|endoftext|>


<commit_before>import std::sys;

#[test]
fn last_os_error() {
    log sys::last_os_error();
}
<commit_msg>stdlib: Add tests for sys::size_of and sys::align_of<commit_after>import std::sys;

#[test]
fn last_os_error() {
    log sys::last_os_error();
}

#[test]
fn size_of_basic() {
    assert sys::size_of::<u8>() == 1u;
    assert sys::size_of::<u16>() == 2u;
    assert sys::size_of::<u32>() == 4u;
    assert sys::size_of::<u64>() == 8u;
}

#[test]
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "arm")]
fn size_of_32() {
    assert sys::size_of::<uint>() == 4u;
    assert sys::size_of::<*uint>() == 4u;
}

#[test]
#[cfg(target_arch = "x86_64")]
fn size_of_64() {
    assert sys::size_of::<uint>() == 8u;
    assert sys::size_of::<*uint>() == 8u;
}

#[test]
fn align_of_basic() {
    assert sys::align_of::<u8>() == 1u;
    assert sys::align_of::<u16>() == 2u;
    assert sys::align_of::<u32>() == 4u;
}

#[test]
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "arm")]
fn align_of_32() {
    assert sys::align_of::<uint>() == 4u;
    assert sys::align_of::<*uint>() == 4u;
}

#[test]
#[cfg(target_arch = "x86_64")]
fn align_of_64() {
    assert sys::align_of::<uint>() == 8u;
    assert sys::align_of::<*uint>() == 8u;
}<|endoftext|>


<commit_before>#[macro_export]
macro_rules! matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => true,
            _ => false
        }
    }
}

#[macro_export]
macro_rules! assert_matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => (),
            ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
        }
    }
}

#[macro_export]
macro_rules! debug_assert_matches {
    ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_matches!($($arg)*); })
}

#[test]
fn matches_works() {
    let foo = Some("-12");
    assert!(matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    ));
}

#[test]
fn assert_matches_works() {
    let foo = Some("-12");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}

#[test]
#[should_panic(expected = "assertion failed: `Some(\"-AB\")` does not match ")]
fn assert_matches_panics() {
    let foo = Some("-AB");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}
<commit_msg>matches: Add docs and examples<commit_after>/// Check if an expression matches a refutable pattern.
///
/// Syntax: `matches!(` *expression* `,` *pattern* `)`
///
/// Return a boolean, true if the expression matches the pattern, false otherwise.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// pub enum Foo<T> {
///     A,
///     B(T),
/// }
///
/// impl<T> Foo<T> {
///     pub fn is_a(&self) -> bool {
///         matches!(*self, Foo::A)
///     }
///
///     pub fn is_b(&self) -> bool {
///         matches!(*self, Foo::B(_))
///     }
/// }
///
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => true,
            _ => false
        }
    }
}

/// Assert that an expression matches a refutable pattern.
///
/// Syntax: `assert_matches!(` *expression* `,` *pattern* `)`
///
/// Panic with a message that shows the expression if it does not match the
/// pattern.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! assert_matches {
    ($expression:expr, $($pattern:tt)+) => {
        match $expression {
            $($pattern)+ => (),
            ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)),
        }
    }
}

/// Assert that an expression matches a refutable pattern using debug assertions.
///
/// Syntax: `debug_assert_matches!(` *expression* `,` *pattern* `)`
///
/// If debug assertions are enabled, panic with a message that shows the
/// expression if it does not match the pattern.
///
/// When debug assertions are not enabled, this macro does nothing.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate matches;
///
/// fn main() {
///     let data = [1, 2, 3];
///     debug_assert_matches!(data.get(1), Some(_));
/// }
/// ```
#[macro_export]
macro_rules! debug_assert_matches {
    ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_matches!($($arg)*); })
}

#[test]
fn matches_works() {
    let foo = Some("-12");
    assert!(matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    ));
}

#[test]
fn assert_matches_works() {
    let foo = Some("-12");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}

#[test]
#[should_panic(expected = "assertion failed: `Some(\"-AB\")` does not match ")]
fn assert_matches_panics() {
    let foo = Some("-AB");
    assert_matches!(foo, Some(bar) if
        matches!(bar.as_bytes()[0], b'+' | b'-') &&
        matches!(bar.as_bytes()[1], b'0'...b'9')
    );
}
<|endoftext|>


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

use clap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;

use common::ui::{Status, UIWriter, UI};
use export_docker;
use export_docker::Result;
use export_k8s::{Manifest, ManifestJson};

use chartfile::ChartFile;
use deps::Deps;
use values::Values;

pub struct Chart<'a> {
    chartdir: PathBuf,
    chartfile: ChartFile,
    manifest_template: Option<ManifestJson>,
    values: Values,
    deps: Deps,
    ui: &'a mut UI,
}

impl<'a> Chart<'a> {
    pub fn new_for_cli_matches(ui: &'a mut UI, matches: &clap::ArgMatches) -> Result<Self> {
        let image = if !matches.is_present("NO_DOCKER_IMAGE") {
            export_docker::export_for_cli_matches(ui, &matches)?
        } else {
            None
        };
        let manifest = Manifest::new_from_cli_matches(ui, &matches, image)?;
        let chartfile = ChartFile::new_from_cli_matches(&matches, &manifest.pkg_ident)?;
        let deps = Deps::new_for_cli_matches(&matches);

        let mut chartdir = PathBuf::new();
        if let Some(o) = matches.value_of_os("OUTPUTDIR") {
            chartdir.push(o);
        }
        chartdir.push(&chartfile.name);

        Ok(Self::new_for_manifest(
            manifest, chartdir, chartfile, deps, ui,
        ))
    }

    fn new_for_manifest(
        manifest: Manifest,
        chartdir: PathBuf,
        chartfile: ChartFile,
        deps: Deps,
        ui: &'a mut UI,
    ) -> Self {
        let mut manifest_template = ManifestJson {
            value: json!({
            "metadata_name": "{{.Values.metadataName}}",
            "service_name": "{{.Values.serviceName}}",
            "image": "{{.Values.imageName}}",
            "count": "{{.Values.instanceCount}}",
            "service_topology": "{{.Values.serviceTopology}}",
            "service_group": manifest.service_group
                .as_ref()
                .map(|_| "{{.Values.serviceGroup}}"),
            "config": manifest.config
                .as_ref()
                .map(|_| "{{.Values.config}}"),
            "ring_secret_name": manifest.ring_secret_name
                .as_ref()
                .map(|_| "{{.Values.ringSecretName}}"),
            }),
        };

        let mut values = Values::new();
        values.add_entry("metadataName", &manifest.metadata_name);
        values.add_entry("serviceName", &manifest.pkg_ident.name);
        values.add_entry("imageName", &manifest.image);
        values.add_entry("instanceCount", &manifest.count.to_string());
        values.add_entry("serviceTopology", &manifest.service_topology.to_string());
        if let Some(ref group) = manifest.service_group {
            values.add_entry("serviceGroup", group);
        }
        if let Some(ref config) = manifest.config {
            values.add_entry("config", config);
        }
        if let Some(ref name) = manifest.ring_secret_name {
            values.add_entry("ringSecretName", name);
        }

        let mut binds = Vec::new();
        let mut i = 0;
        for bind in &manifest.binds {
            let name_var = format!("bindName{}", i);
            let service_var = format!("bindService{}", i);
            let group_var = format!("bindGroup{}", i);
            i = i + 1;

            values.add_entry(&name_var, &bind.name);
            values.add_entry(&service_var, &bind.service_group.service());
            values.add_entry(&group_var, &bind.service_group.group());

            let json = json!({
                "name": format!("{{{{.Values.{}}}}}", name_var),
                "service": format!("{{{{.Values.{}}}}}", service_var),
                "group": format!("{{{{.Values.{}}}}}", group_var),
            });

            binds.push(json);
        }
        manifest_template.value["binds"] = json!(binds);

        Chart {
            chartdir: chartdir,
            chartfile: chartfile,
            manifest_template: Some(manifest_template),
            values: values,
            deps: deps,
            ui: ui,
        }
    }

    pub fn generate(mut self) -> Result<()> {
        self.ui.status(
            Status::Creating,
            format!("directory `{}`", self.chartdir.display()),
        )?;
        fs::create_dir_all(&self.chartdir)?;

        self.generate_chartfile()?;
        self.generate_values()?;
        self.generate_manifest_template()?;
        self.generate_deps()?;

        self.download_deps()
    }

    fn generate_chartfile(&mut self) -> Result<()> {
        let mut write = self.create_file("Chart.yaml")?;
        let out = self.chartfile.into_string()?;

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_manifest_template(&mut self) -> Result<()> {
        let mut path = self.chartdir.clone();
        path.push("templates");
        self.ui
            .status(Status::Creating, format!("directory `{}`", path.display()))?;
        fs::create_dir_all(&path)?;

        path.push("habitat.yaml");
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;
        let mut write = fs::File::create(path)?;
        let out: String = self.manifest_template
            .take()
            .expect("generate_manifest_template() called more than once")
            .into();

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_values(&mut self) -> Result<()> {
        let mut write = self.create_file("values.yaml")?;
        self.values.generate(&mut write)?;

        Ok(())
    }

    fn generate_deps(&mut self) -> Result<()> {
        let mut write = self.create_file("requirements.yaml")?;
        self.deps.generate(&mut write)?;

        Ok(())
    }

    fn download_deps(&mut self) -> Result<()> {
        self.deps.download(&self.chartdir, self.ui)
    }

    fn create_file(&mut self, name: &str) -> Result<fs::File> {
        let mut path = self.chartdir.clone();
        path.push(name);
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;

        fs::File::create(path).map_err(From::from)
    }
}
<commit_msg>pkg-export-helm: Use an enumerating iterator instead of a counter<commit_after>// Copyright (c) 2018 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;

use common::ui::{Status, UIWriter, UI};
use export_docker;
use export_docker::Result;
use export_k8s::{Manifest, ManifestJson};

use chartfile::ChartFile;
use deps::Deps;
use values::Values;

pub struct Chart<'a> {
    chartdir: PathBuf,
    chartfile: ChartFile,
    manifest_template: Option<ManifestJson>,
    values: Values,
    deps: Deps,
    ui: &'a mut UI,
}

impl<'a> Chart<'a> {
    pub fn new_for_cli_matches(ui: &'a mut UI, matches: &clap::ArgMatches) -> Result<Self> {
        let image = if !matches.is_present("NO_DOCKER_IMAGE") {
            export_docker::export_for_cli_matches(ui, &matches)?
        } else {
            None
        };
        let manifest = Manifest::new_from_cli_matches(ui, &matches, image)?;
        let chartfile = ChartFile::new_from_cli_matches(&matches, &manifest.pkg_ident)?;
        let deps = Deps::new_for_cli_matches(&matches);

        let mut chartdir = PathBuf::new();
        if let Some(o) = matches.value_of_os("OUTPUTDIR") {
            chartdir.push(o);
        }
        chartdir.push(&chartfile.name);

        Ok(Self::new_for_manifest(
            manifest, chartdir, chartfile, deps, ui,
        ))
    }

    fn new_for_manifest(
        manifest: Manifest,
        chartdir: PathBuf,
        chartfile: ChartFile,
        deps: Deps,
        ui: &'a mut UI,
    ) -> Self {
        let mut manifest_template = ManifestJson {
            value: json!({
            "metadata_name": "{{.Values.metadataName}}",
            "service_name": "{{.Values.serviceName}}",
            "image": "{{.Values.imageName}}",
            "count": "{{.Values.instanceCount}}",
            "service_topology": "{{.Values.serviceTopology}}",
            "service_group": manifest.service_group
                .as_ref()
                .map(|_| "{{.Values.serviceGroup}}"),
            "config": manifest.config
                .as_ref()
                .map(|_| "{{.Values.config}}"),
            "ring_secret_name": manifest.ring_secret_name
                .as_ref()
                .map(|_| "{{.Values.ringSecretName}}"),
            }),
        };

        let mut values = Values::new();
        values.add_entry("metadataName", &manifest.metadata_name);
        values.add_entry("serviceName", &manifest.pkg_ident.name);
        values.add_entry("imageName", &manifest.image);
        values.add_entry("instanceCount", &manifest.count.to_string());
        values.add_entry("serviceTopology", &manifest.service_topology.to_string());
        if let Some(ref group) = manifest.service_group {
            values.add_entry("serviceGroup", group);
        }
        if let Some(ref config) = manifest.config {
            values.add_entry("config", config);
        }
        if let Some(ref name) = manifest.ring_secret_name {
            values.add_entry("ringSecretName", name);
        }

        let mut binds = Vec::new();
        for (i, bind) in manifest.binds.iter().enumerate() {
            let name_var = format!("bindName{}", i);
            let service_var = format!("bindService{}", i);
            let group_var = format!("bindGroup{}", i);

            values.add_entry(&name_var, &bind.name);
            values.add_entry(&service_var, &bind.service_group.service());
            values.add_entry(&group_var, &bind.service_group.group());

            let json = json!({
                "name": format!("{{{{.Values.{}}}}}", name_var),
                "service": format!("{{{{.Values.{}}}}}", service_var),
                "group": format!("{{{{.Values.{}}}}}", group_var),
            });

            binds.push(json);
        }
        manifest_template.value["binds"] = json!(binds);

        Chart {
            chartdir: chartdir,
            chartfile: chartfile,
            manifest_template: Some(manifest_template),
            values: values,
            deps: deps,
            ui: ui,
        }
    }

    pub fn generate(mut self) -> Result<()> {
        self.ui.status(
            Status::Creating,
            format!("directory `{}`", self.chartdir.display()),
        )?;
        fs::create_dir_all(&self.chartdir)?;

        self.generate_chartfile()?;
        self.generate_values()?;
        self.generate_manifest_template()?;
        self.generate_deps()?;

        self.download_deps()
    }

    fn generate_chartfile(&mut self) -> Result<()> {
        let mut write = self.create_file("Chart.yaml")?;
        let out = self.chartfile.into_string()?;

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_manifest_template(&mut self) -> Result<()> {
        let mut path = self.chartdir.clone();
        path.push("templates");
        self.ui
            .status(Status::Creating, format!("directory `{}`", path.display()))?;
        fs::create_dir_all(&path)?;

        path.push("habitat.yaml");
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;
        let mut write = fs::File::create(path)?;
        let out: String = self.manifest_template
            .take()
            .expect("generate_manifest_template() called more than once")
            .into();

        write.write(out.as_bytes())?;

        Ok(())
    }

    fn generate_values(&mut self) -> Result<()> {
        let mut write = self.create_file("values.yaml")?;
        self.values.generate(&mut write)?;

        Ok(())
    }

    fn generate_deps(&mut self) -> Result<()> {
        let mut write = self.create_file("requirements.yaml")?;
        self.deps.generate(&mut write)?;

        Ok(())
    }

    fn download_deps(&mut self) -> Result<()> {
        self.deps.download(&self.chartdir, self.ui)
    }

    fn create_file(&mut self, name: &str) -> Result<fs::File> {
        let mut path = self.chartdir.clone();
        path.push(name);
        self.ui
            .status(Status::Creating, format!("file `{}`", path.display()))?;

        fs::File::create(path).map_err(From::from)
    }
}
<|endoftext|>


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

// https://leetcode.com/problems/longest-palindrome-by-concatenating-two-letter-words/
pub fn longest_palindrome(words: Vec<String>) -> i32 {
    let mut map: HashMap<String, i32> = HashMap::new();
    for word in words.into_iter() {
        *map.entry(word).or_insert(0) += 1;
    }
    let mut answer = 0;
    while let Some((word, count)) = map.iter().next() {
        let bytes = word.as_bytes();
        if bytes[0] == bytes[1] {
            answer += *count * 2;
            map.remove(&word.clone());
        } else {
            let reversed_word: String = word.chars().rev().collect();
            if let Some(c) = map.get(&reversed_word) {
                answer += count.min(c) * 4;
                map.remove(&word.clone());
                map.remove(&reversed_word);
            } else {
                map.remove(&word.clone());
            }
        }
    }
    answer
}

fn main() {
    // println!(
    //     "{}",
    //     longest_palindrome(vec!["lc".to_string(), "cl".to_string(), "gg".to_string()])
    // ); // 6
    // println!(
    //     "{}",
    //     longest_palindrome(vec![
    //         "ab".to_string(),
    //         "ty".to_string(),
    //         "yt".to_string(),
    //         "lc".to_string(),
    //         "cl".to_string(),
    //         "ab".to_string()
    //     ])
    // ); // 8
    // println!(
    //     "{}",
    //     longest_palindrome(vec!["cc".to_string(), "ll".to_string(), "xx".to_string()])
    // ); // 2
    // println!(
    //     "{}",
    //     longest_palindrome(vec![
    //         "lc".to_string(),
    //         "cl".to_string(),
    //         "gg".to_string(),
    //         "gg".to_string(),
    //         "gg".to_string(),
    //         "aa".to_string(),
    //         "aa".to_string()
    //     ])
    // ); // 14
    println!(
        "{}",
        longest_palindrome(vec![
            "lc".to_string(),
            "cl".to_string(),
            "gg".to_string(),
            "gg".to_string(),
            "gg".to_string(),
            "aa".to_string()
        ])
    ); // 10
}
<commit_msg>Solve problem 2131<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/longest-palindrome-by-concatenating-two-letter-words/
pub fn longest_palindrome(words: Vec<String>) -> i32 {
    let mut map: HashMap<String, i32> = HashMap::new();
    for word in words.into_iter() {
        *map.entry(word).or_insert(0) += 1;
    }
    let mut answer = 0;
    let mut has_odd = false;
    while let Some((word, count)) = map.iter().next() {
        let bytes = word.as_bytes();
        if bytes[0] == bytes[1] {
            if *count % 2 != 0 {
                has_odd = true;
            }
            answer += if *count % 2 == 0 {
                *count * 2
            } else {
                (*count - 1) * 2
            };
            map.remove(&word.clone());
        } else {
            let reversed_word: String = word.chars().rev().collect();
            if let Some(c) = map.get(&reversed_word) {
                answer += count.min(c) * 4;
                map.remove(&word.clone());
                map.remove(&reversed_word);
            } else {
                map.remove(&word.clone());
            }
        }
    }
    if has_odd {
        answer + 2
    } else {
        answer
    }
}

fn main() {
    println!(
        "{}",
        longest_palindrome(vec!["lc".to_string(), "cl".to_string(), "gg".to_string()])
    ); // 6
    println!(
        "{}",
        longest_palindrome(vec![
            "ab".to_string(),
            "ty".to_string(),
            "yt".to_string(),
            "lc".to_string(),
            "cl".to_string(),
            "ab".to_string()
        ])
    ); // 8
    println!(
        "{}",
        longest_palindrome(vec!["cc".to_string(), "ll".to_string(), "xx".to_string()])
    ); // 2
    println!(
        "{}",
        longest_palindrome(vec![
            "lc".to_string(),
            "cl".to_string(),
            "gg".to_string(),
            "gg".to_string(),
            "gg".to_string(),
            "aa".to_string(),
            "aa".to_string()
        ])
    ); // 14
    println!(
        "{}",
        longest_palindrome(vec![
            "lc".to_string(),
            "cl".to_string(),
            "gg".to_string(),
            "gg".to_string(),
            "gg".to_string(),
            "aa".to_string()
        ])
    ); // 10
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/time-needed-to-rearrange-a-binary-string/
pub fn seconds_to_remove_occurrences(s: String) -> i32 {
    let mut answer = 0;
    let mut chars: Vec<char> = s.chars().collect();
    let mut i = 0;
    while i < chars.len() - 1 {
        if chars[i] == '0' && chars[i + 1] == '1' {
            chars.swap(i, i + 1);
            answer += 1;
        }
        i += 1;
    }
    answer
}

fn main() {
    println!("{}", seconds_to_remove_occurrences("0110101".to_string())); // 4
    println!("{}", seconds_to_remove_occurrences("11100".to_string())); // 0
    println!(
        "{}",
        seconds_to_remove_occurrences("1000111001010010010101010101".to_string())
    ); // 15
}
<commit_msg>Update problem 2380<commit_after>// https://leetcode.com/problems/time-needed-to-rearrange-a-binary-string/
pub fn seconds_to_remove_occurrences(s: String) -> i32 {
    let mut answer = 0;
    let mut chars: Vec<char> = s.chars().collect();
    let mut i = 0;
    while i < chars.len() - 1 {
        if chars[i] == '0' && chars[i + 1] == '1' {
            chars.swap(i, i + 1);
            answer += 1;
        }
        i += 1;
    }
    answer
}

fn main() {
    println!("{}", seconds_to_remove_occurrences("0110101".to_string())); // 4
    println!("{}", seconds_to_remove_occurrences("11100".to_string())); // 0
    println!(
        "{}",
        seconds_to_remove_occurrences("1000111001010010010101010101".to_string())
    ); // 15
    println!("{}", seconds_to_remove_occurrences("1100101".to_string())); // 3
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use extra::json;
use serialize::Decodable;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use misc::read_file;

fn build_hex_mesh(&geom: &Geom) -> ~[Vec3<GLfloat>] {
  let mut vertex_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.map_pos_to_world_pos(tile_pos);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      vertex_data.push(pos3d + vertex);
      vertex_data.push(pos3d + next_vertex);
      vertex_data.push(pos3d + Vec3::zero());
    }
  }
  vertex_data
}

fn build_hex_tex_coord() -> ~[Vec2<GLfloat>] {
  let mut vertex_data = ~[];
  for _ in TileIterator::new() {
    for _ in range(0, 6) {
      vertex_data.push(Vec2{x: 0.0, y: 0.0});
      vertex_data.push(Vec2{x: 1.0, y: 0.0});
      vertex_data.push(Vec2{x: 0.5, y: 0.5});
    }
  }
  vertex_data
}

pub struct Visualizer {
  program: GLuint,
  map_mesh: Mesh,
  unit_mesh: Mesh,
  mat_id: GLint,
  win: Option<glfw::Window>,
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
  unit_texture_id: GLuint,
  floor_texture_id: GLuint,
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "Marauder",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win.set_all_polling(true);
  win
}

#[deriving(Decodable)]
struct Size2<T> {
  x: T,
  y: T,
}

fn read_win_size(config_path: &str) -> Vec2<int> {
  let path = Path::new(config_path);
  let json = json::from_str(read_file(&path)).unwrap();
  let mut decoder = json::Decoder::new(json);
  let size: Size2<int> = Decodable::decode(&mut decoder);
  Vec2{x: size.x, y: size.y}
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = read_win_size("config.json");
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      program: 0,
      map_mesh: Mesh::new(),
      unit_mesh: Mesh::new(),
      mat_id: 0,
      win: Some(win),
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
      unit_texture_id: 0,
      floor_texture_id: 0,
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_models();
    vis.init_textures();
    vis
  }

  fn init_textures(&mut self) {
    self.unit_texture_id = glh::load_texture(~"data/tank.png");
    self.floor_texture_id = glh::load_texture(~"data/floor.png");
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn init_models(&mut self) {
    self.program = glh::compile_program(
      read_file(&Path::new("normal.vs.glsl")),
      read_file(&Path::new("normal.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    let position_attr = glh::get_attr(self.program, "in_vertex_coordinates");
    gl::EnableVertexAttribArray(position_attr);
    glh::vertex_attrib_pointer(position_attr, 3);
    let vt_attr = glh::get_attr(self.program, "in_texture_coordinates");
    gl::EnableVertexAttribArray(vt_attr);
    glh::vertex_attrib_pointer(vt_attr, 3);
    let map_vertex_data = build_hex_mesh(&self.geom);
    self.map_mesh.set_vertex_coords(map_vertex_data);
    self.map_mesh.set_texture_coords(build_hex_tex_coord());
    let unit_obj = obj::Model::new("data/tank.obj");
    self.unit_mesh.set_vertex_coords(unit_obj.build());
    self.unit_mesh.set_texture_coords(unit_obj.build_tex_coord());
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
    gl::Enable(gl::DEPTH_TEST);
  }

  fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
  }

  fn draw_unit_at(&self, pos: Vec2<i32>) {
    let world_pos = self.geom.map_pos_to_world_pos(pos);
    let m = glh::tr(self.camera.mat(), world_pos);
    glh::uniform_mat4f(self.mat_id, &m);
    self.unit_mesh.draw(self.program);
  }

  fn draw_units(&self) {
    gl::UseProgram(self.program);
    let basic_texture_loc = glh::get_uniform(self.program, "basic_texture");
    gl::Uniform1ui(basic_texture_loc, 0);
    gl::ActiveTexture(gl::TEXTURE0);
    gl::BindTexture(gl::TEXTURE_2D, self.unit_texture_id);
    self.draw_unit_at(Vec2{x: 0, y: 0});
    self.draw_unit_at(Vec2{x: 1, y: 0});
    self.draw_unit_at(Vec2{x: 2, y: 0});
    self.draw_unit_at(Vec2{x: 1, y: 1});
    if !self.selected_tile_pos.is_none() {
      let p = self.selected_tile_pos.unwrap();
      self.draw_unit_at(p);
    }
  }

  fn draw_map(&self) {
    let basic_texture_loc = glh::get_uniform(self.program, "basic_texture");
    gl::Uniform1ui(basic_texture_loc, 0);
    gl::ActiveTexture(gl::TEXTURE0);
    gl::BindTexture(gl::TEXTURE_2D, self.floor_texture_id);
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.map_mesh.draw(self.program);
  }

  fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    gl::UseProgram(self.program);
    self.draw_units();
    self.draw_map();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  fn handle_key_event(&mut self, key: glfw::Key) {
    match key {
      glfw::KeyEscape | glfw::KeyQ => {
        self.win().set_should_close(true);
      },
      glfw::KeySpace => println!("space"),
      glfw::KeyUp => self.camera.move(270.0),
      glfw::KeyDown => self.camera.move(90.0),
      glfw::KeyRight => self.camera.move(0.0),
      glfw::KeyLeft => self.camera.move(180.0),
      glfw::KeyMinus => self.camera.zoom += 1.0,
      glfw::KeyEqual => self.camera.zoom -= 1.0,
      _ => {},
    }
  }

  fn handle_cursor_pos_event(&mut self, pos: Vec2<f32>) {
    let button = self.win().get_mouse_button(glfw::MouseButtonRight);
    if button == glfw::Press {
      self.camera.z_angle += (self.mouse_pos.x - pos.x) / 2.0;
      self.camera.x_angle += (self.mouse_pos.y - pos.y) / 2.0;
    }
    self.mouse_pos = pos;
  }

  fn get_events(&mut self) -> ~[glfw::WindowEvent] {
    glfw::poll_events();
    let mut events = ~[];
    for (_, event) in self.win().flush_events() {
      events.push(event);
    }
    events
  }

  fn handle_event(&mut self, event: glfw::WindowEvent) {
    match event {
      glfw::KeyEvent(key, _, glfw::Press, _) => {
        self.handle_key_event(key);
      },
      glfw::CursorPosEvent(x, y) => {
        let p = Vec2{x: x as f32, y: y as f32};
        self.handle_cursor_pos_event(p);
      },
      glfw::SizeEvent(w, h) => {
        gl::Viewport(0, 0, w, h);
      },
      _ => {},
    }
  }

  fn handle_events(&mut self) {
    for event in self.get_events().iter() {
      self.handle_event(*event);
    }
  }

  fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
  }

  pub fn tick(&mut self) {
    self.handle_events();
    self.pick_tile();
    self.draw();
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Visualizer: Added basic scene nodes system<commit_after>// See LICENSE file for copyright and license details.

use extra::json;
use std::hashmap::HashMap;
use serialize::Decodable;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use misc::read_file;

fn build_hex_mesh(&geom: &Geom) -> ~[Vec3<GLfloat>] {
  let mut vertex_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.map_pos_to_world_pos(tile_pos);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      vertex_data.push(pos3d + vertex);
      vertex_data.push(pos3d + next_vertex);
      vertex_data.push(pos3d + Vec3::zero());
    }
  }
  vertex_data
}

fn build_hex_tex_coord() -> ~[Vec2<GLfloat>] {
  let mut vertex_data = ~[];
  for _ in TileIterator::new() {
    for _ in range(0, 6) {
      vertex_data.push(Vec2{x: 0.0, y: 0.0});
      vertex_data.push(Vec2{x: 1.0, y: 0.0});
      vertex_data.push(Vec2{x: 0.5, y: 0.5});
    }
  }
  vertex_data
}

pub struct SceneNode {
  pos: Vec3<f32>,
}

pub struct Visualizer {
  program: GLuint,
  map_mesh: Mesh,
  unit_mesh: Mesh,
  mat_id: GLint,
  win: Option<glfw::Window>,
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
  unit_texture_id: GLuint,
  floor_texture_id: GLuint,
  scene_nodes: HashMap<i32, SceneNode>,
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "Marauder",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win.set_all_polling(true);
  win
}

#[deriving(Decodable)]
struct Size2<T> {
  x: T,
  y: T,
}

fn read_win_size(config_path: &str) -> Vec2<int> {
  let path = Path::new(config_path);
  let json = json::from_str(read_file(&path)).unwrap();
  let mut decoder = json::Decoder::new(json);
  let size: Size2<int> = Decodable::decode(&mut decoder);
  Vec2{x: size.x, y: size.y}
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = read_win_size("config.json");
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      program: 0,
      map_mesh: Mesh::new(),
      unit_mesh: Mesh::new(),
      mat_id: 0,
      win: Some(win),
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
      unit_texture_id: 0,
      floor_texture_id: 0,
      scene_nodes: HashMap::new(),
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_models();
    vis.init_textures();
    vis.init_units();
    vis
  }

  fn init_textures(&mut self) {
    self.unit_texture_id = glh::load_texture(~"data/tank.png");
    self.floor_texture_id = glh::load_texture(~"data/floor.png");
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn init_models(&mut self) {
    self.program = glh::compile_program(
      read_file(&Path::new("normal.vs.glsl")),
      read_file(&Path::new("normal.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    let position_attr = glh::get_attr(self.program, "in_vertex_coordinates");
    gl::EnableVertexAttribArray(position_attr);
    glh::vertex_attrib_pointer(position_attr, 3);
    let vt_attr = glh::get_attr(self.program, "in_texture_coordinates");
    gl::EnableVertexAttribArray(vt_attr);
    glh::vertex_attrib_pointer(vt_attr, 3);
    let map_vertex_data = build_hex_mesh(&self.geom);
    self.map_mesh.set_vertex_coords(map_vertex_data);
    self.map_mesh.set_texture_coords(build_hex_tex_coord());
    let unit_obj = obj::Model::new("data/tank.obj");
    self.unit_mesh.set_vertex_coords(unit_obj.build());
    self.unit_mesh.set_texture_coords(unit_obj.build_tex_coord());
  }

  fn add_unit(&mut self, id: i32, pos: Vec2<i32>) {
    let world_pos = self.geom.map_pos_to_world_pos(pos);
    self.scene_nodes.insert(id, SceneNode{pos: world_pos});
  }

  fn init_units(&mut self) {
    self.add_unit(0, Vec2{x: 0, y: 0});
    self.add_unit(1, Vec2{x: 0, y: 1});
    self.add_unit(2, Vec2{x: 1, y: 0});
    self.add_unit(2, Vec2{x: 1, y: 1});
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
    gl::Enable(gl::DEPTH_TEST);
  }

  fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
  }

  fn draw_units(&self) {
    gl::UseProgram(self.program);
    let basic_texture_loc = glh::get_uniform(self.program, "basic_texture");
    gl::Uniform1ui(basic_texture_loc, 0);
    gl::ActiveTexture(gl::TEXTURE0);
    gl::BindTexture(gl::TEXTURE_2D, self.unit_texture_id);
    for (_, unit) in self.scene_nodes.iter() {
      let m = glh::tr(self.camera.mat(), unit.pos);
      glh::uniform_mat4f(self.mat_id, &m);
      self.unit_mesh.draw(self.program);
    }
  }

  fn draw_map(&self) {
    let basic_texture_loc = glh::get_uniform(self.program, "basic_texture");
    gl::Uniform1ui(basic_texture_loc, 0);
    gl::ActiveTexture(gl::TEXTURE0);
    gl::BindTexture(gl::TEXTURE_2D, self.floor_texture_id);
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.map_mesh.draw(self.program);
  }

  fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    gl::UseProgram(self.program);
    self.draw_units();
    self.draw_map();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  fn handle_key_event(&mut self, key: glfw::Key) {
    match key {
      glfw::KeyEscape | glfw::KeyQ => {
        self.win().set_should_close(true);
      },
      glfw::KeySpace => println!("space"),
      glfw::KeyUp => self.camera.move(270.0),
      glfw::KeyDown => self.camera.move(90.0),
      glfw::KeyRight => self.camera.move(0.0),
      glfw::KeyLeft => self.camera.move(180.0),
      glfw::KeyMinus => self.camera.zoom += 1.0,
      glfw::KeyEqual => self.camera.zoom -= 1.0,
      _ => {},
    }
  }

  fn handle_cursor_pos_event(&mut self, pos: Vec2<f32>) {
    let button = self.win().get_mouse_button(glfw::MouseButtonRight);
    if button == glfw::Press {
      self.camera.z_angle += (self.mouse_pos.x - pos.x) / 2.0;
      self.camera.x_angle += (self.mouse_pos.y - pos.y) / 2.0;
    }
    self.mouse_pos = pos;
  }

  fn get_events(&mut self) -> ~[glfw::WindowEvent] {
    glfw::poll_events();
    let mut events = ~[];
    for (_, event) in self.win().flush_events() {
      events.push(event);
    }
    events
  }

  fn handle_event(&mut self, event: glfw::WindowEvent) {
    match event {
      glfw::KeyEvent(key, _, glfw::Press, _) => {
        self.handle_key_event(key);
      },
      glfw::CursorPosEvent(x, y) => {
        let p = Vec2{x: x as f32, y: y as f32};
        self.handle_cursor_pos_event(p);
      },
      glfw::SizeEvent(w, h) => {
        gl::Viewport(0, 0, w, h);
      },
      _ => {},
    }
  }

  fn handle_events(&mut self) {
    for event in self.get_events().iter() {
      self.handle_event(*event);
    }
  }

  fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
    if !self.selected_tile_pos.is_none() {
      let map_pos = self.selected_tile_pos.unwrap();
      let pos = self.geom.map_pos_to_world_pos(map_pos);
      let unit_id = 0;
      self.scene_nodes.get_mut(&unit_id).pos = pos;
    }
  }

  pub fn tick(&mut self) {
    self.handle_events();
    self.pick_tile();
    self.draw();
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>#![crate_name = "uu_date"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Anthony Deschamps <anthony.j.deschamps@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate chrono;
#[macro_use]
extern crate clap;
extern crate uucore;

use chrono::offset::Utc;
use chrono::{DateTime, FixedOffset, Local, Offset};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

// Options
const DATE: &str = "date";
const HOURS: &str = "hours";
const MINUTES: &str = "minutes";
const SECONDS: &str = "seconds";
const NS: &str = "ns";

// Help strings

static ISO_8601_HELP_STRING: &str = "output date/time in ISO 8601 format.
 FMT='date' for date only (the default),
 'hours', 'minutes', 'seconds', or 'ns'
 for date and time to the indicated precision.
 Example: 2006-08-14T02:34:56-06:00";

static RFC_2822_HELP_STRING: &str = "output date and time in RFC 2822 format.
 Example: Mon, 14 Aug 2006 02:34:56 -0600";

static RFC_3339_HELP_STRING: &str = "output date/time in RFC 3339 format.
 FMT='date', 'seconds', or 'ns'
 for date and time to the indicated precision.
 Example: 2006-08-14 02:34:56-06:00";

/// Settings for this program, parsed from the command line
struct Settings {
    utc: bool,
    format: Format,
    date_source: DateSource,
    set_to: Option<DateTime<FixedOffset>>,
}

/// Various ways of displaying the date
enum Format {
    Iso8601(Iso8601Format),
    Rfc2822,
    Rfc3339(Rfc3339Format),
    Custom(String),
    Default,
}

/// Various places that dates can come from
enum DateSource {
    Now,
    Custom(String),
    File(PathBuf),
}

enum Iso8601Format {
    Date,
    Hours,
    Minutes,
    Seconds,
    Ns,
}

impl<'a> From<&'a str> for Iso8601Format {
    fn from(s: &str) -> Self {
        match s {
            HOURS => Iso8601Format::Hours,
            MINUTES => Iso8601Format::Minutes,
            SECONDS => Iso8601Format::Seconds,
            NS => Iso8601Format::Ns,
            DATE => Iso8601Format::Date,
            // Should be caught by clap
            _ => panic!("Invalid format: {}", s),
        }
    }
}

enum Rfc3339Format {
    Date,
    Seconds,
    Ns,
}

impl<'a> From<&'a str> for Rfc3339Format {
    fn from(s: &str) -> Self {
        match s {
            DATE => Rfc3339Format::Date,
            SECONDS => Rfc3339Format::Seconds,
            NS => Rfc3339Format::Ns,
            // Should be caught by clap
            _ => panic!("Invalid format: {}", s),
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let settings = parse_cli(args);

    if let Some(_time) = settings.set_to {
        unimplemented!();
    // Probably need to use this syscall:
    // https://doc.rust-lang.org/libc/i686-unknown-linux-gnu/libc/fn.clock_settime.html
    } else {
        // Declare a file here because it needs to outlive the `dates` iterator.
        let file: File;

        // Get the current time, either in the local time zone or UTC.
        let now: DateTime<FixedOffset> = if settings.utc {
            let now = Utc::now();
            now.with_timezone(&now.offset().fix())
        } else {
            let now = Local::now();
            now.with_timezone(now.offset())
        };

        /// Parse a `String` into a `DateTime`.
        /// If it fails, return a tuple of the `String` along with its `ParseError`.
        fn parse_date(
            s: String,
        ) -> Result<DateTime<FixedOffset>, (String, chrono::format::ParseError)> {
            // TODO: The GNU date command can parse a wide variety of inputs.
            s.parse().map_err(|e| (s, e))
        }

        // Iterate over all dates - whether it's a single date or a file.
        let dates: Box<dyn Iterator<Item = _>> = match settings.date_source {
            DateSource::Custom(ref input) => {
                let date = parse_date(input.clone());
                let iter = std::iter::once(date);
                Box::new(iter)
            }
            DateSource::File(ref path) => {
                file = File::open(path).unwrap();
                let lines = BufReader::new(file).lines();
                let iter = lines.filter_map(Result::ok).map(parse_date);
                Box::new(iter)
            }
            DateSource::Now => {
                let iter = std::iter::once(Ok(now));
                Box::new(iter)
            }
        };

        let format_string = make_format_string(&settings);

        // Format all the dates
        for date in dates {
            match date {
                Ok(date) => {
                    let formatted = date.format(format_string);
                    println!("{}", formatted);
                }
                Err((input, _err)) => {
                    println!("date: invalid date '{}'", input);
                }
            }
        }
    }

    0
}

/// Handle command line arguments.
fn parse_cli(args: Vec<String>) -> Settings {
    let matches = clap_app!(
        date =>
            (@group dates =>
             (@arg date: -d --date [STRING]
              "display time described by STRING, not 'now'")
             (@arg file: -f --file [DATEFILE]
              "like --date; once for each line of DATEFILE"))

            (@group format =>
             (@arg iso_8601: -I --("iso-8601") <FMT>
              possible_value[date hours minutes seconds ns]
              #{0, 1}
              ISO_8601_HELP_STRING)
             (@arg rfc_2822: -R --("rfc-2822")
              RFC_2822_HELP_STRING)
             (@arg rfc_3339: --("rfc-3339") <FMT>
              possible_value[date seconds ns]
              RFC_3339_HELP_STRING)
             (@arg custom_format: +takes_value {
                 |s| if s.starts_with('+') {
                        Ok(())
                     } else {
                        Err(String::from("Date formats must start with a '+' character"))
                     }
             }))

            (@arg debug: --debug
             "annotate the parsed date, and warn about questionable usage to stderr")
            (@arg reference: -r --reference [FILE]
             "display the last modification time of FILE")
            (@arg set: -s --set [STRING]
             "set time described by STRING")
            (@arg utc: -u --utc --universal
             "print or set Coordinated Universal Time (UTC)"))
    // TODO: Decide whether this is appropriate.
    //   The GNU date command has an explanation of all formatting options,
    //   but the `chrono` crate has a few differences (most notably, the %Z option)
    // (after_help: include_str!("usage.txt")))
    .get_matches_from(args);

    let format = if let Some(form) = matches.value_of("custom_format") {
        let form = form[1..].into();
        Format::Custom(form)
    } else if let Some(fmt) = matches
        .values_of("iso_8601")
        .map(|mut iter| iter.next().unwrap_or(DATE).into())
    {
        Format::Iso8601(fmt)
    } else if matches.is_present("rfc_2822") {
        Format::Rfc2822
    } else if let Some(fmt) = matches.value_of("rfc_3339").map(Into::into) {
        Format::Rfc3339(fmt)
    } else {
        Format::Default
    };

    let date_source = if let Some(date) = matches.value_of("date") {
        DateSource::Custom(date.into())
    } else if let Some(file) = matches.value_of("file") {
        DateSource::File(file.into())
    } else {
        DateSource::Now
    };

    Settings {
        utc: matches.is_present("utc"),
        format,
        date_source,
        // TODO: Handle this option:
        set_to: None,
    }
}

/// Return the appropriate format string for the given settings.
fn make_format_string(settings: &Settings) -> &str {
    match settings.format {
        Format::Iso8601(ref fmt) => match *fmt {
            Iso8601Format::Date => "%F",
            Iso8601Format::Hours => "%FT%H%:z",
            Iso8601Format::Minutes => "%FT%H:%M%:z",
            Iso8601Format::Seconds => "%FT%T%:z",
            Iso8601Format::Ns => "%FT%T,%f%:z",
        },
        Format::Rfc2822 => "%a, %d %h %Y %T %z",
        Format::Rfc3339(ref fmt) => match *fmt {
            Rfc3339Format::Date => "%F",
            Rfc3339Format::Seconds => "%F %T%:z",
            Rfc3339Format::Ns => "%F %T.%f%:z",
        },
        Format::Custom(ref fmt) => fmt,
        Format::Default => "%c",
    }
}
<commit_msg>fix(date): fix the date<commit_after>#![crate_name = "uu_date"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Anthony Deschamps <anthony.j.deschamps@gmail.com>
 * (c) Sylvestre Ledru <sylvestre@debian.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate chrono;

extern crate clap;
#[macro_use]
extern crate uucore;

use clap::{App, Arg};

use chrono::offset::Utc;
use chrono::{DateTime, FixedOffset, Local, Offset};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

// Options
const DATE: &str = "date";
const HOURS: &str = "hours";
const MINUTES: &str = "minutes";
const SECONDS: &str = "seconds";
const HOUR: &str = "hour";
const MINUTE: &str = "minute";
const SECOND: &str = "second";
const NS: &str = "ns";

const NAME: &str = "date";
const VERSION: &str = env!("CARGO_PKG_VERSION");
const ABOUT: &str = "print or set the system date and time";

const OPT_DATE: &str = "date";
const OPT_FORMAT: &str = "format";
const OPT_FILE: &str = "file";
const OPT_DEBUG: &str = "debug";
const OPT_ISO_8601: &str = "iso-8601";
const OPT_RFC_EMAIL: &str = "rfc-email";
const OPT_RFC_3339: &str = "rfc-3339";
const OPT_SET: &str = "set";
const OPT_REFERENCE: &str = "reference";
const OPT_UNIVERSAL: &str = "universal";
const OPT_UNIVERSAL_2: &str = "utc";

// Help strings

static ISO_8601_HELP_STRING: &str = "output date/time in ISO 8601 format.
 FMT='date' for date only (the default),
 'hours', 'minutes', 'seconds', or 'ns'
 for date and time to the indicated precision.
 Example: 2006-08-14T02:34:56-06:00";

static RFC_5322_HELP_STRING: &str = "output date and time in RFC 5322 format.
 Example: Mon, 14 Aug 2006 02:34:56 -0600";

static RFC_3339_HELP_STRING: &str = "output date/time in RFC 3339 format.
 FMT='date', 'seconds', or 'ns'
 for date and time to the indicated precision.
 Example: 2006-08-14 02:34:56-06:00";

/// Settings for this program, parsed from the command line
struct Settings {
    utc: bool,
    format: Format,
    date_source: DateSource,
    set_to: Option<DateTime<FixedOffset>>,
}

/// Various ways of displaying the date
enum Format {
    Iso8601(Iso8601Format),
    Rfc5322,
    Rfc3339(Rfc3339Format),
    Custom(String),
    Default,
}

/// Various places that dates can come from
enum DateSource {
    Now,
    Custom(String),
    File(PathBuf),
}

enum Iso8601Format {
    Date,
    Hours,
    Minutes,
    Seconds,
    Ns,
}

impl<'a> From<&'a str> for Iso8601Format {
    fn from(s: &str) -> Self {
        match s {
            HOURS | HOUR => Iso8601Format::Hours,
            MINUTES | MINUTE => Iso8601Format::Minutes,
            SECONDS | SECOND => Iso8601Format::Seconds,
            NS => Iso8601Format::Ns,
            DATE => Iso8601Format::Date,
            // Should be caught by clap
            _ => panic!("Invalid format: {}", s),
        }
    }
}

enum Rfc3339Format {
    Date,
    Seconds,
    Ns,
}

impl<'a> From<&'a str> for Rfc3339Format {
    fn from(s: &str) -> Self {
        match s {
            DATE => Rfc3339Format::Date,
            SECONDS | SECOND => Rfc3339Format::Seconds,
            NS => Rfc3339Format::Ns,
            // Should be caught by clap
            _ => panic!("Invalid format: {}", s),
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let syntax = format!(
        "{0} [OPTION]... [+FORMAT]...
 {0} [OPTION]... [MMDDhhmm[[CC]YY][.ss]]",
        NAME
    );
    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&syntax[..])
        .arg(
            Arg::with_name(OPT_DATE)
                .short("d")
                .long(OPT_DATE)
                .takes_value(true)
                .help("display time described by STRING, not 'now'"),
        )
        .arg(
            Arg::with_name(OPT_FILE)
                .short("f")
                .long(OPT_FILE)
                .takes_value(true)
                .help("like --date; once for each line of DATEFILE"),
        )
        .arg(
            Arg::with_name(OPT_ISO_8601)
                .short("I")
                .long(OPT_ISO_8601)
                .takes_value(true)
                .help(ISO_8601_HELP_STRING),
        )
        .arg(
            Arg::with_name(OPT_RFC_EMAIL)
                .short("R")
                .long(OPT_RFC_EMAIL)
                .help(RFC_5322_HELP_STRING),
        )
        .arg(
            Arg::with_name(OPT_RFC_3339)
                .long(OPT_RFC_3339)
                .takes_value(true)
                .help(RFC_3339_HELP_STRING),
        )
        .arg(
            Arg::with_name(OPT_DEBUG)
                .long(OPT_DEBUG)
                .help("annotate the parsed date, and warn about questionable usage to stderr"),
        )
        .arg(
            Arg::with_name(OPT_REFERENCE)
                .short("r")
                .long(OPT_REFERENCE)
                .takes_value(true)
                .help("display the last modification time of FILE"),
        )
        .arg(
            Arg::with_name(OPT_SET)
                .short("s")
                .long(OPT_SET)
                .takes_value(true)
                .help("set time described by STRING"),
        )
        .arg(
            Arg::with_name(OPT_UNIVERSAL)
                .short("u")
                .long(OPT_UNIVERSAL)
                .alias(OPT_UNIVERSAL_2)
                .help("print or set Coordinated Universal Time (UTC)"),
        )
        .arg(Arg::with_name(OPT_FORMAT).multiple(true))
        .get_matches_from(&args);

    let format = if let Some(form) = matches.value_of(OPT_FORMAT) {
        let form = form[1..].into();
        Format::Custom(form)
    } else if let Some(fmt) = matches
        .values_of(OPT_ISO_8601)
        .map(|mut iter| iter.next().unwrap_or(DATE).into())
    {
        Format::Iso8601(fmt)
    } else if matches.is_present(OPT_RFC_EMAIL) {
        Format::Rfc5322
    } else if let Some(fmt) = matches.value_of(OPT_RFC_3339).map(Into::into) {
        Format::Rfc3339(fmt)
    } else {
        Format::Default
    };

    let date_source = if let Some(date) = matches.value_of(OPT_DATE) {
        DateSource::Custom(date.into())
    } else if let Some(file) = matches.value_of(OPT_FILE) {
        DateSource::File(file.into())
    } else {
        DateSource::Now
    };

    let settings = Settings {
        utc: matches.is_present(OPT_UNIVERSAL),
        format,
        date_source,
        // TODO: Handle this option:
        set_to: None,
    };

    if let Some(_time) = settings.set_to {
        unimplemented!();
    // Probably need to use this syscall:
    // https://doc.rust-lang.org/libc/i686-unknown-linux-gnu/libc/fn.clock_settime.html
    } else {
        // Declare a file here because it needs to outlive the `dates` iterator.
        let file: File;

        // Get the current time, either in the local time zone or UTC.
        let now: DateTime<FixedOffset> = if settings.utc {
            let now = Utc::now();
            now.with_timezone(&now.offset().fix())
        } else {
            let now = Local::now();
            now.with_timezone(now.offset())
        };

        /// Parse a `String` into a `DateTime`.
        /// If it fails, return a tuple of the `String` along with its `ParseError`.
        fn parse_date(
            s: String,
        ) -> Result<DateTime<FixedOffset>, (String, chrono::format::ParseError)> {
            // TODO: The GNU date command can parse a wide variety of inputs.
            s.parse().map_err(|e| (s, e))
        }

        // Iterate over all dates - whether it's a single date or a file.
        let dates: Box<dyn Iterator<Item = _>> = match settings.date_source {
            DateSource::Custom(ref input) => {
                let date = parse_date(input.clone());
                let iter = std::iter::once(date);
                Box::new(iter)
            }
            DateSource::File(ref path) => {
                file = File::open(path).unwrap();
                let lines = BufReader::new(file).lines();
                let iter = lines.filter_map(Result::ok).map(parse_date);
                Box::new(iter)
            }
            DateSource::Now => {
                let iter = std::iter::once(Ok(now));
                Box::new(iter)
            }
        };

        let format_string = make_format_string(&settings);

        // Format all the dates
        for date in dates {
            match date {
                Ok(date) => {
                    let formatted = date.format(format_string);
                    println!("{}", formatted);
                }
                Err((input, _err)) => {
                    println!("date: invalid date '{}'", input);
                }
            }
        }
    }

    0
}

/// Return the appropriate format string for the given settings.
fn make_format_string(settings: &Settings) -> &str {
    match settings.format {
        Format::Iso8601(ref fmt) => match *fmt {
            Iso8601Format::Date => "%F",
            Iso8601Format::Hours => "%FT%H%:z",
            Iso8601Format::Minutes => "%FT%H:%M%:z",
            Iso8601Format::Seconds => "%FT%T%:z",
            Iso8601Format::Ns => "%FT%T,%f%:z",
        },
        Format::Rfc5322 => "%a, %d %h %Y %T %z",
        Format::Rfc3339(ref fmt) => match *fmt {
            Rfc3339Format::Date => "%F",
            Rfc3339Format::Seconds => "%F %T%:z",
            Rfc3339Format::Ns => "%F %T.%f%:z",
        },
        Format::Custom(ref fmt) => fmt,
        Format::Default => "%c",
    }
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::{HashMap, HashSet};
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

//impl PartialOrd for VectorClock<S> {
//    fn partial_cmp(&self, other: &Rhs) -> Option<Ordering> {
//
//    }
//}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        let mut a_lt_b = false;
        for (server, ai) in self.map.iter() {
            let bi = *clock_b.map.get(server).unwrap_or(&0);
            if *ai > bi {return false;}
            a_lt_b = a_lt_b || *ai < bi;
        }
        for (server, bi) in clock_b.map.iter() {
            let ai = *self.map.get(server).unwrap_or(&0);
            if ai > *bi {return false;}
            a_lt_b = a_lt_b || ai < *bi;
        }
        return a_lt_b;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &VectorClock<u64>) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> VectorClock<u64> {
        let clock = self.clock.read();
        clock.clone()
    }
}
<commit_msg>impelement vector clock ordering<commit_after>use std::hash::Hash;
use std::collections::{HashMap, HashSet};
use std::cmp::Ordering;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VectorClock<S: Hash + Eq + Copy> {
    map: HashMap<S, u64>
}

impl <S: Eq + Copy + Hash> PartialOrd for VectorClock<S> {
    fn partial_cmp(&self, other: &VectorClock<S>) -> Option<Ordering> {
        let rel = self.relation(other);
        match rel {
            Relation::Before => Some(Ordering::Less),
            Relation::After => Some(Ordering::Greater),
            Relation::Equal => Some(Ordering::Equal),
            Relation::Concurrent => None
        }
    }

    fn lt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::Before
    }

    fn le(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Before || rel == Relation::Equal
    }

    fn gt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::After
    }

    fn ge(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::After || rel == Relation::Equal
    }
}

impl <S: Eq + Copy + Hash> PartialEq for VectorClock<S> {
    fn eq(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Equal
    }

    fn ne(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        !(rel == Relation::After || rel == Relation::Before)
    }
}

impl <S: Hash + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: HashMap::new()
        }
    }

    pub fn inc(&mut self, server: S) {
        *self.map.entry(server).or_insert(0) += 1;
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        let mut a_lt_b = false;
        for (server, ai) in self.map.iter() {
            let bi = *clock_b.map.get(server).unwrap_or(&0);
            if *ai > bi {return false;}
            a_lt_b = a_lt_b || *ai < bi;
        }
        for (server, bi) in clock_b.map.iter() {
            let ai = *self.map.get(server).unwrap_or(&0);
            if ai > *bi {return false;}
            a_lt_b = a_lt_b || ai < *bi;
        }
        return a_lt_b;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &VectorClock<u64>) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &VectorClock<u64>) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &VectorClock<u64>) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> VectorClock<u64> {
        let clock = self.clock.read();
        clock.clone()
    }
}
<|endoftext|>