<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 util::geometry::Au;
use util::logical_geometry::WritingMode;
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use util::persistent_list::PersistentList;
use std::cmp::{max, min};
use std::i32;
use std::fmt;
use style::computed_values::float;

/// The kind of float: left or right.
#[derive(Clone, RustcEncodable, Debug, Copy)]
pub enum FloatKind {
    Left,
    Right
}

impl FloatKind {
    pub fn from_property(property: float::T) -> FloatKind {
        match property {
            float::T::none => panic!("can't create a float type from an unfloated property"),
            float::T::left => FloatKind::Left,
            float::T::right => FloatKind::Right,
        }
    }
}

/// The kind of clearance: left, right, or both.
#[derive(Copy)]
pub enum ClearType {
    Left,
    Right,
    Both,
}

/// Information about a single float.
#[derive(Clone, Copy)]
struct Float {
    /// The boundaries of this float.
    bounds: LogicalRect<Au>,
    /// The kind of float: left or right.
    kind: FloatKind,
}

impl fmt::Debug for Float {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "bounds={:?} kind={:?}", self.bounds, self.kind)
    }
}

/// Information about the floats next to a flow.
#[derive(Clone)]
struct FloatList {
    /// Information about each of the floats here.
    floats: PersistentList<Float>,
    /// Cached copy of the maximum block-start offset of the float.
    max_block_start: Au,
}

impl FloatList {
    fn new() -> FloatList {
        FloatList {
            floats: PersistentList::new(),
            max_block_start: Au(0),
        }
    }

    /// Returns true if the list is allocated and false otherwise. If false, there are guaranteed
    /// not to be any floats.
    fn is_present(&self) -> bool {
        self.floats.len() > 0
    }
}

impl fmt::Debug for FloatList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "max_block_start={:?} floats={}", self.max_block_start, self.floats.len())
    }
}

/// All the information necessary to place a float.
pub struct PlacementInfo {
    /// The dimensions of the float.
    pub size: LogicalSize<Au>,
    /// The minimum block-start of the float, as determined by earlier elements.
    pub ceiling: Au,
    /// The maximum inline-end position of the float, generally determined by the containing block.
    pub max_inline_size: Au,
    /// The kind of float.
    pub kind: FloatKind
}

impl fmt::Debug for PlacementInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "size={:?} ceiling={:?} max_inline_size={:?} kind={:?}",
               self.size,
               self.ceiling,
               self.max_inline_size,
               self.kind)
    }
}

fn range_intersect(block_start_1: Au, block_end_1: Au, block_start_2: Au, block_end_2: Au) -> (Au, Au) {
    (max(block_start_1, block_start_2), min(block_end_1, block_end_2))
}

/// Encapsulates information about floats. This is optimized to avoid allocation if there are
/// no floats, and to avoid copying when translating the list of floats downward.
#[derive(Clone)]
pub struct Floats {
    /// The list of floats.
    list: FloatList,
    /// The offset of the flow relative to the first float.
    offset: LogicalSize<Au>,
    /// The writing mode of these floats.
    pub writing_mode: WritingMode,
}

impl fmt::Debug for Floats {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if !self.list.is_present() {
            write!(f, "[empty]")
        } else {
            write!(f, "offset={:?} floats={:?}", self.offset, self.list)
        }
    }
}

impl Floats {
    /// Creates a new `Floats` object.
    pub fn new(writing_mode: WritingMode) -> Floats {
        Floats {
            list: FloatList::new(),
            offset: LogicalSize::zero(writing_mode),
            writing_mode: writing_mode,
        }
    }

    /// Adjusts the recorded offset of the flow relative to the first float.
    pub fn translate(&mut self, delta: LogicalSize<Au>) {
        self.offset = self.offset + delta
    }

    /// Returns the position of the last float in flow coordinates.
    pub fn last_float_pos(&self) -> Option<LogicalPoint<Au>> {
        match self.list.floats.front() {
            None => None,
            Some(float) => Some(float.bounds.start + self.offset),
        }
    }

    pub fn len(&self) -> uint {
        self.list.floats.len()
    }

    /// Returns a rectangle that encloses the region from block-start to block-start + block-size,
    /// with inline-size small enough that it doesn't collide with any floats. max_x is the
    /// inline-size beyond which floats have no effect. (Generally this is the containing block
    /// inline-size.)
    pub fn available_rect(&self, block_start: Au, block_size: Au, max_x: Au)
                          -> Option<LogicalRect<Au>> {
        let list = &self.list;
        let block_start = block_start - self.offset.block;

        debug!("available_rect: trying to find space at {:?}", block_start);

        // Relevant dimensions for the inline-end-most inline-start float
        let mut max_inline_start = Au(0) - self.offset.inline;
        let mut l_block_start = None;
        let mut l_block_end = None;
        // Relevant dimensions for the inline-start-most inline-end float
        let mut min_inline_end = max_x - self.offset.inline;
        let mut r_block_start = None;
        let mut r_block_end = None;

        // Find the float collisions for the given range in the block direction.
        for float in list.floats.iter() {
            debug!("available_rect: Checking for collision against float");
            let float_pos = float.bounds.start;
            let float_size = float.bounds.size;

            debug!("float_pos: {:?}, float_size: {:?}", float_pos, float_size);
            match float.kind {
                FloatKind::Left if float_pos.i + float_size.inline > max_inline_start &&
                        float_pos.b + float_size.block > block_start &&
                        float_pos.b < block_start + block_size => {
                    max_inline_start = float_pos.i + float_size.inline;

                    l_block_start = Some(float_pos.b);
                    l_block_end = Some(float_pos.b + float_size.block);

                    debug!("available_rect: collision with inline_start float: new \
                            max_inline_start is {:?}",
                           max_inline_start);
                }
                FloatKind::Right if float_pos.i < min_inline_end &&
                       float_pos.b + float_size.block > block_start &&
                       float_pos.b < block_start + block_size => {
                    min_inline_end = float_pos.i;

                    r_block_start = Some(float_pos.b);
                    r_block_end = Some(float_pos.b + float_size.block);
                    debug!("available_rect: collision with inline_end float: new min_inline_end \
                            is {:?}",
                            min_inline_end);
                }
                FloatKind::Left | FloatKind::Right => {}
            }
        }

        // Extend the vertical range of the rectangle to the closest floats.
        // If there are floats on both sides, take the intersection of the
        // two areas. Also make sure we never return a block-start smaller than the
        // given upper bound.
        let (block_start, block_end) = match (r_block_start,
                                              r_block_end,
                                              l_block_start,
                                              l_block_end) {
            (Some(r_block_start), Some(r_block_end), Some(l_block_start), Some(l_block_end)) => {
                range_intersect(max(block_start, r_block_start),
                                r_block_end,
                                max(block_start, l_block_start),
                                l_block_end)
            }
            (None, None, Some(l_block_start), Some(l_block_end)) => {
                (max(block_start, l_block_start), l_block_end)
            }
            (Some(r_block_start), Some(r_block_end), None, None) => {
                (max(block_start, r_block_start), r_block_end)
            }
            (None, None, None, None) => return None,
            _ => panic!("Reached unreachable state when computing float area")
        };

        // FIXME(eatkinson): This assertion is too strong and fails in some cases. It is OK to
        // return negative inline-sizes since we check against that inline-end away, but we should
        // still understand why they occur and add a stronger assertion here.
        // assert!(max_inline-start < min_inline-end);

        assert!(block_start <= block_end, "Float position error");

        Some(LogicalRect::new(self.writing_mode,
                              max_inline_start + self.offset.inline,
                              block_start + self.offset.block,
                              min_inline_end - max_inline_start,
                              block_end - block_start))
    }

    /// Adds a new float to the list.
    pub fn add_float(&mut self, info: &PlacementInfo) {
        let new_info;
        {
            new_info = PlacementInfo {
                size: info.size,
                ceiling: max(info.ceiling, self.list.max_block_start + self.offset.block),
                max_inline_size: info.max_inline_size,
                kind: info.kind
            }
        }

        debug!("add_float: added float with info {:?}", new_info);

        let new_float = Float {
            bounds: LogicalRect::from_point_size(
                self.writing_mode,
                self.place_between_floats(&new_info).start - self.offset,
                info.size,
            ),
            kind: info.kind
        };

        self.list.floats = self.list.floats.prepend_elem(new_float);
        self.list.max_block_start = max(self.list.max_block_start, new_float.bounds.start.b);
    }

    /// Given the three sides of the bounding rectangle in the block-start direction, finds the
    /// largest block-size that will result in the rectangle not colliding with any floats. Returns
    /// `None` if that block-size is infinite.
    fn max_block_size_for_bounds(&self, inline_start: Au, block_start: Au, inline_size: Au)
                                 -> Option<Au> {
        let list = &self.list;

        let block_start = block_start - self.offset.block;
        let inline_start = inline_start - self.offset.inline;
        let mut max_block_size = None;

        for float in list.floats.iter() {
            if float.bounds.start.b + float.bounds.size.block > block_start &&
                   float.bounds.start.i + float.bounds.size.inline > inline_start &&
                   float.bounds.start.i < inline_start + inline_size {
               let new_y = float.bounds.start.b;
               max_block_size = Some(min(max_block_size.unwrap_or(new_y), new_y));
            }
        }

        max_block_size.map(|h| h + self.offset.block)
    }

