<commit_before>use gl::types::*;
use id_allocator::IdAllocator;
use nalgebra::{normalize, cross};
use nalgebra::{Pnt3, Vec3};
use ncollide::bounding_volume::{AABB, AABB3};
use noise::source::Perlin;
use noise::model::Plane;
use state::EntityId;
use std::collections::hash_map::HashMap;
use std::num::Float;
use stopwatch::TimerSet;
use terrain::{AMPLITUDE, TerrainType};

pub const BLOCK_WIDTH: i32 = 4;
// Number of samples in a single dimension per block.
pub const SAMPLES_PER_BLOCK: uint = 16;
pub const SAMPLE_WIDTH: f32 = BLOCK_WIDTH as f32 / SAMPLES_PER_BLOCK as f32;

#[deriving(Show, PartialEq, Eq, Hash, Copy, Clone)]
pub struct BlockPosition(Pnt3<i32>);

impl BlockPosition {
  #[inline(always)]
  pub fn new(x: i32, y: i32, z: i32) -> BlockPosition {
    BlockPosition(Pnt3::new(x, y, z))
  }

  #[inline(always)]
  pub fn as_pnt<'a>(&'a self) -> &'a Pnt3<i32> {
    let BlockPosition(ref pnt) = *self;
    pnt
  }

  #[inline(always)]
  pub fn as_mut_pnt3<'a>(&'a mut self) -> &'a mut Pnt3<i32> {
    let BlockPosition(ref mut pnt) = *self;
    pnt
  }

  pub fn from_world_position(world_position: &Pnt3<f32>) -> BlockPosition {
    macro_rules! convert_coordinate(
      ($x: expr) => ({
        let x = $x.floor() as i32;
        let x =
          if x < 0 {
            x - (BLOCK_WIDTH - 1)
          } else {
            x
          };
        x / BLOCK_WIDTH
      })
    );
    BlockPosition(
      Pnt3::new(
        convert_coordinate!(world_position.x),
        convert_coordinate!(world_position.y),
        convert_coordinate!(world_position.z),
      )
    )
  }

  pub fn to_world_position(&self) -> Pnt3<f32> {
    Pnt3::new(
      (self.as_pnt().x * BLOCK_WIDTH) as f32,
      (self.as_pnt().y * BLOCK_WIDTH) as f32,
      (self.as_pnt().z * BLOCK_WIDTH) as f32,
    )
  }
}

impl Add<Vec3<i32>, BlockPosition> for BlockPosition {
  fn add(mut self, rhs: Vec3<i32>) -> Self {
    self.as_mut_pnt3().x += rhs.x;
    self.as_mut_pnt3().y += rhs.y;
    self.as_mut_pnt3().z += rhs.z;
    self
  }
}

pub struct TerrainBlock {
  // These Vecs must all be ordered the same way.

  // vertex coordinates flattened into separate GLfloats (x, y, z order)
  pub vertex_coordinates: Vec<GLfloat>,
  // per-vertex normal vectors flattened into separate GLfloats (x, y, z order)
  pub normals: Vec<GLfloat>,
  // per-triangle terrain types
  pub typs: Vec<GLuint>,

  // per-triangle entity IDs
  pub ids: Vec<EntityId>,
  // per-triangle bounding boxes
  pub bounds: HashMap<EntityId, AABB3<GLfloat>>,
}

impl TerrainBlock {
  pub fn empty() -> TerrainBlock {
    TerrainBlock {
      vertex_coordinates: Vec::new(),
      normals: Vec::new(),
      typs: Vec::new(),
      ids: Vec::new(),
      bounds: HashMap::new(),
    }
  }

  pub fn generate(
    timers: &TimerSet,
    id_allocator: &mut IdAllocator<EntityId>,
    heightmap: &Perlin,
    position: &BlockPosition,
  ) -> TerrainBlock {
    timers.time("update.generate_block", || {
      let mut block = TerrainBlock::empty();
      let heightmap = Plane::new(heightmap);

      let x = (position.as_pnt().x * BLOCK_WIDTH) as f32;
      let y = (position.as_pnt().y * BLOCK_WIDTH) as f32;
      let z = (position.as_pnt().z * BLOCK_WIDTH) as f32;

      for dx in range(0, SAMPLES_PER_BLOCK) {
        let x = x + dx as f32 * SAMPLE_WIDTH;
        for dz in range(0, SAMPLES_PER_BLOCK) {
          let z = z + dz as f32 * SAMPLE_WIDTH;
          let position = Pnt3::new(x, y, z);
          TerrainBlock::add_tile(
            timers,
            &heightmap,
            id_allocator,
            &mut block,
            &position,
          );
        }
      }

      block
    })
  }

  #[inline]
  fn add_tile<'a>(
    timers: &TimerSet,
    heightmap: &Plane<'a, Perlin>,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
    position: &Pnt3<f32>,
  ) {
    macro_rules! at(
      ($x: expr, $z: expr) => ({
        let y = AMPLITUDE * (heightmap.get::<GLfloat>($x, $z) + 1.0) / 2.0;
        Pnt3::new($x, y, $z)
      });
    );

    macro_rules! normal_at(
      ($x: expr, $z: expr) => ({
        const DELTA: f32 = 0.2;
        let dx = at!($x + DELTA, $z).to_vec() - at!($x - DELTA, $z).to_vec();
        let dz = at!($x, $z + DELTA).to_vec() - at!($x, $z - DELTA).to_vec();
        normalize(&cross(&dx, &dz))
      });
    );

    let half_width = SAMPLE_WIDTH / 2.0;
    let center = at!(position.x + half_width, position.z + half_width);

    if position.y < center.y && center.y <= position.y + BLOCK_WIDTH as f32 {
      timers.time("update.generate_block.add_tile", || {
        let center_normal = normal_at!(position.x + half_width, position.z + half_width);

        let x2 = position.x + SAMPLE_WIDTH;
        let z2 = position.z + SAMPLE_WIDTH;

        let v1 = at!(position.x, position.z);
        let v2 = at!(position.x, z2);
        let v3 = at!(x2, z2);
        let v4 = at!(x2, position.z);

        let n1 = normal_at!(position.x, position.z);
        let n2 = normal_at!(position.x, z2);
        let n3 = normal_at!(x2, z2);
        let n4 = normal_at!(x2, position.z);

        let mut center_lower_than: int = 0;
        for v in [v1, v2, v3, v4].iter() {
          if center.y < v.y {
            center_lower_than += 1;
          }
        }
        let terrain_type =
          if center_lower_than >= 3 {
            TerrainType::Dirt
          } else {
            TerrainType::Grass
          };

        macro_rules! place_terrain(
          ($v1: expr,
           $v2: expr,
           $n1: expr,
           $n2: expr,
           $minx: expr,
           $minz: expr,
           $maxx: expr,
           $maxz: expr
          ) => ({
            let mut maxy = $v1.y;
            if $v2.y > $v1.y {
              maxy = $v2.y;
            }
            if center.y > maxy {
              maxy = center.y;
            }

            let id = id_allocator.allocate();
            block.vertex_coordinates.push_all(&[
              $v1.x, $v1.y, $v1.z,
              $v2.x, $v2.y, $v2.z,
              center.x, center.y, center.z,
            ]);
            block.normals.push_all(&[
              $n1.x, $n1.y, $n1.z,
              $n2.x, $n2.y, $n2.z,
              center_normal.x, center_normal.y, center_normal.z,
            ]);
            block.typs.push(terrain_type as GLuint);
            block.ids.push(id);
            block.bounds.insert(
              id,
              AABB::new(
                Pnt3::new($minx, $v1.y, $minz),
                Pnt3::new($maxx, maxy, $maxz),
              ),
            );
          });
        );

        place_terrain!(&v1, &v2, &n1, &n2, v1.x, v1.z, center.x, v2.z);
        place_terrain!(&v2, &v3, &n2, &n3, v2.x, center.z, v3.x, v3.z);
        place_terrain!(&v3, &v4, &n3, &n4, center.x, center.z, v3.x, v3.z);
        place_terrain!(&v4, &v1, &n4, &n1, v1.x, v1.z, v4.x, center.z);
      })
    }
  }
}

<commit_msg>--macros<commit_after>use gl::types::*;
use id_allocator::IdAllocator;
use nalgebra::{normalize, cross};
use nalgebra::{Pnt3, Vec3};
use ncollide::bounding_volume::{AABB, AABB3};
use noise::source::Perlin;
use noise::model::Plane;
use state::EntityId;
use std::collections::hash_map::HashMap;
use std::num::Float;
use stopwatch::TimerSet;
use terrain::{AMPLITUDE, TerrainType};

pub const BLOCK_WIDTH: i32 = 4;
// Number of samples in a single dimension per block.
pub const SAMPLES_PER_BLOCK: uint = 16;
pub const SAMPLE_WIDTH: f32 = BLOCK_WIDTH as f32 / SAMPLES_PER_BLOCK as f32;

#[deriving(Show, PartialEq, Eq, Hash, Copy, Clone)]
pub struct BlockPosition(Pnt3<i32>);

impl BlockPosition {
  #[inline(always)]
  pub fn new(x: i32, y: i32, z: i32) -> BlockPosition {
    BlockPosition(Pnt3::new(x, y, z))
  }

  #[inline(always)]
  pub fn as_pnt<'a>(&'a self) -> &'a Pnt3<i32> {
    let BlockPosition(ref pnt) = *self;
    pnt
  }

  #[inline(always)]
  pub fn as_mut_pnt3<'a>(&'a mut self) -> &'a mut Pnt3<i32> {
    let BlockPosition(ref mut pnt) = *self;
    pnt
  }

  pub fn from_world_position(world_position: &Pnt3<f32>) -> BlockPosition {
    macro_rules! convert_coordinate(
      ($x: expr) => ({
        let x = $x.floor() as i32;
        let x =
          if x < 0 {
            x - (BLOCK_WIDTH - 1)
          } else {
            x
          };
        x / BLOCK_WIDTH
      })
    );
    BlockPosition(
      Pnt3::new(
        convert_coordinate!(world_position.x),
        convert_coordinate!(world_position.y),
        convert_coordinate!(world_position.z),
      )
    )
  }

  pub fn to_world_position(&self) -> Pnt3<f32> {
    Pnt3::new(
      (self.as_pnt().x * BLOCK_WIDTH) as f32,
      (self.as_pnt().y * BLOCK_WIDTH) as f32,
      (self.as_pnt().z * BLOCK_WIDTH) as f32,
    )
  }
}

