<commit_before>use crate::key::Key;
use crate::parser::errors::CustomError;
use crate::parser::key::key;
use crate::parser::table::extend_wrong_type;
use crate::parser::trivia::ws;
use crate::parser::value::value;
use crate::table::TableKeyValue;
use crate::{InlineTable, InternalString, Item, Value};
use combine::parser::byte::byte;
use combine::stream::RangeStream;
use combine::*;

// ;; Inline Table

// inline-table = inline-table-open inline-table-keyvals inline-table-close
parse!(inline_table() -> InlineTable, {
    between(byte(INLINE_TABLE_OPEN), byte(INLINE_TABLE_CLOSE),
            inline_table_keyvals().and_then(|(kv, p)| table_from_pairs(kv, p)))
});

fn table_from_pairs(
    v: Vec<(Vec<Key>, TableKeyValue)>,
    preamble: &str,
) -> Result<InlineTable, CustomError> {
    let mut root = InlineTable::new();
    root.preamble = InternalString::from(preamble);
    // Assuming almost all pairs will be directly in `root`
    root.items.reserve(v.len());

    for (path, kv) in v {
        let table = descend_path(&mut root, &path)?;
        let key: InternalString = kv.key.get_internal().into();
        let old = table.items.insert(key.clone(), kv);
        let duplicate_key = old.is_some();
        if duplicate_key {
            return Err(CustomError::DuplicateKey {
                key: key.as_str().into(),
                table: None,
            });
        }
    }
    Ok(root)
}

fn descend_path<'a>(
    mut table: &'a mut InlineTable,
    path: &'a [Key],
) -> Result<&'a mut InlineTable, CustomError> {
    for (i, key) in path.iter().enumerate() {
        let entry = table.entry_format(key).or_insert_with(|| {
            let mut new_table = InlineTable::new();
            new_table.set_dotted(true);

            Value::InlineTable(new_table)
        });
        match *entry {
            Value::InlineTable(ref mut sweet_child_of_mine) => {
                table = sweet_child_of_mine;
            }
            ref v => {
                return Err(extend_wrong_type(path, i, v.type_name()));
            }
        }
    }
    Ok(table)
}

// inline-table-open  = %x7B ws     ; {
pub(crate) const INLINE_TABLE_OPEN: u8 = b'{';
// inline-table-close = ws %x7D     ; }
const INLINE_TABLE_CLOSE: u8 = b'}';
// inline-table-sep   = ws %x2C ws  ; , Comma
const INLINE_TABLE_SEP: u8 = b',';
// keyval-sep = ws %x3D ws ; =
pub(crate) const KEYVAL_SEP: u8 = b'=';

// inline-table-keyvals = [ inline-table-keyvals-non-empty ]
// inline-table-keyvals-non-empty =
// ( key keyval-sep val inline-table-sep inline-table-keyvals-non-empty ) /
// ( key keyval-sep val )

parse!(inline_table_keyvals() -> (Vec<(Vec<Key>, TableKeyValue)>, &'a str), {
    (
        sep_by(keyval(), byte(INLINE_TABLE_SEP)),
        ws(),
    )
});

parse!(keyval() -> (Vec<Key>, TableKeyValue), {
    (
        key(),
        byte(KEYVAL_SEP),
        (ws(), value(), ws()),
    ).map(|(key, _, v)| {
        let mut path = key;
        let key = path.pop().expect("grammar ensures at least 1");

        let (pre, v, suf) = v;
        let v = v.decorated(pre, suf);
        (
            path,
            TableKeyValue {
                key,
                value: Item::Value(v),
            }
        )
    })
});
<commit_msg>use Entry api instead of key clone (#323)<commit_after>use crate::key::Key;
use crate::parser::errors::CustomError;
use crate::parser::key::key;
use crate::parser::table::extend_wrong_type;
use crate::parser::trivia::ws;
use crate::parser::value::value;
use crate::table::TableKeyValue;
use crate::{InlineTable, InternalString, Item, Value};
use combine::parser::byte::byte;
use combine::stream::RangeStream;
use combine::*;
use indexmap::map::Entry;

// ;; Inline Table

// inline-table = inline-table-open inline-table-keyvals inline-table-close
parse!(inline_table() -> InlineTable, {
    between(byte(INLINE_TABLE_OPEN), byte(INLINE_TABLE_CLOSE),
            inline_table_keyvals().and_then(|(kv, p)| table_from_pairs(kv, p)))
});

fn table_from_pairs(
    v: Vec<(Vec<Key>, TableKeyValue)>,
    preamble: &str,
) -> Result<InlineTable, CustomError> {
    let mut root = InlineTable::new();
    root.preamble = InternalString::from(preamble);
    // Assuming almost all pairs will be directly in `root`
    root.items.reserve(v.len());

    for (path, kv) in v {
        let table = descend_path(&mut root, &path)?;
        let key: InternalString = kv.key.get_internal().into();
        match table.items.entry(key) {
            Entry::Vacant(o) => {
                o.insert(kv);
            }
            Entry::Occupied(o) => {
                return Err(CustomError::DuplicateKey {
                    key: o.key().as_str().into(),
                    table: None,
                });
            }
        }
    }
    Ok(root)
}

fn descend_path<'a>(
    mut table: &'a mut InlineTable,
    path: &'a [Key],
) -> Result<&'a mut InlineTable, CustomError> {
    for (i, key) in path.iter().enumerate() {
        let entry = table.entry_format(key).or_insert_with(|| {
            let mut new_table = InlineTable::new();
            new_table.set_dotted(true);

            Value::InlineTable(new_table)
        });
        match *entry {
            Value::InlineTable(ref mut sweet_child_of_mine) => {
                table = sweet_child_of_mine;
            }
            ref v => {
                return Err(extend_wrong_type(path, i, v.type_name()));
            }
        }
    }
    Ok(table)
}

// inline-table-open  = %x7B ws     ; {
pub(crate) const INLINE_TABLE_OPEN: u8 = b'{';
// inline-table-close = ws %x7D     ; }
const INLINE_TABLE_CLOSE: u8 = b'}';
// inline-table-sep   = ws %x2C ws  ; , Comma
const INLINE_TABLE_SEP: u8 = b',';
// keyval-sep = ws %x3D ws ; =
pub(crate) const KEYVAL_SEP: u8 = b'=';

// inline-table-keyvals = [ inline-table-keyvals-non-empty ]
// inline-table-keyvals-non-empty =
// ( key keyval-sep val inline-table-sep inline-table-keyvals-non-empty ) /
// ( key keyval-sep val )

parse!(inline_table_keyvals() -> (Vec<(Vec<Key>, TableKeyValue)>, &'a str), {
    (
        sep_by(keyval(), byte(INLINE_TABLE_SEP)),
        ws(),
    )
});

parse!(keyval() -> (Vec<Key>, TableKeyValue), {
    (
        key(),
        byte(KEYVAL_SEP),
        (ws(), value(), ws()),
    ).map(|(key, _, v)| {
        let mut path = key;
        let key = path.pop().expect("grammar ensures at least 1");

        let (pre, v, suf) = v;
        let v = v.decorated(pre, suf);
        (
            path,
            TableKeyValue {
                key,
                value: Item::Value(v),
            }
        )
    })
});
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
/// rendered.

use css::matching::MatchMethods;
use css::select::new_css_select_ctx;
use layout::aux::{LayoutData, LayoutAuxMethods};
use layout::box::RenderBox;
use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder};
use layout::flow::FlowContext;