    /// Given placement information, finds the closest place a fragment can be positioned without
    /// colliding with any floats.
    pub fn place_between_floats(&self, info: &PlacementInfo) -> LogicalRect<Au> {
        debug!("place_between_floats: Placing object with {:?}", info.size);

        // If no floats, use this fast path.
        if !self.list.is_present() {
            match info.kind {
                FloatKind::Left => {
                    return LogicalRect::new(
                        self.writing_mode,
                        Au(0),
                        info.ceiling,
                        info.max_inline_size,
                        Au(i32::MAX))
                }
                FloatKind::Right => {
                    return LogicalRect::new(
                        self.writing_mode,
                        info.max_inline_size - info.size.inline,
                        info.ceiling,
                        info.max_inline_size,
                        Au(i32::MAX))
                }
            }
        }

        // Can't go any higher than previous floats or previous elements in the document.
        let mut float_b = info.ceiling;
        loop {
            let maybe_location = self.available_rect(float_b,
                                                     info.size.block,
                                                     info.max_inline_size);
            debug!("place_float: Got available rect: {:?} for y-pos: {:?}", maybe_location, float_b);
            match maybe_location {
                // If there are no floats blocking us, return the current location
                // TODO(eatkinson): integrate with overflow
                None => {
                    return match info.kind {
                        FloatKind::Left => {
                            LogicalRect::new(
                                self.writing_mode,
                                Au(0),
                                float_b,
                                info.max_inline_size,
                                Au(i32::MAX))
                        }
                        FloatKind::Right => {
                            LogicalRect::new(
                                self.writing_mode,
                                info.max_inline_size - info.size.inline,
                                float_b,
                                info.max_inline_size,
                                Au(i32::MAX))
                        }
                    }
                }
                Some(rect) => {
                    assert!(rect.start.b + rect.size.block != float_b,
                            "Non-terminating float placement");

                    // Place here if there is enough room
                    if rect.size.inline >= info.size.inline {
                        let block_size = self.max_block_size_for_bounds(rect.start.i,
                                                                rect.start.b,
                                                                rect.size.inline);
                        let block_size = block_size.unwrap_or(Au(i32::MAX));
                        return match info.kind {
                            FloatKind::Left => {
                                LogicalRect::new(
                                    self.writing_mode,
                                    rect.start.i,
                                    float_b,
                                    rect.size.inline,
                                    block_size)
                            }
                            FloatKind::Right => {
                                LogicalRect::new(
                                    self.writing_mode,
                                    rect.start.i + rect.size.inline - info.size.inline,
                                    float_b,
                                    rect.size.inline,
                                    block_size)
                            }
                        }
                    }

                    // Try to place at the next-lowest location.
                    // Need to be careful of fencepost errors.
                    float_b = rect.start.b + rect.size.block;
                }
            }
        }
    }

    pub fn clearance(&self, clear: ClearType) -> Au {
        let list = &self.list;
        let mut clearance = Au(0);
        for float in list.floats.iter() {
            match (clear, float.kind) {
                (ClearType::Left, FloatKind::Left) |
                (ClearType::Right, FloatKind::Right) |
                (ClearType::Both, _) => {
                    let b = self.offset.block + float.bounds.start.b + float.bounds.size.block;
                    clearance = max(clearance, b);
                }
                _ => {}
            }
        }
        clearance
    }
}
<commit_msg>Use usize for Floats::len.<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 util::geometry::Au;
use util::logical_geometry::WritingMode;
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use util::persistent_list::PersistentList;
use std::cmp::{max, min};
use std::i32;
use std::fmt;
use style::computed_values::float;

/// The kind of float: left or right.
#[derive(Clone, RustcEncodable, Debug, Copy)]
pub enum FloatKind {
    Left,
    Right
}

impl FloatKind {
    pub fn from_property(property: float::T) -> FloatKind {
        match property {
            float::T::none => panic!("can't create a float type from an unfloated property"),
            float::T::left => FloatKind::Left,
            float::T::right => FloatKind::Right,
        }
    }
}

/// The kind of clearance: left, right, or both.
#[derive(Copy)]
pub enum ClearType {
    Left,
    Right,
    Both,
}

/// Information about a single float.
#[derive(Clone, Copy)]
struct Float {
    /// The boundaries of this float.
    bounds: LogicalRect<Au>,
    /// The kind of float: left or right.
    kind: FloatKind,
}

impl fmt::Debug for Float {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "bounds={:?} kind={:?}", self.bounds, self.kind)
    }
}

/// Information about the floats next to a flow.
#[derive(Clone)]
struct FloatList {
    /// Information about each of the floats here.
    floats: PersistentList<Float>,
    /// Cached copy of the maximum block-start offset of the float.
    max_block_start: Au,
}

impl FloatList {
    fn new() -> FloatList {
        FloatList {
            floats: PersistentList::new(),
            max_block_start: Au(0),
        }
    }

    /// Returns true if the list is allocated and false otherwise. If false, there are guaranteed
    /// not to be any floats.
    fn is_present(&self) -> bool {
        self.floats.len() > 0
    }
}

impl fmt::Debug for FloatList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "max_block_start={:?} floats={}", self.max_block_start, self.floats.len())
    }
}

/// All the information necessary to place a float.
pub struct PlacementInfo {
    /// The dimensions of the float.
    pub size: LogicalSize<Au>,
    /// The minimum block-start of the float, as determined by earlier elements.
    pub ceiling: Au,
    /// The maximum inline-end position of the float, generally determined by the containing block.
    pub max_inline_size: Au,
    /// The kind of float.
    pub kind: FloatKind
}

impl fmt::Debug for PlacementInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "size={:?} ceiling={:?} max_inline_size={:?} kind={:?}",
               self.size,
               self.ceiling,
               self.max_inline_size,
               self.kind)
    }
}

fn range_intersect(block_start_1: Au, block_end_1: Au, block_start_2: Au, block_end_2: Au) -> (Au, Au) {
    (max(block_start_1, block_start_2), min(block_end_1, block_end_2))
}

/// Encapsulates information about floats. This is optimized to avoid allocation if there are
/// no floats, and to avoid copying when translating the list of floats downward.
#[derive(Clone)]
pub struct Floats {
    /// The list of floats.
    list: FloatList,
    /// The offset of the flow relative to the first float.
    offset: LogicalSize<Au>,
    /// The writing mode of these floats.
    pub writing_mode: WritingMode,
}

impl fmt::Debug for Floats {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if !self.list.is_present() {
            write!(f, "[empty]")
        } else {
            write!(f, "offset={:?} floats={:?}", self.offset, self.list)
        }
    }
}

impl Floats {
    /// Creates a new `Floats` object.
    pub fn new(writing_mode: WritingMode) -> Floats {
        Floats {
            list: FloatList::new(),
            offset: LogicalSize::zero(writing_mode),
            writing_mode: writing_mode,
        }
    }

    /// Adjusts the recorded offset of the flow relative to the first float.
    pub fn translate(&mut self, delta: LogicalSize<Au>) {
        self.offset = self.offset + delta
    }

    /// Returns the position of the last float in flow coordinates.
    pub fn last_float_pos(&self) -> Option<LogicalPoint<Au>> {
        match self.list.floats.front() {
            None => None,
            Some(float) => Some(float.bounds.start + self.offset),
        }
    }

    pub fn len(&self) -> usize {
        self.list.floats.len()
    }

    /// Returns a rectangle that encloses the region from block-start to block-start + block-size,
    /// with inline-size small enough that it doesn't collide with any floats. max_x is the
    /// inline-size beyond which floats have no effect. (Generally this is the containing block
    /// inline-size.)
    pub fn available_rect(&self, block_start: Au, block_size: Au, max_x: Au)
                          -> Option<LogicalRect<Au>> {
        let list = &self.list;
        let block_start = block_start - self.offset.block;

        debug!("available_rect: trying to find space at {:?}", block_start);

        // Relevant dimensions for the inline-end-most inline-start float
        let mut max_inline_start = Au(0) - self.offset.inline;
        let mut l_block_start = None;
        let mut l_block_end = None;
        // Relevant dimensions for the inline-start-most inline-end float
        let mut min_inline_end = max_x - self.offset.inline;
        let mut r_block_start = None;
        let mut r_block_end = None;

        // Find the float collisions for the given range in the block direction.
        for float in list.floats.iter() {
            debug!("available_rect: Checking for collision against float");
            let float_pos = float.bounds.start;
            let float_size = float.bounds.size;

            debug!("float_pos: {:?}, float_size: {:?}", float_pos, float_size);
            match float.kind {
                FloatKind::Left if float_pos.i + float_size.inline > max_inline_start &&
                        float_pos.b + float_size.block > block_start &&
                        float_pos.b < block_start + block_size => {
                    max_inline_start = float_pos.i + float_size.inline;

                    l_block_start = Some(float_pos.b);
                    l_block_end = Some(float_pos.b + float_size.block);

                    debug!("available_rect: collision with inline_start float: new \
                            max_inline_start is {:?}",
                           max_inline_start);
                }
                FloatKind::Right if float_pos.i < min_inline_end &&
                       float_pos.b + float_size.block > block_start &&
                       float_pos.b < block_start + block_size => {
                    min_inline_end = float_pos.i;

                    r_block_start = Some(float_pos.b);
                    r_block_end = Some(float_pos.b + float_size.block);
                    debug!("available_rect: collision with inline_end float: new min_inline_end \
                            is {:?}",
                            min_inline_end);
                }
                FloatKind::Left | FloatKind::Right => {}
            }
        }

        // Extend the vertical range of the rectangle to the closest floats.
        // If there are floats on both sides, take the intersection of the
        // two areas. Also make sure we never return a block-start smaller than the
        // given upper bound.
        let (block_start, block_end) = match (r_block_start,
                                              r_block_end,
                                              l_block_start,
                                              l_block_end) {
            (Some(r_block_start), Some(r_block_end), Some(l_block_start), Some(l_block_end)) => {
                range_intersect(max(block_start, r_block_start),
                                r_block_end,
                                max(block_start, l_block_start),
                                l_block_end)
            }
            (None, None, Some(l_block_start), Some(l_block_end)) => {
                (max(block_start, l_block_start), l_block_end)
            }
            (Some(r_block_start), Some(r_block_end), None, None) => {
                (max(block_start, r_block_start), r_block_end)
            }
            (None, None, None, None) => return None,
            _ => panic!("Reached unreachable state when computing float area")
        };

        // FIXME(eatkinson): This assertion is too strong and fails in some cases. It is OK to
        // return negative inline-sizes since we check against that inline-end away, but we should
        // still understand why they occur and add a stronger assertion here.
        // assert!(max_inline-start < min_inline-end);

        assert!(block_start <= block_end, "Float position error");

        Some(LogicalRect::new(self.writing_mode,
                              max_inline_start + self.offset.inline,
                              block_start + self.offset.block,
                              min_inline_end - max_inline_start,
                              block_end - block_start))
    }

    /// Adds a new float to the list.
    pub fn add_float(&mut self, info: &PlacementInfo) {
        let new_info;
        {
            new_info = PlacementInfo {
                size: info.size,
                ceiling: max(info.ceiling, self.list.max_block_start + self.offset.block),
                max_inline_size: info.max_inline_size,
                kind: info.kind
            }
        }

        debug!("add_float: added float with info {:?}", new_info);

        let new_float = Float {
            bounds: LogicalRect::from_point_size(
                self.writing_mode,
                self.place_between_floats(&new_info).start - self.offset,
                info.size,
            ),
            kind: info.kind
        };

        self.list.floats = self.list.floats.prepend_elem(new_float);
        self.list.max_block_start = max(self.list.max_block_start, new_float.bounds.start.b);
    }

