<commit_before>use dces::prelude::Entity;

use crate::{layout::*, render_object::*};

use super::BuildContext;

/// The `Template` trait is used to implement a particular widget type.
///
/// When a widget's `Template` is implemented, it provides three object types:
/// * a template objet (with default values for its properties, children, handlers)
/// * a render object
/// * a layout object
pub trait Template: Sized {
    /// Builds the template of the widget and returns it.
    ///
    /// # Arguments
    /// * `_id`: The id (Entity) of the instantiated widget in the Entity Store
    /// * `_context`: The BuildContext used to build and instantiate new widgets
    ///
    /// # Example
    /// Define a widget called MyWidget with min, max and val properties with
    /// type of usize, and then set default values and add a TextBlock child.
    ///
    /// ```
    /// widget!(MyWidget {
    ///     min: usize,
    ///     max: usize,
    ///     val: usize
    /// });
    ///
    /// impl Template for MyWidget {
    ///     fn template(self, _id: Entity, context: &mut BuildContext) -> Self {
    ///         self.name("MyWidget")
    ///             .min(100)
    ///             .max(1000)
    ///             .val(500)
    ///             .child(TextBlock::new().text("Set a value!").build(context))
    ///     }
    ///
    ///     fn render_object(&self) -> Box<dyn RenderObject> {
    ///         Box::new(RectangleRenderObject)
    ///     }
    ///
    ///     fn layout(&self) -> Box<dyn Layout> {
    ///        Box::new(AbsoluteLayout)
    ///     }
    /// }
    /// ```
    fn template(self, _id: Entity, _ctx: &mut BuildContext) -> Self {
        self
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// Widgets will be rendered as pixmaps inside the render buffer.
    /// For the list of available render objects, see the
    /// [`render_object`] module.
    ///
    /// [`render_object`]: ../../orbtk_core/render_object/index.html
    fn render_object(&self) -> Box<dyn RenderObject> {
        DefaultRenderObject.into()
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// The `layout` process will arrange all `box` entities of a widget
    /// in a tree, were size properties will meet the individual constraints.
    /// For the list of available layout objects, see
    /// the [`layout`] module.
    ///
    /// [`layout`]: ../../orbtk_core/layout/index.html
    fn layout(&self) -> Box<dyn Layout> {
        GridLayout::new().into()
    }
}
<commit_msg>orbtk_core: widget_base: document MyWidget example<commit_after>use dces::prelude::Entity;

use crate::{layout::*, render_object::*};

use super::BuildContext;

/// The `Template` trait is used to implement a particular widget type.
///
/// When a widget's `Template` is implemented, it provides three object types:
/// * a template objet (with default values for its properties, children, handlers)
/// * a render object
/// * a layout object
pub trait Template: Sized {
    /// Builds the template of the widget and returns it.
    ///
    /// # Arguments
    /// * `_id`: The id (Entity) of the instantiated widget in the Entity Store
    /// * `_context`: The BuildContext used to build and instantiate new widgets
    ///
    /// # Example
    ///
    /// Define a widget called MyWidget with min, max and val
    /// properties. The properties have a type of `usize` and we do
    /// preset suitable default values. The definition is completed
    /// with a TextBlock widget, that is the only child.
    ///
    /// ```rust
    /// widget!(MyWidget {
    ///     min: usize,
    ///     max: usize,
    ///     val: usize
    /// });
    ///
    /// impl Template for MyWidget {
    ///     fn template(self, _id: Entity, context: &mut BuildContext) -> Self {
    ///         self.name("MyWidget")
    ///             .min(100)
    ///             .max(1000)
    ///             .val(500)
    ///             .child(TextBlock::new().text("Set a value!").build(context))
    ///     }
    ///
    ///     fn render_object(&self) -> Box<dyn RenderObject> {
    ///         Box::new(RectangleRenderObject)
    ///     }
    ///
    ///     fn layout(&self) -> Box<dyn Layout> {
    ///        Box::new(AbsoluteLayout)
    ///     }
    /// }
    /// ```
    fn template(self, _id: Entity, _ctx: &mut BuildContext) -> Self {
        self
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// Widgets will be rendered as pixmaps inside the render buffer.
    /// For the list of available render objects, see the
    /// [`render_object`] module.
    ///
    /// [`render_object`]: ../../orbtk_core/render_object/index.html
    fn render_object(&self) -> Box<dyn RenderObject> {
        DefaultRenderObject.into()
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// The `layout` process will arrange all `box` entities of a widget
    /// in a tree, were size properties will meet the individual constraints.
    /// For the list of available layout objects, see
    /// the [`layout`] module.
    ///
    /// [`layout`]: ../../orbtk_core/layout/index.html
    fn layout(&self) -> Box<dyn Layout> {
        GridLayout::new().into()
    }
}
<|endoftext|>


<commit_before>use cocoa::base::id;
use std::borrow::Cow;
use {CompareFunction, Device, StencilDescriptor};

pub struct DepthStencilState(id);

impl DepthStencilState {
    pub fn device(&self) -> &Device {
        unimplemented!();
    }

    pub fn label(&self) -> Cow<str> {
        unimplemented!();
    }

    pub fn set_label(&mut self, label: &str) {
        unimplemented!();
    }
}

impl_from_into_raw!(DepthStencilState, of protocol "MTLDepthStencilState");

pub struct DepthStencilStateDescriptor(id);

impl DepthStencilStateDescriptor {
    pub fn depth_compare_function(&self) -> CompareFunction {
        unimplemented!();
    }

    pub fn set_depth_compare_function(&mut self, compare_function: CompareFunction) {
        unimplemented!();
    }

    pub fn depth_write_enabled(&self) -> bool {
        unimplemented!();
    }

    pub fn set_depth_write_enabled(&mut self, depth_write_enabled: bool) {
        unimplemented!();
    }

    pub fn back_face_stencil(&self) -> StencilDescriptor {
        unimplemented!();
    }

    pub fn set_back_face_stencil(&mut self, back_face_stencil: StencilDescriptor) {
        unimplemented!();
    }

    pub fn front_face_stencil(&self) -> StencilDescriptor {
        unimplemented!();
    }

    pub fn set_front_face_stencil(&mut self, front_face_stencil: StencilDescriptor) {
        unimplemented!();
    }

    pub fn label(&self) -> Cow<str> {
        unimplemented!();
    }

    pub fn set_label(&mut self, label: &str) {
        unimplemented!();
    }
}
<commit_msg>Add allow(unused_variables) to some functions to silence warnings<commit_after>use cocoa::base::id;
use std::borrow::Cow;
use {CompareFunction, Device, StencilDescriptor};

pub struct DepthStencilState(id);

impl DepthStencilState {
    pub fn device(&self) -> &Device {
        unimplemented!();
    }

    pub fn label(&self) -> Cow<str> {
        unimplemented!();
    }

    #[allow(unused_variables)]
    pub fn set_label(&mut self, label: &str) {
        unimplemented!();
    }
}

impl_from_into_raw!(DepthStencilState, of protocol "MTLDepthStencilState");

pub struct DepthStencilStateDescriptor(id);

impl DepthStencilStateDescriptor {
    pub fn depth_compare_function(&self) -> CompareFunction {
        unimplemented!();
    }

    #[allow(unused_variables)]
    pub fn set_depth_compare_function(&mut self, compare_function: CompareFunction) {
        unimplemented!();
    }

    pub fn depth_write_enabled(&self) -> bool {
        unimplemented!();
    }

    #[allow(unused_variables)]
    pub fn set_depth_write_enabled(&mut self, depth_write_enabled: bool) {
        unimplemented!();
    }

    pub fn back_face_stencil(&self) -> StencilDescriptor {
        unimplemented!();
    }

    #[allow(unused_variables)]
    pub fn set_back_face_stencil(&mut self, back_face_stencil: StencilDescriptor) {
        unimplemented!();
    }

    pub fn front_face_stencil(&self) -> StencilDescriptor {
        unimplemented!();
    }

    #[allow(unused_variables)]
    pub fn set_front_face_stencil(&mut self, front_face_stencil: StencilDescriptor) {
        unimplemented!();
    }

    pub fn label(&self) -> Cow<str> {
        unimplemented!();
    }

    #[allow(unused_variables)]
    pub fn set_label(&mut self, label: &str) {
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>use super::super::shape::shape::Shape::{CircleShape, ChainLineShape};
use super::super::body::Body;
use super::super::math::Vec2;
use super::super::manifold::Manifold;
use super::collider::Collider;
use super::collider_result::ColliderResult;

pub struct CircleChainLineCollider {
    pair: (Body, Body)
}

impl Collider for CircleChainLineCollider {
    fn new(pair: (Body, Body)) -> CircleChainLineCollider {
        return CircleChainLineCollider{ pair: pair }
    }

    fn pair(&self) -> (Body, Body) {
        return self.pair.clone();
    }

    fn colliding(&self) -> ColliderResult {
        let circle_shape = self.pair().0.shape;
        let chain_line_shape = self.pair().1.shape;

        match (circle_shape, chain_line_shape) {
            (CircleShape{center, radius}, ChainLineShape{points}) => {
                let global_circle_center = self.pair().0.position + center;
                let mut closest_line_distance = Vec2::new(0.0, 0.0);

                for i in 0..(points.len()-1) {
                    let global_point1 = points[i] + self.pair().1.position;
                    let global_point2 = points[i+1] + self.pair().1.position;

                    let segment_vector = global_point1 - global_point2;
                    let mut point_vector = global_circle_center - global_point2;

                    let scalar_projection = point_vector.dot(segment_vector.normal());

                    let mut closest_point = Vec2::new(0.0, 0.0);

                    if scalar_projection < 0.0 {
                        closest_point = global_point2;
                    } else if scalar_projection > segment_vector.length() {
                        closest_point = global_point1;
                    } else {
                        closest_point = global_point2 + segment_vector.normal().multiply(scalar_projection);
                    }

                    let distance_vector = global_circle_center - closest_point;

                    if i == 0 || distance_vector.length() > closest_line_distance.length() {
                        closest_line_distance = distance_vector;
                    }
                }

                if closest_line_distance.length() < radius {
                    let offset = closest_line_distance.normal().multiply((radius - closest_line_distance.length()));
                    let mut manifold = Manifold{body_a: self.pair().0, body_b: self.pair().1, normal: Vec2::new(0.0, 0.0), penetration: 0.0};
                    manifold.normal = offset.normal();
                    manifold.penetration = offset.length();
                    return ColliderResult::new(Some(manifold), true);
                }

                return ColliderResult::new_empty_false();
            },
            _ => {
                panic!("Something happened. Cannot test circle to chain line collision without circle and chain line!!!");
            }
        }
    }
}
<commit_msg>Fixing circle chain collider bug where the clostest line distance isn't found<commit_after>use super::super::shape::shape::Shape::{CircleShape, ChainLineShape};
use super::super::body::Body;
use super::super::math::Vec2;
use super::super::manifold::Manifold;
use super::collider::Collider;
use super::collider_result::ColliderResult;

pub struct CircleChainLineCollider {
    pair: (Body, Body)
}

impl Collider for CircleChainLineCollider {
    fn new(pair: (Body, Body)) -> CircleChainLineCollider {
        return CircleChainLineCollider{ pair: pair }
    }

    fn pair(&self) -> (Body, Body) {
        return self.pair.clone();
    }

    fn colliding(&self) -> ColliderResult {
        let circle_shape = self.pair().0.shape;
        let chain_line_shape = self.pair().1.shape;

        match (circle_shape, chain_line_shape) {
            (CircleShape{center, radius}, ChainLineShape{points}) => {
                let global_circle_center = self.pair().0.position + center;
                let mut closest_line_distance = Vec2::new(0.0, 0.0);

                for i in 0..(points.len()-1) {
                    let global_point1 = points[i] + self.pair().1.position;
                    let global_point2 = points[i+1] + self.pair().1.position;

                    let segment_vector = global_point1 - global_point2;
                    let mut point_vector = global_circle_center - global_point2;

                    let scalar_projection = point_vector.dot(segment_vector.normal());

                    let mut closest_point = Vec2::new(0.0, 0.0);

                    if scalar_projection < 0.0 {
                        closest_point = global_point2;
                    } else if scalar_projection > segment_vector.length() {
                        closest_point = global_point1;
                    } else {
                        closest_point = global_point2 + segment_vector.normal().multiply(scalar_projection);
                    }

                    let distance_vector = global_circle_center - closest_point;

                    if i == 0 || distance_vector.length() < closest_line_distance.length() {
                        closest_line_distance = distance_vector;
                    }
                }

                if closest_line_distance.length() < radius {
                    let offset = closest_line_distance.normal().multiply((radius - closest_line_distance.length()));
                    let mut manifold = Manifold{body_a: self.pair().0, body_b: self.pair().1, normal: Vec2::new(0.0, 0.0), penetration: 0.0};
                    manifold.normal = offset.normal();
                    manifold.penetration = offset.length();
                    return ColliderResult::new(Some(manifold), true);
                }

                return ColliderResult::new_empty_false();
            },
            _ => {
                panic!("Something happened. Cannot test circle to chain line collision without circle and chain line!!!");
            }
        }
    }
}
<|endoftext|>


<commit_before>extern mod png;

use std::num::{sqrt, min, max, cos, sin};

static WIDTH: int = 800;
static HEIGHT: int = 800;

struct Color {
  r: u8,
  g: u8,
  b: u8
}

static Red: Color = Color { r: 255, g: 0, b: 0 };
static Green: Color = Color { r: 0, g: 255, b: 0 };
static Blue: Color = Color { r: 0, g: 0, b: 255 };
static White: Color = Color { r: 255, g: 255, b: 255 };
static Black: Color = Color { r: 0, g: 0, b: 0 };

struct Point {
  x: f64,
  y: f64,
  z: f64
}

struct Spot {
  pos: Point,
  color: Color,
}

struct Scene {
  eye: Point,
  spot: Spot,
  sphere: Sphere
}

fn solve_poly(a: f64, b: f64, c: f64) -> f64 {
  let delta = b.pow(&2.0) - 4. * a * c;

  if delta < 0. {
    return 0.;
  }

  let sign = match c {
    _ if c < 0. => 1.,
    _ => -1.
  };
  let k = (-b + sign * sqrt(delta)) / (2. * a);
  return match k {
    _ if k > 0. => k,
    _ => 0.
  }
}

trait Shape {
  fn hit(&self, eye: &Point, vector: &Point) -> f64;
  fn get_perp(&self, inter: &Point) -> ~Point;
}

struct Sphere {
  pos: Point,
  radius: f64,
  shininess: f64,
  color: Color
}

impl Shape for Sphere {
  fn hit(&self, eye: &Point, vector: &Point) -> f64 {
    let a = vector.x.pow(&2.) + vector.y.pow(&2.) + vector.z.pow(&2.);
    let b = 2. * (eye.x * vector.x + eye.y * vector.y + eye.z * vector.z);
    let c = eye.x.pow(&2.) + eye.y.pow(&2.) + eye.z.pow(&2.) - self.radius.pow(&2.);
    return solve_poly(a, b, c);
  }

  fn get_perp(&self, inter: &Point) -> ~Point {
    ~Point { x: inter.x, y: inter.y, z: inter.z }
  }
}

fn get_closest(obj: &Sphere, eye: &Point, vector: &Point) -> f64 {
  let e = ~Point { x: eye.x - obj.pos.x, y: eye.y - obj.pos.y, z: eye.z - obj.pos.z };
  let v = ~Point { x: vector.x, y: vector.y, z: vector.z };
  return obj.hit(e, v);
}

fn get_light(obj: &Sphere, spot: &Spot, inter: &Point, light: &Point) -> Color {
  let perp = obj.get_perp(inter);
  let norme_l = sqrt(light.x.pow(&2.) + light.y.pow(&2.) + light.z.pow(&2.));
  let norme_n = sqrt(perp.x.pow(&2.) + perp.y.pow(&2.) + perp.z.pow(&2.));
  let cos_a = (light.x * perp.x + light.y * perp.y + light.z * perp.z) / (norme_l * norme_n);

  if cos_a <= 0. {
    return Black;
  }

  Color {
    r: ((obj.color.r as f64) * cos_a * (1. - obj.shininess) + (spot.color.r as f64) * cos_a * obj.shininess) as u8,
    g: ((obj.color.g as f64) * cos_a * (1. - obj.shininess) + (spot.color.g as f64) * cos_a * obj.shininess) as u8,
    b: ((obj.color.b as f64) * cos_a * (1. - obj.shininess) + (spot.color.b as f64) * cos_a * obj.shininess) as u8
  }
}

fn main() {
  let mut pixels = ~[Black, ..((WIDTH * HEIGHT) as uint)];

  let eye = ~Point { x: -300., y: 0., z: 200. };
  let spot = ~Spot {
    pos: Point { x: -300., y: 100., z: 200. },
    color: White
  };
  let sphere = ~Sphere {
    pos: Point { x: 0., y: 0., z: 100. },
    radius: 160.,
    shininess: 0.2,
    color: Red
  };

  for x in range(0, WIDTH) {
    for y in range(0, HEIGHT) {
      let vector = ~Point {
        x: 100.,
        y: (WIDTH / 2 - x) as f64,
        z: (HEIGHT / 2 - y) as f64
      };

      let closest = get_closest(sphere, eye, vector);

      // // Shadow
      // let inter = Point {
      //   x: eye.x + closest * vector.x,
      //   y: eye.y + closest * vector.y,
      //   z: eye.z + closest * vector.z
      // };
      // let light = Point {
      //   x: spot.pos.x - inter.x,
      //   y: spot.pos.y - inter.y,
      //   z: spot.pos.z - inter.z
      // };

      let inter = ~Point {
        x: (eye.x - sphere.pos.x) + closest * vector.x,
        y: (eye.y - sphere.pos.y) + closest * vector.y,
        z: (eye.z - sphere.pos.z) + closest * vector.z
      };
      let light = ~Point {
        x: spot.pos.x - inter.x,
        y: spot.pos.y - inter.y,
        z: spot.pos.z - inter.z
      };

      pixels[y * WIDTH + x] = match closest {
        0. => Black,
        _ => get_light(sphere, spot, inter, light)
      }
    }
  }

  let img = png::Image {
    width: WIDTH as u32,
    height: HEIGHT as u32,
    color_type: png::RGB8,
    pixels: pixels.flat_map(|&Color { r, g, b }| { ~[r, g, b] })
  };

  png::store_png(&img, &Path::new("out.png"));
}
<commit_msg>Moar structs !<commit_after>extern mod png;

use std::num::{sqrt, min, max, cos, sin};

static WIDTH: int = 800;
static HEIGHT: int = 800;

struct Color {
  r: u8,
  g: u8,
  b: u8
}

static Red: Color = Color { r: 255, g: 0, b: 0 };
static Green: Color = Color { r: 0, g: 255, b: 0 };
static Blue: Color = Color { r: 0, g: 0, b: 255 };
static White: Color = Color { r: 255, g: 255, b: 255 };
static Black: Color = Color { r: 0, g: 0, b: 0 };

struct Point {
  x: f64,
  y: f64,
  z: f64
}

struct Spot {
  pos: Point,
  color: Color,
}

struct Scene {
  eye: Point,
  spot: Spot,
  objects: ~[Shape]
}

fn solve_poly(a: f64, b: f64, c: f64) -> f64 {
  let delta = b.pow(&2.0) - 4. * a * c;

  if delta < 0. {
    return 0.;
  }

  let sign = match c {
    _ if c < 0. => 1.,
    _ => -1.
  };
  let k = (-b + sign * sqrt(delta)) / (2. * a);
  return match k {
    _ if k > 0. => k,
    _ => 0.
  }
}

trait Drawable {
  fn hit(&self, eye: &Point, vector: &Point) -> f64;
  fn perp(&self, inter: &Point) -> ~Point;
}

struct Shape {
  pos: Point,
  shininess: f64,
  color: Color,
  shape: ~Drawable
}

impl Shape {
  fn get_light(&self, spot: &Spot, inter: &Point, light: &Point) -> Color {
    let perp = self.shape.perp(inter);
    let norme_l = sqrt(light.x.pow(&2.) + light.y.pow(&2.) + light.z.pow(&2.));
    let norme_n = sqrt(perp.x.pow(&2.) + perp.y.pow(&2.) + perp.z.pow(&2.));
    let cos_a = (light.x * perp.x + light.y * perp.y + light.z * perp.z) / (norme_l * norme_n);

    if cos_a <= 0. {
      return Black;
    }

    Color {
      r: ((self.color.r as f64) * cos_a * (1. - self.shininess) + (spot.color.r as f64) * cos_a * self.shininess) as u8,
      g: ((self.color.g as f64) * cos_a * (1. - self.shininess) + (spot.color.g as f64) * cos_a * self.shininess) as u8,
      b: ((self.color.b as f64) * cos_a * (1. - self.shininess) + (spot.color.b as f64) * cos_a * self.shininess) as u8
    }
  }
}

struct Sphere {
  radius: f64,
}

impl Drawable for Sphere {
  fn hit(&self, eye: &Point, vector: &Point) -> f64 {
    let a = vector.x.pow(&2.) + vector.y.pow(&2.) + vector.z.pow(&2.);
    let b = 2. * (eye.x * vector.x + eye.y * vector.y + eye.z * vector.z);
    let c = eye.x.pow(&2.) + eye.y.pow(&2.) + eye.z.pow(&2.) - self.radius.pow(&2.);
    return solve_poly(a, b, c);
  }

  fn perp(&self, inter: &Point) -> ~Point {
    ~Point { x: inter.x, y: inter.y, z: inter.z }
  }
}

impl Scene {
  fn get_closest<'a>(&'a self, vector: &'a Point) -> (Option<&'a Shape>, f64) {
    let mut min: f64 = 0.;
    let mut closest: Option<&'a Shape> = None;

    for obj in self.objects.iter() {
      let e = Point { x: self.eye.x - obj.pos.x, y: self.eye.y - obj.pos.y, z: self.eye.z - obj.pos.z };
      let v = Point { x: vector.x, y: vector.y, z: vector.z };
      let k = obj.shape.hit(&e, &v);
      if k != 0. && (min == 0. || k < min) {
        min = k;
        closest = Some(obj);
      }
    }

    return (closest, min);
  }
}

fn main() {
  let mut pixels = ~[Black, ..((WIDTH * HEIGHT) as uint)];

  let scene = ~Scene {
    eye: Point { x: -300., y: 0., z: 200. },
    spot: Spot {
      pos: Point { x: -300., y: 100., z: 200. },
      color: White
    },
    objects: ~[
      Shape {
        pos: Point { x: 0., y: 0., z: 100. },
        shininess: 0.2,
        color: Red,
        shape: ~Sphere { radius: 160. }
      },
    ]
  };

  for x in range(0, WIDTH) {
    for y in range(0, HEIGHT) {
      let vector = ~Point {
        x: 100.,
        y: (WIDTH / 2 - x) as f64,
        z: (HEIGHT / 2 - y) as f64
      };

      let (obj, k) = scene.get_closest(vector);

      if obj.is_none() {
        pixels[y * WIDTH + x] = Black;
      }
      else {
        let closest = obj.unwrap();

        // // Shadow
        // let inter = Point {
        //   x: eye.x + closest * vector.x,
        //   y: eye.y + closest * vector.y,
        //   z: eye.z + closest * vector.z
        // };
        // let light = Point {
        //   x: spot.pos.x - inter.x,
        //   y: spot.pos.y - inter.y,
        //   z: spot.pos.z - inter.z
        // };

        let inter = ~Point {
          x: (scene.eye.x - closest.pos.x) + k * vector.x,
          y: (scene.eye.y - closest.pos.y) + k * vector.y,
          z: (scene.eye.z - closest.pos.z) + k * vector.z
        };
        let light = ~Point {
          x: scene.spot.pos.x - inter.x,
          y: scene.spot.pos.y - inter.y,
          z: scene.spot.pos.z - inter.z
        };

        pixels[y * WIDTH + x] = match k {
          0. => Black,
          _ => closest.get_light(&scene.spot, inter, light)
        }
      }
    }
  }

  let img = png::Image {
    width: WIDTH as u32,
    height: HEIGHT as u32,
    color_type: png::RGB8,
    pixels: pixels.flat_map(|&Color { r, g, b }| { ~[r, g, b] })
  };

  png::store_png(&img, &Path::new("out.png"));
}
<|endoftext|>


<commit_before>use hir::HirDisplay;
use syntax::{ast, AstNode, SyntaxToken, TextSize};
use test_utils::mark;

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

// Assist: infer_function_return_type
//
// Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return
// type specified.
//
// ```
// fn foo() { 4<|>2i32 }
// ```
// ->
// ```
// fn foo() -> i32 { 42i32 }
// ```
pub(crate) fn infer_function_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let expr = ctx.find_node_at_offset::<ast::Expr>()?;
    let (tail_expr, insert_pos, wrap_expr) = extract_tail(expr)?;
    let module = ctx.sema.scope(tail_expr.syntax()).module()?;
    let ty = ctx.sema.type_of_expr(&tail_expr).filter(|ty| !ty.is_unit())?;
    let ty = ty.display_source_code(ctx.db(), module.into()).ok()?;

    acc.add(
        AssistId("infer_function_return_type", AssistKind::RefactorRewrite),
        "Add this function's return type",
        tail_expr.syntax().text_range(),
        |builder| {
            let insert_pos = insert_pos.text_range().end() + TextSize::from(1);
            builder.insert(insert_pos, &format!("-> {} ", ty));
            if wrap_expr {
                mark::hit!(wrap_closure_non_block_expr);
                // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
                builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
            }
        },
    )
}

fn extract_tail(expr: ast::Expr) -> Option<(ast::Expr, SyntaxToken, bool)> {
    let (ret_ty, tail_expr, insert_pos, wrap_expr) =
        if let Some(closure) = expr.syntax().ancestors().find_map(ast::ClosureExpr::cast) {
            let (tail_expr, wrap_expr) = match closure.body()? {
                ast::Expr::BlockExpr(block) => (block.expr()?, false),
                body => (body, true),
            };
            let ret_ty = closure.ret_type();
            let rpipe = closure.param_list()?.syntax().last_token()?;
            (ret_ty, tail_expr, rpipe, wrap_expr)
        } else {
            let func = expr.syntax().ancestors().find_map(ast::Fn::cast)?;
            let tail_expr = func.body()?.expr()?;
            let ret_ty = func.ret_type();
            let rparen = func.param_list()?.r_paren_token()?;
            (ret_ty, tail_expr, rparen, false)
        };
    if ret_ty.is_some() {
        mark::hit!(existing_ret_type);
        mark::hit!(existing_ret_type_closure);
        return None;
    }
    // check whether the expr we were at is indeed the tail expression
    if !tail_expr.syntax().text_range().contains_range(expr.syntax().text_range()) {
        mark::hit!(not_tail_expr);
        return None;
    }
    Some((tail_expr, insert_pos, wrap_expr))
}

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

    use super::*;

    #[test]
    fn infer_return_type() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                45<|>
            }"#,
            r#"fn foo() -> i32 {
                45
            }"#,
        );
    }

    #[test]
    fn infer_return_type_nested() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                if true {
                    3<|>
                } else {
                    5
                }
            }"#,
            r#"fn foo() -> i32 {
                if true {
                    3
                } else {
                    5
                }
            }"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified() {
        mark::check!(existing_ret_type);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() -> i32 {
                ( 45<|> + 32 ) * 123
            }"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr() {
        mark::check!(not_tail_expr);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                let x = <|>3;
                ( 45 + 32 ) * 123
            }"#,
        );
    }

    #[test]
    fn not_applicable_unit_return_type() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                (<|>)
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure_block() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| {
                    x<|>
                };
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 {
                    x
                };
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| { x<|> };
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 { x };
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure_wrap() {
        mark::check!(wrap_closure_non_block_expr);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| x<|>;
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 {x};
            }"#,
        );
    }

    #[test]
    fn infer_return_type_nested_closure() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                || {
                    if true {
                        3<|>
                    } else {
                        5
                    }
                }
            }"#,
            r#"fn foo() {
                || -> i32 {
                    if true {
                        3
                    } else {
                        5
                    }
                }
            }"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified_closure() {
        mark::check!(existing_ret_type_closure);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                || -> i32 { 3<|> }
            }"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr_closure() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                || -> i32 {
                    let x = 3<|>;
                    6
                }
            }"#,
        );
    }
}
<commit_msg>Enable infer_function_return_type in return-type position<commit_after>use hir::HirDisplay;
use syntax::{ast, AstNode, TextRange, TextSize};
use test_utils::mark;

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

