<commit_before>// See LICENSE file for copyright and license details.

use std::io::{
  BufferedReader,
  File
};
use std::str::Words;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use glfw_events::EventHandlers;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 mvp_mat;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = mvp_mat * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

struct ObjFace {
  vertex: [int, ..3],
  texture: [int, ..3],
  normal: [int, ..3],
}

struct ObjModel {
  coords: ~[Vec3<GLfloat>],
  normals: ~[Vec3<GLfloat>],
  texture_coords: ~[Vec2<GLfloat>],
  faces: ~[ObjFace],
}

// TODO: unwrap() -> ...
impl ObjModel {
  fn new(filename: &str) -> ObjModel {
    let mut obj = ObjModel {
      coords: ~[],
      normals: ~[],
      texture_coords: ~[],
      faces: ~[],
    };
    obj.read(filename);
    obj
  }

  fn read_v_or_vn(words: &mut Words) -> Vec3<GLfloat> {
    Vec3 {
      x: from_str(words.next().unwrap()).unwrap(),
      y: from_str(words.next().unwrap()).unwrap(),
      z: from_str(words.next().unwrap()).unwrap(),
    }
  }

  fn read_vt(words: &mut Words) -> Vec2<GLfloat> {
    // TODO: y = 1.0 - y; // flip vertically
    Vec2 {
      x: from_str(words.next().unwrap()).unwrap(),
      y: from_str(words.next().unwrap()).unwrap(),
    }
  }

  fn read_f(words: &mut Words) -> ObjFace {
    let mut face = ObjFace {
      vertex: [0, 0, 0],
      texture: [0, 0, 0],
      normal: [0, 0, 0],
    };
    let mut i = 0;
    for group in *words {
      let mut w = group.split('/');
      face.vertex[i] = from_str(w.next().unwrap()).unwrap();
      face.texture[i] = from_str(w.next().unwrap()).unwrap();
      face.normal[i] = from_str(w.next().unwrap()).unwrap();
      i += 1;
    }
    face
  }

  fn read(&mut self, filename: &str) {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));
    for line in file.lines() {
      let mut words = line.words(); // TODO: Remove mut
      fn is_correct_tag(tag: &str) -> bool {
        tag.len() != 0 && tag[0] != ('#' as u8)
      }
      let tag = match words.next() {
        Some(w) if is_correct_tag(w) => w,
        _ => "", // TODO: ???
      };
      match tag {
        &"v" => self.coords.push(ObjModel::read_v_or_vn(&mut words)),
        &"vn" => self.normals.push(ObjModel::read_v_or_vn(&mut words)),
        &"vt" => self.texture_coords.push(ObjModel::read_vt(&mut words)),
        &"f" => self.faces.push(ObjModel::read_f(&mut words)),
        _ => print!("."),
      }
    }
  }

  fn build(&self) -> ~[Vec3<GLfloat>]{
    let mut mesh = ~[];
    for face in self.faces.iter() {
      for i in range(0, 3) {
        let vertex_id = face.vertex[i] - 1;
        // let texture_coord_id = face.texture[i] - 1; // TODO
        mesh.push(self.coords[vertex_id]);
      }
    }
    mesh
  }
}

pub struct Visualizer {
  glfw_event_handlers: EventHandlers,
  program: GLuint,
  vertex_buffer_obj: GLuint,
  unit_buffer_obj: GLuint,
  unit_mesh: ~[Vec3<GLfloat>],
  mat_id: GLint,
  win: Option<glfw::Window>,
  vertex_data: ~[Vec3<GLfloat>],
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
  obj: ObjModel,
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "OpenGL",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = Vec2::<int>{x: 640, y: 480};
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      glfw_event_handlers: EventHandlers::new(&win),
      program: 0,
      vertex_buffer_obj: 0,
      unit_buffer_obj: 0,
      unit_mesh: ~[],
      mat_id: 0,
      win: Some(win),
      vertex_data: ~[],
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
      obj: ObjModel::new("tank.obj"),
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_model();
    vis
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn build_hex_mesh(&mut self) {
    for tile_pos in TileIterator::new() {
      let pos3d = self.geom.v2i_to_v2f(tile_pos).extend(0.0);
      for num in range(0, 6) {
        let vertex = self.geom.index_to_hex_vertex(num);
        let next_vertex = self.geom.index_to_hex_vertex(num + 1);
        let data = &mut self.vertex_data;
        data.push(pos3d + vertex.extend(0.0));
        data.push(pos3d + next_vertex.extend(0.0));
        data.push(pos3d + Vec3::zero());
      }
    }
  }

  fn init_model(&mut self) {
    self.build_hex_mesh();
    self.program = glh::compile_program(
      VERTEX_SHADER_SRC,
      FRAGMENT_SHADER_SRC,
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    {
      unsafe {
        gl::GenBuffers(1, &mut self.vertex_buffer_obj);
      }
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
      glh::fill_current_coord_vbo(self.vertex_data);
      let pos_attr = glh::get_attr(self.program, "position");
      glh::vertex_attrib_pointer(pos_attr);
    }

    // prepare model
    {
      self.unit_mesh = self.obj.build();
      unsafe {
        gl::GenBuffers(1, &mut self.unit_buffer_obj);
      }
      gl::BindBuffer(gl::ARRAY_BUFFER, self.unit_buffer_obj);
      glh::fill_current_coord_vbo(self.unit_mesh);
    }
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
      gl::DeleteBuffers(1, &self.unit_buffer_obj);
    }
  }

  fn draw_map(&self) {
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
    glh::vertex_attrib_pointer(glh::get_attr(self.program, "position"));
    glh::draw_mesh(self.vertex_data);
  }

  fn draw_model(&self) {
    gl::BindBuffer(gl::ARRAY_BUFFER, self.unit_buffer_obj);
    glh::vertex_attrib_pointer(glh::get_attr(self.program, "position"));
    glh::draw_mesh(self.unit_mesh);
  }

  pub fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    gl::UseProgram(self.program);
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.draw_map();
    self.draw_model();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  pub fn handle_key_events(&mut self) {
    self.glfw_event_handlers.key_handler.handle(|event| {
      if event.action != glfw::Press {
        return;
      }
      match event.key {
        glfw::KeyEscape | glfw::KeyQ
                       => self.win().set_should_close(true),
        glfw::KeySpace => println!("space"),
        glfw::KeyUp    => self.camera.move(270.0),
        glfw::KeyDown  => self.camera.move(90.0),
        glfw::KeyRight => self.camera.move(0.0),
        glfw::KeyLeft  => self.camera.move(180.0),
        _ => {},
      }
    });
  }

  pub fn handle_cursor_pos_events(&mut self) {
    self.glfw_event_handlers.cursor_pos_handler.handle(|event| {
      let button = self.win().get_mouse_button(glfw::MouseButtonRight);
      if button == glfw::Press {
        self.camera.z_angle += self.mouse_pos.x - event.x;
        self.camera.x_angle += self.mouse_pos.y - event.y;
      }
      self.mouse_pos = Vec2{x: event.x, y: event.y};
    });
  }

  pub fn handle_events(&mut self) {
    glfw::poll_events();
    self.handle_key_events();
    self.handle_cursor_pos_events();
  }

  fn close_window(&mut self) {
    // destroy glfw::Window before terminating glfw
    self.win = None;
  }

  pub fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
    println!("selected: {:?}", self.selected_tile_pos);
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
    self.close_window();
    glfw::terminate();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Removed useless empty line<commit_after>// See LICENSE file for copyright and license details.

use std::io::{
  BufferedReader,
  File
};
use std::str::Words;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use glfw_events::EventHandlers;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 mvp_mat;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = mvp_mat * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

struct ObjFace {
  vertex: [int, ..3],
  texture: [int, ..3],
  normal: [int, ..3],
}

struct ObjModel {
  coords: ~[Vec3<GLfloat>],
  normals: ~[Vec3<GLfloat>],
  texture_coords: ~[Vec2<GLfloat>],
  faces: ~[ObjFace],
}

// TODO: unwrap() -> ...
impl ObjModel {
  fn new(filename: &str) -> ObjModel {
    let mut obj = ObjModel {
      coords: ~[],
      normals: ~[],
      texture_coords: ~[],
      faces: ~[],
    };
    obj.read(filename);
    obj
  }

  fn read_v_or_vn(words: &mut Words) -> Vec3<GLfloat> {
    Vec3 {
      x: from_str(words.next().unwrap()).unwrap(),
      y: from_str(words.next().unwrap()).unwrap(),
      z: from_str(words.next().unwrap()).unwrap(),
    }
  }

  fn read_vt(words: &mut Words) -> Vec2<GLfloat> {
    // TODO: y = 1.0 - y; // flip vertically
    Vec2 {
      x: from_str(words.next().unwrap()).unwrap(),
      y: from_str(words.next().unwrap()).unwrap(),
    }
  }

  fn read_f(words: &mut Words) -> ObjFace {
    let mut face = ObjFace {
      vertex: [0, 0, 0],
      texture: [0, 0, 0],
      normal: [0, 0, 0],
    };
    let mut i = 0;
    for group in *words {
      let mut w = group.split('/');
      face.vertex[i] = from_str(w.next().unwrap()).unwrap();
      face.texture[i] = from_str(w.next().unwrap()).unwrap();
      face.normal[i] = from_str(w.next().unwrap()).unwrap();
      i += 1;
    }
    face
  }

  fn read(&mut self, filename: &str) {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));
    for line in file.lines() {
      let mut words = line.words(); // TODO: Remove mut
      fn is_correct_tag(tag: &str) -> bool {
        tag.len() != 0 && tag[0] != ('#' as u8)
      }
      let tag = match words.next() {
        Some(w) if is_correct_tag(w) => w,
        _ => "", // TODO: ???
      };
      match tag {
        &"v" => self.coords.push(ObjModel::read_v_or_vn(&mut words)),
        &"vn" => self.normals.push(ObjModel::read_v_or_vn(&mut words)),
        &"vt" => self.texture_coords.push(ObjModel::read_vt(&mut words)),
        &"f" => self.faces.push(ObjModel::read_f(&mut words)),
        _ => print!("."),
      }
    }
  }

  fn build(&self) -> ~[Vec3<GLfloat>]{
    let mut mesh = ~[];
    for face in self.faces.iter() {
      for i in range(0, 3) {
        let vertex_id = face.vertex[i] - 1;
        // let texture_coord_id = face.texture[i] - 1; // TODO
        mesh.push(self.coords[vertex_id]);
      }
    }
    mesh
  }
}