    /// Given the three sides of the bounding rectangle in the block-start direction, finds the
    /// largest block-size that will result in the rectangle not colliding with any floats. Returns
    /// `None` if that block-size is infinite.
    fn max_block_size_for_bounds(&self, inline_start: Au, block_start: Au, inline_size: Au)
                                 -> Option<Au> {
        let list = &self.list;

        let block_start = block_start - self.offset.block;
        let inline_start = inline_start - self.offset.inline;
        let mut max_block_size = None;

        for float in list.floats.iter() {
            if float.bounds.start.b + float.bounds.size.block > block_start &&
                   float.bounds.start.i + float.bounds.size.inline > inline_start &&
                   float.bounds.start.i < inline_start + inline_size {
               let new_y = float.bounds.start.b;
               max_block_size = Some(min(max_block_size.unwrap_or(new_y), new_y));
            }
        }

        max_block_size.map(|h| h + self.offset.block)
    }

    /// Given placement information, finds the closest place a fragment can be positioned without
    /// colliding with any floats.
    pub fn place_between_floats(&self, info: &PlacementInfo) -> LogicalRect<Au> {
        debug!("place_between_floats: Placing object with {:?}", info.size);

        // If no floats, use this fast path.
        if !self.list.is_present() {
            match info.kind {
                FloatKind::Left => {
                    return LogicalRect::new(
                        self.writing_mode,
                        Au(0),
                        info.ceiling,
                        info.max_inline_size,
                        Au(i32::MAX))
                }
                FloatKind::Right => {
                    return LogicalRect::new(
                        self.writing_mode,
                        info.max_inline_size - info.size.inline,
                        info.ceiling,
                        info.max_inline_size,
                        Au(i32::MAX))
                }
            }
        }

        // Can't go any higher than previous floats or previous elements in the document.
        let mut float_b = info.ceiling;
        loop {
            let maybe_location = self.available_rect(float_b,
                                                     info.size.block,
                                                     info.max_inline_size);
            debug!("place_float: Got available rect: {:?} for y-pos: {:?}", maybe_location, float_b);
            match maybe_location {
                // If there are no floats blocking us, return the current location
                // TODO(eatkinson): integrate with overflow
                None => {
                    return match info.kind {
                        FloatKind::Left => {
                            LogicalRect::new(
                                self.writing_mode,
                                Au(0),
                                float_b,
                                info.max_inline_size,
                                Au(i32::MAX))
                        }
                        FloatKind::Right => {
                            LogicalRect::new(
                                self.writing_mode,
                                info.max_inline_size - info.size.inline,
                                float_b,
                                info.max_inline_size,
                                Au(i32::MAX))
                        }
                    }
                }
                Some(rect) => {
                    assert!(rect.start.b + rect.size.block != float_b,
                            "Non-terminating float placement");

                    // Place here if there is enough room
                    if rect.size.inline >= info.size.inline {
                        let block_size = self.max_block_size_for_bounds(rect.start.i,
                                                                rect.start.b,
                                                                rect.size.inline);
                        let block_size = block_size.unwrap_or(Au(i32::MAX));
                        return match info.kind {
                            FloatKind::Left => {
                                LogicalRect::new(
                                    self.writing_mode,
                                    rect.start.i,
                                    float_b,
                                    rect.size.inline,
                                    block_size)
                            }
                            FloatKind::Right => {
                                LogicalRect::new(
                                    self.writing_mode,
                                    rect.start.i + rect.size.inline - info.size.inline,
                                    float_b,
                                    rect.size.inline,
                                    block_size)
                            }
                        }
                    }

                    // Try to place at the next-lowest location.
                    // Need to be careful of fencepost errors.
                    float_b = rect.start.b + rect.size.block;
                }
            }
        }
    }

    pub fn clearance(&self, clear: ClearType) -> Au {
        let list = &self.list;
        let mut clearance = Au(0);
        for float in list.floats.iter() {
            match (clear, float.kind) {
                (ClearType::Left, FloatKind::Left) |
                (ClearType::Right, FloatKind::Right) |
                (ClearType::Both, _) => {
                    let b = self.offset.block + float.bounds.start.b + float.bounds.size.block;
                    clearance = max(clearance, b);
                }
                _ => {}
            }
        }
        clearance
    }
}
<|endoftext|>


<commit_before>extern crate arrayfire as af;

use af::*;

#[allow(unused_must_use)]
fn test_backend(){
  info();

  let num_rows: u64 = 10;
  let num_cols: u64 = 10;
  let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);

  println!("Create a 5-by-3 matrix of random floats on the compute device");
  let a = match randu(dims, Aftype::F32) {
    Ok(value) => value,
    Err(error) => panic!("{}", error),
  };
  print(&a);
}

#[allow(unused_must_use)]
fn main() {
  println!("There are {} available backends", get_backend_count().unwrap());
  let err = set_backend(AfBackend::AF_BACKEND_CPU);
  match err {
    Ok(_)  => test_backend(),
    Err(e) => println!("CPU backend not available: {}", e),
  };

  let err = set_backend(AfBackend::AF_BACKEND_CUDA);
  match err {
    Ok(_)  => test_backend(),
    Err(e) => println!("CUDA backend not available: {}", e),
  };

  let err = set_backend(AfBackend::AF_BACKEND_OPENCL);
  match err {
    Ok(_)  => test_backend(),
    Err(e) => println!("OpenCL backend not available: {}", e),
  };
}
<commit_msg>fix typo<commit_after>extern crate arrayfire as af;

use af::*;

#[allow(unused_must_use)]
fn test_backend(){
  info();

  let num_rows: u64 = 10;
  let num_cols: u64 = 10;
  let dims = Dim4::new(&[num_rows, num_cols, 1, 1]);

  println!("Create a 10-by-10 matrix of random floats on the compute device");
  let a = match randu(dims, Aftype::F32) {
    Ok(value) => value,
    Err(error) => panic!("{}", error),
  };
  print(&a);
}

#[allow(unused_must_use)]
fn main() {
  println!("There are {} available backends", get_backend_count().unwrap());
  let err = set_backend(AfBackend::AF_BACKEND_CPU);
  match err {
    Ok(_)  => test_backend(),
    Err(e) => println!("CPU backend not available: {}", e),
  };

  let err = set_backend(AfBackend::AF_BACKEND_CUDA);
  match err {
    Ok(_)  => test_backend(),
    Err(e) => println!("CUDA backend not available: {}", e),
  };

  let err = set_backend(AfBackend::AF_BACKEND_OPENCL);
  match err {
    Ok(_)  => test_backend(),
    Err(e) => println!("OpenCL backend not available: {}", e),
  };
}
<|endoftext|>


<commit_before>use rust_mal_lib::env::{Env, Environment};
use rust_mal_lib::reader;
use rust_mal_lib::types::MalType::*;
use rust_mal_lib::types::{
    err_str, err_string, new_function, new_integer, new_list, new_symbol, new_vector, MalError,
    MalResult, MalValue,
};

use rust_mal_steps::scaffold::*;

fn read(string: &str) -> MalResult {
    reader::read_str(string)
}

fn eval_ast(ast: MalValue, env: &mut impl Environment) -> MalResult {
    match *ast {
        Symbol(_) => env.get_env_value(&ast),
        List(ref seq) | Vector(ref seq) => {
            let mut ast_ev = vec![];
            for value in seq {
                ast_ev.push(eval(value.clone(), env)?);
            }
            Ok(match *ast {
                List(_) => new_list(ast_ev),
                _ => new_vector(ast_ev),
            })
        }
        _ => Ok(ast.clone()),
    }
}

fn eval(ast: MalValue, env: &mut impl Environment) -> MalResult {
    let ast_temp = ast.clone();
    let (arg0_symbol, args): (Option<&str>, &Vec<MalValue>) = match *ast_temp {
        List(ref seq) => {
            if seq.is_empty() {
                return Ok(ast);
            }
            match *seq[0] {
                Symbol(ref symbol) => (Some(&symbol[..]), seq),
                _ => (None, seq),
            }
        }
        _ => return eval_ast(ast, env),
    };

    if let Some(slice) = arg0_symbol {
        match slice {
            // (def! key value) ; key must be a Symbol
            // bind the evaluated value in env with the unevaluated key
            "def!" => {
                if args.len() != 3 {
                    return err_str("wrong arity for \"def!\", should be 2");
                }
                let key = args[1].clone();
                let value = eval(args[2].clone(), env)?;
                match *key {
                    Symbol(_) => {
                        println!("deffffffff {:?} {:?}", key, value);
                        env.set_env_value(key, value.clone());
                        return Ok(value);
                    }
                    _ => {
                        return err_str("def! with non-symbol as a key");
                    }
                }
            }
            // (let* (key0 value0 key1 value1 ...) value)
            // evaluate value in a temporary sub-environment where
            // the given (key: Symbol / value: _) pairs are set
            "let*" => {
                if args.len() != 3 {
                    return err_str("wrong arity for \"let*\", should be 2");
                }
                let mut env_let = env.new_inner();
                let bindings = args[1].clone();
                match *bindings {
                    List(ref bindings_seq) => {
                        if bindings_seq.len() % 2 != 0 {
                            return err_str(concat!(
                                "missing key or value ",
                                "in the let* binding list"
                            ));
                        }
                        let mut it = bindings_seq.iter();
                        while it.len() >= 2 {
                            let key = it.next().unwrap();
                            let expr = it.next().unwrap();
                            match **key {
                                Symbol(_) => {
                                    let value = eval(expr.clone(), &mut env_let)?;
                                    env_let.set_env_value(key.clone(), value);
                                }
                                _ => return err_str("non-symbol key in the let* binding list"),
                            }
                        }
                    }
                    _ => return err_str("let* with non-list binding"),
                }
                return eval(args[2].clone(), &mut env_let);
            }
            // otherwise : apply the first item to the other
            _ => (),
        }
    }

    let list_ev = eval_ast(ast.clone(), env)?;
    let items = match *list_ev {
        List(ref seq) => seq,
        _ => return err_str("can only apply on a list"),
    };
    if items.is_empty() {
        return Ok(list_ev.clone());
    }
    let f = &items[0];
    f.apply(items[1..].to_vec())
}