impl Add<Vec3<i32>, BlockPosition> for BlockPosition {
  fn add(mut self, rhs: Vec3<i32>) -> Self {
    self.as_mut_pnt3().x += rhs.x;
    self.as_mut_pnt3().y += rhs.y;
    self.as_mut_pnt3().z += rhs.z;
    self
  }
}

pub struct TerrainBlock {
  // These Vecs must all be ordered the same way.

  // vertex coordinates flattened into separate GLfloats (x, y, z order)
  pub vertex_coordinates: Vec<GLfloat>,
  // per-vertex normal vectors flattened into separate GLfloats (x, y, z order)
  pub normals: Vec<GLfloat>,
  // per-triangle terrain types
  pub typs: Vec<GLuint>,

  // per-triangle entity IDs
  pub ids: Vec<EntityId>,
  // per-triangle bounding boxes
  pub bounds: HashMap<EntityId, AABB3<GLfloat>>,
}

impl TerrainBlock {
  pub fn empty() -> TerrainBlock {
    TerrainBlock {
      vertex_coordinates: Vec::new(),
      normals: Vec::new(),
      typs: Vec::new(),
      ids: Vec::new(),
      bounds: HashMap::new(),
    }
  }

  pub fn generate(
    timers: &TimerSet,
    id_allocator: &mut IdAllocator<EntityId>,
    heightmap: &Perlin,
    position: &BlockPosition,
  ) -> TerrainBlock {
    timers.time("update.generate_block", || {
      let mut block = TerrainBlock::empty();
      let heightmap = Plane::new(heightmap);

      let x = (position.as_pnt().x * BLOCK_WIDTH) as f32;
      let y = (position.as_pnt().y * BLOCK_WIDTH) as f32;
      let z = (position.as_pnt().z * BLOCK_WIDTH) as f32;

      for dx in range(0, SAMPLES_PER_BLOCK) {
        let x = x + dx as f32 * SAMPLE_WIDTH;
        for dz in range(0, SAMPLES_PER_BLOCK) {
          let z = z + dz as f32 * SAMPLE_WIDTH;
          let position = Pnt3::new(x, y, z);
          TerrainBlock::add_tile(
            timers,
            &heightmap,
            id_allocator,
            &mut block,
            &position,
          );
        }
      }

      block
    })
  }

  fn add_tile<'a>(
    timers: &TimerSet,
    hm: &Plane<'a, Perlin>,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
    position: &Pnt3<f32>,
  ) {
    fn at(hm: &Plane<Perlin>, x: f32, z: f32) -> Pnt3<f32> {
      let y = AMPLITUDE * (hm.get(x, z) + 1.0) / 2.0;
      Pnt3::new(x, y, z)
    }

    fn normal_at(hm: &Plane<Perlin>, x: f32, z: f32) -> Vec3<f32> {
      const DELTA: f32 = 0.2;
      let dx = at(hm, x + DELTA, z).to_vec() - at(hm, x - DELTA, z).to_vec();
      let dz = at(hm, x, z + DELTA).to_vec() - at(hm, x, z - DELTA).to_vec();
      normalize(&cross(&dx, &dz))
    }

    let half_width = SAMPLE_WIDTH / 2.0;
    let center = at(hm, position.x + half_width, position.z + half_width);

    if position.y < center.y && center.y <= position.y + BLOCK_WIDTH as f32 {
      timers.time("update.generate_block.add_tile", || {
        let center_normal = normal_at(hm, position.x + half_width, position.z + half_width);

        let x2 = position.x + SAMPLE_WIDTH;
        let z2 = position.z + SAMPLE_WIDTH;

        let vs: [Pnt3<f32>, ..4] =
          [ at(hm, position.x, position.z)
          , at(hm, position.x, z2)
          , at(hm, x2, z2)
          , at(hm, x2, position.z)
          ];

        let ns: [Vec3<f32>, ..4] =
          [ normal_at(hm, position.x, position.z)
          , normal_at(hm, position.x, x2)
          , normal_at(hm, x2, z2)
          , normal_at(hm, x2, position.z)
          ];

        let center_lower_than = vs.iter().filter(|v| center.y < v.y).count();

        let terrain_type =
          if center_lower_than >= 3 {
            TerrainType::Dirt
          } else {
            TerrainType::Grass
          };

        macro_rules! place_terrain(
          ($v1: expr,
           $v2: expr,
           $n1: expr,
           $n2: expr,
           $minx: expr,
           $minz: expr,
           $maxx: expr,
           $maxz: expr
          ) => ({
            let mut maxy = $v1.y;
            if $v2.y > $v1.y {
              maxy = $v2.y;
            }
            if center.y > maxy {
              maxy = center.y;
            }

            let id = id_allocator.allocate();
            block.vertex_coordinates.push_all(&[
              $v1.x, $v1.y, $v1.z,
              $v2.x, $v2.y, $v2.z,
              center.x, center.y, center.z,
            ]);
            block.normals.push_all(&[
              $n1.x, $n1.y, $n1.z,
              $n2.x, $n2.y, $n2.z,
              center_normal.x, center_normal.y, center_normal.z,
            ]);
            block.typs.push(terrain_type as GLuint);
            block.ids.push(id);
            block.bounds.insert(
              id,
              AABB::new(
                Pnt3::new($minx, $v1.y, $minz),
                Pnt3::new($maxx, maxy, $maxz),
              ),
            );
          });
        );

        let centr = center; // makes alignment nice
        place_terrain!(&vs[0], &vs[1], &ns[0], &ns[1], vs[0].x, vs[0].z, centr.x, vs[1].z);
        place_terrain!(&vs[1], &vs[2], &ns[1], &ns[2], vs[1].x, centr.z, vs[2].x, vs[2].z);
        place_terrain!(&vs[2], &vs[3], &ns[2], &ns[3], centr.x, centr.z, vs[2].x, vs[2].z);
        place_terrain!(&vs[3], &vs[0], &ns[3], &ns[0], vs[0].x, vs[0].z, vs[3].x, centr.z);
      })
    }
  }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

mod ffi {
#![allow(dead_code)]
#![allow(non_camel_case_types)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

use std::ptr;
use std::ffi::CStr;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::os::raw::*;

pub use self::ffi::ParseTreeNodeType as ParseTreeNodeType;
pub use self::ffi::ParseTreeOperatorType as ParseTreeOperatorType;
pub use self::ffi::ParseTreeRangeDirection as ParseTreeRangeDirection;
pub use self::ffi::ParseTreeForceMode as ParseTreeForceMode;
pub use self::ffi::ParseTreeFunctionPurity as ParseTreeFunctionPurity;
pub use self::ffi::ParseTreeInterfaceObjectMode as ParseTreeInterfaceObjectMode;
pub use self::ffi::ParseTreeSubprogramKind as ParseTreeSubprogramKind;
pub use self::ffi::ParseTreeEntityClass as ParseTreeEntityClass;
pub use self::ffi::ParseTreeSignalKind as ParseTreeSignalKind;

// FIXME: Copypasta problems?
pub struct VhdlParseTreeNode {
    pub node_type: ParseTreeNodeType,
    pub str1: Vec<u8>,
    pub str2: Vec<u8>,
    pub chr: u8,
    pub integer: i32,
    pub boolean: bool,
    pub boolean2: bool,
    pub boolean3: bool,
    pub pieces: Vec<VhdlParseTreeNode>,
    pub op_type: ParseTreeOperatorType,
    pub range_dir: ParseTreeRangeDirection,
    pub force_mode: ParseTreeForceMode,
    pub purity: ParseTreeFunctionPurity,
    pub interface_mode: ParseTreeInterfaceObjectMode,
    pub subprogram_kind: ParseTreeSubprogramKind,
    pub entity_class: ParseTreeEntityClass,
    pub signal_kind: ParseTreeSignalKind,
    pub first_line: i32,
    pub first_column: i32,
    pub last_line: i32,
    pub last_column: i32,