// Assist: infer_function_return_type
//
// Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return
// type specified. This assists is useable in a functions or closures tail expression or return type position.
//
// ```
// fn foo() { 4<|>2i32 }
// ```
// ->
// ```
// fn foo() -> i32 { 42i32 }
// ```
pub(crate) fn infer_function_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let (tail_expr, builder_edit_pos, wrap_expr) = extract_tail(ctx)?;
    let module = ctx.sema.scope(tail_expr.syntax()).module()?;
    let ty = ctx.sema.type_of_expr(&tail_expr)?;
    if ty.is_unit() {
        return None;
    }
    let ty = ty.display_source_code(ctx.db(), module.into()).ok()?;

    acc.add(
        AssistId("infer_function_return_type", AssistKind::RefactorRewrite),
        "Add this function's return type",
        tail_expr.syntax().text_range(),
        |builder| {
            match builder_edit_pos {
                InsertOrReplace::Insert(insert_pos) => {
                    builder.insert(insert_pos, &format!("-> {} ", ty))
                }
                InsertOrReplace::Replace(text_range) => {
                    builder.replace(text_range, &format!("-> {}", ty))
                }
            }
            if wrap_expr {
                mark::hit!(wrap_closure_non_block_expr);
                // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
                builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
            }
        },
    )
}