fn print(expr: MalValue) -> String {
    expr.pr_str(true)
}

fn int_op<F>(f: F, args: Vec<MalValue>) -> MalResult
where
    F: FnOnce(i32, i32) -> i32,
{
    if args.len() != 2 {
        return err_string(format!(
            "wrong arity ({}) for operation between 2 integers",
            args.len()
        ));
    }
    match *args[0] {
        Integer(left) => match *args[1] {
            Integer(right) => Ok(new_integer(f(left, right))),
            _ => err_str("right argument must be an integer"),
        },
        _ => err_str("left argument must be an integer"),
    }
}
fn add(args: Vec<MalValue>) -> MalResult {
    int_op(|a, b| a + b, args)
}
fn sub(args: Vec<MalValue>) -> MalResult {
    int_op(|a, b| a - b, args)
}
fn mul(args: Vec<MalValue>) -> MalResult {
    int_op(|a, b| a * b, args)
}

fn div(args: Vec<MalValue>) -> MalResult {
    if args.len() != 2 {
        return err_string(format!(
            "wrong arity ({}) for operation between 2 integers",
            args.len()
        ));
    }
    match *args[0] {
        Integer(left) => match *args[1] {
            Integer(right) => {
                if right == 0 {
                    err_str("cannot divide by 0")
                } else {
                    Ok(new_integer(left / right))
                }
            }
            _ => err_str("right argument must be an integer"),
        },
        _ => err_str("left argument must be an integer"),
    }
}

struct Step3Env;
impl InterpreterScaffold<Env> for Step3Env {
    const STEP_NAME: &'static str = "step3_env";

    fn create_env() -> Result<Env, MalError> {
        let mut repl_env: Env = Environment::new(None);
        repl_env
            .set_env_value(new_symbol("+".into()), new_function(add, Some(2), "+"))
            .set_env_value(new_symbol("-".into()), new_function(sub, Some(2), "-"))
            .set_env_value(new_symbol("*".into()), new_function(mul, Some(2), "*"))
            .set_env_value(new_symbol("/".into()), new_function(div, Some(2), "/"));
        Ok(repl_env)
    }

    fn rep(input: &str, env: &Env) -> Result<String, MalError> {
        let ast = read(input)?;
        let mut local_env = env.new_inner();
        let expr = eval(ast, &mut local_env)?;
        Ok(print(expr))
    }
}

fn main() -> Result<(), String> {
    cli_loop::<Env, Step3Env>()
}

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

    #[test]
    fn test_step3_spec() {
        assert_eq!(
            validate_against_spec::<Env, Step3Env>("step3_env.mal"),
            Ok(())
        );
    }
}
<commit_msg>:bug: Fix Step 3 environment not actually registering def! variables<commit_after>use rust_mal_lib::env::{Env, Environment};
use rust_mal_lib::reader;
use rust_mal_lib::types::MalType::*;
use rust_mal_lib::types::{
    err_str, err_string, new_function, new_integer, new_list, new_symbol, new_vector, MalError,
    MalResult, MalValue,
};

use rust_mal_steps::scaffold::*;

fn read(string: &str) -> MalResult {
    reader::read_str(string)
}

fn eval_ast(ast: MalValue, env: &Env) -> MalResult {
    match *ast {
        Symbol(_) => env.get_env_value(&ast),
        List(ref seq) | Vector(ref seq) => {
            let mut ast_ev = vec![];
            for value in seq {
                ast_ev.push(eval(value.clone(), env.clone())?);
            }
            Ok(match *ast {
                List(_) => new_list(ast_ev),
                _ => new_vector(ast_ev),
            })
        }
        _ => Ok(ast.clone()),
    }
}

fn eval(ast: MalValue, mut env: Env) -> MalResult {
    let ast_temp = ast.clone();
    let (arg0_symbol, args): (Option<&str>, &Vec<MalValue>) = match *ast_temp {
        List(ref seq) => {
            if seq.is_empty() {
                return Ok(ast);
            }
            match *seq[0] {
                Symbol(ref symbol) => (Some(&symbol[..]), seq),
                _ => (None, seq),
            }
        }
        _ => return eval_ast(ast, &env),
    };

    if let Some(slice) = arg0_symbol {
        match slice {
            // (def! key value) ; key must be a Symbol
            // bind the evaluated value in env with the unevaluated key
            "def!" => {
                if args.len() != 3 {
                    return err_str("wrong arity for \"def!\", should be 2");
                }
                let key = args[1].clone();
                let value = eval(args[2].clone(), env.clone())?;
                match *key {
                    Symbol(_) => {
                        env.set_env_value(key, value.clone());
                        return Ok(value);
                    }
                    _ => {
                        return err_str("def! with non-symbol as a key");
                    }
                }
            }
            // (let* (key0 value0 key1 value1 ...) value)
            // evaluate value in a temporary sub-environment where
            // the given (key: Symbol / value: _) pairs are set
            "let*" => {
                if args.len() != 3 {
                    return err_str("wrong arity for \"let*\", should be 2");
                }
                let mut env_let = env.new_inner();
                let bindings = args[1].clone();
                match *bindings {
                    List(ref bindings_seq) => {
                        if bindings_seq.len() % 2 != 0 {
                            return err_str(concat!(
                                "missing key or value ",
                                "in the let* binding list"
                            ));
                        }
                        let mut it = bindings_seq.iter();
                        while it.len() >= 2 {
                            let key = it.next().unwrap();
                            let expr = it.next().unwrap();
                            match **key {
                                Symbol(_) => {
                                    let value = eval(expr.clone(), env_let.clone())?;
                                    env_let.set_env_value(key.clone(), value);
                                }
                                _ => return err_str("non-symbol key in the let* binding list"),
                            }
                        }
                    }
                    _ => return err_str("let* with non-list binding"),
                }
                return eval(args[2].clone(), env_let.clone());
            }
            // otherwise : apply the first item to the other
            _ => (),
        }
    }

    let list_ev = eval_ast(ast.clone(), &env)?;
    let items = match *list_ev {
        List(ref seq) => seq,
        _ => return err_str("can only apply on a list"),
    };
    if items.is_empty() {
        return Ok(list_ev.clone());
    }
    let f = &items[0];
    f.apply(items[1..].to_vec())
}

fn print(expr: MalValue) -> String {
    expr.pr_str(true)
}

fn int_op<F>(f: F, args: Vec<MalValue>) -> MalResult
where
    F: FnOnce(i32, i32) -> i32,
{
    if args.len() != 2 {
        return err_string(format!(
            "wrong arity ({}) for operation between 2 integers",
            args.len()
        ));
    }
    match *args[0] {
        Integer(left) => match *args[1] {
            Integer(right) => Ok(new_integer(f(left, right))),
            _ => err_str("right argument must be an integer"),
        },
        _ => err_str("left argument must be an integer"),
    }
}
fn add(args: Vec<MalValue>) -> MalResult {
    int_op(|a, b| a + b, args)
}
fn sub(args: Vec<MalValue>) -> MalResult {
    int_op(|a, b| a - b, args)
}
fn mul(args: Vec<MalValue>) -> MalResult {
    int_op(|a, b| a * b, args)
}

fn div(args: Vec<MalValue>) -> MalResult {
    if args.len() != 2 {
        return err_string(format!(
            "wrong arity ({}) for operation between 2 integers",
            args.len()
        ));
    }
    match *args[0] {
        Integer(left) => match *args[1] {
            Integer(right) => {
                if right == 0 {
                    err_str("cannot divide by 0")
                } else {
                    Ok(new_integer(left / right))
                }
            }
            _ => err_str("right argument must be an integer"),
        },
        _ => err_str("left argument must be an integer"),
    }
}

struct Step3Env;
impl InterpreterScaffold<Env> for Step3Env {
    const STEP_NAME: &'static str = "step3_env";

    fn create_env() -> Result<Env, MalError> {
        let mut repl_env: Env = Environment::new(None);
        repl_env
            .set_env_value(new_symbol("+".into()), new_function(add, Some(2), "+"))
            .set_env_value(new_symbol("-".into()), new_function(sub, Some(2), "-"))
            .set_env_value(new_symbol("*".into()), new_function(mul, Some(2), "*"))
            .set_env_value(new_symbol("/".into()), new_function(div, Some(2), "/"));
        Ok(repl_env)
    }

    fn rep(input: &str, env: &Env) -> Result<String, MalError> {
        let ast = read(input)?;
        let expr = eval(ast, env.clone())?;
        Ok(print(expr))
    }
}

