<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/. */

use fnv::FnvHasher;
use layer::{Layer, ScrollingState};
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
use webrender_traits::{ScrollEventPhase, ScrollLayerId, ScrollLayerInfo, ScrollLayerPixel};
use webrender_traits::{ScrollLayerRect, ScrollLayerState, ScrollLocation, ScrollToWorldTransform};
use webrender_traits::{ServoScrollRootId, WorldPoint, as_scroll_parent_rect};

pub type ScrollStates = HashMap<ScrollLayerId, ScrollingState, BuildHasherDefault<FnvHasher>>;

pub struct ScrollTree {
    pub layers: HashMap<ScrollLayerId, Layer, BuildHasherDefault<FnvHasher>>,
    pub pending_scroll_offsets: HashMap<(PipelineId, ServoScrollRootId), LayerPoint>,

    /// The ScrollLayerId of the currently scrolling layer. Used to allow the same
    /// layer to scroll even if a touch operation leaves the boundaries of that layer.
    pub current_scroll_layer_id: Option<ScrollLayerId>,

    /// The current reference frame id, used for giving a unique id to all new
    /// reference frames. The ScrollTree increments this by one every time a
    /// reference frame is created.
    current_reference_frame_id: usize,

    /// The root reference frame, which is the true root of the ScrollTree. Initially
    /// this ID is not valid, which is indicated by ```layers``` being empty.
    pub root_reference_frame_id: ScrollLayerId,

    /// The root scroll layer, which is the first child of the root reference frame.
    /// Initially this ID is not valid, which is indicated by ```layers``` being empty.
    pub topmost_scroll_layer_id: ScrollLayerId,

    /// A set of pipelines which should be discarded the next time this
    /// tree is drained.
    pub pipelines_to_discard: HashSet<PipelineId>,
}

impl ScrollTree {
    pub fn new() -> ScrollTree {
        let dummy_pipeline = PipelineId(0, 0);
        ScrollTree {
            layers: HashMap::with_hasher(Default::default()),
            pending_scroll_offsets: HashMap::new(),
            current_scroll_layer_id: None,
            root_reference_frame_id: ScrollLayerId::root_reference_frame(dummy_pipeline),
            topmost_scroll_layer_id: ScrollLayerId::root_scroll_layer(dummy_pipeline),
            current_reference_frame_id: 1,
            pipelines_to_discard: HashSet::new(),
        }
    }

    pub fn root_reference_frame_id(&self) -> ScrollLayerId {
        // TODO(mrobinson): We should eventually make this impossible to misuse.
        debug_assert!(!self.layers.is_empty());
        debug_assert!(self.layers.contains_key(&self.root_reference_frame_id));
        self.root_reference_frame_id
    }

    pub fn topmost_scroll_layer_id(&self) -> ScrollLayerId {
        // TODO(mrobinson): We should eventually make this impossible to misuse.
        debug_assert!(!self.layers.is_empty());
        debug_assert!(self.layers.contains_key(&self.topmost_scroll_layer_id));
        self.topmost_scroll_layer_id
    }

    pub fn establish_root(&mut self,
                          pipeline_id: PipelineId,
                          viewport_size: &LayerSize,
                          content_size: &LayerSize) {
        debug_assert!(self.layers.is_empty());

        let identity = LayerToScrollTransform::identity();
        let viewport = LayerRect::new(LayerPoint::zero(), *viewport_size);

        let root_reference_frame_id = ScrollLayerId::root_reference_frame(pipeline_id);
        self.root_reference_frame_id = root_reference_frame_id;
        let reference_frame = Layer::new(&viewport, viewport.size, &identity, pipeline_id);
        self.layers.insert(self.root_reference_frame_id, reference_frame);

        let scroll_layer = Layer::new(&viewport, *content_size, &identity, pipeline_id);
        let topmost_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
        self.topmost_scroll_layer_id = topmost_scroll_layer_id;
        self.add_layer(scroll_layer, topmost_scroll_layer_id, root_reference_frame_id);
    }

    pub fn collect_layers_bouncing_back(&self)
                                        -> HashSet<ScrollLayerId, BuildHasherDefault<FnvHasher>> {
        let mut layers_bouncing_back = HashSet::with_hasher(Default::default());
        for (scroll_layer_id, layer) in self.layers.iter() {
            if layer.scrolling.bouncing_back {
                layers_bouncing_back.insert(*scroll_layer_id);
            }
        }
        layers_bouncing_back
    }

    fn find_scrolling_layer_at_point_in_layer(&self,
                                              cursor: &WorldPoint,
                                              scroll_layer_id: ScrollLayerId)
                                              -> Option<ScrollLayerId> {
        self.layers.get(&scroll_layer_id).and_then(|layer| {
            for child_layer_id in layer.children.iter().rev() {
            if let Some(layer_id) =
                self.find_scrolling_layer_at_point_in_layer(cursor, *child_layer_id) {
                    return Some(layer_id);
                }
            }

            if let ScrollLayerInfo::ReferenceFrame(_) = scroll_layer_id.info {
                return None;
            }

            if layer.ray_intersects_layer(cursor) {
                Some(scroll_layer_id)
            } else {
                None
            }
        })
    }

    pub fn find_scrolling_layer_at_point(&self, cursor: &WorldPoint) -> ScrollLayerId {
        self.find_scrolling_layer_at_point_in_layer(cursor, self.root_reference_frame_id())
            .unwrap_or(self.topmost_scroll_layer_id())
    }

    pub fn get_scroll_layer_state(&self) -> Vec<ScrollLayerState> {
        let mut result = vec![];
        for (scroll_layer_id, scroll_layer) in self.layers.iter() {
            match scroll_layer_id.info {
                ScrollLayerInfo::Scrollable(_, servo_scroll_root_id) => {
                    result.push(ScrollLayerState {
                        pipeline_id: scroll_layer.pipeline_id,
                        scroll_root_id: servo_scroll_root_id,
                        scroll_offset: scroll_layer.scrolling.offset,
                    })
                }
                ScrollLayerInfo::ReferenceFrame(..) => {}
            }
        }
        result
    }

    pub fn drain(&mut self) -> ScrollStates {
        self.current_reference_frame_id = 1;

        let mut scroll_states = HashMap::with_hasher(Default::default());
        for (layer_id, old_layer) in &mut self.layers.drain() {
            if !self.pipelines_to_discard.contains(&layer_id.pipeline_id) {
                scroll_states.insert(layer_id, old_layer.scrolling);
            }
        }

        self.pipelines_to_discard.clear();
        scroll_states
    }

    pub fn scroll_layers(&mut self,
                         origin: LayerPoint,
                         pipeline_id: PipelineId,
                         scroll_root_id: ServoScrollRootId)
                         -> bool {
        if self.layers.is_empty() {
            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
            return false;
        }

        let origin = LayerPoint::new(origin.x.max(0.0), origin.y.max(0.0));

        let mut scrolled_a_layer = false;
        let mut found_layer = false;
        for (layer_id, layer) in self.layers.iter_mut() {
            if layer_id.pipeline_id != pipeline_id {
                continue;
            }

            match layer_id.info {
                ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
                ScrollLayerInfo::ReferenceFrame(..) => continue,
                ScrollLayerInfo::Scrollable(..) => {}
            }

            found_layer = true;
            scrolled_a_layer |= layer.set_scroll_origin(&origin);
        }

        if !found_layer {
            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
        }

        scrolled_a_layer
    }

    pub fn scroll(&mut self,
                  scroll_location: ScrollLocation,
                  cursor: WorldPoint,
                  phase: ScrollEventPhase)
                  -> bool {
        if self.layers.is_empty() {
            return false;
        }

        let scroll_layer_id = match (
            phase,
            self.find_scrolling_layer_at_point(&cursor),
            self.current_scroll_layer_id) {
            (ScrollEventPhase::Start, scroll_layer_id, _) => {
                self.current_scroll_layer_id = Some(scroll_layer_id);
                scroll_layer_id
            },
            (_, _, Some(scroll_layer_id)) => scroll_layer_id,
            (_, _, None) => return false,
        };

        let topmost_scroll_layer_id = self.topmost_scroll_layer_id();
        let non_root_overscroll = if scroll_layer_id != topmost_scroll_layer_id {
            // true if the current layer is overscrolling,
            // and it is not the root scroll layer.
            let child_layer = self.layers.get(&scroll_layer_id).unwrap();
            let overscroll_amount = child_layer.overscroll_amount();
            overscroll_amount.width != 0.0 || overscroll_amount.height != 0.0
        } else {
            false
        };

        let switch_layer = match phase {
            ScrollEventPhase::Start => {
                // if this is a new gesture, we do not switch layer,
                // however we do save the state of non_root_overscroll,
                // for use in the subsequent Move phase.
                let mut current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
                current_layer.scrolling.should_handoff_scroll = non_root_overscroll;
                false
            },
            ScrollEventPhase::Move(_) => {
                // Switch layer if movement originated in a new gesture,
                // from a non root layer in overscroll.
                let current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
                current_layer.scrolling.should_handoff_scroll && non_root_overscroll
            },
            ScrollEventPhase::End => {
                // clean-up when gesture ends.
                let mut current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
                current_layer.scrolling.should_handoff_scroll = false;
                false
            },
        };

        let scroll_layer_info = if switch_layer {
            topmost_scroll_layer_id.info
        } else {
            scroll_layer_id.info
        };

        let scroll_root_id = match scroll_layer_info {
             ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
             _ => unreachable!("Tried to scroll a reference frame."),

        };

        let mut scrolled_a_layer = false;
        for (layer_id, layer) in self.layers.iter_mut() {
            if layer_id.pipeline_id != scroll_layer_id.pipeline_id {
                continue;
            }

            match layer_id.info {
                ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
                ScrollLayerInfo::ReferenceFrame(..) => continue,
                _ => {}
            }

            let scrolled_this_layer = layer.scroll(scroll_location, phase);
            scrolled_a_layer = scrolled_a_layer || scrolled_this_layer;
        }
        scrolled_a_layer
    }

