<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!(feature = "release") {
      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>Hiding cursor.<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>use serde_json;
use errors::route::RouteError;
use utils::crypto::base64::encode;

#[derive(Serialize, Deserialize, Debug)]
pub struct ForwardJSON {
    #[serde(rename = "type")]
    pub type_: String,
    pub to: String,
    pub message: String
}

/// This creates a plaintext of the forward message data structure
pub fn format_forward_msg(ciphertext: &[u8], to_did: &str) -> Result<String, RouteError> {
    let encoded_ciphertext = encode(ciphertext);
    let fwd_json = ForwardJSON {
        type_: String::from("Forward"),
        to: to_did.to_string(),
        message: encoded_ciphertext
    };

    serde_json::to_string(&fwd_json)
        .map_err( | err | RouteError::EncodeError(format!("{}", err)))
}

#[cfg(test)]
mod tests {
    use base64::{encode_config, URL_SAFE};
    use super::*;
    use serde_json::Value;

    #[test]
    fn test_format_forward_msg() {
        //base information
        let message = "unencrypted text converted to byte array".as_bytes();
        let to_did = String::from("did:sov:thisisbobpwdidwithalice#1");
        let message_encoded = encode_config(message, URL_SAFE);

        //create forward message
        let forward_msg = format_forward_msg(message, &to_did).unwrap();

        let expected_output = json!({
                "type" : "Forward",
                "to" : to_did,
                "message" : encode_config(message, URL_SAFE)
            });

        let function_output: Value = serde_json::from_str(&forward_msg).unwrap();
        assert_eq!(function_output, expected_output);
    }
}<commit_msg>"removed forward functionality for this PR"<commit_after><|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

// XXX Should be 32K at least
// XXX Getting the BlockInfo from the object pointer needs fixing if
// XXX BLOCK_SIZE != page size and the memory maps are not BLOCK_SIZE aligned.
pub const BLOCK_SIZE : usize = 4 * 1024;

pub const LINE_SIZE: usize = 256;
pub const NUM_LINES_PER_BLOCK: usize = BLOCK_SIZE / LINE_SIZE;

pub const EVAC_HEADROOM: usize = 5;
pub const BUFFER_BLOCK_COUNT: usize = 10;
<commit_msg>Add statistic constants for cycle/defrag<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

// XXX Should be 32K at least
// XXX Getting the BlockInfo from the object pointer needs fixing if
// XXX BLOCK_SIZE != page size and the memory maps are not BLOCK_SIZE aligned.
pub const BLOCK_SIZE : usize = 4 * 1024;

pub const LINE_SIZE: usize = 256;
pub const NUM_LINES_PER_BLOCK: usize = BLOCK_SIZE / LINE_SIZE;

pub const EVAC_HEADROOM: usize = 5;
pub const BUFFER_BLOCK_COUNT: usize = 10;

pub const CICLE_TRIGGER_THRESHHOLD: f32 = 0.01;
pub const EVAC_TRIGGER_THRESHHOLD: f32 = 0.01;
<|endoftext|>


<commit_before>// Copyright 2015 Ilkka Rauta
//
// 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.

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use std::path::Path;
use libc::{c_uint,c_ulong};

pub const DEMUX_FILTER_SIZE: usize = ffi::DMX_FILTER_SIZE as usize;

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod enums {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/demux-enums.rs"));
}

pub use self::enums::{Input,Output,PesType};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self, buffer: &mut [u8]) -> DeviceResult<usize> {
        self.device.read(buffer)
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self, filter_params: &SectionFilterParams) -> DeviceResult<()> {
        let mut ffi_params = ffi::Struct_dmx_sct_filter_params {
            pid: filter_params.pid,
            filter: ffi::Struct_dmx_filter {
                filter: filter_params.filter.filter,
                mask: filter_params.filter.mask,
                mode: filter_params.filter.mode,
            },
            timeout: filter_params.timeout,
            flags: filter_params.flags.bits()
        };
        self.device.ioctl_pointer(ffi::DMX_SET_FILTER as c_ulong, &mut ffi_params)
    }

    pub fn set_pes_filter(&self, filter_params: &PesFilterParams) -> DeviceResult<()> {
        let mut ffi_params = ffi::Struct_dmx_pes_filter_params {
            pid: filter_params.pid,
            input: filter_params.input.into(),
            output: filter_params.output.into(),
            pes_type: filter_params.pes_type.into(),
            flags: filter_params.flags.bits()
        };
        self.device.ioctl_pointer(ffi::DMX_SET_PES_FILTER as c_ulong, &mut ffi_params)
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        set_buffer_size(&self.device, buffer_size)
    }

    pub fn get_system_time_counter(&self, num: u32) -> DeviceResult<SystemTimeCounter> {
        let mut ffi_stc = ffi::Struct_dmx_stc { num: num as c_uint, base: 0, stc: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_STC as c_ulong, &mut ffi_stc));
        Ok(SystemTimeCounter { base: ffi_stc.base, counter: ffi_stc.stc })
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        let mut ffi_pids = [0u16; 5];
        try!(self.device.ioctl_pointer(ffi::DMX_GET_PES_PIDS as c_ulong, ffi_pids.as_mut_ptr()));
        Ok(ffi_pids)
    }

    /// This function is undocumented in the official documentation, and doesn't seem to be
    /// actually in use. It is still nevertheless included here, if it is used by out-of-tree DVB
    /// drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    /// Like get_caps(), this doesn't seem to be actively in use in Linux, but is still implemented.
    pub fn set_source(&self, source: enums::DemuxSource) -> DeviceResult<()> {
        let mut ffi_source: ffi::dmx_source_t =  source.into();
        self.device.ioctl_pointer(ffi::DMX_SET_SOURCE as c_ulong, &mut ffi_source)
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_ADD_PID as c_ulong, &mut ffi_pid)
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_REMOVE_PID as c_ulong, &mut ffi_pid)
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter {
    pub base: u32,
    pub counter: u64
}

pub struct DemuxFilter {
    pub filter: [u8; DEMUX_FILTER_SIZE],
    pub mask: [u8; DEMUX_FILTER_SIZE],
    pub mode: [u8; DEMUX_FILTER_SIZE],
}

impl Default for DemuxFilter {
    fn default() -> DemuxFilter {
        DemuxFilter {
            filter: [0u8; DEMUX_FILTER_SIZE],
            mask: [0u8; DEMUX_FILTER_SIZE],
            mode: [0u8; DEMUX_FILTER_SIZE],
        }
    }
}

pub struct SectionFilterParams {
    pub pid: u16,
    pub filter: DemuxFilter,
    pub timeout: u32,
    pub flags: flags::SectionFilterFlags
}

pub struct PesFilterParams {
    pub pid: u16,
    pub input: Input,
    pub output: Output,
    pub pes_type: PesType,
    pub flags: flags::PesFilterFlags
}

#[allow(dead_code,non_upper_case_globals)]
pub mod flags {
    use super::ffi as ffi;
    bitflags!{
        flags SectionFilterFlags: u32 {
            const SecCheckCrC = ffi::DMX_CHECK_CRC,
            const SecOneShot = ffi::DMX_ONESHOT,
            const SecImmediateStart = ffi::DMX_IMMEDIATE_START
        }
    }