enum InsertOrReplace {
    Insert(TextSize),
    Replace(TextRange),
}

/// Check the potentially already specified return type and reject it or turn it into a builder command
/// if allowed.
fn ret_ty_to_action(ret_ty: Option<ast::RetType>, insert_pos: TextSize) -> Option<InsertOrReplace> {
    match ret_ty {
        Some(ret_ty) => match ret_ty.ty() {
            Some(ast::Type::InferType(_)) | None => {
                mark::hit!(existing_infer_ret_type);
                mark::hit!(existing_infer_ret_type_closure);
                Some(InsertOrReplace::Replace(ret_ty.syntax().text_range()))
            }
            _ => {
                mark::hit!(existing_ret_type);
                mark::hit!(existing_ret_type_closure);
                None
            }
        },
        None => Some(InsertOrReplace::Insert(insert_pos + TextSize::from(1))),
    }
}

fn extract_tail(ctx: &AssistContext) -> Option<(ast::Expr, InsertOrReplace, bool)> {
    let (tail_expr, return_type_range, action, wrap_expr) =
        if let Some(closure) = ctx.find_node_at_offset::<ast::ClosureExpr>() {
            let rpipe_pos = closure.param_list()?.syntax().last_token()?.text_range().end();
            let action = ret_ty_to_action(closure.ret_type(), rpipe_pos)?;

            let body = closure.body()?;
            let body_start = body.syntax().first_token()?.text_range().start();
            let (tail_expr, wrap_expr) = match body {
                ast::Expr::BlockExpr(block) => (block.expr()?, false),
                body => (body, true),
            };

            let ret_range = TextRange::new(rpipe_pos, body_start);
            (tail_expr, ret_range, action, wrap_expr)
        } else {
            let func = ctx.find_node_at_offset::<ast::Fn>()?;
            let rparen_pos = func.param_list()?.r_paren_token()?.text_range().end();
            let action = ret_ty_to_action(func.ret_type(), rparen_pos)?;

            let body = func.body()?;
            let tail_expr = body.expr()?;

            let ret_range_end = body.l_curly_token()?.text_range().start();
            let ret_range = TextRange::new(rparen_pos, ret_range_end);
            (tail_expr, ret_range, action, false)
        };
    let frange = ctx.frange.range;
    if return_type_range.contains_range(frange) {
        mark::hit!(cursor_in_ret_position);
        mark::hit!(cursor_in_ret_position_closure);
    } else if tail_expr.syntax().text_range().contains_range(frange) {
        mark::hit!(cursor_on_tail);
        mark::hit!(cursor_on_tail_closure);
    } else {
        return None;
    }
    Some((tail_expr, action, wrap_expr))
}

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

    use super::*;

    #[test]
    fn infer_return_type_specified_inferred() {
        mark::check!(existing_infer_ret_type);
        check_assist(
            infer_function_return_type,
            r#"fn foo() -> <|>_ {
                45
            }"#,
            r#"fn foo() -> i32 {
                45
            }"#,
        );
    }

    #[test]
    fn infer_return_type_specified_inferred_closure() {
        mark::check!(existing_infer_ret_type_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                || -> _ {<|>45};
            }"#,
            r#"fn foo() {
                || -> i32 {45};
            }"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos() {
        mark::check!(cursor_in_ret_position);
        check_assist(
            infer_function_return_type,
            r#"fn foo() <|>{
                45
            }"#,
            r#"fn foo() -> i32 {
                45
            }"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos_closure() {
        mark::check!(cursor_in_ret_position_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                || <|>45
            }"#,
            r#"fn foo() {
                || -> i32 {45}
            }"#,
        );
    }

    #[test]
    fn infer_return_type() {
        mark::check!(cursor_on_tail);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                45<|>
            }"#,
            r#"fn foo() -> i32 {
                45
            }"#,
        );
    }

    #[test]
    fn infer_return_type_nested() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                if true {
                    3<|>
                } else {
                    5
                }
            }"#,
            r#"fn foo() -> i32 {
                if true {
                    3
                } else {
                    5
                }
            }"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified() {
        mark::check!(existing_ret_type);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() -> i32 {
                ( 45<|> + 32 ) * 123
            }"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                let x = <|>3;
                ( 45 + 32 ) * 123
            }"#,
        );
    }

    #[test]
    fn not_applicable_unit_return_type() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                (<|>)
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure_block() {
        mark::check!(cursor_on_tail_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| {
                    x<|>
                };
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 {
                    x
                };
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| { x<|> };
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 { x };
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure_wrap() {
        mark::check!(wrap_closure_non_block_expr);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| x<|>;
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 {x};
            }"#,
        );
    }

    #[test]
    fn infer_return_type_nested_closure() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                || {
                    if true {
                        3<|>
                    } else {
                        5
                    }
                }
            }"#,
            r#"fn foo() {
                || -> i32 {
                    if true {
                        3
                    } else {
                        5
                    }
                }
            }"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified_closure() {
        mark::check!(existing_ret_type_closure);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                || -> i32 { 3<|> }
            }"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr_closure() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                || -> i32 {
                    let x = 3<|>;
                    6
                }
            }"#,
        );
    }
}
<|endoftext|>