pub struct Visualizer {
  glfw_event_handlers: EventHandlers,
  program: GLuint,
  vertex_buffer_obj: GLuint,
  unit_buffer_obj: GLuint,
  unit_mesh: ~[Vec3<GLfloat>],
  mat_id: GLint,
  win: Option<glfw::Window>,
  vertex_data: ~[Vec3<GLfloat>],
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
  obj: ObjModel,
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "OpenGL",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = Vec2::<int>{x: 640, y: 480};
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      glfw_event_handlers: EventHandlers::new(&win),
      program: 0,
      vertex_buffer_obj: 0,
      unit_buffer_obj: 0,
      unit_mesh: ~[],
      mat_id: 0,
      win: Some(win),
      vertex_data: ~[],
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
      obj: ObjModel::new("tank.obj"),
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_model();
    vis
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn build_hex_mesh(&mut self) {
    for tile_pos in TileIterator::new() {
      let pos3d = self.geom.v2i_to_v2f(tile_pos).extend(0.0);
      for num in range(0, 6) {
        let vertex = self.geom.index_to_hex_vertex(num);
        let next_vertex = self.geom.index_to_hex_vertex(num + 1);
        let data = &mut self.vertex_data;
        data.push(pos3d + vertex.extend(0.0));
        data.push(pos3d + next_vertex.extend(0.0));
        data.push(pos3d + Vec3::zero());
      }
    }
  }

  fn init_model(&mut self) {
    self.build_hex_mesh();
    self.program = glh::compile_program(
      VERTEX_SHADER_SRC,
      FRAGMENT_SHADER_SRC,
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    {
      unsafe {
        gl::GenBuffers(1, &mut self.vertex_buffer_obj);
      }
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
      glh::fill_current_coord_vbo(self.vertex_data);
      let pos_attr = glh::get_attr(self.program, "position");
      glh::vertex_attrib_pointer(pos_attr);
    }

    // prepare model
    {
      self.unit_mesh = self.obj.build();
      unsafe {
        gl::GenBuffers(1, &mut self.unit_buffer_obj);
      }
      gl::BindBuffer(gl::ARRAY_BUFFER, self.unit_buffer_obj);
      glh::fill_current_coord_vbo(self.unit_mesh);
    }
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
      gl::DeleteBuffers(1, &self.unit_buffer_obj);
    }
  }

  fn draw_map(&self) {
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
    glh::vertex_attrib_pointer(glh::get_attr(self.program, "position"));
    glh::draw_mesh(self.vertex_data);
  }

  fn draw_model(&self) {
    gl::BindBuffer(gl::ARRAY_BUFFER, self.unit_buffer_obj);
    glh::vertex_attrib_pointer(glh::get_attr(self.program, "position"));
    glh::draw_mesh(self.unit_mesh);
  }

  pub fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    gl::UseProgram(self.program);
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.draw_map();
    self.draw_model();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  pub fn handle_key_events(&mut self) {
    self.glfw_event_handlers.key_handler.handle(|event| {
      if event.action != glfw::Press {
        return;
      }
      match event.key {
        glfw::KeyEscape | glfw::KeyQ
                       => self.win().set_should_close(true),
        glfw::KeySpace => println!("space"),
        glfw::KeyUp    => self.camera.move(270.0),
        glfw::KeyDown  => self.camera.move(90.0),
        glfw::KeyRight => self.camera.move(0.0),
        glfw::KeyLeft  => self.camera.move(180.0),
        _ => {},
      }
    });
  }

  pub fn handle_cursor_pos_events(&mut self) {
    self.glfw_event_handlers.cursor_pos_handler.handle(|event| {
      let button = self.win().get_mouse_button(glfw::MouseButtonRight);
      if button == glfw::Press {
        self.camera.z_angle += self.mouse_pos.x - event.x;
        self.camera.x_angle += self.mouse_pos.y - event.y;
      }
      self.mouse_pos = Vec2{x: event.x, y: event.y};
    });
  }

  pub fn handle_events(&mut self) {
    glfw::poll_events();
    self.handle_key_events();
    self.handle_cursor_pos_events();
  }

  fn close_window(&mut self) {
    // destroy glfw::Window before terminating glfw
    self.win = None;
  }

  pub fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
    println!("selected: {:?}", self.selected_tile_pos);
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
    self.close_window();
    glfw::terminate();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>extern crate find_folder;
extern crate rs6502;
extern crate sdl2;

mod console;
mod position;
mod text;

use rs6502::{CodeSegment, Cpu, Disassembler};
use sdl2::render::Renderer;

pub use self::console::Console;
pub use self::position::Position;
pub use self::text::Text;

const HELPTEXT: &'static str = "

HAKKA
-----

Commands:

break | b: addr
       - Toggles a breakpoint at a specific address. If the
         program counter hits this address, execution
         stops.

step | s
       - Executes the current instruction before breaking
         execution again.

continue | c
       - Resumes execution of code within the virtual machine.

list
       - Lists the code surrounding the current program
         counter.

memset | set: addr args [args, ...]
       - memset sets the value of memory directly.

memdmp | dmp: page || start end
       - memdmp dumps a single memory page, or a specified
         memory range from <start> to <end> (inclusive).

monitor | mon: start end
       - monitor dumps the memory between start and end (inclusive)
         every second. Press ENTER to stop the monitor.

source
       - Lists the code currently running in the virtual
         machine. A '>' symbol indicates the current
         program counter.

registers | reg
       - Lists the CPU registers and their current values.

help
       - Lists this help text.
";

#[derive(Debug)]
pub struct MemoryMonitor {
    pub enabled: bool,
    start_addr: usize,
    end_addr: usize,
}

pub struct VirtualMachine<'a> {
    pub cpu: Cpu,
    pub monitor: MemoryMonitor,
    pub console: Console<'a>,
    segments: Vec<CodeSegment>,
    clock_rate: Option<u32>,
    last_command: String,
    breakpoints: [u8; 64 * 1024],
    broken: bool,
    step: bool,
}