    pub fn update_all_layer_transforms(&mut self) {
        if self.layers.is_empty() {
            return;
        }

        let root_reference_frame_id = self.root_reference_frame_id();
        let root_viewport = self.layers[&root_reference_frame_id].local_viewport_rect;
        self.update_layer_transform(root_reference_frame_id,
                                    &ScrollToWorldTransform::identity(),
                                    &as_scroll_parent_rect(&root_viewport));
    }

    fn update_layer_transform(&mut self,
                              layer_id: ScrollLayerId,
                              parent_world_transform: &ScrollToWorldTransform,
                              parent_viewport_rect: &ScrollLayerRect) {
        // TODO(gw): This is an ugly borrow check workaround to clone these.
        //           Restructure this to avoid the clones!
        let (layer_transform_for_children, viewport_rect, layer_children) = {
            match self.layers.get_mut(&layer_id) {
                Some(layer) => {
                    layer.update_transform(parent_world_transform, parent_viewport_rect);

                    (layer.world_content_transform.with_source::<ScrollLayerPixel>(),
                     as_scroll_parent_rect(&layer.combined_local_viewport_rect),
                     layer.children.clone())
                }
                None => return,
            }
        };

        for child_layer_id in layer_children {
            self.update_layer_transform(child_layer_id,
                                        &layer_transform_for_children,
                                        &viewport_rect);
        }
    }

    pub fn tick_scrolling_bounce_animations(&mut self) {
        for (_, layer) in &mut self.layers {
            layer.tick_scrolling_bounce_animation()
        }
    }

    pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
        // TODO(gw): These are all independent - can be run through thread pool if it shows up
        // in the profile!
        for (scroll_layer_id, layer) in &mut self.layers {
            let scrolling_state = match old_states.get(&scroll_layer_id) {
                Some(old_scrolling_state) => *old_scrolling_state,
                None => ScrollingState::new(),
            };

            layer.finalize(&scrolling_state);

            let scroll_root_id = match scroll_layer_id.info {
                ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
                _ => continue,
            };

            let pipeline_id = scroll_layer_id.pipeline_id;
            if let Some(pending_offset) =
                self.pending_scroll_offsets.remove(&(pipeline_id, scroll_root_id)) {
                layer.set_scroll_origin(&pending_offset);
            }
        }

    }

    pub fn add_reference_frame(&mut self,
                               rect: LayerRect,
                               transform: LayerToScrollTransform,
                               pipeline_id: PipelineId,
                               parent_id: ScrollLayerId) -> ScrollLayerId {
        let reference_frame_id = ScrollLayerId {
            pipeline_id: pipeline_id,
            info: ScrollLayerInfo::ReferenceFrame(self.current_reference_frame_id),
        };
        self.current_reference_frame_id += 1;

        let layer = Layer::new(&rect, rect.size, &transform, pipeline_id);
        self.add_layer(layer, reference_frame_id, parent_id);
        reference_frame_id
    }

    pub fn add_layer(&mut self, layer: Layer, id: ScrollLayerId, parent_id: ScrollLayerId) {
        debug_assert!(!self.layers.contains_key(&id));
        self.layers.insert(id, layer);

        debug_assert!(parent_id != id);
        self.layers.get_mut(&parent_id).unwrap().add_child(id);
    }

    pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
        self.pipelines_to_discard.insert(pipeline_id);

        match self.current_scroll_layer_id {
            Some(id) if id.pipeline_id == pipeline_id => self.current_scroll_layer_id = None,
            _ => {}
        }
    }
}

<commit_msg>Auto merge of #800 - gterzian:fix_current_scroll_layer_caching, r=glennw<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/. */

use fnv::FnvHasher;
use layer::{Layer, ScrollingState};
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
use webrender_traits::{ScrollEventPhase, ScrollLayerId, ScrollLayerInfo, ScrollLayerPixel};
use webrender_traits::{ScrollLayerRect, ScrollLayerState, ScrollLocation, ScrollToWorldTransform};
use webrender_traits::{ServoScrollRootId, WorldPoint, as_scroll_parent_rect};

pub type ScrollStates = HashMap<ScrollLayerId, ScrollingState, BuildHasherDefault<FnvHasher>>;

pub struct ScrollTree {
    pub layers: HashMap<ScrollLayerId, Layer, BuildHasherDefault<FnvHasher>>,
    pub pending_scroll_offsets: HashMap<(PipelineId, ServoScrollRootId), LayerPoint>,

    /// The ScrollLayerId of the currently scrolling layer. Used to allow the same
    /// layer to scroll even if a touch operation leaves the boundaries of that layer.
    pub current_scroll_layer_id: Option<ScrollLayerId>,

    /// The current reference frame id, used for giving a unique id to all new
    /// reference frames. The ScrollTree increments this by one every time a
    /// reference frame is created.
    current_reference_frame_id: usize,

    /// The root reference frame, which is the true root of the ScrollTree. Initially
    /// this ID is not valid, which is indicated by ```layers``` being empty.
    pub root_reference_frame_id: ScrollLayerId,

    /// The root scroll layer, which is the first child of the root reference frame.
    /// Initially this ID is not valid, which is indicated by ```layers``` being empty.
    pub topmost_scroll_layer_id: ScrollLayerId,

    /// A set of pipelines which should be discarded the next time this
    /// tree is drained.
    pub pipelines_to_discard: HashSet<PipelineId>,
}

impl ScrollTree {
    pub fn new() -> ScrollTree {
        let dummy_pipeline = PipelineId(0, 0);
        ScrollTree {
            layers: HashMap::with_hasher(Default::default()),
            pending_scroll_offsets: HashMap::new(),
            current_scroll_layer_id: None,
            root_reference_frame_id: ScrollLayerId::root_reference_frame(dummy_pipeline),
            topmost_scroll_layer_id: ScrollLayerId::root_scroll_layer(dummy_pipeline),
            current_reference_frame_id: 1,
            pipelines_to_discard: HashSet::new(),
        }
    }

    pub fn root_reference_frame_id(&self) -> ScrollLayerId {
        // TODO(mrobinson): We should eventually make this impossible to misuse.
        debug_assert!(!self.layers.is_empty());
        debug_assert!(self.layers.contains_key(&self.root_reference_frame_id));
        self.root_reference_frame_id
    }

    pub fn topmost_scroll_layer_id(&self) -> ScrollLayerId {
        // TODO(mrobinson): We should eventually make this impossible to misuse.
        debug_assert!(!self.layers.is_empty());
        debug_assert!(self.layers.contains_key(&self.topmost_scroll_layer_id));
        self.topmost_scroll_layer_id
    }

    pub fn establish_root(&mut self,
                          pipeline_id: PipelineId,
                          viewport_size: &LayerSize,
                          content_size: &LayerSize) {
        debug_assert!(self.layers.is_empty());

        let identity = LayerToScrollTransform::identity();
        let viewport = LayerRect::new(LayerPoint::zero(), *viewport_size);

        let root_reference_frame_id = ScrollLayerId::root_reference_frame(pipeline_id);
        self.root_reference_frame_id = root_reference_frame_id;
        let reference_frame = Layer::new(&viewport, viewport.size, &identity, pipeline_id);
        self.layers.insert(self.root_reference_frame_id, reference_frame);

        let scroll_layer = Layer::new(&viewport, *content_size, &identity, pipeline_id);
        let topmost_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
        self.topmost_scroll_layer_id = topmost_scroll_layer_id;
        self.add_layer(scroll_layer, topmost_scroll_layer_id, root_reference_frame_id);
    }

    pub fn collect_layers_bouncing_back(&self)
                                        -> HashSet<ScrollLayerId, BuildHasherDefault<FnvHasher>> {
        let mut layers_bouncing_back = HashSet::with_hasher(Default::default());
        for (scroll_layer_id, layer) in self.layers.iter() {
            if layer.scrolling.bouncing_back {
                layers_bouncing_back.insert(*scroll_layer_id);
            }
        }
        layers_bouncing_back
    }

