<commit_before>use au = gfx::geometry;
use core::dlist::DList;
use core::dvec::DVec;
use css::values::{BoxAuto, BoxLength, Px};
use dl = gfx::display_list;
use dom::node::Node;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::geometry::au;
use layout::box::{RenderBox, ImageBox, TextBox, GenericBox, UnscannedTextBox};
use layout::context::LayoutContext;
use layout::flow::{FlowContext, InlineFlow};
use layout::text::TextBoxData;
use num::Num;
use servo_text::text_run::TextRun;
use std::arc;
use util::tree;

/*
Lineboxes are represented as offsets into the child list, rather than
as an object that "owns" boxes. Choosing a different set of line
breaks requires a new list of offsets, and possibly some splitting and
merging of TextBoxes.

A similar list will keep track of the mapping between CSS boxes and
the corresponding render boxes in the inline flow.

After line breaks are determined, render boxes in the inline flow may
overlap visually. For example, in the case of nested inline CSS boxes,
outer inlines must be at least as large as the inner inlines, for
purposes of drawing noninherited things like backgrounds, borders,
outlines.

N.B. roc has an alternative design where the list instead consists of
things like "start outer box, text, start inner box, text, end inner
box, text, end outer box, text". This seems a little complicated to
serve as the starting point, but the current design doesn't make it
hard to try out that alternative.
*/

type BoxRange = {start: u8, len: u8};
type NodeRange = {node: Node, span: BoxRange};

// stack-allocated object for scanning an inline flow into
// TextRun-containing TextBoxes.
struct TextRunScanner {
    mut in_clump: bool,
    mut clump_start: uint,
    mut clump_end: uint,
    flow: @FlowContext,
}

fn TextRunScanner(flow: @FlowContext) -> TextRunScanner {
    TextRunScanner {
        in_clump: false,
        clump_start: 0,
        clump_end: 0,
        flow: flow,
    }
}

impl TextRunScanner {
    fn scan_for_runs(ctx: &LayoutContext) {
        // if reused, must be reset.
        assert !self.in_clump;
        assert self.flow.inline().boxes.len() > 0;

        do self.flow.inline().boxes.swap |in_boxes| {
            debug!("scanning %u boxes for text runs...", in_boxes.len());

            let temp_boxes = DVec();
            let mut prev_box: @RenderBox = in_boxes[0];

            for uint::range(0, in_boxes.len()) |i| {
                debug!("considering box: %?", in_boxes[i].debug_str());

                let can_coalesce_with_prev = i > 0 && boxes_can_be_coalesced(prev_box, in_boxes[i]);

                match (self.in_clump, can_coalesce_with_prev) {
                    // start a new clump
                    (false, _)    => { self.reset_clump_to_index(i); },
                    // extend clump
                    (true, true)  => { self.clump_end = i; },
                    // boundary detected; flush and start new clump
                    (true, false) => {
                        self.flush_clump_to_list(ctx, in_boxes, &temp_boxes);
                        self.reset_clump_to_index(i);
                    }
                };

                prev_box = in_boxes[i];
            }
            // handle remaining clumps
            if self.in_clump {
                self.flush_clump_to_list(ctx, in_boxes, &temp_boxes);
            }

            debug!("swapping out boxes.");
            // swap out old and new box list of flow, by supplying
            // temp boxes as return value to boxes.swap |...|
            dvec::unwrap(temp_boxes)
        }

        // helper functions
        pure fn boxes_can_be_coalesced(a: @RenderBox, b: @RenderBox) -> bool {
            assert !core::box::ptr_eq(a, b);

            match (a, b) {
                // TODO: check whether text styles, fonts are the same.
                (@UnscannedTextBox(*), @UnscannedTextBox(*)) => a.can_merge_with_box(b),
                (_, _) => false
            }
        }
    }

    fn reset_clump_to_index(i: uint) {
        debug!("resetting clump to %u", i);

        self.clump_start = i;
        self.clump_end = i;
        self.in_clump = true;
    }

    fn flush_clump_to_list(ctx: &LayoutContext,
                           in_boxes: &[@RenderBox], temp_boxes: &DVec<@RenderBox>) {
        assert self.in_clump;

        debug!("flushing when start=%?,end=%?", self.clump_start, self.clump_end);

        let is_singleton = (self.clump_start == self.clump_end);
        let is_text_clump = match in_boxes[self.clump_start] {
            @UnscannedTextBox(*) => true,
            _ => false
        };

        // TODO: repair the mapping of DOM elements to boxes if it changed.
        // (the mapping does not yet exist; see Issue #103)
        match (is_singleton, is_text_clump) {
            (false, false) => fail ~"WAT: can't coalesce non-text boxes in flush_clump_to_list()!",
            (true, false) => { temp_boxes.push(in_boxes[self.clump_start]); }
            (true, true)  => {
                let text = in_boxes[self.clump_start].raw_text();
                let text_len = text.len();
                // TODO: use actual font for corresponding DOM node to create text run.
                let run = @TextRun(&*ctx.font_cache.get_test_font(), move text);
                let box_guts = TextBoxData(run, 0, text_len);
                debug!("pushing when start=%?,end=%?", self.clump_start, self.clump_end);
                temp_boxes.push(@TextBox(copy *in_boxes[self.clump_start].d(), box_guts));
            },
            (false, true) => {
                let mut run_str : ~str = ~"";
                // TODO: is using ropes to construct the merged text any faster?
                do uint::range(self.clump_start, self.clump_end+1) |i| {
                    run_str = str::append(copy run_str, in_boxes[i].raw_text()); true
                }
                // TODO: use actual font for corresponding DOM node to create text run.
                let run = @TextRun(&*ctx.font_cache.get_test_font(), move run_str);
                let box_guts = TextBoxData(run, 0, run.text.len());
                debug!("pushing when start=%?,end=%?", self.clump_start, self.clump_end);
                temp_boxes.push(@TextBox(copy *in_boxes[self.clump_start].d(), box_guts));
            }
        }
        self.in_clump = false;
    }
}

struct InlineFlowData {
    // A vec of all inline render boxes. Several boxes may
    // correspond to one Node/Element.
    boxes: DVec<@RenderBox>,
    // vec of ranges into boxes that represents line positions.
    // these ranges are disjoint, and are the result of inline layout.
    lines: DVec<BoxRange>,
    // vec of ranges into boxes that represent elements. These
    // ranges must be disjoint or well-nested, and are only related to
    // the content of boxes (not lines)
    elems: DVec<NodeRange>
}

fn InlineFlowData() -> InlineFlowData {
    InlineFlowData {
        boxes: DVec(),
        lines: DVec(),
        elems: DVec(),
    }
}

trait InlineLayout {
    pure fn starts_inline_flow() -> bool;

    fn bubble_widths_inline(@self, ctx: &LayoutContext);
    fn assign_widths_inline(@self, ctx: &LayoutContext);
    fn assign_height_inline(@self, ctx: &LayoutContext);
    fn build_display_list_inline(@self, a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
}

impl FlowContext : InlineLayout {
    pure fn starts_inline_flow() -> bool { match self { InlineFlow(*) => true, _ => false } }

    fn bubble_widths_inline(@self, ctx: &LayoutContext) {
        assert self.starts_inline_flow();

        debug!("box count: %u", self.inline().boxes.len());

        let scanner = TextRunScanner(self);
        scanner.scan_for_runs(ctx);

        let mut min_width = au(0);
        let mut pref_width = au(0);

        debug!("/box count: %u", self.inline().boxes.len());

        for self.inline().boxes.each |box| {
            debug!("measuring box: %s", box.debug_str());
            min_width = au::max(min_width, box.get_min_width(ctx));
            pref_width = au::max(pref_width, box.get_pref_width(ctx));
        }

        self.d().min_width = min_width;
        self.d().pref_width = pref_width;
    }

    /* Recursively (top-down) determines the actual width of child
    contexts and boxes. When called on this context, the context has
    had its width set by the parent context. */
    fn assign_widths_inline(@self, ctx: &LayoutContext) {
        assert self.starts_inline_flow();

        /* Perform inline flow with the available width. */
        //let avail_width = self.d().position.size.width;

        let line_height = au::from_px(20);
        //let mut cur_x = au(0);
        let mut cur_y = au(0);

        // TODO: remove test font uses
        let test_font = ctx.font_cache.get_test_font();

        for self.inline().boxes.each |box| {
            /* TODO: actually do inline flow.
            - Create a working linebox, and successively put boxes
            into it, splitting if necessary.

            - Set width and height for each positioned element based on
            where its chunks ended up.

            - Save the dvec of this context's lineboxes. */

            box.d().position.size.width = match *box {
                @ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).width),
                @TextBox(_,d) => {
                    // TODO: measure twice, cut once doesn't apply to text. Shouldn't need
                    // to measure text again here (should be inside TextBox.split)
                    let metrics = test_font.measure_text(d.run, d.offset, d.length);
                    metrics.advance
                },
                // TODO: this should be set to the extents of its children
                @GenericBox(*) => au(0),
                _ => fail fmt!("Tried to assign width to unknown Box variant: %?", box)
            };

            box.d().position.size.height = match *box {
                @ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).height),
                // TODO: we should use the bounding box of the actual text, i think?
                @TextBox(*) => test_font.metrics.em_size,
                // TODO: this should be set to the extents of its children
                @GenericBox(*) => au(0),
                _ => fail fmt!("Tried to assign width to unknown Box variant: %?", box)
            };

            box.d().position.origin = Point2D(au(0), cur_y);
            cur_y = cur_y.add(&au::max(line_height, box.d().position.size.height));
        } // for boxes.each |box|

    self.d().position.size.height = cur_y;

    /* There are no child contexts, so stop here. */

    // TODO: once there are 'inline-block' elements, this won't be
    // true.  In that case, perform inline flow, and then set the
    // block flow context's width as the width of the
    // 'inline-block' box that created this flow.
    }

    fn assign_height_inline(@self, _ctx: &LayoutContext) {
        // Don't need to set box or ctx heights, since that is done
        // during inline flowing.
    }

    fn build_display_list_inline(@self, builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
                                 offset: &Point2D<au>, list: &dl::DisplayList) {

        assert self.starts_inline_flow();

        // TODO: if the CSS box introducing this inline context is *not* anonymous,
        // we need to draw it too, in a way similar to BlowFlowContext

        // TODO: once we form line boxes and have their cached bounds, we can be
        // smarter and not recurse on a line if nothing in it can intersect dirty
        debug!("building display list for %u inline boxes", self.inline().boxes.len());
        for self.inline().boxes.each |box| {
            box.build_display_list(builder, dirty, offset, list)
        }

        // TODO: should inline-block elements have flows as children
        // of the inline flow, or should the flow be nested inside the
        // box somehow? Maybe it's best to unify flows and boxes into
        // the same enum, so inline-block flows are normal
        // (indivisible) children in the inline flow child list.
    }

} // @FlowContext : InlineLayout
<commit_msg>Clarify debugging output and var names in TextRunScanner; get ready for node range management code.<commit_after>use au = gfx::geometry;
use core::dlist::DList;
use core::dvec::DVec;
use css::values::{BoxAuto, BoxLength, Px};
use dl = gfx::display_list;
use dom::node::Node;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::geometry::au;
use layout::box::{RenderBox, ImageBox, TextBox, GenericBox, UnscannedTextBox};
use layout::context::LayoutContext;
use layout::flow::{FlowContext, InlineFlow};
use layout::text::TextBoxData;
use num::Num;
use servo_text::text_run::TextRun;
use servo_text::util::*;
use std::arc;
use util::tree;

