<commit_before>use color::Color;
use dimensions::Dimensions;
use mouse::Mouse;
use point::Point;
use rectangle;
use ui_context::{ UIID, UiContext };
use vecmath::vec2_add;
use graphics::Graphics;
use graphics::character::CharacterCache;
use widget::Widget;

/// Tuple / Callback params.
pub type Idx = usize;
pub type Len = usize;

/// Represents the state of the menu.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Closed(DrawState),
    Open(DrawState),
}

/// Represents the state of the DropDownList widget.
#[derive(PartialEq, Clone, Copy)]
pub enum DrawState {
    Normal,
    Highlighted(Idx, Len),
    Clicked(Idx, Len),
}

impl DrawState {
    /// Translate the DropDownList's DrawState to the equivalent rectangle::State.
    fn as_rect_state(&self) -> rectangle::State {
        match self {
            &DrawState::Normal => rectangle::State::Normal,
            &DrawState::Highlighted(_, _) => rectangle::State::Highlighted,
            &DrawState::Clicked(_, _) => rectangle::State::Clicked,
        }
    }
}

impl State {
    /// Translate the DropDownList's State to the equivalent rectangle::State.
    fn as_rect_state(&self) -> rectangle::State {
        match self {
            &State::Open(draw_state) | &State::Closed(draw_state) => draw_state.as_rect_state(),
        }
    }
}

widget_fns!(DropDownList, State, Widget::DropDownList(State::Closed(DrawState::Normal)));

/// Is the cursor currently over the widget? If so which item?
fn is_over(pos: Point,
           mouse_pos: Point,
           dim: Dimensions,
           state: State,
           len: Len) -> Option<Idx> {
    match state {
        State::Closed(_) => {
            match rectangle::is_over(pos, mouse_pos, dim) {
                false => None,
                true => Some(0),
            }
        },
        State::Open(_) => {
            let total_h = dim[1] * len as f64;
            match rectangle::is_over(pos, mouse_pos, [dim[0], total_h]) {
                false => None,
                true => Some((((mouse_pos[1] - pos[1]) / total_h) * len as f64) as usize),
            }
        },
    }
}

/// Determine and return the new State by comparing the mouse state
/// and position to the previous State.
fn get_new_state(is_over_idx: Option<Idx>,
                 len: Len,
                 state: State,
                 mouse: Mouse) -> State {
    use self::DrawState::{Normal, Clicked, Highlighted};
    use mouse::ButtonState::{Down, Up};
    match state {
        State::Closed(draw_state) => {
            match is_over_idx {
                Some(_) => {
                    match (draw_state, mouse.left) {
                        (Normal,            Down) => State::Closed(Normal),
                        (Normal,            Up)   |
                        (Highlighted(_, _), Up)   => State::Closed(Highlighted(0, len)),
                        (Highlighted(_, _), Down) => State::Closed(Clicked(0, len)),
                        (Clicked(_, _),     Down) => State::Closed(Clicked(0, len)),
                        (Clicked(_, _),     Up)   => State::Open(Normal),
                    }
                },
                None => State::Closed(Normal),
            }
        },
        State::Open(draw_state) => {
            match is_over_idx {
                Some(idx) => {
                    match (draw_state, mouse.left) {
                        (Normal,            Down) => State::Open(Normal),
                        (Normal,            Up)   |
                        (Highlighted(_, _), Up)   => State::Open(Highlighted(idx, len)),
                        (Highlighted(_, _), Down) => State::Open(Clicked(idx, len)),
                        (Clicked(p_idx, _), Down) => State::Open(Clicked(p_idx, len)),
                        (Clicked(_, _),     Up)   => State::Closed(Normal),
                    }
                },
                None => {
                    match (draw_state, mouse.left) {
                        (Highlighted(p_idx, _), Up) => State::Open(Highlighted(p_idx, len)),
                        _ => State::Closed(Normal),
                    }
                },
            }
        }
    }
}

/// A context on which the builder pattern can be implemented.
pub struct DropDownList<'a, F> {
    ui_id: UIID,
    strings: &'a mut Vec<String>,
    selected: &'a mut Option<Idx>,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl<'a, F> DropDownList<'a, F> {
    pub fn new(ui_id: UIID,
               strings: &'a mut Vec<String>,
               selected: &'a mut Option<Idx>) -> DropDownList<'a, F> {
        DropDownList {
            ui_id: ui_id,
            strings: strings,
            selected: selected,
            pos: [0.0, 0.0],
            dim: [128.0, 32.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

/*
quack! {
    list: DropDownList['a, F]
    get:
        fn () -> Size [] { Size(list.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(
                Widget::DropDownList(State::Closed(DrawState::Normal))
            )
        }
        fn () -> Id [] { Id(list.ui_id) }
    set:
        fn (val: Color) [] { list.maybe_color = Some(val) }
        fn (val: Callback<F>) [where F: FnMut(&mut Option<Idx>, Idx, String) + 'a] {
            list.maybe_callback = Some(val.0)
        }
        fn (val: FrameColor) [] { list.maybe_frame_color = Some(val.0) }
        fn (val: FrameWidth) [] { list.maybe_frame = Some(val.0) }
        fn (val: LabelText<'a>) [] { list.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { list.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] { list.maybe_label_font_size = Some(val.0) }
        fn (val: Position) [] { list.pos = val.0 }
        fn (val: Size) [] { list.dim = val.0 }
    action:
}
*/

impl<'a, F> ::draw::Drawable for DropDownList<'a, F>
    where
        F: FnMut(&mut Option<Idx>, Idx, String) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over_idx = is_over(self.pos, mouse.pos, self.dim, state, self.strings.len());
        let new_state = get_new_state(is_over_idx, self.strings.len(), state, mouse);

        let sel = match *self.selected {
            Some(idx) if idx < self.strings.len() => { Some(idx) },
            _ => None,
        };
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        let t_size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
        let t_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);

        // Call the `callback` closure if mouse was released
        // on one of the DropDownMenu items.
        match (state, new_state) {
            (State::Open(o_d_state), State::Closed(c_d_state)) => {
                match (o_d_state, c_d_state) {
                    (DrawState::Clicked(idx, _), DrawState::Normal) => {
                        match self.maybe_callback {
                            Some(ref mut callback) => (*callback)(self.selected, idx, (*self.strings)[idx].clone()),
                            None => (),
                        }
                    }, _ => (),
                }
            }, _ => (),
        }

        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };

        match new_state {

            State::Closed(_) => {
                let rect_state = new_state.as_rect_state();
                let text = match sel {
                    Some(idx) => &(*self.strings)[idx][..],
                    None => match self.maybe_label {
                        Some(text) => text,
                        None => &(*self.strings)[0][..],
                    },
                };
                rectangle::draw_with_centered_label(
                    uic.win_w, uic.win_h, graphics, uic, rect_state,
                    self.pos, self.dim, maybe_frame, color,
                    text, t_size, t_color
                )
            },

            State::Open(draw_state) => {
                for (i, string) in self.strings.iter().enumerate() {
                    let rect_state = match sel {
                        None => {
                            match draw_state {
                                DrawState::Normal => rectangle::State::Normal,
                                DrawState::Highlighted(idx, _) => {
                                    if i == idx { rectangle::State::Highlighted }
                                    else { rectangle::State::Normal }
                                },
                                DrawState::Clicked(idx, _) => {
                                    if i == idx { rectangle::State::Clicked }
                                    else { rectangle::State::Normal }
                                },
                            }
                        },
                        Some(sel_idx) => {
                            if sel_idx == i { rectangle::State::Clicked }
                            else {
                                match draw_state {
                                    DrawState::Normal => rectangle::State::Normal,
                                    DrawState::Highlighted(idx, _) => {
                                        if i == idx { rectangle::State::Highlighted }
                                        else { rectangle::State::Normal }
                                    },
                                    DrawState::Clicked(idx, _) => {
                                        if i == idx { rectangle::State::Clicked }
                                        else { rectangle::State::Normal }
                                    },
                                }
                            }
                        },
                    };
                    let idx_y = self.dim[1] * i as f64 - i as f64 * frame_w;
                    let idx_pos = vec2_add(self.pos, [0.0, idx_y]);
                    rectangle::draw_with_centered_label(
                        uic.win_w, uic.win_h, graphics, uic, rect_state, idx_pos,
                        self.dim, maybe_frame, color, &string,
                        t_size, t_color
                    )
                }
            },

        }

        set_state(uic, self.ui_id, Widget::DropDownList(new_state), self.pos, self.dim);

    }
}
<commit_msg>Implemented `Colorable` for `DropDownList`<commit_after>use color::{ Color, Colorable };
use dimensions::Dimensions;
use mouse::Mouse;
use point::Point;
use rectangle;
use ui_context::{ UIID, UiContext };
use vecmath::vec2_add;
use graphics::Graphics;
use graphics::character::CharacterCache;
use widget::Widget;

/// Tuple / Callback params.
pub type Idx = usize;
pub type Len = usize;

/// Represents the state of the menu.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Closed(DrawState),
    Open(DrawState),
}

/// Represents the state of the DropDownList widget.
#[derive(PartialEq, Clone, Copy)]
pub enum DrawState {
    Normal,
    Highlighted(Idx, Len),
    Clicked(Idx, Len),
}

impl DrawState {
    /// Translate the DropDownList's DrawState to the equivalent rectangle::State.
    fn as_rect_state(&self) -> rectangle::State {
        match self {
            &DrawState::Normal => rectangle::State::Normal,
            &DrawState::Highlighted(_, _) => rectangle::State::Highlighted,
            &DrawState::Clicked(_, _) => rectangle::State::Clicked,
        }
    }
}

impl State {
    /// Translate the DropDownList's State to the equivalent rectangle::State.
    fn as_rect_state(&self) -> rectangle::State {
        match self {
            &State::Open(draw_state) | &State::Closed(draw_state) => draw_state.as_rect_state(),
        }
    }
}

widget_fns!(DropDownList, State, Widget::DropDownList(State::Closed(DrawState::Normal)));

/// Is the cursor currently over the widget? If so which item?
fn is_over(pos: Point,
           mouse_pos: Point,
           dim: Dimensions,
           state: State,
           len: Len) -> Option<Idx> {
    match state {
        State::Closed(_) => {
            match rectangle::is_over(pos, mouse_pos, dim) {
                false => None,
                true => Some(0),
            }
        },
        State::Open(_) => {
            let total_h = dim[1] * len as f64;
            match rectangle::is_over(pos, mouse_pos, [dim[0], total_h]) {
                false => None,
                true => Some((((mouse_pos[1] - pos[1]) / total_h) * len as f64) as usize),
            }
        },
    }
}