impl<'a> VirtualMachine<'a> {
    pub fn new<CR>(cpu: Cpu, clock_rate: CR, mut console: Console<'a>) -> VirtualMachine<'a>
        where CR: Into<Option<u32>>
    {
        console.println("Welcome to hakka. Type 'help' for instructions.");
        console.println("");

        VirtualMachine {
            cpu: cpu,
            console: console,
            segments: Vec::new(),
            clock_rate: clock_rate.into(),
            monitor: MemoryMonitor {
                enabled: false,
                start_addr: 0,
                end_addr: 0,
            },
            last_command: "".into(),
            breakpoints: [0; 64 * 1024],
            broken: false,
            step: false,
        }
    }

    pub fn render(&mut self, mut renderer: &mut Renderer) {
        self.console.render(renderer);
    }

    pub fn load_code_segments(&mut self, segments: Vec<CodeSegment>) {
        if segments.is_empty() {
            return;
        }
        self.segments = segments;
        for segment in &self.segments {
            self.cpu.load(&segment.code, segment.address).unwrap();
        }

        self.cpu.registers.PC = self.segments[0].address;
    }

    /// Cycles the Virtual Machine CPU according to the clock rate
    pub fn cycle(&mut self) {
        if let Some(clock_rate) = self.clock_rate {
            let mut n = 0;
            while (n < clock_rate && !self.broken) || self.step {
                n += self.cpu.step().expect("SEGFAULT") as u32;
                if self.breakpoints[self.cpu.registers.PC as usize] > 0 {
                    self.broken = true;
                    self.console.println("");
                    self.console
                        .println(format!("BREAKPOINT hit at {:04X}", self.cpu.registers.PC));
                    self.console.toggle();
                }
                // If we stepped, dump the local disassembly
                if self.step {
                    self.dump_local_disassembly();
                }
                self.step = false;
            }
        } else {
            self.cpu.step().expect("SEGFAULT");
            if self.step {
                self.dump_local_disassembly();
            }
            self.step = false;
            if self.breakpoints[self.cpu.registers.PC as usize] > 0 {
                self.broken = true;
                self.console.println("");
                self.console.println(format!("BREAKPOINT hit at {:04X}", self.cpu.registers.PC));
                self.console.toggle();
            }
        }
    }

    pub fn execute_command<S>(&mut self, cmd: S)
        where S: Into<String>
    {
        let mut input: String = cmd.into().trim().into();

        if input == "r" || input == "repeat" {
            input = self.last_command.clone();
        }

        let parts = input.split(' ').collect::<Vec<_>>();

        if input.is_empty() {
            if self.monitor.enabled {
                self.monitor.enabled = false;
            }
        } else if parts[0] == "clear" || parts[0] == "cls" {
            self.console.clear();
        } else if parts[0] == "help" {
            self.console.print_lines(HELPTEXT);
        } else if parts[0] == "source" {
            self.dump_disassembly();
        } else if parts[0] == "list" {
            self.dump_local_disassembly();
        } else if parts[0] == "monitor" || parts[0] == "mon" {
            if self.monitor.enabled {
                self.monitor.enabled = false;
            } else {
                self.enable_memory_monitor(&input);
            }
        } else if parts[0] == "memset" || parts[0] == "set" {
            if parts.len() < 3 {
                self.console
                    .println("ERR: Requires 2 arguments. Example: memset 0x00 0x01 to store 0x01 \
                              in 0x00.");
            } else if parts.len() == 3 {
                if let Ok(dst) = u16::from_str_radix(&parts[1].replace("0x", "")[..], 16) {
                    if let Ok(src) = u8::from_str_radix(&parts[2].replace("0x", "")[..], 16) {
                        self.cpu.memory[dst as usize] = src;
                    } else {
                        self.console.println("ERR: Unable to parse source byte value");
                    }
                } else {
                    self.console.println("ERR: Unable to parse destination byte value");
                }
            } else if let Ok(mut dst) = usize::from_str_radix(&parts[1].replace("0x", "")[..], 16) {
                for p in &parts[2..] {
                    if let Ok(byte) = u8::from_str_radix(&p.replace("0x", "")[..], 16) {
                        self.cpu.memory[dst] = byte;
                        dst += 0x01;
                    } else {
                        self.console.println("ERR: Unable to parse source byte value");
                    }
                }
            } else {
                self.console.println("ERR: Unable to parse destination byte value");
            }
        } else if parts[0] == "memdmp" || parts[0] == "dmp" {
            // 1 argument assumes 1 memory "page"
            if parts.len() == 2 {
                if let Ok(page_number) = parts[1].parse() {

                    self.dump_memory_page(page_number);
                } else {
                    self.console.println("ERR: Unable to parse memory page");
                }
            } else if parts.len() == 3 {
                // A memory range instead
                if let Ok(start) = u16::from_str_radix(&parts[1].replace("0x", "")[..], 16) {
                    if let Ok(end) = u16::from_str_radix(&parts[2].replace("0x", "")[..], 16) {
                        self.dump_memory_range(start, end);
                    } else {
                        self.console.println("ERR: Unable to parse end address value");
                    }
                } else {
                    self.console.println("ERR: Unable to parse start address value");
                }
            }
        } else if parts[0] == "registers" || parts[0] == "reg" {
            self.dump_registers();
        } else if parts[0] == "break" || parts[0] == "b" {
            // 1 argument assumes 1 memory "page"
            if parts.len() == 2 {
                if let Ok(addr) = usize::from_str_radix(&parts[1][..], 16) {
                    if addr <= u16::max_value() as usize {
                        if self.breakpoints[addr] > 0 {
                            self.console.println(format!("Removed breakpoint at {:04X}", addr));
                            self.breakpoints[addr] = 0;
                        } else {
                            self.console.println(format!("Added breakpoint at {:04X}", addr));
                            self.breakpoints[addr] = 1;
                        }
                    } else {
                        self.console.println("ERR: Value outside addressable range.");
                    }
                } else {
                    self.console.println("ERR: Unable to parse breakpoint address");
                }
            } else {
                self.broken = true;
                self.console.println("Execution stopped");
            }
        } else if parts[0] == "continue" || parts[0] == "c" {
            self.broken = false;
            self.console.println("Execution resumed");
        } else if parts[0] == "step" || parts[0] == "s" {
            self.broken = true;
            self.step = true;
        } else {
            self.console.println("Unknown command");
        }

        // Don't assign a blank command as a last command
        if !input.is_empty() {
            self.last_command = input.clone();
        }
    }

    fn enable_memory_monitor(&mut self, input: &str) {
        let parts: Vec<&str> = input.split(' ').collect();
        if parts.len() < 3 {
            self.console.println("ERR: Requires 2 arguments. Example: monitor 0x00 0xFF");
        } else {
            let start = usize::from_str_radix(&parts[1].replace("0x", "")[..], 16).unwrap();
            let end = usize::from_str_radix(&parts[2].replace("0x", "")[..], 16).unwrap();

            self.monitor.start_addr = start;
            self.monitor.end_addr = end;
            self.monitor.enabled = true;
        }
    }

    fn dump_disassembly(&mut self) {
        self.console.println("");

        for segment in &self.segments {
            self.console.println(format!(".ORG ${:04X}", segment.address));
            let disassembler = Disassembler::with_offset(segment.address);
            let pairs = disassembler.disassemble_with_addresses(&segment.code);
            let lines = self.highlight_lines(self.cpu.registers.PC as usize,
                                             pairs,
                                             segment.address,
                                             false);
            self.console.print_lines(lines.join(""));
        }
        self.console.println("");
    }

    fn dump_local_disassembly(&mut self) {
        self.console.println("");

        let result = {
            let pc = self.cpu.registers.PC as usize;
            let local_segment = self.get_local_segment(pc);
            let disassembler = Disassembler::with_offset(local_segment.address);
            let pairs = disassembler.disassemble_with_addresses(&local_segment.code);
            self.highlight_lines(pc, pairs, local_segment.address, true)
        };
        self.console.print_lines(result.join(""));
        self.console.println("");
    }

    pub fn dump_memory_page(&mut self, page: usize) {
        let mut addr = page * 0x100;
        for chunk in self.cpu.memory[page * 0x100..(page * 0x100) + 0x100].chunks(8) {
            self.console.print(format!("{:04X}: ", addr));
            for b in chunk {
                self.console.print(format!("{:02X} ", *b));
            }
            self.console.wrap_line();
            addr += 0x08;
        }
    }

    pub fn dump_memory(&mut self) {
        for chunk in self.cpu.memory[self.monitor.start_addr..self.monitor.end_addr + 0x01]
            .chunks(8) {
            for b in chunk {
                self.console.print(format!("{:02X} ", *b));
            }
            self.console.wrap_line();
        }
    }

    fn dump_memory_range(&mut self, start: u16, end: u16) {
        self.console.println("");
        let start = start as usize;
        let end = end as usize;
        for chunk in self.cpu.memory[start..end + 0x01].chunks(8) {
            for b in chunk {
                self.console.print(format!("{:02X} ", *b));
            }
            self.console.println("");
        }
    }

    fn dump_registers(&mut self) {
        self.console.println("");
        self.console.println(format!("A: {} ({:04X})", self.cpu.registers.A, self.cpu.registers.A));
        self.console.println(format!("X: {} ({:04X})", self.cpu.registers.X, self.cpu.registers.X));
        self.console.println(format!("Y: {} ({:04X})", self.cpu.registers.Y, self.cpu.registers.Y));
        self.console.println(format!("PC: {} ({:04X})",
                                     self.cpu.registers.PC,
                                     self.cpu.registers.PC));
        self.console.println(format!("S: {} ({:04X})",
                                     self.cpu.stack.pointer,
                                     self.cpu.stack.pointer));
    }

    fn get_local_segment(&self, pc: usize) -> &CodeSegment {
        for segment in &self.segments {
            let addr = segment.address as usize;
            if pc >= addr && pc <= addr + segment.code.len() {
                return segment;
            }
        }

        &self.segments[0]
    }

    fn highlight_lines(&self,
                       pc: usize,
                       pairs: Vec<(String, u16)>,
                       segment_start: u16,
                       limit_results: bool)
                       -> Vec<String> {
        let mut result = Vec::new();

        let base = pc as isize - segment_start as isize;

        for pair in pairs {
            if limit_results {
                let start = if base > 0x0A { base - 0x0A } else { 0 };
                if (pair.1 as isize) < start || (pair.1 as isize) > base + 0x0A {
                    continue;
                }
            }
            let current_line = pc as u16 == segment_start + pair.1;
            let breakpoint = self.breakpoints[segment_start as usize + pair.1 as usize] > 0x00;

            if breakpoint && current_line {
                result.push(format!("> * {}", pair.0));
            } else if breakpoint && !current_line {
                result.push(format!("  * {}", pair.0));
            } else if !breakpoint && current_line {
                result.push(format!(">   {}", pair.0));
            } else {
                result.push(format!("    {}", pair.0));
            }
        }

        result
    }
}
<commit_msg>Improve memory output formatting<commit_after>extern crate find_folder;
extern crate rs6502;
extern crate sdl2;

mod console;
mod position;
mod text;

use rs6502::{CodeSegment, Cpu, Disassembler};
use sdl2::render::Renderer;

pub use self::console::Console;
pub use self::position::Position;
pub use self::text::Text;

const HELPTEXT: &'static str = "

HAKKA
-----

Commands:

break | b: addr
       - Toggles a breakpoint at a specific address. If the
         program counter hits this address, execution
         stops.

step | s
       - Executes the current instruction before breaking
         execution again.

continue | c
       - Resumes execution of code within the virtual machine.

list
       - Lists the code surrounding the current program
         counter.

memset | set: addr args [args, ...]
       - memset sets the value of memory directly.

memdmp | dmp: page || start end
       - memdmp dumps a single memory page, or a specified
         memory range from <start> to <end> (inclusive).

monitor | mon: start end
       - monitor dumps the memory between start and end (inclusive)
         every second. Press ENTER to stop the monitor.

source
       - Lists the code currently running in the virtual
         machine. A '>' symbol indicates the current
         program counter.

registers | reg
       - Lists the CPU registers and their current values.

help
       - Lists this help text.
";

#[derive(Debug)]
pub struct MemoryMonitor {
    pub enabled: bool,
    start_addr: usize,
    end_addr: usize,
}

pub struct VirtualMachine<'a> {
    pub cpu: Cpu,
    pub monitor: MemoryMonitor,
    pub console: Console<'a>,
    segments: Vec<CodeSegment>,
    clock_rate: Option<u32>,
    last_command: String,
    breakpoints: [u8; 64 * 1024],
    broken: bool,
    step: bool,
}