use std::cast::transmute;
use std::cell::Cell;
use std::comm::{Port};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::DisplayList;
use gfx::font_context::FontContext;
use gfx::geometry::Au;
use gfx::opts::Opts;
use gfx::render_task::{RenderMsg, RenderChan, RenderLayer};
use newcss::select::SelectCtx;
use newcss::stylesheet::Stylesheet;
use newcss::types::OriginAuthor;
use script::dom::event::ReflowEvent;
use script::dom::node::{AbstractNode, LayoutView};
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
use script::layout_interface::{MatchSelectorsDocumentDamage, Msg};
use script::layout_interface::{QueryMsg, Reflow, ReflowDocumentDamage};
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::{TreeNodeRef, TreeUtils};
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
use extra::net::url::Url;

struct LayoutTask {
    id: PipelineId,
    port: Port<Msg>,
    constellation_chan: ConstellationChan,
    script_chan: ScriptChan,
    render_chan: RenderChan,
    image_cache_task: ImageCacheTask,
    local_image_cache: @mut LocalImageCache,
    font_ctx: @mut FontContext,
    doc_url: Option<Url>,
    screen_size: Option<Size2D<Au>>,

    /// This is used to root reader data.
    layout_refs: ~[@mut LayoutData],

    css_select_ctx: @mut SelectCtx,
    profiler_chan: ProfilerChan,
}

impl LayoutTask {
    pub fn create(id: PipelineId,
                  port: Port<Msg>,
                  constellation_chan: ConstellationChan,
                  script_chan: ScriptChan,
                  render_chan: RenderChan,
                  img_cache_task: ImageCacheTask,
                  opts: Opts,
                  profiler_chan: ProfilerChan) {

        let port = Cell::new(port);
        let constellation_chan = Cell::new(constellation_chan);
        let script_chan = Cell::new(script_chan);
        let render_chan = Cell::new(render_chan);
        let img_cache_task = Cell::new(img_cache_task);
        let profiler_chan = Cell::new(profiler_chan);

        do spawn {
            let mut layout = LayoutTask::new(id,
                                             port.take(),
                                             constellation_chan.take(),
                                             script_chan.take(),
                                             render_chan.take(),
                                             img_cache_task.take(),
                                             &opts,
                                             profiler_chan.take());
            layout.start();
        };
    }

    fn new(id: PipelineId,
           port: Port<Msg>,
           constellation_chan: ConstellationChan,
           script_chan: ScriptChan,
           render_chan: RenderChan,
           image_cache_task: ImageCacheTask,
           opts: &Opts,
           profiler_chan: ProfilerChan)
           -> LayoutTask {
        let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());

        LayoutTask {
            id: id,
            port: port,
            constellation_chan: constellation_chan,
            script_chan: script_chan,
            render_chan: render_chan,
            image_cache_task: image_cache_task.clone(),
            local_image_cache: @mut LocalImageCache(image_cache_task),
            font_ctx: fctx,
            doc_url: None,
            screen_size: None,

            layout_refs: ~[],
            css_select_ctx: @mut new_css_select_ctx(),
            profiler_chan: profiler_chan,
        }
    }

    fn start(&mut self) {
        while self.handle_request() {
            // Loop indefinitely.
        }
    }

    // Create a layout context for use in building display lists, hit testing, &c.
    fn build_layout_context(&self) -> LayoutContext {
        let image_cache = self.local_image_cache;
        let font_ctx = self.font_ctx;
        let screen_size = self.screen_size.unwrap();

        LayoutContext {
            image_cache: image_cache,
            font_ctx: font_ctx,
            screen_size: Rect(Point2D(Au(0), Au(0)), screen_size),
        }
    }

    fn handle_request(&mut self) -> bool {
        match self.port.recv() {
            AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
            ReflowMsg(data) => {
                let data = Cell::new(data);

                do profile(time::LayoutPerformCategory, self.profiler_chan.clone()) {
                    self.handle_reflow(data.take());
                }
            }
            QueryMsg(query) => {
                let query = Cell::new(query);
                do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) {
                    self.handle_query(query.take());
                }
            }
            ExitMsg => {
                debug!("layout: ExitMsg received");
                return false
            }
        }

        true
    }

    fn handle_add_stylesheet(&self, sheet: Stylesheet) {
        let sheet = Cell::new(sheet);
        self.css_select_ctx.append_sheet(sheet.take(), OriginAuthor);
    }

    /// The high-level routine that performs layout tasks.
    fn handle_reflow(&mut self, data: &Reflow) {
        // FIXME: Isolate this transmutation into a "bridge" module.
        let node: &AbstractNode<LayoutView> = unsafe {
            transmute(&data.document_root)
        };

        // FIXME: Bad copy!
        let doc_url = copy data.url;
        let script_chan = data.script_chan.clone();

        debug!("layout: received layout request for: %s", doc_url.to_str());
        debug!("layout: damage is %?", data.damage);
        debug!("layout: parsed Node tree");
        debug!("%?", node.dump());
        // Reset the image cache.
        self.local_image_cache.next_round(self.make_on_image_available_cb(script_chan));

        self.doc_url = Some(doc_url);
        let screen_size = Size2D(Au::from_px(data.window_size.width as int),
                                 Au::from_px(data.window_size.height as int));
        self.screen_size = Some(screen_size);

        // Create a layout context for use throughout the following passes.
        let mut layout_ctx = self.build_layout_context();

        // Initialize layout data for each node.
        //
        // FIXME: This is inefficient. We don't need an entire traversal to do this!
        do profile(time::LayoutAuxInitCategory, self.profiler_chan.clone()) {
            node.initialize_style_for_subtree(&mut self.layout_refs);
        }

        // Perform CSS selector matching if necessary.
        match data.damage.level {
            ReflowDocumentDamage => {}
            MatchSelectorsDocumentDamage => {
                do profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone()) {
                    node.restyle_subtree(self.css_select_ctx);
                }
            }
        }

        // Construct the flow tree.
        let layout_root: FlowContext = do profile(time::LayoutTreeBuilderCategory,
                                                  self.profiler_chan.clone()) {
            let mut builder = LayoutTreeBuilder::new();
            let layout_root: FlowContext = match builder.construct_trees(&layout_ctx, *node) {
                Ok(root) => root,
                Err(*) => fail!(~"Root flow should always exist")
            };

            layout_root
        };

        debug!("layout: constructed Flow tree");
        debug!("", layout_root.dump());

        // Perform the primary layout passes over the flow tree to compute the locations of all
        // the boxes.
        do profile(time::LayoutMainCategory, self.profiler_chan.clone()) {
            for layout_root.traverse_postorder |flow| {
                flow.bubble_widths(&mut layout_ctx);
            };
            for layout_root.traverse_preorder |flow| {
                flow.assign_widths(&mut layout_ctx);
            };

            // For now, this is an inorder traversal
            layout_root.assign_height(&mut layout_ctx);
        }

        // Build the display list if necessary, and send it to the renderer.
        if data.goal == ReflowForDisplay {
            do profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone()) {
                let builder = DisplayListBuilder {
                    ctx: &layout_ctx,
                };

                let display_list = @Cell::new(DisplayList::new());

                // TODO: Set options on the builder before building.
                // TODO: Be smarter about what needs painting.
                do layout_root.partially_traverse_preorder |flow| {
                    flow.build_display_list(&builder, &layout_root.position(), display_list)
                }

                let root_size = do layout_root.with_base |base| {
                    base.position.size
                };

                let render_layer = RenderLayer {
                    display_list: display_list.take(),
                    size: Size2D(root_size.width.to_px() as uint, root_size.height.to_px() as uint)
                };

                self.render_chan.send(RenderMsg(render_layer));
            } // time(layout: display list building)
        }

        debug!("%?", layout_root.dump());

        // Tell script that we're done.
        //
        // FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
        // either select or a filtered recv() that only looks for messages of a given type.
        data.script_join_chan.send(());
        data.script_chan.send(ReflowCompleteMsg(self.id));
    }

    /// Handles a query from the script task. This is the main routine that DOM functions like
    /// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
    fn handle_query(&self, query: LayoutQuery) {
        match query {
            ContentBoxQuery(node, reply_chan) => {
                // FIXME: Isolate this transmutation into a single "bridge" module.
                let node: AbstractNode<LayoutView> = unsafe {
                    transmute(node)
                };

                let response = match node.layout_data().flow {
                    None => {
                        error!("no flow present");
                        Err(())
                    }
                    Some(flow) => {
                        let start_val: Option<Rect<Au>> = None;
                        let rect = do flow.foldl_boxes_for_node(node, start_val) |acc, box| {
                            match acc {
                                Some(acc) => Some(acc.union(&box.content_box())),
                                None => Some(box.content_box())
                            }
                        };

                        match rect {
                            None => {
                                error!("no boxes for node");
                                Err(())
                            }
                            Some(rect) => Ok(ContentBoxResponse(rect))
                        }
                    }
                };

                reply_chan.send(response)
            }
            ContentBoxesQuery(node, reply_chan) => {
                // FIXME: Isolate this transmutation into a single "bridge" module.
                let node: AbstractNode<LayoutView> = unsafe {
                    transmute(node)
                };

                let response = match node.layout_data().flow {
                    None => Err(()),
                    Some(flow) => {
                        let mut boxes = ~[];
                        for flow.iter_boxes_for_node(node) |box| {
                            boxes.push(box.content_box());
                        }

                        Ok(ContentBoxesResponse(boxes))
                    }
                };

                reply_chan.send(response)
            }
            HitTestQuery(node, point, reply_chan) => {
                // FIXME: Isolate this transmutation into a single "bridge" module.
                let node: AbstractNode<LayoutView> = unsafe {
                    transmute(node)
                };
                let mut flow_node: AbstractNode<LayoutView> = node;
                for node.traverse_preorder |node| {
                    if node.layout_data().flow.is_some() {
                        flow_node = node;
                        break;
                    }
                };

                let response = match flow_node.layout_data().flow {
                    None => {
                        debug!("HitTestQuery: flow is None");
                        Err(())
                    }
                    Some(flow) => {
                        let layout_ctx = self.build_layout_context();
                        let builder = DisplayListBuilder {
                            ctx: &layout_ctx,
                        };
                        let display_list: @Cell<DisplayList<RenderBox>> =
                            @Cell::new(DisplayList::new());

                        do flow.partially_traverse_preorder |this_flow| {
                            this_flow.build_display_list(&builder,
                                                    &flow.position(),
                                                    display_list)

                        }
                        let (x, y) = (Au::from_frac_px(point.x as float),
                                      Au::from_frac_px(point.y as float));
                        let mut resp = Err(());
                        let display_list = &display_list.take().list;
                        // iterate in reverse to ensure we have the most recently painted render box
                        for display_list.rev_iter().advance |display_item| {
                            let bounds = display_item.bounds();
                            // TODO this check should really be performed by a method of DisplayItem
                            if x <= bounds.origin.x + bounds.size.width &&
                               bounds.origin.x <= x &&
                               y < bounds.origin.y + bounds.size.height &&
                               bounds.origin.y <  y {
                                resp = Ok(HitTestResponse(display_item.base().extra.node()));
                                break;
                            }
                        }
                        resp
                    }
                };

                reply_chan.send(response)
            }
        }
    }

    // When images can't be loaded in time to display they trigger
    // this callback in some task somewhere. This will send a message
    // to the script task, and ultimately cause the image to be
    // re-requested. We probably don't need to go all the way back to
    // the script task for this.
    fn make_on_image_available_cb(&self, script_chan: ScriptChan)
                                  -> @fn() -> ~fn(ImageResponseMsg) {
        // This has a crazy signature because the image cache needs to
        // make multiple copies of the callback, and the dom event
        // channel is not a copyable type, so this is actually a
        // little factory to produce callbacks
        let id = self.id.clone();
        let f: @fn() -> ~fn(ImageResponseMsg) = || {
            let script_chan = script_chan.clone();
            let f: ~fn(ImageResponseMsg) = |_| {
                script_chan.send(SendEventMsg(id.clone(), ReflowEvent))
            };
            f
        };
        return f;
    }
}