    raw_node: *mut ffi::VhdlParseTreeNode,
    // We only want to call free on the root
    is_root: bool,
}

unsafe fn rustify_str(input: *mut c_char) -> String {
    // Get the string into something Rust can handle
    let string_rs = CStr::from_ptr(input);
    let string_rs = String::from(string_rs.to_str().unwrap());
    // Free the C string
    ffi::VhdlParserFreeString(input);

    string_rs
}

unsafe fn rustify_stdstring(input: *mut c_void) -> Vec<u8> {
    if input.is_null() {
        return vec![];
    }

    let null_terminated_string = ffi::VhdlParserCifyString(input);
    let string_rs = CStr::from_ptr(null_terminated_string);
    let string_rs = string_rs.to_bytes().to_vec();
    // Free the C string
    ffi::VhdlParserFreeString(null_terminated_string);

    string_rs
}

unsafe fn rustify_node(
    input: *mut ffi::VhdlParseTreeNode, is_root: bool) -> VhdlParseTreeNode {

    let str1 = rustify_stdstring((*input).str);
    let str2 = rustify_stdstring((*input).str2);

    let mut inner_nodes = Vec::with_capacity(ffi::NUM_FIXED_PIECES as usize);
    // Recursively convert inner nodes first
    for i in 0..ffi::NUM_FIXED_PIECES {
        let this_child = (*input).pieces[i as usize];
        if this_child.is_null() {
            break;
        }
        inner_nodes.push(rustify_node(this_child, false));
    }

    let ret = VhdlParseTreeNode {
        node_type: (*input).type_,
        chr: (*input).chr as u8,
        integer: (*input).integer,
        boolean: (*input).boolean,
        boolean2: (*input).boolean2,
        boolean3: (*input).boolean3,
        op_type: (*input).op_type,
        range_dir: (*input).range_dir,
        force_mode: (*input).force_mode,
        purity: (*input).purity,
        interface_mode: (*input).interface_mode,
        subprogram_kind: (*input).subprogram_kind,
        entity_class: (*input).entity_class,
        signal_kind: (*input).signal_kind,
        first_line: (*input).first_line,
        first_column: (*input).first_column,
        last_line: (*input).last_line,
        last_column: (*input).last_column,

        str1: str1,
        str2: str2,

        pieces: inner_nodes,

        raw_node: input,
        is_root: is_root,
    };

    ret
}

pub fn parse_file(filename: &OsStr) -> (Option<VhdlParseTreeNode>, String) {
    unsafe {
        let mut errors: *mut c_char = ptr::null_mut::<c_char>();
        let ret = ffi::VhdlParserParseFile(
            filename.as_bytes().as_ptr() as *const i8,
            &mut errors);

        let errors_rs = rustify_str(errors);

        if ret.is_null() {
            (None, errors_rs)
        } else {
            // Need to Rust-ify the struct
            (Some(rustify_node(ret, true)), errors_rs)
        }
    }
}

impl Drop for VhdlParseTreeNode {
    fn drop(&mut self) {
        unsafe {
            if self.is_root {
                ffi::VhdlParserFreePT(self.raw_node);
            }
        }
    }
}

impl VhdlParseTreeNode {
    pub fn debug_print(&self) {
        unsafe {
            ffi::VhdlParseTreeNodeDebugPrint(self.raw_node);
        }
    }
}
<commit_msg>Cleanups<commit_after>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

mod ffi {
#![allow(dead_code)]
#![allow(non_camel_case_types)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

use std::ptr;
use std::ffi::CStr;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::os::raw::*;

pub use self::ffi::ParseTreeNodeType;
pub use self::ffi::ParseTreeOperatorType;
pub use self::ffi::ParseTreeRangeDirection;
pub use self::ffi::ParseTreeForceMode;
pub use self::ffi::ParseTreeFunctionPurity;
pub use self::ffi::ParseTreeInterfaceObjectMode;
pub use self::ffi::ParseTreeSubprogramKind;
pub use self::ffi::ParseTreeEntityClass;
pub use self::ffi::ParseTreeSignalKind;

// FIXME: Copypasta problems?
pub struct VhdlParseTreeNode {
    pub node_type: ParseTreeNodeType,
    pub str1: Vec<u8>,
    pub str2: Vec<u8>,
    pub chr: u8,
    pub integer: i32,
    pub boolean: bool,
    pub boolean2: bool,
    pub boolean3: bool,
    pub pieces: Vec<VhdlParseTreeNode>,
    pub op_type: ParseTreeOperatorType,
    pub range_dir: ParseTreeRangeDirection,
    pub force_mode: ParseTreeForceMode,
    pub purity: ParseTreeFunctionPurity,
    pub interface_mode: ParseTreeInterfaceObjectMode,
    pub subprogram_kind: ParseTreeSubprogramKind,
    pub entity_class: ParseTreeEntityClass,
    pub signal_kind: ParseTreeSignalKind,
    pub first_line: i32,
    pub first_column: i32,
    pub last_line: i32,
    pub last_column: i32,

    raw_node: *mut ffi::VhdlParseTreeNode,
    // We only want to call free on the root
    is_root: bool,
}

unsafe fn rustify_str(input: *mut c_char) -> String {
    // Get the string into something Rust can handle
    let string_rs = CStr::from_ptr(input);
    let string_rs = String::from(string_rs.to_str().unwrap());
    // Free the C string
    ffi::VhdlParserFreeString(input);

    string_rs
}

unsafe fn rustify_stdstring(input: *mut c_void) -> Vec<u8> {
    if input.is_null() {
        return vec![];
    }

    let null_terminated_string = ffi::VhdlParserCifyString(input);
    let string_rs = CStr::from_ptr(null_terminated_string);
    let string_rs = string_rs.to_bytes().to_vec();
    // Free the C string
    ffi::VhdlParserFreeString(null_terminated_string);

    string_rs
}

unsafe fn rustify_node(
    input: *mut ffi::VhdlParseTreeNode, is_root: bool) -> VhdlParseTreeNode {

    let str1 = rustify_stdstring((*input).str);
    let str2 = rustify_stdstring((*input).str2);

    let mut inner_nodes = Vec::with_capacity(ffi::NUM_FIXED_PIECES as usize);
    // Recursively convert inner nodes first
    for i in 0..ffi::NUM_FIXED_PIECES {
        let this_child = (*input).pieces[i as usize];
        if this_child.is_null() {
            break;
        }
        inner_nodes.push(rustify_node(this_child, false));
    }

    VhdlParseTreeNode {
        node_type: (*input).type_,
        chr: (*input).chr as u8,
        integer: (*input).integer,
        boolean: (*input).boolean,
        boolean2: (*input).boolean2,
        boolean3: (*input).boolean3,
        op_type: (*input).op_type,
        range_dir: (*input).range_dir,
        force_mode: (*input).force_mode,
        purity: (*input).purity,
        interface_mode: (*input).interface_mode,
        subprogram_kind: (*input).subprogram_kind,
        entity_class: (*input).entity_class,
        signal_kind: (*input).signal_kind,
        first_line: (*input).first_line,
        first_column: (*input).first_column,
        last_line: (*input).last_line,
        last_column: (*input).last_column,

        str1: str1,
        str2: str2,

        pieces: inner_nodes,

        raw_node: input,
        is_root: is_root,
    }
}

pub fn parse_file(filename: &OsStr) -> (Option<VhdlParseTreeNode>, String) {
    unsafe {
        let mut errors = ptr::null_mut::<c_char>();
        let ret = ffi::VhdlParserParseFile(
            filename.as_bytes().as_ptr() as *const i8,
            &mut errors);

        let errors_rs = rustify_str(errors);

        if ret.is_null() {
            (None, errors_rs)
        } else {
            // Need to Rust-ify the struct
            (Some(rustify_node(ret, true)), errors_rs)
        }
    }
}

impl Drop for VhdlParseTreeNode {
    fn drop(&mut self) {
        unsafe {
            if self.is_root {
                ffi::VhdlParserFreePT(self.raw_node);
            }
        }
    }
}

impl VhdlParseTreeNode {
    pub fn debug_print(&self) {
        unsafe {
            ffi::VhdlParseTreeNodeDebugPrint(self.raw_node);
        }
    }
}
<|endoftext|>


<commit_before>use {File, SyntaxKind, Token};

use syntax_kinds::*;

#[macro_use]
mod parser;
mod event;
mod grammar;
use self::event::Event;

/// Parse a sequence of tokens into the representative node tree
pub fn parse(text: String, tokens: &[Token]) -> File {
    let events = parse_into_events(&text, tokens);
    event::to_file(text, tokens, events)
}

pub(crate) fn parse_into_events<'t>(text: &'t str, raw_tokens: &'t [Token]) -> Vec<Event> {
    let mut parser = parser::Parser::new(text, raw_tokens);
    grammar::file(&mut parser);
    parser.into_events()
}

fn is_insignificant(kind: SyntaxKind) -> bool {
    match kind {
        WHITESPACE | COMMENT => true,
        _ => false,
    }
}
<commit_msg>Simplify<commit_after>use {File, SyntaxKind, Token};

use syntax_kinds::*;

#[macro_use]
mod parser;
mod event;
mod grammar;
use self::event::Event;

/// Parse a sequence of tokens into the representative node tree
pub fn parse(text: String, tokens: &[Token]) -> File {
    let events = {
        let mut parser = parser::Parser::new(&text, tokens);
        grammar::file(&mut parser);
        parser.into_events()
    };
    event::to_file(text, tokens, events)
}

fn is_insignificant(kind: SyntaxKind) -> bool {
    match kind {
        WHITESPACE | COMMENT => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>use domination::Domination;
use multi_objective::MultiObjective;
use crowding_distance::CrowdingDistanceAssignment; // XXX: Change name
use selection::SelectSolutions;
use rayon::par_iter::*;
use selection::tournament_selection_fast;
use rand::Rng;
use std::u32;

pub struct Individual<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    genome: G,

    // The individuals fitness.
    fitness: Option<F>,

    // which pareto front this rated individual belongs to (only valid if fitness.is_some() and
    // pareto fronts have been determined)
    pareto_rank: u32,

    // The crowding distance to neighboring individuals (individuals with similar fitness)
    crowding_distance: f64,

    // the number of individuals in each crowd (points of equal fitness)
    crowd_size: u32,

    selected: bool,
}

impl<G, F> CrowdingDistanceAssignment<F> for Individual<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    fn rank_mut(&mut self) -> &mut u32 {
        &mut self.pareto_rank
    }
    fn dist_mut(&mut self) -> &mut f64 {
        &mut self.crowding_distance
    }
    fn rank(&self) -> u32 {
        self.pareto_rank
    }
    fn dist(&self) -> f64 {
        self.crowding_distance
    }

    fn select(&mut self) {
        assert!(self.selected == false);
        self.selected = true;
    }
    fn unselect(&mut self) {
        self.selected = false;
    }
    fn is_selected(&self) -> bool {
        self.selected
    }

    fn crowd(&self) -> usize {
        self.crowd_size as usize
    }

    fn set_crowd(&mut self, crowd: usize) {
        self.crowd_size = crowd as u32;
    }
}

impl<G, F> Individual<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    fn from_genome(genome: G) -> Self {
        Individual {
            genome: genome,
            fitness: None,
            pareto_rank: u32::MAX,
            crowding_distance: 0.0,
            crowd_size: 1,
            selected: false,
        }
    }

    pub fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    pub fn fitness_mut(&mut self) -> &mut F {
        self.fitness.as_mut().unwrap()
    }
}

/// An unrated Population of individuals.

pub struct UnratedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A rated Population of individuals, i.e. each individual has a fitness assigned.

pub struct RatedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A ranked (selected) Population (pareto_rank and crowding_distance).

pub struct RankedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    individuals: Vec<Individual<G, F>>,
}