impl<'a> VirtualMachine<'a> {
    pub fn new<CR>(cpu: Cpu, clock_rate: CR, mut console: Console<'a>) -> VirtualMachine<'a>
        where CR: Into<Option<u32>>
    {
        console.println("Welcome to hakka. Type 'help' for instructions.");
        console.println("");

        VirtualMachine {
            cpu: cpu,
            console: console,
            segments: Vec::new(),
            clock_rate: clock_rate.into(),
            monitor: MemoryMonitor {
                enabled: false,
                start_addr: 0,
                end_addr: 0,
            },
            last_command: "".into(),
            breakpoints: [0; 64 * 1024],
            broken: false,
            step: false,
        }
    }

    pub fn render(&mut self, mut renderer: &mut Renderer) {
        self.console.render(renderer);
    }

    pub fn load_code_segments(&mut self, segments: Vec<CodeSegment>) {
        if segments.is_empty() {
            return;
        }
        self.segments = segments;
        for segment in &self.segments {
            self.cpu.load(&segment.code, segment.address).unwrap();
        }

        self.cpu.registers.PC = self.segments[0].address;
    }

    /// Cycles the Virtual Machine CPU according to the clock rate
    pub fn cycle(&mut self) {
        if let Some(clock_rate) = self.clock_rate {
            let mut n = 0;
            while (n < clock_rate && !self.broken) || self.step {
                n += self.cpu.step().expect("SEGFAULT") as u32;
                if self.breakpoints[self.cpu.registers.PC as usize] > 0 {
                    self.broken = true;
                    self.console.println("");
                    self.console
                        .println(format!("BREAKPOINT hit at {:04X}", self.cpu.registers.PC));
                    self.console.toggle();
                }
                // If we stepped, dump the local disassembly
                if self.step {
                    self.dump_local_disassembly();
                }
                self.step = false;
            }
        } else {
            self.cpu.step().expect("SEGFAULT");
            if self.step {
                self.dump_local_disassembly();
            }
            self.step = false;
            if self.breakpoints[self.cpu.registers.PC as usize] > 0 {
                self.broken = true;
                self.console.println("");
                self.console.println(format!("BREAKPOINT hit at {:04X}", self.cpu.registers.PC));
                self.console.toggle();
            }
        }
    }

    pub fn execute_command<S>(&mut self, cmd: S)
        where S: Into<String>
    {
        let mut input: String = cmd.into().trim().into();

        if input == "r" || input == "repeat" {
            input = self.last_command.clone();
        }

        let parts = input.split(' ').collect::<Vec<_>>();

        if input.is_empty() {
            if self.monitor.enabled {
                self.monitor.enabled = false;
            }
        } else if parts[0] == "clear" || parts[0] == "cls" {
            self.console.clear();
        } else if parts[0] == "help" {
            self.console.print_lines(HELPTEXT);
        } else if parts[0] == "source" {
            self.dump_disassembly();
        } else if parts[0] == "list" {
            self.dump_local_disassembly();
        } else if parts[0] == "monitor" || parts[0] == "mon" {
            if self.monitor.enabled {
                self.monitor.enabled = false;
            } else {
                self.enable_memory_monitor(&input);
            }
        } else if parts[0] == "memset" || parts[0] == "set" {
            if parts.len() < 3 {
                self.console
                    .println("ERR: Requires 2 arguments. Example: memset 0x00 0x01 to store 0x01 \
                              in 0x00.");
            } else if parts.len() == 3 {
                if let Ok(dst) = u16::from_str_radix(&parts[1].replace("0x", "")[..], 16) {
                    if let Ok(src) = u8::from_str_radix(&parts[2].replace("0x", "")[..], 16) {
                        self.cpu.memory[dst as usize] = src;
                    } else {
                        self.console.println("ERR: Unable to parse source byte value");
                    }
                } else {
                    self.console.println("ERR: Unable to parse destination byte value");
                }
            } else if let Ok(mut dst) = usize::from_str_radix(&parts[1].replace("0x", "")[..], 16) {
                for p in &parts[2..] {
                    if let Ok(byte) = u8::from_str_radix(&p.replace("0x", "")[..], 16) {
                        self.cpu.memory[dst] = byte;
                        dst += 0x01;
                    } else {
                        self.console.println("ERR: Unable to parse source byte value");
                    }
                }
            } else {
                self.console.println("ERR: Unable to parse destination byte value");
            }
        } else if parts[0] == "memdmp" || parts[0] == "dmp" {
            // 1 argument assumes 1 memory "page"
            if parts.len() == 2 {
                if let Ok(page_number) = parts[1].parse() {

                    self.dump_memory_page(page_number);
                } else {
                    self.console.println("ERR: Unable to parse memory page");
                }
            } else if parts.len() == 3 {
                // A memory range instead
                if let Ok(start) = u16::from_str_radix(&parts[1].replace("0x", "")[..], 16) {
                    if let Ok(end) = u16::from_str_radix(&parts[2].replace("0x", "")[..], 16) {
                        self.dump_memory_range(start, end);
                    } else {
                        self.console.println("ERR: Unable to parse end address value");
                    }
                } else {
                    self.console.println("ERR: Unable to parse start address value");
                }
            }
        } else if parts[0] == "registers" || parts[0] == "reg" {
            self.dump_registers();
        } else if parts[0] == "break" || parts[0] == "b" {
            // 1 argument assumes 1 memory "page"
            if parts.len() == 2 {
                if let Ok(addr) = usize::from_str_radix(&parts[1][..], 16) {
                    if addr <= u16::max_value() as usize {
                        if self.breakpoints[addr] > 0 {
                            self.console.println(format!("Removed breakpoint at {:04X}", addr));
                            self.breakpoints[addr] = 0;
                        } else {
                            self.console.println(format!("Added breakpoint at {:04X}", addr));
                            self.breakpoints[addr] = 1;
                        }
                    } else {
                        self.console.println("ERR: Value outside addressable range.");
                    }
                } else {
                    self.console.println("ERR: Unable to parse breakpoint address");
                }
            } else {
                self.broken = true;
                self.console.println("Execution stopped");
            }
        } else if parts[0] == "continue" || parts[0] == "c" {
            self.broken = false;
            self.console.println("Execution resumed");
        } else if parts[0] == "step" || parts[0] == "s" {
            self.broken = true;
            self.step = true;
        } else {
            self.console.println("Unknown command");
        }

        // Don't assign a blank command as a last command
        if !input.is_empty() {
            self.last_command = input.clone();
        }
    }

    fn enable_memory_monitor(&mut self, input: &str) {
        let parts: Vec<&str> = input.split(' ').collect();
        if parts.len() < 3 {
            self.console.println("ERR: Requires 2 arguments. Example: monitor 0x00 0xFF");
        } else {
            let start = usize::from_str_radix(&parts[1].replace("0x", "")[..], 16).unwrap();
            let end = usize::from_str_radix(&parts[2].replace("0x", "")[..], 16).unwrap();

            self.monitor.start_addr = start;
            self.monitor.end_addr = end;
            self.monitor.enabled = true;
        }
    }

    fn dump_disassembly(&mut self) {
        self.console.println("");

        for segment in &self.segments {
            self.console.println(format!(".ORG ${:04X}", segment.address));
            let disassembler = Disassembler::with_offset(segment.address);
            let pairs = disassembler.disassemble_with_addresses(&segment.code);
            let lines = self.highlight_lines(self.cpu.registers.PC as usize,
                                             pairs,
                                             segment.address,
                                             false);
            self.console.print_lines(lines.join(""));
        }
        self.console.println("");
    }

    fn dump_local_disassembly(&mut self) {
        self.console.println("");

        let result = {
            let pc = self.cpu.registers.PC as usize;
            let local_segment = self.get_local_segment(pc);
            let disassembler = Disassembler::with_offset(local_segment.address);
            let pairs = disassembler.disassemble_with_addresses(&local_segment.code);
            self.highlight_lines(pc, pairs, local_segment.address, true)
        };
        self.console.print_lines(result.join(""));
        self.console.println("");
    }

    pub fn dump_memory_page(&mut self, page: usize) {
        let mut addr = page * 0x100;
        for chunk in self.cpu.memory[page * 0x100..(page * 0x100) + 0x100].chunks(8) {
            self.console.print(format!("{:04X}: ", addr));
            for b in chunk {
                self.console.print(format!("{:02X} ", *b));
            }
            self.console.wrap_line();
            addr += 0x08;
        }
        self.console.println("");
    }

    pub fn dump_memory(&mut self) {
        for chunk in self.cpu.memory[self.monitor.start_addr..self.monitor.end_addr + 0x01]
            .chunks(8) {
            for b in chunk {
                self.console.print(format!("{:02X} ", *b));
            }
            self.console.wrap_line();
        }
    }

    fn dump_memory_range(&mut self, start: u16, end: u16) {
        let start = start as usize;
        let end = end as usize;
        for chunk in self.cpu.memory[start..end + 0x01].chunks(8) {
            for b in chunk {
                self.console.print(format!("{:02X} ", *b));
            }
            self.console.wrap_line();
        }
        self.console.println("");
    }

    fn dump_registers(&mut self) {
        self.console.println("");
        self.console.println(format!("A: {} ({:04X})", self.cpu.registers.A, self.cpu.registers.A));
        self.console.println(format!("X: {} ({:04X})", self.cpu.registers.X, self.cpu.registers.X));
        self.console.println(format!("Y: {} ({:04X})", self.cpu.registers.Y, self.cpu.registers.Y));
        self.console.println(format!("PC: {} ({:04X})",
                                     self.cpu.registers.PC,
                                     self.cpu.registers.PC));
        self.console.println(format!("S: {} ({:04X})",
                                     self.cpu.stack.pointer,
                                     self.cpu.stack.pointer));
    }

    fn get_local_segment(&self, pc: usize) -> &CodeSegment {
        for segment in &self.segments {
            let addr = segment.address as usize;
            if pc >= addr && pc <= addr + segment.code.len() {
                return segment;
            }
        }

        &self.segments[0]
    }

    fn highlight_lines(&self,
                       pc: usize,
                       pairs: Vec<(String, u16)>,
                       segment_start: u16,
                       limit_results: bool)
                       -> Vec<String> {
        let mut result = Vec::new();

        let base = pc as isize - segment_start as isize;

        for pair in pairs {
            if limit_results {
                let start = if base > 0x0A { base - 0x0A } else { 0 };
                if (pair.1 as isize) < start || (pair.1 as isize) > base + 0x0A {
                    continue;
                }
            }
            let current_line = pc as u16 == segment_start + pair.1;
            let breakpoint = self.breakpoints[segment_start as usize + pair.1 as usize] > 0x00;

            if breakpoint && current_line {
                result.push(format!("> * {}", pair.0));
            } else if breakpoint && !current_line {
                result.push(format!("  * {}", pair.0));
            } else if !breakpoint && current_line {
                result.push(format!(">   {}", pair.0));
            } else {
                result.push(format!("    {}", pair.0));
            }
        }

        result
    }
}
<|endoftext|>


<commit_before>//! "Weighted" graph types

use std;
use std::ops;
use std::fmt::Debug;

use smallvec::SmallVec;

use super::iter::{Indices,Successors};
use super::interface::{self, Id, Node as INode, Edge as IEdge};
use super::common::{IndexType,NodeIndex,EdgeIndex,DefaultIndexType};

/// Trait bounds for types used as edge and node data payloads.
pub trait Data: Clone + Debug {}
impl<T> Data for T where T: Clone + Debug {}

// ----------------------------------------------------------------
// Edge

/// Weighted edge type.
#[derive(Clone,Debug)]
pub struct Edge<T: Data, I: Id> {
    source: I,
    target: I,
    data: T
}

impl<T, I> interface::Edge<I> for Edge<T, I>
    where T: Data, I: Id {
    impl_basic_edge!();
}

impl<T: Data, I: Id> Edge<T, I> {
    /// Create an edge with the given source & target node indices and
    /// weight data.
    pub fn new(source: I, target: I, data: T) -> Self {
        Edge{source: source, target: target, data: data}
    }
}
///
impl<T: Data, I: Id> std::ops::Deref for Edge<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2, T)> for Edge<T, I>
    where I: From<I2> {
    fn from(u: (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2)
    }
}

impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: &'a (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}
impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2, T)> for Edge<T, I>
    where T: Clone, I: From<I2> {
    fn from(u: &'a (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2.clone())
    }
}

// ----------------------------------------------------------------
// Node

///  Weighted node implementation.
///
/// A reference to the node's weight data can be obtained using the type's
/// `Deref` implementation.
///
/// ```rust
/// use cripes::util::graph::{EdgeIndex,WeightedNode};
///
/// # fn main() {
/// let n = WeightedNode::<_, EdgeIndex<u8>>::new(32);
/// assert_eq!(32, *n);
/// # }
/// ```

#[derive(Clone,Debug)]
pub struct Node<T: Data, I: Id> {
    incoming_edges: SmallVec<[I; 8]>,
    outgoing_edges: SmallVec<[I; 8]>,
    data: T
}

impl<T: Data, I: Id> Node<T, I> {
    /// Instantiate a new node with the given data.
    pub fn new(data: T) -> Self {
        Node{incoming_edges: SmallVec::new(), outgoing_edges: SmallVec::new(), data: data}
    }
}

impl<T: Data, I: Id> std::ops::Deref for Node<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T, I> interface::Node<I> for Node<T, I>
        where T: Data, I: Id {
    impl_basic_node!(I);
}

// ----------------------------------------------------------------
// Graph

/// Directed graph with user-defined node and edge weights.
#[derive(Clone,Debug)]
pub struct Graph<N: Data, E: Data, Ix: IndexType = DefaultIndexType> {
    nodes: Vec<Node<N, EdgeIndex<Ix>>>,
    edges: Vec<Edge<E, NodeIndex<Ix>>>
}

