<commit_before>use gl;
use glfw::{self, Context, CursorMode, SwapInterval, Window};
pub use glfw::{Action, Key, MouseButton};
use std::cell::RefCell;
use std::os::raw::c_void;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};

use camera::{Camera, Freefly};
use linear::Translation;

type Time = f64;

/// Dimension of the window to create.
#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  Fullscreen,
  FullscreenRestricted(u32, u32)
}

type Keyboard = mpsc::Receiver<(Key, Action)>;
type Mouse = mpsc::Receiver<(MouseButton, Action)>;
type MouseMove = mpsc::Receiver<[f32; 2]>;
type Scroll = mpsc::Receiver<[f32; 2]>;

/// Signals events can pass up back to their handlers to notify them how they have processed an
/// event. They’re three kinds of signals:
///
/// - `EventSig::Ignored`:  the event should be passed to other handlers the parents knows about –
///    if any – because it wasn’t handled (ignored);
///
/// - `EventSig::Handled`: the event has been correctly handled;
///
/// - `EventSig::Focused`: the event has been correctly handled, and the parent should consider that
///    the this handler has now an exclusive focus on that event;
///
/// - `EventSig::Aborted`: the event has been correctly handled and the parent handler should be
///    aborted. This signal is typically used to kill all the handlers chain and thus quit the
///    application.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventSig {
  Ignored,
  Handled,
  Focused,
  Aborted
}

/// Class of event handlers.
///
/// All functions return a special object of type `EventSig`. An event report gives information
/// about how a handler has handled the event. See the documentation of `EventSig` for further
/// information.
///
/// All functions’ implementations default to `EventSig::Ignored`.
pub trait EventHandler {
  /// Implement this function if you want to react to key strokes.
  fn on_key(&mut self, _: Key, _: Action) -> EventSig { EventSig::Ignored }
  /// Implement this function if you want to react to mouse button events.
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> EventSig { EventSig::Ignored }
  /// Implement this function if you want to react to cursor moves.
  fn on_cursor_move(&mut self, _: [f32; 2]) -> EventSig { EventSig::Ignored }
  /// Implement this function if you want to react to scroll events.
  fn on_scroll(&mut self, _: [f32; 2]) -> EventSig { EventSig::Ignored }
}

/// Empty handler.
///
/// This handler will just let pass all events without doing anything. It’s only useful for debug
/// purposes when you don’t want to bother with interaction – it doesn’t even let you close the
/// application!
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

impl EventHandler for Unhandled {}

/// Device object.
///
/// Upon bootstrapping, this type is created to add interaction and context handling.
pub struct Device {
  /// Width of the window.
  w: u32,
  /// Height of the window.
  h: u32,
  /// Some kind of epoch start the application started at.
  start_time: Instant,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
  /// Event thread join handle. Unused and keep around until death.
  #[allow(dead_code)]
  event_thread: thread::JoinHandle<()>
}

impl Device {
  /// Entry point.
  ///
  /// This function is the first one you have to call before anything else related to this crate.
  ///
  /// # Arguments
  ///
  /// - `dim`: dimension of the window to create
  /// - `title`: title to give to the window
  pub fn bootstrap(dim: WindowDim, title: &'static str) -> Self {
    info!("{} starting", title);
    info!("window mode: {:?}", dim);

    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // OpenGL hints
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
    glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));

    // open a window in windowed or fullscreen mode
    let (mut window, events, w, h) = match dim {
      WindowDim::Windowed(w, h) => {
        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
        (window, events, w, h)
      },
      WindowDim::Fullscreen => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();
          let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
          let (w, h) = (vmode.width, vmode.height);

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Fullscreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      },
      WindowDim::FullscreenRestricted(w, h) => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Fullscreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      }
    };

    deb!("opened window");

    window.make_current();

    // FIXME: use a target instead
    if cfg!(not(debug_assertions)) {
      deb!("hiding cursor");
      window.set_cursor_mode(CursorMode::Disabled);
    }

    window.set_key_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_mouse_button_polling(true);
    window.set_scroll_polling(true);
    glfw.set_swap_interval(SwapInterval::Sync(1));

    deb!("initializing OpenGL pointers");

    // init OpenGL
    gl::load_with(|s| window.get_proc_address(s) as *const c_void);

    // create channels to stream keyboard and mouse events
    let (kbd_snd, kbd_rcv) = mpsc::channel();
    let (mouse_snd, mouse_rcv) = mpsc::channel();
    let (cursor_snd, cursor_rcv) = mpsc::channel();
    let (scroll_snd, scroll_rcv) = mpsc::channel();

    deb!("spawning the event thread");
    let event_thread = thread::spawn(move || {
      loop {
        glfw.wait_events();

        for (_, event) in glfw::flush_messages(&events) {
          match event {
            glfw::WindowEvent::Key(key, _, action, _) => {
              let _ = kbd_snd.send((key, action));
            },
            glfw::WindowEvent::MouseButton(button, action, _) => {
              let _ = mouse_snd.send((button, action));
            },
            glfw::WindowEvent::CursorPos(x, y) => {
              let _ = cursor_snd.send([x as f32, y as f32]);
            },
            glfw::WindowEvent::Scroll(x, y) => {
              let _ = scroll_snd.send([x as f32, y as f32]);
            },
            _ => {},
          }
        }
      }
    });

    deb!("bootstrapping finished");

    Device {
      w: w,
      h: h,
      start_time: Instant::now(),
      kbd: kbd_rcv,
      mouse: mouse_rcv,
      cursor: cursor_rcv,
      scroll: scroll_rcv,
      window: window,
      event_thread: event_thread
    }
  }

  /// Width of the attached window.
  #[inline]
  pub fn width(&self) -> u32 {
    self.w
  }

  /// Height of the attached window.
  #[inline]
  pub fn height(&self) -> u32 {
    self.h
  }

  /// Current time, starting from the beginning of the creation of that object.
  pub fn time(&self) -> f64 {
    let elapsed = Instant::now() - self.start_time;
    elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
  }

  /// Dispatch events to a handler.
  pub fn dispatch_events<H>(&self, handler: &mut H) -> bool where H: EventHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if handler.on_key(key, action) == EventSig::Aborted {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if handler.on_mouse_button(button, action) == EventSig::Aborted {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if handler.on_cursor_move(xy) == EventSig::Aborted {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if handler.on_scroll(xy) == EventSig::Aborted {
        return false;
      }
    }

    true
  }

  /// Step function.
  ///
  /// This function provides two features:
  ///
  /// - it runs a *drawer* function, responsible of rendering a single frame, by passing it the
  ///   current time
  /// - it performs process idleing if you have requested a certain *framerate* – frame per second.
  ///
  /// The second feature is very neat because it lets you handle the scheduler off your application
  /// and then contribute to better CPU usage.
  ///
  /// > Note: if you pass `None`, no idleing will take place. However, you might be blocked by the
  /// *VSync* if enabled in your driver.
  pub fn step<FPS, R>(&mut self, fps: FPS, mut draw_frame: R) -> bool where FPS: Into<Option<u32>>, R: FnMut(Time) {
    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);
    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps.into() {
      let fps = fps as f64;
      let max_time = 1. / fps;
      let elapsed_time = self.time() - t;

      if elapsed_time < max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(Duration::from_millis((sleep_time * 1e3) as u64));
      }
    }

    true
  }
}

/// Freefly handler.
///
/// This handler is very neat as it provides freefly interaction.
pub struct FreeflyHandler {
  camera: Rc<RefCell<Camera<Freefly>>>,
  left_down: bool,
  right_down: bool,
  last_cursor: [f32; 2]
}

impl FreeflyHandler {
  pub fn new(camera: Rc<RefCell<Camera<Freefly>>>) -> Self {
    FreeflyHandler {
      camera: camera,
      left_down: false,
      right_down: false,
      last_cursor: [0., 0.]
    }
  }