<commit_msg>Clean up calls to layout_root.dump()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
/// rendered.

use css::matching::MatchMethods;
use css::select::new_css_select_ctx;
use layout::aux::{LayoutData, LayoutAuxMethods};
use layout::box::RenderBox;
use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder};
use layout::flow::FlowContext;

use std::cast::transmute;
use std::cell::Cell;
use std::comm::{Port};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::DisplayList;
use gfx::font_context::FontContext;
use gfx::geometry::Au;
use gfx::opts::Opts;
use gfx::render_task::{RenderMsg, RenderChan, RenderLayer};
use newcss::select::SelectCtx;
use newcss::stylesheet::Stylesheet;
use newcss::types::OriginAuthor;
use script::dom::event::ReflowEvent;
use script::dom::node::{AbstractNode, LayoutView};
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse};
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitMsg, LayoutQuery};
use script::layout_interface::{MatchSelectorsDocumentDamage, Msg};
use script::layout_interface::{QueryMsg, Reflow, ReflowDocumentDamage};
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::{TreeNodeRef, TreeUtils};
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
use extra::net::url::Url;

struct LayoutTask {
    id: PipelineId,
    port: Port<Msg>,
    constellation_chan: ConstellationChan,
    script_chan: ScriptChan,
    render_chan: RenderChan,
    image_cache_task: ImageCacheTask,
    local_image_cache: @mut LocalImageCache,
    font_ctx: @mut FontContext,
    doc_url: Option<Url>,
    screen_size: Option<Size2D<Au>>,

    /// This is used to root reader data.
    layout_refs: ~[@mut LayoutData],

    css_select_ctx: @mut SelectCtx,
    profiler_chan: ProfilerChan,
}

impl LayoutTask {
    pub fn create(id: PipelineId,
                  port: Port<Msg>,
                  constellation_chan: ConstellationChan,
                  script_chan: ScriptChan,
                  render_chan: RenderChan,
                  img_cache_task: ImageCacheTask,
                  opts: Opts,
                  profiler_chan: ProfilerChan) {

        let port = Cell::new(port);
        let constellation_chan = Cell::new(constellation_chan);
        let script_chan = Cell::new(script_chan);
        let render_chan = Cell::new(render_chan);
        let img_cache_task = Cell::new(img_cache_task);
        let profiler_chan = Cell::new(profiler_chan);

        do spawn {
            let mut layout = LayoutTask::new(id,
                                             port.take(),
                                             constellation_chan.take(),
                                             script_chan.take(),
                                             render_chan.take(),
                                             img_cache_task.take(),
                                             &opts,
                                             profiler_chan.take());
            layout.start();
        };
    }