impl<G, F> UnratedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }

    pub fn new() -> Self {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, genome: G) {
        self.individuals.push(Individual::from_genome(genome));
    }

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

    /// Rate the individuals in parallel.

    pub fn rate_in_parallel<E>(self, eval: &E, weight: f64) -> RatedPopulation<G, F>
        where E: Fn(&G) -> F + Sync
    {
        let UnratedPopulation { mut individuals } = self;

        individuals.par_iter_mut().weight(weight).for_each(|ind| {
            assert!(ind.fitness.is_none());
            let fitness = eval(&ind.genome);
            ind.fitness = Some(fitness);
        });

        RatedPopulation { individuals: individuals }
    }
}

impl<G, F> RatedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    pub fn select<S, R>(self, population_size: usize, num_objectives: usize, selection: &S, rng: &mut R) -> RankedPopulation<G, F>
        where S: SelectSolutions<Individual<G, F>, F>,
              R: Rng
    {
        let RatedPopulation { mut individuals } = self;

        // evaluate rank and crowding distance: XXX: replace by Select trait
        selection.select_solutions(&mut individuals, population_size, num_objectives, rng);

        // only keep individuals which are selected
        individuals.retain(|i| i.is_selected());

        // sort by rank and crowding-distance
        individuals.sort_by(|a, b| a.rank_and_crowding_order(b));

        assert!(individuals.len() == population_size);

        RankedPopulation { individuals: individuals }
    }

    pub fn individuals_mut(&mut self) -> &mut [Individual<G, F>] {
        &mut self.individuals
    }

    pub fn new() -> Self {
        RatedPopulation { individuals: Vec::new() }
    }

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

    pub fn fitness(&self, index: usize) -> &F {
        self.individuals[index].fitness.as_ref().unwrap()
    }

    pub fn fitness_mut(&mut self, index: usize) -> &mut F {
        self.individuals[index].fitness.as_mut().unwrap()
    }
}

impl<G, F> RankedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    /// Generate an unrated offspring population.
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<G, F>
        where R: Rng,
              M: Fn(&mut R, &G, &G) -> G
    {
        assert!(tournament_k > 0);
        assert!(self.len() > 0);

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<_> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if self.individuals[p1].has_better_rank_and_crowding(&self.individuals[p2]) {
                        (p1, p2)
                    } else if self.individuals[p2].has_better_rank_and_crowding(&self.individuals[p1]) {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    Individual::from_genome(mate(rng, &self.individuals[p1].genome, &self.individuals[p2].genome))
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> Self {
        RankedPopulation { individuals: Vec::new() }
    }

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

    /// Merging a ranked population with a rated population results in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<G, F>) -> RatedPopulation<G, F> {
        let RankedPopulation{mut individuals} = self;

        // XXX: Reset rank and crowding distance.

        individuals.extend(offspring.individuals);

        RatedPopulation { individuals: individuals }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            f(&ind.genome, ind.fitness.as_ref().unwrap());
        }
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.individuals.iter().map(|ind| ind.pareto_rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            if ind.pareto_rank as usize == rank {
                f(&ind.genome, ind.fitness.as_ref().unwrap());
            }
        }
    }

    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }
}
<commit_msg>Add genome() accessor<commit_after>use domination::Domination;
use multi_objective::MultiObjective;
use crowding_distance::CrowdingDistanceAssignment; // XXX: Change name
use selection::SelectSolutions;
use rayon::par_iter::*;
use selection::tournament_selection_fast;
use rand::Rng;
use std::u32;

pub struct Individual<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    genome: G,

    // The individuals fitness.
    fitness: Option<F>,

    // which pareto front this rated individual belongs to (only valid if fitness.is_some() and
    // pareto fronts have been determined)
    pareto_rank: u32,

    // The crowding distance to neighboring individuals (individuals with similar fitness)
    crowding_distance: f64,

    // the number of individuals in each crowd (points of equal fitness)
    crowd_size: u32,

    selected: bool,
}

impl<G, F> CrowdingDistanceAssignment<F> for Individual<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    fn rank_mut(&mut self) -> &mut u32 {
        &mut self.pareto_rank
    }
    fn dist_mut(&mut self) -> &mut f64 {
        &mut self.crowding_distance
    }
    fn rank(&self) -> u32 {
        self.pareto_rank
    }
    fn dist(&self) -> f64 {
        self.crowding_distance
    }

    fn select(&mut self) {
        assert!(self.selected == false);
        self.selected = true;
    }
    fn unselect(&mut self) {
        self.selected = false;
    }
    fn is_selected(&self) -> bool {
        self.selected
    }

    fn crowd(&self) -> usize {
        self.crowd_size as usize
    }

    fn set_crowd(&mut self, crowd: usize) {
        self.crowd_size = crowd as u32;
    }
}

impl<G, F> Individual<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    fn from_genome(genome: G) -> Self {
        Individual {
            genome: genome,
            fitness: None,
            pareto_rank: u32::MAX,
            crowding_distance: 0.0,
            crowd_size: 1,
            selected: false,
        }
    }

    pub fn genome(&self) -> &G {
        &self.genome
    }

    pub fn fitness(&self) -> &F {
        self.fitness.as_ref().unwrap()
    }
    pub fn fitness_mut(&mut self) -> &mut F {
        self.fitness.as_mut().unwrap()
    }
}

/// An unrated Population of individuals.

pub struct UnratedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A rated Population of individuals, i.e. each individual has a fitness assigned.

pub struct RatedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    individuals: Vec<Individual<G, F>>,
}

/// A ranked (selected) Population (pareto_rank and crowding_distance).

pub struct RankedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    individuals: Vec<Individual<G, F>>,
}

impl<G, F> UnratedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }

    pub fn new() -> Self {
        UnratedPopulation { individuals: Vec::new() }
    }

    pub fn push(&mut self, genome: G) {
        self.individuals.push(Individual::from_genome(genome));
    }

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

    /// Rate the individuals in parallel.

    pub fn rate_in_parallel<E>(self, eval: &E, weight: f64) -> RatedPopulation<G, F>
        where E: Fn(&G) -> F + Sync
    {
        let UnratedPopulation { mut individuals } = self;

        individuals.par_iter_mut().weight(weight).for_each(|ind| {
            assert!(ind.fitness.is_none());
            let fitness = eval(&ind.genome);
            ind.fitness = Some(fitness);
        });

        RatedPopulation { individuals: individuals }
    }
}

impl<G, F> RatedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    pub fn select<S, R>(self, population_size: usize, num_objectives: usize, selection: &S, rng: &mut R) -> RankedPopulation<G, F>
        where S: SelectSolutions<Individual<G, F>, F>,
              R: Rng
    {
        let RatedPopulation { mut individuals } = self;

        // evaluate rank and crowding distance: XXX: replace by Select trait
        selection.select_solutions(&mut individuals, population_size, num_objectives, rng);

        // only keep individuals which are selected
        individuals.retain(|i| i.is_selected());

        // sort by rank and crowding-distance
        individuals.sort_by(|a, b| a.rank_and_crowding_order(b));

        assert!(individuals.len() == population_size);

        RankedPopulation { individuals: individuals }
    }

    pub fn individuals_mut(&mut self) -> &mut [Individual<G, F>] {
        &mut self.individuals
    }

    pub fn new() -> Self {
        RatedPopulation { individuals: Vec::new() }
    }

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

    pub fn fitness(&self, index: usize) -> &F {
        self.individuals[index].fitness.as_ref().unwrap()
    }

    pub fn fitness_mut(&mut self, index: usize) -> &mut F {
        self.individuals[index].fitness.as_mut().unwrap()
    }
}

impl<G, F> RankedPopulation<G, F>
    where F: MultiObjective + Domination,
          G: Send
{
    /// Generate an unrated offspring population.
    pub fn reproduce<R, M>(&self,
                           rng: &mut R,
                           offspring_size: usize,
                           tournament_k: usize,
                           mate: &M)
                           -> UnratedPopulation<G, F>
        where R: Rng,
              M: Fn(&mut R, &G, &G) -> G
    {
        assert!(tournament_k > 0);
        assert!(self.len() > 0);

        // create `offspring_size` new offspring using k-tournament (
        // select the best individual out of k randomly choosen individuals)
        let offspring: Vec<_> =
            (0..offspring_size)
                .map(|_| {

                    // first parent. k candidates
                    let p1 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // second parent. k candidates
                    let p2 = tournament_selection_fast(rng,
                                                       |i1, i2| self.individuals[i1].has_better_rank_and_crowding(&self.individuals[i2]),
                                                       self.len(),
                                                       tournament_k);

                    // cross-over the two parents and produce one child (throw away
                    // second child XXX)

                    // The potentially dominating individual is gives as first
                    // parameter.
                    let (p1, p2) = if self.individuals[p1].has_better_rank_and_crowding(&self.individuals[p2]) {
                        (p1, p2)
                    } else if self.individuals[p2].has_better_rank_and_crowding(&self.individuals[p1]) {
                        (p2, p1)
                    } else {
                        (p1, p2)
                    };

                    Individual::from_genome(mate(rng, &self.individuals[p1].genome, &self.individuals[p2].genome))
                })
                .collect();

        assert!(offspring.len() == offspring_size);

        UnratedPopulation { individuals: offspring }
    }

    pub fn new() -> Self {
        RankedPopulation { individuals: Vec::new() }
    }

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

    /// Merging a ranked population with a rated population results in a rated population as the selection
    /// criteria is no longer met.
    pub fn merge(self, offspring: RatedPopulation<G, F>) -> RatedPopulation<G, F> {
        let RankedPopulation{mut individuals} = self;

        // XXX: Reset rank and crowding distance.

        individuals.extend(offspring.individuals);

        RatedPopulation { individuals: individuals }
    }

    pub fn all<C>(&self, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            f(&ind.genome, ind.fitness.as_ref().unwrap());
        }
    }

    pub fn max_rank(&self) -> Option<usize> {
        self.individuals.iter().map(|ind| ind.pareto_rank).max().map(|r| r as usize)
    }

    pub fn all_of_rank<C>(&self, rank: usize, f: &mut C)
        where C: FnMut(&G, &F)
    {
        for ind in &self.individuals {
            if ind.pareto_rank as usize == rank {
                f(&ind.genome, ind.fitness.as_ref().unwrap());
            }
        }
    }

    pub fn individuals(&self) -> &[Individual<G, F>] {
        &self.individuals
    }
}
<|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 dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::Reflectable;
use dom::document::Document;
use dom::element::HTMLBodyElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::WindowMethods;
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLBodyElement {
    pub htmlelement: HTMLElement
}