<commit_before>use ra_syntax::{
    ast::{self, AstNode},
    SyntaxKind::WHITESPACE,
    SyntaxNode, TextUnit,
};

use crate::assists::{AssistCtx, Assist};

pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option<Assist> {
    let node = ctx.covering_node();
    let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;

    let anchor_stmt = anchor_stmt(expr)?;
    let indent = anchor_stmt.prev_sibling()?;
    if indent.kind() != WHITESPACE {
        return None;
    }
    ctx.build("introduce variable", move |edit| {
        let mut buf = String::new();

        buf.push_str("let var_name = ");
        expr.syntax().text().push_to(&mut buf);
        let full_stmt = ast::ExprStmt::cast(anchor_stmt);
        let is_full_stmt = if let Some(expr_stmt) = full_stmt {
            Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
        } else {
            false
        };
        if is_full_stmt {
            if !full_stmt.unwrap().has_semi() {
                buf.push_str(";");
            }
            edit.replace(expr.syntax().range(), buf);
        } else {
            buf.push_str(";");
            indent.text().push_to(&mut buf);
            edit.replace(expr.syntax().range(), "var_name".to_string());
            edit.insert(anchor_stmt.range().start(), buf);
        }
        edit.set_cursor(anchor_stmt.range().start() + TextUnit::of_str("let "));
    })
}

/// Statement or last in the block expression, which will follow
/// the freshly introduced var.
fn anchor_stmt(expr: &ast::Expr) -> Option<&SyntaxNode> {
    expr.syntax().ancestors().find(|&node| {
        if ast::Stmt::cast(node).is_some() {
            return true;
        }
        if let Some(expr) = node
            .parent()
            .and_then(ast::Block::cast)
            .and_then(|it| it.expr())
        {
            if expr.syntax() == node {
                return true;
            }
        }
        false
    })
}

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

    #[test]
    fn test_introduce_var_simple() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    foo(<|>1 + 1<|>);
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    foo(var_name);
}",
        );
    }

    #[test]
    fn test_introduce_var_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1 + 1<|>;
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_part_of_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1<|> + 1;
}",
            "
fn foo() {
    let <|>var_name = 1;
    var_name + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_last_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    bar(<|>1 + 1<|>)
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    bar(var_name)
}",
        );
    }

    #[test]
    fn test_introduce_var_last_full_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>bar(1 + 1)<|>
}",
            "
fn foo() {
    let <|>var_name = bar(1 + 1);
    var_name
}",
        );
    }

    #[test]
    fn test_introduce_var_block_expr_second_to_last() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>{ let x = 0; x }<|>
    something_else();
}",
            "
fn foo() {
    let <|>var_name = { let x = 0; x };
    something_else();
}",
        );
    }
}
<commit_msg>Fix #667<commit_after>use ra_syntax::{
    ast::{self, AstNode},
    SyntaxKind::WHITESPACE, SyntaxKind::MATCH_ARM, SyntaxKind::LAMBDA_EXPR,
    SyntaxNode, TextUnit,
};

use crate::assists::{AssistCtx, Assist};

pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option<Assist> {
    let node = ctx.covering_node();
    let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;

    let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?;
    let indent = anchor_stmt.prev_sibling()?;
    if indent.kind() != WHITESPACE {
        return None;
    }
    ctx.build("introduce variable", move |edit| {
        let mut buf = String::new();

        let cursor_offset = if wrap_in_block {
            buf.push_str("{ let var_name = ");
            TextUnit::of_str("{ let ")
        } else {
            buf.push_str("let var_name = ");
            TextUnit::of_str("let ")
        };

        expr.syntax().text().push_to(&mut buf);
        let full_stmt = ast::ExprStmt::cast(anchor_stmt);
        let is_full_stmt = if let Some(expr_stmt) = full_stmt {
            Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
        } else {
            false
        };
        if is_full_stmt {
            if !full_stmt.unwrap().has_semi() {
                buf.push_str(";");
            }
            edit.replace(expr.syntax().range(), buf);
        } else {
            buf.push_str(";");
            indent.text().push_to(&mut buf);
            edit.replace(expr.syntax().range(), "var_name".to_string());
            edit.insert(anchor_stmt.range().start(), buf);
            if wrap_in_block {
                edit.insert(anchor_stmt.range().end(), " }");
            }
        }
        edit.set_cursor(anchor_stmt.range().start() + cursor_offset);
    })
}

/// Returns the syntax node which will follow the freshly introduced var
/// and a boolean indicating whether we have to wrap it within a { } block
/// to produce correct code.
/// It can be a statement, the last in a block expression or a wanna be block
/// expression like a lamba or match arm.
fn anchor_stmt(expr: &ast::Expr) -> Option<(&SyntaxNode, bool)> {
    expr.syntax().ancestors().find_map(|node| {
        if ast::Stmt::cast(node).is_some() {
            return Some((node, false));
        }

        if let Some(expr) = node
            .parent()
            .and_then(ast::Block::cast)
            .and_then(|it| it.expr())
        {
            if expr.syntax() == node {
                return Some((node, false));
            }
        }

        if let Some(parent) = node.parent() {
            if parent.kind() == MATCH_ARM
                || parent.kind() == LAMBDA_EXPR
            {
                return Some((node, true));
            }
        }

        None
    })
}

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

    #[test]
    fn test_introduce_var_simple() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    foo(<|>1 + 1<|>);
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    foo(var_name);
}",
        );
    }

    #[test]
    fn test_introduce_var_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1 + 1<|>;
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_part_of_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1<|> + 1;
}",
            "
fn foo() {
    let <|>var_name = 1;
    var_name + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_last_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    bar(<|>1 + 1<|>)
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    bar(var_name)
}",
        );
    }

    #[test]
    fn test_introduce_var_last_full_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>bar(1 + 1)<|>
}",
            "
fn foo() {
    let <|>var_name = bar(1 + 1);
    var_name
}",
        );
    }

    #[test]
    fn test_introduce_var_block_expr_second_to_last() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>{ let x = 0; x }<|>
    something_else();
}",
            "