impl<N, E, Ix> interface::Graph for Graph<N, E, Ix>
    where N: Data, E: Data, Ix: IndexType {
    type NodeId = NodeIndex<Ix>;
    type EdgeId = EdgeIndex<Ix>;
    type Node = Node<N, Self::EdgeId>;
    type Edge = Edge<E, Self::NodeId>;
    type EdgeIdIterator = Indices<Self::EdgeId>;
    type NodeIdIterator = Indices<Self::NodeId>;

    fn new() -> Self {
        Graph{nodes: Vec::new(), edges: Vec::new()}
    }

    fn add_node(&mut self, n: Self::Node) -> Self::NodeId {
        self.nodes.push(n);
        NodeIndex::new(self.nodes.len() - 1)
    }

    #[inline(always)]
    fn contains_node(&self, n: Self::NodeId) -> bool {
        n.index() < self.nodes.len()
    }

    #[inline(always)]
    fn node(&self, n: Self::NodeId) -> &Self::Node {
        &self.nodes[n.index()]
    }

    #[inline(always)]
    fn node_mut(&mut self, n: Self::NodeId) -> &mut Self::Node {
        &mut self.nodes[n.index()]
    }

    #[inline]
    fn incoming_edges(&self, n: Self::NodeId) -> std::slice::Iter<Self::EdgeId> {
        self.nodes[n.index()].incoming_edges()
    }

    #[inline]
    fn outgoing_edges(&self, n: Self::NodeId) -> std::slice::Iter<Self::EdgeId> {
        self.nodes[n.index()].outgoing_edges()
    }

    #[inline]
    fn direct_successors(&self, n: Self::NodeId) -> Successors<Self> {
        Successors::new(self, self.outgoing_edges(n))
    }

    #[inline]
    fn node_ids(&self) -> Self::NodeIdIterator {
        Indices::new(0..self.nodes.len())
    }

    #[inline]
    fn node_count(&self) -> usize {
        self.nodes.len()
    }

    fn add_edge(&mut self, e: Self::Edge) -> Self::EdgeId {
        let srcidx = e.source();
        let destidx = e.target();

        self.edges.push(e);
        let index = EdgeIndex::new(self.edges.len() - 1);

        // Update cross-referenced edge lists for the connected nodes.
        self.nodes[srcidx.index()].add_outgoing_edge(index);
        self.nodes[destidx.index()].add_incoming_edge(index);

        index
    }

    fn edge(&self, e: Self::EdgeId) -> &Self::Edge {
        &self.edges[e.index()]
    }

    fn contains_edge(&self, e: Self::EdgeId) -> bool {
        e.index() < self.edges.len()
    }

    fn edge_source(&self, e: EdgeIndex<Ix>) -> Self::NodeId {
        self.edges[e.index()].source()
    }

    fn edge_target(&self, e: EdgeIndex<Ix>) -> Self::NodeId {
        self.edges[e.index()].target()
    }

    fn edge_endpoints(&self, e: EdgeIndex<Ix>) -> (Self::NodeId, Self::NodeId) {
        let ref edge = self.edges[e.index()];
        (edge.source(), edge.target())
    }

    fn edge_ids(&self) -> Self::EdgeIdIterator {
        Indices::new(0..self.edges.len())
    }

    fn edge_count(&self) -> usize {
        self.edges.len()
    }
}

impl<N: Data, E: Data, Ix: IndexType> Graph<N, E, Ix> {
    /// Add a node to the graph.
    ///
    /// @return Index of the newly-added node.
    pub fn add_node(&mut self, data: N) -> NodeIndex<Ix> {
        <Self as interface::Graph>::add_node(self, <Self as interface::Graph>::Node::new(data))
    }

    /// Add an edge to the graph.
    ///
    /// The source and target nodes, as identified by calling `edge.source()`
    /// and `edge.target()` on the edge, will be updated as appropriate.
    ///
    /// **Panics** if either of the source or target node indices are invalid.
    ///
    /// @return Index of the newly-added edge.
    ///
    /// @fixme Is there any way we can make this operation atomic, or at least
    /// less drawn-out?
    pub fn add_edge(&mut self, source: NodeIndex<Ix>, target: NodeIndex<Ix>, data: E) -> EdgeIndex<Ix> {
        panic_unless!(source.index() < self.nodes.len(), "Invalid source-node index provided to `Graph::add_edge`");
        panic_unless!(target.index() < self.nodes.len(), "Invalid target-node index provided to `Graph::add_edge`");

        // Add the edge itself
        self.edges.push(<Self as interface::Graph>::Edge::new(source, target, data));

        // ...and add cross-references to the nodes.
        let edge = EdgeIndex::new(self.edges.len() - 1);
        self.nodes[source.index()].add_outgoing_edge(edge);
        self.nodes[target.index()].add_incoming_edge(edge);

        edge
    }
}

// Implement node-data lookup via indexing.
macro_rules! graph_index_impl {
    ($tp: ty, $n: ident, $e: ident, $r: ident, $m: ident) => {
        impl<$n: Data, $e: Data, Ix: IndexType> ops::Index<$tp> for Graph<N, E, Ix> {
            type Output = $r;
            fn index(&self, ix: $tp) -> &$r {
                &self.$m[ix.index()].data
            }

        }
        impl<$n: Data, $e: Data, Ix: IndexType> ops::IndexMut<$tp> for Graph<N, E, Ix> {
            fn index_mut(&mut self, ix: $tp) -> &mut $r {
                &mut self.$m[ix.index()].data
            }

        }
    }
}
graph_index_impl!(EdgeIndex<Ix>, N, E, E, edges);
graph_index_impl!(NodeIndex<Ix>, N, E, N, nodes);
<commit_msg>util/graph/weighted.rs: remove methods with default impls in Graph<commit_after>//! "Weighted" graph types

use std;
use std::ops;
use std::fmt::Debug;

use smallvec::SmallVec;

use super::iter::{Indices,Successors};
use super::interface::{self, Id, Node as INode, Edge as IEdge};
use super::common::{IndexType,NodeIndex,EdgeIndex,DefaultIndexType};

/// Trait bounds for types used as edge and node data payloads.
pub trait Data: Clone + Debug {}
impl<T> Data for T where T: Clone + Debug {}

// ----------------------------------------------------------------
// Edge

/// Weighted edge type.
#[derive(Clone,Debug)]
pub struct Edge<T: Data, I: Id> {
    source: I,
    target: I,
    data: T
}

impl<T, I> interface::Edge<I> for Edge<T, I>
    where T: Data, I: Id {
    impl_basic_edge!();
}

impl<T: Data, I: Id> Edge<T, I> {
    /// Create an edge with the given source & target node indices and
    /// weight data.
    pub fn new(source: I, target: I, data: T) -> Self {
        Edge{source: source, target: target, data: data}
    }
}
///
impl<T: Data, I: Id> std::ops::Deref for Edge<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2, T)> for Edge<T, I>
    where I: From<I2> {
    fn from(u: (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2)
    }
}

impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: &'a (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}
impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2, T)> for Edge<T, I>
    where T: Clone, I: From<I2> {
    fn from(u: &'a (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2.clone())
    }
}

// ----------------------------------------------------------------
// Node

///  Weighted node implementation.
///
/// A reference to the node's weight data can be obtained using the type's
/// `Deref` implementation.
///
/// ```rust
/// use cripes::util::graph::{EdgeIndex,WeightedNode};
///
/// # fn main() {
/// let n = WeightedNode::<_, EdgeIndex<u8>>::new(32);
/// assert_eq!(32, *n);
/// # }
/// ```

#[derive(Clone,Debug)]
pub struct Node<T: Data, I: Id> {
    incoming_edges: SmallVec<[I; 8]>,
    outgoing_edges: SmallVec<[I; 8]>,
    data: T
}

impl<T: Data, I: Id> Node<T, I> {
    /// Instantiate a new node with the given data.
    pub fn new(data: T) -> Self {
        Node{incoming_edges: SmallVec::new(), outgoing_edges: SmallVec::new(), data: data}
    }
}

impl<T: Data, I: Id> std::ops::Deref for Node<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T, I> interface::Node<I> for Node<T, I>
        where T: Data, I: Id {
    impl_basic_node!(I);
}

// ----------------------------------------------------------------
// Graph

/// Directed graph with user-defined node and edge weights.
#[derive(Clone,Debug)]
pub struct Graph<N: Data, E: Data, Ix: IndexType = DefaultIndexType> {
    nodes: Vec<Node<N, EdgeIndex<Ix>>>,
    edges: Vec<Edge<E, NodeIndex<Ix>>>
}

impl<N, E, Ix> interface::Graph for Graph<N, E, Ix>
    where N: Data, E: Data, Ix: IndexType {
    type NodeId = NodeIndex<Ix>;
    type EdgeId = EdgeIndex<Ix>;
    type Node = Node<N, Self::EdgeId>;
    type Edge = Edge<E, Self::NodeId>;
    type EdgeIdIterator = Indices<Self::EdgeId>;
    type NodeIdIterator = Indices<Self::NodeId>;

    fn new() -> Self {
        Graph{nodes: Vec::new(), edges: Vec::new()}
    }

    fn add_node(&mut self, n: Self::Node) -> Self::NodeId {
        self.nodes.push(n);
        NodeIndex::new(self.nodes.len() - 1)
    }

    #[inline(always)]
    fn contains_node(&self, n: Self::NodeId) -> bool {
        n.index() < self.nodes.len()
    }

    #[inline(always)]
    fn node(&self, n: Self::NodeId) -> &Self::Node {
        &self.nodes[n.index()]
    }

    #[inline(always)]
    fn node_mut(&mut self, n: Self::NodeId) -> &mut Self::Node {
        &mut self.nodes[n.index()]
    }

    #[inline]
    fn node_ids(&self) -> Self::NodeIdIterator {
        Indices::new(0..self.nodes.len())
    }

    #[inline]
    fn node_count(&self) -> usize {
        self.nodes.len()
    }

    fn add_edge(&mut self, e: Self::Edge) -> Self::EdgeId {
        let srcidx = e.source();
        let destidx = e.target();

        self.edges.push(e);
        let index = EdgeIndex::new(self.edges.len() - 1);

        // Update cross-referenced edge lists for the connected nodes.
        self.nodes[srcidx.index()].add_outgoing_edge(index);
        self.nodes[destidx.index()].add_incoming_edge(index);

        index
    }

    fn edge(&self, e: Self::EdgeId) -> &Self::Edge {
        &self.edges[e.index()]
    }

    fn contains_edge(&self, e: Self::EdgeId) -> bool {
        e.index() < self.edges.len()
    }

    fn edge_ids(&self) -> Self::EdgeIdIterator {
        Indices::new(0..self.edges.len())
    }

    fn edge_count(&self) -> usize {
        self.edges.len()
    }
}

impl<N: Data, E: Data, Ix: IndexType> Graph<N, E, Ix> {
    /// Add a node to the graph.
    ///
    /// @return Index of the newly-added node.
    pub fn add_node(&mut self, data: N) -> NodeIndex<Ix> {
        <Self as interface::Graph>::add_node(self, <Self as interface::Graph>::Node::new(data))
    }

    /// Add an edge to the graph.
    ///
    /// The source and target nodes, as identified by calling `edge.source()`
    /// and `edge.target()` on the edge, will be updated as appropriate.
    ///
    /// **Panics** if either of the source or target node indices are invalid.
    ///
    /// @return Index of the newly-added edge.
    ///
    /// @fixme Is there any way we can make this operation atomic, or at least
    /// less drawn-out?
    pub fn add_edge(&mut self, source: NodeIndex<Ix>, target: NodeIndex<Ix>, data: E) -> EdgeIndex<Ix> {
        panic_unless!(source.index() < self.nodes.len(), "Invalid source-node index provided to `Graph::add_edge`");
        panic_unless!(target.index() < self.nodes.len(), "Invalid target-node index provided to `Graph::add_edge`");

        // Add the edge itself
        self.edges.push(<Self as interface::Graph>::Edge::new(source, target, data));

        // ...and add cross-references to the nodes.
        let edge = EdgeIndex::new(self.edges.len() - 1);
        self.nodes[source.index()].add_outgoing_edge(edge);
        self.nodes[target.index()].add_incoming_edge(edge);

        edge
    }
}