/// Determine and return the new State by comparing the mouse state
/// and position to the previous State.
fn get_new_state(is_over_idx: Option<Idx>,
                 len: Len,
                 state: State,
                 mouse: Mouse) -> State {
    use self::DrawState::{Normal, Clicked, Highlighted};
    use mouse::ButtonState::{Down, Up};
    match state {
        State::Closed(draw_state) => {
            match is_over_idx {
                Some(_) => {
                    match (draw_state, mouse.left) {
                        (Normal,            Down) => State::Closed(Normal),
                        (Normal,            Up)   |
                        (Highlighted(_, _), Up)   => State::Closed(Highlighted(0, len)),
                        (Highlighted(_, _), Down) => State::Closed(Clicked(0, len)),
                        (Clicked(_, _),     Down) => State::Closed(Clicked(0, len)),
                        (Clicked(_, _),     Up)   => State::Open(Normal),
                    }
                },
                None => State::Closed(Normal),
            }
        },
        State::Open(draw_state) => {
            match is_over_idx {
                Some(idx) => {
                    match (draw_state, mouse.left) {
                        (Normal,            Down) => State::Open(Normal),
                        (Normal,            Up)   |
                        (Highlighted(_, _), Up)   => State::Open(Highlighted(idx, len)),
                        (Highlighted(_, _), Down) => State::Open(Clicked(idx, len)),
                        (Clicked(p_idx, _), Down) => State::Open(Clicked(p_idx, len)),
                        (Clicked(_, _),     Up)   => State::Closed(Normal),
                    }
                },
                None => {
                    match (draw_state, mouse.left) {
                        (Highlighted(p_idx, _), Up) => State::Open(Highlighted(p_idx, len)),
                        _ => State::Closed(Normal),
                    }
                },
            }
        }
    }
}

/// A context on which the builder pattern can be implemented.
pub struct DropDownList<'a, F> {
    ui_id: UIID,
    strings: &'a mut Vec<String>,
    selected: &'a mut Option<Idx>,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl<'a, F> DropDownList<'a, F> {
    pub fn new(ui_id: UIID,
               strings: &'a mut Vec<String>,
               selected: &'a mut Option<Idx>) -> DropDownList<'a, F> {
        DropDownList {
            ui_id: ui_id,
            strings: strings,
            selected: selected,
            pos: [0.0, 0.0],
            dim: [128.0, 32.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, F> Colorable for DropDownList<'a, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

/*
quack! {
    list: DropDownList['a, F]
    get:
        fn () -> Size [] { Size(list.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(
                Widget::DropDownList(State::Closed(DrawState::Normal))
            )
        }
        fn () -> Id [] { Id(list.ui_id) }
    set:
        fn (val: Callback<F>) [where F: FnMut(&mut Option<Idx>, Idx, String) + 'a] {
            list.maybe_callback = Some(val.0)
        }
        fn (val: FrameColor) [] { list.maybe_frame_color = Some(val.0) }
        fn (val: FrameWidth) [] { list.maybe_frame = Some(val.0) }
        fn (val: LabelText<'a>) [] { list.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { list.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] { list.maybe_label_font_size = Some(val.0) }
        fn (val: Position) [] { list.pos = val.0 }
        fn (val: Size) [] { list.dim = val.0 }
    action:
}
*/

impl<'a, F> ::draw::Drawable for DropDownList<'a, F>
    where
        F: FnMut(&mut Option<Idx>, Idx, String) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over_idx = is_over(self.pos, mouse.pos, self.dim, state, self.strings.len());
        let new_state = get_new_state(is_over_idx, self.strings.len(), state, mouse);

        let sel = match *self.selected {
            Some(idx) if idx < self.strings.len() => { Some(idx) },
            _ => None,
        };
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        let t_size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
        let t_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);

        // Call the `callback` closure if mouse was released
        // on one of the DropDownMenu items.
        match (state, new_state) {
            (State::Open(o_d_state), State::Closed(c_d_state)) => {
                match (o_d_state, c_d_state) {
                    (DrawState::Clicked(idx, _), DrawState::Normal) => {
                        match self.maybe_callback {
                            Some(ref mut callback) => (*callback)(self.selected, idx, (*self.strings)[idx].clone()),
                            None => (),
                        }
                    }, _ => (),
                }
            }, _ => (),
        }

        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };

        match new_state {

            State::Closed(_) => {
                let rect_state = new_state.as_rect_state();
                let text = match sel {
                    Some(idx) => &(*self.strings)[idx][..],
                    None => match self.maybe_label {
                        Some(text) => text,
                        None => &(*self.strings)[0][..],
                    },
                };
                rectangle::draw_with_centered_label(
                    uic.win_w, uic.win_h, graphics, uic, rect_state,
                    self.pos, self.dim, maybe_frame, color,
                    text, t_size, t_color
                )
            },

            State::Open(draw_state) => {
                for (i, string) in self.strings.iter().enumerate() {
                    let rect_state = match sel {
                        None => {
                            match draw_state {
                                DrawState::Normal => rectangle::State::Normal,
                                DrawState::Highlighted(idx, _) => {
                                    if i == idx { rectangle::State::Highlighted }
                                    else { rectangle::State::Normal }
                                },
                                DrawState::Clicked(idx, _) => {
                                    if i == idx { rectangle::State::Clicked }
                                    else { rectangle::State::Normal }
                                },
                            }
                        },
                        Some(sel_idx) => {
                            if sel_idx == i { rectangle::State::Clicked }
                            else {
                                match draw_state {
                                    DrawState::Normal => rectangle::State::Normal,
                                    DrawState::Highlighted(idx, _) => {
                                        if i == idx { rectangle::State::Highlighted }
                                        else { rectangle::State::Normal }
                                    },
                                    DrawState::Clicked(idx, _) => {
                                        if i == idx { rectangle::State::Clicked }
                                        else { rectangle::State::Normal }
                                    },
                                }
                            }
                        },
                    };
                    let idx_y = self.dim[1] * i as f64 - i as f64 * frame_w;
                    let idx_pos = vec2_add(self.pos, [0.0, idx_y]);
                    rectangle::draw_with_centered_label(
                        uic.win_w, uic.win_h, graphics, uic, rect_state, idx_pos,
                        self.dim, maybe_frame, color, &string,
                        t_size, t_color
                    )
                }
            },

        }

        set_state(uic, self.ui_id, Widget::DropDownList(new_state), self.pos, self.dim);

    }
}
<|endoftext|>


<commit_before>use cairo;
use cairo_sys;
use glib::translate::*;
use glib_sys;
use libc;
use pango;
use pango_sys;

use color::*;
use error::*;
use node::NodeType;
use node::RsvgNode;
use opacity::*;
use path_builder::RsvgPathBuilder;
use state::RsvgState;

pub enum RsvgDrawingCtx {}