fn main() -> Result<(), String> {
    cli_loop::<Env, Step3Env>()
}

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

    #[test]
    fn test_step3_spec() {
        assert_eq!(
            validate_against_spec::<Env, Step3Env>("step3_env.mal"),
            Ok(())
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use smallvec::SmallVec;

use command_buffer::RawCommandBufferPrototype;
use command_buffer::CommandsList;
use command_buffer::CommandsListSink;
use format::FormatTy;
use image::Image;
use image::Layout;
use sampler::Filter;
use VulkanObject;
use VulkanPointers;
use vk;

/// Wraps around a commands list and adds at the end of it a command that blits from an image to
/// another.
pub struct CmdBlitImageUnsynced<L, S, D>
    where L: CommandsList
{
    // Parent commands list.
    previous: L,
    source: S,
    source_raw: vk::Image,
    source_layout: vk::ImageLayout,
    destination: D,
    destination_raw: vk::Image,
    destination_layout: vk::ImageLayout,
    filter: vk::Filter,
    regions: SmallVec<[vk::ImageBlit; 1]>,
}

impl<L, S, D> CmdBlitImageUnsynced<L, S, D>
    where L: CommandsList, S: Image, D: Image
{
    pub unsafe fn new<I>(previous: L, source: S, source_layout: Layout,
                         destination: D, destination_layout: Layout, filter: Filter,
                         regions: I)
                         -> Result<CmdBlitImageUnsynced<L, S, D>, CmdBlitImageUnsyncedError>
        where I: IntoIterator<Item = BlitRegion>
    {
        // FIXME: check that we're outside a render pass

        if !source.inner().usage_transfer_src() {
            return Err(CmdBlitImageUnsyncedError::SourceUsageMissingSrcTransfer);
        }

        if !source.inner().usage_transfer_dest() {
            return Err(CmdBlitImageUnsyncedError::DestinationUsageMissingDestTransfer);
        }

        if !source.inner().supports_blit_source() {
            return Err(CmdBlitImageUnsyncedError::SourceFormatDoesntSupportBlits);
        }

        if !source.inner().supports_blit_destination() {
            return Err(CmdBlitImageUnsyncedError::DestinationFormatDoesntSupportBlits);
        }

        match (source.inner().format().ty(), destination.inner().format().ty()) {
            (FormatTy::Sint, FormatTy::Sint) => (),
            (FormatTy::Sint, _) | (_, FormatTy::Sint) => {
                return Err(CmdBlitImageUnsyncedError::IncompatibleSourceDestinationFormats);
            },
            (FormatTy::Uint, FormatTy::Uint) => (),
            (FormatTy::Uint, _) | (_, FormatTy::Uint) => {
                return Err(CmdBlitImageUnsyncedError::IncompatibleSourceDestinationFormats);
            },
            (FormatTy::Depth, _) | (FormatTy::Stencil, _) | (FormatTy::DepthStencil, _) => {
                if source.inner().format() != destination.inner().format() {
                    return Err(CmdBlitImageUnsyncedError::IncompatibleSourceDestinationFormats);
                }
            },
            _ => ()
        }

        if source.inner().samples() != 1 {
            return Err(CmdBlitImageUnsyncedError::SourceMultisampled);
        }

        if destination.inner().samples() != 1 {
            return Err(CmdBlitImageUnsyncedError::DestinationMultisampled);
        }

        if filter == Filter::Linear && !source.inner().supports_linear_filtering() {
            return Err(CmdBlitImageUnsyncedError::SourceDoesntSupportLinearFilter);
        }

        let raw_regions = {
            let mut raw_regions = SmallVec::new();
            for region in regions {
                // FIXME: check dimensions
                // FIXME: check overlap and document how it works

                raw_regions.push(vk::ImageBlit {
                    srcOffsets: [
                        vk::Offset3D {
                            x: region.source_offset[0] as i32,
                            y: region.source_offset[1] as i32,
                            z: region.source_offset[2] as i32,
                        },
                        vk::Offset3D {
                            x: region.source_offset[0] as i32 + region.source_size[0],
                            y: region.source_offset[1] as i32 + region.source_size[1],
                            z: region.source_offset[2] as i32 + region.source_size[2],
                        },
                    ],
                    srcSubresource: vk::ImageSubresourceLayers {
                        aspectMask: region.aspect as u32,
                        mipLevel: region.source_mipmap,
                        baseArrayLayer: region.source_array_layer,
                        layerCount: region.num_arrays_layers,
                    },
                    dstOffsets: [
                        vk::Offset3D {
                            x: region.destination_offset[0] as i32,
                            y: region.destination_offset[1] as i32,
                            z: region.destination_offset[2] as i32,
                        },
                        vk::Offset3D {
                            x: region.destination_offset[0] as i32 + region.destination_size[0],
                            y: region.destination_offset[1] as i32 + region.destination_size[1],
                            z: region.destination_offset[2] as i32 + region.destination_size[2],
                        },
                    ],
                    dstSubresource: vk::ImageSubresourceLayers {
                        aspectMask: region.aspect as u32,
                        mipLevel: region.destination_mipmap,
                        baseArrayLayer: region.destination_array_layer,
                        layerCount: region.num_arrays_layers,
                    },
                });
            }
            raw_regions
        };

        assert_eq!(source.inner().device().internal_object(),
                   destination.inner().device().internal_object());
        debug_assert!(source_layout == Layout::TransferSrcOptimal ||
                      source_layout == Layout::General);
        debug_assert!(destination_layout == Layout::TransferDstOptimal ||
                      destination_layout == Layout::General);

        let source_raw = source.inner().internal_object();
        let destination_raw = destination.inner().internal_object();

        Ok(CmdBlitImageUnsynced {
            previous: previous,
            source: source,
            source_raw: source_raw,
            source_layout: source_layout as u32,
            destination: destination,
            destination_raw: destination_raw,
            destination_layout: destination_layout as u32,
            filter: filter as vk::Filter,
            regions: raw_regions,
        })
    }
}

impl<L, S, D> CmdBlitImageUnsynced<L, S, D>
    where L: CommandsList, S: Image, D: Image
{
    #[inline]
    fn append<'a>(&'a self, builder: &mut CommandsListSink<'a>) {
        self.previous.append(builder);

        assert_eq!(self.source.inner().device().internal_object(),
                   builder.device().internal_object());

        builder.add_command(Box::new(move |raw: &mut RawCommandBufferPrototype| {
            unsafe {
                let vk = raw.device.pointers();
                let cmd = raw.command_buffer.clone().take().unwrap();
                vk.CmdBlitImage(cmd, self.source_raw, self.source_layout, self.destination_raw,
                                self.destination_layout, self.regions.len() as u32,
                                self.regions.as_ptr(), self.filter);
            }
        }));
    }
}

/// A region of a blit operation.
#[derive(Debug, Copy, Clone)]
pub struct BlitRegion {
    /// Which aspect of the source and destination to blit.
    pub aspect: BlitRegionAspect,
    /// The mipmap of the source image to copy. You can only blit one mipmap at a time.
    pub source_mipmap: u32,
    /// 3D coordinates of the starting pixel in the source image.
    pub source_offset: [u32; 3],
    /// Size of the source area. Can be negative if you want to flip the area.
    pub source_size: [i32; 3],
    /// First array layer of the source image.
    pub source_array_layer: u32,
    /// The mipmap of the destination image to copy. You can only blit one mipmap at a time.
    pub destination_mipmap: u32,
    /// 3D coordinates of the starting pixel in the destination image.
    pub destination_offset: [u32; 3],
    /// Size of the destination area. Can be negative if you want to flip the area.
    pub destination_size: [i32; 3],
    /// First array layer of the destination image.
    pub destination_array_layer: u32,
    /// Number of array layers to blit. Each array layer is blit one by one.
    pub num_arrays_layers: u32,
}

// TODO: maybe we can merge this type with other similar types?
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum BlitRegionAspect {
    Color = vk::IMAGE_ASPECT_COLOR_BIT,
    Depth = vk::IMAGE_ASPECT_DEPTH_BIT,
    Stencil = vk::IMAGE_ASPECT_STENCIL_BIT,
    DepthStencil = vk::IMAGE_ASPECT_DEPTH_BIT | vk::IMAGE_ASPECT_STENCIL_BIT,
}

/// Error that can happen when creating a `CmdBlitImageUnsynced`.
#[derive(Debug, Copy, Clone)]
pub enum CmdBlitImageUnsyncedError {
    /// The source image wasn't created with source transfer operations support.
    SourceUsageMissingSrcTransfer,
    /// The destination image wasn't created with destination transfer operations support.
    DestinationUsageMissingDestTransfer,
    /// The format of the source image doesn't support blit operations.
    SourceFormatDoesntSupportBlits,
    /// The format of the destination image doesn't support blit operations.
    DestinationFormatDoesntSupportBlits,
    /// The format of the source and the destination aren't compatible for blit operations.
    // TODO: link to documentation with these rules:
    // If either of srcImage or dstImage was created with a signed integer VkFormat, the other must also have been created with a signed integer VkFormat
    // If either of srcImage or dstImage was created with an unsigned integer VkFormat, the other must also have been created with an unsigned integer VkFormat
    // If either of srcImage or dstImage was created with a depth/stencil format, the other must have exactly the same format
    IncompatibleSourceDestinationFormats,
    /// The source image must only have one sample.
    SourceMultisampled,
    /// The destination image must only have one sample.
    DestinationMultisampled,
    /// The filter is `Linear` but the source format doesn't support linear filtering.
    SourceDoesntSupportLinearFilter,
}

impl error::Error for CmdBlitImageUnsyncedError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CmdBlitImageUnsyncedError::SourceUsageMissingSrcTransfer => {
                "the source image wasn't created with source transfer operations support"
            },
            CmdBlitImageUnsyncedError::DestinationUsageMissingDestTransfer => {
                "the destination image wasn't created with destination transfer operations support"
            },
            CmdBlitImageUnsyncedError::SourceFormatDoesntSupportBlits => {
                "the format of the source image doesn't support blit operations"
            },
            CmdBlitImageUnsyncedError::DestinationFormatDoesntSupportBlits => {
                "the format of the destination image doesn't support blit operations"
            },
            CmdBlitImageUnsyncedError::IncompatibleSourceDestinationFormats => {
                "the format of the source and the destination aren't compatible for blit operations"
            },
            CmdBlitImageUnsyncedError::SourceMultisampled => {
                "the source image must only have one sample"
            },
            CmdBlitImageUnsyncedError::DestinationMultisampled => {
                "the destination image must only have one sample"
            },
            CmdBlitImageUnsyncedError::SourceDoesntSupportLinearFilter => {
                "the filter is `Linear` but the source format doesn't support linear filtering"
            },
        }
    }
}

impl fmt::Display for CmdBlitImageUnsyncedError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}
<commit_msg>Fix wrong checks in blit image<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use smallvec::SmallVec;

use command_buffer::RawCommandBufferPrototype;
use command_buffer::CommandsList;
use command_buffer::CommandsListSink;
use format::FormatTy;
use image::Image;
use image::Layout;
use sampler::Filter;
use VulkanObject;
use VulkanPointers;
use vk;

/// Wraps around a commands list and adds at the end of it a command that blits from an image to
/// another.
pub struct CmdBlitImageUnsynced<L, S, D>
    where L: CommandsList
{
    // Parent commands list.
    previous: L,
    source: S,
    source_raw: vk::Image,
    source_layout: vk::ImageLayout,
    destination: D,
    destination_raw: vk::Image,
    destination_layout: vk::ImageLayout,
    filter: vk::Filter,
    regions: SmallVec<[vk::ImageBlit; 1]>,
}