/*
Lineboxes are represented as offsets into the child list, rather than
as an object that "owns" boxes. Choosing a different set of line
breaks requires a new list of offsets, and possibly some splitting and
merging of TextBoxes.

A similar list will keep track of the mapping between CSS boxes and
the corresponding render boxes in the inline flow.

After line breaks are determined, render boxes in the inline flow may
overlap visually. For example, in the case of nested inline CSS boxes,
outer inlines must be at least as large as the inner inlines, for
purposes of drawing noninherited things like backgrounds, borders,
outlines.

N.B. roc has an alternative design where the list instead consists of
things like "start outer box, text, start inner box, text, end inner
box, text, end outer box, text". This seems a little complicated to
serve as the starting point, but the current design doesn't make it
hard to try out that alternative.
*/

type BoxRange = {start: u8, len: u8};
type NodeRange = {node: Node, span: BoxRange};

// stack-allocated object for scanning an inline flow into
// TextRun-containing TextBoxes.
struct TextRunScanner {
    mut in_clump: bool,
    mut clump_start: uint,
    mut clump_end: uint,
    flow: @FlowContext,
}

fn TextRunScanner(flow: @FlowContext) -> TextRunScanner {
    TextRunScanner {
        in_clump: false,
        clump_start: 0,
        clump_end: 0,
        flow: flow,
    }
}

impl TextRunScanner {
    fn scan_for_runs(ctx: &LayoutContext) {
        // if reused, must be reset.
        assert !self.in_clump;
        assert self.flow.inline().boxes.len() > 0;

        do self.flow.inline().boxes.swap |in_boxes| {
            debug!("TextRunScanner: scanning %u boxes for text runs...", in_boxes.len());

            let temp_boxes = DVec();
            let mut prev_box: @RenderBox = in_boxes[0];

            for uint::range(0, in_boxes.len()) |i| {
                debug!("TextRunScanner: considering box: %?", in_boxes[i].debug_str());

                let can_coalesce_with_prev = i > 0 && boxes_can_be_coalesced(prev_box, in_boxes[i]);

                match (self.in_clump, can_coalesce_with_prev) {
                    // start a new clump
                    (false, _)    => { self.reset_clump_to_index(i); },
                    // extend clump
                    (true, true)  => { self.clump_end = i; },
                    // boundary detected; flush and start new clump
                    (true, false) => {
                        self.flush_clump_to_list(ctx, in_boxes, &temp_boxes);
                        self.reset_clump_to_index(i);
                    }
                };

                prev_box = in_boxes[i];
            }
            // handle remaining clumps
            if self.in_clump {
                self.flush_clump_to_list(ctx, in_boxes, &temp_boxes);
            }

            debug!("TextRunScanner: swapping out boxes.");
            // swap out old and new box list of flow, by supplying
            // temp boxes as return value to boxes.swap |...|
            dvec::unwrap(temp_boxes)
        }

        // helper functions
        pure fn boxes_can_be_coalesced(a: @RenderBox, b: @RenderBox) -> bool {
            assert !core::box::ptr_eq(a, b);

            match (a, b) {
                // TODO: check whether text styles, fonts are the same.
                (@UnscannedTextBox(*), @UnscannedTextBox(*)) => a.can_merge_with_box(b),
                (_, _) => false
            }
        }
    }

    fn reset_clump_to_index(i: uint) {
        debug!("TextRunScanner: resetting clump to %u", i);

        self.clump_start = i;
        self.clump_end = i;
        self.in_clump = true;
    }

    // a 'clump' is a range of inline flow leaves that can be merged
    // together into a single RenderBox. Adjacent text with the same
    // style can be merged, and nothing else can.
    //
    // the flow keeps track of the RenderBoxes contained by all
    // non-leaf DOM nodes. This is necessary for correct painting
    // order. Since we compress several leaf RenderBoxes here, the
    // mapping must be adjusted.
    fn flush_clump_to_list(ctx: &LayoutContext,
                           in_boxes: &[@RenderBox], out_boxes: &DVec<@RenderBox>) {
        assert self.in_clump;

        debug!("TextRunScanner: flushing boxes when start=%?,end=%?", self.clump_start, self.clump_end);

        let is_singleton = (self.clump_start == self.clump_end);
        let is_text_clump = match in_boxes[self.clump_start] {
            @UnscannedTextBox(*) => true,
            _ => false
        };

        do self.flow.inline().elems.borrow |_node_map: &[NodeRange]| {
        // TODO: repair the mapping of DOM elements to boxes if it changed.
        // (the mapping does not yet exist; see Issue #103)
        match (is_singleton, is_text_clump) {
            (false, false) => fail ~"WAT: can't coalesce non-text boxes in flush_clump_to_list()!",
            (true, false) => {
                debug!("TextRunScanner: pushing single non-text box when start=%u,end=%u",
                       self.clump_start, self.clump_end);
                out_boxes.push(in_boxes[self.clump_start]);
            },
            (true, true)  => {
                let text = in_boxes[self.clump_start].raw_text();
                // TODO: use actual CSS 'white-space' property of relevant style.
                let compression = CompressWhitespaceNewline;
                let transformed_text = transform_text(text, compression);
                // TODO: use actual font for corresponding DOM node to create text run.
                let run = @TextRun(&*ctx.font_cache.get_test_font(), move transformed_text);
                let box_guts = TextBoxData(run, 0, run.text.len());
                debug!("TextRunScanner: pushing single text box when start=%u,end=%u", self.clump_start, self.clump_end);
                out_boxes.push(@TextBox(copy *in_boxes[self.clump_start].d(), box_guts));
            },
            (false, true) => {
                let mut run_str : ~str = ~"";
                // TODO: is using ropes to construct the merged text any faster?
                do uint::range(self.clump_start, self.clump_end+1) |i| {
                    run_str = str::append(copy run_str, in_boxes[i].raw_text()); true
                }
                // TODO: use actual font for corresponding DOM node to create text run.
                let run = @TextRun(&*ctx.font_cache.get_test_font(), move run_str);
                let box_guts = TextBoxData(run, 0, run.text.len());
                debug!("TextRunScanner: pushing box(es) when start=%?,end=%?", self.clump_start, self.clump_end);
                out_boxes.push(@TextBox(copy *in_boxes[self.clump_start].d(), box_guts));
            }
        }
        self.in_clump = false;
        }
    }
}

struct InlineFlowData {
    // A vec of all inline render boxes. Several boxes may
    // correspond to one Node/Element.
    boxes: DVec<@RenderBox>,
    // vec of ranges into boxes that represents line positions.
    // these ranges are disjoint, and are the result of inline layout.
    lines: DVec<BoxRange>,
    // vec of ranges into boxes that represent elements. These
    // ranges must be disjoint or well-nested, and are only related to
    // the content of boxes (not lines)
    elems: DVec<NodeRange>
}

fn InlineFlowData() -> InlineFlowData {
    InlineFlowData {
        boxes: DVec(),
        lines: DVec(),
        elems: DVec(),
    }
}

trait InlineLayout {
    pure fn starts_inline_flow() -> bool;

    fn bubble_widths_inline(@self, ctx: &LayoutContext);
    fn assign_widths_inline(@self, ctx: &LayoutContext);
    fn assign_height_inline(@self, ctx: &LayoutContext);
    fn build_display_list_inline(@self, a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
}

impl FlowContext : InlineLayout {
    pure fn starts_inline_flow() -> bool { match self { InlineFlow(*) => true, _ => false } }

    fn bubble_widths_inline(@self, ctx: &LayoutContext) {
        assert self.starts_inline_flow();

        debug!("box count: %u", self.inline().boxes.len());

        let scanner = TextRunScanner(self);
        scanner.scan_for_runs(ctx);

        let mut min_width = au(0);
        let mut pref_width = au(0);

        debug!("/box count: %u", self.inline().boxes.len());

        for self.inline().boxes.each |box| {
            debug!("measuring box: %s", box.debug_str());
            min_width = au::max(min_width, box.get_min_width(ctx));
            pref_width = au::max(pref_width, box.get_pref_width(ctx));
        }

        self.d().min_width = min_width;
        self.d().pref_width = pref_width;
    }

    /* Recursively (top-down) determines the actual width of child
    contexts and boxes. When called on this context, the context has
    had its width set by the parent context. */
    fn assign_widths_inline(@self, ctx: &LayoutContext) {
        assert self.starts_inline_flow();

        /* Perform inline flow with the available width. */
        //let avail_width = self.d().position.size.width;

        let line_height = au::from_px(20);
        //let mut cur_x = au(0);
        let mut cur_y = au(0);

        // TODO: remove test font uses
        let test_font = ctx.font_cache.get_test_font();

        for self.inline().boxes.each |box| {
            /* TODO: actually do inline flow.
            - Create a working linebox, and successively put boxes
            into it, splitting if necessary.

            - Set width and height for each positioned element based on
            where its chunks ended up.

            - Save the dvec of this context's lineboxes. */

            box.d().position.size.width = match *box {
                @ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).width),
                @TextBox(_,d) => {
                    // TODO: measure twice, cut once doesn't apply to text. Shouldn't need
                    // to measure text again here (should be inside TextBox.split)
                    let metrics = test_font.measure_text(d.run, d.offset, d.length);
                    metrics.advance
                },
                // TODO: this should be set to the extents of its children
                @GenericBox(*) => au(0),
                _ => fail fmt!("Tried to assign width to unknown Box variant: %?", box)
            };