extern "C" {
    fn rsvg_drawing_ctx_get_dpi(
        draw_ctx: *const RsvgDrawingCtx,
        out_dpi_x: *mut f64,
        out_dpi_y: *mut f64,
    );

    fn rsvg_drawing_ctx_get_normalized_font_size(draw_ctx: *const RsvgDrawingCtx) -> f64;

    fn rsvg_drawing_ctx_get_view_box_size(
        draw_ctx: *const RsvgDrawingCtx,
        out_x: *mut f64,
        out_y: *mut f64,
    );

    fn rsvg_drawing_ctx_push_view_box(draw_ctx: *const RsvgDrawingCtx, width: f64, height: f64);

    fn rsvg_drawing_ctx_pop_view_box(draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_acquire_node(
        draw_ctx: *const RsvgDrawingCtx,
        url: *const libc::c_char,
    ) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_acquire_node_of_type(
        draw_ctx: *const RsvgDrawingCtx,
        url: *const libc::c_char,
        node_type: NodeType,
    ) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_release_node(draw_ctx: *const RsvgDrawingCtx, node: *mut RsvgNode);

    fn rsvg_drawing_ctx_get_current_state_affine(draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;

    fn rsvg_drawing_ctx_set_current_state_affine(
        draw_ctx: *const RsvgDrawingCtx,
        affine: *const cairo::Matrix,
    );

    fn rsvg_drawing_ctx_set_affine_on_cr(
        draw_ctx: *const RsvgDrawingCtx,
        cr: *mut cairo_sys::cairo_t,
        affine: *const cairo::Matrix,
    );

    fn rsvg_drawing_ctx_get_pango_context(
        draw_ctx: *const RsvgDrawingCtx,
    ) -> *mut pango_sys::PangoContext;

    fn rsvg_drawing_ctx_add_clipping_rect(
        draw_ctx: *const RsvgDrawingCtx,
        x: f64,
        y: f64,
        w: f64,
        h: f64,
    );

    fn rsvg_drawing_ctx_draw_node_from_stack(
        draw_ctx: *const RsvgDrawingCtx,
        node: *const RsvgNode,
        dominate: i32,
    );

    fn rsvg_current_state(draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
    fn rsvg_state_new() -> *mut RsvgState;
    fn rsvg_state_free(state: *mut RsvgState);
    fn rsvg_state_reinit(state: *mut RsvgState);
    fn rsvg_state_reconstruct(state: *mut RsvgState, node: *const RsvgNode);
    fn rsvg_state_is_overflow(state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_has_overflow(state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_cond_true(state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_set_cond_true(state: *const RsvgState, cond_true: glib_sys::gboolean);
    fn rsvg_state_get_stop_color(state: *const RsvgState) -> *const ColorSpec;
    fn rsvg_state_get_stop_opacity(state: *const RsvgState) -> *const OpacitySpec;
    fn rsvg_state_get_current_color(state: *const RsvgState) -> u32;

    fn rsvg_state_push(draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_state_pop(draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_state_reinherit_top(
        draw_ctx: *const RsvgDrawingCtx,
        state: *mut RsvgState,
        dominate: libc::c_int,
    );

    fn rsvg_push_discrete_layer(draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_pop_discrete_layer(draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_render_path_builder(
        draw_ctx: *const RsvgDrawingCtx,
        builder: *const RsvgPathBuilder,
    );
    fn rsvg_drawing_ctx_render_surface(
        draw_ctx: *const RsvgDrawingCtx,
        surface: *const cairo_sys::cairo_surface_t,
        x: f64,
        y: f64,
        w: f64,
        h: f64,
    );

    fn rsvg_cairo_get_cairo_context(draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
    fn rsvg_cairo_set_cairo_context(draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
}

pub fn get_dpi(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut dpi_x: f64 = 0.0;
    let mut dpi_y: f64 = 0.0;

    unsafe {
        rsvg_drawing_ctx_get_dpi(draw_ctx, &mut dpi_x, &mut dpi_y);
    }

    (dpi_x, dpi_y)
}

pub fn get_normalized_font_size(draw_ctx: *const RsvgDrawingCtx) -> f64 {
    unsafe { rsvg_drawing_ctx_get_normalized_font_size(draw_ctx) }
}

pub fn get_view_box_size(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut w: f64 = 0.0;
    let mut h: f64 = 0.0;

    unsafe {
        rsvg_drawing_ctx_get_view_box_size(draw_ctx, &mut w, &mut h);
    }

    (w, h)
}

pub fn push_view_box(draw_ctx: *const RsvgDrawingCtx, width: f64, height: f64) {
    unsafe {
        rsvg_drawing_ctx_push_view_box(draw_ctx, width, height);
    }
}

pub fn pop_view_box(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_drawing_ctx_pop_view_box(draw_ctx);
    }
}

pub fn get_acquired_node(draw_ctx: *const RsvgDrawingCtx, url: &str) -> Option<AcquiredNode> {
    let raw_node = unsafe { rsvg_drawing_ctx_acquire_node(draw_ctx, str::to_glib_none(url).0) };

    if raw_node.is_null() {
        None
    } else {
        Some(AcquiredNode(draw_ctx, raw_node))
    }
}

pub fn get_acquired_node_of_type(
    draw_ctx: *const RsvgDrawingCtx,
    url: &str,
    node_type: NodeType,
) -> Option<AcquiredNode> {
    let raw_node = unsafe {
        rsvg_drawing_ctx_acquire_node_of_type(draw_ctx, str::to_glib_none(url).0, node_type)
    };

    if raw_node.is_null() {
        None
    } else {
        Some(AcquiredNode(draw_ctx, raw_node))
    }
}

pub fn state_reinherit_top(draw_ctx: *const RsvgDrawingCtx, state: *mut RsvgState, dominate: i32) {
    unsafe {
        rsvg_state_reinherit_top(draw_ctx, state, dominate);
    }
}

pub fn push_discrete_layer(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_push_discrete_layer(draw_ctx);
    }
}

pub fn pop_discrete_layer(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_pop_discrete_layer(draw_ctx);
    }
}

pub fn render_path_builder(draw_ctx: *const RsvgDrawingCtx, builder: &RsvgPathBuilder) {
    unsafe {
        rsvg_drawing_ctx_render_path_builder(draw_ctx, builder);
    }
}

pub fn render_surface(
    draw_ctx: *const RsvgDrawingCtx,
    surface: &cairo::ImageSurface,
    x: f64,
    y: f64,
    w: f64,
    h: f64,
) {
    unsafe {
        rsvg_drawing_ctx_render_surface(draw_ctx, surface.to_raw_none(), x, y, w, h);
    }
}

pub fn get_cairo_context(draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
    unsafe {
        let raw_cr = rsvg_cairo_get_cairo_context(draw_ctx);

        cairo::Context::from_glib_none(raw_cr)
    }
}

pub fn set_cairo_context(draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
    unsafe {
        let raw_cr = cr.to_glib_none().0;

        rsvg_cairo_set_cairo_context(draw_ctx, raw_cr);
    }
}

pub fn get_current_state_affine(draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
    unsafe { rsvg_drawing_ctx_get_current_state_affine(draw_ctx) }
}

pub fn set_current_state_affine(draw_ctx: *const RsvgDrawingCtx, affine: cairo::Matrix) {
    unsafe {
        rsvg_drawing_ctx_set_current_state_affine(draw_ctx, &affine);
    }
}

pub fn set_affine_on_cr(
    draw_ctx: *const RsvgDrawingCtx,
    cr: &cairo::Context,
    affine: &cairo::Matrix,
) {
    unsafe {
        rsvg_drawing_ctx_set_affine_on_cr(
            draw_ctx,
            cr.to_glib_none().0,
            affine as *const cairo::Matrix,
        );
    }
}

pub fn get_pango_context(draw_ctx: *const RsvgDrawingCtx) -> pango::Context {
    unsafe { from_glib_full(rsvg_drawing_ctx_get_pango_context(draw_ctx)) }
}

pub fn add_clipping_rect(draw_ctx: *const RsvgDrawingCtx, x: f64, y: f64, w: f64, h: f64) {
    unsafe {
        rsvg_drawing_ctx_add_clipping_rect(draw_ctx, x, y, w, h);
    }
}

pub fn draw_node_from_stack(draw_ctx: *const RsvgDrawingCtx, node: *const RsvgNode, dominate: i32) {
    unsafe {
        rsvg_drawing_ctx_draw_node_from_stack(draw_ctx, node, dominate);
    }
}

pub fn get_current_state(draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState {
    unsafe { rsvg_current_state(draw_ctx) }
}

pub fn state_new() -> *mut RsvgState {
    unsafe { rsvg_state_new() }
}

pub fn state_free(state: *mut RsvgState) {
    unsafe {
        rsvg_state_free(state);
    }
}

pub fn state_reinit(state: *mut RsvgState) {
    unsafe {
        rsvg_state_reinit(state);
    }
}

pub fn state_reconstruct(state: *mut RsvgState, node: *const RsvgNode) {
    unsafe {
        rsvg_state_reconstruct(state, node);
    }
}

pub fn state_is_overflow(state: *const RsvgState) -> bool {
    unsafe { from_glib(rsvg_state_is_overflow(state)) }
}

pub fn state_has_overflow(state: *const RsvgState) -> bool {
    unsafe { from_glib(rsvg_state_has_overflow(state)) }
}

pub fn state_get_cond_true(state: *const RsvgState) -> bool {
    unsafe { from_glib(rsvg_state_get_cond_true(state)) }
}

pub fn state_set_cond_true(state: *const RsvgState, cond_true: bool) {
    unsafe {
        rsvg_state_set_cond_true(state, cond_true.to_glib());
    }
}

pub fn state_push(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_push(draw_ctx);
    }
}

pub fn state_pop(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_pop(draw_ctx);
    }
}

pub fn state_get_stop_color(state: *const RsvgState) -> Result<Option<Color>, AttributeError> {
    unsafe {
        let spec_ptr = rsvg_state_get_stop_color(state);

        if spec_ptr.is_null() {
            Ok(None)
        } else {
            Color::from_color_spec(&*spec_ptr).map(Some)
        }
    }
}

pub fn state_get_stop_opacity(state: *const RsvgState) -> Result<Option<Opacity>, AttributeError> {
    unsafe {
        let opacity_ptr = rsvg_state_get_stop_opacity(state);

        if opacity_ptr.is_null() {
            Ok(None)
        } else {
            Opacity::from_opacity_spec(&*opacity_ptr).map(Some)
        }
    }
}

pub fn state_get_current_color(state: *const RsvgState) -> Color {
    let argb = unsafe { rsvg_state_get_current_color(state) };

    Color::from(argb)
}

pub struct AcquiredNode(*const RsvgDrawingCtx, *mut RsvgNode);

impl Drop for AcquiredNode {
    fn drop(&mut self) {
        unsafe {
            rsvg_drawing_ctx_release_node(self.0, self.1);
        }
    }
}

impl AcquiredNode {
    pub fn get(&self) -> RsvgNode {
        unsafe { (*self.1).clone() }
    }
}
<commit_msg>drawing_ctx::insert_bbox() - bind to Rust<commit_after>use cairo;
use cairo_sys;
use glib::translate::*;
use glib_sys;
use libc;
use pango;
use pango_sys;

use bbox::RsvgBbox;
use color::*;
use error::*;
use node::NodeType;
use node::RsvgNode;
use opacity::*;
use path_builder::RsvgPathBuilder;
use state::RsvgState;

pub enum RsvgDrawingCtx {}

extern "C" {
    fn rsvg_drawing_ctx_get_dpi(
        draw_ctx: *const RsvgDrawingCtx,
        out_dpi_x: *mut f64,
        out_dpi_y: *mut f64,
    );

    fn rsvg_drawing_ctx_get_normalized_font_size(draw_ctx: *const RsvgDrawingCtx) -> f64;

    fn rsvg_drawing_ctx_get_view_box_size(
        draw_ctx: *const RsvgDrawingCtx,
        out_x: *mut f64,
        out_y: *mut f64,
    );

    fn rsvg_drawing_ctx_push_view_box(draw_ctx: *const RsvgDrawingCtx, width: f64, height: f64);

    fn rsvg_drawing_ctx_pop_view_box(draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_acquire_node(
        draw_ctx: *const RsvgDrawingCtx,
        url: *const libc::c_char,
    ) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_acquire_node_of_type(
        draw_ctx: *const RsvgDrawingCtx,
        url: *const libc::c_char,
        node_type: NodeType,
    ) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_release_node(draw_ctx: *const RsvgDrawingCtx, node: *mut RsvgNode);

    fn rsvg_drawing_ctx_get_current_state_affine(draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;

    fn rsvg_drawing_ctx_set_current_state_affine(
        draw_ctx: *const RsvgDrawingCtx,
        affine: *const cairo::Matrix,
    );

    fn rsvg_drawing_ctx_set_affine_on_cr(
        draw_ctx: *const RsvgDrawingCtx,
        cr: *mut cairo_sys::cairo_t,
        affine: *const cairo::Matrix,
    );

    fn rsvg_drawing_ctx_get_pango_context(
        draw_ctx: *const RsvgDrawingCtx,
    ) -> *mut pango_sys::PangoContext;

    fn rsvg_drawing_ctx_add_clipping_rect(
        draw_ctx: *const RsvgDrawingCtx,
        x: f64,
        y: f64,
        w: f64,
        h: f64,
    );

    fn rsvg_drawing_ctx_insert_bbox(draw_ctx: *const RsvgDrawingCtx, bbox: *const RsvgBbox);

    fn rsvg_drawing_ctx_draw_node_from_stack(
        draw_ctx: *const RsvgDrawingCtx,
        node: *const RsvgNode,
        dominate: i32,
    );

    fn rsvg_current_state(draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
    fn rsvg_state_new() -> *mut RsvgState;
    fn rsvg_state_free(state: *mut RsvgState);
    fn rsvg_state_reinit(state: *mut RsvgState);
    fn rsvg_state_reconstruct(state: *mut RsvgState, node: *const RsvgNode);
    fn rsvg_state_is_overflow(state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_has_overflow(state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_cond_true(state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_set_cond_true(state: *const RsvgState, cond_true: glib_sys::gboolean);
    fn rsvg_state_get_stop_color(state: *const RsvgState) -> *const ColorSpec;
    fn rsvg_state_get_stop_opacity(state: *const RsvgState) -> *const OpacitySpec;
    fn rsvg_state_get_current_color(state: *const RsvgState) -> u32;

    fn rsvg_state_push(draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_state_pop(draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_state_reinherit_top(
        draw_ctx: *const RsvgDrawingCtx,
        state: *mut RsvgState,
        dominate: libc::c_int,
    );

    fn rsvg_push_discrete_layer(draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_pop_discrete_layer(draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_render_path_builder(
        draw_ctx: *const RsvgDrawingCtx,
        builder: *const RsvgPathBuilder,
    );
    fn rsvg_drawing_ctx_render_surface(
        draw_ctx: *const RsvgDrawingCtx,
        surface: *const cairo_sys::cairo_surface_t,
        x: f64,
        y: f64,
        w: f64,
        h: f64,
    );

    fn rsvg_cairo_get_cairo_context(draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
    fn rsvg_cairo_set_cairo_context(draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
}

pub fn get_dpi(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut dpi_x: f64 = 0.0;
    let mut dpi_y: f64 = 0.0;

    unsafe {
        rsvg_drawing_ctx_get_dpi(draw_ctx, &mut dpi_x, &mut dpi_y);
    }

    (dpi_x, dpi_y)
}

pub fn get_normalized_font_size(draw_ctx: *const RsvgDrawingCtx) -> f64 {
    unsafe { rsvg_drawing_ctx_get_normalized_font_size(draw_ctx) }
}

pub fn get_view_box_size(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut w: f64 = 0.0;
    let mut h: f64 = 0.0;

    unsafe {
        rsvg_drawing_ctx_get_view_box_size(draw_ctx, &mut w, &mut h);
    }

    (w, h)
}

pub fn push_view_box(draw_ctx: *const RsvgDrawingCtx, width: f64, height: f64) {
    unsafe {
        rsvg_drawing_ctx_push_view_box(draw_ctx, width, height);
    }
}

pub fn pop_view_box(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_drawing_ctx_pop_view_box(draw_ctx);
    }
}

pub fn get_acquired_node(draw_ctx: *const RsvgDrawingCtx, url: &str) -> Option<AcquiredNode> {
    let raw_node = unsafe { rsvg_drawing_ctx_acquire_node(draw_ctx, str::to_glib_none(url).0) };

    if raw_node.is_null() {
        None
    } else {
        Some(AcquiredNode(draw_ctx, raw_node))
    }
}

pub fn get_acquired_node_of_type(
    draw_ctx: *const RsvgDrawingCtx,
    url: &str,
    node_type: NodeType,
) -> Option<AcquiredNode> {
    let raw_node = unsafe {
        rsvg_drawing_ctx_acquire_node_of_type(draw_ctx, str::to_glib_none(url).0, node_type)
    };

    if raw_node.is_null() {
        None
    } else {
        Some(AcquiredNode(draw_ctx, raw_node))
    }
}

pub fn state_reinherit_top(draw_ctx: *const RsvgDrawingCtx, state: *mut RsvgState, dominate: i32) {
    unsafe {
        rsvg_state_reinherit_top(draw_ctx, state, dominate);
    }
}

pub fn push_discrete_layer(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_push_discrete_layer(draw_ctx);
    }
}

pub fn pop_discrete_layer(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_pop_discrete_layer(draw_ctx);
    }
}

pub fn render_path_builder(draw_ctx: *const RsvgDrawingCtx, builder: &RsvgPathBuilder) {
    unsafe {
        rsvg_drawing_ctx_render_path_builder(draw_ctx, builder);
    }
}

pub fn render_surface(
    draw_ctx: *const RsvgDrawingCtx,
    surface: &cairo::ImageSurface,
    x: f64,
    y: f64,
    w: f64,
    h: f64,
) {
    unsafe {
        rsvg_drawing_ctx_render_surface(draw_ctx, surface.to_raw_none(), x, y, w, h);
    }
}

pub fn get_cairo_context(draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
    unsafe {
        let raw_cr = rsvg_cairo_get_cairo_context(draw_ctx);

        cairo::Context::from_glib_none(raw_cr)
    }
}

pub fn set_cairo_context(draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
    unsafe {
        let raw_cr = cr.to_glib_none().0;

        rsvg_cairo_set_cairo_context(draw_ctx, raw_cr);
    }
}

pub fn get_current_state_affine(draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
    unsafe { rsvg_drawing_ctx_get_current_state_affine(draw_ctx) }
}

pub fn set_current_state_affine(draw_ctx: *const RsvgDrawingCtx, affine: cairo::Matrix) {
    unsafe {
        rsvg_drawing_ctx_set_current_state_affine(draw_ctx, &affine);
    }
}

pub fn set_affine_on_cr(
    draw_ctx: *const RsvgDrawingCtx,
    cr: &cairo::Context,
    affine: &cairo::Matrix,
) {
    unsafe {
        rsvg_drawing_ctx_set_affine_on_cr(
            draw_ctx,
            cr.to_glib_none().0,
            affine as *const cairo::Matrix,
        );
    }
}

pub fn get_pango_context(draw_ctx: *const RsvgDrawingCtx) -> pango::Context {
    unsafe { from_glib_full(rsvg_drawing_ctx_get_pango_context(draw_ctx)) }
}

pub fn add_clipping_rect(draw_ctx: *const RsvgDrawingCtx, x: f64, y: f64, w: f64, h: f64) {
    unsafe {
        rsvg_drawing_ctx_add_clipping_rect(draw_ctx, x, y, w, h);
    }
}

pub fn insert_bbox(draw_ctx: *const RsvgDrawingCtx, bbox: &RsvgBbox) {
    unsafe {
        rsvg_drawing_ctx_insert_bbox(draw_ctx, bbox as *const _);
    }
}

pub fn draw_node_from_stack(draw_ctx: *const RsvgDrawingCtx, node: *const RsvgNode, dominate: i32) {
    unsafe {
        rsvg_drawing_ctx_draw_node_from_stack(draw_ctx, node, dominate);
    }
}

pub fn get_current_state(draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState {
    unsafe { rsvg_current_state(draw_ctx) }
}

pub fn state_new() -> *mut RsvgState {
    unsafe { rsvg_state_new() }
}

pub fn state_free(state: *mut RsvgState) {
    unsafe {
        rsvg_state_free(state);
    }
}

pub fn state_reinit(state: *mut RsvgState) {
    unsafe {
        rsvg_state_reinit(state);
    }
}

pub fn state_reconstruct(state: *mut RsvgState, node: *const RsvgNode) {
    unsafe {
        rsvg_state_reconstruct(state, node);
    }
}

pub fn state_is_overflow(state: *const RsvgState) -> bool {
    unsafe { from_glib(rsvg_state_is_overflow(state)) }
}

pub fn state_has_overflow(state: *const RsvgState) -> bool {
    unsafe { from_glib(rsvg_state_has_overflow(state)) }
}

pub fn state_get_cond_true(state: *const RsvgState) -> bool {
    unsafe { from_glib(rsvg_state_get_cond_true(state)) }
}

pub fn state_set_cond_true(state: *const RsvgState, cond_true: bool) {
    unsafe {
        rsvg_state_set_cond_true(state, cond_true.to_glib());
    }
}

pub fn state_push(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_push(draw_ctx);
    }
}

pub fn state_pop(draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_pop(draw_ctx);
    }
}

pub fn state_get_stop_color(state: *const RsvgState) -> Result<Option<Color>, AttributeError> {
    unsafe {
        let spec_ptr = rsvg_state_get_stop_color(state);

        if spec_ptr.is_null() {
            Ok(None)
        } else {
            Color::from_color_spec(&*spec_ptr).map(Some)
        }
    }
}

pub fn state_get_stop_opacity(state: *const RsvgState) -> Result<Option<Opacity>, AttributeError> {
    unsafe {
        let opacity_ptr = rsvg_state_get_stop_opacity(state);

        if opacity_ptr.is_null() {
            Ok(None)
        } else {
            Opacity::from_opacity_spec(&*opacity_ptr).map(Some)
        }
    }
}

pub fn state_get_current_color(state: *const RsvgState) -> Color {
    let argb = unsafe { rsvg_state_get_current_color(state) };

    Color::from(argb)
}

pub struct AcquiredNode(*const RsvgDrawingCtx, *mut RsvgNode);

impl Drop for AcquiredNode {
    fn drop(&mut self) {
        unsafe {
            rsvg_drawing_ctx_release_node(self.0, self.1);
        }
    }
}

impl AcquiredNode {
    pub fn get(&self) -> RsvgNode {
        unsafe { (*self.1).clone() }
    }
}
<|endoftext|>


<commit_before>//! Types for the *m.room.tombstone* event.

use ruma_events_macros::StateEventContent;
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};

use crate::StateEvent;

/// A state event signifying that a room has been upgraded to a different room version, and that
/// clients should go there.
pub type TombstoneEvent = StateEvent<TombstoneEventContent>;

/// The payload for `TombstoneEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)]
#[ruma_event(type = "m.room.tombstone")]
pub struct TombstoneEventContent {
    /// A server-defined message.
    pub body: String,

    /// The new room the client should be visiting.
    pub replacement_room: RoomId,
}
<commit_msg>events: Allow m.room.tombstone without a body under `unstable-synapse-quirks`<commit_after>//! Types for the *m.room.tombstone* event.

use ruma_events_macros::StateEventContent;
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};

use crate::StateEvent;

/// A state event signifying that a room has been upgraded to a different room version, and that
/// clients should go there.
pub type TombstoneEvent = StateEvent<TombstoneEventContent>;

/// The payload for `TombstoneEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)]
#[ruma_event(type = "m.room.tombstone")]
pub struct TombstoneEventContent {
    /// A server-defined message.
    #[cfg_attr(feature = "unstable-synapse-quirks", serde(default))]
    pub body: String,

    /// The new room the client should be visiting.
    pub replacement_room: RoomId,
}
<|endoftext|>


<commit_before>use hash_utils::sha2::{Digest, Sha256};
use parser::{
    graph_triples::{relations::Range, resources::ResourceDigest, Pairs, Resource, ResourceInfo},
    utils::apply_tags,
};
use std::{collections::HashMap, path::Path, sync::Mutex};
use tree_sitter::Tree;

// Re-exports for the convenience of crates implementing a Tree-sitter
// based parser
pub use parser::*;
pub use path_utils;

/// A parser based on `tree-sitter`
///
/// This simply encapsulates a `tree-sitter` usage pattern to
/// avoid repetitive boiler plate code in the language-specific sub-modules.
pub struct TreesitterParser {
    /// The `tree-sitter` parser
    inner: Mutex<tree_sitter::Parser>,

    /// The `tree-sitter` query
    query: tree_sitter::Query,
}

impl TreesitterParser {
    /// Create a new compiler for a language with a pre-defined query
    ///
    /// # Arguments
    ///
    /// - `language`: The `tree-sitter` language definition
    /// - `query`: The `tree-sitter` query definition
    pub fn new(language: tree_sitter::Language, query: &str) -> TreesitterParser {
        let mut parser = tree_sitter::Parser::new();
        parser
            .set_language(language)
            .expect("Should be able to set language");
        let parser = Mutex::new(parser);

        let query = tree_sitter::Query::new(language, query).expect("Query should compile");

        TreesitterParser {
            inner: parser,
            query,
        }
    }

    /// Parse some code and return a tree
    ///
    /// # Arguments
    ///
    /// - `code`: The code to parse
    ///
    /// # Returns
    ///
    /// The parsed syntax tree.
    pub fn parse(&self, code: &[u8]) -> tree_sitter::Tree {
        self.inner
            .lock()
            .expect("Unable to lock parser")
            .parse(code, None)
            .expect("Should be a tree result")
    }

    /// Query a parse tree
    ///
    /// # Arguments
    ///
    /// - `code`: The code to parse
    /// - `tree`: The `tree-sitter` parse tree
    ///
    /// # Returns
    ///
    /// A vector of `(pattern, captures)` enumerating the matches for
    /// patterns in the query.
    pub fn query<'tree>(
        &self,
        code: &[u8],
        tree: &'tree tree_sitter::Tree,
    ) -> Vec<(usize, Vec<Capture<'tree>>)> {
        let mut cursor = tree_sitter::QueryCursor::new();
        let matches = cursor.matches(&self.query, tree.root_node(), code);

        let capture_names = self.query.capture_names();
        matches
            .map(|query_match| {
                let pattern = query_match.pattern_index;
                let captures = query_match
                    .captures
                    .iter()
                    .map(|capture| {
                        let start = capture.node.start_position();
                        let end = capture.node.end_position();
                        Capture::new(
                            capture.index,
                            capture_names[capture.index as usize].clone(),
                            capture.node,
                            (start.row, start.column, end.row, end.column),
                            capture
                                .node
                                .utf8_text(code)
                                .expect("Should be able to get text")
                                .to_string(),
                        )
                    })
                    .collect();
                (pattern, captures)
            })
            .collect()
    }
}

/// A capture resulting from a `tree-sitter` query
pub struct Capture<'tree> {
    #[allow(dead_code)]
    /// The index of the capture in the pattern
    index: u32,

    /// The name of the capture in the pattern
    name: String,

    /// The captured node
    pub node: tree_sitter::Node<'tree>,

    /// The captured range
    pub range: Range,

    /// The captured text
    pub text: String,
}

impl<'tree> Capture<'tree> {
    pub fn new(
        index: u32,
        name: String,
        node: tree_sitter::Node<'tree>,
        range: Range,
        text: String,
    ) -> Capture {
        Capture {
            index,
            name,
            node,
            range,
            text,
        }
    }
}

/// Convert a vector of `Capture`s into a `HashMap` of captures
///
/// This relies on captures using the names `@arg` (for non-keyword args)
/// and `@arg_name` and `@arg_value` pairs (for keyword args).
pub fn captures_as_args_map<'tree>(
    captures: &'tree [Capture],
) -> HashMap<String, &'tree Capture<'tree>> {
    let mut map = HashMap::new();

    let mut index = 0;
    let mut name = String::new();
    for capture in captures {
        match capture.name.as_str() {
            "arg" => {
                map.insert(index.to_string(), capture);
                index += 1;
            }
            "arg_name" => {
                name = capture.text.clone();
            }
            "arg_value" => {
                map.insert(name.clone(), capture);
            }
            _ => {}
        }
    }

    map
}

/// Get the text of a child node
///
/// Returns an empty string if the child does not exists, or the text could
/// not be obtained
pub fn child_text<'tree>(
    node: tree_sitter::Node<'tree>,
    name: &str,
    code: &'tree [u8],
) -> &'tree str {
    node.child_by_field_name(name)
        .and_then(|child| child.utf8_text(code).ok())
        .unwrap_or("")
}

/// Create a [`ResourceInfo`] instance from a Treesitter parse tree and pattern matches
///
/// Applies manual tags (e.g. `@uses`) in a comments to the relations derived from
/// semantic code analysis.
///
/// # Arguments
///
/// - `path`: The path of the subject code resource
/// - `lang`: The language (used for creating `Resource::Module` variants)
/// - `code`: The code that was parsed
/// - `matches`: The matches from querying the code
/// - `comment_pattern`: The index of the pattern from which to extract tags
/// - `relations`: The relation pairs
///
/// Assumes that the first capture has the text content of the comment.
/// If the tag ends in `only` then all existing relations of that type
/// will be removed from `relations`.
#[allow(clippy::too_many_arguments)]
pub fn resource_info(
    resource: Resource,
    path: &Path,
    lang: &str,
    code: &[u8],
    tree: &Tree,
    semantics_exclude: &[&str],
    matches: Vec<(usize, Vec<Capture>)>,
    comment_pattern: usize,
    relations: Pairs,
) -> ResourceInfo {
    // Make the resource
    let mut resource_info = ResourceInfo::new(
        resource,
        Some(relations),
        None,
        None,
        Some(ResourceDigest::from_bytes(
            &content_digest(code),
            Some(&semantic_digest(tree, code, semantics_exclude)),
        )),
        None,
        None,
    );

    // Apply tags from comments (this needs to be done at the end because tags
    // may remove pairs if `only` is specified)
    for (pattern_, captures) in matches {
        if pattern_ != comment_pattern {
            continue;
        }

        let comment = &captures[0];
        apply_tags(
            path,
            lang,
            comment.range.0,
            &comment.text,
            None,
            &mut resource_info,
        )
    }

    resource_info
}

/// Generate a content digest of the code (just a SHA256 of the content)
fn content_digest(code: &[u8]) -> [u8; 32] {
    let mut sha256 = Sha256::new();
    sha256.update(code);
    sha256
        .finalize()
        .as_slice()
        .try_into()
        .expect("Should always convert to 32 bytes")
}

/// Generate a semantic digest of a Tree-sitter tree
///
/// The digest excludes "anonymous" nodes and some "named" nodes.
/// See https://tree-sitter.github.io/tree-sitter/using-parsers#named-vs-anonymous-nodes
/// for a discussion of the distinction between the two.
fn semantic_digest(tree: &Tree, code: &[u8], exclude: &[&str]) -> [u8; 32] {
    let mut sha256 = Sha256::new();

    // Traverse tree adding the text of named leaf nodes.
    //
    // This implementation derived from https://github.com/tree-sitter/py-tree-sitter/issues/33#issuecomment-864557166
    // and https://github.com/skmendez/tree-sitter-traversal/blob/main/src/lib.rs
    let mut cursor = tree.walk();
    let mut finished = false;
    while !finished {
        // Get current node
        let node = cursor.node();
        let kind = node.kind();
        if node.is_named() && !exclude.contains(&kind) {
            sha256.update(&kind);
            if node.child_count() == 0 {
                let text = node.utf8_text(code).unwrap();
                sha256.update(&text);
            }
        }

        // Continue traverse
        if cursor.goto_first_child() {
            continue;
        }
        if cursor.goto_next_sibling() {
            continue;
        }
        let mut retracing = true;
        while retracing {
            if !cursor.goto_parent() {
                retracing = false;
                finished = true;
            }
            if cursor.goto_next_sibling() {
                retracing = false;
            }
        }
    }

    sha256
        .finalize()
        .as_slice()
        .try_into()
        .expect("Should always convert to 32 bytes")
}
<commit_msg>fix(Tree-sitter parsers): Strip carriage returns to avoid different digests on Windows<commit_after>use hash_utils::sha2::{Digest, Sha256};
use parser::{
    graph_triples::{relations::Range, resources::ResourceDigest, Pairs, Resource, ResourceInfo},
    utils::apply_tags,
};
use std::{collections::HashMap, path::Path, sync::Mutex};
use tree_sitter::Tree;

// Re-exports for the convenience of crates implementing a Tree-sitter
// based parser
pub use parser::*;
pub use path_utils;

/// A parser based on `tree-sitter`
///
/// This simply encapsulates a `tree-sitter` usage pattern to
/// avoid repetitive boiler plate code in the language-specific sub-modules.
pub struct TreesitterParser {
    /// The `tree-sitter` parser
    inner: Mutex<tree_sitter::Parser>,

    /// The `tree-sitter` query
    query: tree_sitter::Query,
}

impl TreesitterParser {
    /// Create a new compiler for a language with a pre-defined query
    ///
    /// # Arguments
    ///
    /// - `language`: The `tree-sitter` language definition
    /// - `query`: The `tree-sitter` query definition
    pub fn new(language: tree_sitter::Language, query: &str) -> TreesitterParser {
        let mut parser = tree_sitter::Parser::new();
        parser
            .set_language(language)
            .expect("Should be able to set language");
        let parser = Mutex::new(parser);

        let query = tree_sitter::Query::new(language, query).expect("Query should compile");

        TreesitterParser {
            inner: parser,
            query,
        }
    }

    /// Parse some code and return a tree
    ///
    /// # Arguments
    ///
    /// - `code`: The code to parse
    ///
    /// # Returns
    ///
    /// The parsed syntax tree.
    pub fn parse(&self, code: &[u8]) -> tree_sitter::Tree {
        self.inner
            .lock()
            .expect("Unable to lock parser")
            .parse(code, None)
            .expect("Should be a tree result")
    }

    /// Query a parse tree
    ///
    /// # Arguments
    ///
    /// - `code`: The code to parse
    /// - `tree`: The `tree-sitter` parse tree
    ///
    /// # Returns
    ///
    /// A vector of `(pattern, captures)` enumerating the matches for
    /// patterns in the query.
    pub fn query<'tree>(
        &self,
        code: &[u8],
        tree: &'tree tree_sitter::Tree,
    ) -> Vec<(usize, Vec<Capture<'tree>>)> {
        let mut cursor = tree_sitter::QueryCursor::new();
        let matches = cursor.matches(&self.query, tree.root_node(), code);

        let capture_names = self.query.capture_names();
        matches
            .map(|query_match| {
                let pattern = query_match.pattern_index;
                let captures = query_match
                    .captures
                    .iter()
                    .map(|capture| {
                        let start = capture.node.start_position();
                        let end = capture.node.end_position();
                        Capture::new(
                            capture.index,
                            capture_names[capture.index as usize].clone(),
                            capture.node,
                            (start.row, start.column, end.row, end.column),
                            capture
                                .node
                                .utf8_text(code)
                                .expect("Should be able to get text")
                                .to_string(),
                        )
                    })
                    .collect();
                (pattern, captures)
            })
            .collect()
    }
}

/// A capture resulting from a `tree-sitter` query
pub struct Capture<'tree> {
    #[allow(dead_code)]
    /// The index of the capture in the pattern
    index: u32,

    /// The name of the capture in the pattern
    name: String,

    /// The captured node
    pub node: tree_sitter::Node<'tree>,

    /// The captured range
    pub range: Range,

    /// The captured text
    pub text: String,
}

impl<'tree> Capture<'tree> {
    pub fn new(
        index: u32,
        name: String,
        node: tree_sitter::Node<'tree>,
        range: Range,
        text: String,
    ) -> Capture {
        Capture {
            index,
            name,
            node,
            range,
            text,
        }
    }
}

/// Convert a vector of `Capture`s into a `HashMap` of captures
///
/// This relies on captures using the names `@arg` (for non-keyword args)
/// and `@arg_name` and `@arg_value` pairs (for keyword args).
pub fn captures_as_args_map<'tree>(
    captures: &'tree [Capture],
) -> HashMap<String, &'tree Capture<'tree>> {
    let mut map = HashMap::new();

    let mut index = 0;
    let mut name = String::new();
    for capture in captures {
        match capture.name.as_str() {
            "arg" => {
                map.insert(index.to_string(), capture);
                index += 1;
            }
            "arg_name" => {
                name = capture.text.clone();
            }
            "arg_value" => {
                map.insert(name.clone(), capture);
            }
            _ => {}
        }
    }

    map
}

/// Get the text of a child node
///
/// Returns an empty string if the child does not exists, or the text could
/// not be obtained
pub fn child_text<'tree>(
    node: tree_sitter::Node<'tree>,
    name: &str,
    code: &'tree [u8],
) -> &'tree str {
    node.child_by_field_name(name)
        .and_then(|child| child.utf8_text(code).ok())
        .unwrap_or("")
}

/// Create a [`ResourceInfo`] instance from a Treesitter parse tree and pattern matches
///
/// Applies manual tags (e.g. `@uses`) in a comments to the relations derived from
/// semantic code analysis.
///
/// # Arguments
///
/// - `path`: The path of the subject code resource
/// - `lang`: The language (used for creating `Resource::Module` variants)
/// - `code`: The code that was parsed
/// - `matches`: The matches from querying the code
/// - `comment_pattern`: The index of the pattern from which to extract tags
/// - `relations`: The relation pairs
///
/// Assumes that the first capture has the text content of the comment.
/// If the tag ends in `only` then all existing relations of that type
/// will be removed from `relations`.
#[allow(clippy::too_many_arguments)]
pub fn resource_info(
    resource: Resource,
    path: &Path,
    lang: &str,
    code: &[u8],
    tree: &Tree,
    semantics_exclude: &[&str],
    matches: Vec<(usize, Vec<Capture>)>,
    comment_pattern: usize,
    relations: Pairs,
) -> ResourceInfo {
    // Make the resource
    let mut resource_info = ResourceInfo::new(
        resource,
        Some(relations),
        None,
        None,
        Some(ResourceDigest::from_bytes(
            &content_digest(code),
            Some(&semantic_digest(tree, code, semantics_exclude)),
        )),
        None,
        None,
    );

    // Apply tags from comments (this needs to be done at the end because tags
    // may remove pairs if `only` is specified)
    for (pattern_, captures) in matches {
        if pattern_ != comment_pattern {
            continue;
        }

        let comment = &captures[0];
        apply_tags(
            path,
            lang,
            comment.range.0,
            &comment.text,
            None,
            &mut resource_info,
        )
    }

    resource_info
}

/// Generate a content digest of the code (just a SHA256 of the content)
///
/// Strips carriage returns to avoid different digests on Windows.
fn content_digest(code: &[u8]) -> [u8; 32] {
    let mut sha256 = Sha256::new();
    let text = String::from_utf8_lossy(code).replace("\r", "");
    sha256.update(&text);
    sha256
        .finalize()
        .as_slice()
        .try_into()
        .expect("Should always convert to 32 bytes")
}

/// Generate a semantic digest of a Tree-sitter tree
///
/// The digest excludes "anonymous" nodes and some "named" nodes.
/// See https://tree-sitter.github.io/tree-sitter/using-parsers#named-vs-anonymous-nodes
/// for a discussion of the distinction between the two.
///
/// Strips carriage returns to avoid different digests on Windows.
fn semantic_digest(tree: &Tree, code: &[u8], exclude: &[&str]) -> [u8; 32] {
    let mut sha256 = Sha256::new();

    // Traverse tree adding the text of named leaf nodes.
    //
    // This implementation derived from https://github.com/tree-sitter/py-tree-sitter/issues/33#issuecomment-864557166
    // and https://github.com/skmendez/tree-sitter-traversal/blob/main/src/lib.rs
    let mut cursor = tree.walk();
    let mut finished = false;
    while !finished {
        // Get current node
        let node = cursor.node();
        let kind = node.kind();
        if node.is_named() && !exclude.contains(&kind) {
            sha256.update(&kind);
            if node.child_count() == 0 {
                let text = node.utf8_text(code).unwrap().replace("\r", "");
                sha256.update(&text);
            }
        }

        // Continue traverse
        if cursor.goto_first_child() {
            continue;
        }
        if cursor.goto_next_sibling() {
            continue;
        }
        let mut retracing = true;
        while retracing {
            if !cursor.goto_parent() {
                retracing = false;
                finished = true;
            }
            if cursor.goto_next_sibling() {
                retracing = false;
            }
        }
    }

    sha256
        .finalize()
        .as_slice()
        .try_into()
        .expect("Should always convert to 32 bytes")
}
<|endoftext|>


<commit_before>//! Fast Positive Hash, aka "Позитивный Хэш"
//!
//! by Positive Technologies.
//!
//! https://github.com/leo-yuriev/t1ha
//!
//! Briefly, it is a 64-bit Hash Function:
//!
//! Created for 64-bit little-endian platforms, in predominantly for x86_64,
//! but without penalties could runs on any 64-bit CPU.
//! In most cases up to 15% faster than City64, xxHash, mum-hash,
//! metro-hash and all others which are not use specific hardware tricks.
//! Not suitable for cryptography.
//! Please see t1ha.c for implementation details.
//!
//! Acknowledgement:
//!
//! The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев)
//! for The 1Hippeus project - zerocopy messaging in the spirit of Sparta!
//!
//! Requirements and Portability:
//!
//! t1ha designed for modern 64-bit architectures. But on the other hand,
//! t1ha doesn't uses any one tricks nor instructions specific to any particular architecture:
//! therefore t1ha could be used on any CPU for which GCC provides support 64-bit arithmetics.
//! but unfortunately t1ha could be dramatically slowly on architectures
//! without native 64-bit operations.
//! This implementation of t1ha requires modern GNU C compatible compiler,
//! includes Clang/LLVM; or MSVC++ 14.0 (Visual Studio 2015).
//!
//! # Example
//!
//! ```
//! use std::hash::{Hash, Hasher};
//!
//! use fasthash::{t1ha, T1haHasher};
//!
//! fn hash<T: Hash>(t: &T) -> u64 {
//!     let mut s = T1haHasher::new();
//!     t.hash(&mut s);
//!     s.finish()
//! }
//!
//! let h = t1ha::hash64(b"hello world\xff");
//!
//! assert_eq!(h, hash(&"hello world"));
//! ```
//!
use std::os::raw::c_void;

use ffi;

use hasher::FastHash;

#[doc(hidden)]
pub struct T1ha64Le {}

impl FastHash for T1ha64Le {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha(bytes.as_ref().as_ptr() as *const c_void,
                      bytes.as_ref().len(),
                      seed)
        }
    }
}

impl_hasher!(T1ha64LeHasher, T1ha64Le);

#[doc(hidden)]
pub struct T1ha64Be {}

impl FastHash for T1ha64Be {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha_64be(bytes.as_ref().as_ptr() as *const c_void,
                           bytes.as_ref().len(),
                           seed)
        }
    }
}