    fn new(id: PipelineId,
           port: Port<Msg>,
           constellation_chan: ConstellationChan,
           script_chan: ScriptChan,
           render_chan: RenderChan,
           image_cache_task: ImageCacheTask,
           opts: &Opts,
           profiler_chan: ProfilerChan)
           -> LayoutTask {
        let fctx = @mut FontContext::new(opts.render_backend, true, profiler_chan.clone());

        LayoutTask {
            id: id,
            port: port,
            constellation_chan: constellation_chan,
            script_chan: script_chan,
            render_chan: render_chan,
            image_cache_task: image_cache_task.clone(),
            local_image_cache: @mut LocalImageCache(image_cache_task),
            font_ctx: fctx,
            doc_url: None,
            screen_size: None,

            layout_refs: ~[],
            css_select_ctx: @mut new_css_select_ctx(),
            profiler_chan: profiler_chan,
        }
    }

    fn start(&mut self) {
        while self.handle_request() {
            // Loop indefinitely.
        }
    }

    // Create a layout context for use in building display lists, hit testing, &c.
    fn build_layout_context(&self) -> LayoutContext {
        let image_cache = self.local_image_cache;
        let font_ctx = self.font_ctx;
        let screen_size = self.screen_size.unwrap();

        LayoutContext {
            image_cache: image_cache,
            font_ctx: font_ctx,
            screen_size: Rect(Point2D(Au(0), Au(0)), screen_size),
        }
    }

    fn handle_request(&mut self) -> bool {
        match self.port.recv() {
            AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet),
            ReflowMsg(data) => {
                let data = Cell::new(data);

                do profile(time::LayoutPerformCategory, self.profiler_chan.clone()) {
                    self.handle_reflow(data.take());
                }
            }
            QueryMsg(query) => {
                let query = Cell::new(query);
                do profile(time::LayoutQueryCategory, self.profiler_chan.clone()) {
                    self.handle_query(query.take());
                }
            }
            ExitMsg => {
                debug!("layout: ExitMsg received");
                return false
            }
        }

        true
    }

    fn handle_add_stylesheet(&self, sheet: Stylesheet) {
        let sheet = Cell::new(sheet);
        self.css_select_ctx.append_sheet(sheet.take(), OriginAuthor);
    }

    /// The high-level routine that performs layout tasks.
    fn handle_reflow(&mut self, data: &Reflow) {
        // FIXME: Isolate this transmutation into a "bridge" module.
        let node: &AbstractNode<LayoutView> = unsafe {
            transmute(&data.document_root)
        };

        // FIXME: Bad copy!
        let doc_url = copy data.url;
        let script_chan = data.script_chan.clone();

        debug!("layout: received layout request for: %s", doc_url.to_str());
        debug!("layout: damage is %?", data.damage);
        debug!("layout: parsed Node tree");
        debug!("%?", node.dump());
        // Reset the image cache.
        self.local_image_cache.next_round(self.make_on_image_available_cb(script_chan));

        self.doc_url = Some(doc_url);
        let screen_size = Size2D(Au::from_px(data.window_size.width as int),
                                 Au::from_px(data.window_size.height as int));
        self.screen_size = Some(screen_size);

        // Create a layout context for use throughout the following passes.
        let mut layout_ctx = self.build_layout_context();

        // Initialize layout data for each node.
        //
        // FIXME: This is inefficient. We don't need an entire traversal to do this!
        do profile(time::LayoutAuxInitCategory, self.profiler_chan.clone()) {
            node.initialize_style_for_subtree(&mut self.layout_refs);
        }

        // Perform CSS selector matching if necessary.
        match data.damage.level {
            ReflowDocumentDamage => {}
            MatchSelectorsDocumentDamage => {
                do profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone()) {
                    node.restyle_subtree(self.css_select_ctx);
                }
            }
        }

        // Construct the flow tree.
        let layout_root: FlowContext = do profile(time::LayoutTreeBuilderCategory,
                                                  self.profiler_chan.clone()) {
            let mut builder = LayoutTreeBuilder::new();
            let layout_root: FlowContext = match builder.construct_trees(&layout_ctx, *node) {
                Ok(root) => root,
                Err(*) => fail!(~"Root flow should always exist")
            };

            layout_root
        };

        debug!("layout: constructed Flow tree");
        debug!("%?", layout_root.dump());

        // Perform the primary layout passes over the flow tree to compute the locations of all
        // the boxes.
        do profile(time::LayoutMainCategory, self.profiler_chan.clone()) {
            for layout_root.traverse_postorder |flow| {
                flow.bubble_widths(&mut layout_ctx);
            };
            for layout_root.traverse_preorder |flow| {
                flow.assign_widths(&mut layout_ctx);
            };

            // For now, this is an inorder traversal
            layout_root.assign_height(&mut layout_ctx);
        }

        // Build the display list if necessary, and send it to the renderer.
        if data.goal == ReflowForDisplay {
            do profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone()) {
                let builder = DisplayListBuilder {
                    ctx: &layout_ctx,
                };

                let display_list = @Cell::new(DisplayList::new());

                // TODO: Set options on the builder before building.
                // TODO: Be smarter about what needs painting.
                do layout_root.partially_traverse_preorder |flow| {
                    flow.build_display_list(&builder, &layout_root.position(), display_list)
                }

                let root_size = do layout_root.with_base |base| {
                    base.position.size
                };

                let render_layer = RenderLayer {
                    display_list: display_list.take(),
                    size: Size2D(root_size.width.to_px() as uint, root_size.height.to_px() as uint)
                };

                self.render_chan.send(RenderMsg(render_layer));
            } // time(layout: display list building)
        }

        // Tell script that we're done.
        //
        // FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
        // either select or a filtered recv() that only looks for messages of a given type.
        data.script_join_chan.send(());
        data.script_chan.send(ReflowCompleteMsg(self.id));
    }

    /// Handles a query from the script task. This is the main routine that DOM functions like
    /// `getClientRects()` or `getBoundingClientRect()` ultimately invoke.
    fn handle_query(&self, query: LayoutQuery) {
        match query {
            ContentBoxQuery(node, reply_chan) => {
                // FIXME: Isolate this transmutation into a single "bridge" module.
                let node: AbstractNode<LayoutView> = unsafe {
                    transmute(node)
                };

                let response = match node.layout_data().flow {
                    None => {
                        error!("no flow present");
                        Err(())
                    }
                    Some(flow) => {
                        let start_val: Option<Rect<Au>> = None;
                        let rect = do flow.foldl_boxes_for_node(node, start_val) |acc, box| {
                            match acc {
                                Some(acc) => Some(acc.union(&box.content_box())),
                                None => Some(box.content_box())
                            }
                        };

                        match rect {
                            None => {
                                error!("no boxes for node");
                                Err(())
                            }
                            Some(rect) => Ok(ContentBoxResponse(rect))
                        }
                    }
                };

                reply_chan.send(response)
            }
            ContentBoxesQuery(node, reply_chan) => {
                // FIXME: Isolate this transmutation into a single "bridge" module.
                let node: AbstractNode<LayoutView> = unsafe {
                    transmute(node)
                };

                let response = match node.layout_data().flow {
                    None => Err(()),
                    Some(flow) => {
                        let mut boxes = ~[];
                        for flow.iter_boxes_for_node(node) |box| {
                            boxes.push(box.content_box());
                        }

                        Ok(ContentBoxesResponse(boxes))
                    }
                };

                reply_chan.send(response)
            }
            HitTestQuery(node, point, reply_chan) => {
                // FIXME: Isolate this transmutation into a single "bridge" module.
                let node: AbstractNode<LayoutView> = unsafe {
                    transmute(node)
                };
                let mut flow_node: AbstractNode<LayoutView> = node;
                for node.traverse_preorder |node| {
                    if node.layout_data().flow.is_some() {
                        flow_node = node;
                        break;
                    }
                };

                let response = match flow_node.layout_data().flow {
                    None => {
                        debug!("HitTestQuery: flow is None");
                        Err(())
                    }
                    Some(flow) => {
                        let layout_ctx = self.build_layout_context();
                        let builder = DisplayListBuilder {
                            ctx: &layout_ctx,
                        };
                        let display_list: @Cell<DisplayList<RenderBox>> =
                            @Cell::new(DisplayList::new());

                        do flow.partially_traverse_preorder |this_flow| {
                            this_flow.build_display_list(&builder,
                                                    &flow.position(),
                                                    display_list)

                        }
                        let (x, y) = (Au::from_frac_px(point.x as float),
                                      Au::from_frac_px(point.y as float));
                        let mut resp = Err(());
                        let display_list = &display_list.take().list;
                        // iterate in reverse to ensure we have the most recently painted render box
                        for display_list.rev_iter().advance |display_item| {
                            let bounds = display_item.bounds();
                            // TODO this check should really be performed by a method of DisplayItem
                            if x <= bounds.origin.x + bounds.size.width &&
                               bounds.origin.x <= x &&
                               y < bounds.origin.y + bounds.size.height &&
                               bounds.origin.y <  y {
                                resp = Ok(HitTestResponse(display_item.base().extra.node()));
                                break;
                            }
                        }
                        resp
                    }
                };

                reply_chan.send(response)
            }
        }
    }

    // When images can't be loaded in time to display they trigger
    // this callback in some task somewhere. This will send a message
    // to the script task, and ultimately cause the image to be
    // re-requested. We probably don't need to go all the way back to
    // the script task for this.
    fn make_on_image_available_cb(&self, script_chan: ScriptChan)
                                  -> @fn() -> ~fn(ImageResponseMsg) {
        // This has a crazy signature because the image cache needs to
        // make multiple copies of the callback, and the dom event
        // channel is not a copyable type, so this is actually a
        // little factory to produce callbacks
        let id = self.id.clone();
        let f: @fn() -> ~fn(ImageResponseMsg) = || {
            let script_chan = script_chan.clone();
            let f: ~fn(ImageResponseMsg) = |_| {
                script_chan.send(SendEventMsg(id.clone(), ReflowEvent))
            };
            f
        };
        return f;
    }
}