    bitflags!{
        flags PesFilterFlags: u32 {
            const PesImmediateStart = ffi::DMX_IMMEDIATE_START
        }
    }
}

pub struct Dvr {
    device: DeviceFileDescriptor
}

impl Dvr {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Dvr> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Dvr { device: device })
    }

    pub fn write(&self, buffer: &mut [u8]) -> DeviceResult<usize> {
        self.device.write(buffer)
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        set_buffer_size(&self.device, buffer_size)
    }
}

fn set_buffer_size(device: &DeviceFileDescriptor, buffer_size: u32) -> DeviceResult<()> {
    let mut ffi_size = buffer_size as c_ulong;
    device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
}
<commit_msg>Fix demux::set_buffer_size().<commit_after>// Copyright 2015 Ilkka Rauta
//
// 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.

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod ffi;

use std::path::Path;
use libc::{c_uint,c_ulong};

pub const DEMUX_FILTER_SIZE: usize = ffi::DMX_FILTER_SIZE as usize;

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod enums {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/demux-enums.rs"));
}

pub use self::enums::{Input,Output,PesType};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self, buffer: &mut [u8]) -> DeviceResult<usize> {
        self.device.read(buffer)
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self, filter_params: &SectionFilterParams) -> DeviceResult<()> {
        let mut ffi_params = ffi::Struct_dmx_sct_filter_params {
            pid: filter_params.pid,
            filter: ffi::Struct_dmx_filter {
                filter: filter_params.filter.filter,
                mask: filter_params.filter.mask,
                mode: filter_params.filter.mode,
            },
            timeout: filter_params.timeout,
            flags: filter_params.flags.bits()
        };
        self.device.ioctl_pointer(ffi::DMX_SET_FILTER as c_ulong, &mut ffi_params)
    }

    pub fn set_pes_filter(&self, filter_params: &PesFilterParams) -> DeviceResult<()> {
        let mut ffi_params = ffi::Struct_dmx_pes_filter_params {
            pid: filter_params.pid,
            input: filter_params.input.into(),
            output: filter_params.output.into(),
            pes_type: filter_params.pes_type.into(),
            flags: filter_params.flags.bits()
        };
        self.device.ioctl_pointer(ffi::DMX_SET_PES_FILTER as c_ulong, &mut ffi_params)
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        set_buffer_size(&self.device, buffer_size)
    }

    pub fn get_system_time_counter(&self, num: u32) -> DeviceResult<SystemTimeCounter> {
        let mut ffi_stc = ffi::Struct_dmx_stc { num: num as c_uint, base: 0, stc: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_STC as c_ulong, &mut ffi_stc));
        Ok(SystemTimeCounter { base: ffi_stc.base, counter: ffi_stc.stc })
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        let mut ffi_pids = [0u16; 5];
        try!(self.device.ioctl_pointer(ffi::DMX_GET_PES_PIDS as c_ulong, ffi_pids.as_mut_ptr()));
        Ok(ffi_pids)
    }

    /// This function is undocumented in the official documentation, and doesn't seem to be
    /// actually in use. It is still nevertheless included here, if it is used by out-of-tree DVB
    /// drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    /// Like get_caps(), this doesn't seem to be actively in use in Linux, but is still implemented.
    pub fn set_source(&self, source: enums::DemuxSource) -> DeviceResult<()> {
        let mut ffi_source: ffi::dmx_source_t =  source.into();
        self.device.ioctl_pointer(ffi::DMX_SET_SOURCE as c_ulong, &mut ffi_source)
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_ADD_PID as c_ulong, &mut ffi_pid)
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_REMOVE_PID as c_ulong, &mut ffi_pid)
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter {
    pub base: u32,
    pub counter: u64
}

pub struct DemuxFilter {
    pub filter: [u8; DEMUX_FILTER_SIZE],
    pub mask: [u8; DEMUX_FILTER_SIZE],
    pub mode: [u8; DEMUX_FILTER_SIZE],
}

impl Default for DemuxFilter {
    fn default() -> DemuxFilter {
        DemuxFilter {
            filter: [0u8; DEMUX_FILTER_SIZE],
            mask: [0u8; DEMUX_FILTER_SIZE],
            mode: [0u8; DEMUX_FILTER_SIZE],
        }
    }
}

pub struct SectionFilterParams {
    pub pid: u16,
    pub filter: DemuxFilter,
    pub timeout: u32,
    pub flags: flags::SectionFilterFlags
}

pub struct PesFilterParams {
    pub pid: u16,
    pub input: Input,
    pub output: Output,
    pub pes_type: PesType,
    pub flags: flags::PesFilterFlags
}

#[allow(dead_code,non_upper_case_globals)]
pub mod flags {
    use super::ffi as ffi;
    bitflags!{
        flags SectionFilterFlags: u32 {
            const SecCheckCrC = ffi::DMX_CHECK_CRC,
            const SecOneShot = ffi::DMX_ONESHOT,
            const SecImmediateStart = ffi::DMX_IMMEDIATE_START
        }
    }

    bitflags!{
        flags PesFilterFlags: u32 {
            const PesImmediateStart = ffi::DMX_IMMEDIATE_START
        }
    }
}

pub struct Dvr {
    device: DeviceFileDescriptor
}

impl Dvr {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Dvr> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Dvr { device: device })
    }

    pub fn write(&self, buffer: &mut [u8]) -> DeviceResult<usize> {
        self.device.write(buffer)
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        set_buffer_size(&self.device, buffer_size)
    }
}

fn set_buffer_size(device: &DeviceFileDescriptor, buffer_size: u32) -> DeviceResult<()> {
    device.ioctl_value(ffi::DMX_SET_BUFFER_SIZE as c_ulong, buffer_size as c_ulong)
}
<|endoftext|>


<commit_before>#![crate_name = "foo"]

#![unstable(feature = "humans",
            reason = "who ever let humans program computers, we're apparently really bad at it",
            issue = "none")]

#![feature(foo, foo2)]
#![feature(staged_api)]

// @has 'foo/fn.foo.html' '//pre' 'pub fn foo() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const fn foo() -> u32 { 42 }

// @has 'foo/fn.foo_unsafe.html' '//pre' 'pub unsafe fn foo_unsafe() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const unsafe fn foo_unsafe() -> u32 { 42 }

// @has 'foo/fn.foo2.html' '//pre' 'pub const fn foo2() -> u32'
// @!has - '//span[@class="since"]'
#[unstable(feature = "humans", issue = "none")]
pub const fn foo2() -> u32 { 42 }

// @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
// @has - //span '1.0.0 (const: 1.0.0)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
pub const fn bar2() -> u32 { 42 }

// @has 'foo/fn.foo2_gated.html' '//pre' 'pub const fn foo2_gated() -> u32'
// @!has - '//span[@class="since"]'
#[unstable(feature = "foo2", issue = "none")]
pub const fn foo2_gated() -> u32 { 42 }

// @has 'foo/fn.bar2_gated.html' '//pre' 'pub const fn bar2_gated() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: 1.0.0)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
pub const fn bar2_gated() -> u32 { 42 }

// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub const fn bar_not_gated() -> u32'
// @!has - '//span[@class="since"]'
pub const fn bar_not_gated() -> u32 { 42 }