fn foo() {
    let <|>var_name = { let x = 0; x };
    something_else();
}",
        );
    }

    #[test]
    fn test_introduce_var_in_match_arm_no_block() {
        check_assist_range(
            introduce_variable,
            "
fn main() {
    let x = true;
    let tuple = match x {
        true => (<|>2 + 2<|>, true)
        _ => (0, false)
    };
}
",
            "
fn main() {
    let x = true;
    let tuple = match x {
        true => { let <|>var_name = 2 + 2; (var_name, true) }
        _ => (0, false)
    };
}
",
        );
    }

    #[test]
    fn test_introduce_var_in_match_arm_with_block() {
        check_assist_range(
            introduce_variable,
            "
fn main() {
    let x = true;
    let tuple = match x {
        true => {
            let y = 1;
            (<|>2 + y<|>, true)
        }
        _ => (0, false)
    };
}
",
            "
fn main() {
    let x = true;
    let tuple = match x {
        true => {
            let y = 1;
            let <|>var_name = 2 + y;
            (var_name, true)
        }
        _ => (0, false)
    };
}
",
        );
    }

    #[test]
    fn test_introduce_var_in_closure_no_block() {
        check_assist_range(
            introduce_variable,
            "
fn main() {
    let lambda = |x: u32| <|>x * 2<|>;
}
",
            "
fn main() {
    let lambda = |x: u32| { let <|>var_name = x * 2; var_name };
}
",
        );
    }

    #[test]
    fn test_introduce_var_in_closure_with_block() {
        check_assist_range(
            introduce_variable,
            "
fn main() {
    let lambda = |x: u32| { <|>x * 2<|> };
}
",
            "
fn main() {
    let lambda = |x: u32| { let <|>var_name = x * 2; var_name };
}
",
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput};
use diem_crypto::{hash::SPARSE_MERKLE_PLACEHOLDER_HASH, HashValue};
use diem_types::account_state_blob::AccountStateBlob;
use itertools::zip_eq;
use rand::{distributions::Standard, prelude::StdRng, seq::IteratorRandom, Rng, SeedableRng};
use scratchpad::{test_utils::naive_smt::NaiveSmt, SparseMerkleTree};
use std::collections::HashSet;

type ProofReader = scratchpad::test_utils::proof_reader::ProofReader<AccountStateBlob>;

struct Block {
    smt: SparseMerkleTree<AccountStateBlob>,
    updates: Vec<Vec<(HashValue, AccountStateBlob)>>,
    proof_reader: ProofReader,
}

impl Block {
    fn updates(&self) -> Vec<Vec<(HashValue, &AccountStateBlob)>> {
        self.updates
            .iter()
            .map(|small_batch| small_batch.iter().map(|(k, v)| (*k, v)).collect())
            .collect()
    }

    fn updates_flat_batch(&self) -> Vec<(HashValue, &AccountStateBlob)> {
        self.updates().iter().flatten().cloned().collect()
    }
}

struct Group {
    name: String,
    blocks: Vec<Block>,
}

impl Group {
    fn run(&self, c: &mut Criterion) {
        let mut group = c.benchmark_group(&self.name);

        for block in &self.blocks {
            let block_size = block.updates.len();
            let small_batches = block.updates();
            let one_large_batch = block.updates_flat_batch();

            group.throughput(Throughput::Elements(block_size as u64));

            group.bench_function(BenchmarkId::new("serial_update", block_size), |b| {
                b.iter_batched(
                    || small_batches.clone(),
                    |small_batches| {
                        block
                            .smt
                            .serial_update(small_batches, &block.proof_reader)
                            .unwrap();
                    },
                    BatchSize::LargeInput,
                )
            });
            group.bench_function(BenchmarkId::new("batches_update", block_size), |b| {
                b.iter_batched(
                    || small_batches.clone(),
                    |small_batches| {
                        block
                            .smt
                            .batches_update(small_batches, &block.proof_reader)
                            .unwrap();
                    },
                    BatchSize::LargeInput,
                )
            });
            group.bench_function(
                BenchmarkId::new("batches_update__flat_batch", block_size),
                |b| {
                    b.iter_batched(
                        || one_large_batch.clone(),
                        |one_large_batch| {
                            block
                                .smt
                                .batches_update(vec![one_large_batch], &block.proof_reader)
                                .unwrap();
                        },
                        BatchSize::LargeInput,
                    )
                },
            );
            group.bench_function(BenchmarkId::new("batch_update", block_size), |b| {
                b.iter_batched(
                    || one_large_batch.clone(),
                    |one_large_batch| {
                        block
                            .smt
                            .batch_update(one_large_batch, &block.proof_reader)
                            .unwrap();
                    },
                    BatchSize::LargeInput,
                )
            });
        }
        group.finish();
    }
}

struct Benches {
    base_empty: Group,
    base_committed: Group,
    base_uncommitted: Group,
}

impl Benches {
    fn gen(block_sizes: &[usize]) -> Self {
        let mut rng = Self::rng();

        // 1 million possible keys
        let keys = std::iter::repeat_with(|| HashValue::random_with_rng(&mut rng))
            .take(1_000_000)
            .collect::<HashSet<_>>()
            .into_iter()
            .collect::<Vec<_>>();

        // group: insert to an empty SMT
        let base_empty = Group {
            name: "insert to empty".into(),
            blocks: block_sizes
                .iter()
                .map(|block_size| Block {
                    smt: SparseMerkleTree::new(*SPARSE_MERKLE_PLACEHOLDER_HASH),
                    updates: Self::gen_updates(&mut rng, &keys, *block_size),
                    proof_reader: ProofReader::new(Vec::new()),
                })
                .collect(),
        };

        // all addresses with an existing value
        let values = std::iter::repeat_with(|| Self::gen_value(&mut rng))
            .take(keys.len())
            .collect::<Vec<_>>();
        let existing_state = zip_eq(&keys, &values)
            .map(|(key, value)| (*key, value))
            .collect::<Vec<_>>();
        let mut naive_base_smt = NaiveSmt::new(existing_state.as_slice());

        // group: insert to a committed SMT ("unknown" root)
        let base_committed = Group {
            name: "insert to committed base".into(),
            blocks: block_sizes
                .iter()
                .map(|block_size| {
                    let updates = Self::gen_updates(&mut rng, &keys, *block_size);
                    let proof_reader = Self::gen_proof_reader(&mut naive_base_smt, &updates);
                    Block {
                        smt: SparseMerkleTree::new(naive_base_smt.get_root_hash()),
                        updates,
                        proof_reader,
                    }
                })
                .collect(),
        };

        // group: insert to an uncommitted SMT (some structures in mem)
        let base_uncommitted = Group {
            name: "insert to uncommitted base".into(),
            blocks: base_committed
                .blocks
                .iter()
                .map(|base_block| {
                    // This is an SMT holding updates from the `base_committed` block in mem.
                    let updates = Self::gen_updates(&mut rng, &keys, base_block.updates.len());
                    let proof_reader = Self::gen_proof_reader(&mut naive_base_smt, &updates);

                    Block {
                        smt: base_block
                            .smt
                            .batch_update(base_block.updates_flat_batch(), &base_block.proof_reader)
                            .unwrap(),
                        updates,
                        proof_reader,
                    }
                })
                .collect(),
        };

        Self {
            base_empty,
            base_committed,
            base_uncommitted,
        }
    }

    fn run(&self, c: &mut Criterion) {
        self.base_empty.run(c);
        self.base_committed.run(c);
        self.base_uncommitted.run(c);
    }

    fn gen_updates(
        rng: &mut StdRng,
        keys: &[HashValue],
        block_size: usize,
    ) -> Vec<Vec<(HashValue, AccountStateBlob)>> {
        std::iter::repeat_with(|| vec![Self::gen_update(rng, keys), Self::gen_update(rng, keys)])
            .take(block_size)
            .collect()
    }

    fn gen_update(rng: &mut StdRng, keys: &[HashValue]) -> (HashValue, AccountStateBlob) {
        (*keys.iter().choose(rng).unwrap(), Self::gen_value(rng))
    }

    fn gen_value(rng: &mut StdRng) -> AccountStateBlob {
        rng.sample_iter(&Standard)
            .take(100)
            .collect::<Vec<u8>>()
            .into()
    }

    fn gen_proof_reader(
        naive_smt: &mut NaiveSmt,
        updates: &[Vec<(HashValue, AccountStateBlob)>],
    ) -> ProofReader {
        let proofs = updates
            .iter()
            .flatten()
            .map(|(key, _)| (*key, naive_smt.get_proof(key)))
            .collect();
        ProofReader::new(proofs)
    }

    fn rng() -> StdRng {
        let seed: &[_] = &[1, 2, 3, 4];
        let mut actual_seed = [0u8; 32];
        actual_seed[..seed.len()].copy_from_slice(&seed);

        StdRng::from_seed(actual_seed)
    }
}

fn sparse_merkle_benches(c: &mut Criterion) {
    // Fix Rayon threadpool size to 8, which is realistic as in the current production setting
    // and benchmarking result will be more stable across different machines.
    rayon::ThreadPoolBuilder::new()
        .num_threads(8)
        .thread_name(|index| format!("rayon-global-{}", index))
        .build_global()
        .expect("Failed to build rayon global thread pool.");

    Benches::gen(&[2, 4, 8, 16, 32, 100, 1000, 10000]).run(c);
}

criterion_group!(benches, sparse_merkle_benches);
criterion_main!(benches);
<commit_msg>[scratchpad][bench] return smt so the cost of Dropping is not counted<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput};
use diem_crypto::{hash::SPARSE_MERKLE_PLACEHOLDER_HASH, HashValue};
use diem_types::account_state_blob::AccountStateBlob;
use itertools::zip_eq;
use rand::{distributions::Standard, prelude::StdRng, seq::IteratorRandom, Rng, SeedableRng};
use scratchpad::{test_utils::naive_smt::NaiveSmt, SparseMerkleTree};
use std::collections::HashSet;

type ProofReader = scratchpad::test_utils::proof_reader::ProofReader<AccountStateBlob>;

struct Block {
    smt: SparseMerkleTree<AccountStateBlob>,
    updates: Vec<Vec<(HashValue, AccountStateBlob)>>,
    proof_reader: ProofReader,
}

impl Block {
    fn updates(&self) -> Vec<Vec<(HashValue, &AccountStateBlob)>> {
        self.updates
            .iter()
            .map(|small_batch| small_batch.iter().map(|(k, v)| (*k, v)).collect())
            .collect()
    }

    fn updates_flat_batch(&self) -> Vec<(HashValue, &AccountStateBlob)> {
        self.updates().iter().flatten().cloned().collect()
    }
}

struct Group {
    name: String,
    blocks: Vec<Block>,
}

impl Group {
    fn run(&self, c: &mut Criterion) {
        let mut group = c.benchmark_group(&self.name);

        for block in &self.blocks {
            let block_size = block.updates.len();
            let small_batches = block.updates();
            let one_large_batch = block.updates_flat_batch();

            group.throughput(Throughput::Elements(block_size as u64));

            group.bench_function(BenchmarkId::new("serial_update", block_size), |b| {
                b.iter_batched(
                    || small_batches.clone(),
                    // return the resulting smt so the cost of Dropping it is not counted
                    |small_batches| -> SparseMerkleTree<AccountStateBlob> {
                        block
                            .smt
                            .serial_update(small_batches, &block.proof_reader)
                            .unwrap()
                            .1
                    },
                    BatchSize::LargeInput,
                )
            });
            group.bench_function(BenchmarkId::new("batches_update", block_size), |b| {
                b.iter_batched(
                    || small_batches.clone(),
                    // return the resulting smt so the cost of Dropping it is not counted
                    |small_batches| -> SparseMerkleTree<AccountStateBlob> {
                        block
                            .smt
                            .batches_update(small_batches, &block.proof_reader)
                            .unwrap()
                            .1
                    },
                    BatchSize::LargeInput,
                )
            });
            group.bench_function(
                BenchmarkId::new("batches_update__flat_batch", block_size),
                |b| {
                    b.iter_batched(
                        || one_large_batch.clone(),
                        // return the resulting smt so the cost of Dropping it is not counted
                        |one_large_batch| -> SparseMerkleTree<AccountStateBlob> {
                            block
                                .smt
                                .batches_update(vec![one_large_batch], &block.proof_reader)
                                .unwrap()
                                .1
                        },
                        BatchSize::LargeInput,
                    )
                },
            );
            group.bench_function(BenchmarkId::new("batch_update", block_size), |b| {
                b.iter_batched(
                    || one_large_batch.clone(),
                    // return the resulting smt so the cost of Dropping it is not counted
                    |one_large_batch| -> SparseMerkleTree<AccountStateBlob> {
                        block
                            .smt
                            .batch_update(one_large_batch, &block.proof_reader)
                            .unwrap()
                    },
                    BatchSize::LargeInput,
                )
            });
        }
        group.finish();
    }
}