impl<L, S, D> CmdBlitImageUnsynced<L, S, D>
    where L: CommandsList, S: Image, D: Image
{
    pub unsafe fn new<I>(previous: L, source: S, source_layout: Layout,
                         destination: D, destination_layout: Layout, filter: Filter,
                         regions: I)
                         -> Result<CmdBlitImageUnsynced<L, S, D>, CmdBlitImageUnsyncedError>
        where I: IntoIterator<Item = BlitRegion>
    {
        // FIXME: check that we're outside a render pass

        if !source.inner().usage_transfer_src() {
            return Err(CmdBlitImageUnsyncedError::SourceUsageMissingSrcTransfer);
        }

        if !destination.inner().usage_transfer_dest() {
            return Err(CmdBlitImageUnsyncedError::DestinationUsageMissingDestTransfer);
        }

        if !source.inner().supports_blit_source() {
            return Err(CmdBlitImageUnsyncedError::SourceFormatDoesntSupportBlits);
        }

        if !destination.inner().supports_blit_destination() {
            return Err(CmdBlitImageUnsyncedError::DestinationFormatDoesntSupportBlits);
        }

        match (source.inner().format().ty(), destination.inner().format().ty()) {
            (FormatTy::Sint, FormatTy::Sint) => (),
            (FormatTy::Sint, _) | (_, FormatTy::Sint) => {
                return Err(CmdBlitImageUnsyncedError::IncompatibleSourceDestinationFormats);
            },
            (FormatTy::Uint, FormatTy::Uint) => (),
            (FormatTy::Uint, _) | (_, FormatTy::Uint) => {
                return Err(CmdBlitImageUnsyncedError::IncompatibleSourceDestinationFormats);
            },
            (FormatTy::Depth, _) | (FormatTy::Stencil, _) | (FormatTy::DepthStencil, _) => {
                if source.inner().format() != destination.inner().format() {
                    return Err(CmdBlitImageUnsyncedError::IncompatibleSourceDestinationFormats);
                }
            },
            _ => ()
        }

        if source.inner().samples() != 1 {
            return Err(CmdBlitImageUnsyncedError::SourceMultisampled);
        }

        if destination.inner().samples() != 1 {
            return Err(CmdBlitImageUnsyncedError::DestinationMultisampled);
        }

        if filter == Filter::Linear && !source.inner().supports_linear_filtering() {
            return Err(CmdBlitImageUnsyncedError::SourceDoesntSupportLinearFilter);
        }

        let raw_regions = {
            let mut raw_regions = SmallVec::new();
            for region in regions {
                // FIXME: check dimensions
                // FIXME: check overlap and document how it works

                raw_regions.push(vk::ImageBlit {
                    srcOffsets: [
                        vk::Offset3D {
                            x: region.source_offset[0] as i32,
                            y: region.source_offset[1] as i32,
                            z: region.source_offset[2] as i32,
                        },
                        vk::Offset3D {
                            x: region.source_offset[0] as i32 + region.source_size[0],
                            y: region.source_offset[1] as i32 + region.source_size[1],
                            z: region.source_offset[2] as i32 + region.source_size[2],
                        },
                    ],
                    srcSubresource: vk::ImageSubresourceLayers {
                        aspectMask: region.aspect as u32,
                        mipLevel: region.source_mipmap,
                        baseArrayLayer: region.source_array_layer,
                        layerCount: region.num_arrays_layers,
                    },
                    dstOffsets: [
                        vk::Offset3D {
                            x: region.destination_offset[0] as i32,
                            y: region.destination_offset[1] as i32,
                            z: region.destination_offset[2] as i32,
                        },
                        vk::Offset3D {
                            x: region.destination_offset[0] as i32 + region.destination_size[0],
                            y: region.destination_offset[1] as i32 + region.destination_size[1],
                            z: region.destination_offset[2] as i32 + region.destination_size[2],
                        },
                    ],
                    dstSubresource: vk::ImageSubresourceLayers {
                        aspectMask: region.aspect as u32,
                        mipLevel: region.destination_mipmap,
                        baseArrayLayer: region.destination_array_layer,
                        layerCount: region.num_arrays_layers,
                    },
                });
            }
            raw_regions
        };

        assert_eq!(source.inner().device().internal_object(),
                   destination.inner().device().internal_object());
        debug_assert!(source_layout == Layout::TransferSrcOptimal ||
                      source_layout == Layout::General);
        debug_assert!(destination_layout == Layout::TransferDstOptimal ||
                      destination_layout == Layout::General);

        let source_raw = source.inner().internal_object();
        let destination_raw = destination.inner().internal_object();

        Ok(CmdBlitImageUnsynced {
            previous: previous,
            source: source,
            source_raw: source_raw,
            source_layout: source_layout as u32,
            destination: destination,
            destination_raw: destination_raw,
            destination_layout: destination_layout as u32,
            filter: filter as vk::Filter,
            regions: raw_regions,
        })
    }
}

impl<L, S, D> CmdBlitImageUnsynced<L, S, D>
    where L: CommandsList, S: Image, D: Image
{
    #[inline]
    fn append<'a>(&'a self, builder: &mut CommandsListSink<'a>) {
        self.previous.append(builder);

        assert_eq!(self.source.inner().device().internal_object(),
                   builder.device().internal_object());

        builder.add_command(Box::new(move |raw: &mut RawCommandBufferPrototype| {
            unsafe {
                let vk = raw.device.pointers();
                let cmd = raw.command_buffer.clone().take().unwrap();
                vk.CmdBlitImage(cmd, self.source_raw, self.source_layout, self.destination_raw,
                                self.destination_layout, self.regions.len() as u32,
                                self.regions.as_ptr(), self.filter);
            }
        }));
    }
}

/// A region of a blit operation.
#[derive(Debug, Copy, Clone)]
pub struct BlitRegion {
    /// Which aspect of the source and destination to blit.
    pub aspect: BlitRegionAspect,
    /// The mipmap of the source image to copy. You can only blit one mipmap at a time.
    pub source_mipmap: u32,
    /// 3D coordinates of the starting pixel in the source image.
    pub source_offset: [u32; 3],
    /// Size of the source area. Can be negative if you want to flip the area.
    pub source_size: [i32; 3],
    /// First array layer of the source image.
    pub source_array_layer: u32,
    /// The mipmap of the destination image to copy. You can only blit one mipmap at a time.
    pub destination_mipmap: u32,
    /// 3D coordinates of the starting pixel in the destination image.
    pub destination_offset: [u32; 3],
    /// Size of the destination area. Can be negative if you want to flip the area.
    pub destination_size: [i32; 3],
    /// First array layer of the destination image.
    pub destination_array_layer: u32,
    /// Number of array layers to blit. Each array layer is blit one by one.
    pub num_arrays_layers: u32,
}

// TODO: maybe we can merge this type with other similar types?
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum BlitRegionAspect {
    Color = vk::IMAGE_ASPECT_COLOR_BIT,
    Depth = vk::IMAGE_ASPECT_DEPTH_BIT,
    Stencil = vk::IMAGE_ASPECT_STENCIL_BIT,
    DepthStencil = vk::IMAGE_ASPECT_DEPTH_BIT | vk::IMAGE_ASPECT_STENCIL_BIT,
}

/// Error that can happen when creating a `CmdBlitImageUnsynced`.
#[derive(Debug, Copy, Clone)]
pub enum CmdBlitImageUnsyncedError {
    /// The source image wasn't created with source transfer operations support.
    SourceUsageMissingSrcTransfer,
    /// The destination image wasn't created with destination transfer operations support.
    DestinationUsageMissingDestTransfer,
    /// The format of the source image doesn't support blit operations.
    SourceFormatDoesntSupportBlits,
    /// The format of the destination image doesn't support blit operations.
    DestinationFormatDoesntSupportBlits,
    /// The format of the source and the destination aren't compatible for blit operations.
    // TODO: link to documentation with these rules:
    // If either of srcImage or dstImage was created with a signed integer VkFormat, the other must also have been created with a signed integer VkFormat
    // If either of srcImage or dstImage was created with an unsigned integer VkFormat, the other must also have been created with an unsigned integer VkFormat
    // If either of srcImage or dstImage was created with a depth/stencil format, the other must have exactly the same format
    IncompatibleSourceDestinationFormats,
    /// The source image must only have one sample.
    SourceMultisampled,
    /// The destination image must only have one sample.
    DestinationMultisampled,
    /// The filter is `Linear` but the source format doesn't support linear filtering.
    SourceDoesntSupportLinearFilter,
}

impl error::Error for CmdBlitImageUnsyncedError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CmdBlitImageUnsyncedError::SourceUsageMissingSrcTransfer => {
                "the source image wasn't created with source transfer operations support"
            },
            CmdBlitImageUnsyncedError::DestinationUsageMissingDestTransfer => {
                "the destination image wasn't created with destination transfer operations support"
            },
            CmdBlitImageUnsyncedError::SourceFormatDoesntSupportBlits => {
                "the format of the source image doesn't support blit operations"
            },
            CmdBlitImageUnsyncedError::DestinationFormatDoesntSupportBlits => {
                "the format of the destination image doesn't support blit operations"
            },
            CmdBlitImageUnsyncedError::IncompatibleSourceDestinationFormats => {
                "the format of the source and the destination aren't compatible for blit operations"
            },
            CmdBlitImageUnsyncedError::SourceMultisampled => {
                "the source image must only have one sample"
            },
            CmdBlitImageUnsyncedError::DestinationMultisampled => {
                "the destination image must only have one sample"
            },
            CmdBlitImageUnsyncedError::SourceDoesntSupportLinearFilter => {
                "the filter is `Linear` but the source format doesn't support linear filtering"
            },
        }
    }
}

impl fmt::Display for CmdBlitImageUnsyncedError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}
<|endoftext|>


<commit_before>use ra_syntax::{
    ast::{self, AstNode},
    TextSize, T,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: remove_dbg
//
// Removes `dbg!()` macro call.
//
// ```
// fn main() {
//     <|>dbg!(92);
// }
// ```
// ->
// ```
// fn main() {
//     92;
// }
// ```
pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;

    if !is_valid_macrocall(&macro_call, "dbg")? {
        return None;
    }

    let macro_range = macro_call.syntax().text_range();

    let macro_content = {
        let macro_args = macro_call.token_tree()?.syntax().clone();

        let text = macro_args.text();
        let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
        text.slice(without_parens).to_string()
    };

    let target = macro_call.syntax().text_range();
    acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| {
        builder.replace(macro_range, macro_content);
    })
}