    fn find_scrolling_layer_at_point_in_layer(&self,
                                              cursor: &WorldPoint,
                                              scroll_layer_id: ScrollLayerId)
                                              -> Option<ScrollLayerId> {
        self.layers.get(&scroll_layer_id).and_then(|layer| {
            for child_layer_id in layer.children.iter().rev() {
            if let Some(layer_id) =
                self.find_scrolling_layer_at_point_in_layer(cursor, *child_layer_id) {
                    return Some(layer_id);
                }
            }

            if let ScrollLayerInfo::ReferenceFrame(_) = scroll_layer_id.info {
                return None;
            }

            if layer.ray_intersects_layer(cursor) {
                Some(scroll_layer_id)
            } else {
                None
            }
        })
    }

    pub fn find_scrolling_layer_at_point(&self, cursor: &WorldPoint) -> ScrollLayerId {
        self.find_scrolling_layer_at_point_in_layer(cursor, self.root_reference_frame_id())
            .unwrap_or(self.topmost_scroll_layer_id())
    }

    pub fn get_scroll_layer_state(&self) -> Vec<ScrollLayerState> {
        let mut result = vec![];
        for (scroll_layer_id, scroll_layer) in self.layers.iter() {
            match scroll_layer_id.info {
                ScrollLayerInfo::Scrollable(_, servo_scroll_root_id) => {
                    result.push(ScrollLayerState {
                        pipeline_id: scroll_layer.pipeline_id,
                        scroll_root_id: servo_scroll_root_id,
                        scroll_offset: scroll_layer.scrolling.offset,
                    })
                }
                ScrollLayerInfo::ReferenceFrame(..) => {}
            }
        }
        result
    }

    pub fn drain(&mut self) -> ScrollStates {
        self.current_reference_frame_id = 1;

        let mut scroll_states = HashMap::with_hasher(Default::default());
        for (layer_id, old_layer) in &mut self.layers.drain() {
            if !self.pipelines_to_discard.contains(&layer_id.pipeline_id) {
                scroll_states.insert(layer_id, old_layer.scrolling);
            }
        }

        self.pipelines_to_discard.clear();
        scroll_states
    }

    pub fn scroll_layers(&mut self,
                         origin: LayerPoint,
                         pipeline_id: PipelineId,
                         scroll_root_id: ServoScrollRootId)
                         -> bool {
        if self.layers.is_empty() {
            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
            return false;
        }

        let origin = LayerPoint::new(origin.x.max(0.0), origin.y.max(0.0));

        let mut scrolled_a_layer = false;
        let mut found_layer = false;
        for (layer_id, layer) in self.layers.iter_mut() {
            if layer_id.pipeline_id != pipeline_id {
                continue;
            }

            match layer_id.info {
                ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
                ScrollLayerInfo::ReferenceFrame(..) => continue,
                ScrollLayerInfo::Scrollable(..) => {}
            }

            found_layer = true;
            scrolled_a_layer |= layer.set_scroll_origin(&origin);
        }

        if !found_layer {
            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
        }

        scrolled_a_layer
    }

    pub fn scroll(&mut self,
                  scroll_location: ScrollLocation,
                  cursor: WorldPoint,
                  phase: ScrollEventPhase)
                  -> bool {
        if self.layers.is_empty() {
            return false;
        }

        let scroll_layer_id = match (
            phase,
            self.find_scrolling_layer_at_point(&cursor),
            self.current_scroll_layer_id) {
            (ScrollEventPhase::Start, scroll_layer_at_point_id, _) => {
                self.current_scroll_layer_id = Some(scroll_layer_at_point_id);
                scroll_layer_at_point_id
            },
            (_, scroll_layer_at_point_id, Some(cached_scroll_layer_id)) => {
                let scroll_layer_id = match self.layers.get(&cached_scroll_layer_id) {
                    Some(_) => cached_scroll_layer_id,
                    None => {
                        self.current_scroll_layer_id = Some(scroll_layer_at_point_id);
                        scroll_layer_at_point_id
                    },
                };
                scroll_layer_id
            },
            (_, _, None) => return false,
        };

        let topmost_scroll_layer_id = self.topmost_scroll_layer_id();
        let non_root_overscroll = if scroll_layer_id != topmost_scroll_layer_id {
            // true if the current layer is overscrolling,
            // and it is not the root scroll layer.
            let child_layer = self.layers.get(&scroll_layer_id).unwrap();
            let overscroll_amount = child_layer.overscroll_amount();
            overscroll_amount.width != 0.0 || overscroll_amount.height != 0.0
        } else {
            false
        };

        let switch_layer = match phase {
            ScrollEventPhase::Start => {
                // if this is a new gesture, we do not switch layer,
                // however we do save the state of non_root_overscroll,
                // for use in the subsequent Move phase.
                let mut current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
                current_layer.scrolling.should_handoff_scroll = non_root_overscroll;
                false
            },
            ScrollEventPhase::Move(_) => {
                // Switch layer if movement originated in a new gesture,
                // from a non root layer in overscroll.
                let current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
                current_layer.scrolling.should_handoff_scroll && non_root_overscroll
            },
            ScrollEventPhase::End => {
                // clean-up when gesture ends.
                let mut current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
                current_layer.scrolling.should_handoff_scroll = false;
                false
            },
        };

        let scroll_layer_info = if switch_layer {
            topmost_scroll_layer_id.info
        } else {
            scroll_layer_id.info
        };

        let scroll_root_id = match scroll_layer_info {
             ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
             _ => unreachable!("Tried to scroll a reference frame."),

        };

        let mut scrolled_a_layer = false;
        for (layer_id, layer) in self.layers.iter_mut() {
            if layer_id.pipeline_id != scroll_layer_id.pipeline_id {
                continue;
            }

            match layer_id.info {
                ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
                ScrollLayerInfo::ReferenceFrame(..) => continue,
                _ => {}
            }

            let scrolled_this_layer = layer.scroll(scroll_location, phase);
            scrolled_a_layer = scrolled_a_layer || scrolled_this_layer;
        }
        scrolled_a_layer
    }

    pub fn update_all_layer_transforms(&mut self) {
        if self.layers.is_empty() {
            return;
        }

        let root_reference_frame_id = self.root_reference_frame_id();
        let root_viewport = self.layers[&root_reference_frame_id].local_viewport_rect;
        self.update_layer_transform(root_reference_frame_id,
                                    &ScrollToWorldTransform::identity(),
                                    &as_scroll_parent_rect(&root_viewport));
    }

    fn update_layer_transform(&mut self,
                              layer_id: ScrollLayerId,
                              parent_world_transform: &ScrollToWorldTransform,
                              parent_viewport_rect: &ScrollLayerRect) {
        // TODO(gw): This is an ugly borrow check workaround to clone these.
        //           Restructure this to avoid the clones!
        let (layer_transform_for_children, viewport_rect, layer_children) = {
            match self.layers.get_mut(&layer_id) {
                Some(layer) => {
                    layer.update_transform(parent_world_transform, parent_viewport_rect);

                    (layer.world_content_transform.with_source::<ScrollLayerPixel>(),
                     as_scroll_parent_rect(&layer.combined_local_viewport_rect),
                     layer.children.clone())
                }
                None => return,
            }
        };

        for child_layer_id in layer_children {
            self.update_layer_transform(child_layer_id,
                                        &layer_transform_for_children,
                                        &viewport_rect);
        }
    }

    pub fn tick_scrolling_bounce_animations(&mut self) {
        for (_, layer) in &mut self.layers {
            layer.tick_scrolling_bounce_animation()
        }
    }

    pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
        // TODO(gw): These are all independent - can be run through thread pool if it shows up
        // in the profile!
        for (scroll_layer_id, layer) in &mut self.layers {
            let scrolling_state = match old_states.get(&scroll_layer_id) {
                Some(old_scrolling_state) => *old_scrolling_state,
                None => ScrollingState::new(),
            };

            layer.finalize(&scrolling_state);

            let scroll_root_id = match scroll_layer_id.info {
                ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
                _ => continue,
            };

            let pipeline_id = scroll_layer_id.pipeline_id;
            if let Some(pending_offset) =
                self.pending_scroll_offsets.remove(&(pipeline_id, scroll_root_id)) {
                layer.set_scroll_origin(&pending_offset);
            }
        }

    }

    pub fn add_reference_frame(&mut self,
                               rect: LayerRect,
                               transform: LayerToScrollTransform,
                               pipeline_id: PipelineId,
                               parent_id: ScrollLayerId) -> ScrollLayerId {
        let reference_frame_id = ScrollLayerId {
            pipeline_id: pipeline_id,
            info: ScrollLayerInfo::ReferenceFrame(self.current_reference_frame_id),
        };
        self.current_reference_frame_id += 1;

        let layer = Layer::new(&rect, rect.size, &transform, pipeline_id);
        self.add_layer(layer, reference_frame_id, parent_id);
        reference_frame_id
    }

    pub fn add_layer(&mut self, layer: Layer, id: ScrollLayerId, parent_id: ScrollLayerId) {
        debug_assert!(!self.layers.contains_key(&id));
        self.layers.insert(id, layer);

        debug_assert!(parent_id != id);
        self.layers.get_mut(&parent_id).unwrap().add_child(id);
    }

    pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
        self.pipelines_to_discard.insert(pipeline_id);

        match self.current_scroll_layer_id {
            Some(id) if id.pipeline_id == pipeline_id => self.current_scroll_layer_id = None,
            _ => {}
        }
    }
}