  fn move_camera_on_event(&mut self, key: Key) {
    let camera = &mut self.camera.borrow_mut();

    match key {
      Key::W => camera.mv(Translation::new(0., 0., 1.)),
      Key::S => camera.mv(Translation::new(0., 0., -1.)),
      Key::A => camera.mv(Translation::new(1., 0., 0.)),
      Key::D => camera.mv(Translation::new(-1., 0., 0.)),
      Key::Q => camera.mv(Translation::new(0., -1., 0.)),
      Key::E => camera.mv(Translation::new(0., 1., 0.)),
      _ => ()
    }
  }

  fn orient_camera_on_event(&mut self, cursor: [f32; 2]) {
    let camera = &mut self.camera.borrow_mut();

    if self.left_down {
      let (dx, dy) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(dy, dx, 0.));
    } else if self.right_down {
      let (dx, _) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(0., 0., dx));
    }

    self.last_cursor = cursor;
  }
}

impl EventHandler for FreeflyHandler {
  fn on_key(&mut self, key: Key, action: Action) -> EventSig {
    match action {
      Action::Press | Action::Repeat => self.move_camera_on_event(key),
      Action::Release => if key == Key::Escape { return EventSig::Aborted }
    }

    EventSig::Handled
  }

  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> EventSig {
    match (button, action) {
      (MouseButton::Button1, Action::Press) => {
        self.left_down = true;
      },
      (MouseButton::Button1, Action::Release) => {
        self.left_down = false;
      },
      (MouseButton::Button2, Action::Press) => {
        self.right_down = true;
      },
      (MouseButton::Button2, Action::Release) => {
        self.right_down = false;
      },
      _ => ()
    }

    EventSig::Handled
  }

  fn on_cursor_move(&mut self, dir: [f32; 2]) -> EventSig {
    self.orient_camera_on_event(dir);
    EventSig::Handled
  }
}
<commit_msg>Fixed PR about Fullscreen.<commit_after>use gl;
use glfw::{self, Context, CursorMode, SwapInterval, Window};
pub use glfw::{Action, Key, MouseButton};
use std::cell::RefCell;
use std::os::raw::c_void;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};

use camera::{Camera, Freefly};
use linear::Translation;

type Time = f64;

/// Dimension of the window to create.
#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  Fullscreen,
  FullscreenRestricted(u32, u32)
}

type Keyboard = mpsc::Receiver<(Key, Action)>;
type Mouse = mpsc::Receiver<(MouseButton, Action)>;
type MouseMove = mpsc::Receiver<[f32; 2]>;
type Scroll = mpsc::Receiver<[f32; 2]>;

/// Signals events can pass up back to their handlers to notify them how they have processed an
/// event. They’re three kinds of signals:
///
/// - `EventSig::Ignored`:  the event should be passed to other handlers the parents knows about –
///    if any – because it wasn’t handled (ignored);
///
/// - `EventSig::Handled`: the event has been correctly handled;
///
/// - `EventSig::Focused`: the event has been correctly handled, and the parent should consider that
///    the this handler has now an exclusive focus on that event;
///
/// - `EventSig::Aborted`: the event has been correctly handled and the parent handler should be
///    aborted. This signal is typically used to kill all the handlers chain and thus quit the
///    application.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventSig {
  Ignored,
  Handled,
  Focused,
  Aborted
}

/// Class of event handlers.
///
/// All functions return a special object of type `EventSig`. An event report gives information
/// about how a handler has handled the event. See the documentation of `EventSig` for further
/// information.
///
/// All functions’ implementations default to `EventSig::Ignored`.
pub trait EventHandler {
  /// Implement this function if you want to react to key strokes.
  fn on_key(&mut self, _: Key, _: Action) -> EventSig { EventSig::Ignored }
  /// Implement this function if you want to react to mouse button events.
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> EventSig { EventSig::Ignored }
  /// Implement this function if you want to react to cursor moves.
  fn on_cursor_move(&mut self, _: [f32; 2]) -> EventSig { EventSig::Ignored }
  /// Implement this function if you want to react to scroll events.
  fn on_scroll(&mut self, _: [f32; 2]) -> EventSig { EventSig::Ignored }
}

/// Empty handler.
///
/// This handler will just let pass all events without doing anything. It’s only useful for debug
/// purposes when you don’t want to bother with interaction – it doesn’t even let you close the
/// application!
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

impl EventHandler for Unhandled {}

/// Device object.
///
/// Upon bootstrapping, this type is created to add interaction and context handling.
pub struct Device {
  /// Width of the window.
  w: u32,
  /// Height of the window.
  h: u32,
  /// Some kind of epoch start the application started at.
  start_time: Instant,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
  /// Event thread join handle. Unused and keep around until death.
  #[allow(dead_code)]
  event_thread: thread::JoinHandle<()>
}

impl Device {
  /// Entry point.
  ///
  /// This function is the first one you have to call before anything else related to this crate.
  ///
  /// # Arguments
  ///
  /// - `dim`: dimension of the window to create
  /// - `title`: title to give to the window
  pub fn bootstrap(dim: WindowDim, title: &'static str) -> Self {
    info!("{} starting", title);
    info!("window mode: {:?}", dim);

    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // OpenGL hints
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
    glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));

    // open a window in windowed or fullscreen mode
    let (mut window, events, w, h) = match dim {
      WindowDim::Windowed(w, h) => {
        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
        (window, events, w, h)
      },
      WindowDim::Fullscreen => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();
          let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
          let (w, h) = (vmode.width, vmode.height);

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      },
      WindowDim::FullscreenRestricted(w, h) => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      }
    };

    deb!("opened window");

    window.make_current();

    // FIXME: use a target instead
    if cfg!(not(debug_assertions)) {
      deb!("hiding cursor");
      window.set_cursor_mode(CursorMode::Disabled);
    }

    window.set_key_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_mouse_button_polling(true);
    window.set_scroll_polling(true);
    glfw.set_swap_interval(SwapInterval::Sync(1));

    deb!("initializing OpenGL pointers");

    // init OpenGL
    gl::load_with(|s| window.get_proc_address(s) as *const c_void);

    // create channels to stream keyboard and mouse events
    let (kbd_snd, kbd_rcv) = mpsc::channel();
    let (mouse_snd, mouse_rcv) = mpsc::channel();
    let (cursor_snd, cursor_rcv) = mpsc::channel();
    let (scroll_snd, scroll_rcv) = mpsc::channel();

    deb!("spawning the event thread");
    let event_thread = thread::spawn(move || {
      loop {
        glfw.wait_events();

        for (_, event) in glfw::flush_messages(&events) {
          match event {
            glfw::WindowEvent::Key(key, _, action, _) => {
              let _ = kbd_snd.send((key, action));
            },
            glfw::WindowEvent::MouseButton(button, action, _) => {
              let _ = mouse_snd.send((button, action));
            },
            glfw::WindowEvent::CursorPos(x, y) => {
              let _ = cursor_snd.send([x as f32, y as f32]);
            },
            glfw::WindowEvent::Scroll(x, y) => {
              let _ = scroll_snd.send([x as f32, y as f32]);
            },
            _ => {},
          }
        }
      }
    });

    deb!("bootstrapping finished");

    Device {
      w: w,
      h: h,
      start_time: Instant::now(),
      kbd: kbd_rcv,
      mouse: mouse_rcv,
      cursor: cursor_rcv,
      scroll: scroll_rcv,
      window: window,
      event_thread: event_thread
    }
  }

  /// Width of the attached window.
  #[inline]
  pub fn width(&self) -> u32 {
    self.w
  }

  /// Height of the attached window.
  #[inline]
  pub fn height(&self) -> u32 {
    self.h
  }

  /// Current time, starting from the beginning of the creation of that object.
  pub fn time(&self) -> f64 {
    let elapsed = Instant::now() - self.start_time;
    elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
  }

  /// Dispatch events to a handler.
  pub fn dispatch_events<H>(&self, handler: &mut H) -> bool where H: EventHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if handler.on_key(key, action) == EventSig::Aborted {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if handler.on_mouse_button(button, action) == EventSig::Aborted {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if handler.on_cursor_move(xy) == EventSig::Aborted {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if handler.on_scroll(xy) == EventSig::Aborted {
        return false;
      }
    }

    true
  }

  /// Step function.
  ///
  /// This function provides two features:
  ///
  /// - it runs a *drawer* function, responsible of rendering a single frame, by passing it the
  ///   current time
  /// - it performs process idleing if you have requested a certain *framerate* – frame per second.
  ///
  /// The second feature is very neat because it lets you handle the scheduler off your application
  /// and then contribute to better CPU usage.
  ///
  /// > Note: if you pass `None`, no idleing will take place. However, you might be blocked by the
  /// *VSync* if enabled in your driver.
  pub fn step<FPS, R>(&mut self, fps: FPS, mut draw_frame: R) -> bool where FPS: Into<Option<u32>>, R: FnMut(Time) {
    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);
    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps.into() {
      let fps = fps as f64;
      let max_time = 1. / fps;
      let elapsed_time = self.time() - t;

      if elapsed_time < max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(Duration::from_millis((sleep_time * 1e3) as u64));
      }
    }

    true
  }
}