impl_hasher!(T1ha64BeHasher, T1ha64Be);

#[doc(hidden)]
pub struct T1ha32Le {}

impl FastHash for T1ha32Le {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha_32le(bytes.as_ref().as_ptr() as *const c_void,
                           bytes.as_ref().len(),
                           seed)
        }
    }
}

impl_hasher!(T1ha32LeHasher, T1ha32Le);

#[doc(hidden)]
pub struct T1ha32Be {}

impl FastHash for T1ha32Be {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha_32be(bytes.as_ref().as_ptr() as *const c_void,
                           bytes.as_ref().len(),
                           seed)
        }
    }
}

impl_hasher!(T1ha32BeHasher, T1ha32Be);

#[cfg(feature = "sse42")]
#[doc(hidden)]
pub struct T1ha64Crc {}

#[cfg(feature = "sse42")]
impl FastHash for T1ha64Crc {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha_ia32crc(bytes.as_ref().as_ptr() as *const c_void,
                              bytes.as_ref().len(),
                              seed)
        }
    }
}

#[cfg(feature = "sse42")]
impl_hasher!(T1ha64CrcHasher, T1ha64Crc);

/// T1Hash 32-bit hash functions for a byte array.
#[inline]
pub fn hash32<T: AsRef<[u8]>>(v: &T) -> u64 {
    T1ha32Le::hash(v)
}