impl HTMLBodyElementDerived for EventTarget {
    fn is_htmlbodyelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLBodyElementTypeId))
    }
}

impl HTMLBodyElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLBodyElement {
        HTMLBodyElement {
            htmlelement: HTMLElement::new_inherited(HTMLBodyElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLBodyElement> {
        let element = HTMLBodyElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap)
    }
}

pub trait HTMLBodyElementMethods {
    fn GetOnunload(&self) -> Option<EventHandlerNonNull>;
    fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>);
}

impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> {
    fn GetOnunload(&self) -> Option<EventHandlerNonNull> {
        let win = window_from_node(self).root();
        win.deref().GetOnunload()
    }

    fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>) {
        let mut win = window_from_node(self).root();
        win.SetOnunload(listener)
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods:> {
        let element: &JSRef<HTMLElement> = HTMLElementCast::from_ref(self);
        Some(element as &VirtualMethods:)
    }

    fn after_set_attr(&self, name: DOMString, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name.clone(), value.clone()),
            _ => (),
        }

        if name.as_slice().starts_with("on") {
            static forwarded_events: &'static [&'static str] =
                &["onfocus", "onload", "onscroll", "onafterprint", "onbeforeprint",
                  "onbeforeunload", "onhashchange", "onlanguagechange", "onmessage",
                  "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate",
                  "onstorage", "onresize", "onunload", "onerror"];
            let mut window = window_from_node(self).root();
            let (cx, url, reflector) = (window.get_cx(),
                                        window.get_url(),
                                        window.reflector().get_jsobject());
            let evtarget: &JSRef<EventTarget> =
                if forwarded_events.iter().any(|&event| name.as_slice() == event) {
                    EventTargetCast::from_ref(&*window)
                } else {
                    EventTargetCast::from_ref(self)
                };
            evtarget.set_event_handler_uncompiled(cx, url, reflector,
                                                  name.as_slice().slice_from(2),
                                                  value);
        }
    }
}
<commit_msg>Pass immutable self to HTMLBodyElement::SetOnunload.<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 dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::Reflectable;
use dom::document::Document;
use dom::element::HTMLBodyElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::WindowMethods;
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLBodyElement {
    pub htmlelement: HTMLElement
}

impl HTMLBodyElementDerived for EventTarget {
    fn is_htmlbodyelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLBodyElementTypeId))
    }
}

impl HTMLBodyElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLBodyElement {
        HTMLBodyElement {
            htmlelement: HTMLElement::new_inherited(HTMLBodyElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLBodyElement> {
        let element = HTMLBodyElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap)
    }
}

pub trait HTMLBodyElementMethods {
    fn GetOnunload(&self) -> Option<EventHandlerNonNull>;
    fn SetOnunload(&self, listener: Option<EventHandlerNonNull>);
}

impl<'a> HTMLBodyElementMethods for JSRef<'a, HTMLBodyElement> {
    fn GetOnunload(&self) -> Option<EventHandlerNonNull> {
        let win = window_from_node(self).root();
        win.deref().GetOnunload()
    }

    fn SetOnunload(&self, listener: Option<EventHandlerNonNull>) {
        let win = window_from_node(self).root();
        win.deref().SetOnunload(listener)
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods:> {
        let element: &JSRef<HTMLElement> = HTMLElementCast::from_ref(self);
        Some(element as &VirtualMethods:)
    }

    fn after_set_attr(&self, name: DOMString, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name.clone(), value.clone()),
            _ => (),
        }

        if name.as_slice().starts_with("on") {
            static forwarded_events: &'static [&'static str] =
                &["onfocus", "onload", "onscroll", "onafterprint", "onbeforeprint",
                  "onbeforeunload", "onhashchange", "onlanguagechange", "onmessage",
                  "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate",
                  "onstorage", "onresize", "onunload", "onerror"];
            let mut window = window_from_node(self).root();
            let (cx, url, reflector) = (window.get_cx(),
                                        window.get_url(),
                                        window.reflector().get_jsobject());
            let evtarget: &JSRef<EventTarget> =
                if forwarded_events.iter().any(|&event| name.as_slice() == event) {
                    EventTargetCast::from_ref(&*window)
                } else {
                    EventTargetCast::from_ref(self)
                };
            evtarget.set_event_handler_uncompiled(cx, url, reflector,
                                                  name.as_slice().slice_from(2),
                                                  value);
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use super::byteorder::{BigEndian, ByteOrder};

use super::sdl2;
use super::sdl2::pixels::Color;
use super::sdl2::rect::Point;
use super::sdl2::event::Event;
use super::sdl2::keyboard::Keycode;

// Size of the memory map of a CHIP-8 interpreter is 4kb.
const RAM_SIZE: usize = 4096;

// Where fonts are stored in interpreter memory.
const FONT_OFFSET: usize = 0;

// Font size constants.
const CHARACTER_SIZE: usize = 5;
const CHARACTER_COUNT: usize = 16;

// Display size parameters.
const DISPLAY_WIDTH: usize = 64;
const DISPLAY_HEIGHT: usize = 32;
const DISPLAY_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT;

// Memory map constraints.
pub const START_RESERVED: usize = 0x000;
pub const END_RESERVED: usize = 0x200;
pub const END_PROGRAM_SPACE: usize = 0xFFF;

pub struct Interconnect {
    sdl_context: sdl2::Sdl,
    video_subsystem: sdl2::VideoSubsystem,
    renderer: sdl2::render::Renderer<'static>,
    event_pump: sdl2::EventPump,

    pub halt: bool,

    pub ram: Vec<u8>,
    pub display: Vec<u8>,
}

impl Interconnect {
    pub fn new(rom: Vec<u8>) -> Interconnect {
        let mut ram = vec![0; RAM_SIZE];

        // Dump the rom into ram starting at the start of the program space.
        for i in 0..rom.len() {
            ram[i + END_RESERVED] = rom[i];
        }

        // Setup SDL for graphics and audio.
        let sdl_context = sdl2::init().unwrap();
        let video_subsystem = sdl_context.video().unwrap();
        let window = video_subsystem.window("Notch", 640, 320)
            .position_centered()
            .opengl()
            .build()
            .unwrap();

        let mut renderer = window.renderer().build().unwrap();
        renderer.set_scale(10.0, 10.0);

        // Clear the screen to black.
        renderer.set_draw_color(Color::RGB(0, 0, 0));
        renderer.clear();
        renderer.present();

        let mut event_pump = sdl_context.event_pump().unwrap();

        let mut interconnect = Interconnect {
            sdl_context: sdl_context,
            video_subsystem: video_subsystem,
            renderer: renderer,
            event_pump: event_pump,

            halt: false,

            ram: ram,
            display: vec![0; DISPLAY_SIZE],
        };
        interconnect.dump_fonts();
        interconnect
    }