pub struct Foo;

impl Foo {
    // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub fn gated() -> u32'
    // @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_const_unstable(feature="foo", issue = "none")]
    pub const fn gated() -> u32 { 42 }

    // @has 'foo/struct.Foo.html' '//div[@id="method.gated_unsafe"]/code' 'pub unsafe fn gated_unsafe() -> u32'
    // @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_const_unstable(feature="foo", issue = "none")]
    pub const unsafe fn gated_unsafe() -> u32 { 42 }

    // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
    // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
    pub const fn stable_impl() -> u32 { 42 }
}
<commit_msg>Readd `unsafe` keyword in tests<commit_after>#![crate_name = "foo"]

#![unstable(feature = "humans",
            reason = "who ever let humans program computers, we're apparently really bad at it",
            issue = "none")]

#![feature(foo, foo2)]
#![feature(staged_api)]

// @has 'foo/fn.foo.html' '//pre' 'pub fn foo() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const fn foo() -> u32 { 42 }

// @has 'foo/fn.foo_unsafe.html' '//pre' 'pub unsafe fn foo_unsafe() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const unsafe fn foo_unsafe() -> u32 { 42 }

// @has 'foo/fn.foo2.html' '//pre' 'pub const fn foo2() -> u32'
// @!has - '//span[@class="since"]'
#[unstable(feature = "humans", issue = "none")]
pub const fn foo2() -> u32 { 42 }

// @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
// @has - //span '1.0.0 (const: 1.0.0)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
pub const fn bar2() -> u32 { 42 }

// @has 'foo/fn.foo2_gated.html' '//pre' 'pub const unsafe fn foo2_gated() -> u32'
// @!has - '//span[@class="since"]'
#[unstable(feature = "foo2", issue = "none")]
pub const unsafe fn foo2_gated() -> u32 { 42 }

// @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: 1.0.0)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
pub const unsafe fn bar2_gated() -> u32 { 42 }

// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32'
// @!has - '//span[@class="since"]'
pub const unsafe fn bar_not_gated() -> u32 { 42 }

pub struct Foo;

impl Foo {
    // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub fn gated() -> u32'
    // @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_const_unstable(feature="foo", issue = "none")]
    pub const fn gated() -> u32 { 42 }

    // @has 'foo/struct.Foo.html' '//div[@id="method.gated_unsafe"]/code' 'pub unsafe fn gated_unsafe() -> u32'
    // @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_const_unstable(feature="foo", issue = "none")]
    pub const unsafe fn gated_unsafe() -> u32 { 42 }

    // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
    // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
    pub const fn stable_impl() -> u32 { 42 }
}
<|endoftext|>


<commit_before>use board::sjadam_board::SjadamBoard;
use uci::UciBoard;
use board::sjadam_move::SjadamMove;
use search_algorithms::alpha_beta;
use search_algorithms::game_move::Move;
use search_algorithms::board::EvalBoard;
use search_algorithms::board::Color;
use uci;
use std::sync;