/// T1Hash 32-bit hash function for a byte array.
/// For convenience, a 32-bit seed is also hashed into the result.
#[inline]
pub fn hash32_with_seed<T: AsRef<[u8]>>(v: &T, seed: u64) -> u64 {
    T1ha32Le::hash_with_seed(v, seed)
}

/// T1Hash 64-bit hash functions for a byte array.
#[cfg(not(feature = "sse42"))]
#[inline]
pub fn hash64<T: AsRef<[u8]>>(v: &T) -> u64 {
    T1ha64Le::hash(v)
}

/// T1Hash 64-bit hash function for a byte array.
/// For convenience, a 64-bit seed is also hashed into the result.
#[cfg(not(feature = "sse42"))]
#[inline]
pub fn hash64_with_seed<T: AsRef<[u8]>>(v: &T, seed: u64) -> u64 {
    T1ha64Le::hash_with_seed(v, seed)
}

/// T1Hash 64-bit hash function for a byte array using HW CRC instruction.
/// That require SSE4.2 instructions to be available.
#[cfg(any(feature = "doc", feature = "sse42"))]
#[inline]
pub fn hash64<T: AsRef<[u8]>>(v: &T) -> u64 {
    T1ha64Crc::hash(v)
}

/// T1Hash 64-bit hash function for a byte array using HW CRC instruction.
/// That require SSE4.2 instructions to be available.
/// For convenience, a 64-bit seed is also hashed into the result.
#[cfg(any(feature = "doc", feature = "sse42"))]
#[inline]
pub fn hash64_with_seed<T: AsRef<[u8]>>(v: &T, seed: u64) -> u64 {
    T1ha64Crc::hash_with_seed(v, seed)
}