<|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![macro_escape]

extern crate libc;

#[macro_export]
macro_rules! show_error(
    ($($args:expr),+) => ({
        safe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME);
        safe_writeln!(&mut ::std::io::stderr(), $($args),+);
    })
)

#[macro_export]
macro_rules! show_warning(
    ($($args:expr),+) => ({
        safe_write!(&mut ::std::io::stderr(), "{}: warning: ", ::NAME);
        safe_writeln!(&mut ::std::io::stderr(), $($args),+);
    })
)

#[macro_export]
macro_rules! crash(
    ($exitcode:expr, $($args:expr),+) => ({
        safe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME);
        safe_writeln!(&mut ::std::io::stderr(), $($args),+);
        unsafe { self::libc::exit($exitcode as self::libc::c_int); }
    })
)

#[macro_export]
macro_rules! exit(
    ($exitcode:expr) => ({
        unsafe { self::libc::exit($exitcode); }
    })
)

#[macro_export]
macro_rules! crash_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!($exitcode, "{}", f.to_str())
        }
    )
)

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:expr),+) => (
        match write!($fd, $($args),+) {
            Ok(_) => {}
            Err(f) => { fail!(f.to_str()); }
        }
    )
)

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:expr),+) => (
        match writeln!($fd, $($args),+) {
            Ok(_) => {}
            Err(f) => { fail!(f.to_str()); }
        }
    )
)

#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!(1, "{}", f.to_str())
        }
    )
)
<commit_msg>common: make libc reference in util look for the libc in util<commit_after>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![macro_escape]

extern crate libc;

#[macro_export]
macro_rules! show_error(
    ($($args:expr),+) => ({
        safe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME);
        safe_writeln!(&mut ::std::io::stderr(), $($args),+);
    })
)

#[macro_export]
macro_rules! show_warning(
    ($($args:expr),+) => ({
        safe_write!(&mut ::std::io::stderr(), "{}: warning: ", ::NAME);
        safe_writeln!(&mut ::std::io::stderr(), $($args),+);
    })
)

#[macro_export]
macro_rules! crash(
    ($exitcode:expr, $($args:expr),+) => ({
        safe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME);
        safe_writeln!(&mut ::std::io::stderr(), $($args),+);
        unsafe { ::util::libc::exit($exitcode as ::util::libc::c_int); }
    })
)

#[macro_export]
macro_rules! exit(
    ($exitcode:expr) => ({
        unsafe { ::util::libc::exit($exitcode); }
    })
)

#[macro_export]
macro_rules! crash_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!($exitcode, "{}", f.to_str())
        }
    )
)

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:expr),+) => (
        match write!($fd, $($args),+) {
            Ok(_) => {}
            Err(f) => { fail!(f.to_str()); }
        }
    )
)

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:expr),+) => (
        match writeln!($fd, $($args),+) {
            Ok(_) => {}
            Err(f) => { fail!(f.to_str()); }
        }
    )
)

#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!(1, "{}", f.to_str())
        }
    )
)
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Input / output.

pub trait InputStream {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize>;

    fn read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let n = try!(self.try_read(buf, min_bytes));
        if n < min_bytes {
            Err(::std::io::Error::new(::std::io::ErrorKind::Other, "Premature EOF", None))
        } else {
            Ok(n)
        }
    }

    fn read_exact(&mut self, buf : &mut [u8]) -> ::std::io::Result<()> {
        let min_bytes = buf.len();
        try!(self.read(buf, min_bytes));
        Ok(())
    }
}

impl <'a, T : InputStream> InputStream for &'a mut T {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        (**self).try_read(buf, min_bytes)
    }
}

pub struct ReadInputStream<R> {
    reader : R,
}

impl <R : ::std::io::Read> ReadInputStream <R> {
    pub fn new(reader : R) -> ReadInputStream<R> {
        ReadInputStream { reader : reader }
    }
}

impl <R : ::std::io::Read> InputStream for ReadInputStream<R> {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let mut pos = 0;
        let buf_len = buf.len();
        while pos < min_bytes {
            let buf1 = &mut buf[pos .. buf_len];
            let n = try!(self.reader.read(buf1));
            pos += n;
        }
        return Ok(pos);
    }
}

pub trait BufferedInputStream : InputStream {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()>;
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)>;
}

pub struct BufferedInputStreamWrapper<R> {
    inner : R,
    buf : Vec<u8>,
    pos : usize,
    cap : usize
}

impl <R> BufferedInputStreamWrapper<R> {
    pub fn new(r : R) -> BufferedInputStreamWrapper<R> {
        let mut result = BufferedInputStreamWrapper {
            inner : r,
            buf : Vec::with_capacity(8192),
            pos : 0,
            cap : 0
        };
        unsafe {
            result.buf.set_len(8192)
        }
        return result;
    }
}

impl<R: InputStream> BufferedInputStream for BufferedInputStreamWrapper<R> {

   fn skip(&mut self, mut bytes : usize) -> ::std::io::Result<()> {
        let available = self.cap - self.pos;
        if bytes <= available {
            self.pos += bytes;
        } else {
            bytes -= available;
            if bytes <= self.buf.len() {
                //# Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), bytes));
                self.pos = bytes;
                self.cap = n;
            } else {
                //# Forward large skip to the underlying stream.
                panic!("TODO")
            }
        }
        Ok(())
    }

    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        if self.cap - self.pos == 0 {
            let n = try!(self.inner.try_read(self.buf.as_mut_slice(), 1));
            self.cap = n;
            self.pos = 0;
        }
        Ok((self.buf.get_unchecked(self.pos) as *const u8,
            self.buf.get_unchecked(self.cap) as *const u8))
    }
}

impl<R: InputStream> InputStream for BufferedInputStreamWrapper<R> {
    fn try_read(&mut self, mut dst: &mut [u8], mut min_bytes : usize) -> ::std::io::Result<usize> {
        if min_bytes <= self.cap - self.pos {
            // Serve from the current buffer.
            let n = ::std::cmp::min(self.cap - self.pos, dst.len());
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.pos + n]);
            self.pos += n;
            return Ok(n);
        } else {
            // Copy current available into destination.
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.cap]);
            let from_first_buffer = self.cap - self.pos;

            let dst = &mut dst[from_first_buffer ..];
            min_bytes -= from_first_buffer;

            if dst.len() <= self.buf.len() {
                // Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), min_bytes));
                let from_second_buffer = ::std::cmp::min(n, dst.len());
                ::std::slice::bytes::copy_memory(dst,
                                                 &self.buf[0 .. from_second_buffer]);
                self.cap = n;
                self.pos = from_second_buffer;
                return Ok(from_first_buffer + from_second_buffer);
            } else {
                // Forward large read to the underlying stream.
                self.pos = 0;
                self.cap = 0;
                return Ok(from_first_buffer + try!(self.inner.try_read(dst, min_bytes)));
            }
        }
    }
}

pub struct ArrayInputStream<'a> {
    array : &'a [u8]
}

impl <'a> ArrayInputStream<'a> {
    pub fn new<'b>(array : &'b [u8]) -> ArrayInputStream<'b> {
        ArrayInputStream { array : array }
    }
}

impl <'a> InputStream for ArrayInputStream<'a> {
    fn try_read(&mut self, dst: &mut [u8], _min_bytes : usize) -> ::std::io::Result<usize> {
        let n = ::std::cmp::min(dst.len(), self.array.len());
        ::std::slice::bytes::copy_memory(dst, &self.array[0 .. n]);
        self.array = &self.array[n ..];
        Ok(n)
    }
}

impl <'a> BufferedInputStream for ArrayInputStream<'a> {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()> {
        assert!(self.array.len() >= bytes,
                "ArrayInputStream ended prematurely.");
        self.array = &self.array[bytes ..];
        Ok(())
    }
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        let len = self.array.len();
        Ok((self.array.as_ptr() as *const u8,
           self.array.get_unchecked(len) as *const u8))
    }
}

pub trait OutputStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()>;
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl <'a, T : OutputStream> OutputStream for &'a mut T {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        (**self).write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        (**self).flush()
    }
}

pub struct WriteOutputStream<W> {
    writer : W,
}

impl <W : ::std::io::Write> WriteOutputStream <W> {
    pub fn new(writer : W) -> WriteOutputStream<W> {
        WriteOutputStream { writer : writer }
    }
}

impl <W : ::std::io::Write> OutputStream for WriteOutputStream<W> {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        self.writer.write_all(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.writer.flush()
    }
}

pub trait BufferedOutputStream : OutputStream {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8);
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()>;
}

pub struct BufferedOutputStreamWrapper<W> {
    inner: W,
    buf: Vec<u8>,
    pos: usize
}

impl <W> BufferedOutputStreamWrapper<W> {
    pub fn new<'b> (w : W) -> BufferedOutputStreamWrapper<W> {
        let mut result = BufferedOutputStreamWrapper {
            inner: w,
            buf : Vec::with_capacity(8192),
            pos : 0
        };
        unsafe {
            result.buf.set_len(8192);
        }
        return result;
    }
}