    pub fn handle_input(&mut self) {
        for event in self.event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    self.halt = true;
                },
                _ => {}
            }
        }
    }

    /// Reads a 16 bit word from ram. This function is used mainly to read and
    /// execute instructions.
    #[inline(always)]
    pub fn read_word(&self, addr: u16) -> u16 {
        BigEndian::read_u16(&self.ram[addr as usize..])
    }

    /// Dumps the standard CHIP-8 fonts to ram.
    pub fn dump_fonts(&mut self) {
        // The characters 0-F to be stored in ram as a font for chip 8 programs.
        // Vectorception for ease of reading.
        let fonts = vec![
            vec![0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
            vec![0x20, 0x60, 0x20, 0x20, 0x70], // 1
            vec![0xF0, 0x10, 0xf0, 0x80, 0xF0], // 2
            vec![0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
            vec![0x90, 0x90, 0xF0, 0x10, 0x10], // 4
            vec![0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
            vec![0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
            vec![0xF0, 0x10, 0x20, 0x40, 0x40], // 7
            vec![0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
            vec![0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
            vec![0xF0, 0x90, 0xF0, 0x90, 0x90], // A
            vec![0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
            vec![0xF0, 0x80, 0x80, 0x80, 0xF0], // C
            vec![0xE0, 0x90, 0x90, 0x90, 0xE0], // D
            vec![0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
            vec![0xF0, 0x80, 0xF0, 0x80, 0x80], // F
        ];

        for i in 0..CHARACTER_COUNT {
            // Find where the current character should be stored in memory.
            let start: usize = FONT_OFFSET + i * CHARACTER_SIZE;

            // Copy the current character into the calculated spot in memory.
            for j in 0..CHARACTER_SIZE {
                self.ram[start + j] = fonts[i][j];
            }
        }
    }

    /// Find the memory address of the requested character.
    #[inline(always)]
    pub fn get_font(&self, font: u8) -> u16 {
        FONT_OFFSET as u16 + font as u16 * CHARACTER_SIZE as u16
    }

    /// Draws a sprite to the display.
    #[inline(always)]
    pub fn draw(&mut self, x: usize, y: usize, sprite: Vec<u8>) -> u8 {
        let line = y * DISPLAY_WIDTH;
        let mut collision: u8 = 0;
        let mut values = vec![0 as u8; 8];

        for i in 0..sprite.len() {
            // Each byte in a sprite draws on one line.
            let offset = line + DISPLAY_WIDTH * i;

            // Organize the bits from the current sprite byte into a slice.
            for j in 0..values.len() {
                let bit = (sprite[i] >> j) & 0x01;
                values[8 - 1 - j] = bit;
            }

            // Loop through the bits in the current byte and set the display
            // values based on them.
            for j in 0..values.len() {
                let value = values[j];
                let pos: usize = x + j;
                let index: usize;

                // Draw a pixel in the sprite onto the display. If the pixel x
                // position is greater than the width of the display, the sprite
                // wraps around the display.
                if pos > DISPLAY_WIDTH {
                    // Wrap around to the left side to draw.
                    index = offset + pos - DISPLAY_WIDTH;
                } else {
                    // Draw at the current offset.
                    index = offset + pos;
                }

                // Save the previous state of the pixel before setting it
                // for collision detection.
                let prev = self.display[index];

                // Draw the bit to the display.
                self.display[index] = value ^ prev;

                // Check the previous state of the pixel and check if it
                // was erased, if so then there was a sprite collision.
                if prev == 1 && self.display[index] == 0 {
                    collision = 1;
                }
            }
        }

        // TODO: Get rid of when a real framebuffer is aquired. Just a way to
        // visually see what is being drawn in the terminal.
        self.draw_display();

        collision
    }

    /// Clears all pixels on the display by setting them all to an off state.
    pub fn clear_display(&mut self) {
        for i in 0..DISPLAY_SIZE {
            self.display[i] = 0;
        }
    }

    /// Draw the display to the terminal. Used primarily for debug purposes
    /// and will be replaced in the future when a framebuffer becomes available.
    fn draw_display(&mut self) {
        // Clear the screen to black.
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        self.renderer.clear();

        self.renderer.set_draw_color(Color::RGB(255, 255, 255));
        for i in 0..DISPLAY_HEIGHT {
            let offset = DISPLAY_WIDTH * i;
            for j in 0..DISPLAY_WIDTH {
                if self.display[offset + j] == 1 {
                    self.renderer.draw_point(Point::new(j as i32, i as i32));
                }
            }
        }
        self.renderer.present();
    }
}

impl fmt::Debug for Interconnect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "interconnect")
    }
}
<commit_msg>Updated irrevelant comments<commit_after>use std::fmt;

use super::byteorder::{BigEndian, ByteOrder};

use super::sdl2;
use super::sdl2::pixels::Color;
use super::sdl2::rect::Point;
use super::sdl2::event::Event;
use super::sdl2::keyboard::Keycode;

// Size of the memory map of a CHIP-8 interpreter is 4kb.
const RAM_SIZE: usize = 4096;

// Where fonts are stored in interpreter memory.
const FONT_OFFSET: usize = 0;

// Font size constants.
const CHARACTER_SIZE: usize = 5;
const CHARACTER_COUNT: usize = 16;

// Display size parameters.
const DISPLAY_WIDTH: usize = 64;
const DISPLAY_HEIGHT: usize = 32;
const DISPLAY_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT;

// Memory map constraints.
pub const START_RESERVED: usize = 0x000;
pub const END_RESERVED: usize = 0x200;
pub const END_PROGRAM_SPACE: usize = 0xFFF;

pub struct Interconnect {
    sdl_context: sdl2::Sdl,
    video_subsystem: sdl2::VideoSubsystem,
    renderer: sdl2::render::Renderer<'static>,
    event_pump: sdl2::EventPump,

    pub halt: bool,

    pub ram: Vec<u8>,
    pub display: Vec<u8>,
}

impl Interconnect {
    pub fn new(rom: Vec<u8>) -> Interconnect {
        let mut ram = vec![0; RAM_SIZE];

        // Dump the rom into ram starting at the start of the program space.
        for i in 0..rom.len() {
            ram[i + END_RESERVED] = rom[i];
        }

        // Setup SDL for graphics and audio.
        let sdl_context = sdl2::init().unwrap();
        let video_subsystem = sdl_context.video().unwrap();
        let window = video_subsystem.window("Notch", 640, 320)
            .position_centered()
            .opengl()
            .build()
            .unwrap();

        let mut renderer = window.renderer().build().unwrap();
        renderer.set_scale(10.0, 10.0);

        // Clear the screen to black.
        renderer.set_draw_color(Color::RGB(0, 0, 0));
        renderer.clear();
        renderer.present();

        let mut event_pump = sdl_context.event_pump().unwrap();

        let mut interconnect = Interconnect {
            sdl_context: sdl_context,
            video_subsystem: video_subsystem,
            renderer: renderer,
            event_pump: event_pump,

            halt: false,

            ram: ram,
            display: vec![0; DISPLAY_SIZE],
        };
        interconnect.dump_fonts();
        interconnect
    }

    pub fn handle_input(&mut self) {
        for event in self.event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    self.halt = true;
                },
                _ => {}
            }
        }
    }

    /// Reads a 16 bit word from ram. This function is used mainly to read and
    /// execute instructions.
    #[inline(always)]
    pub fn read_word(&self, addr: u16) -> u16 {
        BigEndian::read_u16(&self.ram[addr as usize..])
    }

    /// Dumps the standard CHIP-8 fonts to ram.
    pub fn dump_fonts(&mut self) {
        // The characters 0-F to be stored in ram as a font for chip 8 programs.
        // Vectorception for ease of reading.
        let fonts = vec![
            vec![0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
            vec![0x20, 0x60, 0x20, 0x20, 0x70], // 1
            vec![0xF0, 0x10, 0xf0, 0x80, 0xF0], // 2
            vec![0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
            vec![0x90, 0x90, 0xF0, 0x10, 0x10], // 4
            vec![0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
            vec![0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
            vec![0xF0, 0x10, 0x20, 0x40, 0x40], // 7
            vec![0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
            vec![0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
            vec![0xF0, 0x90, 0xF0, 0x90, 0x90], // A
            vec![0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
            vec![0xF0, 0x80, 0x80, 0x80, 0xF0], // C
            vec![0xE0, 0x90, 0x90, 0x90, 0xE0], // D
            vec![0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
            vec![0xF0, 0x80, 0xF0, 0x80, 0x80], // F
        ];

        for i in 0..CHARACTER_COUNT {
            // Find where the current character should be stored in memory.
            let start: usize = FONT_OFFSET + i * CHARACTER_SIZE;

            // Copy the current character into the calculated spot in memory.
            for j in 0..CHARACTER_SIZE {
                self.ram[start + j] = fonts[i][j];
            }
        }
    }

    /// Find the memory address of the requested character.
    #[inline(always)]
    pub fn get_font(&self, font: u8) -> u16 {
        FONT_OFFSET as u16 + font as u16 * CHARACTER_SIZE as u16
    }

    /// Draws a sprite to the display.
    #[inline(always)]
    pub fn draw(&mut self, x: usize, y: usize, sprite: Vec<u8>) -> u8 {
        let line = y * DISPLAY_WIDTH;
        let mut collision: u8 = 0;
        let mut values = vec![0 as u8; 8];

        for i in 0..sprite.len() {
            // Each byte in a sprite draws on one line.
            let offset = line + DISPLAY_WIDTH * i;

            // Organize the bits from the current sprite byte into a slice.
            for j in 0..values.len() {
                let bit = (sprite[i] >> j) & 0x01;
                values[8 - 1 - j] = bit;
            }

            // Loop through the bits in the current byte and set the display
            // values based on them.
            for j in 0..values.len() {
                let value = values[j];
                let pos: usize = x + j;
                let index: usize;

                // Draw a pixel in the sprite onto the display. If the pixel x
                // position is greater than the width of the display, the sprite
                // wraps around the display.
                if pos > DISPLAY_WIDTH {
                    // Wrap around to the left side to draw.
                    index = offset + pos - DISPLAY_WIDTH;
                } else {
                    // Draw at the current offset.
                    index = offset + pos;
                }

                // Save the previous state of the pixel before setting it
                // for collision detection.
                let prev = self.display[index];

                // Draw the bit to the display.
                self.display[index] = value ^ prev;

                // Check the previous state of the pixel and check if it
                // was erased, if so then there was a sprite collision.
                if prev == 1 && self.display[index] == 0 {
                    collision = 1;
                }
            }
        }

        // Draw to the SDL surface. Humans have these things called "eyes" and
        // they get upset when they cannot see things.
        self.draw_display();

        collision
    }

    /// Clears all pixels on the display by setting them all to an off state.
    pub fn clear_display(&mut self) {
        for i in 0..DISPLAY_SIZE {
            self.display[i] = 0;
        }
    }

    /// Draw the display to the SDL surface. All pixels are white.
    fn draw_display(&mut self) {
        // Clear the screen to black.
        self.renderer.set_draw_color(Color::RGB(0, 0, 0));
        self.renderer.clear();

        // Draw the display to the SDL surface.
        self.renderer.set_draw_color(Color::RGB(255, 255, 255));
        for i in 0..DISPLAY_HEIGHT {
            let offset = DISPLAY_WIDTH * i;
            for j in 0..DISPLAY_WIDTH {
                if self.display[offset + j] == 1 {
                    self.renderer.draw_point(Point::new(j as i32, i as i32));
                }
            }
        }
        self.renderer.present();
    }
}

impl fmt::Debug for Interconnect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "interconnect")
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;

#[derive(Debug)]
pub enum Command {
    Nick,
    User,
    Join,
    Quit,
    Ping,
    Mode,
    Pong,
    Pass,
    Numeric(u32),
    Unknown(String)
}

impl Command {
    pub fn as_str(&self) -> &'static str {
        match *self {
            Command::Nick => "NICK",
            Command::Join => "JOIN",
            Command::Pong => "PONG",
            Command::Numeric(1) => "001",
            _ => ""
        }
    }
}

impl Message {
    pub fn to_string(&self) -> String {
        let mut ret = String::new();
        match self.prefix {
            Some(ref pfx) => {
                ret.push(':');
                ret.push_str(pfx.trim());
                ret.push(' ');
            },
            None => ()
        };
        ret.push_str(self.command.as_str());
        for ref arg in self.args.iter() {
            ret.push(' ');
            ret.push_str(arg.trim());
        }

        return ret;
    }
}

impl From<Command> for Message {
    fn from(c: Command) -> Message {
        Message {
            prefix: None,
            command: c,
            args: vec![],
            suffix: None
        }
    }
}

impl FromStr for Command {
    type Err = Command;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NICK" => Ok(Command::Nick),
            "USER" => Ok(Command::User),
            "JOIN" => Ok(Command::Join),
            "QUIT" => Ok(Command::Quit),
            "PING" => Ok(Command::Ping),
            "MODE" => Ok(Command::Mode),
            "PASS" => Ok(Command::Pass),
            _ => Ok(Command::Unknown(s.to_string()))
        }
    }
}

#[derive(Debug)]
pub struct Message {
    pub prefix: Option<String>,
    pub command: Command,
    pub args: Vec<String>,
    pub suffix: Option<String>
}
<commit_msg>irc: protocol: restructure to/from str fns to reuiqre impls for all enum values<commit_after>use std::str::FromStr;

#[derive(Debug)]
pub enum Command {
    Nick,
    User,
    Join,
    Quit,
    Ping,
    Mode,
    Pong,
    Pass,
    Privmsg,
    Numeric(u32),
    Unknown(String)
}

impl Command {
    pub fn as_string(&self) -> String {
        match self {
            &Command::Nick => "NICK".to_string(),
            &Command::Join => "JOIN".to_string(),
            &Command::Pong => "PONG".to_string(),
            &Command::Privmsg => "PRIVMSG".to_string(),
            &Command::User => "USER".to_string(),
            &Command::Quit => "QUIT".to_string(),
            &Command::Ping => "PING".to_string(),
            &Command::Mode => "MODE".to_string(),
            &Command::Pass => "PASS".to_string(),
            &Command::Numeric(n)=> format!("{:3?}", n),
            &Command::Unknown(ref s) => s.clone()
        }
    }
}

impl Message {
    pub fn to_string(&self) -> String {
        let mut ret = String::new();
        match self.prefix {
            Some(ref pfx) => {
                ret.push(':');
                ret.push_str(pfx.trim());
                ret.push(' ');
            },
            None => ()
        };
        ret.push_str(self.command.as_string().trim());
        for ref arg in self.args.iter() {
            ret.push(' ');
            ret.push_str(arg.trim());
        }

        return ret;
    }
}

impl From<Command> for Message {
    fn from(c: Command) -> Message {
        Message {
            prefix: None,
            command: c,
            args: vec![],
            suffix: None
        }
    }
}

impl FromStr for Command {
    type Err = Command;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NICK" => Ok(Command::Nick),
            "USER" => Ok(Command::User),
            "JOIN" => Ok(Command::Join),
            "QUIT" => Ok(Command::Quit),
            "PING" => Ok(Command::Ping),
            "MODE" => Ok(Command::Mode),
            "PASS" => Ok(Command::Pass),
            _ => Ok(Command::Unknown(s.to_string()))
        }
    }
}

#[derive(Debug)]
pub struct Message {
    pub prefix: Option<String>,
    pub command: Command,
    pub args: Vec<String>,
    pub suffix: Option<String>
}
<|endoftext|>


<commit_before>//! Types and traits for working with JavaScript exceptions.

use std::error::Error;
use std::fmt::{Display, Formatter, Result as FmtResult};
use handle::Handle;
use types::Value;
use context::Context;

/// An error sentinel type used by `NeonResult` (and `JsResult`) to indicate that the JS engine has entered into a throwing state.
#[derive(Debug)]
pub struct Throw;

impl Display for Throw {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        fmt.write_str("JavaScript Error")
    }
}

impl Error for Throw {
    fn description(&self) -> &str {
        "javascript error"
    }
}

/// The result of a computation that might send the JS engine into a throwing state.
pub type NeonResult<T> = Result<T, Throw>;

/// The result of a computation that produces a JavaScript value and might send the JS engine into a throwing state.
pub type JsResult<'b, T> = NeonResult<Handle<'b, T>>;

/// An extension trait for `Result` values that can be converted into `JsResult` values by throwing a JavaScript
/// exception in the error case.
pub trait JsResultExt<'a, V: Value> {
    fn or_throw<'b, C: Context<'b>>(self, cx: &mut C) -> JsResult<'a, V>;
}
<commit_msg>`Throw` no longer implements `Error`.<commit_after>//! Types and traits for working with JavaScript exceptions.

use std::fmt::{Display, Formatter, Result as FmtResult};
use handle::Handle;
use types::Value;
use context::Context;

/// An error sentinel type used by `NeonResult` (and `JsResult`) to indicate that the JavaScript engine
/// has entered into a throwing state.
///
/// `Throw` deliberately does not implement `std::error::Error`, because it's generally not a good idea
/// to chain JavaScript exceptions with other kinds of Rust errors, since entering into the throwing
/// state means that the JavaScript engine is unavailable until the exception is handled.
#[derive(Debug)]
pub struct Throw;

impl Display for Throw {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        fmt.write_str("JavaScript Error")
    }
}