/// Freefly handler.
///
/// This handler is very neat as it provides freefly interaction.
pub struct FreeflyHandler {
  camera: Rc<RefCell<Camera<Freefly>>>,
  left_down: bool,
  right_down: bool,
  last_cursor: [f32; 2]
}

impl FreeflyHandler {
  pub fn new(camera: Rc<RefCell<Camera<Freefly>>>) -> Self {
    FreeflyHandler {
      camera: camera,
      left_down: false,
      right_down: false,
      last_cursor: [0., 0.]
    }
  }

  fn move_camera_on_event(&mut self, key: Key) {
    let camera = &mut self.camera.borrow_mut();

    match key {
      Key::W => camera.mv(Translation::new(0., 0., 1.)),
      Key::S => camera.mv(Translation::new(0., 0., -1.)),
      Key::A => camera.mv(Translation::new(1., 0., 0.)),
      Key::D => camera.mv(Translation::new(-1., 0., 0.)),
      Key::Q => camera.mv(Translation::new(0., -1., 0.)),
      Key::E => camera.mv(Translation::new(0., 1., 0.)),
      _ => ()
    }
  }

  fn orient_camera_on_event(&mut self, cursor: [f32; 2]) {
    let camera = &mut self.camera.borrow_mut();

    if self.left_down {
      let (dx, dy) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(dy, dx, 0.));
    } else if self.right_down {
      let (dx, _) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(0., 0., dx));
    }

    self.last_cursor = cursor;
  }
}

impl EventHandler for FreeflyHandler {
  fn on_key(&mut self, key: Key, action: Action) -> EventSig {
    match action {
      Action::Press | Action::Repeat => self.move_camera_on_event(key),
      Action::Release => if key == Key::Escape { return EventSig::Aborted }
    }

    EventSig::Handled
  }

  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> EventSig {
    match (button, action) {
      (MouseButton::Button1, Action::Press) => {
        self.left_down = true;
      },
      (MouseButton::Button1, Action::Release) => {
        self.left_down = false;
      },
      (MouseButton::Button2, Action::Press) => {
        self.right_down = true;
      },
      (MouseButton::Button2, Action::Release) => {
        self.right_down = false;
      },
      _ => ()
    }

    EventSig::Handled
  }

  fn on_cursor_move(&mut self, dir: [f32; 2]) -> EventSig {
    self.orient_camera_on_event(dir);
    EventSig::Handled
  }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

use registry::{Registry, Ns};
use std::io;

#[allow(missing_copy_implementations)]
pub struct DebugStructGenerator;

impl super::Generator for DebugStructGenerator {
    fn write<W>(&self, registry: &Registry, ns: Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
        try!(write_header(dest));
        try!(write_type_aliases(&ns, dest));
        try!(write_enums(registry, dest));
        try!(write_fnptr_struct_def(dest));
        try!(write_panicking_fns(&ns, dest));
        try!(write_struct(registry, &ns, dest));
        try!(write_impl(registry, &ns, dest));
        Ok(())
    }
}

/// Creates a `__gl_imports` module which contains all the external symbols that we need for the
///  bindings.
fn write_header<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        mod __gl_imports {{
            extern crate gl_common;
            extern crate libc;
            pub use std::mem;
            pub use std::marker::Send;
        }}
    "#)
}

/// Creates a `types` module which contains all the type aliases.
///
/// See also `generators::gen_type_aliases`.
fn write_type_aliases<W>(ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        pub mod types {{
            #![allow(non_camel_case_types)]
            #![allow(non_snake_case)]
            #![allow(dead_code)]
            #![allow(missing_copy_implementations)]
    "#));

    try!(super::gen_type_aliases(ns, dest));

    writeln!(dest, "}}")
}

/// Creates all the `<enum>` elements at the root of the bindings.
fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    for e in registry.enum_iter() {
        try!(super::gen_enum_item(e, "types::", dest));
    }

    Ok(())
}

/// Creates a `FnPtr` structure which contains the store for a single binding.
fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, "
        #[allow(dead_code)]
        #[allow(missing_copy_implementations)]
        #[allow(raw_pointer_derive)]
        #[derive(Clone)]
        pub struct FnPtr {{
            /// The function pointer that will be used when calling the function.
            f: *const __gl_imports::libc::c_void,
            /// True if the pointer points to a real function, false if points to a `panic!` fn.
            is_loaded: bool,
        }}

        impl FnPtr {{
            /// Creates a `FnPtr` from a load attempt.
            fn new(ptr: *const __gl_imports::libc::c_void) -> FnPtr {{
                if ptr.is_null() {{
                    FnPtr {{
                        f: missing_fn_panic as *const __gl_imports::libc::c_void,
                        is_loaded: false
                    }}
                }} else {{
                    FnPtr {{ f: ptr, is_loaded: true }}
                }}
            }}

            /// Returns `true` if the function has been successfully loaded.
            ///
            /// If it returns `false`, calling the corresponding function will fail.
            #[inline]
            #[allow(dead_code)]
            pub fn is_loaded(&self) -> bool {{
                self.is_loaded
            }}
        }}
    ")
}

/// Creates a `panicking` module which contains one function per GL command.
///
/// These functions are the mocks that are called if the real function could not be loaded.
fn write_panicking_fns<W>(ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest,
        "#[inline(never)]
        fn missing_fn_panic() -> ! {{
            panic!(\"{ns} function was not loaded\")
        }}",
        ns = ns
    )
}

/// Creates a structure which stores all the `FnPtr` of the bindings.
///
/// The name of the struct corresponds to the namespace.
fn write_struct<W>(registry: &Registry, ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, "
        #[allow(non_camel_case_types)]
        #[allow(non_snake_case)]
        #[allow(dead_code)]
        #[derive(Clone)]
        pub struct {ns} {{",
        ns = ns.fmt_struct_name()
    ));

    for c in registry.cmd_iter() {
        if let Some(v) = registry.aliases.get(&c.proto.ident) {
            try!(writeln!(dest, "/// Fallbacks: {}", v.connect(", ")));
        }
        try!(writeln!(dest, "pub {name}: FnPtr,", name = c.proto.ident));
    }

    writeln!(dest, "}}")
}