/// Verifies that the given macro_call actually matches the given name
/// and contains proper ending tokens
fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<bool> {
    let path = macro_call.path()?;
    let name_ref = path.segment()?.name_ref()?;

    // Make sure it is actually a dbg-macro call, dbg followed by !
    let excl = path.syntax().next_sibling_or_token()?;

    if name_ref.text() != macro_name || excl.kind() != T![!] {
        return None;
    }

    let node = macro_call.token_tree()?.syntax().clone();
    let first_child = node.first_child_or_token()?;
    let last_child = node.last_child_or_token()?;

    match (first_child.kind(), last_child.kind()) {
        (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => Some(true),
        _ => Some(false),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    #[test]
    fn test_remove_dbg() {
        check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");

        check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)");

        check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1");

        check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1");

        check_assist(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "
fn foo(n: usize) {
    if let Some(_) = n.checked_sub(4) {
        // ...
    }
}
",
        );
    }
    #[test]
    fn test_remove_dbg_with_brackets_and_braces() {
        check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1");
        check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1");
    }

    #[test]
    fn test_remove_dbg_not_applicable() {
        check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]");
        check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)");
        check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7");
    }

    #[test]
    fn remove_dbg_target() {
        check_assist_target(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "dbg!(n.checked_sub(4))",
        );
    }
}
<commit_msg>Added failing tests<commit_after>use ra_syntax::{
    ast::{self, AstNode},
    TextSize, T,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: remove_dbg
//
// Removes `dbg!()` macro call.
//
// ```
// fn main() {
//     <|>dbg!(92);
// }
// ```
// ->
// ```
// fn main() {
//     92;
// }
// ```
pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;

    if !is_valid_macrocall(&macro_call, "dbg")? {
        return None;
    }

    let macro_range = macro_call.syntax().text_range();

    let macro_content = {
        let macro_args = macro_call.token_tree()?.syntax().clone();

        let text = macro_args.text();
        let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
        text.slice(without_parens).to_string()
    };

    let target = macro_call.syntax().text_range();
    acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| {
        builder.replace(macro_range, macro_content);
    })
}