/// The result of a computation that might send the JS engine into a throwing state.
pub type NeonResult<T> = Result<T, Throw>;

/// The result of a computation that produces a JavaScript value and might send the JS engine into a throwing state.
pub type JsResult<'b, T> = NeonResult<Handle<'b, T>>;

/// An extension trait for `Result` values that can be converted into `JsResult` values by throwing a JavaScript
/// exception in the error case.
pub trait JsResultExt<'a, V: Value> {
    fn or_throw<'b, C: Context<'b>>(self, cx: &mut C) -> JsResult<'a, V>;
}
<|endoftext|>


<commit_before>//! A `ProxyStream` that bypasses or proxies data through proxy server automatically

use std::{
    io::{self, IoSlice},
    net::SocketAddr,
    pin::Pin,
    sync::Arc,
    task::{self, Poll},
};

use pin_project::pin_project;
use shadowsocks::{
    net::TcpStream,
    relay::{
        socks5::Address,
        tcprelay::proxy_stream::{ProxyClientStream, ProxyClientStreamReadHalf, ProxyClientStreamWriteHalf},
    },
};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf, ReadHalf, WriteHalf};

use crate::{
    local::{context::ServiceContext, loadbalancing::ServerIdent},
    net::MonProxyStream,
};

use super::auto_proxy_io::AutoProxyIo;

/// Unified stream for bypassed and proxied connections
#[allow(clippy::large_enum_variant)]
#[pin_project(project = AutoProxyClientStreamProj)]
pub enum AutoProxyClientStream {
    Proxied(#[pin] ProxyClientStream<MonProxyStream<TcpStream>>),
    Bypassed(#[pin] TcpStream),
}

impl AutoProxyClientStream {
    /// Connect to target `addr` via shadowsocks' server configured by `svr_cfg`
    pub async fn connect<A>(
        context: Arc<ServiceContext>,
        server: &ServerIdent,
        addr: A,
    ) -> io::Result<AutoProxyClientStream>
    where
        A: Into<Address>,
    {
        let addr = addr.into();
        if context.check_target_bypassed(&addr).await {
            AutoProxyClientStream::connect_bypassed(context, addr).await
        } else {
            AutoProxyClientStream::connect_proxied(context, server, addr).await
        }
    }

    /// Connect directly to target `addr`
    pub async fn connect_bypassed<A>(context: Arc<ServiceContext>, addr: A) -> io::Result<AutoProxyClientStream>
    where
        A: Into<Address>,
    {
        // Connect directly.
        let addr = addr.into();
        let stream =
            TcpStream::connect_remote_with_opts(context.context_ref(), &addr, context.connect_opts_ref()).await?;
        Ok(AutoProxyClientStream::Bypassed(stream))
    }

    /// Connect to target `addr` via shadowsocks' server configured by `svr_cfg`
    pub async fn connect_proxied<A>(
        context: Arc<ServiceContext>,
        server: &ServerIdent,
        addr: A,
    ) -> io::Result<AutoProxyClientStream>
    where
        A: Into<Address>,
    {
        let flow_stat = context.flow_stat();
        let stream = match ProxyClientStream::connect_with_opts_map(
            context.context(),
            server.server_config(),
            addr,
            context.connect_opts_ref(),
            |stream| MonProxyStream::from_stream(stream, flow_stat),
        )
        .await
        {
            Ok(s) => s,
            Err(err) => {
                server.tcp_score().report_failure().await;
                return Err(err);
            }
        };
        Ok(AutoProxyClientStream::Proxied(stream))
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            AutoProxyClientStream::Proxied(ref s) => s.get_ref().get_ref().local_addr(),
            AutoProxyClientStream::Bypassed(ref s) => s.local_addr(),
        }
    }

    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        match *self {
            AutoProxyClientStream::Proxied(ref s) => s.get_ref().get_ref().set_nodelay(nodelay),
            AutoProxyClientStream::Bypassed(ref s) => s.set_nodelay(nodelay),
        }
    }
}

impl AutoProxyIo for AutoProxyClientStream {
    fn is_proxied(&self) -> bool {
        matches!(*self, AutoProxyClientStream::Proxied(..))
    }
}

impl AsyncRead for AutoProxyClientStream {
    fn poll_read(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_read(cx, buf),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for AutoProxyClientStream {
    fn poll_write(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_write(cx, buf),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_flush(cx),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_shutdown(cx),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_shutdown(cx),
        }
    }

    fn poll_write_vectored(
        self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        bufs: &[IoSlice<'_>],
    ) -> Poll<io::Result<usize>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_write_vectored(cx, bufs),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_write_vectored(cx, bufs),
        }
    }
}

impl From<ProxyClientStream<MonProxyStream<TcpStream>>> for AutoProxyClientStream {
    fn from(s: ProxyClientStream<MonProxyStream<TcpStream>>) -> Self {
        AutoProxyClientStream::Proxied(s)
    }
}

impl AutoProxyClientStream {
    pub fn into_split(self) -> (AutoProxyClientStreamReadHalf, AutoProxyClientStreamWriteHalf) {
        match self {
            AutoProxyClientStream::Proxied(s) => {
                let (r, w) = s.into_split();
                (
                    AutoProxyClientStreamReadHalf::Proxied(r),
                    AutoProxyClientStreamWriteHalf::Proxied(w),
                )
            }
            AutoProxyClientStream::Bypassed(s) => {
                let (r, w) = tokio::io::split(s);
                (
                    AutoProxyClientStreamReadHalf::Bypassed(r),
                    AutoProxyClientStreamWriteHalf::Bypassed(w),
                )
            }
        }
    }
}