// Implement node-data lookup via indexing.
macro_rules! graph_index_impl {
    ($tp: ty, $n: ident, $e: ident, $r: ident, $m: ident) => {
        impl<$n: Data, $e: Data, Ix: IndexType> ops::Index<$tp> for Graph<N, E, Ix> {
            type Output = $r;
            fn index(&self, ix: $tp) -> &$r {
                &self.$m[ix.index()].data
            }

        }
        impl<$n: Data, $e: Data, Ix: IndexType> ops::IndexMut<$tp> for Graph<N, E, Ix> {
            fn index_mut(&mut self, ix: $tp) -> &mut $r {
                &mut self.$m[ix.index()].data
            }

        }
    }
}
graph_index_impl!(EdgeIndex<Ix>, N, E, E, edges);
graph_index_impl!(NodeIndex<Ix>, N, E, N, nodes);
<|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 browser_host::{ServoCefBrowserHost, ServoCefBrowserHostExtensions};
use eutil::Downcast;
use frame::{ServoCefFrame, ServoCefFrameExtensions};
use interfaces::{CefBrowser, CefBrowserHost, CefClient, CefFrame, CefRequestContext};
use interfaces::{cef_browser_t, cef_browser_host_t, cef_client_t, cef_frame_t};
use interfaces::{cef_request_context_t};
use servo::Browser;
use types::{cef_browser_settings_t, cef_string_t, cef_window_info_t, cef_window_handle_t};
use window;
use wrappers::CefWrap;

use compositing::windowing::{WindowNavigateMsg, WindowEvent};
use glutin_app;
use libc::c_int;
use std::cell::{Cell, RefCell, BorrowState};
use std::ptr;
use std::rc::Rc;
use std::sync::atomic::{AtomicIsize, Ordering};

thread_local!(pub static ID_COUNTER: AtomicIsize = AtomicIsize::new(0));
thread_local!(pub static BROWSERS: RefCell<Vec<CefBrowser>> = RefCell::new(vec!()));

pub enum ServoBrowser {
    Invalid,
    OnScreen(Browser),
    OffScreen(Browser),
}

impl ServoBrowser {
    fn handle_event(&mut self, event: WindowEvent) {
        match *self {
            ServoBrowser::OnScreen(ref mut browser) => { browser.handle_events(vec![event]); }
            ServoBrowser::OffScreen(ref mut browser) => { browser.handle_events(vec![event]); }
            ServoBrowser::Invalid => {}
        }
    }

    pub fn get_title_for_main_frame(&self) {
        match *self {
            ServoBrowser::OnScreen(ref browser) => browser.get_title_for_main_frame(),
            ServoBrowser::OffScreen(ref browser) => browser.get_title_for_main_frame(),
            ServoBrowser::Invalid => {}
        }
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        match *self {
            ServoBrowser::OnScreen(ref browser) => browser.pinch_zoom_level(),
            ServoBrowser::OffScreen(ref browser) => browser.pinch_zoom_level(),
            ServoBrowser::Invalid => 1.0,
        }
    }
}

cef_class_impl! {
    ServoCefBrowser : CefBrowser, cef_browser_t {
        fn get_host(&this,) -> *mut cef_browser_host_t {{
            this.downcast().host.clone()
        }}

        fn go_back(&this,) -> () {{
            this.send_window_event(WindowEvent::Navigation(WindowNavigateMsg::Back));
        }}

        fn go_forward(&this,) -> () {{
            this.send_window_event(WindowEvent::Navigation(WindowNavigateMsg::Forward));
        }}

        // Returns the main (top-level) frame for the browser window.
        fn get_main_frame(&this,) -> *mut cef_frame_t {{
            this.downcast().frame.clone()
        }}

        fn get_identifier(&this,) -> c_int {{
            this.downcast().id as c_int
        }}
    }
}

pub struct ServoCefBrowser {
    /// A reference to the browser's primary frame.
    pub frame: CefFrame,
    /// A reference to the browser's host.
    pub host: CefBrowserHost,
    /// A reference to the browser client.
    pub client: CefClient,
    /// the glutin window when using windowed rendering
    pub window: Option<Rc<glutin_app::window::Window>>,
    /// Whether the on-created callback has fired yet.
    pub callback_executed: Cell<bool>,
    /// the display system window handle: only to be used with host.get_window_handle()
    window_handle: cef_window_handle_t,

    id: isize,
    servo_browser: RefCell<ServoBrowser>,
    message_queue: RefCell<Vec<WindowEvent>>,
}

impl ServoCefBrowser {
    pub fn new(window_info: &cef_window_info_t, client: CefClient) -> ServoCefBrowser {
        let frame = ServoCefFrame::new().as_cef_interface();
        let host = ServoCefBrowserHost::new(client.clone()).as_cef_interface();
        let mut window_handle: cef_window_handle_t = get_null_window_handle();
        let mut glutin_window: Option<Rc<glutin_app::window::Window>> = None;

        let servo_browser = if window_info.windowless_rendering_enabled == 0 {
            glutin_window = Some(glutin_app::create_window(window_info.parent_window as glutin_app::WindowID));
            let servo_browser = Browser::new(glutin_window.clone());
            window_handle = match glutin_window {
                Some(ref win) => win.platform_window() as cef_window_handle_t,
                None => get_null_window_handle()
            };
            ServoBrowser::OnScreen(servo_browser)
        } else {
            ServoBrowser::Invalid
        };

        let id = ID_COUNTER.with(|counter| {
            counter.fetch_add(1, Ordering::SeqCst)
        });

        ServoCefBrowser {
            frame: frame,
            host: host,
            client: client,
            window: glutin_window,
            callback_executed: Cell::new(false),
            servo_browser: RefCell::new(servo_browser),
            message_queue: RefCell::new(vec!()),
            id: id,
            window_handle: window_handle,
        }
    }
}

pub trait ServoCefBrowserExtensions {
    fn init(&self, window_info: &cef_window_info_t);
    fn send_window_event(&self, event: WindowEvent);
    fn get_title_for_main_frame(&self);
    fn pinch_zoom_level(&self) -> f32;
}

impl ServoCefBrowserExtensions for CefBrowser {
    fn init(&self, window_info: &cef_window_info_t) {
        if window_info.windowless_rendering_enabled != 0 {
            let window = window::Window::new(window_info.width, window_info.height);
            window.set_browser(self.clone());
            let servo_browser = Browser::new(Some(window.clone()));
            *self.downcast().servo_browser.borrow_mut() = ServoBrowser::OffScreen(servo_browser);
        }

        self.downcast().host.set_browser((*self).clone());
        self.downcast().frame.set_browser((*self).clone());
        if window_info.windowless_rendering_enabled == 0 {
            self.downcast().host.initialize_compositing();
        }
    }

    fn send_window_event(&self, event: WindowEvent) {
        self.downcast().message_queue.borrow_mut().push(event);

        loop {
            match self.downcast().servo_browser.borrow_state() {
                BorrowState::Unused => {
                    let event = match self.downcast().message_queue.borrow_mut().pop() {
                        None => return,
                        Some(event) => event,
                    };
                    self.downcast().servo_browser.borrow_mut().handle_event(event);
                }
                _ => {
                    // We're trying to send an event while processing another one. This will
                    // cause general badness, so queue up that event instead of immediately
                    // processing it.
                    break
                }
            }
        }
    }

    fn get_title_for_main_frame(&self) {
        self.downcast().servo_browser.borrow().get_title_for_main_frame()
    }

    fn pinch_zoom_level(&self) -> f32 {
        self.downcast().servo_browser.borrow().pinch_zoom_level()
    }
}

#[cfg(target_os="macos")]
pub fn get_null_window_handle() -> cef_window_handle_t {
    ptr::null_mut()
}
#[cfg(target_os="linux")]
pub fn get_null_window_handle() -> cef_window_handle_t {
    0
}

pub fn update() {
    BROWSERS.with(|browsers| {
        for browser in browsers.borrow().iter() {
            if browser.downcast().callback_executed.get() == false {
                browser_callback_after_created(browser.clone());
            }
            let event = match browser.downcast().window {
                Some(ref win) => win.wait_events(),
                None => WindowEvent::Idle
            };
            browser.send_window_event(event);
        }
    });
}

pub fn close(browser: CefBrowser) {
    BROWSERS.with(|browsers| {
        let mut browsers = browsers.borrow_mut();
        browsers.iter()
                .position(|&ref n| n.downcast().id == browser.downcast().id)
                .map(|e| browsers.remove(e));
    });
}

pub fn get_window(browser: &CefBrowser) -> cef_window_handle_t {
    browser.downcast().window_handle
}

pub fn browser_callback_after_created(browser: CefBrowser) {
    if browser.downcast().client.is_null_cef_object() {
        return
    }
    let client = browser.downcast().client.clone();
    let life_span_handler = client.get_life_span_handler();
    if life_span_handler.is_not_null_cef_object() {
        life_span_handler.on_after_created(browser.clone());
    }
    browser.downcast().callback_executed.set(true);
}

fn browser_host_create(window_info: &cef_window_info_t,
                       client: CefClient,
                       url: *const cef_string_t,
                       callback_executed: bool)
                       -> CefBrowser {
    let browser = ServoCefBrowser::new(window_info, client).as_cef_interface();
    browser.init(window_info);
    if callback_executed {
        browser_callback_after_created(browser.clone());
    }
    //if url != ptr::null() {
       //unsafe { browser.downcast().frame.load_url(CefWrap::to_rust(url)); }
    //}
    BROWSERS.with(|browsers| {
        browsers.borrow_mut().push(browser.clone());
    });
    browser
}

cef_static_method_impls! {
    fn cef_browser_host_create_browser(window_info: *const cef_window_info_t,
                                       client: *mut cef_client_t,
                                       url: *const cef_string_t,
                                       _browser_settings: *const cef_browser_settings_t,
                                       _request_context: *mut cef_request_context_t)
                                       -> c_int {{
        let client: CefClient = client;
        let _browser_settings: &cef_browser_settings_t = _browser_settings;
        let _request_context: CefRequestContext = _request_context;
        browser_host_create(window_info, client, url, false);
        1i32
    }}
    fn cef_browser_host_create_browser_sync(window_info: *const cef_window_info_t,
                                            client: *mut cef_client_t,
                                            url: *const cef_string_t,
                                            _browser_settings: *const cef_browser_settings_t,
                                            _request_context: *mut cef_request_context_t)
                                            -> *mut cef_browser_t {{
        let client: CefClient = client;
        let _browser_settings: &cef_browser_settings_t = _browser_settings;
        let _request_context: CefRequestContext = _request_context;
        browser_host_create(window_info, client, url, true)
    }}
}
<commit_msg>fix compile after pcwalton's multi-event handling PR<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 browser_host::{ServoCefBrowserHost, ServoCefBrowserHostExtensions};
use eutil::Downcast;
use frame::{ServoCefFrame, ServoCefFrameExtensions};
use interfaces::{CefBrowser, CefBrowserHost, CefClient, CefFrame, CefRequestContext};
use interfaces::{cef_browser_t, cef_browser_host_t, cef_client_t, cef_frame_t};
use interfaces::{cef_request_context_t};
use servo::Browser;
use types::{cef_browser_settings_t, cef_string_t, cef_window_info_t, cef_window_handle_t};
use window;
use wrappers::CefWrap;

use compositing::windowing::{WindowNavigateMsg, WindowEvent};
use glutin_app;
use libc::c_int;
use std::cell::{Cell, RefCell, BorrowState};
use std::ptr;
use std::rc::Rc;
use std::sync::atomic::{AtomicIsize, Ordering};