impl<W: OutputStream> BufferedOutputStream for BufferedOutputStreamWrapper<W> {
    #[inline]
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.buf.len();
        (self.buf.get_unchecked_mut(self.pos) as *mut u8,
         self.buf.get_unchecked_mut(len) as *mut u8)
    }

    #[inline]
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.buf.get_unchecked_mut(self.pos) as *mut u8;
        if easy_case {
            self.pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }

}

impl<W: OutputStream> OutputStream for BufferedOutputStreamWrapper<W> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        let available = self.buf.len() - self.pos;
        let mut size = buf.len();
        if size <= available {
            let dst = &mut self.buf.as_mut_slice()[self.pos ..];
            ::std::slice::bytes::copy_memory(dst, buf);
            self.pos += size;
        } else if size <= self.buf.len() {
            // Too much for this buffer, but not a full buffer's
            // worth, so we'll go ahead and copy.
            {
                let dst = &mut self.buf.as_mut_slice()[self.pos ..];
                ::std::slice::bytes::copy_memory(dst, &buf[0 .. available]);
            }
            try!(self.inner.write(self.buf.as_mut_slice()));

            size -= available;
            let src = &buf[available ..];
            let dst = &mut self.buf.as_mut_slice()[0 ..];
            ::std::slice::bytes::copy_memory(dst, src);
            self.pos = size;
        } else {
            // Writing so much data that we might as well write
            // directly to avoid a copy.
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
            try!(self.inner.write(buf));
        }
        return Ok(());
    }

    fn flush(&mut self) -> ::std::io::Result<()> {
        if self.pos > 0 {
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
        }
        self.inner.flush()
    }
}

pub struct ArrayOutputStream<'a> {
    array : &'a mut [u8],
    fill_pos : usize,
}

impl <'a> ArrayOutputStream<'a> {
    pub fn new<'b>(array : &'b mut [u8]) -> ArrayOutputStream<'b> {
        ArrayOutputStream {
            array : array,
            fill_pos : 0
        }
    }
}

impl <'a> OutputStream for ArrayOutputStream<'a> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        assert!(buf.len() <= self.array.len() - self.fill_pos,
                "ArrayOutputStream's backing array was not large enough for the data written.");
        ::std::slice::bytes::copy_memory(&mut self.array[self.fill_pos ..], buf);
        self.fill_pos += buf.len();
        Ok(())
    }
}

impl <'a> BufferedOutputStream for ArrayOutputStream<'a> {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.array.len();
        (self.array.get_unchecked_mut(self.fill_pos) as *mut u8,
         self.array.get_unchecked_mut(len) as *mut u8)
    }
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.array.get_unchecked_mut(self.fill_pos) as *mut u8;
        if easy_case {
            self.fill_pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }
}
<commit_msg>Fix bug in try_read for ReadInputStream.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Input / output.

pub trait InputStream {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize>;

    fn read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let n = try!(self.try_read(buf, min_bytes));
        if n < min_bytes {
            Err(::std::io::Error::new(::std::io::ErrorKind::Other, "Premature EOF", None))
        } else {
            Ok(n)
        }
    }

    fn read_exact(&mut self, buf : &mut [u8]) -> ::std::io::Result<()> {
        let min_bytes = buf.len();
        try!(self.read(buf, min_bytes));
        Ok(())
    }
}

impl <'a, T : InputStream> InputStream for &'a mut T {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        (**self).try_read(buf, min_bytes)
    }
}

pub struct ReadInputStream<R> {
    reader : R,
}

impl <R : ::std::io::Read> ReadInputStream <R> {
    pub fn new(reader : R) -> ReadInputStream<R> {
        ReadInputStream { reader : reader }
    }
}

impl <R : ::std::io::Read> InputStream for ReadInputStream<R> {
    fn try_read(&mut self, buf : &mut [u8], min_bytes : usize) -> ::std::io::Result<usize> {
        let mut pos = 0;
        let buf_len = buf.len();
        while pos < min_bytes {
            let buf1 = &mut buf[pos .. buf_len];
            let n = try!(self.reader.read(buf1));
            pos += n;
            if n == 0 { return Ok(pos); }
        }
        return Ok(pos);
    }
}

pub trait BufferedInputStream : InputStream {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()>;
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)>;
}

pub struct BufferedInputStreamWrapper<R> {
    inner : R,
    buf : Vec<u8>,
    pos : usize,
    cap : usize
}

impl <R> BufferedInputStreamWrapper<R> {
    pub fn new(r : R) -> BufferedInputStreamWrapper<R> {
        let mut result = BufferedInputStreamWrapper {
            inner : r,
            buf : Vec::with_capacity(8192),
            pos : 0,
            cap : 0
        };
        unsafe {
            result.buf.set_len(8192)
        }
        return result;
    }
}

impl<R: InputStream> BufferedInputStream for BufferedInputStreamWrapper<R> {

   fn skip(&mut self, mut bytes : usize) -> ::std::io::Result<()> {
        let available = self.cap - self.pos;
        if bytes <= available {
            self.pos += bytes;
        } else {
            bytes -= available;
            if bytes <= self.buf.len() {
                //# Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), bytes));
                self.pos = bytes;
                self.cap = n;
            } else {
                //# Forward large skip to the underlying stream.
                panic!("TODO")
            }
        }
        Ok(())
    }

    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        if self.cap - self.pos == 0 {
            let n = try!(self.inner.try_read(self.buf.as_mut_slice(), 1));
            self.cap = n;
            self.pos = 0;
        }
        Ok((self.buf.get_unchecked(self.pos) as *const u8,
            self.buf.get_unchecked(self.cap) as *const u8))
    }
}

impl<R: InputStream> InputStream for BufferedInputStreamWrapper<R> {
    fn try_read(&mut self, mut dst: &mut [u8], mut min_bytes : usize) -> ::std::io::Result<usize> {
        if min_bytes <= self.cap - self.pos {
            // Serve from the current buffer.
            let n = ::std::cmp::min(self.cap - self.pos, dst.len());
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.pos + n]);
            self.pos += n;
            return Ok(n);
        } else {
            // Copy current available into destination.
            ::std::slice::bytes::copy_memory(dst,
                                             &self.buf[self.pos .. self.cap]);
            let from_first_buffer = self.cap - self.pos;

            let dst = &mut dst[from_first_buffer ..];
            min_bytes -= from_first_buffer;

            if dst.len() <= self.buf.len() {
                // Read the next buffer-full.
                let n = try!(self.inner.try_read(self.buf.as_mut_slice(), min_bytes));
                let from_second_buffer = ::std::cmp::min(n, dst.len());
                ::std::slice::bytes::copy_memory(dst,
                                                 &self.buf[0 .. from_second_buffer]);
                self.cap = n;
                self.pos = from_second_buffer;
                return Ok(from_first_buffer + from_second_buffer);
            } else {
                // Forward large read to the underlying stream.
                self.pos = 0;
                self.cap = 0;
                return Ok(from_first_buffer + try!(self.inner.try_read(dst, min_bytes)));
            }
        }
    }
}

pub struct ArrayInputStream<'a> {
    array : &'a [u8]
}

impl <'a> ArrayInputStream<'a> {
    pub fn new<'b>(array : &'b [u8]) -> ArrayInputStream<'b> {
        ArrayInputStream { array : array }
    }
}

impl <'a> InputStream for ArrayInputStream<'a> {
    fn try_read(&mut self, dst: &mut [u8], _min_bytes : usize) -> ::std::io::Result<usize> {
        let n = ::std::cmp::min(dst.len(), self.array.len());
        ::std::slice::bytes::copy_memory(dst, &self.array[0 .. n]);
        self.array = &self.array[n ..];
        Ok(n)
    }
}

impl <'a> BufferedInputStream for ArrayInputStream<'a> {
    fn skip(&mut self, bytes : usize) -> ::std::io::Result<()> {
        assert!(self.array.len() >= bytes,
                "ArrayInputStream ended prematurely.");
        self.array = &self.array[bytes ..];
        Ok(())
    }
    unsafe fn get_read_buffer(&mut self) -> ::std::io::Result<(*const u8, *const u8)> {
        let len = self.array.len();
        Ok((self.array.as_ptr() as *const u8,
           self.array.get_unchecked(len) as *const u8))
    }
}

pub trait OutputStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()>;
    fn flush(&mut self) -> ::std::io::Result<()> { Ok(()) }
}

impl <'a, T : OutputStream> OutputStream for &'a mut T {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        (**self).write(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        (**self).flush()
    }
}

pub struct WriteOutputStream<W> {
    writer : W,
}

impl <W : ::std::io::Write> WriteOutputStream <W> {
    pub fn new(writer : W) -> WriteOutputStream<W> {
        WriteOutputStream { writer : writer }
    }
}

impl <W : ::std::io::Write> OutputStream for WriteOutputStream<W> {
    fn write(&mut self, buf : &[u8]) -> ::std::io::Result<()> {
        self.writer.write_all(buf)
    }
    fn flush(&mut self) -> ::std::io::Result<()> {
        self.writer.flush()
    }
}

pub trait BufferedOutputStream : OutputStream {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8);
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()>;
}

pub struct BufferedOutputStreamWrapper<W> {
    inner: W,
    buf: Vec<u8>,
    pos: usize
}