<|endoftext|>


<commit_before>use std::fmt;

mod tokens;
use self::tokens::*;

enum OperationInput {
    StaticValue(f64),
    SubOperation(Box<Operation>, Sign),
    Unset,
}

impl OperationInput {
    fn get(&self) -> f64 {
        match *self {
            OperationInput::StaticValue(f) => f,
            OperationInput::SubOperation(ref ob, sign) => {
                let res = ob.calc();
                if sign == Sign::Minus {
                    res * -1f64
                } else {
                    res
                }
            },
            OperationInput::Unset => panic!("Can't get value of unset operation input"),
        }
    }

    fn add_sign(&mut self, new_sign: Sign) {

        println!("[debug] add sign {} to {}", new_sign, self.get());

        match *self {
            OperationInput::StaticValue(value) => {
                if new_sign == Sign::Minus {
                    *self = OperationInput::StaticValue(value * -1f64);
                }
            },
            OperationInput::SubOperation(_, ref mut sign) => {
                *sign = sign.applay(new_sign);
            },
            OperationInput::Unset => panic!("Can't add sing to unset operation input"),
        }
    }
}

enum OperationType {
    Add,
    Subtract,
    Multiply,
    Divide,
    Unset,
}
impl fmt::Display for OperationType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OperationType::Add => write!(f, "+"),
            OperationType::Subtract => write!(f, "-"),
            OperationType::Multiply => write!(f, "*"),
            OperationType::Divide => write!(f, "/"),
            OperationType::Unset => write!(f, "unset"),
        }
    }
}

struct Operation {
    right: OperationInput,
    operator: OperationType,
    left: OperationInput,
}

impl Operation {
    fn calc(&self) -> f64 {
        match self.left {
            OperationInput::Unset => return 0f64,
            _ => {}
        }

        match self.operator {
            OperationType::Add => self.left.get() + self.right.get(),
            OperationType::Subtract => self.left.get() - self.right.get(),
            OperationType::Multiply => self.left.get() * self.right.get(),
            OperationType::Divide => self.left.get() / self.right.get(),
            OperationType::Unset => self.left.get(),
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum Sign {
    Plus,
    Minus,
}

impl Sign {
    fn invert(&self) -> Sign {
        match *self {
            Sign::Minus => Sign::Plus,
            Sign::Plus => Sign::Minus,
        }
    }
    fn applay(&self, sign: Sign) -> Sign {
        match sign {
            Sign::Minus => self.invert(),
            _ => *self
        }
    }
}

impl fmt::Display for Sign {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Sign::Minus => write!(f, "minus"),
            Sign::Plus => write!(f, "plus"),
        }
    }
}

fn to_operation(tokens: &[Token]) -> Result<Operation, (&str, usize)> {

    if tokens.len() == 0 {
        return Result::Err(("nothing to calculate", 0));
    }

    #[derive(Debug, PartialEq, Eq)]
    enum State {
        NothingDone,
        RightSet,
        OperatorSet,
        LeftSet,
    }

    let mut state = State::NothingDone;

    let mut left = OperationInput::Unset;
    let mut left_num_sign = Sign::Plus;

    let mut operator = OperationType::Unset;

    let mut right = OperationInput::Unset;
    let mut right_num_sign = Sign::Plus;

    println!("[debug] tokens:");

    for (pos, t) in tokens.iter().enumerate() {

        println!("[debug] - '{}' of type {}", t.content, t.token_type);

        match t.token_type {
            TokenType::Operator => {
                if state == State::LeftSet {
                    operator = match t.content.as_ref() {
                        "+" => OperationType::Add,
                        "-" => OperationType::Subtract,
                        "*" => OperationType::Multiply,
                        "/" => OperationType::Divide,
                        _ => panic!(format!("{} is not an operator", t.content))
                    };

                    state = State::OperatorSet;
                } else {
                    let sign_optional = match t.content.as_ref() {
                        "+" => Option::Some(Sign::Plus),
                        "-" => Option::Some(Sign::Minus),
                        _ => Option::None
                    };

                    if let Some(sign) = sign_optional {
                        match state {
                            State::NothingDone => {
                                left_num_sign = left_num_sign.applay(sign);
                            },
                            State::OperatorSet => {
                                right_num_sign = right_num_sign.applay(sign);
                            },
                            _ => return Result::Err(("unexpected operator", t.pos))
                        }
                    } else {
                        return Result::Err(("unexpected operator", t.pos));
                    }
                }
            },
            TokenType::Number => {
                let value = t.content.replace(",", ".").parse().unwrap();

                match state {
                    State::NothingDone => {
                        left = OperationInput::StaticValue(value);
                        left.add_sign(left_num_sign);
                        state = State::LeftSet;
                    },
                    State::OperatorSet => {
                        if pos == tokens.len() - 1 {
                            right = OperationInput::StaticValue(value);
                            if right_num_sign != Sign::Plus {
                                right.add_sign(right_num_sign);
                            }
                            state = State::RightSet;
                        } else {
                            let remaining = &tokens[pos..tokens.len()];

                            match to_operation(remaining) {
                                Err((msg, pos)) => {
                                    return Result::Err((msg, pos));
                                },
                                Ok(operation) => {
                                    right = OperationInput::SubOperation(Box::new(operation), right_num_sign);
                                },
                            }
                            state = State::RightSet;
                            break;
                        }
                    },
                    _ => return Result::Err(("unexpected number", t.pos))
                }
            },
            TokenType::None => {},
        }
    }

    if state == State::OperatorSet {
        if let Some(last_token) = tokens.last() {
            return Result::Err(("missing ending token", last_token.pos));
        }
    }

    return Result::Ok(Operation {
        left: left,
        operator: operator,
        right: right,
    });
}

pub fn exec_expression(expr_str: &str) -> Result<f64, (String, usize)> {
    match tokenize(expr_str) {
        Ok(tokens) => {
            match to_operation(tokens.as_slice()) {
                Ok(operation) => Result::Ok(operation.calc()),
                Err((msg, pos)) => Result::Err((String::from(msg), pos)),
            }
        },
        Err((msg, pos)) => Result::Err((String::from(msg), pos)),
    }
}
<commit_msg>Rename `pos` to `i` (the token index)<commit_after>use std::fmt;

mod tokens;
use self::tokens::*;

enum OperationInput {
    StaticValue(f64),
    SubOperation(Box<Operation>, Sign),
    Unset,
}

impl OperationInput {
    fn get(&self) -> f64 {
        match *self {
            OperationInput::StaticValue(f) => f,
            OperationInput::SubOperation(ref ob, sign) => {
                let res = ob.calc();
                if sign == Sign::Minus {
                    res * -1f64
                } else {
                    res
                }
            },
            OperationInput::Unset => panic!("Can't get value of unset operation input"),
        }
    }