struct Benches {
    base_empty: Group,
    base_committed: Group,
    base_uncommitted: Group,
}

impl Benches {
    fn gen(block_sizes: &[usize]) -> Self {
        let mut rng = Self::rng();

        // 1 million possible keys
        let keys = std::iter::repeat_with(|| HashValue::random_with_rng(&mut rng))
            .take(1_000_000)
            .collect::<HashSet<_>>()
            .into_iter()
            .collect::<Vec<_>>();

        // group: insert to an empty SMT
        let base_empty = Group {
            name: "insert to empty".into(),
            blocks: block_sizes
                .iter()
                .map(|block_size| Block {
                    smt: SparseMerkleTree::new(*SPARSE_MERKLE_PLACEHOLDER_HASH),
                    updates: Self::gen_updates(&mut rng, &keys, *block_size),
                    proof_reader: ProofReader::new(Vec::new()),
                })
                .collect(),
        };

        // all addresses with an existing value
        let values = std::iter::repeat_with(|| Self::gen_value(&mut rng))
            .take(keys.len())
            .collect::<Vec<_>>();
        let existing_state = zip_eq(&keys, &values)
            .map(|(key, value)| (*key, value))
            .collect::<Vec<_>>();
        let mut naive_base_smt = NaiveSmt::new(existing_state.as_slice());

        // group: insert to a committed SMT ("unknown" root)
        let base_committed = Group {
            name: "insert to committed base".into(),
            blocks: block_sizes
                .iter()
                .map(|block_size| {
                    let updates = Self::gen_updates(&mut rng, &keys, *block_size);
                    let proof_reader = Self::gen_proof_reader(&mut naive_base_smt, &updates);
                    Block {
                        smt: SparseMerkleTree::new(naive_base_smt.get_root_hash()),
                        updates,
                        proof_reader,
                    }
                })
                .collect(),
        };

        // group: insert to an uncommitted SMT (some structures in mem)
        let base_uncommitted = Group {
            name: "insert to uncommitted base".into(),
            blocks: base_committed
                .blocks
                .iter()
                .map(|base_block| {
                    // This is an SMT holding updates from the `base_committed` block in mem.
                    let updates = Self::gen_updates(&mut rng, &keys, base_block.updates.len());
                    let proof_reader = Self::gen_proof_reader(&mut naive_base_smt, &updates);

                    Block {
                        smt: base_block
                            .smt
                            .batch_update(base_block.updates_flat_batch(), &base_block.proof_reader)
                            .unwrap(),
                        updates,
                        proof_reader,
                    }
                })
                .collect(),
        };

        Self {
            base_empty,
            base_committed,
            base_uncommitted,
        }
    }

    fn run(&self, c: &mut Criterion) {
        self.base_empty.run(c);
        self.base_committed.run(c);
        self.base_uncommitted.run(c);
    }

    fn gen_updates(
        rng: &mut StdRng,
        keys: &[HashValue],
        block_size: usize,
    ) -> Vec<Vec<(HashValue, AccountStateBlob)>> {
        std::iter::repeat_with(|| vec![Self::gen_update(rng, keys), Self::gen_update(rng, keys)])
            .take(block_size)
            .collect()
    }

    fn gen_update(rng: &mut StdRng, keys: &[HashValue]) -> (HashValue, AccountStateBlob) {
        (*keys.iter().choose(rng).unwrap(), Self::gen_value(rng))
    }

    fn gen_value(rng: &mut StdRng) -> AccountStateBlob {
        rng.sample_iter(&Standard)
            .take(100)
            .collect::<Vec<u8>>()
            .into()
    }

    fn gen_proof_reader(
        naive_smt: &mut NaiveSmt,
        updates: &[Vec<(HashValue, AccountStateBlob)>],
    ) -> ProofReader {
        let proofs = updates
            .iter()
            .flatten()
            .map(|(key, _)| (*key, naive_smt.get_proof(key)))
            .collect();
        ProofReader::new(proofs)
    }

    fn rng() -> StdRng {
        let seed: &[_] = &[1, 2, 3, 4];
        let mut actual_seed = [0u8; 32];
        actual_seed[..seed.len()].copy_from_slice(&seed);

        StdRng::from_seed(actual_seed)
    }
}

fn sparse_merkle_benches(c: &mut Criterion) {
    // Fix Rayon threadpool size to 8, which is realistic as in the current production setting
    // and benchmarking result will be more stable across different machines.
    rayon::ThreadPoolBuilder::new()
        .num_threads(8)
        .thread_name(|index| format!("rayon-global-{}", index))
        .build_global()
        .expect("Failed to build rayon global thread pool.");

    Benches::gen(&[2, 4, 8, 16, 32, 100, 1000, 10000]).run(c);
}

criterion_group!(benches, sparse_merkle_benches);
criterion_main!(benches);
<|endoftext|>


<commit_before>use std::sync::Arc;

use minihttp::Status;
use tokio_core::io::Io;
use futures::future::ok;

use default_error_page::serve_error_page;
use config::redirect::BaseRedirect;
use incoming::{reply, Request, Input};

pub fn base_redirect<S: Io + 'static>(settings: &Arc<BaseRedirect>, inp: Input)
    -> Request<S>
{
    serve_redirect(settings.redirect_to_domain.as_str(), inp)
}

pub fn strip_www_redirect<S: Io + 'static>(inp: Input)
    -> Request<S>
{
    let dest = inp.headers.host()
        .and_then(|host| host.splitn(2, '.').last());
    match dest {
        Some(host) => serve_redirect(host, inp),
        None => serve_error_page(Status::InternalServerError, inp),
    }
}

fn serve_redirect<S: Io + 'static>(host: &str, inp: Input)
    -> Request<S>
{
    // TODO: properly identify request scheme
    let dest = format!("http://{}{}", host, inp.headers.path().unwrap_or("/"));
    reply(inp, move |mut e| {
        e.status(Status::Found);
        e.add_header("Location", dest);
        e.add_length(0);
        if e.done_headers() {
            // TODO: add HTML with redirect link;
            //      link must be url-encoded;
        }
        Box::new(ok(e.done()))
    })
}
<commit_msg>check host prefix on www redirect<commit_after>use std::sync::Arc;
use std::ascii::AsciiExt;

use minihttp::Status;
use tokio_core::io::Io;
use futures::future::ok;

use default_error_page::serve_error_page;
use config::redirect::BaseRedirect;
use incoming::{reply, Request, Input};

pub fn base_redirect<S: Io + 'static>(settings: &Arc<BaseRedirect>, inp: Input)
    -> Request<S>
{
    serve_redirect(settings.redirect_to_domain.as_str(), Status::Found, inp)
}

pub fn strip_www_redirect<S: Io + 'static>(inp: Input)
    -> Request<S>
{

    let base_host = inp.headers.host().and_then(|h| {
        if h.len() > 4 && h[0..4].eq_ignore_ascii_case("www.") {
            Some(h.split_at(4).1)
        } else {
            None
        }
    });
    match base_host {
        Some(host) => serve_redirect(host, Status::MovedPermanently, inp),
        None => serve_error_page(Status::NotFound, inp),
    }
}

fn serve_redirect<S: Io + 'static>(host: &str, status: Status, inp: Input)
    -> Request<S>
{
    // TODO: properly identify request scheme
    let dest = format!("http://{}{}", host, inp.headers.path().unwrap_or("/"));
    reply(inp, move |mut e| {
        e.status(status);
        e.add_header("Location", dest);
        e.add_length(0);
        if e.done_headers() {
            // TODO: add HTML with redirect link;
            //      link must be url-encoded;
        }
        Box::new(ok(e.done()))
    })
}
<|endoftext|>


<commit_before>use neb::ram::cell;
use neb::ram::cell::*;
use neb::ram::schema::*;
use neb::ram::chunk::Chunks;
use neb::ram::types::*;
use neb::ram::io::writer;

use std::mem;
use super::*;

pub const CHUNK_SIZE: usize = 8 * 1024 * 1024;

#[test]
pub fn header_size() {
    assert_eq!(mem::size_of::<cell::Header>(), cell::HEADER_SIZE);
}

#[test]
pub fn cell_rw () {
    let fields = default_fields();
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let mut schema = Schema {
        id: 1,
        name: String::from("dummy"),
        key_field: None,
        str_key_field: None,
        fields: fields,
        is_dynamic: false
    };
    let mut data_map = Map::new();
    data_map.insert(&String::from("id"), Value::I64(100));
    data_map.insert(&String::from("score"), Value::U64(70));
    data_map.insert(&String::from("name"), Value::String(String::from("Jack")));
    let mut data = Value::Map(data_map);
    let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
    chunk.meta.schemas.new_schema(schema.clone());
    let mut cell = Cell {
        header: Header::new(0, schema.id, &id1),
//        Header {
//            version: 1,
//            size: 0,
//            schema: 0,
//            hash: 1,
//            partition: 1,
//        },
        data: data
    };
    let mut loc = cell.write_to_chunk(&chunk);
    let cell_1_ptr = loc.unwrap();
    {
        let stored_cell = Cell::from_chunk_raw(cell_1_ptr, &chunk).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].I64().unwrap(), 100);
        assert_eq!(stored_cell.data["name"].String().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].U64().unwrap(), 70);
    }
    data_map = Map::new();
    data_map.insert(&String::from("id"), Value::I64(2));
    data_map.insert(&String::from("score"), Value::U64(80));
    data_map.insert(&String::from("name"), Value::String(String::from("John")));
    data = Value::Map(data_map);
    cell = Cell {
        header: Header::new(0, schema.id, &id2),
//        Header {
//            version: 1,
//            size: 0,
//            schema: 0,
//            hash: 2,
//            partition: 1,
//        },
        data: data
    };
    loc = cell.write_to_chunk(&chunk);
    let cell_2_ptr = loc.unwrap();

    assert_eq!(cell_2_ptr, cell_1_ptr + cell.header.size as usize);
    {
        let stored_cell = Cell::from_chunk_raw(cell_2_ptr, &chunk).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].I64().unwrap(), 2);
        assert_eq!(stored_cell.data["score"].U64().unwrap(), 80);
        assert_eq!(stored_cell.data["name"].String().unwrap(), "John");
    }
    {
        let stored_cell = Cell::from_chunk_raw(cell_1_ptr, &chunk).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].I64().unwrap(), 100);
        assert_eq!(stored_cell.data["name"].String().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].U64().unwrap(), 70);
    }
}
<commit_msg>test for dynamic cell #4<commit_after>use neb::ram::cell;
use neb::ram::cell::*;
use neb::ram::schema::*;
use neb::ram::chunk::Chunks;
use neb::ram::types::*;
use neb::ram::io::writer;