impl <W> BufferedOutputStreamWrapper<W> {
    pub fn new<'b> (w : W) -> BufferedOutputStreamWrapper<W> {
        let mut result = BufferedOutputStreamWrapper {
            inner: w,
            buf : Vec::with_capacity(8192),
            pos : 0
        };
        unsafe {
            result.buf.set_len(8192);
        }
        return result;
    }
}

impl<W: OutputStream> BufferedOutputStream for BufferedOutputStreamWrapper<W> {
    #[inline]
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.buf.len();
        (self.buf.get_unchecked_mut(self.pos) as *mut u8,
         self.buf.get_unchecked_mut(len) as *mut u8)
    }

    #[inline]
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.buf.get_unchecked_mut(self.pos) as *mut u8;
        if easy_case {
            self.pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }

}

impl<W: OutputStream> OutputStream for BufferedOutputStreamWrapper<W> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        let available = self.buf.len() - self.pos;
        let mut size = buf.len();
        if size <= available {
            let dst = &mut self.buf.as_mut_slice()[self.pos ..];
            ::std::slice::bytes::copy_memory(dst, buf);
            self.pos += size;
        } else if size <= self.buf.len() {
            // Too much for this buffer, but not a full buffer's
            // worth, so we'll go ahead and copy.
            {
                let dst = &mut self.buf.as_mut_slice()[self.pos ..];
                ::std::slice::bytes::copy_memory(dst, &buf[0 .. available]);
            }
            try!(self.inner.write(self.buf.as_mut_slice()));

            size -= available;
            let src = &buf[available ..];
            let dst = &mut self.buf.as_mut_slice()[0 ..];
            ::std::slice::bytes::copy_memory(dst, src);
            self.pos = size;
        } else {
            // Writing so much data that we might as well write
            // directly to avoid a copy.
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
            try!(self.inner.write(buf));
        }
        return Ok(());
    }

    fn flush(&mut self) -> ::std::io::Result<()> {
        if self.pos > 0 {
            try!(self.inner.write(&self.buf[0 .. self.pos]));
            self.pos = 0;
        }
        self.inner.flush()
    }
}

pub struct ArrayOutputStream<'a> {
    array : &'a mut [u8],
    fill_pos : usize,
}

impl <'a> ArrayOutputStream<'a> {
    pub fn new<'b>(array : &'b mut [u8]) -> ArrayOutputStream<'b> {
        ArrayOutputStream {
            array : array,
            fill_pos : 0
        }
    }
}

impl <'a> OutputStream for ArrayOutputStream<'a> {
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<()> {
        assert!(buf.len() <= self.array.len() - self.fill_pos,
                "ArrayOutputStream's backing array was not large enough for the data written.");
        ::std::slice::bytes::copy_memory(&mut self.array[self.fill_pos ..], buf);
        self.fill_pos += buf.len();
        Ok(())
    }
}

impl <'a> BufferedOutputStream for ArrayOutputStream<'a> {
    unsafe fn get_write_buffer(&mut self) -> (*mut u8, *mut u8) {
        let len = self.array.len();
        (self.array.get_unchecked_mut(self.fill_pos) as *mut u8,
         self.array.get_unchecked_mut(len) as *mut u8)
    }
    unsafe fn write_ptr(&mut self, ptr: *mut u8, size: usize) -> ::std::io::Result<()> {
        let easy_case = ptr == self.array.get_unchecked_mut(self.fill_pos) as *mut u8;
        if easy_case {
            self.fill_pos += size;
            Ok(())
        } else {
            let buf = ::std::slice::from_raw_parts_mut::<u8>(ptr, size);
            self.write(buf)
        }
    }
}
<|endoftext|>


<commit_before>//! Asynchronous I/O.
//!
//! This module is the asynchronous version of `std::io`. Primarily, it
//! defines two traits, [`AsyncRead`] and [`AsyncWrite`], which extend the
//! `Read` and `Write` traits of the standard library.
//!
//! # AsyncRead and AsyncWrite
//!
//! [`AsyncRead`] and [`AsyncWrite`] must only be implemented for
//! non-blocking I/O types that integrate with the futures type system. In
//! other words, these types must never block the thread, and instead the
//! current task is notified when the I/O resource is ready.
//!
//! # Standard input and output
//!
//! Tokio provides asynchronous APIs to standard [input], [output], and [error].
//! These APIs are very similar to the ones provided by `std`, but they also
//! implement [`AsyncRead`] and [`AsyncWrite`].
//!
//! Unlike *most* other Tokio APIs, the standard input / output APIs
//! **must** be used from the context of the Tokio runtime as they require
//! Tokio specific features to function.
//!
//! [input]: fn.stdin.html
//! [output]: fn.stdout.html
//! [error]: fn.stderr.html
//!
//! # Utility functions
//!
//! Utilities functions are provided for working with [`AsyncRead`] /
//! [`AsyncWrite`] types. For example, [`copy`] asynchronously copies all
//! data from a source to a destination.
//!
//! # `std` re-exports
//!
//! Additionally, [`Read`], [`Write`], [`Error`], [`ErrorKind`], and
//! [`Result`] are re-exported from `std::io` for ease of use.
//!
//! [`AsyncRead`]: trait.AsyncRead.html
//! [`AsyncWrite`]: trait.AsyncWrite.html
//! [`copy`]: fn.copy.html
//! [`Read`]: trait.Read.html
//! [`Write`]: trait.Write.html
//! [`Error`]: struct.Error.html
//! [`ErrorKind`]: enum.ErrorKind.html
//! [`Result`]: type.Result.html

pub use tokio_io::{
    AsyncRead,
    AsyncWrite,
};

// standard input, output, and error
pub use tokio_fs::{
    stdin,
    Stdin,
    stdout,
    Stdout,
    stderr,
    Stderr,
};

// Utils
pub use tokio_io::io::{
    copy,
    Copy,
    flush,
    Flush,
    lines,
    Lines,
    read_exact,
    ReadExact,
    read_to_end,
    ReadToEnd,
    read_until,
    ReadUntil,
    ReadHalf,
    shutdown,
    Shutdown,
    write_all,
    WriteAll,
    WriteHalf,
};

// Re-export io::Error so that users don't have to deal
// with conflicts when `use`ing `futures::io` and `std::io`.
pub use ::std::io::{
    Error,
    ErrorKind,
    Result,
    Read,
    Write,
};
<commit_msg>re-export tokio_io::read in tokio::io (#689)<commit_after>//! Asynchronous I/O.
//!
//! This module is the asynchronous version of `std::io`. Primarily, it
//! defines two traits, [`AsyncRead`] and [`AsyncWrite`], which extend the
//! `Read` and `Write` traits of the standard library.
//!
//! # AsyncRead and AsyncWrite
//!
//! [`AsyncRead`] and [`AsyncWrite`] must only be implemented for
//! non-blocking I/O types that integrate with the futures type system. In
//! other words, these types must never block the thread, and instead the
//! current task is notified when the I/O resource is ready.
//!
//! # Standard input and output
//!
//! Tokio provides asynchronous APIs to standard [input], [output], and [error].
//! These APIs are very similar to the ones provided by `std`, but they also
//! implement [`AsyncRead`] and [`AsyncWrite`].
//!
//! Unlike *most* other Tokio APIs, the standard input / output APIs
//! **must** be used from the context of the Tokio runtime as they require
//! Tokio specific features to function.
//!
//! [input]: fn.stdin.html
//! [output]: fn.stdout.html
//! [error]: fn.stderr.html
//!
//! # Utility functions
//!
//! Utilities functions are provided for working with [`AsyncRead`] /
//! [`AsyncWrite`] types. For example, [`copy`] asynchronously copies all
//! data from a source to a destination.
//!
//! # `std` re-exports
//!
//! Additionally, [`Read`], [`Write`], [`Error`], [`ErrorKind`], and
//! [`Result`] are re-exported from `std::io` for ease of use.
//!
//! [`AsyncRead`]: trait.AsyncRead.html
//! [`AsyncWrite`]: trait.AsyncWrite.html
//! [`copy`]: fn.copy.html
//! [`Read`]: trait.Read.html
//! [`Write`]: trait.Write.html
//! [`Error`]: struct.Error.html
//! [`ErrorKind`]: enum.ErrorKind.html
//! [`Result`]: type.Result.html

pub use tokio_io::{
    AsyncRead,
    AsyncWrite,
};

// standard input, output, and error
pub use tokio_fs::{
    stdin,
    Stdin,
    stdout,
    Stdout,
    stderr,
    Stderr,
};

// Utils
pub use tokio_io::io::{
    copy,
    Copy,
    flush,
    Flush,
    lines,
    Lines,
    read,
    read_exact,
    ReadExact,
    read_to_end,
    ReadToEnd,
    read_until,
    ReadUntil,
    ReadHalf,
    shutdown,
    Shutdown,
    write_all,
    WriteAll,
    WriteHalf,
};

// Re-export io::Error so that users don't have to deal
// with conflicts when `use`ing `futures::io` and `std::io`.
pub use ::std::io::{
    Error,
    ErrorKind,
    Result,
    Read,
    Write,
};
<|endoftext|>


<commit_before>//! EVM Program Counter.

use bigint::M256;
use util::opcode::Opcode;
use std::cmp::min;
use std::marker::PhantomData;
use super::Patch;
use super::errors::{OnChainError, NotSupportedError, RuntimeError};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(missing_docs)]
/// Instructions for the program counter. This is the same as `Opcode`
/// except `PUSH`, which might take longer length.
pub enum Instruction {
    STOP, ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP,
    SIGNEXTEND, LT, GT, SLT, SGT, EQ, ISZERO, AND, OR, XOR, NOT, BYTE,
    SHA3, ADDRESS, BALANCE, ORIGIN, CALLER, CALLVALUE, CALLDATALOAD,
    CALLDATASIZE, CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE,
    EXTCODESIZE, EXTCODECOPY, BLOCKHASH, COINBASE, TIMESTAMP, NUMBER,
    DIFFICULTY, GASLIMIT, POP, MLOAD, MSTORE, MSTORE8, SLOAD, SSTORE,
    JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, CREATE, CALL, CALLCODE,
    RETURN, DELEGATECALL, SUICIDE,