#[pin_project(project = AutoProxyClientStreamReadHalfProj)]
pub enum AutoProxyClientStreamReadHalf {
    Proxied(#[pin] ProxyClientStreamReadHalf<MonProxyStream<TcpStream>>),
    Bypassed(#[pin] ReadHalf<TcpStream>),
}

impl AutoProxyIo for AutoProxyClientStreamReadHalf {
    fn is_proxied(&self) -> bool {
        matches!(*self, AutoProxyClientStreamReadHalf::Proxied(..))
    }
}

impl AsyncRead for AutoProxyClientStreamReadHalf {
    fn poll_read(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamReadHalfProj::Proxied(s) => s.poll_read(cx, buf),
            AutoProxyClientStreamReadHalfProj::Bypassed(s) => s.poll_read(cx, buf),
        }
    }
}

#[pin_project(project = AutoProxyClientStreamWriteHalfProj)]
pub enum AutoProxyClientStreamWriteHalf {
    Proxied(#[pin] ProxyClientStreamWriteHalf<MonProxyStream<TcpStream>>),
    Bypassed(#[pin] WriteHalf<TcpStream>),
}

impl AutoProxyIo for AutoProxyClientStreamWriteHalf {
    fn is_proxied(&self) -> bool {
        matches!(*self, AutoProxyClientStreamWriteHalf::Proxied(..))
    }
}

impl AsyncWrite for AutoProxyClientStreamWriteHalf {
    fn poll_write(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            AutoProxyClientStreamWriteHalfProj::Proxied(s) => s.poll_write(cx, buf),
            AutoProxyClientStreamWriteHalfProj::Bypassed(s) => s.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamWriteHalfProj::Proxied(s) => s.poll_flush(cx),
            AutoProxyClientStreamWriteHalfProj::Bypassed(s) => s.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamWriteHalfProj::Proxied(s) => s.poll_shutdown(cx),
            AutoProxyClientStreamWriteHalfProj::Bypassed(s) => s.poll_shutdown(cx),
        }
    }

    fn poll_write_vectored(
        self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        bufs: &[IoSlice<'_>],
    ) -> Poll<io::Result<usize>> {
        match self.project() {
            AutoProxyClientStreamWriteHalfProj::Proxied(s) => s.poll_write_vectored(cx, bufs),
            AutoProxyClientStreamWriteHalfProj::Bypassed(s) => s.poll_write_vectored(cx, bufs),
        }
    }
}
<commit_msg>make clippy happy<commit_after>//! A `ProxyStream` that bypasses or proxies data through proxy server automatically

use std::{
    io::{self, IoSlice},
    net::SocketAddr,
    pin::Pin,
    sync::Arc,
    task::{self, Poll},
};

use pin_project::pin_project;
use shadowsocks::{
    net::TcpStream,
    relay::{
        socks5::Address,
        tcprelay::proxy_stream::{ProxyClientStream, ProxyClientStreamReadHalf, ProxyClientStreamWriteHalf},
    },
};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf, ReadHalf, WriteHalf};

use crate::{
    local::{context::ServiceContext, loadbalancing::ServerIdent},
    net::MonProxyStream,
};

use super::auto_proxy_io::AutoProxyIo;

/// Unified stream for bypassed and proxied connections
#[allow(clippy::large_enum_variant)]
#[pin_project(project = AutoProxyClientStreamProj)]
pub enum AutoProxyClientStream {
    Proxied(#[pin] ProxyClientStream<MonProxyStream<TcpStream>>),
    Bypassed(#[pin] TcpStream),
}

impl AutoProxyClientStream {
    /// Connect to target `addr` via shadowsocks' server configured by `svr_cfg`
    pub async fn connect<A>(
        context: Arc<ServiceContext>,
        server: &ServerIdent,
        addr: A,
    ) -> io::Result<AutoProxyClientStream>
    where
        A: Into<Address>,
    {
        let addr = addr.into();
        if context.check_target_bypassed(&addr).await {
            AutoProxyClientStream::connect_bypassed(context, addr).await
        } else {
            AutoProxyClientStream::connect_proxied(context, server, addr).await
        }
    }

    /// Connect directly to target `addr`
    pub async fn connect_bypassed<A>(context: Arc<ServiceContext>, addr: A) -> io::Result<AutoProxyClientStream>
    where
        A: Into<Address>,
    {
        // Connect directly.
        let addr = addr.into();
        let stream =
            TcpStream::connect_remote_with_opts(context.context_ref(), &addr, context.connect_opts_ref()).await?;
        Ok(AutoProxyClientStream::Bypassed(stream))
    }

    /// Connect to target `addr` via shadowsocks' server configured by `svr_cfg`
    pub async fn connect_proxied<A>(
        context: Arc<ServiceContext>,
        server: &ServerIdent,
        addr: A,
    ) -> io::Result<AutoProxyClientStream>
    where
        A: Into<Address>,
    {
        let flow_stat = context.flow_stat();
        let stream = match ProxyClientStream::connect_with_opts_map(
            context.context(),
            server.server_config(),
            addr,
            context.connect_opts_ref(),
            |stream| MonProxyStream::from_stream(stream, flow_stat),
        )
        .await
        {
            Ok(s) => s,
            Err(err) => {
                server.tcp_score().report_failure().await;
                return Err(err);
            }
        };
        Ok(AutoProxyClientStream::Proxied(stream))
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            AutoProxyClientStream::Proxied(ref s) => s.get_ref().get_ref().local_addr(),
            AutoProxyClientStream::Bypassed(ref s) => s.local_addr(),
        }
    }

    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        match *self {
            AutoProxyClientStream::Proxied(ref s) => s.get_ref().get_ref().set_nodelay(nodelay),
            AutoProxyClientStream::Bypassed(ref s) => s.set_nodelay(nodelay),
        }
    }
}

impl AutoProxyIo for AutoProxyClientStream {
    fn is_proxied(&self) -> bool {
        matches!(*self, AutoProxyClientStream::Proxied(..))
    }
}

impl AsyncRead for AutoProxyClientStream {
    fn poll_read(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_read(cx, buf),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_read(cx, buf),
        }
    }
}

impl AsyncWrite for AutoProxyClientStream {
    fn poll_write(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_write(cx, buf),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_flush(cx),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_shutdown(cx),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_shutdown(cx),
        }
    }

    fn poll_write_vectored(
        self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        bufs: &[IoSlice<'_>],
    ) -> Poll<io::Result<usize>> {
        match self.project() {
            AutoProxyClientStreamProj::Proxied(s) => s.poll_write_vectored(cx, bufs),
            AutoProxyClientStreamProj::Bypassed(s) => s.poll_write_vectored(cx, bufs),
        }
    }
}

impl From<ProxyClientStream<MonProxyStream<TcpStream>>> for AutoProxyClientStream {
    fn from(s: ProxyClientStream<MonProxyStream<TcpStream>>) -> Self {
        AutoProxyClientStream::Proxied(s)
    }
}

impl AutoProxyClientStream {
    pub fn into_split(self) -> (AutoProxyClientStreamReadHalf, AutoProxyClientStreamWriteHalf) {
        match self {
            AutoProxyClientStream::Proxied(s) => {
                let (r, w) = s.into_split();
                (
                    AutoProxyClientStreamReadHalf::Proxied(r),
                    AutoProxyClientStreamWriteHalf::Proxied(w),
                )
            }
            AutoProxyClientStream::Bypassed(s) => {
                let (r, w) = tokio::io::split(s);
                (
                    AutoProxyClientStreamReadHalf::Bypassed(r),
                    AutoProxyClientStreamWriteHalf::Bypassed(w),
                )
            }
        }
    }
}

#[allow(clippy::large_enum_variant)]
#[pin_project(project = AutoProxyClientStreamReadHalfProj)]
pub enum AutoProxyClientStreamReadHalf {
    Proxied(#[pin] ProxyClientStreamReadHalf<MonProxyStream<TcpStream>>),
    Bypassed(#[pin] ReadHalf<TcpStream>),
}

impl AutoProxyIo for AutoProxyClientStreamReadHalf {
    fn is_proxied(&self) -> bool {
        matches!(*self, AutoProxyClientStreamReadHalf::Proxied(..))
    }
}

impl AsyncRead for AutoProxyClientStreamReadHalf {
    fn poll_read(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamReadHalfProj::Proxied(s) => s.poll_read(cx, buf),
            AutoProxyClientStreamReadHalfProj::Bypassed(s) => s.poll_read(cx, buf),
        }
    }
}

#[allow(clippy::large_enum_variant)]
#[pin_project(project = AutoProxyClientStreamWriteHalfProj)]
pub enum AutoProxyClientStreamWriteHalf {
    Proxied(#[pin] ProxyClientStreamWriteHalf<MonProxyStream<TcpStream>>),
    Bypassed(#[pin] WriteHalf<TcpStream>),
}

impl AutoProxyIo for AutoProxyClientStreamWriteHalf {
    fn is_proxied(&self) -> bool {
        matches!(*self, AutoProxyClientStreamWriteHalf::Proxied(..))
    }
}

impl AsyncWrite for AutoProxyClientStreamWriteHalf {
    fn poll_write(self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        match self.project() {
            AutoProxyClientStreamWriteHalfProj::Proxied(s) => s.poll_write(cx, buf),
            AutoProxyClientStreamWriteHalfProj::Bypassed(s) => s.poll_write(cx, buf),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamWriteHalfProj::Proxied(s) => s.poll_flush(cx),
            AutoProxyClientStreamWriteHalfProj::Bypassed(s) => s.poll_flush(cx),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> {
        match self.project() {
            AutoProxyClientStreamWriteHalfProj::Proxied(s) => s.poll_shutdown(cx),
            AutoProxyClientStreamWriteHalfProj::Bypassed(s) => s.poll_shutdown(cx),
        }
    }

    fn poll_write_vectored(
        self: Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        bufs: &[IoSlice<'_>],
    ) -> Poll<io::Result<usize>> {
        match self.project() {
            AutoProxyClientStreamWriteHalfProj::Proxied(s) => s.poll_write_vectored(cx, bufs),
            AutoProxyClientStreamWriteHalfProj::Bypassed(s) => s.poll_write_vectored(cx, bufs),
        }
    }
}
<|endoftext|>