thread_local!(pub static ID_COUNTER: AtomicIsize = AtomicIsize::new(0));
thread_local!(pub static BROWSERS: RefCell<Vec<CefBrowser>> = RefCell::new(vec!()));

pub enum ServoBrowser {
    Invalid,
    OnScreen(Browser),
    OffScreen(Browser),
}

impl ServoBrowser {
    fn handle_event(&mut self, event: WindowEvent) {
        match *self {
            ServoBrowser::OnScreen(ref mut browser) => { browser.handle_events(vec![event]); }
            ServoBrowser::OffScreen(ref mut browser) => { browser.handle_events(vec![event]); }
            ServoBrowser::Invalid => {}
        }
    }

    pub fn get_title_for_main_frame(&self) {
        match *self {
            ServoBrowser::OnScreen(ref browser) => browser.get_title_for_main_frame(),
            ServoBrowser::OffScreen(ref browser) => browser.get_title_for_main_frame(),
            ServoBrowser::Invalid => {}
        }
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        match *self {
            ServoBrowser::OnScreen(ref browser) => browser.pinch_zoom_level(),
            ServoBrowser::OffScreen(ref browser) => browser.pinch_zoom_level(),
            ServoBrowser::Invalid => 1.0,
        }
    }
}

cef_class_impl! {
    ServoCefBrowser : CefBrowser, cef_browser_t {
        fn get_host(&this,) -> *mut cef_browser_host_t {{
            this.downcast().host.clone()
        }}

        fn go_back(&this,) -> () {{
            this.send_window_event(WindowEvent::Navigation(WindowNavigateMsg::Back));
        }}

        fn go_forward(&this,) -> () {{
            this.send_window_event(WindowEvent::Navigation(WindowNavigateMsg::Forward));
        }}

        // Returns the main (top-level) frame for the browser window.
        fn get_main_frame(&this,) -> *mut cef_frame_t {{
            this.downcast().frame.clone()
        }}

        fn get_identifier(&this,) -> c_int {{
            this.downcast().id as c_int
        }}
    }
}

pub struct ServoCefBrowser {
    /// A reference to the browser's primary frame.
    pub frame: CefFrame,
    /// A reference to the browser's host.
    pub host: CefBrowserHost,
    /// A reference to the browser client.
    pub client: CefClient,
    /// the glutin window when using windowed rendering
    pub window: Option<Rc<glutin_app::window::Window>>,
    /// Whether the on-created callback has fired yet.
    pub callback_executed: Cell<bool>,
    /// the display system window handle: only to be used with host.get_window_handle()
    window_handle: cef_window_handle_t,

    id: isize,
    servo_browser: RefCell<ServoBrowser>,
    message_queue: RefCell<Vec<WindowEvent>>,
}

impl ServoCefBrowser {
    pub fn new(window_info: &cef_window_info_t, client: CefClient) -> ServoCefBrowser {
        let frame = ServoCefFrame::new().as_cef_interface();
        let host = ServoCefBrowserHost::new(client.clone()).as_cef_interface();
        let mut window_handle: cef_window_handle_t = get_null_window_handle();
        let mut glutin_window: Option<Rc<glutin_app::window::Window>> = None;

        let servo_browser = if window_info.windowless_rendering_enabled == 0 {
            glutin_window = Some(glutin_app::create_window(window_info.parent_window as glutin_app::WindowID));
            let servo_browser = Browser::new(glutin_window.clone());
            window_handle = match glutin_window {
                Some(ref win) => win.platform_window() as cef_window_handle_t,
                None => get_null_window_handle()
            };
            ServoBrowser::OnScreen(servo_browser)
        } else {
            ServoBrowser::Invalid
        };

        let id = ID_COUNTER.with(|counter| {
            counter.fetch_add(1, Ordering::SeqCst)
        });

        ServoCefBrowser {
            frame: frame,
            host: host,
            client: client,
            window: glutin_window,
            callback_executed: Cell::new(false),
            servo_browser: RefCell::new(servo_browser),
            message_queue: RefCell::new(vec!()),
            id: id,
            window_handle: window_handle,
        }
    }
}

pub trait ServoCefBrowserExtensions {
    fn init(&self, window_info: &cef_window_info_t);
    fn send_window_event(&self, event: WindowEvent);
    fn get_title_for_main_frame(&self);
    fn pinch_zoom_level(&self) -> f32;
}

impl ServoCefBrowserExtensions for CefBrowser {
    fn init(&self, window_info: &cef_window_info_t) {
        if window_info.windowless_rendering_enabled != 0 {
            let window = window::Window::new(window_info.width, window_info.height);
            window.set_browser(self.clone());
            let servo_browser = Browser::new(Some(window.clone()));
            *self.downcast().servo_browser.borrow_mut() = ServoBrowser::OffScreen(servo_browser);
        }

        self.downcast().host.set_browser((*self).clone());
        self.downcast().frame.set_browser((*self).clone());
        if window_info.windowless_rendering_enabled == 0 {
            self.downcast().host.initialize_compositing();
        }
    }

    fn send_window_event(&self, event: WindowEvent) {
        self.downcast().message_queue.borrow_mut().push(event);

        loop {
            match self.downcast().servo_browser.borrow_state() {
                BorrowState::Unused => {
                    let event = match self.downcast().message_queue.borrow_mut().pop() {
                        None => return,
                        Some(event) => event,
                    };
                    self.downcast().servo_browser.borrow_mut().handle_event(event);
                }
                _ => {
                    // We're trying to send an event while processing another one. This will
                    // cause general badness, so queue up that event instead of immediately
                    // processing it.
                    break
                }
            }
        }
    }

    fn get_title_for_main_frame(&self) {
        self.downcast().servo_browser.borrow().get_title_for_main_frame()
    }

    fn pinch_zoom_level(&self) -> f32 {
        self.downcast().servo_browser.borrow().pinch_zoom_level()
    }
}

#[cfg(target_os="macos")]
pub fn get_null_window_handle() -> cef_window_handle_t {
    ptr::null_mut()
}
#[cfg(target_os="linux")]
pub fn get_null_window_handle() -> cef_window_handle_t {
    0
}

pub fn update() {
    BROWSERS.with(|browsers| {
        for browser in browsers.borrow().iter() {
            if browser.downcast().callback_executed.get() == false {
                browser_callback_after_created(browser.clone());
            }
            let mut events = match browser.downcast().window {
                Some(ref win) => win.wait_events(),
                None => vec![WindowEvent::Idle]
            };
            loop {
               match events.pop() {
                   Some(event) => browser.send_window_event(event),
                   None => break
               }
            }
        }
    });
}

pub fn close(browser: CefBrowser) {
    BROWSERS.with(|browsers| {
        let mut browsers = browsers.borrow_mut();
        browsers.iter()
                .position(|&ref n| n.downcast().id == browser.downcast().id)
                .map(|e| browsers.remove(e));
    });
}

pub fn get_window(browser: &CefBrowser) -> cef_window_handle_t {
    browser.downcast().window_handle
}

pub fn browser_callback_after_created(browser: CefBrowser) {
    if browser.downcast().client.is_null_cef_object() {
        return
    }
    let client = browser.downcast().client.clone();
    let life_span_handler = client.get_life_span_handler();
    if life_span_handler.is_not_null_cef_object() {
        life_span_handler.on_after_created(browser.clone());
    }
    browser.downcast().callback_executed.set(true);
}

fn browser_host_create(window_info: &cef_window_info_t,
                       client: CefClient,
                       url: *const cef_string_t,
                       callback_executed: bool)
                       -> CefBrowser {
    let browser = ServoCefBrowser::new(window_info, client).as_cef_interface();
    browser.init(window_info);
    if callback_executed {
        browser_callback_after_created(browser.clone());
    }
    //if url != ptr::null() {
       //unsafe { browser.downcast().frame.load_url(CefWrap::to_rust(url)); }
    //}
    BROWSERS.with(|browsers| {
        browsers.borrow_mut().push(browser.clone());
    });
    browser
}