    PUSH(M256),
    DUP(usize),
    SWAP(usize),
    LOG(usize),
}

/// Represents a program counter in EVM.
pub struct PC<P: Patch> {
    position: usize,
    code: Vec<u8>,
    valids: Vec<bool>,
    _patch: PhantomData<P>,
}

impl<P: Patch> PC<P> {
    /// Create a new program counter from the given code.
    pub fn new(code: &[u8]) -> Self {
        let code: Vec<u8> = code.into();
        let mut valids: Vec<bool> = Vec::with_capacity(code.len());
        valids.resize(code.len(), false);

        let mut i = 0;
        while i < code.len() {
            let opcode: Opcode = code[i].into();
            match opcode {
                Opcode::JUMPDEST => {
                    valids[i] = true;
                    i = i + 1;
                },
                Opcode::PUSH(v) => {
                    i = i + v + 1;
                },
                _ => {
                    i = i + 1;
                }
            }
        }

        PC {
            code,
            position: 0,
            valids: valids,
            _patch: PhantomData,
        }
    }

    fn read_bytes(&self, from_position: usize, byte_count: usize) -> Result<M256, RuntimeError> {
        if from_position > self.code.len() {
            return Err(RuntimeError::OnChain(OnChainError::PCOverflow));
        }
        let position = from_position;
        if position.checked_add(byte_count).is_none() {
            return Err(RuntimeError::NotSupported(NotSupportedError::PCIndexNotSupported));
        }
        let max = min(position + byte_count, self.code.len());
        Ok(M256::from(&self.code[position..max]))
    }

    /// Get the code bytearray.
    pub fn code(&self) -> &[u8] {
        &self.code
    }

    /// Jump to a position in the code. The destination must be valid
    /// to jump.
    pub fn jump(&mut self, position: usize) -> Result<(), OnChainError> {
        if position >= self.code.len() {
            return Err(OnChainError::PCOverflow);
        }

        if !self.valids[position] {
            return Err(OnChainError::BadJumpDest);
        }

        self.position = position;
        Ok(())
    }

    /// Get the current program counter position.
    pub fn position(&self) -> usize {
        self.position
    }

    /// Returns `true` if the position is a valid jump destination. If
    /// not, returns `false`.
    pub fn is_valid(&self, position: usize) -> bool {
        if position >= self.code.len() {
            return false;
        }

        if !self.valids[position] {
            return false;
        }

        return true;
    }

    /// Check whether the PC is ended. Next `read` on this PC would
    /// result in `PCError::PCOverflow`.
    pub fn is_end(&self) -> bool {
        self.position == self.code.len()
    }

    /// Peek the next instruction.
    pub fn peek(&self) -> Result<Instruction, RuntimeError> {
        let position = self.position;
        if position >= self.code.len() {
            return Err(OnChainError::PCOverflow.into());
        }
        let opcode: Opcode = self.code[position].into();
        Ok(match opcode {
            Opcode::STOP => Instruction::STOP,
            Opcode::ADD => Instruction::ADD,
            Opcode::MUL => Instruction::MUL,
            Opcode::SUB => Instruction::SUB,
            Opcode::DIV => Instruction::DIV,
            Opcode::SDIV => Instruction::SDIV,
            Opcode::MOD => Instruction::MOD,
            Opcode::SMOD => Instruction::SMOD,
            Opcode::ADDMOD => Instruction::ADDMOD,
            Opcode::MULMOD => Instruction::MULMOD,
            Opcode::EXP => Instruction::EXP,
            Opcode::SIGNEXTEND => Instruction::SIGNEXTEND,

            Opcode::LT => Instruction::LT,
            Opcode::GT => Instruction::GT,
            Opcode::SLT => Instruction::SLT,
            Opcode::SGT => Instruction::SGT,
            Opcode::EQ => Instruction::EQ,
            Opcode::ISZERO => Instruction::ISZERO,
            Opcode::AND => Instruction::AND,
            Opcode::OR => Instruction::OR,
            Opcode::XOR => Instruction::XOR,
            Opcode::NOT => Instruction::NOT,
            Opcode::BYTE => Instruction::BYTE,

            Opcode::SHA3 => Instruction::SHA3,

            Opcode::ADDRESS => Instruction::ADDRESS,
            Opcode::BALANCE => Instruction::BALANCE,
            Opcode::ORIGIN => Instruction::ORIGIN,
            Opcode::CALLER => Instruction::CALLER,
            Opcode::CALLVALUE => Instruction::CALLVALUE,
            Opcode::CALLDATALOAD => Instruction::CALLDATALOAD,
            Opcode::CALLDATASIZE => Instruction::CALLDATASIZE,
            Opcode::CALLDATACOPY => Instruction::CALLDATACOPY,
            Opcode::CODESIZE => Instruction::CODESIZE,
            Opcode::CODECOPY => Instruction::CODECOPY,
            Opcode::GASPRICE => Instruction::GASPRICE,
            Opcode::EXTCODESIZE => Instruction::EXTCODESIZE,
            Opcode::EXTCODECOPY => Instruction::EXTCODECOPY,

            Opcode::BLOCKHASH => Instruction::BLOCKHASH,
            Opcode::COINBASE => Instruction::COINBASE,
            Opcode::TIMESTAMP => Instruction::TIMESTAMP,
            Opcode::NUMBER => Instruction::NUMBER,
            Opcode::DIFFICULTY => Instruction::DIFFICULTY,
            Opcode::GASLIMIT => Instruction::GASLIMIT,

            Opcode::POP => Instruction::POP,
            Opcode::MLOAD => Instruction::MLOAD,
            Opcode::MSTORE => Instruction::MSTORE,
            Opcode::MSTORE8 => Instruction::MSTORE8,
            Opcode::SLOAD => Instruction::SLOAD,
            Opcode::SSTORE => Instruction::SSTORE,
            Opcode::JUMP => Instruction::JUMP,
            Opcode::JUMPI => Instruction::JUMPI,
            Opcode::PC => Instruction::PC,
            Opcode::MSIZE => Instruction::MSIZE,
            Opcode::GAS => Instruction::GAS,
            Opcode::JUMPDEST => Instruction::JUMPDEST,

            Opcode::PUSH(v) => {
                let param = self.read_bytes(position + 1, v)?;
                Instruction::PUSH(param)
            },

            Opcode::DUP(v) => Instruction::DUP(v),
            Opcode::SWAP(v) => Instruction::SWAP(v),
            Opcode::LOG(v) => Instruction::LOG(v),

            Opcode::CREATE => Instruction::CREATE,
            Opcode::CALL => Instruction::CALL,
            Opcode::CALLCODE => Instruction::CALLCODE,
            Opcode::RETURN => Instruction::RETURN,
            Opcode::DELEGATECALL => {
                if P::has_delegate_call() {
                    Instruction::DELEGATECALL
                } else {
                    return Err(OnChainError::InvalidOpcode.into());
                }
            },

            Opcode::INVALID => {
                return Err(OnChainError::InvalidOpcode.into());
            },
            Opcode::SUICIDE => Instruction::SUICIDE,
        })
    }

    /// Read the next instruction and step the program counter.
    pub fn read(&mut self) -> Result<Instruction, RuntimeError> {
        let result = self.peek()?;
        let opcode: Opcode = self.code[self.position].into();
        match opcode {
            Opcode::PUSH(v) => {
                self.position = min(self.position + v + 1, self.code.len());
            },
            _ => {
                self.position = self.position + 1;
            },
        }
        Ok(result)
    }
}
<commit_msg>PC::read_bytes should never return not supported error<commit_after>//! EVM Program Counter.