use std::mem;
use super::*;

pub const CHUNK_SIZE: usize = 8 * 1024 * 1024;

#[test]
pub fn header_size() {
    assert_eq!(mem::size_of::<cell::Header>(), cell::HEADER_SIZE);
}

#[test]
pub fn cell_rw () {
    let fields = default_fields();
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let mut schema = Schema {
        id: 1,
        name: String::from("dummy"),
        key_field: None,
        str_key_field: None,
        fields: fields,
        is_dynamic: false
    };
    let mut data_map = Map::new();
    data_map.insert("id", Value::I64(100));
    data_map.insert("score", Value::U64(70));
    data_map.insert("name", Value::String(String::from("Jack")));
    let mut data = Value::Map(data_map);
    let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
    chunk.meta.schemas.new_schema(schema.clone());
    let mut cell = Cell {
        header: Header::new(0, schema.id, &id1),
        data: data
    };
    let mut loc = cell.write_to_chunk(&chunk);
    let cell_1_ptr = loc.unwrap();
    {
        let stored_cell = Cell::from_chunk_raw(cell_1_ptr, &chunk).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].I64().unwrap(), 100);
        assert_eq!(stored_cell.data["name"].String().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].U64().unwrap(), 70);
    }
    data_map = Map::new();
    data_map.insert("id", Value::I64(2));
    data_map.insert("score", Value::U64(80));
    data_map.insert("name", Value::String(String::from("John")));
    data = Value::Map(data_map);
    cell = Cell {
        header: Header::new(0, schema.id, &id2),
        data: data
    };
    loc = cell.write_to_chunk(&chunk);
    let cell_2_ptr = loc.unwrap();

    assert_eq!(cell_2_ptr, cell_1_ptr + cell.header.size as usize);
    {
        let stored_cell = Cell::from_chunk_raw(cell_2_ptr, &chunk).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].I64().unwrap(), 2);
        assert_eq!(stored_cell.data["score"].U64().unwrap(), 80);
        assert_eq!(stored_cell.data["name"].String().unwrap(), "John");
    }
    {
        let stored_cell = Cell::from_chunk_raw(cell_1_ptr, &chunk).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].I64().unwrap(), 100);
        assert_eq!(stored_cell.data["name"].String().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].U64().unwrap(), 70);
    }
}

#[test]
pub fn dynamic() {
    let fields = default_fields();
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let mut schema = Schema {
        id: 1,
        name: String::from("dummy"),
        key_field: None,
        str_key_field: None,
        fields: fields,
        is_dynamic: true
    };
    let mut data_map = Map::new();
    data_map.insert("id", Value::I64(100));
    data_map.insert("score", Value::U64(70));
    data_map.insert("name", Value::String(String::from("Jack")));
    data_map.insert("year", Value::U16(2010));
    data_map.insert("major", Value::String(String::from("CS")));
    let mut data = Value::Map(data_map);
    let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
    chunk.meta.schemas.new_schema(schema.clone());
    let mut cell = Cell {
        header: Header::new(0, schema.id, &id1),
        data: data
    };
    let mut loc = cell.write_to_chunk(&chunk);
    let cell_1_ptr = loc.unwrap();
    {
        let stored_cell = Cell::from_chunk_raw(cell_1_ptr, &chunk).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].I64().unwrap(), 100);
        assert_eq!(stored_cell.data["name"].String().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].U64().unwrap(), 70);
        assert_eq!(stored_cell.data["year"].U16().unwrap(), 2010);
        assert_eq!(stored_cell.data["major"].String().unwrap(), "CS");
    }

    data_map = Map::new();
    data_map.insert("id", Value::I64(2));
    data_map.insert("score", Value::U64(80));
    data_map.insert("name", Value::String(String::from("John")));
    data = Value::Map(data_map);
    cell = Cell {
        header: Header::new(0, schema.id, &id2),
        data: data
    };
    loc = cell.write_to_chunk(&chunk);
    let cell_2_ptr = loc.unwrap();
    {
        let stored_cell = Cell::from_chunk_raw(cell_2_ptr, &chunk).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].I64().unwrap(), 2);
        assert_eq!(stored_cell.data["score"].U64().unwrap(), 80);
        assert_eq!(stored_cell.data["name"].String().unwrap(), "John");
        assert!(stored_cell.data["major"].String().is_none());
    }
}<|endoftext|>


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

use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use std::num::{NumCast, One, Zero};

#[deriving(Clone,Eq)]
pub struct Au(i32);

impl Add<Au,Au> for Au {
    fn add(&self, other: &Au) -> Au { Au(**self + **other) }
}

impl Sub<Au,Au> for Au {
    fn sub(&self, other: &Au) -> Au { Au(**self - **other) }
}

impl Mul<Au,Au> for Au {
    fn mul(&self, other: &Au) -> Au { Au(**self * **other) }
}

impl Div<Au,Au> for Au {
    fn div(&self, other: &Au) -> Au { Au(**self / **other) }
}

impl Rem<Au,Au> for Au {
    fn rem(&self, other: &Au) -> Au { Au(**self % **other) }
}

impl Neg<Au> for Au {
    fn neg(&self) -> Au { Au(-**self) }
}

impl Ord for Au {
    fn lt(&self, other: &Au) -> bool { **self <  **other }
    fn le(&self, other: &Au) -> bool { **self <= **other }
    fn ge(&self, other: &Au) -> bool { **self >= **other }
    fn gt(&self, other: &Au) -> bool { **self >  **other }
}

impl One for Au {
    fn one() -> Au { Au(1) }
}

impl Zero for Au {
    fn zero() -> Au { Au(0) }
    fn is_zero(&self) -> bool { **self == 0 }
}

impl Num for Au {}

pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

impl NumCast for Au {
    fn from<T:NumCast>(n: T) -> Au { Au(n.to_i32()) }

    fn to_u8(&self) -> u8       { (**self).to_u8() }
    fn to_u16(&self) -> u16     { (**self).to_u16() }
    fn to_u32(&self) -> u32     { (**self).to_u32() }
    fn to_u64(&self) -> u64     { (**self).to_u64() }
    fn to_uint(&self) -> uint   { (**self).to_uint() }

    fn to_i8(&self) -> i8       { (**self).to_i8() }
    fn to_i16(&self) -> i16     { (**self).to_i16() }
    fn to_i32(&self) -> i32     { (**self).to_i32() }
    fn to_i64(&self) -> i64     { (**self).to_i64() }
    fn to_int(&self) -> int     { (**self).to_int() }

    fn to_f32(&self) -> f32     { (**self).to_f32() }
    fn to_f64(&self) -> f64     { (**self).to_f64() }
    fn to_float(&self) -> float { (**self).to_float() }
}

pub fn box<T:Clone + Ord + Add<T,T> + Sub<T,T>>(x: T, y: T, w: T, h: T) -> Rect<T> {
    Rect(Point2D(x, y), Size2D(w, h))
}

impl Au {
    pub fn scale_by(self, factor: float) -> Au {
        Au(((*self as float) * factor) as i32)
    }

    pub fn from_px(px: int) -> Au {
        NumCast::from(px * 60)
    }

    pub fn to_px(&self) -> int {
        (**self / 60) as int
    }

    pub fn to_snapped(&self) -> Au {
        let res = **self % 60i32;
        return if res >= 30i32 { return Au(**self - res + 60i32) }
                       else { return Au(**self - res) };
    }

    pub fn zero_point() -> Point2D<Au> {
        Point2D(Au(0), Au(0))
    }

    pub fn zero_rect() -> Rect<Au> {
        let z = Au(0);
        Rect(Point2D(z, z), Size2D(z, z))
    }

    pub fn from_pt(pt: float) -> Au {
        from_px(pt_to_px(pt) as int)
    }

    pub fn from_frac_px(px: float) -> Au {
        Au((px * 60f) as i32)
    }

    pub fn min(x: Au, y: Au) -> Au { if *x < *y { x } else { y } }
    pub fn max(x: Au, y: Au) -> Au { if *x > *y { x } else { y } }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: float) -> float {
    pt / 72f * 96f
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: float) -> float {
    px / 96f * 72f
}

pub fn zero_rect() -> Rect<Au> {
    let z = Au(0);
    Rect(Point2D(z, z), Size2D(z, z))
}

pub fn zero_point() -> Point2D<Au> {
    Point2D(Au(0), Au(0))
}

pub fn zero_size() -> Size2D<Au> {
    Size2D(Au(0), Au(0))
}

pub fn from_frac_px(px: float) -> Au {
    Au((px * 60f) as i32)
}

pub fn from_px(px: int) -> Au {
    NumCast::from(px * 60)
}

pub fn to_px(au: Au) -> int {
    (*au / 60) as int
}

pub fn to_frac_px(au: Au) -> float {
    (*au as float) / 60f
}

// assumes 72 points per inch, and 96 px per inch
pub fn from_pt(pt: float) -> Au {
    from_px((pt / 72f * 96f) as int)
}
<commit_msg>Round results for scale_by and to_px.<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 geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;

use std::num::{NumCast, One, Zero};

#[deriving(Clone,Eq)]
pub struct Au(i32);

impl Add<Au,Au> for Au {
    fn add(&self, other: &Au) -> Au { Au(**self + **other) }
}

impl Sub<Au,Au> for Au {
    fn sub(&self, other: &Au) -> Au { Au(**self - **other) }
}

impl Mul<Au,Au> for Au {
    fn mul(&self, other: &Au) -> Au { Au(**self * **other) }
}

impl Div<Au,Au> for Au {
    fn div(&self, other: &Au) -> Au { Au(**self / **other) }
}

impl Rem<Au,Au> for Au {
    fn rem(&self, other: &Au) -> Au { Au(**self % **other) }
}

impl Neg<Au> for Au {
    fn neg(&self) -> Au { Au(-**self) }
}

impl Ord for Au {
    fn lt(&self, other: &Au) -> bool { **self <  **other }
    fn le(&self, other: &Au) -> bool { **self <= **other }
    fn ge(&self, other: &Au) -> bool { **self >= **other }
    fn gt(&self, other: &Au) -> bool { **self >  **other }
}

impl One for Au {
    fn one() -> Au { Au(1) }
}

impl Zero for Au {
    fn zero() -> Au { Au(0) }
    fn is_zero(&self) -> bool { **self == 0 }
}