            box.d().position.size.height = match *box {
                @ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).height),
                // TODO: we should use the bounding box of the actual text, i think?
                @TextBox(*) => test_font.metrics.em_size,
                // TODO: this should be set to the extents of its children
                @GenericBox(*) => au(0),
                _ => fail fmt!("Tried to assign width to unknown Box variant: %?", box)
            };

            box.d().position.origin = Point2D(au(0), cur_y);
            cur_y = cur_y.add(&au::max(line_height, box.d().position.size.height));
        } // for boxes.each |box|

    self.d().position.size.height = cur_y;

    /* There are no child contexts, so stop here. */

    // TODO: once there are 'inline-block' elements, this won't be
    // true.  In that case, perform inline flow, and then set the
    // block flow context's width as the width of the
    // 'inline-block' box that created this flow.
    }

    fn assign_height_inline(@self, _ctx: &LayoutContext) {
        // Don't need to set box or ctx heights, since that is done
        // during inline flowing.
    }

    fn build_display_list_inline(@self, builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
                                 offset: &Point2D<au>, list: &dl::DisplayList) {

        assert self.starts_inline_flow();

        // TODO: if the CSS box introducing this inline context is *not* anonymous,
        // we need to draw it too, in a way similar to BlowFlowContext

        // TODO: once we form line boxes and have their cached bounds, we can be
        // smarter and not recurse on a line if nothing in it can intersect dirty
        debug!("building display list for %u inline boxes", self.inline().boxes.len());
        for self.inline().boxes.each |box| {
            box.build_display_list(builder, dirty, offset, list)
        }

        // TODO: should inline-block elements have flows as children
        // of the inline flow, or should the flow be nested inside the
        // box somehow? Maybe it's best to unify flows and boxes into
        // the same enum, so inline-block flows are normal
        // (indivisible) children in the inline flow child list.
    }

} // @FlowContext : InlineLayout
<|endoftext|>


<commit_before>extern crate elektra;

use elektra::{
    KDBError, KeyBuilder, KeySet, LookupOption, StringKey, ValidationError, WriteableKey, KDB,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Open a KDB session
    let mut kdb = KDB::open()?;

    // Create a keyset that will hold the keys we get from the get call
    let mut ks = KeySet::with_capacity(10);

    // Get the current state of the key database
    let mut parent_key = StringKey::new("user/test")?;
    kdb.get(&mut ks, &mut parent_key)?;

    // We can append a new key we want to store in the key database.
    let new_key: StringKey = KeyBuilder::new("user/test/mycolor")?.value("#fff").build();
    ks.append_key(new_key)?;

    // Lookup a key in the keyset and modify it
    // As an example, we're modifying the same key we just added
    if let Some(mut key) = ks.lookup_by_name("user/test/mycolor", LookupOption::KDB_O_NONE) {
        key.set_value("#ff00ff00");
    } else {
        panic!("Did not find the key!");
    }

    // Store the modified keyset
    // If we don't care about specific errors and just want to print
    // a nice error message, we could do
    // kdb.set(&mut ks, &mut parent_key).unwrap_or_else(|err| panic!("{}", err));

    // Instead, you may want to match on specific error types
    if let Err(KDBError::Validation(ValidationError::Syntactic(val_err))) =
        kdb.set(&mut ks, &mut parent_key)
    {
        panic!("{}", val_err);
    }

    Ok(())
}
<commit_msg>rust: Update error handling in KDB example<commit_after>extern crate elektra;