cef_static_method_impls! {
    fn cef_browser_host_create_browser(window_info: *const cef_window_info_t,
                                       client: *mut cef_client_t,
                                       url: *const cef_string_t,
                                       _browser_settings: *const cef_browser_settings_t,
                                       _request_context: *mut cef_request_context_t)
                                       -> c_int {{
        let client: CefClient = client;
        let _browser_settings: &cef_browser_settings_t = _browser_settings;
        let _request_context: CefRequestContext = _request_context;
        browser_host_create(window_info, client, url, false);
        1i32
    }}
    fn cef_browser_host_create_browser_sync(window_info: *const cef_window_info_t,
                                            client: *mut cef_client_t,
                                            url: *const cef_string_t,
                                            _browser_settings: *const cef_browser_settings_t,
                                            _request_context: *mut cef_request_context_t)
                                            -> *mut cef_browser_t {{
        let client: CefClient = client;
        let _browser_settings: &cef_browser_settings_t = _browser_settings;
        let _request_context: CefRequestContext = _request_context;
        browser_host_create(window_info, client, url, true)
    }}
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Generic char output trait.

use core::str::{Str, StrPrelude};
use core::slice::SliceExt;
use core::iter::range;

use core::mem::zeroed;

use util::strconv;

/// CharIO provides interface for outputting characters.
///
/// This trait implements the common functions to output strings and numbers,
/// requiring only one method: `putc`.
pub trait CharIO {
  /// Outputs a character.
  fn putc(&self, value: char);

  /// Outputs a string.
  fn puts(&self, s: &str) {
    let chars : &[u8] = s.as_slice().as_bytes();
    for i in range(0, s.len()) {
      let c : char = chars[i] as char;
      self.putc(c);
    }
  }

  /// Outputs an integer with given base.
  fn putint(&self, i: u32, base: u32) {
    let mut buf : [u8, ..32] = unsafe { zeroed() };
    let bsl : &mut [u8] = &mut buf;
    strconv::itoa(i, bsl, base);

    for &i in bsl.iter() {
      if i == 0 {
        break;
      }
      self.putc(i as char);
    }
  }

  /// Outputs an integer.
  fn puti(&self, i: u32) {
    self.putint(i, 10);
  }

  /// Outputs an integer as a hex string.
  fn puth(&self, i: u32) {
    self.putint(i, 16);
  }
}

#[cfg(test)]
pub mod test {
  use core::cell::RefCell;

  use drivers::chario::CharIO;

  pub struct TestCharIOData {
    last_char: char,
    putc_calls: uint,
  }

  pub struct TestCharIO {
    data: RefCell<TestCharIOData>
  }

  impl CharIO for TestCharIO {
    fn putc(&self, value: char) {
      let mut data = self.data.borrow_mut();
      data.putc_calls += 1;
      data.last_char = value;
    }
  }

  impl TestCharIO {
    pub fn new() -> TestCharIO {
      TestCharIO {
        data: RefCell::new(TestCharIOData {
          last_char: '\0',
          putc_calls: 0,
        }),
      }
    }

    fn get_last_char(&self) -> char {
      self.data.borrow().last_char
    }

    fn get_and_reset_putc_calls(&self) -> uint {
      let current = self.data.borrow().putc_calls;
      self.data.borrow_mut().putc_calls = 0;
      current
    }
  }

  #[test]
  fn putc_should_store_a_char() {
    let io = TestCharIO::new();
    io.putc('a');
    assert!(io.get_last_char() == 'a');
    io.putc('z');
    assert!(io.get_last_char() == 'z');
  }

  #[test]
  fn puti_should_store_a_number_as_char() {
    let io = TestCharIO::new();
    io.puti(3);
    assert!(io.get_last_char() == '3');
    io.puti(9);
    assert!(io.get_last_char() == '9');
    io.puti(10);
    assert!(io.get_last_char() == '0');
    io.puti(11);
    assert!(io.get_last_char() == '1');
  }

  #[test]
  fn puth_should_store_a_number_as_char() {
    let io = TestCharIO::new();
    io.puth(3);
    assert!(io.get_last_char() == '3');
    io.puth(9);
    assert!(io.get_last_char() == '9');
    io.puth(10);
    assert!(io.get_last_char() == 'a');
    io.puth(11);
    assert!(io.get_last_char() == 'b');
    io.puth(16);
    assert!(io.get_last_char() == '0');
    io.puth(17);
    assert!(io.get_last_char() == '1');
  }

  #[test]
  fn putint_should_work_with_different_bases() {
    let io = TestCharIO::new();
    io.putint(0, 2);
    assert!(io.get_last_char() == '0');
    io.putint(1, 2);
    assert!(io.get_last_char() == '1');
    io.putint(2, 2);
    assert!(io.get_last_char() == '0');
    io.putint(3, 2);
    assert!(io.get_last_char() == '1');
    io.putint(7, 7);
    assert!(io.get_last_char() == '0');
    io.putint(8, 7);
    assert!(io.get_last_char() == '1');
    io.putint(12, 7);
    assert!(io.get_last_char() == '5');
    io.putint(14, 7);
    assert!(io.get_last_char() == '0');
  }

  #[test]
  fn puts_should_leave_us_with_just_the_last_char() {
    let io = TestCharIO::new();
    io.puts("fu!");
    assert!(io.get_last_char() == '!');
    assert!(io.get_and_reset_putc_calls() == 3);
    io.puts("\n\t");
    assert!(io.get_last_char() == '\t');
    assert!(io.get_and_reset_putc_calls() == 2);
  }
}
<commit_msg>StrPrelude -> StrExt<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Generic char output trait.

use core::str::{Str, StrExt};
use core::slice::SliceExt;
use core::iter::range;

use core::mem::zeroed;

use util::strconv;

/// CharIO provides interface for outputting characters.
///
/// This trait implements the common functions to output strings and numbers,
/// requiring only one method: `putc`.
pub trait CharIO {
  /// Outputs a character.
  fn putc(&self, value: char);

  /// Outputs a string.
  fn puts(&self, s: &str) {
    let chars : &[u8] = s.as_slice().as_bytes();
    for i in range(0, s.len()) {
      let c : char = chars[i] as char;
      self.putc(c);
    }
  }

  /// Outputs an integer with given base.
  fn putint(&self, i: u32, base: u32) {
    let mut buf : [u8, ..32] = unsafe { zeroed() };
    let bsl : &mut [u8] = &mut buf;
    strconv::itoa(i, bsl, base);

    for &i in bsl.iter() {
      if i == 0 {
        break;
      }
      self.putc(i as char);
    }
  }

  /// Outputs an integer.
  fn puti(&self, i: u32) {
    self.putint(i, 10);
  }

  /// Outputs an integer as a hex string.
  fn puth(&self, i: u32) {
    self.putint(i, 16);
  }
}

#[cfg(test)]
pub mod test {
  use core::cell::RefCell;

  use drivers::chario::CharIO;

  pub struct TestCharIOData {
    last_char: char,
    putc_calls: uint,
  }

  pub struct TestCharIO {
    data: RefCell<TestCharIOData>
  }

  impl CharIO for TestCharIO {
    fn putc(&self, value: char) {
      let mut data = self.data.borrow_mut();
      data.putc_calls += 1;
      data.last_char = value;
    }
  }

  impl TestCharIO {
    pub fn new() -> TestCharIO {
      TestCharIO {
        data: RefCell::new(TestCharIOData {
          last_char: '\0',
          putc_calls: 0,
        }),
      }
    }

    fn get_last_char(&self) -> char {
      self.data.borrow().last_char
    }

    fn get_and_reset_putc_calls(&self) -> uint {
      let current = self.data.borrow().putc_calls;
      self.data.borrow_mut().putc_calls = 0;
      current
    }
  }

  #[test]
  fn putc_should_store_a_char() {
    let io = TestCharIO::new();
    io.putc('a');
    assert!(io.get_last_char() == 'a');
    io.putc('z');
    assert!(io.get_last_char() == 'z');
  }

  #[test]
  fn puti_should_store_a_number_as_char() {
    let io = TestCharIO::new();
    io.puti(3);
    assert!(io.get_last_char() == '3');
    io.puti(9);
    assert!(io.get_last_char() == '9');
    io.puti(10);
    assert!(io.get_last_char() == '0');
    io.puti(11);
    assert!(io.get_last_char() == '1');
  }

  #[test]
  fn puth_should_store_a_number_as_char() {
    let io = TestCharIO::new();
    io.puth(3);
    assert!(io.get_last_char() == '3');
    io.puth(9);
    assert!(io.get_last_char() == '9');
    io.puth(10);
    assert!(io.get_last_char() == 'a');
    io.puth(11);
    assert!(io.get_last_char() == 'b');
    io.puth(16);
    assert!(io.get_last_char() == '0');
    io.puth(17);
    assert!(io.get_last_char() == '1');
  }

  #[test]
  fn putint_should_work_with_different_bases() {
    let io = TestCharIO::new();
    io.putint(0, 2);
    assert!(io.get_last_char() == '0');
    io.putint(1, 2);
    assert!(io.get_last_char() == '1');
    io.putint(2, 2);
    assert!(io.get_last_char() == '0');
    io.putint(3, 2);
    assert!(io.get_last_char() == '1');
    io.putint(7, 7);
    assert!(io.get_last_char() == '0');
    io.putint(8, 7);
    assert!(io.get_last_char() == '1');
    io.putint(12, 7);
    assert!(io.get_last_char() == '5');
    io.putint(14, 7);
    assert!(io.get_last_char() == '0');
  }

  #[test]
  fn puts_should_leave_us_with_just_the_last_char() {
    let io = TestCharIO::new();
    io.puts("fu!");
    assert!(io.get_last_char() == '!');
    assert!(io.get_and_reset_putc_calls() == 3);
    io.puts("\n\t");
    assert!(io.get_last_char() == '\t');
    assert!(io.get_and_reset_putc_calls() == 2);
  }
}
<|endoftext|>


<commit_before>use std::cell::Cell;

use cairo::{self, MatrixTrait};

use crate::attributes::Attribute;
use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::drawing_ctx::DrawingCtx;
use crate::error::RenderingError;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::ParseValue;
use crate::property_bag::PropertyBag;

coord_units!(ClipPathUnits, CoordUnits::UserSpaceOnUse);

pub struct NodeClipPath {
    units: Cell<ClipPathUnits>,
}

impl NodeClipPath {
    pub fn new() -> NodeClipPath {
        NodeClipPath {
            units: Cell::new(ClipPathUnits::default()),
        }
    }

    pub fn get_units(&self) -> ClipPathUnits {
        self.units.get()
    }

    pub fn to_cairo_context(
        &self,
        node: &RsvgNode,
        affine_before_clip: &cairo::Matrix,
        draw_ctx: &mut DrawingCtx,
        bbox: &BoundingBox,
    ) -> Result<(), RenderingError> {
        let cascaded = node.get_cascaded_values();

        let clip_units = self.units.get();

        let cr = draw_ctx.get_cairo_context();
        let save_affine = cr.get_matrix();

        let child_matrix = if clip_units == ClipPathUnits(CoordUnits::ObjectBoundingBox) {
            if bbox.rect.is_none() {
                // The node being clipped is empty / doesn't have a
                // bounding box, so there's nothing to clip!
                return Ok(());
            }

            let rect = bbox.rect.as_ref().unwrap();

            let bbtransform = cairo::Matrix::new(rect.width, 0.0, 0.0, rect.height, rect.x, rect.y);
            cairo::Matrix::multiply(&bbtransform, affine_before_clip)
        } else {
            *affine_before_clip
        };

        cr.set_matrix(child_matrix);

        // here we don't push a layer because we are clipping
        let res = node.draw_children(&cascaded, draw_ctx, true);

        cr.set_matrix(save_affine);

        cr.clip();

        res
    }
}

impl NodeTrait for NodeClipPath {
    fn set_atts(&self, _: &RsvgNode, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                Attribute::ClipPathUnits => self.units.set(attr.parse(value)?),
                _ => (),
            }
        }

        Ok(())
    }
}
<commit_msg>NodeClipPath.to_cairo_context() - Simplify the way in which the affine is set<commit_after>use std::cell::Cell;

use cairo::{self, MatrixTrait};

use crate::attributes::Attribute;
use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::drawing_ctx::DrawingCtx;
use crate::error::RenderingError;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::parsers::ParseValue;
use crate::property_bag::PropertyBag;

coord_units!(ClipPathUnits, CoordUnits::UserSpaceOnUse);

pub struct NodeClipPath {
    units: Cell<ClipPathUnits>,
}

impl NodeClipPath {
    pub fn new() -> NodeClipPath {
        NodeClipPath {
            units: Cell::new(ClipPathUnits::default()),
        }
    }

    pub fn get_units(&self) -> ClipPathUnits {
        self.units.get()
    }

    pub fn to_cairo_context(
        &self,
        node: &RsvgNode,
        affine_before_clip: &cairo::Matrix,
        draw_ctx: &mut DrawingCtx,
        bbox: &BoundingBox,
    ) -> Result<(), RenderingError> {
        let cascaded = node.get_cascaded_values();

        let clip_units = self.units.get();

        let cr = draw_ctx.get_cairo_context();
        let save_affine = cr.get_matrix();

        cr.set_matrix(*affine_before_clip);

        if clip_units == ClipPathUnits(CoordUnits::ObjectBoundingBox) {
            if bbox.rect.is_none() {
                // The node being clipped is empty / doesn't have a
                // bounding box, so there's nothing to clip!
                return Ok(());
            }

            let rect = bbox.rect.as_ref().unwrap();

            cr.transform(cairo::Matrix::new(rect.width, 0.0, 0.0, rect.height, rect.x, rect.y))
        }

        // here we don't push a layer because we are clipping
        let res = node.draw_children(&cascaded, draw_ctx, true);

        cr.set_matrix(save_affine);

        cr.clip();

        res
    }
}

impl NodeTrait for NodeClipPath {
    fn set_atts(&self, _: &RsvgNode, pbag: &PropertyBag<'_>) -> NodeResult {
        for (attr, value) in pbag.iter() {
            match attr {
                Attribute::ClipPathUnits => self.units.set(attr.parse(value)?),
                _ => (),
            }
        }

        Ok(())
    }
}
<|endoftext|>