/// Verifies that the given macro_call actually matches the given name
/// and contains proper ending tokens
fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<bool> {
    let path = macro_call.path()?;
    let name_ref = path.segment()?.name_ref()?;

    // Make sure it is actually a dbg-macro call, dbg followed by !
    let excl = path.syntax().next_sibling_or_token()?;

    if name_ref.text() != macro_name || excl.kind() != T![!] {
        return None;
    }

    let node = macro_call.token_tree()?.syntax().clone();
    let first_child = node.first_child_or_token()?;
    let last_child = node.last_child_or_token()?;

    match (first_child.kind(), last_child.kind()) {
        (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => Some(true),
        _ => Some(false),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    #[test]
    fn test_remove_dbg() {
        check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");

        check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)");

        check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1");

        check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1");

        check_assist(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "
fn foo(n: usize) {
    if let Some(_) = n.checked_sub(4) {
        // ...
    }
}
",
        );
    }
    #[test]
    fn test_remove_dbg_with_brackets_and_braces() {
        check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1");
        check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1");
    }

    #[test]
    fn test_remove_dbg_not_applicable() {
        check_assist_not_applicable(remove_dbg, "<|>vec![1, 2, 3]");
        check_assist_not_applicable(remove_dbg, "<|>dbg(5, 6, 7)");
        check_assist_not_applicable(remove_dbg, "<|>dbg!(5, 6, 7");
    }

    #[test]
    fn remove_dbg_target() {
        check_assist_target(
            remove_dbg,
            "
fn foo(n: usize) {
    if let Some(_) = dbg!(n.<|>checked_sub(4)) {
        // ...
    }
}
",
            "dbg!(n.checked_sub(4))",
        );
    }

    #[test]
    fn remove_dbg_leave_semicolon() {
        // https://github.com/rust-analyzer/rust-analyzer/issues/5129#issuecomment-651399779
        // not quite though
        let code = "
let res = <|>dbg!(1 * 20); // needless comment
";
        let expected = "
let res = 1 * 20; // needless comment
";
        check_assist(remove_dbg, code, expected);
    }

    #[test]
    fn remove_dbg_keep_expression() {
        let code = "
let res = <|>dbg!(a + b).foo();";
        let expected = "let res = (a + b).foo();";
        check_assist(remove_dbg, code, expected);
    }
}
<|endoftext|>


<commit_before>use base::world::{Chunk, ChunkProvider, World};
use super::GameContext;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::mem::replace;
use std::thread;
use std::cell::{Ref, RefCell};
use std::sync::mpsc::{Receiver, Sender, TryRecvError, channel};
use base::world::{CHUNK_SIZE, ChunkIndex};
use base::math::*;
use world::WorldView;
use std::cell::RefMut;

#[derive(Clone)]
pub struct WorldManager {
    shared: Rc<RefCell<Shared>>,
    chunk_requests: Sender<ChunkIndex>,
    context: Rc<GameContext>,
}

struct Shared {
    world: World,
    world_view: WorldView,
    provided_chunks: Receiver<(ChunkIndex, Chunk)>,
    sent_requests: HashSet<ChunkIndex>,
    load_distance: f32,
    player_chunk: ChunkIndex,
}

impl WorldManager {
    pub fn new(provider: Box<ChunkProvider>, game_context: Rc<GameContext>) -> Self {
        // Create two channels to send chunk positions and receive chunks.
        let (chunk_request_sender, chunk_request_recv) = channel();
        let (chunk_sender, chunk_recv) = channel();

        let this = WorldManager {
            shared: Rc::new(RefCell::new(Shared {
                world: World::empty(),
                world_view: WorldView::new(game_context.clone(), provider.get_plant_list()),
                sent_requests: HashSet::new(),
                provided_chunks: chunk_recv,
                // TODO: load this from the config!
                load_distance: 10.0,
                player_chunk: ChunkIndex(AxialPoint::new(0, 0)),
            })),
            chunk_requests: chunk_request_sender,
            context: game_context,
        };

        // Spawn worker thread, which will detach from the main thread. But
        // that is no problem: once the last sender is destroyed, the worker
        // thread will quit.
        thread::spawn(move || {
            worker_thread(provider, chunk_request_recv, chunk_sender);
        });

        this.update_player_chunk();
        this
    }

    /// Called when the player moves to a different chunk.
    ///
    /// This unloads all currently loaded chunks that are too far away from the
    /// player, and loads all chunks close enough to the player (if they aren't
    /// already requested).
    fn update_player_chunk(&self) {
        let mut shared = self.shared.borrow_mut();
        let load_distance = shared.load_distance;
        let player_chunk = shared.player_chunk.0;
        let radius = load_distance as i32;

        let is_chunk_in_range = |chunk_pos: AxialPoint| {
            let chunk_center = chunk_pos * CHUNK_SIZE as i32 +
                               AxialVector::new(CHUNK_SIZE as i32 / 2, CHUNK_SIZE as i32 / 2);
            let player_center = player_chunk * CHUNK_SIZE as i32 +
                                AxialVector::new(CHUNK_SIZE as i32 / 2, CHUNK_SIZE as i32 / 2);
            (chunk_center - player_center).to_real().distance(Vector2f::zero()) <
                load_distance * CHUNK_SIZE as f32
        };

        // Load new range
        for qd in -radius..radius + 1 {
            for rd in -radius..radius + 1 {
                let chunk_pos = AxialPoint::new(player_chunk.q + qd, player_chunk.r + rd);
                if is_chunk_in_range(chunk_pos) {
                    let chunk_index = ChunkIndex(chunk_pos);

                    if !shared.world.chunks.contains_key(&chunk_index) {
                        if !shared.sent_requests.contains(&chunk_index) {
                            self.chunk_requests.send(chunk_index).unwrap();
                            shared.sent_requests.insert(chunk_index);
                        }
                    }
                }
            }
        }

        // Drop unneeded chunks from world
        let chunks = replace(&mut shared.world.chunks, HashMap::new());
        let mut new_chunks = HashMap::new();
        for (index, chunk) in chunks {
            let chunk_pos = index.0;
            if is_chunk_in_range(chunk_pos) {
                // Still in range
                new_chunks.insert(index, chunk);
            } else {
                // Remove
                shared.world_view.remove_chunk(index);
            }
        }
        shared.world.chunks = new_chunks;
    }

    /// Returns an immutable reference to the world.
    ///
    /// *Note*: since the world manager uses a `RefCell` to save the world, a
    /// `Ref` is returned. But thanks to deref coercions you can use it like a
    /// standard reference.
    pub fn get_world(&self) -> Ref<World> {
        Ref::map(self.shared.borrow(), |shared| &shared.world)
    }

    pub fn mut_world(&self) -> RefMut<World> {
        RefMut::map(self.shared.borrow_mut(), |shared| &mut shared.world)
    }

    /// Returns an immutable reference to the world view.
    pub fn get_view(&self) -> Ref<WorldView> {
        Ref::map(self.shared.borrow(), |shared| &shared.world_view)
    }

    /// Returns an mutable reference to the world view.
    pub fn get_mut_view(&self) -> RefMut<WorldView> {
        RefMut::map(self.shared.borrow_mut(), |shared| &mut shared.world_view)
    }

    pub fn get_context(&self) -> &Rc<GameContext> {
        &self.context
    }

    /// Starts to generate all chunks within `load_distance` (config parameter)
    /// around `pos`.
    fn load_world_around(&self, pos: Point2f) {
        let axial_pos = AxialPoint::from_real(pos);
        let chunk_pos = AxialPoint::new(axial_pos.q / CHUNK_SIZE as i32,
                                        axial_pos.r / CHUNK_SIZE as i32);

        let mut shared = self.shared.borrow_mut();
        if shared.player_chunk.0 != chunk_pos {
            shared.player_chunk = ChunkIndex(chunk_pos);
            debug!("player moved to chunk {:?} (player at {:?})",
                   chunk_pos,
                   pos);
            drop(shared);

            self.update_player_chunk();
        }
    }

    /// Applies all queued updated to the actual world. Notably, all generated
    /// chunks are added.
    pub fn update_world(&self, player_pos: Point3f) {
        self.load_world_around(Point2f::new(player_pos.x, player_pos.y));

        let mut shared = self.shared.borrow_mut();
        let mut changed = false;

        loop {
            let (pos, chunk) = match shared.provided_chunks.try_recv() {
                Err(TryRecvError::Empty) => {
                    // No new chunks for us, we will check again next time ;-)
                    break;
                }
                Err(TryRecvError::Disconnected) => {
                    // The worker thread has shut down: this should never happen
                    // thus we can just panic, too.
                    error!("chunk providing worker thread shut down");
                    panic!("chunk providing worker thread shut down");
                }
                Ok(val) => val,
            };

            changed = true;
            shared.world_view.refresh_chunk(pos, &chunk, self.context.get_facade());

            shared.sent_requests.remove(&pos);
            let res = shared.world.add_chunk(pos, chunk);
            if res.is_err() {
                warn!("chunk at {:?} already exists!", pos);
            }
        }

        if changed {
            debug!("{} chunks loaded", shared.world.chunks.len());
        }
    }

    pub fn recalculate_chunk(&mut self, pos: AxialPoint) {
        use std::ops::DerefMut;

        let mut shared_tmp = self.shared.borrow_mut();
        let shared = shared_tmp.deref_mut();

        let chunk_pos = AxialPoint::new(pos.q / CHUNK_SIZE as i32, pos.r / CHUNK_SIZE as i32);
        let index = ChunkIndex(chunk_pos);

        shared.world_view.refresh_chunk(index,
                                        shared.world.chunk_at(index).unwrap(),
                                        self.context.get_facade());
    }
}

fn worker_thread(provider: Box<ChunkProvider>,
                 commands: Receiver<ChunkIndex>,
                 chunks: Sender<(ChunkIndex, Chunk)>) {
    loop {
        let requested_chunk = match commands.recv() {
            Err(_) => {
                // The other side has hung up, so we can stop working, too.
                break;
            }
            Ok(index) => index,
        };

        debug!("chunk provider thread: received request to generate chunk {:?}",
               requested_chunk.0);

        match provider.load_chunk(requested_chunk) {
            Some(chunk) => {
                debug!("chunk provider thread: chunk at {:?} successfully loaded",
                       requested_chunk);
                chunks.send((requested_chunk, chunk)).expect("main thread has hung up");
            }
            None => {
                warn!("chunk provider thread: failed to load chunk at {:?}",
                      requested_chunk)
            }
        }
    }

    info!("chunk provider thread: now stopping ...")
}
<commit_msg>This looks strictly worse than before, thank you rustfmt.<commit_after>use base::world::{Chunk, ChunkProvider, World};
use super::GameContext;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::mem::replace;
use std::thread;
use std::cell::{Ref, RefCell};
use std::sync::mpsc::{Receiver, Sender, TryRecvError, channel};
use base::world::{CHUNK_SIZE, ChunkIndex};
use base::math::*;
use world::WorldView;
use std::cell::RefMut;

#[derive(Clone)]
pub struct WorldManager {
    shared: Rc<RefCell<Shared>>,
    chunk_requests: Sender<ChunkIndex>,
    context: Rc<GameContext>,
}

struct Shared {
    world: World,
    world_view: WorldView,
    provided_chunks: Receiver<(ChunkIndex, Chunk)>,
    sent_requests: HashSet<ChunkIndex>,
    load_distance: f32,
    player_chunk: ChunkIndex,
}

impl WorldManager {
    pub fn new(provider: Box<ChunkProvider>, game_context: Rc<GameContext>) -> Self {
        // Create two channels to send chunk positions and receive chunks.
        let (chunk_request_sender, chunk_request_recv) = channel();
        let (chunk_sender, chunk_recv) = channel();

        let this = WorldManager {
            shared: Rc::new(RefCell::new(Shared {
                world: World::empty(),
                world_view: WorldView::new(game_context.clone(), provider.get_plant_list()),
                sent_requests: HashSet::new(),
                provided_chunks: chunk_recv,
                // TODO: load this from the config!
                load_distance: 10.0,
                player_chunk: ChunkIndex(AxialPoint::new(0, 0)),
            })),
            chunk_requests: chunk_request_sender,
            context: game_context,
        };

        // Spawn worker thread, which will detach from the main thread. But
        // that is no problem: once the last sender is destroyed, the worker
        // thread will quit.
        thread::spawn(move || {
            worker_thread(provider, chunk_request_recv, chunk_sender);
        });

        this.update_player_chunk();
        this
    }

    /// Called when the player moves to a different chunk.
    ///
    /// This unloads all currently loaded chunks that are too far away from the
    /// player, and loads all chunks close enough to the player (if they aren't
    /// already requested).
    fn update_player_chunk(&self) {
        let mut shared = self.shared.borrow_mut();
        let load_distance = shared.load_distance;
        let player_chunk = shared.player_chunk.0;
        let radius = load_distance as i32;

        let is_chunk_in_range = |chunk_pos: AxialPoint| {
            let chunk_center = chunk_pos * CHUNK_SIZE as i32 +
                               AxialVector::new(CHUNK_SIZE as i32 / 2, CHUNK_SIZE as i32 / 2);
            let player_center = player_chunk * CHUNK_SIZE as i32 +
                                AxialVector::new(CHUNK_SIZE as i32 / 2, CHUNK_SIZE as i32 / 2);
            (chunk_center - player_center).to_real().distance(Vector2f::zero()) <
            load_distance * CHUNK_SIZE as f32
        };

        // Load new range
        for qd in -radius..radius + 1 {
            for rd in -radius..radius + 1 {
                let chunk_pos = AxialPoint::new(player_chunk.q + qd, player_chunk.r + rd);
                if is_chunk_in_range(chunk_pos) {
                    let chunk_index = ChunkIndex(chunk_pos);

                    if !shared.world.chunks.contains_key(&chunk_index) {
                        if !shared.sent_requests.contains(&chunk_index) {
                            self.chunk_requests.send(chunk_index).unwrap();
                            shared.sent_requests.insert(chunk_index);
                        }
                    }
                }
            }
        }

        // Drop unneeded chunks from world
        let chunks = replace(&mut shared.world.chunks, HashMap::new());
        let mut new_chunks = HashMap::new();
        for (index, chunk) in chunks {
            let chunk_pos = index.0;
            if is_chunk_in_range(chunk_pos) {
                // Still in range
                new_chunks.insert(index, chunk);
            } else {
                // Remove
                shared.world_view.remove_chunk(index);
            }
        }
        shared.world.chunks = new_chunks;
    }

    /// Returns an immutable reference to the world.
    ///
    /// *Note*: since the world manager uses a `RefCell` to save the world, a
    /// `Ref` is returned. But thanks to deref coercions you can use it like a
    /// standard reference.
    pub fn get_world(&self) -> Ref<World> {
        Ref::map(self.shared.borrow(), |shared| &shared.world)
    }

    pub fn mut_world(&self) -> RefMut<World> {
        RefMut::map(self.shared.borrow_mut(), |shared| &mut shared.world)
    }

    /// Returns an immutable reference to the world view.
    pub fn get_view(&self) -> Ref<WorldView> {
        Ref::map(self.shared.borrow(), |shared| &shared.world_view)
    }

    /// Returns an mutable reference to the world view.
    pub fn get_mut_view(&self) -> RefMut<WorldView> {
        RefMut::map(self.shared.borrow_mut(), |shared| &mut shared.world_view)
    }

    pub fn get_context(&self) -> &Rc<GameContext> {
        &self.context
    }

    /// Starts to generate all chunks within `load_distance` (config parameter)
    /// around `pos`.
    fn load_world_around(&self, pos: Point2f) {
        let axial_pos = AxialPoint::from_real(pos);
        let chunk_pos = AxialPoint::new(axial_pos.q / CHUNK_SIZE as i32,
                                        axial_pos.r / CHUNK_SIZE as i32);

        let mut shared = self.shared.borrow_mut();
        if shared.player_chunk.0 != chunk_pos {
            shared.player_chunk = ChunkIndex(chunk_pos);
            debug!("player moved to chunk {:?} (player at {:?})",
                   chunk_pos,
                   pos);
            drop(shared);

            self.update_player_chunk();
        }
    }

    /// Applies all queued updated to the actual world. Notably, all generated
    /// chunks are added.
    pub fn update_world(&self, player_pos: Point3f) {
        self.load_world_around(Point2f::new(player_pos.x, player_pos.y));

        let mut shared = self.shared.borrow_mut();
        let mut changed = false;

        loop {
            let (pos, chunk) = match shared.provided_chunks.try_recv() {
                Err(TryRecvError::Empty) => {
                    // No new chunks for us, we will check again next time ;-)
                    break;
                }
                Err(TryRecvError::Disconnected) => {
                    // The worker thread has shut down: this should never happen
                    // thus we can just panic, too.
                    error!("chunk providing worker thread shut down");
                    panic!("chunk providing worker thread shut down");
                }
                Ok(val) => val,
            };

            changed = true;
            shared.world_view.refresh_chunk(pos, &chunk, self.context.get_facade());

            shared.sent_requests.remove(&pos);
            let res = shared.world.add_chunk(pos, chunk);
            if res.is_err() {
                warn!("chunk at {:?} already exists!", pos);
            }
        }

        if changed {
            debug!("{} chunks loaded", shared.world.chunks.len());
        }
    }

    pub fn recalculate_chunk(&mut self, pos: AxialPoint) {
        use std::ops::DerefMut;

        let mut shared_tmp = self.shared.borrow_mut();
        let shared = shared_tmp.deref_mut();

        let chunk_pos = AxialPoint::new(pos.q / CHUNK_SIZE as i32, pos.r / CHUNK_SIZE as i32);
        let index = ChunkIndex(chunk_pos);

        shared.world_view.refresh_chunk(index,
                                        shared.world.chunk_at(index).unwrap(),
                                        self.context.get_facade());
    }
}

fn worker_thread(provider: Box<ChunkProvider>,
                 commands: Receiver<ChunkIndex>,
                 chunks: Sender<(ChunkIndex, Chunk)>) {
    loop {
        let requested_chunk = match commands.recv() {
            Err(_) => {
                // The other side has hung up, so we can stop working, too.
                break;
            }
            Ok(index) => index,
        };

        debug!("chunk provider thread: received request to generate chunk {:?}",
               requested_chunk.0);

        match provider.load_chunk(requested_chunk) {
            Some(chunk) => {
                debug!("chunk provider thread: chunk at {:?} successfully loaded",
                       requested_chunk);
                chunks.send((requested_chunk, chunk)).expect("main thread has hung up");
            }
            None => {
                warn!("chunk provider thread: failed to load chunk at {:?}",
                      requested_chunk)
            }
        }
    }

    info!("chunk provider thread: now stopping ...")
}
<|endoftext|>