    fn add_sign(&mut self, new_sign: Sign) {

        println!("[debug] add sign {} to {}", new_sign, self.get());

        match *self {
            OperationInput::StaticValue(value) => {
                if new_sign == Sign::Minus {
                    *self = OperationInput::StaticValue(value * -1f64);
                }
            },
            OperationInput::SubOperation(_, ref mut sign) => {
                *sign = sign.applay(new_sign);
            },
            OperationInput::Unset => panic!("Can't add sing to unset operation input"),
        }
    }
}

enum OperationType {
    Add,
    Subtract,
    Multiply,
    Divide,
    Unset,
}
impl fmt::Display for OperationType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OperationType::Add => write!(f, "+"),
            OperationType::Subtract => write!(f, "-"),
            OperationType::Multiply => write!(f, "*"),
            OperationType::Divide => write!(f, "/"),
            OperationType::Unset => write!(f, "unset"),
        }
    }
}

struct Operation {
    right: OperationInput,
    operator: OperationType,
    left: OperationInput,
}

impl Operation {
    fn calc(&self) -> f64 {
        match self.left {
            OperationInput::Unset => return 0f64,
            _ => {}
        }

        match self.operator {
            OperationType::Add => self.left.get() + self.right.get(),
            OperationType::Subtract => self.left.get() - self.right.get(),
            OperationType::Multiply => self.left.get() * self.right.get(),
            OperationType::Divide => self.left.get() / self.right.get(),
            OperationType::Unset => self.left.get(),
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum Sign {
    Plus,
    Minus,
}

impl Sign {
    fn invert(&self) -> Sign {
        match *self {
            Sign::Minus => Sign::Plus,
            Sign::Plus => Sign::Minus,
        }
    }
    fn applay(&self, sign: Sign) -> Sign {
        match sign {
            Sign::Minus => self.invert(),
            _ => *self
        }
    }
}

impl fmt::Display for Sign {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Sign::Minus => write!(f, "minus"),
            Sign::Plus => write!(f, "plus"),
        }
    }
}

fn to_operation(tokens: &[Token]) -> Result<Operation, (&str, usize)> {

    if tokens.len() == 0 {
        return Result::Err(("nothing to calculate", 0));
    }

    #[derive(Debug, PartialEq, Eq)]
    enum State {
        NothingDone,
        RightSet,
        OperatorSet,
        LeftSet,
    }

    let mut state = State::NothingDone;

    let mut left = OperationInput::Unset;
    let mut left_num_sign = Sign::Plus;

    let mut operator = OperationType::Unset;

    let mut right = OperationInput::Unset;
    let mut right_num_sign = Sign::Plus;

    println!("[debug] tokens:");

    for (i, t) in tokens.iter().enumerate() {

        println!("[debug] - '{}' of type {}", t.content, t.token_type);

        match t.token_type {
            TokenType::Operator => {
                if state == State::LeftSet {
                    operator = match t.content.as_ref() {
                        "+" => OperationType::Add,
                        "-" => OperationType::Subtract,
                        "*" => OperationType::Multiply,
                        "/" => OperationType::Divide,
                        _ => panic!(format!("{} is not an operator", t.content))
                    };

                    state = State::OperatorSet;
                } else {
                    let sign_optional = match t.content.as_ref() {
                        "+" => Option::Some(Sign::Plus),
                        "-" => Option::Some(Sign::Minus),
                        _ => Option::None
                    };

                    if let Some(sign) = sign_optional {
                        match state {
                            State::NothingDone => {
                                left_num_sign = left_num_sign.applay(sign);
                            },
                            State::OperatorSet => {
                                right_num_sign = right_num_sign.applay(sign);
                            },
                            _ => return Result::Err(("unexpected operator", t.pos))
                        }
                    } else {
                        return Result::Err(("unexpected operator", t.pos));
                    }
                }
            },
            TokenType::Number => {
                let value = t.content.replace(",", ".").parse().unwrap();

                match state {
                    State::NothingDone => {
                        left = OperationInput::StaticValue(value);
                        left.add_sign(left_num_sign);
                        state = State::LeftSet;
                    },
                    State::OperatorSet => {
                        if i == tokens.len() - 1 {
                            right = OperationInput::StaticValue(value);
                            if right_num_sign != Sign::Plus {
                                right.add_sign(right_num_sign);
                            }
                            state = State::RightSet;
                        } else {
                            let remaining = &tokens[i..tokens.len()];

                            match to_operation(remaining) {
                                Err((msg, pos)) => {
                                    return Result::Err((msg, pos));
                                },
                                Ok(operation) => {
                                    right = OperationInput::SubOperation(Box::new(operation), right_num_sign);
                                },
                            }
                            state = State::RightSet;
                            break;
                        }
                    },
                    _ => return Result::Err(("unexpected number", t.pos))
                }
            },
            TokenType::None => {},
        }
    }

    if state == State::OperatorSet {
        if let Some(last_token) = tokens.last() {
            return Result::Err(("missing ending token", last_token.pos));
        }
    }

    return Result::Ok(Operation {
        left: left,
        operator: operator,
        right: right,
    });
}

pub fn exec_expression(expr_str: &str) -> Result<f64, (String, usize)> {
    match tokenize(expr_str) {
        Ok(tokens) => {
            match to_operation(tokens.as_slice()) {
                Ok(operation) => Result::Ok(operation.calc()),
                Err((msg, pos)) => Result::Err((String::from(msg), pos)),
            }
        },
        Err((msg, pos)) => Result::Err((String::from(msg), pos)),
    }
}
<|endoftext|>


<commit_before>use std::ops::{Index, IndexMut};
use sha1::{Sha1, Digest};
use metainfo::FileInfo;

pub struct PartialFile {
    collection: PieceCollection,
    info: FileInfo
}

impl PartialFile {
    pub fn new(info: &FileInfo) -> PartialFile {
        PartialFile {
            info: info.clone(),
            collection: PieceCollection::new(info.piece_length as usize,
                info.pieces.len() as u64)
        }
    }