use bigint::M256;
use util::opcode::Opcode;
use std::cmp::min;
use std::marker::PhantomData;
use super::Patch;
use super::errors::{OnChainError, RuntimeError};

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(missing_docs)]
/// Instructions for the program counter. This is the same as `Opcode`
/// except `PUSH`, which might take longer length.
pub enum Instruction {
    STOP, ADD, MUL, SUB, DIV, SDIV, MOD, SMOD, ADDMOD, MULMOD, EXP,
    SIGNEXTEND, LT, GT, SLT, SGT, EQ, ISZERO, AND, OR, XOR, NOT, BYTE,
    SHA3, ADDRESS, BALANCE, ORIGIN, CALLER, CALLVALUE, CALLDATALOAD,
    CALLDATASIZE, CALLDATACOPY, CODESIZE, CODECOPY, GASPRICE,
    EXTCODESIZE, EXTCODECOPY, BLOCKHASH, COINBASE, TIMESTAMP, NUMBER,
    DIFFICULTY, GASLIMIT, POP, MLOAD, MSTORE, MSTORE8, SLOAD, SSTORE,
    JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, CREATE, CALL, CALLCODE,
    RETURN, DELEGATECALL, SUICIDE,

    PUSH(M256),
    DUP(usize),
    SWAP(usize),
    LOG(usize),
}

/// Represents a program counter in EVM.
pub struct PC<P: Patch> {
    position: usize,
    code: Vec<u8>,
    valids: Vec<bool>,
    _patch: PhantomData<P>,
}

impl<P: Patch> PC<P> {
    /// Create a new program counter from the given code.
    pub fn new(code: &[u8]) -> Self {
        let code: Vec<u8> = code.into();
        let mut valids: Vec<bool> = Vec::with_capacity(code.len());
        valids.resize(code.len(), false);

        let mut i = 0;
        while i < code.len() {
            let opcode: Opcode = code[i].into();
            match opcode {
                Opcode::JUMPDEST => {
                    valids[i] = true;
                    i = i + 1;
                },
                Opcode::PUSH(v) => {
                    i = i + v + 1;
                },
                _ => {
                    i = i + 1;
                }
            }
        }

        PC {
            code,
            position: 0,
            valids: valids,
            _patch: PhantomData,
        }
    }

    fn read_bytes(&self, from_position: usize, byte_count: usize) -> Result<M256, RuntimeError> {
        if from_position > self.code.len() {
            return Err(RuntimeError::OnChain(OnChainError::PCOverflow));
        }
        let position = from_position;
        let max = min(position.saturating_add(byte_count), self.code.len());
        Ok(M256::from(&self.code[position..max]))
    }

    /// Get the code bytearray.
    pub fn code(&self) -> &[u8] {
        &self.code
    }

    /// Jump to a position in the code. The destination must be valid
    /// to jump.
    pub fn jump(&mut self, position: usize) -> Result<(), OnChainError> {
        if position >= self.code.len() {
            return Err(OnChainError::PCOverflow);
        }

        if !self.valids[position] {
            return Err(OnChainError::BadJumpDest);
        }

        self.position = position;
        Ok(())
    }

    /// Get the current program counter position.
    pub fn position(&self) -> usize {
        self.position
    }

    /// Returns `true` if the position is a valid jump destination. If
    /// not, returns `false`.
    pub fn is_valid(&self, position: usize) -> bool {
        if position >= self.code.len() {
            return false;
        }

        if !self.valids[position] {
            return false;
        }

        return true;
    }

    /// Check whether the PC is ended. Next `read` on this PC would
    /// result in `PCError::PCOverflow`.
    pub fn is_end(&self) -> bool {
        self.position == self.code.len()
    }

    /// Peek the next instruction.
    pub fn peek(&self) -> Result<Instruction, RuntimeError> {
        let position = self.position;
        if position >= self.code.len() {
            return Err(OnChainError::PCOverflow.into());
        }
        let opcode: Opcode = self.code[position].into();
        Ok(match opcode {
            Opcode::STOP => Instruction::STOP,
            Opcode::ADD => Instruction::ADD,
            Opcode::MUL => Instruction::MUL,
            Opcode::SUB => Instruction::SUB,
            Opcode::DIV => Instruction::DIV,
            Opcode::SDIV => Instruction::SDIV,
            Opcode::MOD => Instruction::MOD,
            Opcode::SMOD => Instruction::SMOD,
            Opcode::ADDMOD => Instruction::ADDMOD,
            Opcode::MULMOD => Instruction::MULMOD,
            Opcode::EXP => Instruction::EXP,
            Opcode::SIGNEXTEND => Instruction::SIGNEXTEND,

            Opcode::LT => Instruction::LT,
            Opcode::GT => Instruction::GT,
            Opcode::SLT => Instruction::SLT,
            Opcode::SGT => Instruction::SGT,
            Opcode::EQ => Instruction::EQ,
            Opcode::ISZERO => Instruction::ISZERO,
            Opcode::AND => Instruction::AND,
            Opcode::OR => Instruction::OR,
            Opcode::XOR => Instruction::XOR,
            Opcode::NOT => Instruction::NOT,
            Opcode::BYTE => Instruction::BYTE,

            Opcode::SHA3 => Instruction::SHA3,

            Opcode::ADDRESS => Instruction::ADDRESS,
            Opcode::BALANCE => Instruction::BALANCE,
            Opcode::ORIGIN => Instruction::ORIGIN,
            Opcode::CALLER => Instruction::CALLER,
            Opcode::CALLVALUE => Instruction::CALLVALUE,
            Opcode::CALLDATALOAD => Instruction::CALLDATALOAD,
            Opcode::CALLDATASIZE => Instruction::CALLDATASIZE,
            Opcode::CALLDATACOPY => Instruction::CALLDATACOPY,
            Opcode::CODESIZE => Instruction::CODESIZE,
            Opcode::CODECOPY => Instruction::CODECOPY,
            Opcode::GASPRICE => Instruction::GASPRICE,
            Opcode::EXTCODESIZE => Instruction::EXTCODESIZE,
            Opcode::EXTCODECOPY => Instruction::EXTCODECOPY,

            Opcode::BLOCKHASH => Instruction::BLOCKHASH,
            Opcode::COINBASE => Instruction::COINBASE,
            Opcode::TIMESTAMP => Instruction::TIMESTAMP,
            Opcode::NUMBER => Instruction::NUMBER,
            Opcode::DIFFICULTY => Instruction::DIFFICULTY,
            Opcode::GASLIMIT => Instruction::GASLIMIT,

            Opcode::POP => Instruction::POP,
            Opcode::MLOAD => Instruction::MLOAD,
            Opcode::MSTORE => Instruction::MSTORE,
            Opcode::MSTORE8 => Instruction::MSTORE8,
            Opcode::SLOAD => Instruction::SLOAD,
            Opcode::SSTORE => Instruction::SSTORE,
            Opcode::JUMP => Instruction::JUMP,
            Opcode::JUMPI => Instruction::JUMPI,
            Opcode::PC => Instruction::PC,
            Opcode::MSIZE => Instruction::MSIZE,
            Opcode::GAS => Instruction::GAS,
            Opcode::JUMPDEST => Instruction::JUMPDEST,

            Opcode::PUSH(v) => {
                let param = self.read_bytes(position + 1, v)?;
                Instruction::PUSH(param)
            },

            Opcode::DUP(v) => Instruction::DUP(v),
            Opcode::SWAP(v) => Instruction::SWAP(v),
            Opcode::LOG(v) => Instruction::LOG(v),

            Opcode::CREATE => Instruction::CREATE,
            Opcode::CALL => Instruction::CALL,
            Opcode::CALLCODE => Instruction::CALLCODE,
            Opcode::RETURN => Instruction::RETURN,
            Opcode::DELEGATECALL => {
                if P::has_delegate_call() {
                    Instruction::DELEGATECALL
                } else {
                    return Err(OnChainError::InvalidOpcode.into());
                }
            },

            Opcode::INVALID => {
                return Err(OnChainError::InvalidOpcode.into());
            },
            Opcode::SUICIDE => Instruction::SUICIDE,
        })
    }

    /// Read the next instruction and step the program counter.
    pub fn read(&mut self) -> Result<Instruction, RuntimeError> {
        let result = self.peek()?;
        let opcode: Opcode = self.code[self.position].into();
        match opcode {
            Opcode::PUSH(v) => {
                self.position = min(self.position + v + 1, self.code.len());
            },
            _ => {
                self.position = self.position + 1;
            },
        }
        Ok(result)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: u32 = 0x20000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn map_peripheral( & mut self) {
        self.mem_fd = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(self.mem_fd.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        self.map = mmap;
        self.addr = self.map.data() as *mut u32;
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= 7 << (((y) % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u32) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<commit_msg>add constructor for Bcm2835Peripheral<commit_after>#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: u32 = 0x20000000;
pub const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4 * 1024);

pub struct Bcm2835Peripheral {
    pub addr_p: *const u8,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut u32
}

impl Bcm2835Peripheral {
    pub fn new() -> Bcm2835Peripheral {
        let mem_file= OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = & [
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            // MapOption::MapAddr(self.addr_p),
            MapOption::MapFd(mem_file.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };
        Bcm2835Peripheral {
            addr_p: &GPIO_BASE,
            mem_fd: mem_file,
            addr: mmap.data() as *mut u32,  //switch order to avoid error of moved value `mmap`
            map: mmap,
        }
    }

    pub fn unmap_peripheral(self) {
        drop(self);
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= 7 << (((y) % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: u32) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: u32) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<|endoftext|>