/// Creates the `impl` of the structure created by `write_struct`.
fn write_impl<W>(registry: &Registry, ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest,
        "impl {ns} {{
            /// Load each OpenGL symbol using a custom load function. This allows for the
            /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
            ///
            /// ~~~ignore
            /// let gl = Gl::load_with(|s| glfw.get_proc_address(s));
            /// ~~~
            #[allow(dead_code)]
            #[allow(unused_variables)]
            pub fn load_with<F>(mut loadfn: F) -> {ns} where F: FnMut(&str) -> *const __gl_imports::libc::c_void {{
                let mut metaloadfn = |symbol: &str, symbols: &[&str]| {{
                    let mut ptr = loadfn(symbol);
                    if ptr.is_null() {{
                        for &sym in symbols.iter() {{
                            ptr = loadfn(sym);
                            if !ptr.is_null() {{ break; }}
                        }}
                    }}
                    ptr
                }};
                {ns} {{",
        ns = ns.fmt_struct_name()
    ));

    for c in registry.cmd_iter() {
        try!(writeln!(dest,
            "{name}: FnPtr::new(metaloadfn(\"{symbol}\", &[{fallbacks}])),",
            name = c.proto.ident,
            symbol = super::gen_symbol_name(ns, &c.proto.ident),
            fallbacks = match registry.aliases.get(&c.proto.ident) {
                Some(fbs) => {
                    fbs.iter()
                       .map(|name| format!("\"{}\"", super::gen_symbol_name(ns, &name)))
                       .collect::<Vec<_>>().connect(", ")
                },
                None => format!(""),
            },
        ))
    }

    try!(writeln!(dest,
            "}}
        }}

        /// Load each OpenGL symbol using a custom load function.
        ///
        /// ~~~ignore
        /// let gl = Gl::load(&glfw);
        /// ~~~
        #[allow(dead_code)]
        #[allow(unused_variables)]
        pub fn load<T: __gl_imports::gl_common::GlFunctionsSource>(loader: &T) -> {ns} {{
            {ns}::load_with(|name| loader.get_proc_addr(name))
        }}",
        ns = ns.fmt_struct_name()
    ));

    for c in registry.cmd_iter() {
        let idents = super::gen_parameters(c, true, false);
        let typed_params = super::gen_parameters(c, false, true);
        let println = format!("println!(\"[OpenGL] {}({})\" {});",
                                c.proto.ident,
                                (0 .. idents.len()).map(|_| "{:?}".to_string()).collect::<Vec<_>>().connect(", "),
                                idents.iter().zip(typed_params.iter())
                                      .map(|(name, ty)| {
                                          if ty.contains("GLDEBUGPROC") {
                                              format!(", \"<callback>\"")
                                          } else {
                                              format!(", {}", name)
                                          }
                                      }).collect::<Vec<_>>().concat());

        try!(writeln!(dest,
            "#[allow(non_snake_case)] #[allow(unused_variables)] #[allow(dead_code)]
            #[inline] pub unsafe fn {name}(&self, {params}) -> {return_suffix} {{ \
                {println}
                __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\
                    (self.{name}.f)({idents}) \
            }}",
            name = c.proto.ident,
            params = super::gen_parameters(c, true, true).connect(", "),
            typed_params = typed_params.connect(", "),
            return_suffix = super::gen_return_type(c),
            idents = idents.connect(", "),
            println = println
        ))
    }

    writeln!(dest,
        "}}

        unsafe impl __gl_imports::Send for {ns} {{}}",
        ns = ns.fmt_struct_name()
    )
}
<commit_msg>The DebugStructGenerator now calls glGetError after each call<commit_after>// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

use registry::{Registry, Ns};
use std::io;

#[allow(missing_copy_implementations)]
pub struct DebugStructGenerator;

impl super::Generator for DebugStructGenerator {
    fn write<W>(&self, registry: &Registry, ns: Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
        try!(write_header(dest));
        try!(write_type_aliases(&ns, dest));
        try!(write_enums(registry, dest));
        try!(write_fnptr_struct_def(dest));
        try!(write_panicking_fns(&ns, dest));
        try!(write_struct(registry, &ns, dest));
        try!(write_impl(registry, &ns, dest));
        Ok(())
    }
}

/// Creates a `__gl_imports` module which contains all the external symbols that we need for the
///  bindings.
fn write_header<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        mod __gl_imports {{
            extern crate gl_common;
            extern crate libc;
            pub use std::mem;
            pub use std::marker::Send;
        }}
    "#)
}

/// Creates a `types` module which contains all the type aliases.
///
/// See also `generators::gen_type_aliases`.
fn write_type_aliases<W>(ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        pub mod types {{
            #![allow(non_camel_case_types)]
            #![allow(non_snake_case)]
            #![allow(dead_code)]
            #![allow(missing_copy_implementations)]
    "#));

    try!(super::gen_type_aliases(ns, dest));

    writeln!(dest, "}}")
}

/// Creates all the `<enum>` elements at the root of the bindings.
fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    for e in registry.enum_iter() {
        try!(super::gen_enum_item(e, "types::", dest));
    }

    Ok(())
}

/// Creates a `FnPtr` structure which contains the store for a single binding.
fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, "
        #[allow(dead_code)]
        #[allow(missing_copy_implementations)]
        #[allow(raw_pointer_derive)]
        #[derive(Clone)]
        pub struct FnPtr {{
            /// The function pointer that will be used when calling the function.
            f: *const __gl_imports::libc::c_void,
            /// True if the pointer points to a real function, false if points to a `panic!` fn.
            is_loaded: bool,
        }}

        impl FnPtr {{
            /// Creates a `FnPtr` from a load attempt.
            fn new(ptr: *const __gl_imports::libc::c_void) -> FnPtr {{
                if ptr.is_null() {{
                    FnPtr {{
                        f: missing_fn_panic as *const __gl_imports::libc::c_void,
                        is_loaded: false
                    }}
                }} else {{
                    FnPtr {{ f: ptr, is_loaded: true }}
                }}
            }}

            /// Returns `true` if the function has been successfully loaded.
            ///
            /// If it returns `false`, calling the corresponding function will fail.
            #[inline]
            #[allow(dead_code)]
            pub fn is_loaded(&self) -> bool {{
                self.is_loaded
            }}
        }}
    ")
}

/// Creates a `panicking` module which contains one function per GL command.
///
/// These functions are the mocks that are called if the real function could not be loaded.
fn write_panicking_fns<W>(ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest,
        "#[inline(never)]
        fn missing_fn_panic() -> ! {{
            panic!(\"{ns} function was not loaded\")
        }}",
        ns = ns
    )
}

/// Creates a structure which stores all the `FnPtr` of the bindings.
///
/// The name of the struct corresponds to the namespace.
fn write_struct<W>(registry: &Registry, ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, "
        #[allow(non_camel_case_types)]
        #[allow(non_snake_case)]
        #[allow(dead_code)]
        #[derive(Clone)]
        pub struct {ns} {{",
        ns = ns.fmt_struct_name()
    ));

    for c in registry.cmd_iter() {
        if let Some(v) = registry.aliases.get(&c.proto.ident) {
            try!(writeln!(dest, "/// Fallbacks: {}", v.connect(", ")));
        }
        try!(writeln!(dest, "pub {name}: FnPtr,", name = c.proto.ident));
    }

    writeln!(dest, "}}")
}