/// Promotes a pawn through a sjadam move, which mates
#[test]
fn promote_pawn_to_mate() {
    let board = SjadamBoard::from_fen("k7/5R2/5P2/8/8/8/8/7K w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("f6f8-").unwrap();
    basic_tactics_prop(&board, correct_move);
}

/// Checks that the expected move is indeed played in the position
fn basic_tactics_prop(board : &SjadamBoard, best_move : SjadamMove) {
    let (handle, channel) = alpha_beta::start_uci_search(
        board.clone(), uci::TimeRestriction::Depth(3),
        uci::EngineOptions::new(),
        sync::Arc::new(sync::Mutex::new(uci::EngineComm::new())), None);

    let (score, move_str) = uci::get_uci_move_checked(handle, channel).unwrap();

    let game_move = SjadamMove::from_alg(&move_str).unwrap();

    assert_eq!(game_move, best_move,
               "Best move was {:?} with score {}, expected {:?}, board:\n{:?}",
               game_move, score,
               best_move, board);
}

#[test]
fn sjadammate1() {
    let board = SjadamBoard::from_fen("r2q2n1/p5pp/2p3k1/1p1R4/8/5P2/P1P1P3/2B3K1 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("d5b7b7g7").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate2() {
    let board = SjadamBoard::from_fen("4Q3/5p1p/3p4/q1p2rP1/p1k1b3/3Q2R1/2P4P/1K4N1 b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-c4b4").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate3() {
    let board = SjadamBoard::from_fen("r1bqkb1r/pp1ppppp/3n4/2p1P3/5P2/4N3/PPP2PPP/RNBQKB1R b KQkq - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-d6f5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate6() {
    let board = SjadamBoard::from_fen("1b3rk1/pp4pp/3p3P/3p3B/6RK/2N2p1P/PP3R2/8 b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("b8b6b6d8").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate7() {
    let board = SjadamBoard::from_fen("3k3r/1pppppp1/8/p1P5/PP2PPn1/2b3Kp/3PR2R/8 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("f4b2b2c3").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate8() {
    let board = SjadamBoard::from_fen("4r3/pr4pk/1pp3RP/4p2B/2P3K1/P4p1P/1NP2R2/4P3 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-g6g5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate9() {
    let board = SjadamBoard::from_fen("2kr1br1/5ppp/1pB1n3/2P2n2/4p3/2P3P1/PP1NNP2/R4R1K b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("c8e8e8e7").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate10() {
    let board = SjadamBoard::from_fen("r1b2bkr/ppp1p1pp/P1n2n2/8/4Pp1R/3NB3/2PP2PP/4RK2 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("d3d5d5f6").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate11() {
    let board = SjadamBoard::from_fen("k7/p2b4/5p2/p2Kb3/1pB2p2/4p1P1/2P4P/3Q4 b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-d7f5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate12() {
    let board = SjadamBoard::from_fen("rn1qk3/ppp1p1pp/3p1b2/6P1/2R1b3/3P4/PPpPPRP1/3QKB2 w KQkq - 0 2").unwrap();
    let correct_move = SjadamMove::from_alg("d1f3f3g4").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate13() {
    let board = SjadamBoard::from_fen("r3k3/pppppppp/8/8/3K4/8/PPPPPPPP/R4BN1 b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-d7d5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate14() {
    let board = SjadamBoard::from_fen("q2k1b1r/2p1pppp/1p6/1R6/2P5/3P1Q2/4PPPP/5KN1 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-f3c6").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate15() {
    let board = SjadamBoard::from_fen("r1bqkb1r/2ppp1pp/p1n3n1/4P3/1NpP1p2/4P3/P2NP1PP/R1BQKB1R w KQkq - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("d4f6f6f7").unwrap();
    is_mate_in_one(&board, correct_move);
}

fn is_mate_in_one(board: &SjadamBoard, best_move: SjadamMove) {
    let (handle, channel) = alpha_beta::start_uci_search(
        board.clone(), uci::TimeRestriction::Depth(4),
        uci::EngineOptions::new(),
        sync::Arc::new(sync::Mutex::new(uci::EngineComm::new())), None);

    let (score, move_str) = uci::get_uci_move_checked(handle, channel).unwrap();

    let game_move = SjadamMove::from_alg(&move_str).unwrap();

    assert_eq!(game_move, best_move,
               "Best move was {:?} with score {}, expected {:?}, board:\n{:?}",
               game_move, score,
               best_move, board);
    if board.to_move() == Color::White {
        assert_eq!(score, alpha_beta::Score::WhiteWin(3));
    }
    else {
        assert_eq!(score, alpha_beta::Score::BlackWin(3));
    }
}
<commit_msg>Added 3 more sjadam tactics tests<commit_after>use board::sjadam_board::SjadamBoard;
use uci::UciBoard;
use board::sjadam_move::SjadamMove;
use search_algorithms::alpha_beta;
use search_algorithms::game_move::Move;
use search_algorithms::board::EvalBoard;
use search_algorithms::board::Color;
use uci;
use std::sync;

/// Promotes a pawn through a sjadam move, which mates
#[test]
fn promote_pawn_to_mate() {
    let board = SjadamBoard::from_fen("k7/5R2/5P2/8/8/8/8/7K w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("f6f8-").unwrap();
    basic_tactics_prop(&board, correct_move);
}

/// Checks that the expected move is indeed played in the position
fn basic_tactics_prop(board : &SjadamBoard, best_move : SjadamMove) {
    let (handle, channel) = alpha_beta::start_uci_search(
        board.clone(), uci::TimeRestriction::Depth(3),
        uci::EngineOptions::new(),
        sync::Arc::new(sync::Mutex::new(uci::EngineComm::new())), None);

    let (score, move_str) = uci::get_uci_move_checked(handle, channel).unwrap();

    let game_move = SjadamMove::from_alg(&move_str).unwrap();

    assert_eq!(game_move, best_move,
               "Best move was {:?} with score {}, expected {:?}, board:\n{:?}",
               game_move, score,
               best_move, board);
}

#[test]
fn sjadammate1() {
    let board = SjadamBoard::from_fen("r2q2n1/p5pp/2p3k1/1p1R4/8/5P2/P1P1P3/2B3K1 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("d5b7b7g7").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate2() {
    let board = SjadamBoard::from_fen("4Q3/5p1p/3p4/q1p2rP1/p1k1b3/3Q2R1/2P4P/1K4N1 b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-c4b4").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate3() {
    let board = SjadamBoard::from_fen("r1bqkb1r/pp1ppppp/3n4/2p1P3/5P2/4N3/PPP2PPP/RNBQKB1R b KQkq - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-d6f5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate6() {
    let board = SjadamBoard::from_fen("1b3rk1/pp4pp/3p3P/3p3B/6RK/2N2p1P/PP3R2/8 b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("b8b6b6d8").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate7() {
    let board = SjadamBoard::from_fen("3k3r/1pppppp1/8/p1P5/PP2PPn1/2b3Kp/3PR2R/8 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("f4b2b2c3").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate8() {
    let board = SjadamBoard::from_fen("4r3/pr4pk/1pp3RP/4p2B/2P3K1/P4p1P/1NP2R2/4P3 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-g6g5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate9() {
    let board = SjadamBoard::from_fen("2kr1br1/5ppp/1pB1n3/2P2n2/4p3/2P3P1/PP1NNP2/R4R1K b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("c8e8e8e7").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate10() {
    let board = SjadamBoard::from_fen("r1b2bkr/ppp1p1pp/P1n2n2/8/4Pp1R/3NB3/2PP2PP/4RK2 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("d3d5d5f6").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate11() {
    let board = SjadamBoard::from_fen("k7/p2b4/5p2/p2Kb3/1pB2p2/4p1P1/2P4P/3Q4 b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-d7f5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate12() {
    let board = SjadamBoard::from_fen("rn1qk3/ppp1p1pp/3p1b2/6P1/2R1b3/3P4/PPpPPRP1/3QKB2 w KQkq - 0 2").unwrap();
    let correct_move = SjadamMove::from_alg("d1f3f3g4").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate13() {
    let board = SjadamBoard::from_fen("r3k3/pppppppp/8/8/3K4/8/PPPPPPPP/R4BN1 b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-d7d5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate14() {
    let board = SjadamBoard::from_fen("q2k1b1r/2p1pppp/1p6/1R6/2P5/3P1Q2/4PPPP/5KN1 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-f3c6").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate15() {
    let board = SjadamBoard::from_fen("r1bqkb1r/2ppp1pp/p1n3n1/4P3/1NpP1p2/4P3/P2NP1PP/R1BQKB1R w KQkq - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("d4f6f6f7").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate16() {
    let board = SjadamBoard::from_fen("2b3k1/2pp1pp1/1n2p1p1/1rB5/4N3/1P2P3/3PB1PP/KR5R b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("g6a2a2b1").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate17() {
    let board = SjadamBoard::from_fen("1k5r/1bbp1pp1/pp6/3p1N2/1nPBP2p/1P3P2/2PP2R1/1K6 w - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("-e4e5").unwrap();
    is_mate_in_one(&board, correct_move);
}

#[test]
fn sjadammate18() {
    let board = SjadamBoard::from_fen("7k/1pppp1pr/1pn3P1/8/1rNb2NP/2P1PPP1/1P1PQ3/R6K b - - 0 1").unwrap();
    let correct_move = SjadamMove::from_alg("d7f7f7g6").unwrap();
    is_mate_in_one(&board, correct_move);
}

fn is_mate_in_one(board: &SjadamBoard, best_move: SjadamMove) {
    let (handle, channel) = alpha_beta::start_uci_search(
        board.clone(), uci::TimeRestriction::Depth(3),
        uci::EngineOptions::new(),
        sync::Arc::new(sync::Mutex::new(uci::EngineComm::new())), None);

    let (score, move_str) = uci::get_uci_move_checked(handle, channel).unwrap();

    let game_move = SjadamMove::from_alg(&move_str).unwrap();

    assert_eq!(game_move, best_move,
               "Best move was {:?} with score {}, expected {:?}, board:\n{:?}",
               game_move, score,
               best_move, board);
    if board.to_move() == Color::White {
        assert_eq!(score, alpha_beta::Score::WhiteWin(3));
    }
    else {
        assert_eq!(score, alpha_beta::Score::BlackWin(3));
    }
}
<|endoftext|>


<commit_before>//! The public FFI functions for initializing, adding sinks to, and applying a logger.

use std::convert::TryFrom;
use std::ffi::{CStr, CString};
use std::ptr;
use std::str::from_utf8;

use fern::Dispatch;
use libc::{c_char, c_int};
use log::{error, LevelFilter as LogLevelFilter};

use pact_matching::logging::fetch_buffer_contents;

use crate::error::set_error_msg;
use crate::log::level_filter::LevelFilter;
use crate::log::logger::{add_sink, apply_logger, set_logger};
use crate::log::sink::Sink;
use crate::log::status::Status;
use crate::util::string::to_c;

/// Convenience function to direct all logging to stdout.
#[no_mangle]
pub extern "C" fn log_to_stdout(level_filter: LevelFilter) -> c_int {
    logger_init();

    let spec = match CString::new("stdout") {
        Ok(spec) => spec,
        Err(e) => {
            set_error_msg(e.to_string());
            return Status::CantConstructSink as c_int;
        }
    };

    let status = logger_attach_sink(spec.as_ptr(), level_filter);
    if status != 0 {
        return status;
    }

    let status = logger_apply();
    if status != 0 {
        return status;
    }

    Status::Success as c_int
}

/// Convenience function to direct all logging to stderr.
#[no_mangle]
pub extern "C" fn log_to_stderr(level_filter: LevelFilter) -> c_int {
    logger_init();

    let spec = match CString::new("stderr") {
        Ok(spec) => spec,
        Err(e) => {
            set_error_msg(e.to_string());
            return Status::CantConstructSink as c_int;
        }
    };

    let status = logger_attach_sink(spec.as_ptr(), level_filter);
    if status != 0 {
        return status;
    }

    let status = logger_apply();
    if status != 0 {
        return status;
    }

    Status::Success as c_int
}

/// Convenience function to direct all logging to a file.
#[no_mangle]
pub unsafe extern "C" fn log_to_file(
    file_name: *const c_char,
    level_filter: LevelFilter,
) -> c_int {
    logger_init();

    let spec = {
        if file_name.is_null() {
            return Status::CantConstructSink as c_int;
        }

        let file_name =
            match CStr::from_ptr(file_name).to_str() {
                Ok(file_name) => file_name,
                Err(e) => {
                    set_error_msg(e.to_string());
                    return Status::CantConstructSink as c_int;
                }
            };

        let spec = format!("file {}", file_name);

        match CString::new(spec) {
            Ok(spec) => spec,
            Err(e) => {
                set_error_msg(e.to_string());
                return Status::CantConstructSink as c_int;
            }
        }
    };

    let status = logger_attach_sink(spec.as_ptr(), level_filter);
    if status != 0 {
        return status;
    }

    let status = logger_apply();
    if status != 0 {
        return status;
    }

    Status::Success as c_int
}

/// Convenience function to direct all logging to a thread local memory buffer.
#[no_mangle]
pub extern "C" fn log_to_buffer(level_filter: LevelFilter) -> c_int {
  logger_init();

  let spec = match CString::new("buffer") {
    Ok(spec) => spec,
    Err(e) => {
      set_error_msg(e.to_string());
      return Status::CantConstructSink as c_int;
    }
  };

  let status = logger_attach_sink(spec.as_ptr(), level_filter);
  if status != 0 {
    return status;
  }

  let status = logger_apply();
  if status != 0 {
    return status;
  }

  Status::Success as c_int
}

// C API uses something like the pledge API to select write locations, including:
//
// * stdout (`logger_attach_sink("stdout", LevelFilter_Info)`)
// * stderr (`logger_attach_sink("stderr", LevelFilter_Debug)`)
// * file w/ file path (`logger_attach_sink("file /some/file/path", LevelFilter_Trace)`)
//
// The general flow is:
//
// 1. Call `logger_init` to create a `Dispatch` struct.
// 2. Call `logger_attach_sink` to add an additional sink, using bitflags to set the metadata.
// 3. Call `logger_apply` to finalize the logger and enable logging to the configured sinks.
//
// Once `logger_apply` has been called, any additional calls to `logger_attach_sink` will fail
// with an error indicating the logger has been applied already.
//
// ```
// logger_init();
//
// int result = logger_attach_sink("stderr", FilterLevel_Debug);
// /* handle the error */
//
// int result = logger_attach_sink("file /some/file/path", FilterLevel_Info);
// /* handle the error */
//
// int result = logger_apply();
// /* handle the error */
// ```

/// Initialize the thread-local logger with no sinks.
///
/// This initialized logger does nothing until `logger_apply` has been called.
///
/// # Usage
///
/// ```c
/// logger_init();
/// ```
///
/// # Safety
///
/// This function is always safe to call.
#[no_mangle]
pub extern "C" fn logger_init() {
    set_logger(Dispatch::new());
}

/// Attach an additional sink to the thread-local logger.
///
/// This logger does nothing until `logger_apply` has been called.
///
/// Three types of sinks can be specified:
///
/// - stdout (`logger_attach_sink("stdout", LevelFilter_Info)`)
/// - stderr (`logger_attach_sink("stderr", LevelFilter_Debug)`)
/// - file w/ file path (`logger_attach_sink("file /some/file/path", LevelFilter_Trace)`)
/// - buffer (`logger_attach_sink("buffer", LevelFilter_Debug)`)
///
/// # Usage
///
/// ```c
/// int result = logger_attach_sink("file /some/file/path", LogLevel_Filter);
/// ```
///
/// # Error Handling
///
/// The return error codes are as follows:
///
/// - `-1`: Can't set logger (applying the logger failed, perhaps because one is applied already).
/// - `-2`: No logger has been initialized (call `logger_init` before any other log function).
/// - `-3`: The sink specifier was not UTF-8 encoded.
/// - `-4`: The sink type specified is not a known type (known types: "stdout", "stderr", or "file /some/path").
/// - `-5`: No file path was specified in a file-type sink specification.
/// - `-6`: Opening a sink to the specified file path failed (check permissions).
///
/// # Safety
///
/// This function checks the validity of the passed-in sink specifier, and errors
/// out if the specifier isn't valid UTF-8.
#[allow(clippy::missing_safety_doc)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn logger_attach_sink(
    sink_specifier: *const c_char,
    level_filter: LevelFilter,
) -> c_int {
    // Get the specifier from the raw C string.
    let sink_specifier = unsafe { CStr::from_ptr(sink_specifier) };
    let sink_specifier = match sink_specifier.to_str() {
        Ok(sink_specifier) => sink_specifier,
        // TODO: Permit non-UTF8 strings, as some filesystems may have non-UTF8
        //       paths to which the user wants to direct the logging output.
        Err(_) => return Status::SpecifierNotUtf8 as c_int,
    };

    // Attempt to construct a sink from the specifier.
    let sink = match Sink::try_from(sink_specifier) {
        Ok(sink) => sink,
        Err(err) => return Status::from(err) as c_int,
    };

    // Convert from our `#[repr(C)]` LevelFilter to the one from the `log` crate.
    let level_filter: LogLevelFilter = level_filter.into();

    // Construct a dispatcher from the sink and level filter.
    let dispatch = Into::<Dispatch>::into(sink)
        .level(level_filter)
        .format(|out, message, record| {
            out.finish(format_args!(
                "[{}][{}] {}",
                record.level(),
                record.target(),
                message
            ))
        });

    // Take the existing logger, if there is one, add a new sink to it, and put it back.
    let status = match add_sink(dispatch) {
        Ok(_) => Status::Success,
        Err(err) => Status::from(err),
    };

    status as c_int
}

/// Apply the thread-local logger to the program.
///
/// Any attempts to modify the logger after the call to `logger_apply` will fail.
#[no_mangle]
pub extern "C" fn logger_apply() -> c_int {
    let status = match apply_logger() {
        Ok(_) => Status::Success,
        Err(err) => Status::from(err),
    };

    status as c_int
}

/// Fetch the in-memory logger buffer contents. This will only have any contents if the `buffer`
/// sink has been configured to log to. The contents will be allocated on the heap and will need
/// to be freed with `string_delete`.
///
/// Fetches the logs associated with the provided identifier, or uses the "global" one if the
/// identifier is not specified (i.e. NULL).
///
/// Returns a NULL pointer if the buffer can't be fetched. This can occur is there is not
/// sufficient memory to make a copy of the contents or the buffer contains non-UTF-8 characters.
#[no_mangle]
pub extern "C" fn fetch_log_buffer(log_id: *const c_char,) -> *const c_char {
  let id = if log_id.is_null() {
    "global"
  } else {
    unsafe { CStr::from_ptr(log_id) }.to_str().unwrap_or("global")
  };
  match from_utf8(&fetch_buffer_contents(&id.to_string())) {
    Ok(contents) => match to_c(contents) {
      Ok(c_str) => c_str,
      Err(err) => {
        error!("Failed to copy in-memory log buffer - {}", err);
        ptr::null()
      }
    }
    Err(err) => {
      error!("Failed to convert in-memory log buffer to UTF-8 = {}", err);
      ptr::null()
    }
  }
}
<commit_msg>chore: clippy violation<commit_after>//! The public FFI functions for initializing, adding sinks to, and applying a logger.

use std::convert::TryFrom;
use std::ffi::{CStr, CString};
use std::ptr;
use std::str::from_utf8;

use fern::Dispatch;
use libc::{c_char, c_int};
use log::{error, LevelFilter as LogLevelFilter};

use pact_matching::logging::fetch_buffer_contents;

use crate::error::set_error_msg;
use crate::log::level_filter::LevelFilter;
use crate::log::logger::{add_sink, apply_logger, set_logger};
use crate::log::sink::Sink;
use crate::log::status::Status;
use crate::util::string::to_c;

/// Convenience function to direct all logging to stdout.
#[no_mangle]
pub extern "C" fn log_to_stdout(level_filter: LevelFilter) -> c_int {
    logger_init();

    let spec = match CString::new("stdout") {
        Ok(spec) => spec,
        Err(e) => {
            set_error_msg(e.to_string());
            return Status::CantConstructSink as c_int;
        }
    };

    let status = logger_attach_sink(spec.as_ptr(), level_filter);
    if status != 0 {
        return status;
    }

    let status = logger_apply();
    if status != 0 {
        return status;
    }

    Status::Success as c_int
}

/// Convenience function to direct all logging to stderr.
#[no_mangle]
pub extern "C" fn log_to_stderr(level_filter: LevelFilter) -> c_int {
    logger_init();

    let spec = match CString::new("stderr") {
        Ok(spec) => spec,
        Err(e) => {
            set_error_msg(e.to_string());
            return Status::CantConstructSink as c_int;
        }
    };

    let status = logger_attach_sink(spec.as_ptr(), level_filter);
    if status != 0 {
        return status;
    }

    let status = logger_apply();
    if status != 0 {
        return status;
    }

    Status::Success as c_int
}

/// Convenience function to direct all logging to a file.
#[no_mangle]
pub unsafe extern "C" fn log_to_file(
    file_name: *const c_char,
    level_filter: LevelFilter,
) -> c_int {
    logger_init();

    let spec = {
        if file_name.is_null() {
            return Status::CantConstructSink as c_int;
        }

        let file_name =
            match CStr::from_ptr(file_name).to_str() {
                Ok(file_name) => file_name,
                Err(e) => {
                    set_error_msg(e.to_string());
                    return Status::CantConstructSink as c_int;
                }
            };

        let spec = format!("file {}", file_name);

        match CString::new(spec) {
            Ok(spec) => spec,
            Err(e) => {
                set_error_msg(e.to_string());
                return Status::CantConstructSink as c_int;
            }
        }
    };

    let status = logger_attach_sink(spec.as_ptr(), level_filter);
    if status != 0 {
        return status;
    }

    let status = logger_apply();
    if status != 0 {
        return status;
    }

    Status::Success as c_int
}

/// Convenience function to direct all logging to a thread local memory buffer.
#[no_mangle]
pub extern "C" fn log_to_buffer(level_filter: LevelFilter) -> c_int {
  logger_init();

  let spec = match CString::new("buffer") {
    Ok(spec) => spec,
    Err(e) => {
      set_error_msg(e.to_string());
      return Status::CantConstructSink as c_int;
    }
  };

  let status = logger_attach_sink(spec.as_ptr(), level_filter);
  if status != 0 {
    return status;
  }

  let status = logger_apply();
  if status != 0 {
    return status;
  }

  Status::Success as c_int
}

// C API uses something like the pledge API to select write locations, including:
//
// * stdout (`logger_attach_sink("stdout", LevelFilter_Info)`)
// * stderr (`logger_attach_sink("stderr", LevelFilter_Debug)`)
// * file w/ file path (`logger_attach_sink("file /some/file/path", LevelFilter_Trace)`)
//
// The general flow is:
//
// 1. Call `logger_init` to create a `Dispatch` struct.
// 2. Call `logger_attach_sink` to add an additional sink, using bitflags to set the metadata.
// 3. Call `logger_apply` to finalize the logger and enable logging to the configured sinks.
//
// Once `logger_apply` has been called, any additional calls to `logger_attach_sink` will fail
// with an error indicating the logger has been applied already.
//
// ```
// logger_init();
//
// int result = logger_attach_sink("stderr", FilterLevel_Debug);
// /* handle the error */
//
// int result = logger_attach_sink("file /some/file/path", FilterLevel_Info);
// /* handle the error */
//
// int result = logger_apply();
// /* handle the error */
// ```

/// Initialize the thread-local logger with no sinks.
///
/// This initialized logger does nothing until `logger_apply` has been called.
///
/// # Usage
///
/// ```c
/// logger_init();
/// ```
///
/// # Safety
///
/// This function is always safe to call.
#[no_mangle]
pub extern "C" fn logger_init() {
    set_logger(Dispatch::new());
}

/// Attach an additional sink to the thread-local logger.
///
/// This logger does nothing until `logger_apply` has been called.
///
/// Three types of sinks can be specified:
///
/// - stdout (`logger_attach_sink("stdout", LevelFilter_Info)`)
/// - stderr (`logger_attach_sink("stderr", LevelFilter_Debug)`)
/// - file w/ file path (`logger_attach_sink("file /some/file/path", LevelFilter_Trace)`)
/// - buffer (`logger_attach_sink("buffer", LevelFilter_Debug)`)
///
/// # Usage
///
/// ```c
/// int result = logger_attach_sink("file /some/file/path", LogLevel_Filter);
/// ```
///
/// # Error Handling
///
/// The return error codes are as follows:
///
/// - `-1`: Can't set logger (applying the logger failed, perhaps because one is applied already).
/// - `-2`: No logger has been initialized (call `logger_init` before any other log function).
/// - `-3`: The sink specifier was not UTF-8 encoded.
/// - `-4`: The sink type specified is not a known type (known types: "stdout", "stderr", or "file /some/path").
/// - `-5`: No file path was specified in a file-type sink specification.
/// - `-6`: Opening a sink to the specified file path failed (check permissions).
///
/// # Safety
///
/// This function checks the validity of the passed-in sink specifier, and errors
/// out if the specifier isn't valid UTF-8.
#[allow(clippy::missing_safety_doc)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[no_mangle]
pub extern "C" fn logger_attach_sink(
    sink_specifier: *const c_char,
    level_filter: LevelFilter,
) -> c_int {
    // Get the specifier from the raw C string.
    let sink_specifier = unsafe { CStr::from_ptr(sink_specifier) };
    let sink_specifier = match sink_specifier.to_str() {
        Ok(sink_specifier) => sink_specifier,
        // TODO: Permit non-UTF8 strings, as some filesystems may have non-UTF8
        //       paths to which the user wants to direct the logging output.
        Err(_) => return Status::SpecifierNotUtf8 as c_int,
    };

    // Attempt to construct a sink from the specifier.
    let sink = match Sink::try_from(sink_specifier) {
        Ok(sink) => sink,
        Err(err) => return Status::from(err) as c_int,
    };

    // Convert from our `#[repr(C)]` LevelFilter to the one from the `log` crate.
    let level_filter: LogLevelFilter = level_filter.into();

    // Construct a dispatcher from the sink and level filter.
    let dispatch = Into::<Dispatch>::into(sink)
        .level(level_filter)
        .format(|out, message, record| {
            out.finish(format_args!(
                "[{}][{}] {}",
                record.level(),
                record.target(),
                message
            ))
        });

    // Take the existing logger, if there is one, add a new sink to it, and put it back.
    let status = match add_sink(dispatch) {
        Ok(_) => Status::Success,
        Err(err) => Status::from(err),
    };

    status as c_int
}

/// Apply the thread-local logger to the program.
///
/// Any attempts to modify the logger after the call to `logger_apply` will fail.
#[no_mangle]
pub extern "C" fn logger_apply() -> c_int {
    let status = match apply_logger() {
        Ok(_) => Status::Success,
        Err(err) => Status::from(err),
    };

    status as c_int
}

/// Fetch the in-memory logger buffer contents. This will only have any contents if the `buffer`
/// sink has been configured to log to. The contents will be allocated on the heap and will need
/// to be freed with `string_delete`.
///
/// Fetches the logs associated with the provided identifier, or uses the "global" one if the
/// identifier is not specified (i.e. NULL).
///
/// Returns a NULL pointer if the buffer can't be fetched. This can occur is there is not
/// sufficient memory to make a copy of the contents or the buffer contains non-UTF-8 characters.
#[no_mangle]
pub unsafe extern "C" fn fetch_log_buffer(log_id: *const c_char,) -> *const c_char {
  let id = if log_id.is_null() {
    "global"
  } else {
    CStr::from_ptr(log_id).to_str().unwrap_or("global")
  };
  match from_utf8(&fetch_buffer_contents(&id.to_string())) {
    Ok(contents) => match to_c(contents) {
      Ok(c_str) => c_str,
      Err(err) => {
        error!("Failed to copy in-memory log buffer - {}", err);
        ptr::null()
      }
    }
    Err(err) => {
      error!("Failed to convert in-memory log buffer to UTF-8 = {}", err);
      ptr::null()
    }
  }
}
<|endoftext|>


<commit_before>use base::*;

pub struct Downmixer {
    active_channels: PerChannel<bool>,
}

impl Downmixer {
    pub fn new(channels: PerChannel<bool>) -> Downmixer {
        Downmixer {
            active_channels: channels,
        }
    }

    pub fn set_channel_active(&mut self, c: ChannelPos, active: bool) {
        self.active_channels.set(c, active);
    }

    fn have_channel(&self, c: ChannelPos) -> bool {
        self.active_channels.get(c) == Some(&true)
    }

    fn downmix_channel(&self, frame: &mut Frame, c: ChannelPos, out: &[(ChannelPos, f32)]) {
        if self.have_channel(c) {
            return;
        }
        let in_pcm = match frame.take_channel(c) {
            None => return,
            Some(in_pcm) => in_pcm,
        };

        for &(c, level) in out {
            let out_pcm = frame.ensure_channel(c);
            for i in 0..out_pcm.len() {
                out_pcm[i] += in_pcm[i] * level;
            }
        }
    }

    pub fn process(&self, mut frame: Frame) -> Frame {
        self.downmix_channel(
            &mut frame,
            ChannelPos::Sub,
            &[
                (ChannelPos::FL, 0.5 * SUBWOOFER_LEVEL),
                (ChannelPos::FL, 0.5 * SUBWOOFER_LEVEL),
            ],
        );
        self.downmix_channel(
            &mut frame,
            ChannelPos::FC,
            &[(ChannelPos::FL, 0.5), (ChannelPos::FL, 0.5)],
        );
        self.downmix_channel(&mut frame, ChannelPos::SL, &[(ChannelPos::FL, 1.0)]);
        self.downmix_channel(&mut frame, ChannelPos::SR, &[(ChannelPos::FR, 1.0)]);
        if self.have_channel(ChannelPos::SL) && self.have_channel(ChannelPos::SR) {
            self.downmix_channel(
                &mut frame,
                ChannelPos::SC,
                &[(ChannelPos::SL, 0.5), (ChannelPos::SL, 0.5)],
            );
        } else {
            self.downmix_channel(
                &mut frame,
                ChannelPos::SC,
                &[(ChannelPos::FL, 0.5), (ChannelPos::FL, 0.5)],
            );
        }
        frame
    }
}
<commit_msg>Fix downmixer<commit_after>use base::*;

pub struct Downmixer {
    active_channels: PerChannel<bool>,
}

impl Downmixer {
    pub fn new(channels: PerChannel<bool>) -> Downmixer {
        Downmixer {
            active_channels: channels,
        }
    }

    pub fn set_channel_active(&mut self, c: ChannelPos, active: bool) {
        self.active_channels.set(c, active);
    }

    fn have_channel(&self, c: ChannelPos) -> bool {
        self.active_channels.get(c) == Some(&true)
    }

    fn downmix_channel(&self, frame: &mut Frame, c: ChannelPos, out: &[(ChannelPos, f32)]) {
        if self.have_channel(c) {
            return;
        }
        let in_pcm = match frame.take_channel(c) {
            None => return,
            Some(in_pcm) => in_pcm,
        };

        for &(c, level) in out {
            let out_pcm = frame.ensure_channel(c);
            for i in 0..out_pcm.len() {
                out_pcm[i] += in_pcm[i] * level;
            }
        }
    }

    pub fn process(&self, mut frame: Frame) -> Frame {
        self.downmix_channel(
            &mut frame,
            ChannelPos::Sub,
            &[
                (ChannelPos::FL, 0.5 * SUBWOOFER_LEVEL),
                (ChannelPos::FL, 0.5 * SUBWOOFER_LEVEL),
            ],
        );
        self.downmix_channel(
            &mut frame,
            ChannelPos::FC,
            &[(ChannelPos::FL, 0.5), (ChannelPos::FR, 0.5)],
        );
        self.downmix_channel(&mut frame, ChannelPos::SL, &[(ChannelPos::FL, 1.0)]);
        self.downmix_channel(&mut frame, ChannelPos::SR, &[(ChannelPos::FR, 1.0)]);
        if self.have_channel(ChannelPos::SL) && self.have_channel(ChannelPos::SR) {
            self.downmix_channel(
                &mut frame,
                ChannelPos::SC,
                &[(ChannelPos::SL, 0.5), (ChannelPos::SR, 0.5)],
            );
        } else {
            self.downmix_channel(
                &mut frame,
                ChannelPos::SC,
                &[(ChannelPos::FL, 0.5), (ChannelPos::FR, 0.5)],
            );
        }
        frame
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * 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 super::{Drawable, BoundingBox, MeasureMode};
use ::elements::{Element};
use ::paint::{Canvas, Point, Rect};
use ::platform::Context;
use ::props::{Color};

pub type StrokeWidthReader<T> = fn(&T) -> f32;
pub type ColorReader<T> = fn(&T) -> &Color;

pub enum LineParam {
    Fixed { start: Point, end: Point },
    Vertical { x: f32 },
    Horizontal { y: f32 },
}

pub struct Line<'a, T: Element + 'a> {
    param: LineParam,

    element: &'a T,
    stroke_width_reader: StrokeWidthReader<T>,
    color_reader: ColorReader<T>,

    bounding_box: BoundingBox,
    start: Point,
    end: Point,
}

impl<'a, T: Element + 'a> Drawable for Line<'a, T> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        canvas.draw_line(
            &self.start,
            &self.end,
            (self.color_reader)(self.element),
            (self.stroke_width_reader)(self.element),
        )
    }

    fn calculate(&mut self, context: &Context, width_mode: &MeasureMode, height_mode: &MeasureMode) {
        let (start, end) = match self.param {
            LineParam::Fixed { ref start, ref end } => {
                (start.clone(), end.clone())
            },
            LineParam::Vertical { x } => {
                (
                    Point::new(x, 0.),
                    Point::new(x, if let MeasureMode::UpTo(height) = *height_mode { height } else { 0. })
                )
            },
            LineParam::Horizontal { y } => {
                (
                    Point::new(0., y),
                    Point::new(if let MeasureMode::UpTo(width) = *width_mode { width } else { 0. }, y)
                )
            }
        };

        let stroke_width = (self.stroke_width_reader)(self.element);

        let slope = (start.y()-end.y()).abs() / (start.x()-end.x()).abs();
        let angle = slope.atan();
        let x_diff = angle.sin()*stroke_width/2.;
        let y_diff = angle.cos()*stroke_width/2.;

        println!("Slope: {}, Angle: {}, x_diff: {}, y_diff: {}", slope, angle, x_diff, y_diff);

        let width = (start.x()-end.x()).abs()+(x_diff*2.);
        let height = (start.y()-end.y()).abs()+(y_diff*2.);

        self.start = &start+&Point::new(x_diff, y_diff);
        self.end = &end+&Point::new(x_diff, y_diff);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: height/2.,
            axis: height/2.,
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a, T: Element + 'a> Line<'a, T> {
    pub fn new(param: LineParam, element: &'a T, stroke_width_reader: StrokeWidthReader<T>,
               color_reader: ColorReader<T>) -> Line<'a, T> {
        Line {
            param,
            element,
            stroke_width_reader,
            color_reader,
            bounding_box: BoundingBox::default(),
            start: Point::new(0., 0.),
            end: Point::new(0., 0.),
        }
    }
}

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

    struct MockElement;
    impl Element for MockElement {
        fn layout<'a>(&'a self, context: &Context) -> Box<Drawable + 'a> {
            unimplemented!()
        }
    }

    #[test]
    fn it_work_vertically() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Vertical { x: 10. },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::UpTo(100.));

        assert_eq!(line.bounding_box().width(), 5.);
        assert_eq!(line.bounding_box().height(), 100.);
    }

    #[test]
    fn it_work_horizontally() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Horizontal { y: 10. },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::UpTo(100.), &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 100.);
        assert_eq!(line.bounding_box().height(), 5.);
    }

    #[test]
    fn it_works_when_inclined() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(10., 10.) },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 13.535534);
        assert_eq!(line.bounding_box().height(), 13.535534);
    }
}<commit_msg>Cleanup<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * 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 super::{Drawable, BoundingBox, MeasureMode};
use ::elements::{Element};
use ::paint::{Canvas, Point, Rect};
use ::platform::Context;
use ::props::{Color};

pub type StrokeWidthReader<T> = fn(&T) -> f32;
pub type ColorReader<T> = fn(&T) -> &Color;

pub enum LineParam {
    Fixed { start: Point, end: Point },
    Vertical { x: f32 },
    Horizontal { y: f32 },
}

pub struct Line<'a, T: Element + 'a> {
    param: LineParam,

    element: &'a T,
    stroke_width_reader: StrokeWidthReader<T>,
    color_reader: ColorReader<T>,

    bounding_box: BoundingBox,
    start: Point,
    end: Point,
}

impl<'a, T: Element + 'a> Drawable for Line<'a, T> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        canvas.draw_line(
            &self.start,
            &self.end,
            (self.color_reader)(self.element),
            (self.stroke_width_reader)(self.element),
        )
    }

    fn calculate(&mut self, context: &Context, width_mode: &MeasureMode, height_mode: &MeasureMode) {
        let (start, end) = match self.param {
            LineParam::Fixed { ref start, ref end } => {
                (start.clone(), end.clone())
            },
            LineParam::Vertical { x } => {
                (
                    Point::new(x, 0.),
                    Point::new(x, if let MeasureMode::UpTo(height) = *height_mode { height } else { 0. })
                )
            },
            LineParam::Horizontal { y } => {
                (
                    Point::new(0., y),
                    Point::new(if let MeasureMode::UpTo(width) = *width_mode { width } else { 0. }, y)
                )
            }
        };

        let stroke_width = (self.stroke_width_reader)(self.element);

        let slope = (start.y()-end.y()).abs() / (start.x()-end.x()).abs();
        let angle = slope.atan();
        let x_diff = angle.sin()*stroke_width/2.;
        let y_diff = angle.cos()*stroke_width/2.;

        let width = (start.x()-end.x()).abs()+(x_diff*2.);
        let height = (start.y()-end.y()).abs()+(y_diff*2.);

        self.start = &start+&Point::new(x_diff, y_diff);
        self.end = &end+&Point::new(x_diff, y_diff);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: height/2.,
            axis: height/2.,
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a, T: Element + 'a> Line<'a, T> {
    pub fn new(param: LineParam, element: &'a T, stroke_width_reader: StrokeWidthReader<T>,
               color_reader: ColorReader<T>) -> Line<'a, T> {
        Line {
            param,
            element,
            stroke_width_reader,
            color_reader,
            bounding_box: BoundingBox::default(),
            start: Point::new(0., 0.),
            end: Point::new(0., 0.),
        }
    }
}

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

    struct MockElement;
    impl Element for MockElement {
        fn layout<'a>(&'a self, context: &Context) -> Box<Drawable + 'a> {
            unimplemented!()
        }
    }

    #[test]
    fn it_work_vertically() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Vertical { x: 10. },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::UpTo(100.));

        assert_eq!(line.bounding_box().width(), 5.);
        assert_eq!(line.bounding_box().height(), 100.);
    }

    #[test]
    fn it_work_horizontally() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Horizontal { y: 10. },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::UpTo(100.), &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 100.);
        assert_eq!(line.bounding_box().height(), 5.);
    }

    #[test]
    fn it_works_when_inclined() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(10., 10.) },
            &element,
            |_| 5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 13.535534);
        assert_eq!(line.bounding_box().height(), 13.535534);
    }
}<|endoftext|>