impl Num for Au {}

pub fn min(x: Au, y: Au) -> Au { if x < y { x } else { y } }
pub fn max(x: Au, y: Au) -> Au { if x > y { x } else { y } }

impl NumCast for Au {
    fn from<T:NumCast>(n: T) -> Au { Au(n.to_i32()) }

    fn to_u8(&self) -> u8       { (**self).to_u8() }
    fn to_u16(&self) -> u16     { (**self).to_u16() }
    fn to_u32(&self) -> u32     { (**self).to_u32() }
    fn to_u64(&self) -> u64     { (**self).to_u64() }
    fn to_uint(&self) -> uint   { (**self).to_uint() }

    fn to_i8(&self) -> i8       { (**self).to_i8() }
    fn to_i16(&self) -> i16     { (**self).to_i16() }
    fn to_i32(&self) -> i32     { (**self).to_i32() }
    fn to_i64(&self) -> i64     { (**self).to_i64() }
    fn to_int(&self) -> int     { (**self).to_int() }

    fn to_f32(&self) -> f32     { (**self).to_f32() }
    fn to_f64(&self) -> f64     { (**self).to_f64() }
    fn to_float(&self) -> float { (**self).to_float() }
}

pub fn box<T:Clone + Ord + Add<T,T> + Sub<T,T>>(x: T, y: T, w: T, h: T) -> Rect<T> {
    Rect(Point2D(x, y), Size2D(w, h))
}

impl Au {
    pub fn scale_by(self, factor: float) -> Au {
        Au(((*self as float) * factor).round() as i32)
    }

    pub fn from_px(px: int) -> Au {
        NumCast::from(px * 60)
    }

    pub fn to_px(&self) -> int {
        ((**self as float) / 60f).round() as int
    }

    pub fn to_snapped(&self) -> Au {
        let res = **self % 60i32;
        return if res >= 30i32 { return Au(**self - res + 60i32) }
                       else { return Au(**self - res) };
    }

    pub fn zero_point() -> Point2D<Au> {
        Point2D(Au(0), Au(0))
    }

    pub fn zero_rect() -> Rect<Au> {
        let z = Au(0);
        Rect(Point2D(z, z), Size2D(z, z))
    }

    pub fn from_pt(pt: float) -> Au {
        from_px(pt_to_px(pt) as int)
    }

    pub fn from_frac_px(px: float) -> Au {
        Au((px * 60f) as i32)
    }

    pub fn min(x: Au, y: Au) -> Au { if *x < *y { x } else { y } }
    pub fn max(x: Au, y: Au) -> Au { if *x > *y { x } else { y } }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: float) -> float {
    pt / 72f * 96f
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: float) -> float {
    px / 96f * 72f
}

pub fn zero_rect() -> Rect<Au> {
    let z = Au(0);
    Rect(Point2D(z, z), Size2D(z, z))
}

pub fn zero_point() -> Point2D<Au> {
    Point2D(Au(0), Au(0))
}

pub fn zero_size() -> Size2D<Au> {
    Size2D(Au(0), Au(0))
}

pub fn from_frac_px(px: float) -> Au {
    Au((px * 60f) as i32)
}

pub fn from_px(px: int) -> Au {
    NumCast::from(px * 60)
}

pub fn to_px(au: Au) -> int {
    (*au / 60) as int
}

pub fn to_frac_px(au: Au) -> float {
    (*au as float) / 60f
}

// assumes 72 points per inch, and 96 px per inch
pub fn from_pt(pt: float) -> Au {
    from_px((pt / 72f * 96f) as int)
}
<|endoftext|>


<commit_before>use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use std::collections::HashSet;
use std;

pub struct KeyboardDriver {
    events: sdl2::EventPump
}

impl KeyboardDriver {
    pub fn new(sdl_context: &sdl2::Sdl) -> Self {
        KeyboardDriver {
            events: sdl_context.event_pump().unwrap(),
        }
    }

    pub fn poll(&mut self)  {

        let mut prev_keys = HashSet::new();

        'running: loop {
            for event in self.events.poll_iter() {
                if let Event::Quit {..} = event {
                    break 'running;
                };
            }

            // Create a set of pressed Keys.
            let keys = self.events.keyboard_state().pressed_scancodes().filter_map(Keycode::from_scancode).collect();

            // Get the difference between the new and old sets.
            let new_keys = &keys - &prev_keys;
            let old_keys = &prev_keys - &keys;

            if !new_keys.is_empty() || !old_keys.is_empty() {
                println!("new_keys: {:?}\told_keys:{:?}", new_keys, old_keys);
            }

            prev_keys = keys;

            std::thread::sleep(std::time::Duration::from_millis(100));
        }
    }
}
<commit_msg>convert keyboard keys to chip8 keypad flags<commit_after>use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use std;

pub struct KeyboardDriver {
    events: sdl2::EventPump
}

impl KeyboardDriver {
    pub fn new(sdl_context: &sdl2::Sdl) -> Self {
        KeyboardDriver {
            events: sdl_context.event_pump().unwrap(),
        }
    }

    pub fn poll(&mut self)  {

        'running: loop {
            for event in self.events.poll_iter() {
                if let Event::Quit {..} = event {
                    break 'running;
                };
            }

            let keys: Vec<Keycode> = self.events.keyboard_state()
                .pressed_scancodes()
                .filter_map(Keycode::from_scancode)
                .collect();

            let mut chip8_keys = [false; 16];

            for key in keys {
                let index = match key {
                    Keycode::Num1 => Some(0x1),
                    Keycode::Num2 => Some(0x2),
                    Keycode::Num3 => Some(0x3),
                    Keycode::Num4 => Some(0xc),
                    Keycode::Q    => Some(0x4),
                    Keycode::W    => Some(0x5),
                    Keycode::E    => Some(0x6),
                    Keycode::R    => Some(0xd),
                    Keycode::A    => Some(0x7),
                    Keycode::S    => Some(0x8),
                    Keycode::D    => Some(0x9),
                    Keycode::F    => Some(0xe),
                    Keycode::Z    => Some(0xa),
                    Keycode::X    => Some(0x0),
                    Keycode::C    => Some(0xb),
                    Keycode::V    => Some(0xf),
                    _             => None,
                };

                if let Some(i) = index {
                    chip8_keys[i] = true;
                }

            }

            println!("{:?}", chip8_keys);

            // prev_keys = keys;

            std::thread::sleep(std::time::Duration::from_millis(100));
        }
    }
}
<|endoftext|>


<commit_before>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::Rectangle;
use util::units::{Direction, Point, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_frame: Rectangle,
    map_view: Point,
    info_frame: Rectangle,
    message_frame: Rectangle,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_frame: Rectangle::new(Point::new(16, 1), Size::new(63, 38)),
                map_view: Point::new(0, 0),
                info_frame: Rectangle::new(Point::new(1, 1), Size::new(13, 48)),
                message_frame: Rectangle::new(Point::new(16, 41), Size::new(63, 8)),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_frame.location() + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.map_frame.move_dir(Point::new(0, -1)).location(), "Map");

        self.draw_box(console, self.info_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.info_frame.move_dir(Point::new(0, -1)).location(), "Info");

        self.draw_box(console, self.message_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.message_frame.move_dir(Point::new(0, -1)).location(), "Messages");
    }

    fn draw_box(&self, console: &mut Console, rect: Rectangle) {
        console.put_plain(rect.location() + Point::new(0, 0), chars::NW);
        console.put_plain(rect.location() + Point::new(rect.width(), 0), chars::NE);
        console.put_plain(rect.location() + Point::new(0, rect.height()), chars::SW);
        console.put_plain(rect.location() + Point::new(rect.width(), rect.height()), chars::SE);

        for x in 1..rect.width() {
            console.put_plain(rect.location() + Point::new(x, 0), chars::HLINE);
            console.put_plain(rect.location() + Point::new(x, rect.height()), chars::HLINE);
        }

        for y in 1..rect.height() {
            console.put_plain(rect.location() + Point::new(0, y), chars::VLINE);
            console.put_plain(rect.location() + Point::new(rect.width(), y), chars::VLINE);
        }
    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        let (width, height) = (63, 38);

        for (y, line) in map.tiles[self.map_view.y as usize .. self.map_view.y as usize + height].iter().enumerate() {
            for (x, cell) in line[self.map_view.x as usize .. self.map_view.x as usize + width].iter().enumerate() {
                console.put(self.map_frame.location() + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

}
<commit_msg>Add methods for whether the view can move down or right<commit_after>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::Rectangle;
use util::units::{Direction, Point, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_frame: Rectangle,
    map_view: Point,
    info_frame: Rectangle,
    message_frame: Rectangle,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_frame: Rectangle::new(Point::new(16, 1), Size::new(63, 38)),
                map_view: Point::new(0, 0),
                info_frame: Rectangle::new(Point::new(1, 1), Size::new(13, 48)),
                message_frame: Rectangle::new(Point::new(16, 41), Size::new(63, 8)),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_frame.location() + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.map_frame.move_dir(Point::new(0, -1)).location(), "Map");

        self.draw_box(console, self.info_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.info_frame.move_dir(Point::new(0, -1)).location(), "Info");

        self.draw_box(console, self.message_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.message_frame.move_dir(Point::new(0, -1)).location(), "Messages");
    }

    fn draw_box(&self, console: &mut Console, rect: Rectangle) {
        console.put_plain(rect.location() + Point::new(0, 0), chars::NW);
        console.put_plain(rect.location() + Point::new(rect.width(), 0), chars::NE);
        console.put_plain(rect.location() + Point::new(0, rect.height()), chars::SW);
        console.put_plain(rect.location() + Point::new(rect.width(), rect.height()), chars::SE);

        for x in 1..rect.width() {
            console.put_plain(rect.location() + Point::new(x, 0), chars::HLINE);
            console.put_plain(rect.location() + Point::new(x, rect.height()), chars::HLINE);
        }

        for y in 1..rect.height() {
            console.put_plain(rect.location() + Point::new(0, y), chars::VLINE);
            console.put_plain(rect.location() + Point::new(rect.width(), y), chars::VLINE);
        }
    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        let (width, height) = (63, 38);

        for (y, line) in map.tiles[self.map_view.y as usize .. self.map_view.y as usize + height].iter().enumerate() {
            for (x, cell) in line[self.map_view.x as usize .. self.map_view.x as usize + width].iter().enumerate() {
                console.put(self.map_frame.location() + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

    fn view_can_move_right(&self, game: &Game) -> bool {
        self.map_view.x + self.map_frame.width() < game.world.map.width()
    }

    fn view_can_move_down(&self, game: &Game) -> bool {
        self.map_view.y + self.map_frame.height() < game.world.map.height()
    }

}
<|endoftext|>