/// Creates the `impl` of the structure created by `write_struct`.
fn write_impl<W>(registry: &Registry, ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest,
        "impl {ns} {{
            /// Load each OpenGL symbol using a custom load function. This allows for the
            /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
            ///
            /// ~~~ignore
            /// let gl = Gl::load_with(|s| glfw.get_proc_address(s));
            /// ~~~
            #[allow(dead_code)]
            #[allow(unused_variables)]
            pub fn load_with<F>(mut loadfn: F) -> {ns} where F: FnMut(&str) -> *const __gl_imports::libc::c_void {{
                let mut metaloadfn = |symbol: &str, symbols: &[&str]| {{
                    let mut ptr = loadfn(symbol);
                    if ptr.is_null() {{
                        for &sym in symbols.iter() {{
                            ptr = loadfn(sym);
                            if !ptr.is_null() {{ break; }}
                        }}
                    }}
                    ptr
                }};
                {ns} {{",
        ns = ns.fmt_struct_name()
    ));

    for c in registry.cmd_iter() {
        try!(writeln!(dest,
            "{name}: FnPtr::new(metaloadfn(\"{symbol}\", &[{fallbacks}])),",
            name = c.proto.ident,
            symbol = super::gen_symbol_name(ns, &c.proto.ident),
            fallbacks = match registry.aliases.get(&c.proto.ident) {
                Some(fbs) => {
                    fbs.iter()
                       .map(|name| format!("\"{}\"", super::gen_symbol_name(ns, &name)))
                       .collect::<Vec<_>>().connect(", ")
                },
                None => format!(""),
            },
        ))
    }

    try!(writeln!(dest,
            "}}
        }}

        /// Load each OpenGL symbol using a custom load function.
        ///
        /// ~~~ignore
        /// let gl = Gl::load(&glfw);
        /// ~~~
        #[allow(dead_code)]
        #[allow(unused_variables)]
        pub fn load<T: __gl_imports::gl_common::GlFunctionsSource>(loader: &T) -> {ns} {{
            {ns}::load_with(|name| loader.get_proc_addr(name))
        }}",
        ns = ns.fmt_struct_name()
    ));

    for c in registry.cmd_iter() {
        let idents = super::gen_parameters(c, true, false);
        let typed_params = super::gen_parameters(c, false, true);
        let println = format!("println!(\"[OpenGL] {}({})\" {});",
                                c.proto.ident,
                                (0 .. idents.len()).map(|_| "{:?}".to_string()).collect::<Vec<_>>().connect(", "),
                                idents.iter().zip(typed_params.iter())
                                      .map(|(name, ty)| {
                                          if ty.contains("GLDEBUGPROC") {
                                              format!(", \"<callback>\"")
                                          } else {
                                              format!(", {}", name)
                                          }
                                      }).collect::<Vec<_>>().concat());

        try!(writeln!(dest,
            "#[allow(non_snake_case)] #[allow(unused_variables)] #[allow(dead_code)]
            #[inline] pub unsafe fn {name}(&self, {params}) -> {return_suffix} {{ \
                {println}
                let r = __gl_imports::mem::transmute::<_, extern \"system\" fn({typed_params}) -> {return_suffix}>\
                    (self.{name}.f)({idents});
                {print_err}
                r
            }}",
            name = c.proto.ident,
            params = super::gen_parameters(c, true, true).connect(", "),
            typed_params = typed_params.connect(", "),
            return_suffix = super::gen_return_type(c),
            idents = idents.connect(", "),
            println = println,
            print_err = if c.proto.ident != "GetError" && registry.cmd_iter().find(|c| c.proto.ident == "GetError").is_some() {
                format!(r#"match __gl_imports::mem::transmute::<_, extern "system" fn() -> u32>
                    (self.GetError.f)() {{ 0 => (), r => println!("[OpenGL] ^ GL error triggered: {{}}", r) }}"#)
            } else {
                format!("")
            }
        ))
    }

    writeln!(dest,
        "}}

        unsafe impl __gl_imports::Send for {ns} {{}}",
        ns = ns.fmt_struct_name()
    )
}
<|endoftext|>


<commit_before>/// Epoch-based garbage collector.
///
/// # Examples
///
/// ```
/// use crossbeam_epoch::Collector;
///
/// let collector = Collector::new();
///
/// let handle = collector.handle();
/// drop(collector); // `handle` still works after dropping `collector`
///
/// handle.pin(|scope| {
///     scope.flush();
/// });
/// ```

use std::sync::Arc;
use internal::{Global, Local};
use scope::Scope;

/// An epoch-based garbage collector.
pub struct Collector(Arc<Global>);

/// A handle to a garbage collector.
pub struct Handle {
    global: Arc<Global>,
    local: Local,
}

impl Collector {
    /// Creates a new collector.
    pub fn new() -> Self {
        Self { 0: Arc::new(Global::new()) }
    }

    /// Creates a new handle for the collector.
    #[inline]
    pub fn handle(&self) -> Handle {
        Handle::new(self.0.clone())
    }
}

impl Handle {
    fn new(global: Arc<Global>) -> Self {
        let local = Local::new(&global);
        Self { global, local }
    }

    /// Pin the current handle.
    #[inline]
    pub fn pin<F, R>(&self, f: F) -> R
    where
        F: FnOnce(&Scope) -> R,
    {
        unsafe { self.local.pin(&self.global, f) }
    }

    /// Check if the current handle is pinned.
    #[inline]
    pub fn is_pinned(&self) -> bool {
        self.local.is_pinned()
    }
}

impl Drop for Handle {
    fn drop(&mut self) {
        unsafe { self.local.unregister(&self.global) }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
    use std::sync::atomic::Ordering;
    use crossbeam_utils::scoped;

    use {Collector, Owned};

    const NUM_THREADS: usize = 8;

    #[test]
    fn pin_reentrant() {
        let collector = Collector::new();
        let handle = collector.handle();
        drop(collector);

        assert!(!handle.is_pinned());
        handle.pin(|_| {
            assert!(handle.is_pinned());
            handle.pin(|_| {
                assert!(handle.is_pinned());
            });
            assert!(handle.is_pinned());
        });
        assert!(!handle.is_pinned());
    }

    #[test]
    fn flush_local_bag() {
        let collector = Collector::new();
        let handle = collector.handle();
        drop(collector);

        for _ in 0..100 {
            handle.pin(|scope| unsafe {
                let a = Owned::new(7).into_ptr(scope);
                scope.defer(move || a.into_owned());

                assert!(!(*scope.bag).is_empty());

                while !(*scope.bag).is_empty() {
                    scope.flush();
                }
            });
        }
    }

    #[test]
    fn garbage_buffering() {
        let collector = Collector::new();
        let handle = collector.handle();
        drop(collector);

        handle.pin(|scope| unsafe {
            for _ in 0..10 {
                let a = Owned::new(7).into_ptr(scope);
                scope.defer(move || a.into_owned());
            }
            assert!(!(*scope.bag).is_empty());
        });
    }

    #[test]
    fn pin_holds_advance() {
        let collector = Collector::new();

        let threads = (0..NUM_THREADS)
            .map(|_| {
                scoped::scope(|scope| {
                    scope.spawn(|| {
                        let handle = collector.handle();
                        for _ in 0..500_000 {
                            handle.pin(|scope| {
                                let before = collector.0.get_epoch();
                                collector.0.collect(scope);
                                let after = collector.0.get_epoch();

                                assert!(after.wrapping_sub(before) <= 2);
                            });
                        }
                    })
                })
            })
            .collect::<Vec<_>>();
        drop(collector);

        for t in threads {
            t.join();
        }
    }

    #[test]
    fn incremental() {
        const COUNT: usize = 100_000;
        static DESTROYS: AtomicUsize = ATOMIC_USIZE_INIT;

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            for _ in 0..COUNT {
                let a = Owned::new(7i32).into_ptr(scope);
                scope.defer(move || {
                    drop(a.into_owned());
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
                });
            }
            scope.flush();
        });

        let mut last = 0;