use elektra::{KeyBuilder, KeySet, LookupOption, StringKey, WriteableKey, KDB};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Open a KDB session
    let mut kdb = KDB::open()?;

    // Create a keyset that will hold the keys we get from the get call
    let mut ks = KeySet::with_capacity(10);

    // Get the current state of the key database
    let mut parent_key = StringKey::new("user/test")?;
    kdb.get(&mut ks, &mut parent_key)?;

    // We can append a new key we want to store in the key database.
    let new_key: StringKey = KeyBuilder::new("user/test/mycolor")?.value("#fff").build();
    ks.append_key(new_key);

    // Lookup a key in the keyset and modify it
    // As an example, we're modifying the same key we just added
    if let Some(mut key) = ks.lookup_by_name("user/test/mycolor", LookupOption::KDB_O_NONE) {
        key.set_value("#ff00ff00");
    } else {
        panic!("Did not find the key!");
    }

    // Store the modified keyset
    let set_res = kdb.set(&mut ks, &mut parent_key);

    // If we don't care about specific errors and just want to print
    // a nice error message, we could do
    // set_res.unwrap_or_else(|err| panic!("{}", err));

    // Instead, you may want to match on specific error types
    match set_res {
        Ok(success) => {
            if success {
                println!("Successfully set new key in KDB.");
            } else {
                println!("No changes were made to the KDB.");
            }
            Ok(())
        }
        Err(kdb_error) => {
            if kdb_error.is_semantic() {
                // Handle the semantic validation error
                Ok(())
            } else {
                // Otherwise propagate the error up
                Err(Box::new(kdb_error))
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::collections::HashMap;
use frontend::structs::LRegInfo;
use middle::ssa::{BBInfo, SSAMod, ValueType};
use middle::ir::{MOpcode, WidthSpec};
use middle::phiplacement::PhiPlacer;

#[derive(Debug)]
pub struct SubRegister {
	// usize or WidthSpec
	pub base:  usize,
	pub shift: usize,
	pub width: usize
}

pub struct SubRegisterFile {
	pub whole_registers: Vec<ValueType>, // methods don't use this, ownership transfer of whole_r outwards desirable (currently cloning)
	pub named_registers: HashMap<String, SubRegister>,
	pub whole_names:     Vec<String>,
}

impl SubRegisterFile {
	pub fn new(reg_info: &LRegInfo) -> SubRegisterFile {
		let mut slices = HashMap::new();
		let mut events: Vec<(usize, usize, usize)> = Vec::new();
		for (i, reg) in reg_info.reg_info.iter().enumerate() {
			// println!("{:?}", reg);
			if reg.type_str != "gpr" { continue; } // st7 from "fpu" overlaps with zf from "gpr" (r2 bug?)
			if reg.name.ends_with("flags") { continue; } // HARDCODED x86
			events.push((i, reg.offset, reg.offset + reg.size));
		}

		events.sort_by(|a, b| {
			let o = a.1.cmp(&b.1);
			match o {
				Ordering::Equal => b.2.cmp(&a.2),
				_ => o
			}
		});

		let mut current: (usize, usize, usize) = (0, 0, 0);
		let mut whole: Vec<ValueType> = Vec::new();
		let mut names: Vec<String> = Vec::new();
		for &ev in &events {
			let name = &reg_info.reg_info[ev.0].name;
			if ev.1 >= current.2 {
				current = ev;
				whole.push(ValueType::Integer { width: (current.2 - current.1) as WidthSpec });
				names.push(name.clone());
			} else {
				assert!(ev.2 <= current.2);
			}
			slices.insert(name.clone(), SubRegister {
				base: whole.len()-1,
				shift: ev.1 - current.1,
				width: ev.2 - ev.1
			});
		}
		/*for (ref name, ref sr) in &slices {
		  println!("{} = (u{})(r{}>>{})", name, sr.width, sr.base, sr.shift);
		  }*/
		SubRegisterFile {
			whole_registers: whole,
			named_registers: slices,
			whole_names:     names,
		}
	}

	pub fn write_register<'a, T: SSAMod<BBInfo=BBInfo> + 'a>(
		&self, phiplacer: &mut PhiPlacer<'a, T>, base: usize,
		block: T::ActionRef,
		var: &String,
		mut value: T::ValueRef
	) {
		let info = &self.named_registers[var];
		let id = info.base + base;
		match phiplacer.variable_types[id] {
			ValueType::Integer{width} if info.width < (width as usize) => {
				//println!("Assigning to {:?}: {:?}", var, info);
				let vt = ValueType::Integer{width: width as WidthSpec};

				let mut new_value = phiplacer.ssa.add_op(block, MOpcode::OpWiden(width as WidthSpec), vt);
				phiplacer.ssa.op_use(new_value, 0, value);
				value = new_value;

				if info.shift > 0 {
					//println!("Shifting by {:?}", info.shift);
					let shift_amount_node = phiplacer.ssa.add_const(block, info.shift as u64);
					new_value = phiplacer.ssa.add_op(block, MOpcode::OpLsl, vt);
					phiplacer.ssa.op_use(new_value, 0, value);
					phiplacer.ssa.op_use(new_value, 1, shift_amount_node);
					value = new_value;
				}

				let fullvalue: u64 = !((!1u64) << (width-1));
				let maskvalue: u64 = ((!((!1u64) << (info.width-1))) << info.shift) ^ fullvalue;

				if maskvalue != 0 {
					//println!("Masking with {:?}", maskvalue);
					let mut ov = phiplacer.read_variable(block, id);
					let maskvalue_node = phiplacer.ssa.add_const(block, maskvalue);

					new_value = phiplacer.ssa.add_op(block, MOpcode::OpAnd, vt);
					phiplacer.ssa.op_use(new_value, 0, ov);
					phiplacer.ssa.op_use(new_value, 1, maskvalue_node);
					ov = new_value;

					new_value = phiplacer.ssa.add_op(block, MOpcode::OpOr, vt);
					phiplacer.ssa.op_use(new_value, 0, value);
					phiplacer.ssa.op_use(new_value, 1, ov);
					value = new_value;
				}
			},
			ValueType::Integer{..} => (),
			//_ => unimplemented!()
		}
		phiplacer.write_variable(block, id, value);
	}

	pub fn read_register<'a, T: SSAMod<BBInfo=BBInfo> + 'a>(
		&self, phiplacer: &mut PhiPlacer<'a, T>,
		base: usize,
		block: T::ActionRef,
		var: &String
		) ->
		T::ValueRef
	{
		let info = &self.named_registers[var];
		let id = info.base + base;
		let mut value = phiplacer.read_variable(block, id);
		match phiplacer.variable_types[id] {
			ValueType::Integer{width} => {
				if info.shift > 0 {
					let shift_amount_node = phiplacer.ssa.add_const(block, info.shift as u64);
					let new_value = phiplacer.ssa.add_op(block, MOpcode::OpLsr, ValueType::Integer{width: width as WidthSpec});
					phiplacer.ssa.op_use(new_value, 0, value);
					phiplacer.ssa.op_use(new_value, 1, shift_amount_node);
					value = new_value;
				}
				if (width as usize) < info.width {
					let new_value = phiplacer.ssa.add_op(block, MOpcode::OpNarrow(info.width as WidthSpec), ValueType::Integer{width: info.width as WidthSpec});
					phiplacer.ssa.op_use(new_value, 0, value);
					value = new_value;
				}
				value
			},
			//_ => unimplemented!()
		}
	}
}
<commit_msg>middle/regfile.rs: Added documentation<commit_after>//! Contains the struct `SubRegisterFile` which extends `PhiPlacer`s
//! functionality by reads and writes to partial registers.

use std::cmp::Ordering;
use std::collections::HashMap;
use frontend::structs::LRegInfo;
use middle::ssa::{BBInfo, SSAMod, ValueType};
use middle::ir::{MOpcode, WidthSpec};
use middle::phiplacement::PhiPlacer;

#[derive(Debug)]
struct SubRegister {
	// usize or WidthSpec
	pub base:  usize,
	pub shift: usize,
	pub width: usize
}

/// A structure containing information about whole and partial registers of a platform.
/// Upon creation it builds a vector of `ValueType`s representing whole registers
/// to be added to a PhiPlacer.
///
/// It can then translate accesses to partial registers to accesses of whole registers.
/// Shifts and masks are added automatically.

pub struct SubRegisterFile {
	/// `ValueType`s of whole registers ready to be added to a PhiPlacer.
	/// The index within PhiPlacer to the first register is needed
	/// as argument `base` to `read_register` and `write_register` later.
	// {read,write}_register don't use this, ownership transfer of whole_registers outwards desirable (currently cloning)
	pub whole_registers: Vec<ValueType>,
	/// Contains the respective names for the registers described in `whole_registers`
	pub whole_names:     Vec<String>,

	named_registers: HashMap<String, SubRegister>,
}

impl SubRegisterFile {
	/// Creates a new SubRegisterFile based on a provided register profile.
	pub fn new(reg_info: &LRegInfo) -> SubRegisterFile {
		let mut slices = HashMap::new();
		let mut events: Vec<(usize, usize, usize)> = Vec::new();
		for (i, reg) in reg_info.reg_info.iter().enumerate() {
			// println!("{:?}", reg);
			if reg.type_str != "gpr" { continue; } // st7 from "fpu" overlaps with zf from "gpr" (r2 bug?)
			if reg.name.ends_with("flags") { continue; } // HARDCODED x86
			events.push((i, reg.offset, reg.offset + reg.size));
		}

		events.sort_by(|a, b| {
			let o = a.1.cmp(&b.1);
			match o {
				Ordering::Equal => b.2.cmp(&a.2),
				_ => o
			}
		});

		let mut current: (usize, usize, usize) = (0, 0, 0);
		let mut whole: Vec<ValueType> = Vec::new();
		let mut names: Vec<String> = Vec::new();
		for &ev in &events {
			let name = &reg_info.reg_info[ev.0].name;
			if ev.1 >= current.2 {
				current = ev;
				whole.push(ValueType::Integer { width: (current.2 - current.1) as WidthSpec });
				names.push(name.clone());
			} else {
				assert!(ev.2 <= current.2);
			}
			slices.insert(name.clone(), SubRegister {
				base: whole.len()-1,
				shift: ev.1 - current.1,
				width: ev.2 - ev.1
			});
		}
		/*for (ref name, ref sr) in &slices {
		  println!("{} = (u{})(r{}>>{})", name, sr.width, sr.base, sr.shift);
		  }*/
		SubRegisterFile {
			whole_registers: whole,
			named_registers: slices,
			whole_names:     names,
		}
	}

	/// Emit code for setting the specified register to the specified value.
	/// Will automatically insert code for shifting and masking in case of subregisters.
	/// This implies that it also tries to read the old value of the whole register.
	///
	/// # Arguments
	/// * `phiplacer` - A PhiPlacer that has already been informed of our variables.
	///                 It will also give us access to the SSA to modify
	/// * `base`      - Index of the PhiPlacer variable that corresponds to our first register.
	/// * `block`     - Reference to the basic block to which operations will be appended.
	/// * `var`       - Name of the register to write as a string.
	/// * `value`     - An SSA node whose value shall be assigned to the register.
	///                 As with most APIs in radeco, we will not check if the value is reachable
	///                 from the position where the caller is trying to insert these operations.
	pub fn write_register<'a, T: SSAMod<BBInfo=BBInfo> + 'a>(
		&self, phiplacer: &mut PhiPlacer<'a, T>, base: usize,
		block: T::ActionRef,
		var: &String, // change to str?
		mut value: T::ValueRef
	) {
		let info = &self.named_registers[var];
		let id = info.base + base;
		match phiplacer.variable_types[id] {
			ValueType::Integer{width} if info.width < (width as usize) => {
				//println!("Assigning to {:?}: {:?}", var, info);
				let vt = ValueType::Integer{width: width as WidthSpec};

				let mut new_value = phiplacer.ssa.add_op(block, MOpcode::OpWiden(width as WidthSpec), vt);
				phiplacer.ssa.op_use(new_value, 0, value);
				value = new_value;

				if info.shift > 0 {
					//println!("Shifting by {:?}", info.shift);
					let shift_amount_node = phiplacer.ssa.add_const(block, info.shift as u64);
					new_value = phiplacer.ssa.add_op(block, MOpcode::OpLsl, vt);
					phiplacer.ssa.op_use(new_value, 0, value);
					phiplacer.ssa.op_use(new_value, 1, shift_amount_node);
					value = new_value;
				}

				let fullvalue: u64 = !((!1u64) << (width-1));
				let maskvalue: u64 = ((!((!1u64) << (info.width-1))) << info.shift) ^ fullvalue;

				if maskvalue != 0 {
					//println!("Masking with {:?}", maskvalue);
					let mut ov = phiplacer.read_variable(block, id);
					let maskvalue_node = phiplacer.ssa.add_const(block, maskvalue);

					new_value = phiplacer.ssa.add_op(block, MOpcode::OpAnd, vt);
					phiplacer.ssa.op_use(new_value, 0, ov);
					phiplacer.ssa.op_use(new_value, 1, maskvalue_node);
					ov = new_value;

					new_value = phiplacer.ssa.add_op(block, MOpcode::OpOr, vt);
					phiplacer.ssa.op_use(new_value, 0, value);
					phiplacer.ssa.op_use(new_value, 1, ov);
					value = new_value;
				}
			},
			ValueType::Integer{..} => (),
			//_ => unimplemented!()
		}
		phiplacer.write_variable(block, id, value);
	}

	/// Emit code for reading the current value of the specified register.
	///
	/// # Arguments
	/// * `phiplacer` - A PhiPlacer that has already been informed of our variables.
	///                 It will also give us access to the SSA to modify
	/// * `base`      - Index of the PhiPlacer variable that corresponds to our first register.
	/// * `block`     - Reference to the basic block to which operations will be appended.
	/// * `var`       - Name of the register to read as a string.
	///
	/// # Return value
	/// A SSA node representing the value of the register as seen by the current end of `block`.
	/// Unless prior basic blocks are marked as sealed in the PhiPlacer this will always return
	/// a reference to a Phi node.
	/// Either way, once nodes are sealed redundant Phi nodes are eliminated by PhiPlacer.
	pub fn read_register<'a, T: SSAMod<BBInfo=BBInfo> + 'a>(
		&self, phiplacer: &mut PhiPlacer<'a, T>,
		base: usize,
		block: T::ActionRef,
		var: &String
		) ->
		T::ValueRef
	{
		let info = &self.named_registers[var];
		let id = info.base + base;
		let mut value = phiplacer.read_variable(block, id);
		match phiplacer.variable_types[id] {
			ValueType::Integer{width} => {
				if info.shift > 0 {
					let shift_amount_node = phiplacer.ssa.add_const(block, info.shift as u64);
					let new_value = phiplacer.ssa.add_op(block, MOpcode::OpLsr, ValueType::Integer{width: width as WidthSpec});
					phiplacer.ssa.op_use(new_value, 0, value);
					phiplacer.ssa.op_use(new_value, 1, shift_amount_node);
					value = new_value;
				}
				if (width as usize) < info.width {
					let new_value = phiplacer.ssa.add_op(block, MOpcode::OpNarrow(info.width as WidthSpec), ValueType::Integer{width: info.width as WidthSpec});
					phiplacer.ssa.op_use(new_value, 0, value);
					value = new_value;
				}
				value
			},
			//_ => unimplemented!()
		}
	}
}
<|endoftext|>


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

use chrono::NaiveDateTime;
use diesel::prelude::*;

use crate::util::errors::{cargo_err, AppResult};

use crate::models::{Crate, Dependency, User};
use crate::schema::*;

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug, Queryable, Deserialize, Serialize)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: String,
    pub updated_at: NaiveDateTime,
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: serde_json::Value,
    pub yanked: bool,
    pub license: Option<String>,
    pub crate_size: Option<i32>,
    pub published_by: Option<i32>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: serde_json::Value,
    license: Option<String>,
    crate_size: Option<i32>,
    published_by: i32,
}

/// The highest version (semver order) and the most recently updated version.
/// Typically used for a single crate.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TopVersions {
    /// The "highest" version in terms of semver
    pub highest: Option<semver::Version>,
    /// The "highest" non-prerelease version
    pub highest_stable: Option<semver::Version>,
    /// The "newest" version in terms of publishing date
    pub newest: Option<semver::Version>,
}

impl TopVersions {
    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a list of `Version` instances.
    pub fn from_versions(versions: Vec<Version>) -> Self {
        Self::from_date_version_pairs(versions.into_iter().map(|v| (v.created_at, v.num)))
    }

    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a collection of date/version pairs.
    pub fn from_date_version_pairs<T>(pairs: T) -> Self
    where
        T: Clone + IntoIterator<Item = (NaiveDateTime, String)>,
    {
        // filter out versions that we can't parse
        let pairs: Vec<(NaiveDateTime, semver::Version)> = pairs
            .into_iter()
            .filter_map(|(date, version)| {
                semver::Version::parse(&version)
                    .ok()
                    .map(|version| (date, version))
            })
            .collect();

        let newest = pairs.iter().max().map(|(_, v)| v.clone());
        let highest = pairs.iter().map(|(_, v)| v).max().cloned();
        let highest_stable = pairs
            .iter()
            .map(|(_, v)| v)
            .filter(|v| v.pre.is_empty())
            .max()
            .cloned();

        Self {
            highest,
            highest_stable,
            newest,
        }
    }
}

impl Version {
    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    pub fn record_readme_rendering(version_id_: i32, conn: &PgConnection) -> QueryResult<usize> {
        use crate::schema::readme_renderings::dsl::*;
        use diesel::dsl::now;

        diesel::insert_into(readme_renderings)
            .values(version_id.eq(version_id_))
            .on_conflict(version_id)
            .do_update()
            .set(rendered_at.eq(now))
            .execute(conn)
    }