#[cfg(test)]
mod tests {
    use std::hash::Hasher;

    use hasher::FastHash;
    use super::*;

    #[test]
    fn test_t1ha_32_le() {
        assert_eq!(T1ha32Le::hash(b"hello"), 1026677640742993727);
        assert_eq!(T1ha32Le::hash_with_seed(b"hello", 123), 9601366527779802491);
        assert_eq!(T1ha32Le::hash(b"helloworld"), 15938092988918204794);

        let mut h = T1ha32LeHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 1026677640742993727);

        h.write(b"world");
        assert_eq!(h.finish(), 15938092988918204794);
    }

    #[test]
    fn test_t1ha_32_be() {
        assert_eq!(T1ha32Be::hash(b"hello"), 14968514543474807977);
        assert_eq!(T1ha32Be::hash_with_seed(b"hello", 123),
                   18258318775703579484);
        assert_eq!(T1ha32Be::hash(b"helloworld"), 6104456647282750739);

        let mut h = T1ha32BeHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 14968514543474807977);

        h.write(b"world");
        assert_eq!(h.finish(), 6104456647282750739);
    }

    #[test]
    fn test_t1ha_64_le() {
        assert_eq!(T1ha64Le::hash(b"hello"), 12810198970222070563);
        assert_eq!(T1ha64Le::hash_with_seed(b"hello", 123), 7105133355958514544);
        assert_eq!(T1ha64Le::hash(b"helloworld"), 16997942636322422782);

        let mut h = T1ha64LeHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 12810198970222070563);

        h.write(b"world");
        assert_eq!(h.finish(), 16997942636322422782);
    }

    #[test]
    fn test_t1ha_64_be() {
        assert_eq!(T1ha64Be::hash(b"hello"), 14880640220959195744);
        assert_eq!(T1ha64Be::hash_with_seed(b"hello", 123), 1421069625385545216);
        assert_eq!(T1ha64Be::hash(b"helloworld"), 15825971635414726702);

        let mut h = T1ha64BeHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 14880640220959195744);

        h.write(b"world");
        assert_eq!(h.finish(), 15825971635414726702);
    }

    #[test]
    fn test_t1ha_64_crc() {
        assert_eq!(T1ha64Crc::hash(b"hello"), 12810198970222070563);
        assert_eq!(T1ha64Crc::hash_with_seed(b"hello", 123),
                   7105133355958514544);
        assert_eq!(T1ha64Crc::hash(b"helloworld"), 16997942636322422782);

        let mut h = T1ha64CrcHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 12810198970222070563);

        h.write(b"world");
        assert_eq!(h.finish(), 16997942636322422782);
    }
}
<commit_msg>Improve document<commit_after>//! Fast Positive Hash, aka "Позитивный Хэш"
//!
//! by Positive Technologies.
//!
//! https://github.com/leo-yuriev/t1ha
//!
//! Briefly, it is a 64-bit Hash Function:
//!
//! Created for 64-bit little-endian platforms, in predominantly for x86_64,
//! but without penalties could runs on any 64-bit CPU.
//! In most cases up to 15% faster than City64, xxHash, mum-hash,
//! metro-hash and all others which are not use specific hardware tricks.
//! Not suitable for cryptography.
//! Please see t1ha.c for implementation details.
//!
//! Acknowledgement:
//!
//! The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев)
//! for The 1Hippeus project - zerocopy messaging in the spirit of Sparta!
//!
//! Requirements and Portability:
//!
//! t1ha designed for modern 64-bit architectures. But on the other hand,
//! t1ha doesn't uses any one tricks nor instructions specific to any particular architecture:
//! therefore t1ha could be used on any CPU for which GCC provides support 64-bit arithmetics.
//! but unfortunately t1ha could be dramatically slowly on architectures
//! without native 64-bit operations.
//! This implementation of t1ha requires modern GNU C compatible compiler,
//! includes Clang/LLVM; or MSVC++ 14.0 (Visual Studio 2015).
//!
//! # Example
//!
//! ```
//! use std::hash::{Hash, Hasher};
//!
//! use fasthash::{t1ha, T1haHasher};
//!
//! fn hash<T: Hash>(t: &T) -> u64 {
//!     let mut s = T1haHasher::new();
//!     t.hash(&mut s);
//!     s.finish()
//! }
//!
//! let h = t1ha::hash64(b"hello world\xff");
//!
//! assert_eq!(h, hash(&"hello world"));
//! ```
//!
use std::os::raw::c_void;