        while last < COUNT {
            let curr = DESTROYS.load(Ordering::Relaxed);
            assert!(curr - last <= 1024);
            last = curr;

            handle.pin(|scope| collector.0.collect(scope));
        }
        assert!(DESTROYS.load(Ordering::Relaxed) == 100_000);
    }

    #[test]
    fn buffering() {
        const COUNT: usize = 10;
        static DESTROYS: AtomicUsize = ATOMIC_USIZE_INIT;

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            for _ in 0..COUNT {
                let a = Owned::new(7i32).into_ptr(scope);
                scope.defer(move || {
                    drop(a.into_owned());
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
                });
            }
        });

        for _ in 0..100_000 {
            handle.pin(|scope| { collector.0.collect(scope); });
        }
        assert!(DESTROYS.load(Ordering::Relaxed) < COUNT);

        handle.pin(|scope| scope.flush());

        while DESTROYS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn count_drops() {
        const COUNT: usize = 100_000;
        static DROPS: AtomicUsize = ATOMIC_USIZE_INIT;

        struct Elem(i32);

        impl Drop for Elem {
            fn drop(&mut self) {
                DROPS.fetch_add(1, Ordering::Relaxed);
            }
        }

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            for _ in 0..COUNT {
                let a = Owned::new(Elem(7i32)).into_ptr(scope);
                scope.defer(move || a.into_owned());
            }
            scope.flush();
        });

        while DROPS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn count_destroy() {
        const COUNT: usize = 100_000;
        static DESTROYS: AtomicUsize = ATOMIC_USIZE_INIT;

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            for _ in 0..COUNT {
                let a = Owned::new(7i32).into_ptr(scope);
                scope.defer(move || {
                    drop(a.into_owned());
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
                });
            }
            scope.flush();
        });

        while DESTROYS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn drop_array() {
        const COUNT: usize = 700;
        static DROPS: AtomicUsize = ATOMIC_USIZE_INIT;

        struct Elem(i32);

        impl Drop for Elem {
            fn drop(&mut self) {
                DROPS.fetch_add(1, Ordering::Relaxed);
            }
        }

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            let mut v = Vec::with_capacity(COUNT);
            for i in 0..COUNT {
                v.push(Elem(i as i32));
            }

            let a = Owned::new(v).into_ptr(scope);
            scope.defer(move || a.into_owned());
            scope.flush();
        });

        while DROPS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn destroy_array() {
        const COUNT: usize = 100_000;
        static DESTROYS: AtomicUsize = ATOMIC_USIZE_INIT;

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            let mut v = Vec::with_capacity(COUNT);
            for i in 0..COUNT {
                v.push(i as i32);
            }

            let ptr = v.as_mut_ptr() as usize;
            let len = v.len();
            scope.defer(move || {
                drop(Vec::from_raw_parts(ptr as *const u8 as *mut u8, len, len));
                DESTROYS.fetch_add(len, Ordering::Relaxed);
            });
            scope.flush();

            mem::forget(v);
        });

        while DESTROYS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn stress() {
        const THREADS: usize = 8;
        const COUNT: usize = 100_000;
        static DROPS: AtomicUsize = ATOMIC_USIZE_INIT;

        struct Elem(i32);

        impl Drop for Elem {
            fn drop(&mut self) {
                DROPS.fetch_add(1, Ordering::Relaxed);
            }
        }

        let collector = Collector::new();

        let threads = (0..THREADS)
            .map(|_| {
                scoped::scope(|scope| {
                    scope.spawn(|| {
                        let handle = collector.handle();
                        for _ in 0..COUNT {
                            handle.pin(|scope| unsafe {
                                let a = Owned::new(Elem(7i32)).into_ptr(scope);
                                scope.defer(move || a.into_owned());
                            });
                        }
                    })
                })
            })
            .collect::<Vec<_>>();

        for t in threads {
            t.join();
        }

        let handle = collector.handle();
        while DROPS.load(Ordering::Relaxed) < COUNT * THREADS {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT * THREADS);
    }
}
<commit_msg>Implement Handle::clone() (#26)<commit_after>/// Epoch-based garbage collector.
///
/// # Examples
///
/// ```
/// use crossbeam_epoch::Collector;
///
/// let collector = Collector::new();
///
/// let handle = collector.handle();
/// drop(collector); // `handle` still works after dropping `collector`
///
/// handle.pin(|scope| {
///     scope.flush();
/// });
/// ```

use std::sync::Arc;
use internal::{Global, Local};
use scope::Scope;

/// An epoch-based garbage collector.
pub struct Collector(Arc<Global>);

/// A handle to a garbage collector.
pub struct Handle {
    global: Arc<Global>,
    local: Local,
}

impl Collector {
    /// Creates a new collector.
    pub fn new() -> Self {
        Self { 0: Arc::new(Global::new()) }
    }

    /// Creates a new handle for the collector.
    #[inline]
    pub fn handle(&self) -> Handle {
        Handle::new(self.0.clone())
    }
}

impl Handle {
    fn new(global: Arc<Global>) -> Self {
        let local = Local::new(&global);
        Self { global, local }
    }

    /// Pin the current handle.
    #[inline]
    pub fn pin<F, R>(&self, f: F) -> R
    where
        F: FnOnce(&Scope) -> R,
    {
        unsafe { self.local.pin(&self.global, f) }
    }

    /// Check if the current handle is pinned.
    #[inline]
    pub fn is_pinned(&self) -> bool {
        self.local.is_pinned()
    }
}

impl Clone for Handle {
    fn clone(&self) -> Self {
        Self::new(self.global.clone())
    }
}

unsafe impl Send for Handle {}

impl Drop for Handle {
    fn drop(&mut self) {
        unsafe { self.local.unregister(&self.global) }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
    use std::sync::atomic::Ordering;
    use crossbeam_utils::scoped;

    use {Collector, Owned};

    const NUM_THREADS: usize = 8;

    #[test]
    fn pin_reentrant() {
        let collector = Collector::new();
        let handle = collector.handle();
        drop(collector);

        assert!(!handle.is_pinned());
        handle.pin(|_| {
            assert!(handle.is_pinned());
            handle.pin(|_| {
                assert!(handle.is_pinned());
            });
            assert!(handle.is_pinned());
        });
        assert!(!handle.is_pinned());
    }

    #[test]
    fn flush_local_bag() {
        let collector = Collector::new();
        let handle = collector.handle();
        drop(collector);

        for _ in 0..100 {
            handle.pin(|scope| unsafe {
                let a = Owned::new(7).into_ptr(scope);
                scope.defer(move || a.into_owned());

                assert!(!(*scope.bag).is_empty());

                while !(*scope.bag).is_empty() {
                    scope.flush();
                }
            });
        }
    }

    #[test]
    fn garbage_buffering() {
        let collector = Collector::new();
        let handle = collector.handle();
        drop(collector);

        handle.pin(|scope| unsafe {
            for _ in 0..10 {
                let a = Owned::new(7).into_ptr(scope);
                scope.defer(move || a.into_owned());
            }
            assert!(!(*scope.bag).is_empty());
        });
    }

    #[test]
    fn pin_holds_advance() {
        let collector = Collector::new();

        let threads = (0..NUM_THREADS)
            .map(|_| {
                scoped::scope(|scope| {
                    scope.spawn(|| {
                        let handle = collector.handle();
                        for _ in 0..500_000 {
                            handle.pin(|scope| {
                                let before = collector.0.get_epoch();
                                collector.0.collect(scope);
                                let after = collector.0.get_epoch();

                                assert!(after.wrapping_sub(before) <= 2);
                            });
                        }
                    })
                })
            })
            .collect::<Vec<_>>();
        drop(collector);

        for t in threads {
            t.join();
        }
    }

    #[test]
    fn incremental() {
        const COUNT: usize = 100_000;
        static DESTROYS: AtomicUsize = ATOMIC_USIZE_INIT;

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            for _ in 0..COUNT {
                let a = Owned::new(7i32).into_ptr(scope);
                scope.defer(move || {
                    drop(a.into_owned());
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
                });
            }
            scope.flush();
        });

        let mut last = 0;

        while last < COUNT {
            let curr = DESTROYS.load(Ordering::Relaxed);
            assert!(curr - last <= 1024);
            last = curr;

            handle.pin(|scope| collector.0.collect(scope));
        }
        assert!(DESTROYS.load(Ordering::Relaxed) == 100_000);
    }

    #[test]
    fn buffering() {
        const COUNT: usize = 10;
        static DESTROYS: AtomicUsize = ATOMIC_USIZE_INIT;

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            for _ in 0..COUNT {
                let a = Owned::new(7i32).into_ptr(scope);
                scope.defer(move || {
                    drop(a.into_owned());
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
                });
            }
        });

        for _ in 0..100_000 {
            handle.pin(|scope| { collector.0.collect(scope); });
        }
        assert!(DESTROYS.load(Ordering::Relaxed) < COUNT);

        handle.pin(|scope| scope.flush());

        while DESTROYS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn count_drops() {
        const COUNT: usize = 100_000;
        static DROPS: AtomicUsize = ATOMIC_USIZE_INIT;

        struct Elem(i32);

        impl Drop for Elem {
            fn drop(&mut self) {
                DROPS.fetch_add(1, Ordering::Relaxed);
            }
        }

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            for _ in 0..COUNT {
                let a = Owned::new(Elem(7i32)).into_ptr(scope);
                scope.defer(move || a.into_owned());
            }
            scope.flush();
        });

        while DROPS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn count_destroy() {
        const COUNT: usize = 100_000;
        static DESTROYS: AtomicUsize = ATOMIC_USIZE_INIT;

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            for _ in 0..COUNT {
                let a = Owned::new(7i32).into_ptr(scope);
                scope.defer(move || {
                    drop(a.into_owned());
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
                });
            }
            scope.flush();
        });

        while DESTROYS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn drop_array() {
        const COUNT: usize = 700;
        static DROPS: AtomicUsize = ATOMIC_USIZE_INIT;

        struct Elem(i32);

        impl Drop for Elem {
            fn drop(&mut self) {
                DROPS.fetch_add(1, Ordering::Relaxed);
            }
        }

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            let mut v = Vec::with_capacity(COUNT);
            for i in 0..COUNT {
                v.push(Elem(i as i32));
            }

            let a = Owned::new(v).into_ptr(scope);
            scope.defer(move || a.into_owned());
            scope.flush();
        });

        while DROPS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn destroy_array() {
        const COUNT: usize = 100_000;
        static DESTROYS: AtomicUsize = ATOMIC_USIZE_INIT;

        let collector = Collector::new();
        let handle = collector.handle();

        handle.pin(|scope| unsafe {
            let mut v = Vec::with_capacity(COUNT);
            for i in 0..COUNT {
                v.push(i as i32);
            }

            let ptr = v.as_mut_ptr() as usize;
            let len = v.len();
            scope.defer(move || {
                drop(Vec::from_raw_parts(ptr as *const u8 as *mut u8, len, len));
                DESTROYS.fetch_add(len, Ordering::Relaxed);
            });
            scope.flush();

            mem::forget(v);
        });

        while DESTROYS.load(Ordering::Relaxed) < COUNT {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
    }

    #[test]
    fn stress() {
        const THREADS: usize = 8;
        const COUNT: usize = 100_000;
        static DROPS: AtomicUsize = ATOMIC_USIZE_INIT;

        struct Elem(i32);

        impl Drop for Elem {
            fn drop(&mut self) {
                DROPS.fetch_add(1, Ordering::Relaxed);
            }
        }

        let collector = Collector::new();

        let threads = (0..THREADS)
            .map(|_| {
                scoped::scope(|scope| {
                    scope.spawn(|| {
                        let handle = collector.handle();
                        for _ in 0..COUNT {
                            handle.pin(|scope| unsafe {
                                let a = Owned::new(Elem(7i32)).into_ptr(scope);
                                scope.defer(move || a.into_owned());
                            });
                        }
                    })
                })
            })
            .collect::<Vec<_>>();

        for t in threads {
            t.join();
        }

        let handle = collector.handle();
        while DROPS.load(Ordering::Relaxed) < COUNT * THREADS {
            handle.pin(|scope| collector.0.collect(scope));
        }
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT * THREADS);
    }

    #[test]
    fn send_handle() {
        let ref collector = Collector::new();
        let handle_global = collector.handle();

        let threads = (0..NUM_THREADS)
            .map(|_| {
                scoped::scope(|scope| {
                    let handle = handle_global.clone();
                    scope.spawn(move || handle.pin(|scope| scope.flush()))
                })
            })
            .collect::<Vec<_>>();
        drop(collector);

        for t in threads {
            t.join();
        }
    }
}
<|endoftext|>