    /// Gets the User who ran `cargo publish` for this version, if recorded.
    /// Not for use when you have a group of versions you need the publishers for.
    pub fn published_by(&self, conn: &PgConnection) -> Option<User> {
        match self.published_by {
            Some(pb) => users::table.find(pb).first(conn).ok(),
            None => None,
        }
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
        crate_size: i32,
        published_by: i32,
    ) -> AppResult<Self> {
        let features = serde_json::to_value(features)?;

        let mut new_version = NewVersion {
            crate_id,
            num: num.to_string(),
            features,
            license,
            crate_size: Some(crate_size),
            published_by,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(&self, conn: &PgConnection, published_by_email: &str) -> AppResult<Version> {
        use crate::schema::versions::dsl::*;
        use diesel::dsl::exists;
        use diesel::{insert_into, select};

        conn.transaction(|| {
            let already_uploaded = versions
                .filter(crate_id.eq(self.crate_id))
                .filter(num.eq(&self.num));
            if select(exists(already_uploaded)).get_result(conn)? {
                return Err(cargo_err(&format_args!(
                    "crate version `{}` is already \
                     uploaded",
                    self.num
                )));
            }

            let version: Version = insert_into(versions).values(self).get_result(conn)?;

            insert_into(versions_published_by::table)
                .values((
                    versions_published_by::version_id.eq(version.id),
                    versions_published_by::email.eq(published_by_email),
                ))
                .execute(conn)?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> AppResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    cargo_err(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::TopVersions;
    use chrono::NaiveDateTime;

    #[track_caller]
    fn date(str: &str) -> NaiveDateTime {
        str.parse().unwrap()
    }

    #[track_caller]
    fn version(str: &str) -> semver::Version {
        semver::Version::parse(str).unwrap()
    }

    #[test]
    fn top_versions_empty() {
        let versions = vec![];
        assert_eq!(
            TopVersions::from_date_version_pairs(versions),
            TopVersions {
                highest: None,
                highest_stable: None,
                newest: None,
            }
        );
    }

    #[test]
    fn top_versions_single() {
        let versions = vec![(date("2020-12-03T12:34:56"), "1.0.0".into())];
        assert_eq!(
            TopVersions::from_date_version_pairs(versions),
            TopVersions {
                highest: Some(version("1.0.0")),
                highest_stable: Some(version("1.0.0")),
                newest: Some(version("1.0.0")),
            }
        );
    }

    #[test]
    fn top_versions_prerelease() {
        let versions = vec![(date("2020-12-03T12:34:56"), "1.0.0-beta.5".into())];
        assert_eq!(
            TopVersions::from_date_version_pairs(versions),
            TopVersions {
                highest: Some(version("1.0.0-beta.5")),
                highest_stable: None,
                newest: Some(version("1.0.0-beta.5")),
            }
        );
    }

    #[test]
    fn top_versions_multiple() {
        let versions = vec![
            (date("2018-12-03T12:34:56"), "1.0.0".into()),
            (date("2019-12-03T12:34:56"), "2.0.0-alpha.1".into()),
            (date("2020-12-01T12:34:56"), "everything is broken".into()),
            (date("2020-12-03T12:34:56"), "1.1.0".into()),
            (date("2020-12-31T12:34:56"), "1.0.4".into()),
        ];
        assert_eq!(
            TopVersions::from_date_version_pairs(versions),
            TopVersions {
                highest: Some(version("2.0.0-alpha.1")),
                highest_stable: Some(version("1.1.0")),
                newest: Some(version("1.0.4")),
            }
        );
    }
}
<commit_msg>Auto merge of #4292 - Turbo87:license-validation, r=Turbo87<commit_after>use std::collections::HashMap;

use chrono::NaiveDateTime;
use diesel::prelude::*;

use crate::util::errors::{cargo_err, AppResult};

use crate::models::{Crate, Dependency, User};
use crate::schema::*;

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug, Queryable, Deserialize, Serialize)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: String,
    pub updated_at: NaiveDateTime,
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: serde_json::Value,
    pub yanked: bool,
    pub license: Option<String>,
    pub crate_size: Option<i32>,
    pub published_by: Option<i32>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: serde_json::Value,
    license: Option<String>,
    crate_size: Option<i32>,
    published_by: i32,
}

/// The highest version (semver order) and the most recently updated version.
/// Typically used for a single crate.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TopVersions {
    /// The "highest" version in terms of semver
    pub highest: Option<semver::Version>,
    /// The "highest" non-prerelease version
    pub highest_stable: Option<semver::Version>,
    /// The "newest" version in terms of publishing date
    pub newest: Option<semver::Version>,
}

impl TopVersions {
    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a list of `Version` instances.
    pub fn from_versions(versions: Vec<Version>) -> Self {
        Self::from_date_version_pairs(versions.into_iter().map(|v| (v.created_at, v.num)))
    }

    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a collection of date/version pairs.
    pub fn from_date_version_pairs<T>(pairs: T) -> Self
    where
        T: Clone + IntoIterator<Item = (NaiveDateTime, String)>,
    {
        // filter out versions that we can't parse
        let pairs: Vec<(NaiveDateTime, semver::Version)> = pairs
            .into_iter()
            .filter_map(|(date, version)| {
                semver::Version::parse(&version)
                    .ok()
                    .map(|version| (date, version))
            })
            .collect();

        let newest = pairs.iter().max().map(|(_, v)| v.clone());
        let highest = pairs.iter().map(|(_, v)| v).max().cloned();
        let highest_stable = pairs
            .iter()
            .map(|(_, v)| v)
            .filter(|v| v.pre.is_empty())
            .max()
            .cloned();

        Self {
            highest,
            highest_stable,
            newest,
        }
    }
}

impl Version {
    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    pub fn record_readme_rendering(version_id_: i32, conn: &PgConnection) -> QueryResult<usize> {
        use crate::schema::readme_renderings::dsl::*;
        use diesel::dsl::now;

        diesel::insert_into(readme_renderings)
            .values(version_id.eq(version_id_))
            .on_conflict(version_id)
            .do_update()
            .set(rendered_at.eq(now))
            .execute(conn)
    }

    /// Gets the User who ran `cargo publish` for this version, if recorded.
    /// Not for use when you have a group of versions you need the publishers for.
    pub fn published_by(&self, conn: &PgConnection) -> Option<User> {
        match self.published_by {
            Some(pb) => users::table.find(pb).first(conn).ok(),
            None => None,
        }
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
        crate_size: i32,
        published_by: i32,
    ) -> AppResult<Self> {
        let features = serde_json::to_value(features)?;

        let mut new_version = NewVersion {
            crate_id,
            num: num.to_string(),
            features,
            license,
            crate_size: Some(crate_size),
            published_by,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(&self, conn: &PgConnection, published_by_email: &str) -> AppResult<Version> {
        use crate::schema::versions::dsl::*;
        use diesel::dsl::exists;
        use diesel::{insert_into, select};

        conn.transaction(|| {
            let already_uploaded = versions
                .filter(crate_id.eq(self.crate_id))
                .filter(num.eq(&self.num));
            if select(exists(already_uploaded)).get_result(conn)? {
                return Err(cargo_err(&format_args!(
                    "crate version `{}` is already \
                     uploaded",
                    self.num
                )));
            }

            let version: Version = insert_into(versions).values(self).get_result(conn)?;

            insert_into(versions_published_by::table)
                .values((
                    versions_published_by::version_id.eq(version.id),
                    versions_published_by::email.eq(published_by_email),
                ))
                .execute(conn)?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> AppResult<()> {
        if let Some(ref license) = self.license {
            validate_license_expr(license)?;
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}

fn validate_license_expr(s: &str) -> AppResult<()> {
    for part in s.split('/') {
        license_exprs::validate_license_expr(part).map_err(|e| {
            cargo_err(&format_args!("{}; see http://opensource.org/licenses for options, and http://spdx.org/licenses/ for their identifiers", e))
        })?;
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::{validate_license_expr, TopVersions};
    use chrono::NaiveDateTime;

    #[track_caller]
    fn date(str: &str) -> NaiveDateTime {
        str.parse().unwrap()
    }

    #[track_caller]
    fn version(str: &str) -> semver::Version {
        semver::Version::parse(str).unwrap()
    }

    #[test]
    fn top_versions_empty() {
        let versions = vec![];
        assert_eq!(
            TopVersions::from_date_version_pairs(versions),
            TopVersions {
                highest: None,
                highest_stable: None,
                newest: None,
            }
        );
    }

    #[test]
    fn top_versions_single() {
        let versions = vec![(date("2020-12-03T12:34:56"), "1.0.0".into())];
        assert_eq!(
            TopVersions::from_date_version_pairs(versions),
            TopVersions {
                highest: Some(version("1.0.0")),
                highest_stable: Some(version("1.0.0")),
                newest: Some(version("1.0.0")),
            }
        );
    }

    #[test]
    fn top_versions_prerelease() {
        let versions = vec![(date("2020-12-03T12:34:56"), "1.0.0-beta.5".into())];
        assert_eq!(
            TopVersions::from_date_version_pairs(versions),
            TopVersions {
                highest: Some(version("1.0.0-beta.5")),
                highest_stable: None,
                newest: Some(version("1.0.0-beta.5")),
            }
        );
    }

    #[test]
    fn top_versions_multiple() {
        let versions = vec![
            (date("2018-12-03T12:34:56"), "1.0.0".into()),
            (date("2019-12-03T12:34:56"), "2.0.0-alpha.1".into()),
            (date("2020-12-01T12:34:56"), "everything is broken".into()),
            (date("2020-12-03T12:34:56"), "1.1.0".into()),
            (date("2020-12-31T12:34:56"), "1.0.4".into()),
        ];
        assert_eq!(
            TopVersions::from_date_version_pairs(versions),
            TopVersions {
                highest: Some(version("2.0.0-alpha.1")),
                highest_stable: Some(version("1.1.0")),
                newest: Some(version("1.0.4")),
            }
        );
    }

    #[test]
    fn licenses() {
        assert_ok!(validate_license_expr("MIT"));
        assert_ok!(validate_license_expr("MIT OR Apache-2.0"));
        assert_ok!(validate_license_expr("MIT/Apache-2.0"));
        assert_ok!(validate_license_expr("MIT AND Apache-2.0"));

        let error = assert_err!(validate_license_expr("apache 2.0"));
        let error = format!("{}", error);
        assert!(error.starts_with("unknown license or other term: apache; see http"));

        let error = assert_err!(validate_license_expr("MIT OR (Apache-2.0 AND MIT)"));
        let error = format!("{}", error);
        assert!(error.starts_with("unknown license or other term: (Apache-2.0; see http"));
    }
}
<|endoftext|>


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

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::time::Duration;
use std::thread;
use tikv::util::HandyRwLock;
use tikv::storage::{self, Storage, Engine, Snapshot, Modify, Mutation, make_key, ALL_CFS, Options};
use tikv::storage::engine::{self, Callback, Result};
use kvproto::kvrpcpb::Context;
use raftstore::server::new_server_cluster_with_cfs;
use raftstore::cluster::Cluster;
use raftstore::server::ServerCluster;
use raftstore::util::*;
use super::sync_storage::SyncStorage;

fn new_raft_storage() -> (Cluster<ServerCluster>, SyncStorage, Context) {
    let mut cluster = new_server_cluster_with_cfs(0, 1, ALL_CFS);
    cluster.run();
    // make sure leader has been elected.
    assert_eq!(cluster.must_get(b""), None);

    let region = cluster.get_region(b"");
    let leader_id = cluster.leader_of_region(region.get_id()).unwrap();
    let engine = cluster.sim.rl().storages[&leader_id.get_id()].clone();

    let mut ctx = Context::new();
    ctx.set_region_id(region.get_id());
    ctx.set_region_epoch(region.get_region_epoch().clone());
    ctx.set_peer(region.get_peers()[0].clone());

    (cluster, SyncStorage::from_engine(engine, &Default::default()), ctx)
}

#[test]
fn test_raft_storage() {
    let (_cluster, storage, mut ctx) = new_raft_storage();
    let key = make_key(b"key");
    assert_eq!(storage.get(ctx.clone(), &key, 5).unwrap(), None);
    storage.prewrite(ctx.clone(),
                  vec![Mutation::Put((key.clone(), b"value".to_vec()))],
                  b"key".to_vec(),
                  10)
        .unwrap();
    storage.commit(ctx.clone(), vec![key.clone()], 10, 15).unwrap();
    assert_eq!(storage.get(ctx.clone(), &key, 20).unwrap().unwrap(),
               b"value".to_vec());

    // Test wronng region id.
    let region_id = ctx.get_region_id();
    ctx.set_region_id(region_id + 1);
    assert!(storage.get(ctx.clone(), &key, 20).is_err());
    assert!(storage.batch_get(ctx.clone(), &[key.clone()], 20).is_err());
    assert!(storage.scan(ctx.clone(), key.clone(), 1, false, 20).is_err());
    assert!(storage.scan_lock(ctx.clone(), 20).is_err());
}

#[test]
fn test_engine_leader_change_twice() {
    let mut cluster = new_server_cluster_with_cfs(0, 3, ALL_CFS);
    cluster.run();

    let region = cluster.get_region(b"");
    let peers = region.get_peers();

    cluster.must_transfer_leader(region.get_id(), peers[0].clone());
    let engine = cluster.sim.rl().storages[&peers[0].get_id()].clone();

    let term = cluster.request(b"", vec![new_get_cmd(b"")], true, Duration::from_secs(5))
        .get_header()
        .get_current_term();

    let mut ctx = Context::new();
    ctx.set_region_id(region.get_id());
    ctx.set_region_epoch(region.get_region_epoch().clone());
    ctx.set_peer(peers[0].clone());
    ctx.set_term(term);

    // Not leader.
    cluster.must_transfer_leader(region.get_id(), peers[1].clone());
    assert!(engine.write(&ctx, vec![]).is_err());
    // Term not match.
    cluster.must_transfer_leader(region.get_id(), peers[0].clone());
    let res = engine.write(&ctx, vec![]);
    if let engine::Error::Request(ref e) = *res.as_ref().err().unwrap() {
        assert!(e.has_stale_command());
    } else {
        panic!("expect stale command, but got {:?}", res);
    }
}

#[test]
fn test_scheduler_leader_change_twice() {
    let mut cluster = new_server_cluster_with_cfs(0, 2, ALL_CFS);
    cluster.run();

    let region = cluster.get_region(b"");
    let peers = region.get_peers();

    cluster.must_transfer_leader(region.get_id(), peers[0].clone());
    let engine = cluster.sim.rl().storages[&peers[0].get_id()].clone();
    let block = Arc::new(AtomicBool::new(true));
    let engine = BlockSnapshotEngine {
        engine: engine,
        block_snapshot: block.clone(),
    };
    let config = Default::default();
    let mut storage = Storage::from_engine(box engine, &config).unwrap();
    storage.start(&config).unwrap();

    let mut ctx = Context::new();
    ctx.set_region_id(region.get_id());
    ctx.set_region_epoch(region.get_region_epoch().clone());
    ctx.set_peer(peers[0].clone());

    let (tx, rx) = channel();
    storage.async_prewrite(ctx.clone(),
                        vec![Mutation::Put((make_key(b"k"), b"v".to_vec()))],
                        b"k".to_vec(),
                        10,
                        Options::default(),
                        box move |res: storage::Result<_>| {
            if let storage::Error::Engine(engine::Error::Request(ref e)) = *res.as_ref()
                .err()
                .unwrap() {
                assert!(e.has_stale_command());
            } else {
                panic!("expect stale command, but got {:?}", res);
            }
            tx.send(1).unwrap();
        })
        .unwrap();
    // Sleep a while, the prewrite should be blocked at snapshot stage.
    thread::sleep(Duration::from_millis(50));
    // Transfer leader twice, then unblock snapshot.
    cluster.must_transfer_leader(region.get_id(), peers[1].clone());
    cluster.must_transfer_leader(region.get_id(), peers[0].clone());
    block.store(false, Ordering::SeqCst);

    rx.recv_timeout(Duration::from_secs(3)).unwrap();
}

#[derive(Debug)]
struct BlockSnapshotEngine {
    engine: Box<Engine>,
    block_snapshot: Arc<AtomicBool>,
}

impl Engine for BlockSnapshotEngine {
    fn async_write(&self, ctx: &Context, batch: Vec<Modify>, callback: Callback<()>) -> Result<()> {
        self.engine.async_write(ctx, batch, callback)
    }

    fn async_snapshot(&self, ctx: &Context, callback: Callback<Box<Snapshot>>) -> Result<()> {
        let block_snapshot = self.block_snapshot.clone();
        self.engine.async_snapshot(ctx,
                                   box move |res| {
            thread::spawn(move || {
                while block_snapshot.load(Ordering::SeqCst) {
                    thread::sleep(Duration::from_millis(50));
                }
                callback(res);
            });
        })
    }

    fn clone(&self) -> Box<Engine + 'static> {
        box BlockSnapshotEngine {
            engine: self.engine.clone(),
            block_snapshot: self.block_snapshot.clone(),
        }
    }
}
<commit_msg>[issues_2294 in tidb]:init test<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::mpsc::channel;
use std::time::Duration;
use std::thread;
use tikv::util::HandyRwLock;
use tikv::storage::{self, Storage, Engine, Snapshot, Modify, Mutation, make_key, ALL_CFS, Options};
use tikv::storage::engine::{self, Callback, Result};
use kvproto::kvrpcpb::Context;
use raftstore::server::new_server_cluster_with_cfs;
use raftstore::cluster::Cluster;
use raftstore::server::ServerCluster;
use raftstore::util::*;
use super::sync_storage::SyncStorage;

fn new_raft_storage() -> (Cluster<ServerCluster>, SyncStorage, Context) {
    let mut cluster = new_server_cluster_with_cfs(0, 1, ALL_CFS);
    cluster.run();
    // make sure leader has been elected.
    assert_eq!(cluster.must_get(b""), None);

    let region = cluster.get_region(b"");
    let leader_id = cluster.leader_of_region(region.get_id()).unwrap();
    let engine = cluster.sim.rl().storages[&leader_id.get_id()].clone();

    let mut ctx = Context::new();
    ctx.set_region_id(region.get_id());
    ctx.set_region_epoch(region.get_region_epoch().clone());
    ctx.set_peer(region.get_peers()[0].clone());

    (cluster, SyncStorage::from_engine(engine, &Default::default()), ctx)
}

#[test]
fn test_raft_storage() {
    let (_cluster, storage, mut ctx) = new_raft_storage();
    let key = make_key(b"key");
    assert_eq!(storage.get(ctx.clone(), &key, 5).unwrap(), None);
    storage.prewrite(ctx.clone(),
                  vec![Mutation::Put((key.clone(), b"value".to_vec()))],
                  b"key".to_vec(),
                  10)
        .unwrap();
    storage.commit(ctx.clone(), vec![key.clone()], 10, 15).unwrap();
    assert_eq!(storage.get(ctx.clone(), &key, 20).unwrap().unwrap(),
               b"value".to_vec());

    // Test wrong region id.
    let region_id = ctx.get_region_id();
    ctx.set_region_id(region_id + 1);
    assert!(storage.get(ctx.clone(), &key, 20).is_err());
    assert!(storage.batch_get(ctx.clone(), &[key.clone()], 20).is_err());
    assert!(storage.scan(ctx.clone(), key.clone(), 1, false, 20).is_err());
    assert!(storage.scan_lock(ctx.clone(), 20).is_err());
}

#[test]
fn test_raft_storage() {
    let (_cluster, storage, mut ctx) = new_raft_storage();
    let key = make_key(b"key");
    assert_eq!(storage.get(ctx.clone(), &key, 5).unwrap(), None);
    storage.prewrite(ctx.clone(),
                  vec![Mutation::Put((key.clone(), b"value".to_vec()))],
                  b"key".to_vec(),
                  10)
        .unwrap();
    storage.commit(ctx.clone(), vec![key.clone()], 10, 15).unwrap();
    assert_eq!(storage.get(ctx.clone(), &key, 20).unwrap().unwrap(),
               b"value".to_vec());

    // Test wrong region id.
    let region_id = ctx.get_region_id();
    ctx.set_region_id(region_id + 1);
    assert!(storage.get(ctx.clone(), &key, 20).is_err());
    assert!(storage.batch_get(ctx.clone(), &[key.clone()], 20).is_err());
    assert!(storage.scan(ctx.clone(), key.clone(), 1, false, 20).is_err());
    assert!(storage.scan_lock(ctx.clone(), 20).is_err());
}

#[test]
fn test_raft_storage() {
    let (_cluster, storage, mut ctx) = new_raft_storage();
    let key = make_key(b"key");
    assert_eq!(storage.get(ctx.clone(), &key, 5).unwrap(), None);
    storage.prewrite(ctx.clone(),
                  vec![Mutation::Put((key.clone(), b"value".to_vec()))],
                  b"key".to_vec(),
                  10)
        .unwrap();
    storage.commit(ctx.clone(), vec![key.clone()], 10, 15).unwrap();
    assert_eq!(storage.get(ctx.clone(), &key, 20).unwrap().unwrap(),
               b"value".to_vec());

    // Test store not match.
    let store_id = ctx.get_peer().get_store_id();
    ctx.get_peer().set_store_id(store_id + 1);
    assert!(storage.get(ctx.clone(), &key, 20).is_err());
    assert!(storage.batch_get(ctx.clone(), &[key.clone()], 20).is_err());
    assert!(storage.scan(ctx.clone(), key.clone(), 1, false, 20).is_err());
    assert!(storage.scan_lock(ctx.clone(), 20).is_err());
}

#[test]
fn test_engine_leader_change_twice() {
    let mut cluster = new_server_cluster_with_cfs(0, 3, ALL_CFS);
    cluster.run();

    let region = cluster.get_region(b"");
    let peers = region.get_peers();

    cluster.must_transfer_leader(region.get_id(), peers[0].clone());
    let engine = cluster.sim.rl().storages[&peers[0].get_id()].clone();

    let term = cluster.request(b"", vec![new_get_cmd(b"")], true, Duration::from_secs(5))
        .get_header()
        .get_current_term();

    let mut ctx = Context::new();
    ctx.set_region_id(region.get_id());
    ctx.set_region_epoch(region.get_region_epoch().clone());
    ctx.set_peer(peers[0].clone());
    ctx.set_term(term);

    // Not leader.
    cluster.must_transfer_leader(region.get_id(), peers[1].clone());
    assert!(engine.write(&ctx, vec![]).is_err());
    // Term not match.
    cluster.must_transfer_leader(region.get_id(), peers[0].clone());
    let res = engine.write(&ctx, vec![]);
    if let engine::Error::Request(ref e) = *res.as_ref().err().unwrap() {
        assert!(e.has_stale_command());
    } else {
        panic!("expect stale command, but got {:?}", res);
    }
}

#[test]
fn test_scheduler_leader_change_twice() {
    let mut cluster = new_server_cluster_with_cfs(0, 2, ALL_CFS);
    cluster.run();

    let region = cluster.get_region(b"");
    let peers = region.get_peers();

    cluster.must_transfer_leader(region.get_id(), peers[0].clone());
    let engine = cluster.sim.rl().storages[&peers[0].get_id()].clone();
    let block = Arc::new(AtomicBool::new(true));
    let engine = BlockSnapshotEngine {
        engine: engine,
        block_snapshot: block.clone(),
    };
    let config = Default::default();
    let mut storage = Storage::from_engine(box engine, &config).unwrap();
    storage.start(&config).unwrap();

    let mut ctx = Context::new();
    ctx.set_region_id(region.get_id());
    ctx.set_region_epoch(region.get_region_epoch().clone());
    ctx.set_peer(peers[0].clone());

    let (tx, rx) = channel();
    storage.async_prewrite(ctx.clone(),
                        vec![Mutation::Put((make_key(b"k"), b"v".to_vec()))],
                        b"k".to_vec(),
                        10,
                        Options::default(),
                        box move |res: storage::Result<_>| {
            if let storage::Error::Engine(engine::Error::Request(ref e)) = *res.as_ref()
                .err()
                .unwrap() {
                assert!(e.has_stale_command());
            } else {
                panic!("expect stale command, but got {:?}", res);
            }
            tx.send(1).unwrap();
        })
        .unwrap();
    // Sleep a while, the prewrite should be blocked at snapshot stage.
    thread::sleep(Duration::from_millis(50));
    // Transfer leader twice, then unblock snapshot.
    cluster.must_transfer_leader(region.get_id(), peers[1].clone());
    cluster.must_transfer_leader(region.get_id(), peers[0].clone());
    block.store(false, Ordering::SeqCst);

    rx.recv_timeout(Duration::from_secs(3)).unwrap();
}

#[derive(Debug)]
struct BlockSnapshotEngine {
    engine: Box<Engine>,
    block_snapshot: Arc<AtomicBool>,
}

impl Engine for BlockSnapshotEngine {
    fn async_write(&self, ctx: &Context, batch: Vec<Modify>, callback: Callback<()>) -> Result<()> {
        self.engine.async_write(ctx, batch, callback)
    }

    fn async_snapshot(&self, ctx: &Context, callback: Callback<Box<Snapshot>>) -> Result<()> {
        let block_snapshot = self.block_snapshot.clone();
        self.engine.async_snapshot(ctx,
                                   box move |res| {
            thread::spawn(move || {
                while block_snapshot.load(Ordering::SeqCst) {
                    thread::sleep(Duration::from_millis(50));
                }
                callback(res);
            });
        })
    }

    fn clone(&self) -> Box<Engine + 'static> {
        box BlockSnapshotEngine {
            engine: self.engine.clone(),
            block_snapshot: self.block_snapshot.clone(),
        }
    }
}
<|endoftext|>


<commit_before>
use internal::{
    CanColor,
    Color,
    ColorComponent,
    HasColor,
};

/// Implemented by contexts that contains color.
pub trait RelativeColor<'a, T> {
    /// Multiplies with red, green, blue and alpha values.
    fn mul_rgba(
        &'a self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> T;

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&'a self, f: ColorComponent) -> T {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&'a self, f: ColorComponent) -> T {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }
}

impl<
    'a,
    T: HasColor<'a, Color> + CanColor<'a, U, Color>,
    U
> RelativeColor<'a, U> for T {
    #[inline(always)]
    fn mul_rgba(
        &'a self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> U {
        let color = self.get_color();
        self.color([color[0] * r, color[1] * g, color[2] * b, color[3] * a])
    }
}

<commit_msg>Added `hue_rad` and `hue_deg`<commit_after>
use internal::{
    CanColor,
    Color,
    ColorComponent,
    HasColor,
};
use vecmath::{
    hsv,
};

/// Implemented by contexts that contains color.
pub trait RelativeColor<'a, T> {
    /// Multiplies with red, green, blue and alpha values.
    fn mul_rgba(
        &'a self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> T;

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&'a self, f: ColorComponent) -> T {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&'a self, f: ColorComponent) -> T {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(&'a self, angle: ColorComponent) -> T {
        let pi: ColorComponent = Float::pi();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    fn hue_rad(&'a self, angle: ColorComponent) -> T;
}

impl<
    'a,
    T: HasColor<'a, Color> + CanColor<'a, U, Color>,
    U
> RelativeColor<'a, U> for T {
    #[inline(always)]
    fn mul_rgba(
        &'a self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> U {
        let color = self.get_color();
        self.color([color[0] * r, color[1] * g, color[2] * b, color[3] * a])
    }

    #[inline(always)]
    fn hue_rad(&'a self, angle: ColorComponent) -> U {
        self.color(hsv(*self.get_color(), angle, 1.0, 1.0))
    }
}

<|endoftext|>


<commit_before>extern crate message_verifier;

use message_verifier::{Verifier, Encryptor};

fn main() {
    let key_base = "helloworld";
    let salt = "test salt";
    let sign_salt = "test signed salt";

    let verifier = Verifier::new(key_base);
    let encryptor = Encryptor::new(key_base, salt, sign_salt, 64, 1000).unwrap();

    let message = "{\"key\":\"value\"}";

    println!("{}", verifier.generate(message).expect("Verifier failed"));
    println!("{}", encryptor.encrypt_and_sign(message).expect("Encryptor failed"));
}
<commit_msg>Fix examples/generate_encrypt.rs<commit_after>extern crate message_verifier;

use message_verifier::{Verifier, Encryptor};

fn main() {
    let key_base = "helloworld";
    let salt = "test salt";
    let sign_salt = "test signed salt";

    let verifier = Verifier::new(key_base);
    let encryptor = Encryptor::new(key_base, salt, sign_salt, 64, 1000).unwrap();

    let message = "{\"key\":\"value\"}";

    println!("{}", verifier.generate(message));
    println!("{}", encryptor.encrypt_and_sign(message).expect("Encryptor failed"));
}
<|endoftext|>


<commit_before>// Copyright 2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Utilities for Bayesian statistics.

use ordered_float::OrderedFloat;
use itertools::Itertools;

use stats::LogProb;

/// For each of the hypothesis tests given as posterior error probabilities
/// (PEPs, i.e. the posterior probability of the null hypothesis), estimate the FDR
/// for the case that all null hypotheses with at most this PEP are rejected.
/// FDR is calculated as presented by Müller, Parmigiani, and Rice,
/// "FDR and Bayesian Multiple Comparisons Rules" (July 2006).
/// Johns Hopkin's University, Dept. of Biostatistics Working Papers. Working Paper 115.
///
/// # Returns
///
/// A vector of expected FDRs in the same order as the given PEPs.
pub fn expected_fdr(peps: &[LogProb]) -> Vec<LogProb> {
    // sort indices
    let sorted_idx =
        (0..peps.len()).sorted_by(|&i, &j| OrderedFloat(*peps[i]).cmp(&OrderedFloat(*peps[j])));
    // estimate FDR
    let mut expected_fdr = vec![LogProb::ln_zero(); peps.len()];
    for (i, expected_fp) in LogProb::ln_cumsum_exp(sorted_idx.iter().map(|&i| peps[i]))
            .enumerate() {
        let fdr = LogProb(*expected_fp / (i + 1) as f64);
        expected_fdr[i] = if fdr <= LogProb::ln_one() {
            fdr
        } else {
            LogProb::ln_one()
        };
    }

    expected_fdr
}

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

    #[test]
    fn test_expected_fdr() {
        let peps = [LogProb(0.1f64.ln()), LogProb::ln_zero(), LogProb(0.25f64.ln())];
        let fdrs = expected_fdr(&peps);

        assert_relative_eq!(*fdrs[1], *LogProb::ln_zero());
        assert_relative_eq!(*fdrs[0], *LogProb(0.05f64.ln()));
        assert_relative_eq!(*fdrs[0], *LogProb(0.35 / 3.0f64.ln()));
    }
}
<commit_msg>Fix expected FDR implementation.<commit_after>// Copyright 2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Utilities for Bayesian statistics.

use ordered_float::OrderedFloat;
use itertools::Itertools;

use stats::LogProb;

/// For each of the hypothesis tests given as posterior error probabilities
/// (PEPs, i.e. the posterior probability of the null hypothesis), estimate the FDR
/// for the case that all null hypotheses with at most this PEP are rejected.
/// FDR is calculated as presented by Müller, Parmigiani, and Rice,
/// "FDR and Bayesian Multiple Comparisons Rules" (July 2006).
/// Johns Hopkin's University, Dept. of Biostatistics Working Papers. Working Paper 115.
///
/// # Returns
///
/// A vector of expected FDRs in the same order as the given PEPs.
pub fn expected_fdr(peps: &[LogProb]) -> Vec<LogProb> {
    // sort indices
    let sorted_idx =
        (0..peps.len()).sorted_by(|&i, &j| OrderedFloat(*peps[i]).cmp(&OrderedFloat(*peps[j])));
    // estimate FDR
    let mut expected_fdr = vec![LogProb::ln_zero(); peps.len()];
    for (i, expected_fp) in LogProb::ln_cumsum_exp(sorted_idx.iter().map(|&i| peps[i]))
            .enumerate() {
        let fdr = LogProb(*expected_fp - ((i + 1) as f64).ln());
        expected_fdr[i] = if fdr <= LogProb::ln_one() {
            fdr
        } else {
            LogProb::ln_one()
        };
    }

    expected_fdr
}

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

    #[test]
    fn test_expected_fdr() {
        let peps = [LogProb(0.1f64.ln()), LogProb::ln_zero(), LogProb(0.25f64.ln())];
        let fdrs = expected_fdr(&peps);
        println!("{:?}", fdrs);

        assert_relative_eq!(*fdrs[1], *LogProb::ln_zero());
        assert_relative_eq!(*fdrs[0], *LogProb(0.05f64.ln()));
        assert_relative_eq!(*fdrs[2], *LogProb((0.35 / 3.0f64).ln()));
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Handling log-probabilities.

use std::mem;
use std::f64;
use std::iter;

pub use stats::{Prob, LogProb};

/// A factor to convert log-probabilities to PHRED-scale (phred = p * LOG_TO_PHRED_FACTOR).
const LOG_TO_PHRED_FACTOR: f64 = -4.3429448190325175; // -10 * 1 / ln(10)

/// A factor to convert PHRED-scale to log-probabilities (p = phred * PHRED_TO_LOG_FACTOR).
const PHRED_TO_LOG_FACTOR: f64 = -0.23025850929940456; // 1 / (-10 * log10(e))

/// Calculate log(1 - p) with p given in log space without loss of precision as described in
/// http://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf.
pub fn ln_1m_exp(p: LogProb) -> LogProb {
    assert!(p <= 0.0);
    if p < -0.693 {
        (-p.exp()).ln_1p()
    } else {
        (-p.exp_m1()).ln()
    }
}

/// Convert log scale probability to PHRED scale.
pub fn log_to_phred(p: LogProb) -> f64 {
    p * LOG_TO_PHRED_FACTOR
}

/// Convert PHRED scale probability to log scale.
pub fn phred_to_log(p: f64) -> LogProb {
    p * PHRED_TO_LOG_FACTOR
}

/// Calculate the sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn sum(probs: &[LogProb]) -> LogProb {
    if probs.is_empty() {
        f64::NEG_INFINITY
    } else {
        let mut pmax = probs[0];
        let mut imax = 0;
        for (i, &p) in probs.iter().enumerate().skip(1) {
            if p > pmax {
                pmax = p;
                imax = i;
            }
        }
        if pmax == f64::NEG_INFINITY {
            f64::NEG_INFINITY
        } else if pmax == f64::INFINITY {
            f64::INFINITY
        } else {
            // TODO use sum() once it has been stabilized: .sum::<usize>()
            pmax +
            (probs.iter()
                  .enumerate()
                  .filter_map(|(i, p)| {
                      if i == imax {
                          None
                      } else {
                          Some((p - pmax).exp())
                      }
                  })
                  .fold(0.0, |s, e| s + e))
                .ln_1p()
        }
    }
}

/// Add the given probabilities in a numerically stable way (Durbin 1998).
pub fn add(mut p0: LogProb, mut p1: LogProb) -> LogProb {
    if p1 > p0 {
        mem::swap(&mut p0, &mut p1);
    }
    if p0 == f64::NEG_INFINITY {
        f64::NEG_INFINITY
    } else if p0 == f64::INFINITY {
        f64::INFINITY
    } else {
        p0 + (p1 - p0).exp().ln_1p()
    }
}

/// Subtract the given probabilities in a numerically stable way (Durbin 1998).
pub fn sub(p0: LogProb, p1: LogProb) -> LogProb {
    assert!(p0 >= p1, "Subtraction would lead to negative probability, which is undefined in log space.");
    if p0 == p1 || p0 == f64::NEG_INFINITY {
        // the first case leads to zero,
        // in the second case p0 and p1 are -inf, which is fine
        f64::NEG_INFINITY
    } else if p0 == f64::INFINITY {
        f64::INFINITY
    } else {
        p0 + ln_1m_exp(p1 - p0)
    }
}

fn scan_add(s: &mut LogProb, p: LogProb) -> Option<LogProb> {
    *s = add(*s, p);
    Some(*s)
}

/// Iterator returned by scans over logprobs.
pub type ScanIter<I> = iter::Scan<I, LogProb, fn(&mut LogProb, LogProb) -> Option<LogProb>>;

/// Calculate the cumulative sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn cumsum<I: Iterator<Item = LogProb>>(probs: I) -> ScanIter<I> {
    probs.scan(f64::NEG_INFINITY, scan_add)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f64;
    use itertools::Itertools;

    #[test]
    fn test_sum() {
        let probs = [f64::NEG_INFINITY, 0.0, f64::NEG_INFINITY];
        assert_eq!(sum(&probs), 0.0);
    }

    #[test]
    fn test_empty_sum() {
        assert_eq!(sum(&[]), f64::NEG_INFINITY);
    }

    #[test]
    fn test_cumsum() {
        let probs = vec![0.0f64.ln(), 0.01f64.ln(), 0.001f64.ln()];
        assert_eq!(cumsum(probs.into_iter()).collect_vec(),
                   [0.0f64.ln(), 0.01f64.ln(), 0.011f64.ln()]);
    }

    #[test]
    fn test_sub() {
        assert_eq!(sub(0.0f64.ln(), 0.0f64.ln()), f64::NEG_INFINITY);
        assert_relative_eq!(sub(1.0f64.ln(), 0.5f64.ln()), 0.5f64.ln());
    }

    #[test]
    fn test_ln_1m_exp() {
        assert_eq!(ln_1m_exp(f64::NEG_INFINITY), 0.0);
        assert_eq!(ln_1m_exp(0.0001), f64::NEG_INFINITY);
    }
}
<commit_msg>Fixed problematic test case.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Handling log-probabilities.

use std::mem;
use std::f64;
use std::iter;

pub use stats::{Prob, LogProb};

/// A factor to convert log-probabilities to PHRED-scale (phred = p * LOG_TO_PHRED_FACTOR).
const LOG_TO_PHRED_FACTOR: f64 = -4.3429448190325175; // -10 * 1 / ln(10)

/// A factor to convert PHRED-scale to log-probabilities (p = phred * PHRED_TO_LOG_FACTOR).
const PHRED_TO_LOG_FACTOR: f64 = -0.23025850929940456; // 1 / (-10 * log10(e))

/// Calculate log(1 - p) with p given in log space without loss of precision as described in
/// http://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf.
pub fn ln_1m_exp(p: LogProb) -> LogProb {
    assert!(p <= 0.0);
    if p < -0.693 {
        (-p.exp()).ln_1p()
    } else {
        (-p.exp_m1()).ln()
    }
}

/// Convert log scale probability to PHRED scale.
pub fn log_to_phred(p: LogProb) -> f64 {
    p * LOG_TO_PHRED_FACTOR
}

/// Convert PHRED scale probability to log scale.
pub fn phred_to_log(p: f64) -> LogProb {
    p * PHRED_TO_LOG_FACTOR
}

/// Calculate the sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn sum(probs: &[LogProb]) -> LogProb {
    if probs.is_empty() {
        f64::NEG_INFINITY
    } else {
        let mut pmax = probs[0];
        let mut imax = 0;
        for (i, &p) in probs.iter().enumerate().skip(1) {
            if p > pmax {
                pmax = p;
                imax = i;
            }
        }
        if pmax == f64::NEG_INFINITY {
            f64::NEG_INFINITY
        } else if pmax == f64::INFINITY {
            f64::INFINITY
        } else {
            // TODO use sum() once it has been stabilized: .sum::<usize>()
            pmax +
            (probs.iter()
                  .enumerate()
                  .filter_map(|(i, p)| {
                      if i == imax {
                          None
                      } else {
                          Some((p - pmax).exp())
                      }
                  })
                  .fold(0.0, |s, e| s + e))
                .ln_1p()
        }
    }
}

/// Add the given probabilities in a numerically stable way (Durbin 1998).
pub fn add(mut p0: LogProb, mut p1: LogProb) -> LogProb {
    if p1 > p0 {
        mem::swap(&mut p0, &mut p1);
    }
    if p0 == f64::NEG_INFINITY {
        f64::NEG_INFINITY
    } else if p0 == f64::INFINITY {
        f64::INFINITY
    } else {
        p0 + (p1 - p0).exp().ln_1p()
    }
}

/// Subtract the given probabilities in a numerically stable way (Durbin 1998).
pub fn sub(p0: LogProb, p1: LogProb) -> LogProb {
    assert!(p0 >= p1, "Subtraction would lead to negative probability, which is undefined in log space.");
    if p0 == p1 || p0 == f64::NEG_INFINITY {
        // the first case leads to zero,
        // in the second case p0 and p1 are -inf, which is fine
        f64::NEG_INFINITY
    } else if p0 == f64::INFINITY {
        f64::INFINITY
    } else {
        p0 + ln_1m_exp(p1 - p0)
    }
}

fn scan_add(s: &mut LogProb, p: LogProb) -> Option<LogProb> {
    *s = add(*s, p);
    Some(*s)
}

/// Iterator returned by scans over logprobs.
pub type ScanIter<I> = iter::Scan<I, LogProb, fn(&mut LogProb, LogProb) -> Option<LogProb>>;

/// Calculate the cumulative sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn cumsum<I: Iterator<Item = LogProb>>(probs: I) -> ScanIter<I> {
    probs.scan(f64::NEG_INFINITY, scan_add)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::f64;
    use itertools::Itertools;

    #[test]
    fn test_sum() {
        let probs = [f64::NEG_INFINITY, 0.0, f64::NEG_INFINITY];
        assert_eq!(sum(&probs), 0.0);
    }

    #[test]
    fn test_empty_sum() {
        assert_eq!(sum(&[]), f64::NEG_INFINITY);
    }

    #[test]
    fn test_cumsum() {
        let probs = vec![0.0f64.ln(), 0.01f64.ln(), 0.001f64.ln()];
        assert_eq!(cumsum(probs.into_iter()).collect_vec(),
                   [0.0f64.ln(), 0.01f64.ln(), 0.011f64.ln()]);
    }

    #[test]
    fn test_sub() {
        assert_eq!(sub(0.0f64.ln(), 0.0f64.ln()), f64::NEG_INFINITY);
        assert_relative_eq!(sub(1.0f64.ln(), 0.5f64.ln()), 0.5f64.ln());
    }

    #[test]
    fn test_ln_1m_exp() {
        assert_eq!(ln_1m_exp(f64::NEG_INFINITY), 0.0);
        assert_eq!(ln_1m_exp(-0.0), f64::NEG_INFINITY);
    }
}
<|endoftext|>