    pub fn is_complete(&self) -> bool {
        for i in 0..self.info.pieces.len() {
            if !self._is_piece_complete(i) {
                return false;
            }
        }
        true
    }

    fn _is_piece_complete(&self, i: usize) -> bool {
        let mut sha1: Sha1 = Sha1::new();
        sha1.update(&self.collection[i]);
        let ref bytes1 = sha1.digest().bytes();
        let ref bytes2 = self.info.pieces[i];
        bytes1 == bytes2.as_slice()
    }

    pub fn bit_array(&self) -> Vec<bool> {
        (0..self.info.pieces.len())
            .map(|i| self._is_piece_complete(i))
            .collect::<Vec<bool>>()
    }

    pub fn add_piece(&mut self, index: usize, offset: usize, block: Vec<u8>) -> bool {
        self.collection.add(index, offset, block)
    }
}

struct PieceCollection {
    pieces: Vec<Vec<u8>>,
    piece_size: u64
}

impl PieceCollection {
    pub fn new(pieces: usize, size: u64) -> PieceCollection {
        let mut vec = Vec::new();
        for i in 0..pieces {
            vec.push(Vec::new());
        }
        PieceCollection { pieces: vec, piece_size: size }
    }

    pub fn add(&mut self, index: usize, offset: usize, block: Vec<u8>) -> bool {
        if index >= self.pieces.len() { return false; }
        if offset + block.len() > self.piece_size as usize {
            return false;
        }

        let existing_block = &mut self.pieces[index];
        existing_block.resize(offset + block.len(), 0);
        for i in 0..block.len() {
            existing_block[offset + i as usize] = block[i];
        }
        true
    }
}

impl Index<usize> for PieceCollection {
    type Output = Vec<u8>;

    fn index<'a>(&'a self, _index: usize) -> &'a Vec<u8> {
        &self.pieces[_index]
    }
}

impl IndexMut<usize> for PieceCollection {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Vec<u8> {
        &mut self.pieces[_index]
    }
}
<commit_msg>Add Piece struct<commit_after>use std::ops::{Index, IndexMut};
use sha1::{Sha1, Digest};
use metainfo::FileInfo;

pub struct PartialFile {
    collection: PieceCollection,
    info: FileInfo
}

impl PartialFile {
    pub fn new(info: &FileInfo) -> PartialFile {
        PartialFile {
            info: info.clone(),
            collection: PieceCollection::new(info.piece_length as usize,
                info.pieces.len() as u64)
        }
    }

    pub fn is_complete(&self) -> bool {
        for i in 0..self.info.pieces.len() {
            if !self._is_piece_complete(i) {
                return false;
            }
        }
        true
    }

    pub fn has_piece(&self, i: usize) -> bool {
        self._is_piece_complete(i)
    }

    pub fn get_piece_mut<'a>(&self, i: usize) -> &'a mut Piece {
        &mut self.collection.pieces[i]
    }

    fn _is_piece_complete(&self, i: usize) -> bool {
        let mut sha1: Sha1 = Sha1::new();
        sha1.update(&self.collection[i]);
        let ref bytes1 = sha1.digest().bytes();
        let ref bytes2 = self.info.pieces[i];
        bytes1 == bytes2.as_slice()
    }

    pub fn bit_array(&self) -> Vec<bool> {
        (0..self.info.pieces.len())
            .map(|i| self._is_piece_complete(i))
            .collect::<Vec<bool>>()
    }

    pub fn add_piece(&mut self, index: usize, offset: usize, block: Vec<u8>) -> bool {
        self.collection.add(index, offset, block)
    }
}

struct Piece {
    data: Vec<u8>,
    length: u32
}

impl Piece {
    pub fn add(&mut self: offset: u32, block: Vec<u8>) {

    }

    pub fn get_offset(
}

struct PieceCollection {
    pieces: Vec<Vec<u8>>,
    piece_size: u64
}

impl PieceCollection {
    pub fn new(pieces: usize, size: u64) -> PieceCollection {
        let mut vec = Vec::new();
        for i in 0..pieces {
            vec.push(Vec::new());
        }
        PieceCollection { pieces: vec, piece_size: size }
    }

    pub fn add(&mut self, index: usize, offset: usize, block: Vec<u8>) -> bool {
        if index >= self.pieces.len() { return false; }
        if offset + block.len() > self.piece_size as usize {
            return false;
        }

        let existing_block = &mut self.pieces[index];
        existing_block.resize(offset + block.len(), 0);
        for i in 0..block.len() {
            existing_block[offset + i as usize] = block[i];
        }
        true
    }
}

impl Index<usize> for PieceCollection {
    type Output = Vec<u8>;

    fn index<'a>(&'a self, _index: usize) -> &'a Vec<u8> {
        &self.pieces[_index]
    }
}

impl IndexMut<usize> for PieceCollection {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Vec<u8> {
        &mut self.pieces[_index]
    }
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::higher::FormatArgsExpn;
use clippy_utils::{is_expn_of, match_function_call, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
    /// replaced with `(e)print!()` / `(e)println!()`
    ///
    /// **Why is this bad?** Using `(e)println! is clearer and more concise
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # use std::io::Write;
    /// # let bar = "furchtbar";
    /// // this would be clearer as `eprintln!("foo: {:?}", bar);`
    /// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
    /// ```
    pub EXPLICIT_WRITE,
    complexity,
    "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
}

declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]);

impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if_chain! {
            // match call to unwrap
            if let ExprKind::MethodCall(unwrap_fun, _, [write_call], _) = expr.kind;
            if unwrap_fun.ident.name == sym::unwrap;
            // match call to write_fmt
            if let ExprKind::MethodCall(write_fun, _, [write_recv, write_arg], _) = write_call.kind;
            if write_fun.ident.name == sym!(write_fmt);
            // match calls to std::io::stdout() / std::io::stderr ()
            if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
                Some("stdout")
            } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() {
                Some("stderr")
            } else {
                None
            };
            if let Some(format_args) = FormatArgsExpn::parse(write_arg);
            then {
                let calling_macro =
                    // ordering is important here, since `writeln!` uses `write!` internally
                    if is_expn_of(write_call.span, "writeln").is_some() {
                        Some("writeln")
                    } else if is_expn_of(write_call.span, "write").is_some() {
                        Some("write")
                    } else {
                        None
                    };
                let prefix = if dest_name == "stderr" {
                    "e"
                } else {
                    ""
                };

                // We need to remove the last trailing newline from the string because the
                // underlying `fmt::write` function doesn't know whether `println!` or `print!` was
                // used.
                if let [write_output] = *format_args.format_string_symbols {
                    let mut write_output = write_output.to_string();
                    if write_output.ends_with('\n') {
                        write_output.pop();
                    }

                    if let Some(macro_name) = calling_macro {
                        span_lint_and_sugg(
                            cx,
                            EXPLICIT_WRITE,
                            expr.span,
                            &format!(
                                "use of `{}!({}(), ...).unwrap()`",
                                macro_name,
                                dest_name
                            ),
                            "try this",
                            format!("{}{}!(\"{}\")", prefix, macro_name.replace("write", "print"), write_output.escape_default()),
                            Applicability::MachineApplicable
                        );
                    } else {
                        span_lint_and_sugg(
                            cx,
                            EXPLICIT_WRITE,
                            expr.span,
                            &format!("use of `{}().write_fmt(...).unwrap()`", dest_name),
                            "try this",
                            format!("{}print!(\"{}\")", prefix, write_output.escape_default()),
                            Applicability::MachineApplicable
                        );
                    }
                } else {
                    // We don't have a proper suggestion
                    if let Some(macro_name) = calling_macro {
                        span_lint(
                            cx,
                            EXPLICIT_WRITE,
                            expr.span,
                            &format!(
                                "use of `{}!({}(), ...).unwrap()`. Consider using `{}{}!` instead",
                                macro_name,
                                dest_name,
                                prefix,
                                macro_name.replace("write", "print")
                            )
                        );
                    } else {
                        span_lint(
                            cx,
                            EXPLICIT_WRITE,
                            expr.span,
                            &format!("use of `{}().write_fmt(...).unwrap()`. Consider using `{}print!` instead", dest_name, prefix),
                        );
                    }
                }

            }
        }
    }
}
<commit_msg>Reduce redundant code<commit_after>use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::higher::FormatArgsExpn;
use clippy_utils::{is_expn_of, match_function_call, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
    /// replaced with `(e)print!()` / `(e)println!()`
    ///
    /// **Why is this bad?** Using `(e)println! is clearer and more concise
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # use std::io::Write;
    /// # let bar = "furchtbar";
    /// // this would be clearer as `eprintln!("foo: {:?}", bar);`
    /// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
    /// ```
    pub EXPLICIT_WRITE,
    complexity,
    "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
}

declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]);

impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if_chain! {
            // match call to unwrap
            if let ExprKind::MethodCall(unwrap_fun, _, [write_call], _) = expr.kind;
            if unwrap_fun.ident.name == sym::unwrap;
            // match call to write_fmt
            if let ExprKind::MethodCall(write_fun, _, [write_recv, write_arg], _) = write_call.kind;
            if write_fun.ident.name == sym!(write_fmt);
            // match calls to std::io::stdout() / std::io::stderr ()
            if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
                Some("stdout")
            } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() {
                Some("stderr")
            } else {
                None
            };
            if let Some(format_args) = FormatArgsExpn::parse(write_arg);
            then {
                let calling_macro =
                    // ordering is important here, since `writeln!` uses `write!` internally
                    if is_expn_of(write_call.span, "writeln").is_some() {
                        Some("writeln")
                    } else if is_expn_of(write_call.span, "write").is_some() {
                        Some("write")
                    } else {
                        None
                    };
                let prefix = if dest_name == "stderr" {
                    "e"
                } else {
                    ""
                };

                // We need to remove the last trailing newline from the string because the
                // underlying `fmt::write` function doesn't know whether `println!` or `print!` was
                // used.
                let (used, sugg_mac) = if let Some(macro_name) = calling_macro {
                    (
                        format!("{}!({}(), ...)", macro_name, dest_name),
                        macro_name.replace("write", "print"),
                    )
                } else {
                    (
                        format!("{}().write_fmt(...)", dest_name),
                        "print".into(),
                    )
                };
                let msg = format!("use of `{}.unwrap()`", used);
                if let [write_output] = *format_args.format_string_symbols {
                    let mut write_output = write_output.to_string();
                    if write_output.ends_with('\n') {
                        write_output.pop();
                    }

                    let sugg = format!("{}{}!(\"{}\")", prefix, sugg_mac, write_output.escape_default());
                    span_lint_and_sugg(
                        cx,
                        EXPLICIT_WRITE,
                        expr.span,
                        &msg,
                        "try this",
                        sugg,
                        Applicability::MachineApplicable
                    );
                } else {
                    // We don't have a proper suggestion
                    let msg = format!("{}. Consider using `{}{}!` instead", msg, prefix, sugg_mac);
                    span_lint(cx, EXPLICIT_WRITE, expr.span, &msg);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{last_path_segment, snippet, span_lint_and_sugg};
use rustc_hir::{GenericArg, Mutability, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

use if_chain::if_chain;
use rustc_errors::Applicability;

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `&Option<&T>`.
    ///
    /// **Why is this bad?** Since `&` is Copy, it's useless to have a
    /// reference on `Option<&T>`.
    ///
    /// **Known problems:** It may be irrevelent to use this lint on
    /// public API code as it will make a breaking change to apply it.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// let x: &Option<&u32> = &Some(&0u32);
    /// ```
    /// Use instead:
    /// ```rust,ignore
    /// let x: Option<&u32> = Some(&0u32);
    /// ```
    pub REF_OPTION_REF,
    style,
    "use `Option<&T>` instead of `&Option<&T>`"
}

declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]);

impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
        if_chain! {
            if let TyKind::Rptr(_, ref mut_ty) = ty.kind;
            if mut_ty.mutbl == Mutability::Not;
            if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
            let last = last_path_segment(qpath);
            if let Some(res) = last.res;
            if let Some(def_id) = res.opt_def_id();

            if cx.tcx.is_diagnostic_item(sym!(option_type), def_id);
            if let Some(ref params) = last_path_segment(qpath).args ;
            if !params.parenthesized;
            if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg {
                GenericArg::Type(inner_ty) => Some(inner_ty),
                _ => None,
            });
            if let TyKind::Rptr(_, _) = inner_ty.kind;

            then {
                span_lint_and_sugg(
                    cx,
                    REF_OPTION_REF,
                    ty.span,
                    "since & implements Copy trait, &Option<&T> can be simplifyied into Option<&T>",
                    "try",
                    format!("Option<{}>", &snippet(cx, inner_ty.span, "..")),
                    Applicability::Unspecified,
                );
            }
        }
    }
}
<commit_msg>Update clippy_lints/src/ref_option_ref.rs<commit_after>use crate::utils::{last_path_segment, snippet, span_lint_and_sugg};
use rustc_hir::{GenericArg, Mutability, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

use if_chain::if_chain;
use rustc_errors::Applicability;

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `&Option<&T>`.
    ///
    /// **Why is this bad?** Since `&` is Copy, it's useless to have a
    /// reference on `Option<&T>`.
    ///
    /// **Known problems:** It may be irrevelent to use this lint on
    /// public API code as it will make a breaking change to apply it.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// let x: &Option<&u32> = &Some(&0u32);
    /// ```
    /// Use instead:
    /// ```rust,ignore
    /// let x: Option<&u32> = Some(&0u32);
    /// ```
    pub REF_OPTION_REF,
    pedantic,
    "use `Option<&T>` instead of `&Option<&T>`"
}

declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]);

impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
        if_chain! {
            if let TyKind::Rptr(_, ref mut_ty) = ty.kind;
            if mut_ty.mutbl == Mutability::Not;
            if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
            let last = last_path_segment(qpath);
            if let Some(res) = last.res;
            if let Some(def_id) = res.opt_def_id();

            if cx.tcx.is_diagnostic_item(sym!(option_type), def_id);
            if let Some(ref params) = last_path_segment(qpath).args ;
            if !params.parenthesized;
            if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg {
                GenericArg::Type(inner_ty) => Some(inner_ty),
                _ => None,
            });
            if let TyKind::Rptr(_, _) = inner_ty.kind;

            then {
                span_lint_and_sugg(
                    cx,
                    REF_OPTION_REF,
                    ty.span,
                    "since & implements Copy trait, &Option<&T> can be simplifyied into Option<&T>",
                    "try",
                    format!("Option<{}>", &snippet(cx, inner_ty.span, "..")),
                    Applicability::Unspecified,
                );
            }
        }
    }
}
<|endoftext|>