use ffi;

use hasher::FastHash;

/// T1ha 64-bit hash functions for 64-bit little-endian platforms.
pub struct T1ha64Le {}

impl FastHash for T1ha64Le {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha(bytes.as_ref().as_ptr() as *const c_void,
                      bytes.as_ref().len(),
                      seed)
        }
    }
}

impl_hasher!(T1ha64LeHasher, T1ha64Le);

/// T1ha 64-bit hash functions for 64-bit big-endian platforms.
pub struct T1ha64Be {}

impl FastHash for T1ha64Be {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha_64be(bytes.as_ref().as_ptr() as *const c_void,
                           bytes.as_ref().len(),
                           seed)
        }
    }
}

impl_hasher!(T1ha64BeHasher, T1ha64Be);

/// T1ha 32-bit hash functions for 32-bit little-endian platforms.
pub struct T1ha32Le {}

impl FastHash for T1ha32Le {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha_32le(bytes.as_ref().as_ptr() as *const c_void,
                           bytes.as_ref().len(),
                           seed)
        }
    }
}

impl_hasher!(T1ha32LeHasher, T1ha32Le);

/// T1ha 32-bit hash functions for 32-bit big-endian platforms.
pub struct T1ha32Be {}

impl FastHash for T1ha32Be {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha_32be(bytes.as_ref().as_ptr() as *const c_void,
                           bytes.as_ref().len(),
                           seed)
        }
    }
}

impl_hasher!(T1ha32BeHasher, T1ha32Be);

/// T1ha 64-bit hash functions using HW CRC instruction for 64-bit little-endian platforms.
#[cfg(feature = "sse42")]
pub struct T1ha64Crc {}

#[cfg(feature = "sse42")]
impl FastHash for T1ha64Crc {
    type Value = u64;
    type Seed = u64;

    #[inline]
    fn hash_with_seed<T: AsRef<[u8]>>(bytes: &T, seed: u64) -> u64 {
        unsafe {
            ffi::t1ha_ia32crc(bytes.as_ref().as_ptr() as *const c_void,
                              bytes.as_ref().len(),
                              seed)
        }
    }
}

#[cfg(feature = "sse42")]
impl_hasher!(T1ha64CrcHasher, T1ha64Crc);

/// T1Hash 32-bit hash functions for a byte array.
#[inline]
pub fn hash32<T: AsRef<[u8]>>(v: &T) -> u64 {
    T1ha32Le::hash(v)
}

/// T1Hash 32-bit hash function for a byte array.
/// For convenience, a 32-bit seed is also hashed into the result.
#[inline]
pub fn hash32_with_seed<T: AsRef<[u8]>>(v: &T, seed: u64) -> u64 {
    T1ha32Le::hash_with_seed(v, seed)
}

/// T1Hash 64-bit hash functions for a byte array.
#[cfg(not(feature = "sse42"))]
#[inline]
pub fn hash64<T: AsRef<[u8]>>(v: &T) -> u64 {
    T1ha64Le::hash(v)
}

/// T1Hash 64-bit hash function for a byte array.
/// For convenience, a 64-bit seed is also hashed into the result.
#[cfg(not(feature = "sse42"))]
#[inline]
pub fn hash64_with_seed<T: AsRef<[u8]>>(v: &T, seed: u64) -> u64 {
    T1ha64Le::hash_with_seed(v, seed)
}

/// T1Hash 64-bit hash function for a byte array using HW CRC instruction.
/// That require SSE4.2 instructions to be available.
#[cfg(any(feature = "doc", feature = "sse42"))]
#[inline]
pub fn hash64<T: AsRef<[u8]>>(v: &T) -> u64 {
    T1ha64Crc::hash(v)
}

/// T1Hash 64-bit hash function for a byte array using HW CRC instruction.
/// That require SSE4.2 instructions to be available.
/// For convenience, a 64-bit seed is also hashed into the result.
#[cfg(any(feature = "doc", feature = "sse42"))]
#[inline]
pub fn hash64_with_seed<T: AsRef<[u8]>>(v: &T, seed: u64) -> u64 {
    T1ha64Crc::hash_with_seed(v, seed)
}

#[cfg(test)]
mod tests {
    use std::hash::Hasher;

    use hasher::FastHash;
    use super::*;

    #[test]
    fn test_t1ha_32_le() {
        assert_eq!(T1ha32Le::hash(b"hello"), 1026677640742993727);
        assert_eq!(T1ha32Le::hash_with_seed(b"hello", 123), 9601366527779802491);
        assert_eq!(T1ha32Le::hash(b"helloworld"), 15938092988918204794);

        let mut h = T1ha32LeHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 1026677640742993727);

        h.write(b"world");
        assert_eq!(h.finish(), 15938092988918204794);
    }

    #[test]
    fn test_t1ha_32_be() {
        assert_eq!(T1ha32Be::hash(b"hello"), 14968514543474807977);
        assert_eq!(T1ha32Be::hash_with_seed(b"hello", 123),
                   18258318775703579484);
        assert_eq!(T1ha32Be::hash(b"helloworld"), 6104456647282750739);

        let mut h = T1ha32BeHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 14968514543474807977);

        h.write(b"world");
        assert_eq!(h.finish(), 6104456647282750739);
    }

    #[test]
    fn test_t1ha_64_le() {
        assert_eq!(T1ha64Le::hash(b"hello"), 12810198970222070563);
        assert_eq!(T1ha64Le::hash_with_seed(b"hello", 123), 7105133355958514544);
        assert_eq!(T1ha64Le::hash(b"helloworld"), 16997942636322422782);

        let mut h = T1ha64LeHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 12810198970222070563);

        h.write(b"world");
        assert_eq!(h.finish(), 16997942636322422782);
    }

    #[test]
    fn test_t1ha_64_be() {
        assert_eq!(T1ha64Be::hash(b"hello"), 14880640220959195744);
        assert_eq!(T1ha64Be::hash_with_seed(b"hello", 123), 1421069625385545216);
        assert_eq!(T1ha64Be::hash(b"helloworld"), 15825971635414726702);

        let mut h = T1ha64BeHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 14880640220959195744);

        h.write(b"world");
        assert_eq!(h.finish(), 15825971635414726702);
    }

    #[test]
    fn test_t1ha_64_crc() {
        assert_eq!(T1ha64Crc::hash(b"hello"), 12810198970222070563);
        assert_eq!(T1ha64Crc::hash_with_seed(b"hello", 123),
                   7105133355958514544);
        assert_eq!(T1ha64Crc::hash(b"helloworld"), 16997942636322422782);

        let mut h = T1ha64CrcHasher::new();

        h.write(b"hello");
        assert_eq!(h.finish(), 12810198970222070563);

        h.write(b"world");
        assert_eq!(h.finish(), 16997942636322422782);
    }
}
<|endoftext|>


<commit_before>/// TODO: submit upstream

use std::io::{Reader, Writer, Seek, SeekStyle};
use std::io::mem::{MemReader, MemWriter};

/// Writes to an owned, growable byte vector but also implements read with fail-on-call methods.
struct MemWriterFakeStream(MemWriter);

impl MemWriterFakeStream {
    pub fn new() -> MemWriterFakeStream { MemWriterFakeStream(MemWriter::new()) }
}

impl Writer for MemWriterFakeStream {
    fn write(&mut self, buf: &[u8]) { (**self).write(buf) }
    fn flush(&mut self) { (**self).flush() }
}

impl Seek for MemWriterFakeStream {
    fn tell(&self) -> u64 { (**self).tell() }
    fn seek(&mut self, pos: i64, style: SeekStyle) { (**self).seek(pos, style) }
}

impl Reader for MemWriterFakeStream {
    fn read(&mut self, _buf: &mut [u8]) -> Option<uint> {
        fail!("Uh oh, you didn't aught to call MemWriterFakeStream.read()!")
    }
    fn eof(&mut self) -> bool {
        fail!("Uh oh, you didn't aught to call MemWriterFakeStream.eof()!")
    }
}

/// Reads from an owned byte vector, but also implements write with fail-on-call methods.
pub struct MemReaderFakeStream(MemReader);

impl MemReaderFakeStream {
    pub fn new(buf: ~[u8]) -> MemReaderFakeStream { MemReaderFakeStream(MemReader::new(buf)) }
}

impl Reader for MemReaderFakeStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { (**self).read(buf) }
    fn eof(&mut self) -> bool { (**self).eof() }
}

impl Seek for MemReaderFakeStream {
    fn tell(&self) -> u64 { (**self).tell() }
    fn seek(&mut self, pos: i64, style: SeekStyle) { (**self).seek(pos, style) }
}

impl Writer for MemReaderFakeStream {
    fn write(&mut self, _buf: &[u8]) {
        fail!("Uh oh, you didn't aught to call MemReaderFakeStream.write()!")
    }
    fn flush(&mut self) {
        fail!("Uh oh, you didn't aught to call MemReaderFakeStream.flush()!")
    }
}

#[cfg(test)]
mod test {
    use super::{MemReaderFakeStream, MemWriterFakeStream};

    #[test]
    fn test_mem_writer_fake_stream() {
        let mut writer = MemWriterFakeStream::new();
        assert_eq!(writer.tell(), 0);
        writer.write([0]);
        assert_eq!(writer.tell(), 1);
        writer.write([1, 2, 3]);
        writer.write([4, 5, 6, 7]);
        assert_eq!(writer.tell(), 8);
    }