<commit_before>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

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

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("mkdir -p path_name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");

    println!("cd {path_name}");

    env::set_current_dir(&path_name).expect("changing directory failed");

    let app_name = format!("{program_name}-{program_type}");
    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    println!("cd {folder_name}");

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let git_rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    if git_rev_list_output.status.success() {
        let git_rev_list_output_cow =
            String::from_utf8_lossy(&git_rev_list_output.stdout).to_string();

        for (i, commit_hash) in git_rev_list_output_cow.split("\n").enumerate() {
            println!("i: {i}");
            if !commit_hash.is_empty() {
                println!("git checkout {commit_hash}");

                let git_checkout_output = Command::new("git")
                    .arg("checkout")
                    .arg(commit_hash)
                    .output()
                    .expect("checkout failed");

                if git_checkout_output.status.success() {
                    println!(
                        "git checkout stdout: {}",
                        String::from_utf8(git_checkout_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git checkout stderr: {}",
                        String::from_utf8(git_checkout_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                println!("git show");

                let git_show_output = Command::new("git")
                    .arg("show")
                    .output()
                    .expect("show failed");

                if git_show_output.status.success() {
                    println!(
                        "git show stdout: {}",
                        String::from_utf8(git_show_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git show stderr: {}",
                        String::from_utf8(git_show_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                let mut path = env::current_dir().expect("getting current directory failed");
                path.push(&app_name);
                let metadata = fs::metadata(path);
                match metadata {
                    Ok(_) => {
                        println!("{app_name} found");
                    }
                    Err(_) => {
                        println!("{app_name} not found");
                        continue;
                    }
                };

                println!("cd {app_name}");

                env::set_current_dir(&app_name).expect("changing directory failed");

                println!("cargo test");

                let cargo_test_output = Command::new("cargo")
                    .arg("test")
                    .output()
                    .expect("test failed");

                if cargo_test_output.status.success() {
                    println!(
                        "cargo test stdout: {}",
                        String::from_utf8(cargo_test_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "cargo test stderr: {}",
                        String::from_utf8(cargo_test_output.stderr).unwrap()
                    );

                    process::exit(1);
                }
            }
        }

        println!(
            "rev-list stdout: {}",
            String::from_utf8(git_rev_list_output.stdout).unwrap()
        );
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8(git_rev_list_output.stderr).unwrap()
        );

        process::exit(1);
    }
}
<commit_msg>going back to the parent folder after running test<commit_after>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

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

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("mkdir -p path_name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");

    println!("cd {path_name}");

    env::set_current_dir(&path_name).expect("changing directory failed");

    let app_name = format!("{program_name}-{program_type}");
    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    println!("cd {folder_name}");

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let git_rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    if git_rev_list_output.status.success() {
        let git_rev_list_output_cow =
            String::from_utf8_lossy(&git_rev_list_output.stdout).to_string();

        for (i, commit_hash) in git_rev_list_output_cow.split("\n").enumerate() {
            println!("i: {i}");
            if !commit_hash.is_empty() {
                println!("git checkout {commit_hash}");

                let git_checkout_output = Command::new("git")
                    .arg("checkout")
                    .arg(commit_hash)
                    .output()
                    .expect("checkout failed");

                if git_checkout_output.status.success() {
                    println!(
                        "git checkout stdout: {}",
                        String::from_utf8(git_checkout_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git checkout stderr: {}",
                        String::from_utf8(git_checkout_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                println!("git show");

                let git_show_output = Command::new("git")
                    .arg("show")
                    .output()
                    .expect("show failed");

                if git_show_output.status.success() {
                    println!(
                        "git show stdout: {}",
                        String::from_utf8(git_show_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "git show stderr: {}",
                        String::from_utf8(git_show_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                let parent_path = env::current_dir().expect("getting current directory failed");
                let mut path = parent_path.clone();
                path.push(&app_name);
                let metadata = fs::metadata(path);
                match metadata {
                    Ok(_) => {
                        println!("{app_name} found");
                    }
                    Err(_) => {
                        println!("{app_name} not found");
                        continue;
                    }
                };

                println!("cd {app_name}");

                env::set_current_dir(&app_name).expect("changing directory failed");

                println!("cargo test");

                let cargo_test_output = Command::new("cargo")
                    .arg("test")
                    .output()
                    .expect("test failed");

                if cargo_test_output.status.success() {
                    println!(
                        "cargo test stdout: {}",
                        String::from_utf8(cargo_test_output.stdout).unwrap()
                    );
                } else {
                    println!(
                        "cargo test stderr: {}",
                        String::from_utf8(cargo_test_output.stderr).unwrap()
                    );

                    process::exit(1);
                }

                println!("cd ..");

                env::set_current_dir(parent_path).expect("changing directory failed");
            }
        }

        println!(
            "rev-list stdout: {}",
            String::from_utf8(git_rev_list_output.stdout).unwrap()
        );
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8(git_rev_list_output.stderr).unwrap()
        );

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>extern crate actix;
extern crate actix_web;
extern crate bytes;
extern crate futures;
extern crate env_logger;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate json;

use actix_web::{
    middleware, http, error, server,
    App, AsyncResponder, HttpRequest, HttpResponse, HttpMessage, Error, Json};

use bytes::BytesMut;
use futures::{Future, Stream};
use json::JsonValue;

#[derive(Debug, Serialize, Deserialize)]
struct MyObj {
    name: String,
    number: i32,
}

/// This handler uses `HttpRequest::json()` for loading serde json object.
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
    req.json()
        .from_err()  // convert all errors into `Error`
        .and_then(|val: MyObj| {
            println!("model: {:?}", val);
            Ok(HttpResponse::Ok().json(val))  // <- send response
        })
        .responder()
}

/// This handler uses `With` helper for loading serde json object.
fn extract_item(item: Json<MyObj>) -> HttpResponse {
    println!("model: {:?}", &item);
    HttpResponse::Ok().json(item.0)  // <- send response
}

const MAX_SIZE: usize = 262_144;  // max payload size is 256k

/// This handler manually load request payload and parse serde json
fn index_manual(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
    // HttpRequest is stream of Bytes objects
    req
        // `Future::from_err` acts like `?` in that it coerces the error type from
        // the future into the final error type
        .from_err()

        // `fold` will asynchronously read each chunk of the request body and
        // call supplied closure, then it resolves to result of closure
        .fold(BytesMut::new(), move |mut body, chunk| {
            // limit max size of in-memory payload
            if (body.len() + chunk.len()) > MAX_SIZE {
                Err(error::ErrorBadRequest("overflow"))
            } else {
                body.extend_from_slice(&chunk);
                Ok(body)
            }
        })
        // `Future::and_then` can be used to merge an asynchronous workflow with a
        // synchronous workflow
        .and_then(|body| {
            // body is loaded, now we can deserialize serde-json
            let obj = serde_json::from_slice::<MyObj>(&body)?;
            Ok(HttpResponse::Ok().json(obj)) // <- send response
        })
        .responder()
}

/// This handler manually load request payload and parse json-rust
fn index_mjsonrust(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
    req.concat2()
        .from_err()
        .and_then(|body| {
            // body is loaded, now we can deserialize json-rust
            let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result
            let injson: JsonValue = match result { Ok(v) => v, Err(e) => object!{"err" => e.to_string() } };
            Ok(HttpResponse::Ok()
                .content_type("application/json")
                .body(injson.dump()))
        })
        .responder()
}

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    let _ = env_logger::init();
    let sys = actix::System::new("json-example");

    let _ = server::new(|| {
        App::new()
            // enable logger
            .middleware(middleware::Logger::default())
            .resource("/extractor/{name}/{number}/",
                      |r| r.method(http::Method::GET).with(extract_item))
            .resource("/manual", |r| r.method(http::Method::POST).f(index_manual))
            .resource("/mjsonrust", |r| r.method(http::Method::POST).f(index_mjsonrust))
            .resource("/", |r| r.method(http::Method::POST).f(index))})
        .bind("127.0.0.1:8080").unwrap()
        .shutdown_timeout(1)
        .start();

    println!("Started http server: 127.0.0.1:8080");
    let _ = sys.run();
}
<commit_msg>update json example<commit_after>extern crate actix;
extern crate actix_web;
extern crate bytes;
extern crate futures;
extern crate env_logger;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate json;

use actix_web::{
    middleware, http, error, server,
    App, AsyncResponder, HttpRequest, HttpResponse, HttpMessage, Error, Json};

use bytes::BytesMut;
use futures::{Future, Stream};
use json::JsonValue;

#[derive(Debug, Serialize, Deserialize)]
struct MyObj {
    name: String,
    number: i32,
}

/// This handler uses `HttpRequest::json()` for loading json object.
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
    req.json()
        .from_err()  // convert all errors into `Error`
        .and_then(|val: MyObj| {
            println!("model: {:?}", val);
            Ok(HttpResponse::Ok().json(val))  // <- send response
        })
        .responder()
}

/// This handler uses json extractor
fn extract_item(item: Json<MyObj>) -> HttpResponse {
    println!("model: {:?}", &item);
    HttpResponse::Ok().json(item.0)  // <- send response
}

const MAX_SIZE: usize = 262_144;  // max payload size is 256k

/// This handler manually load request payload and parse json object
fn index_manual(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
    // HttpRequest is stream of Bytes objects
    req
        // `Future::from_err` acts like `?` in that it coerces the error type from
        // the future into the final error type
        .from_err()

        // `fold` will asynchronously read each chunk of the request body and
        // call supplied closure, then it resolves to result of closure
        .fold(BytesMut::new(), move |mut body, chunk| {
            // limit max size of in-memory payload
            if (body.len() + chunk.len()) > MAX_SIZE {
                Err(error::ErrorBadRequest("overflow"))
            } else {
                body.extend_from_slice(&chunk);
                Ok(body)
            }
        })
        // `Future::and_then` can be used to merge an asynchronous workflow with a
        // synchronous workflow
        .and_then(|body| {
            // body is loaded, now we can deserialize serde-json
            let obj = serde_json::from_slice::<MyObj>(&body)?;
            Ok(HttpResponse::Ok().json(obj)) // <- send response
        })
        .responder()
}

/// This handler manually load request payload and parse json-rust
fn index_mjsonrust(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
    req.concat2()
        .from_err()
        .and_then(|body| {
            // body is loaded, now we can deserialize json-rust
            let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result
            let injson: JsonValue = match result { Ok(v) => v, Err(e) => object!{"err" => e.to_string() } };
            Ok(HttpResponse::Ok()
                .content_type("application/json")
                .body(injson.dump()))
        })
        .responder()
}

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();
    let sys = actix::System::new("json-example");

    let _ = server::new(|| {
        App::new()
            // enable logger
            .middleware(middleware::Logger::default())
            .resource("/extractor", |r| {
                r.method(http::Method::POST)
                    .with(extract_item)
                    .limit(4096); // <- limit size of the payload
            })
            .resource("/manual", |r| r.method(http::Method::POST).f(index_manual))
            .resource("/mjsonrust", |r| r.method(http::Method::POST).f(index_mjsonrust))
            .resource("/", |r| r.method(http::Method::POST).f(index))})
        .bind("127.0.0.1:8080").unwrap()
        .shutdown_timeout(1)
        .start();

    println!("Started http server: 127.0.0.1:8080");
    let _ = sys.run();
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate rs_poker;
extern crate test;
use rs_poker::core::Hand;
use rs_poker::holdem::Game;

#[bench]
fn simulate_one_game(b: &mut test::Bencher) {
    let hands = ["AdAh", "2c2s"]
        .iter()
        .map(|s| Hand::new_from_str(s).expect("Should be able to create a hand."))
        .collect();
    let mut g = Game::new_with_hands(hands).expect("Should be able to create a game.");
    b.iter(|| {
               let r = g.simulate().expect("There should be one best rank.");
               g.reset();
               r
           })

}
<commit_msg>Fix the build.<commit_after>#![feature(test)]
extern crate rs_poker;
extern crate test;
use rs_poker::core::Hand;
use rs_poker::holdem::MonteCarloGame;

#[bench]
fn simulate_one_game(b: &mut test::Bencher) {
    let hands = ["AdAh", "2c2s"]
        .iter()
        .map(|s| Hand::new_from_str(s).expect("Should be able to create a hand."))
        .collect();
    let mut g = MonteCarloGame::new_with_hands(hands).expect("Should be able to create a game.");
    b.iter(|| {
               let r = g.simulate().expect("There should be one best rank.");
               g.reset();
               r
           })

}
<|endoftext|>