    #[test]
    fn test_mem_reader_fake_stream() {
        let mut reader = MemReaderFakeStream::new(~[0, 1, 2, 3, 4, 5, 6, 7]);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }
}
<commit_msg>Remove tuple-struct derefing (mozilla/rust#11188)<commit_after>/// TODO: submit upstream

use std::io::{Reader, Writer, Seek, SeekStyle};
use std::io::mem::{MemReader, MemWriter};

/// Writes to an owned, growable byte vector but also implements read with fail-on-call methods.
struct MemWriterFakeStream(MemWriter);

impl MemWriterFakeStream {
    pub fn new() -> MemWriterFakeStream { MemWriterFakeStream(MemWriter::new()) }
}

impl Writer for MemWriterFakeStream {
    fn write(&mut self, buf: &[u8]) {
        let &MemWriterFakeStream(ref mut s) = self;
        s.write(buf)
    }

    fn flush(&mut self) {
        let &MemWriterFakeStream(ref mut s) = self;
        s.flush()
    }
}

impl Seek for MemWriterFakeStream {
    fn tell(&self) -> u64 {
        let &MemWriterFakeStream(ref s) = self;
        s.tell()
    }

    fn seek(&mut self, pos: i64, style: SeekStyle) {
        let &MemWriterFakeStream(ref mut s) = self;
        s.seek(pos, style)
    }
}

impl Reader for MemWriterFakeStream {
    fn read(&mut self, _buf: &mut [u8]) -> Option<uint> {
        fail!("Uh oh, you didn't aught to call MemWriterFakeStream.read()!")
    }
    fn eof(&mut self) -> bool {
        fail!("Uh oh, you didn't aught to call MemWriterFakeStream.eof()!")
    }
}

/// Reads from an owned byte vector, but also implements write with fail-on-call methods.
pub struct MemReaderFakeStream(MemReader);

impl MemReaderFakeStream {
    pub fn new(buf: ~[u8]) -> MemReaderFakeStream { MemReaderFakeStream(MemReader::new(buf)) }
}

impl Reader for MemReaderFakeStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        let &MemReaderFakeStream(ref mut s) = self;
        s.read(buf)
    }

    fn eof(&mut self) -> bool {
        let &MemReaderFakeStream(ref mut s) = self;
        s.eof()
    }
}

impl Seek for MemReaderFakeStream {
    fn tell(&self) -> u64 {
        let &MemReaderFakeStream(ref s) = self;
        s.tell()
    }

    fn seek(&mut self, pos: i64, style: SeekStyle) {
        let &MemReaderFakeStream(ref mut s) = self;
        s.seek(pos, style)
    }
}

impl Writer for MemReaderFakeStream {
    fn write(&mut self, _buf: &[u8]) {
        fail!("Uh oh, you didn't aught to call MemReaderFakeStream.write()!")
    }
    fn flush(&mut self) {
        fail!("Uh oh, you didn't aught to call MemReaderFakeStream.flush()!")
    }
}

#[cfg(test)]
mod test {
    use super::{MemReaderFakeStream, MemWriterFakeStream};

    #[test]
    fn test_mem_writer_fake_stream() {
        let mut writer = MemWriterFakeStream::new();
        assert_eq!(writer.tell(), 0);
        writer.write([0]);
        assert_eq!(writer.tell(), 1);
        writer.write([1, 2, 3]);
        writer.write([4, 5, 6, 7]);
        assert_eq!(writer.tell(), 8);
    }

    #[test]
    fn test_mem_reader_fake_stream() {
        let mut reader = MemReaderFakeStream::new(~[0, 1, 2, 3, 4, 5, 6, 7]);
        let mut buf = [];
        assert_eq!(reader.read(buf), Some(0));
        assert_eq!(reader.tell(), 0);
        let mut buf = [0];
        assert_eq!(reader.read(buf), Some(1));
        assert_eq!(reader.tell(), 1);
        assert_eq!(buf, [0]);
        let mut buf = [0, ..4];
        assert_eq!(reader.read(buf), Some(4));
        assert_eq!(reader.tell(), 5);
        assert_eq!(buf, [1, 2, 3, 4]);
        assert_eq!(reader.read(buf), Some(3));
        assert_eq!(buf.slice(0, 3), [5, 6, 7]);
        assert!(reader.eof());
        assert_eq!(reader.read(buf), None);
        assert!(reader.eof());
    }
}
<|endoftext|>


<commit_before>/// TODO: submit upstream

use std::io::{IoResult, Seek, SeekStyle};
use std::io::{MemReader, MemWriter};

/// Writes to an owned, growable byte vector but also implements read with fail-on-call methods.
struct MemWriterFakeStream(MemWriter);

impl MemWriterFakeStream {
    pub fn new() -> MemWriterFakeStream { MemWriterFakeStream(MemWriter::new()) }
}

impl Writer for MemWriterFakeStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let &MemWriterFakeStream(ref mut s) = self;
        s.write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        let &MemWriterFakeStream(ref mut s) = self;
        s.flush()
    }
}

impl Seek for MemWriterFakeStream {
    fn tell(&self) -> IoResult<u64> {
        let &MemWriterFakeStream(ref s) = self;
        s.tell()
    }

    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
        let &MemWriterFakeStream(ref mut s) = self;
        s.seek(pos, style)
    }
}

impl Reader for MemWriterFakeStream {
    fn read(&mut self, _buf: &mut [u8]) -> IoResult<uint> {
        fail!("Uh oh, you didn't aught to call MemWriterFakeStream.read()!")
    }
}

/// Reads from an owned byte vector, but also implements write with fail-on-call methods.
pub struct MemReaderFakeStream(MemReader);

impl MemReaderFakeStream {
    pub fn new(buf: Vec<u8>) -> MemReaderFakeStream { MemReaderFakeStream(MemReader::new(buf)) }
}

impl Reader for MemReaderFakeStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let &MemReaderFakeStream(ref mut s) = self;
        s.read(buf)
    }
}

impl Seek for MemReaderFakeStream {
    fn tell(&self) -> IoResult<u64> {
        let &MemReaderFakeStream(ref s) = self;
        s.tell()
    }

    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
        let &MemReaderFakeStream(ref mut s) = self;
        s.seek(pos, style)
    }
}

impl Writer for MemReaderFakeStream {
    fn write(&mut self, _buf: &[u8]) -> IoResult<()> {
        fail!("Uh oh, you didn't aught to call MemReaderFakeStream.write()!")
    }
    fn flush(&mut self) -> IoResult<()> {
        fail!("Uh oh, you didn't aught to call MemReaderFakeStream.flush()!")
    }
}

#[cfg(test)]
mod test {
    use super::{MemReaderFakeStream, MemWriterFakeStream};

    #[test]
    fn test_mem_writer_fake_stream() {
        let mut writer = MemWriterFakeStream::new();
        assert_eq!(writer.tell(),              Ok(0));
        assert_eq!(writer.write([0]),          Ok(()));
        assert_eq!(writer.tell(),              Ok(1));
        assert_eq!(writer.write([1, 2, 3]),    Ok(()));
        assert_eq!(writer.write([4, 5, 6, 7]), Ok(()));
        assert_eq!(writer.tell(),              Ok(8));
    }

    #[test]
    fn test_mem_reader_fake_stream() {
        let mut reader = MemReaderFakeStream::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
        let mut buf = vec![];
        assert_eq!(reader.read(buf),      Ok(0));
        assert_eq!(reader.tell(),         Ok(0));
        let mut buf = vec![0];
        assert_eq!(reader.read(buf),      Ok(1));
        assert_eq!(reader.tell(),         Ok(1));
        assert_eq!(buf,                   vec![0]);
        let mut buf = vec![0, 0, 0, 0];
        assert_eq!(reader.read(buf),      Ok(4));
        assert_eq!(reader.tell(),         Ok(5));
        assert_eq!(buf,                   vec[1, 2, 3, 4]);
        assert_eq!(reader.read(buf),      Ok(3));
        assert_eq!(buf.slice(0, 3),       &[5, 6, 7]);
        assert_eq!(reader.read(buf).ok(), None);
    }
}
<commit_msg>Fixed tests in memstream.rs<commit_after>/// TODO: submit upstream

use std::io::{IoResult, Seek, SeekStyle};
use std::io::{MemReader, MemWriter};

/// Writes to an owned, growable byte vector but also implements read with fail-on-call methods.
struct MemWriterFakeStream(MemWriter);

impl MemWriterFakeStream {
    pub fn new() -> MemWriterFakeStream { MemWriterFakeStream(MemWriter::new()) }
}

impl Writer for MemWriterFakeStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let &MemWriterFakeStream(ref mut s) = self;
        s.write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        let &MemWriterFakeStream(ref mut s) = self;
        s.flush()
    }
}

impl Seek for MemWriterFakeStream {
    fn tell(&self) -> IoResult<u64> {
        let &MemWriterFakeStream(ref s) = self;
        s.tell()
    }

    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
        let &MemWriterFakeStream(ref mut s) = self;
        s.seek(pos, style)
    }
}

impl Reader for MemWriterFakeStream {
    fn read(&mut self, _buf: &mut [u8]) -> IoResult<uint> {
        fail!("Uh oh, you didn't aught to call MemWriterFakeStream.read()!")
    }
}

/// Reads from an owned byte vector, but also implements write with fail-on-call methods.
pub struct MemReaderFakeStream(MemReader);

impl MemReaderFakeStream {
    pub fn new(buf: Vec<u8>) -> MemReaderFakeStream { MemReaderFakeStream(MemReader::new(buf)) }
}

impl Reader for MemReaderFakeStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let &MemReaderFakeStream(ref mut s) = self;
        s.read(buf)
    }
}

impl Seek for MemReaderFakeStream {
    fn tell(&self) -> IoResult<u64> {
        let &MemReaderFakeStream(ref s) = self;
        s.tell()
    }

    fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
        let &MemReaderFakeStream(ref mut s) = self;
        s.seek(pos, style)
    }
}

impl Writer for MemReaderFakeStream {
    fn write(&mut self, _buf: &[u8]) -> IoResult<()> {
        fail!("Uh oh, you didn't aught to call MemReaderFakeStream.write()!")
    }
    fn flush(&mut self) -> IoResult<()> {
        fail!("Uh oh, you didn't aught to call MemReaderFakeStream.flush()!")
    }
}

#[cfg(test)]
mod test {
    use super::{MemReaderFakeStream, MemWriterFakeStream};

    #[test]
    fn test_mem_writer_fake_stream() {
        let mut writer = MemWriterFakeStream::new();
        assert_eq!(writer.tell(),              Ok(0));
        assert_eq!(writer.write([0]),          Ok(()));
        assert_eq!(writer.tell(),              Ok(1));
        assert_eq!(writer.write([1, 2, 3]),    Ok(()));
        assert_eq!(writer.write([4, 5, 6, 7]), Ok(()));
        assert_eq!(writer.tell(),              Ok(8));
    }

    #[test]
    fn test_mem_reader_fake_stream() {
        let mut reader = MemReaderFakeStream::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
        let mut buf = vec![];
        assert_eq!(reader.read(buf.as_mut_slice()),      Ok(0));
        assert_eq!(reader.tell(),         Ok(0));
        let mut buf = vec![0];
        assert_eq!(reader.read(buf.as_mut_slice()),      Ok(1));
        assert_eq!(reader.tell(),         Ok(1));
        assert_eq!(buf,                   vec![0]);
        let mut buf = vec![0, 0, 0, 0];
        assert_eq!(reader.read(buf.as_mut_slice()),      Ok(4));
        assert_eq!(reader.tell(),         Ok(5));
        assert_eq!(buf,                   vec![1, 2, 3, 4]);
        assert_eq!(reader.read(buf.as_mut_slice()),      Ok(3));
        assert_eq!(buf.slice(0, 3),       &[5, 6, 7]);
        assert_eq!(reader.read(buf.as_mut_slice()).ok(), None);
    }
}
<|endoftext|>