<commit_before>// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![cfg_attr(
  feature = "cargo-clippy",
  deny(
    clippy,
    default_trait_access,
    expl_impl_clone_on_copy,
    if_not_else,
    needless_continue,
    single_match_else,
    unseparated_literal_suffix,
    used_underscore_binding
  )
)]
// It is often more clear to show that nothing is being moved.
#![cfg_attr(feature = "cargo-clippy", allow(match_ref_pats))]
// Subjective style.
#![cfg_attr(
  feature = "cargo-clippy",
  allow(len_without_is_empty, redundant_field_names)
)]
// Default isn't as big a deal as people seem to think it is.
#![cfg_attr(
  feature = "cargo-clippy",
  allow(new_without_default, new_without_default_derive)
)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![cfg_attr(feature = "cargo-clippy", allow(mutex_atomic))]

extern crate rand;
extern crate termion;
extern crate unicode_segmentation;

use std::collections::{BTreeMap, VecDeque};
use std::io::Write;
use std::io::{stdout, Result, Stdout};
use std::thread;
use std::time::Duration;

use termion::cursor::DetectCursorPos;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;
use termion::{clear, color, cursor};
use unicode_segmentation::UnicodeSegmentation;

enum Console {
  Terminal(RawTerminal<Stdout>),
  Pipe(Stdout),
}

pub struct EngineDisplay {
  sigil: char,
  divider: String,
  poll_interval_ms: Duration,
  padding: String,
  terminal: Console,
  action_map: BTreeMap<String, String>,
  logs: VecDeque<String>,
  running: bool,
  cursor_start: (u16, u16),
  terminal_size: (u16, u16),
}

// TODO: Prescribe a threading/polling strategy for callers - or implement a built-in one.
// TODO: Better error handling for .flush() and .write() failure modes.
// TODO: Permit scrollback in the terminal - both at exit and during the live run.
impl EngineDisplay {
  /// Create a EngineDisplay only if stdout is tty and v2 ui is enabled.
  pub fn create(display_worker_count: usize, should_render_ui: bool) -> Option<EngineDisplay> {
    if should_render_ui && termion::is_tty(&stdout()) {
      let mut display = EngineDisplay::for_stdout(0);
      display.initialize(display_worker_count);
      Some(display)
    } else {
      None
    }
  }

  fn initialize(&mut self, display_worker_count: usize) {
    self.start();
    let worker_ids: Vec<String> = (0..display_worker_count)
      .map(|s| format!("{}", s))
      .collect();
    for worker_id in worker_ids {
      self.add_worker(worker_id);
    }
    self.render();
  }

  pub fn for_stdout(indent_level: u16) -> EngineDisplay {
    let write_handle = stdout();

    EngineDisplay {
      sigil: '⚡',
      divider: "▵".to_string(),
      poll_interval_ms: Duration::from_millis(55),
      padding: " ".repeat(indent_level.into()),
      terminal: match write_handle.into_raw_mode() {
        Ok(t) => Console::Terminal(t),
        Err(_) => Console::Pipe(stdout()),
      },
      action_map: BTreeMap::new(),
      // This is arbitrary based on a guesstimated peak terminal row size for modern displays.
      // The reason this can't be capped to e.g. the starting size is because of resizing - we
      // want to be able to fill the entire screen if resized much larger than when we started.
      logs: VecDeque::with_capacity(500),
      running: false,
      // N.B. This will cause the screen to clear - but with some improved position
      // tracking logic we could avoid screen clearing in favor of using the value
      // of `EngineDisplay::get_cursor_pos()` as initialization here. From there, the
      // trick would be to push the on-screen text screen up (ideally, prior to entering
      // raw mode) via newline printing - and then ensuring the rendered text never
      // overflows past the screen row bounds. Before we could safely do that tho, we
      // probably want to plumb a signal handler for SIGWINCH so that ^L works to redraw
      // the screen in the case of any display issues. Otherwise, simply clearing the screen
      // as we've done here is the safest way to avoid terminal oddness.
      cursor_start: (1, 1),
      terminal_size: EngineDisplay::get_size(),
    }
  }

  // Gets the current terminal's cursor position, if applicable.
  fn get_cursor_pos(&mut self) -> (u16, u16) {
    match self.terminal {
      // N.B. Real TTY coordinates start at (1, 1).
      Console::Terminal(ref mut t) => t.cursor_pos().unwrap_or((0, 0)),
      Console::Pipe(_) => (0, 0),
    }
  }

  // Gets the current terminal's width and height, if applicable.
  fn get_size() -> (u16, u16) {
    termion::terminal_size().unwrap_or((0, 0))
  }

  // Whether or not the EngineDisplay is running (whether .start() has been called).
  pub fn is_running(&self) -> bool {
    self.running
  }

  // Sets the terminal size per-render for signal-free resize detection.
  fn set_size(&mut self) {
    self.terminal_size = EngineDisplay::get_size();
  }

  // Sets the terminal size for signal-free resize detection.
  fn get_max_log_rows(&self) -> usize {
    // TODO: If the terminal size is smaller than the action map, we should fall back
    // to non-tty mode output to avoid.
    self.terminal_size.1 as usize - self.action_map.len() - 1
  }

  // Prep the screen for painting by clearing it from the cursor start position.
  fn clear(&mut self) {
    let cursor_start = self.cursor_start;
    self
      .write(&format!(
        "{goto_origin}{clear}",
        goto_origin = cursor::Goto(cursor_start.0, cursor_start.1),
        clear = clear::AfterCursor,
      )).expect("could not write to terminal");
  }

  // Flush terminal output.
  fn flush(&mut self) -> Result<()> {
    match self.terminal {
      Console::Terminal(ref mut t) => t.flush(),
      Console::Pipe(ref mut p) => p.flush(),
    }
  }

  // Writes output to the terminal.
  fn write(&mut self, msg: &str) -> Result<usize> {
    let res = match self.terminal {
      Console::Terminal(ref mut t) => t.write(msg.as_bytes()),
      Console::Pipe(ref mut p) => p.write(msg.as_bytes()),
    };
    self.flush();
    res
  }

  // Renders a divider between the logs and action output.
  fn render_divider(&mut self, offset: u16) {
    let cursor_start = self.cursor_start;
    let padding = self.padding.clone();
    let divider = self.divider.clone();

    self
      .write(&format!(
        "{pos}{clear_line}{padding}{blue}{divider}{reset}",
        pos = cursor::Goto(1, cursor_start.1 + offset),
        clear_line = clear::CurrentLine,
        padding = padding,
        blue = color::Fg(color::Blue),
        divider = divider,
        reset = color::Fg(color::Reset)
      )).expect("could not write to terminal");
  }

  // Renders one frame of the log portion of the screen.
  fn render_logs(&mut self, max_entries: usize) -> usize {
    let cursor_start = self.cursor_start;
    let printable_logs: Vec<String> = self.logs.iter().take(max_entries).cloned().collect();

    let mut counter: usize = 0;
    for (n, log_entry) in printable_logs.iter().rev().enumerate() {
      counter += 1;
      let line_shortened_log_entry: String = format!(
        "{padding}{log_entry}",
        padding = self.padding,
        log_entry = log_entry
      ).graphemes(true)
      .take(self.terminal_size.0 as usize)
      .collect();

      self
        .write(&format!(
          "{pos}{clear_line}{entry}",
          pos = cursor::Goto(1, cursor_start.1 + n as u16),
          clear_line = clear::CurrentLine,
          entry = line_shortened_log_entry
        )).expect("could not write to terminal");
    }

    if counter > 0 {
      self.render_divider(counter as u16);
      counter += 1;
    }
    counter
  }

  // Renders one frame of the action portion of the screen.
  fn render_actions(&mut self, start_row: usize) {
    let cursor_start = self.cursor_start;
    let worker_states = self.action_map.clone();

    // For every active worker in the action map, jump to the exact cursor
    // representing the swimlane for this worker and lay down a text label.
    for (n, (_worker_id, action)) in worker_states.iter().enumerate() {
      let line_shortened_output: String = format!(
        "{padding}{blue}{sigil}{reset}{action}",
        padding = self.padding,
        blue = color::Fg(color::LightBlue),
        sigil = self.sigil,
        reset = color::Fg(color::Reset),
        action = action
      ).graphemes(true)
      // Account for control characters.
      .take(self.terminal_size.0 as usize + 14)
      .collect();

      self
        .write(&format!(
          "{pos}{entry}",
          pos = cursor::Goto(1, cursor_start.1 + start_row as u16 + n as u16),
          entry = line_shortened_output
        )).expect("could not write to terminal");
    }
  }

  // Paints one screen of rendering.
  fn render_for_tty(&mut self) {
    self.set_size();
    self.clear();
    let max_log_rows = self.get_max_log_rows();
    let rendered_count = self.render_logs(max_log_rows);
    self.render_actions(rendered_count);
    self.flush().expect("could not flush terminal!");
  }

  // Paints one screen of rendering.
  pub fn render(&mut self) {
    self.render_for_tty()
  }

  // Paints one screen of rendering and sleeps for the poll interval.
  pub fn render_and_sleep(&mut self) {
    self.render();
    thread::sleep(self.poll_interval_ms);
  }

  // Starts the EngineDisplay at the current cursor position.
  pub fn start(&mut self) {
    self.running = true;
    let cursor_start = self.cursor_start;
    self
      .write(&format!(
        "{hide_cursor}{cursor_init}{clear_after_cursor}",
        hide_cursor = termion::cursor::Hide,
        cursor_init = cursor::Goto(cursor_start.0, cursor_start.1),
        clear_after_cursor = clear::AfterCursor
      )).expect("could not write to terminal");
  }

  // Adds a worker/thread to the visual representation.
  pub fn add_worker(&mut self, worker_name: String) {
    let action_msg = format!("booting {}", worker_name);
    self.update(worker_name, action_msg);
  }

  // Updates the status of a worker/thread.
  pub fn update(&mut self, worker_name: String, action: String) {
    self.action_map.insert(worker_name, action);
  }

  // Removes a worker/thread from the visual representation.
  pub fn remove_worker(&mut self, worker_id: &str) {
    self.action_map.remove(worker_id);
  }

  // Adds a log entry for display.
  pub fn log(&mut self, log_entry: String) {
    self.logs.push_front(log_entry)
  }

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

  // Terminates the EngineDisplay and returns the cursor to a static position.
  pub fn finish(&mut self) {
    self.running = false;
    let current_pos = self.get_cursor_pos();
    let action_count = self.action_map.len() as u16;
    self
      .write(&format!(
        "{park_cursor}{clear_after_cursor}{reveal_cursor}",
        park_cursor = cursor::Goto(1, current_pos.1 - action_count),
        clear_after_cursor = clear::AfterCursor,
        reveal_cursor = termion::cursor::Show
      )).expect("could not write to terminal");
  }
}
<commit_msg>Fix unused error value. (#6834)<commit_after>// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![cfg_attr(
  feature = "cargo-clippy",
  deny(
    clippy,
    default_trait_access,
    expl_impl_clone_on_copy,
    if_not_else,
    needless_continue,
    single_match_else,
    unseparated_literal_suffix,
    used_underscore_binding
  )
)]
// It is often more clear to show that nothing is being moved.
#![cfg_attr(feature = "cargo-clippy", allow(match_ref_pats))]
// Subjective style.
#![cfg_attr(
  feature = "cargo-clippy",
  allow(len_without_is_empty, redundant_field_names)
)]
// Default isn't as big a deal as people seem to think it is.
#![cfg_attr(
  feature = "cargo-clippy",
  allow(new_without_default, new_without_default_derive)
)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![cfg_attr(feature = "cargo-clippy", allow(mutex_atomic))]

extern crate rand;
extern crate termion;
extern crate unicode_segmentation;

use std::collections::{BTreeMap, VecDeque};
use std::io::Write;
use std::io::{stdout, Result, Stdout};
use std::thread;
use std::time::Duration;

use termion::cursor::DetectCursorPos;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;
use termion::{clear, color, cursor};
use unicode_segmentation::UnicodeSegmentation;

enum Console {
  Terminal(RawTerminal<Stdout>),
  Pipe(Stdout),
}

pub struct EngineDisplay {
  sigil: char,
  divider: String,
  poll_interval_ms: Duration,
  padding: String,
  terminal: Console,
  action_map: BTreeMap<String, String>,
  logs: VecDeque<String>,
  running: bool,
  cursor_start: (u16, u16),
  terminal_size: (u16, u16),
}

// TODO: Prescribe a threading/polling strategy for callers - or implement a built-in one.
// TODO: Better error handling for .flush() and .write() failure modes.
// TODO: Permit scrollback in the terminal - both at exit and during the live run.
impl EngineDisplay {
  /// Create a EngineDisplay only if stdout is tty and v2 ui is enabled.
  pub fn create(display_worker_count: usize, should_render_ui: bool) -> Option<EngineDisplay> {
    if should_render_ui && termion::is_tty(&stdout()) {
      let mut display = EngineDisplay::for_stdout(0);
      display.initialize(display_worker_count);
      Some(display)
    } else {
      None
    }
  }

  fn initialize(&mut self, display_worker_count: usize) {
    self.start();
    let worker_ids: Vec<String> = (0..display_worker_count)
      .map(|s| format!("{}", s))
      .collect();
    for worker_id in worker_ids {
      self.add_worker(worker_id);
    }
    self.render();
  }

  pub fn for_stdout(indent_level: u16) -> EngineDisplay {
    let write_handle = stdout();

    EngineDisplay {
      sigil: '⚡',
      divider: "▵".to_string(),
      poll_interval_ms: Duration::from_millis(55),
      padding: " ".repeat(indent_level.into()),
      terminal: match write_handle.into_raw_mode() {
        Ok(t) => Console::Terminal(t),
        Err(_) => Console::Pipe(stdout()),
      },
      action_map: BTreeMap::new(),
      // This is arbitrary based on a guesstimated peak terminal row size for modern displays.
      // The reason this can't be capped to e.g. the starting size is because of resizing - we
      // want to be able to fill the entire screen if resized much larger than when we started.
      logs: VecDeque::with_capacity(500),
      running: false,
      // N.B. This will cause the screen to clear - but with some improved position
      // tracking logic we could avoid screen clearing in favor of using the value
      // of `EngineDisplay::get_cursor_pos()` as initialization here. From there, the
      // trick would be to push the on-screen text screen up (ideally, prior to entering
      // raw mode) via newline printing - and then ensuring the rendered text never
      // overflows past the screen row bounds. Before we could safely do that tho, we
      // probably want to plumb a signal handler for SIGWINCH so that ^L works to redraw
      // the screen in the case of any display issues. Otherwise, simply clearing the screen
      // as we've done here is the safest way to avoid terminal oddness.
      cursor_start: (1, 1),
      terminal_size: EngineDisplay::get_size(),
    }
  }

  // Gets the current terminal's cursor position, if applicable.
  fn get_cursor_pos(&mut self) -> (u16, u16) {
    match self.terminal {
      // N.B. Real TTY coordinates start at (1, 1).
      Console::Terminal(ref mut t) => t.cursor_pos().unwrap_or((0, 0)),
      Console::Pipe(_) => (0, 0),
    }
  }

  // Gets the current terminal's width and height, if applicable.
  fn get_size() -> (u16, u16) {
    termion::terminal_size().unwrap_or((0, 0))
  }

  // Whether or not the EngineDisplay is running (whether .start() has been called).
  pub fn is_running(&self) -> bool {
    self.running
  }

  // Sets the terminal size per-render for signal-free resize detection.
  fn set_size(&mut self) {
    self.terminal_size = EngineDisplay::get_size();
  }

  // Sets the terminal size for signal-free resize detection.
  fn get_max_log_rows(&self) -> usize {
    // TODO: If the terminal size is smaller than the action map, we should fall back
    // to non-tty mode output to avoid.
    self.terminal_size.1 as usize - self.action_map.len() - 1
  }

  // Prep the screen for painting by clearing it from the cursor start position.
  fn clear(&mut self) {
    let cursor_start = self.cursor_start;
    self
      .write(&format!(
        "{goto_origin}{clear}",
        goto_origin = cursor::Goto(cursor_start.0, cursor_start.1),
        clear = clear::AfterCursor,
      )).expect("could not write to terminal");
  }

  // Flush terminal output.
  fn flush(&mut self) -> Result<()> {
    match self.terminal {
      Console::Terminal(ref mut t) => t.flush(),
      Console::Pipe(ref mut p) => p.flush(),
    }
  }

  // Writes output to the terminal.
  fn write(&mut self, msg: &str) -> Result<usize> {
    let res = match self.terminal {
      Console::Terminal(ref mut t) => t.write(msg.as_bytes()),
      Console::Pipe(ref mut p) => p.write(msg.as_bytes()),
    };
    self.flush()?;
    res
  }

  // Renders a divider between the logs and action output.
  fn render_divider(&mut self, offset: u16) {
    let cursor_start = self.cursor_start;
    let padding = self.padding.clone();
    let divider = self.divider.clone();

    self
      .write(&format!(
        "{pos}{clear_line}{padding}{blue}{divider}{reset}",
        pos = cursor::Goto(1, cursor_start.1 + offset),
        clear_line = clear::CurrentLine,
        padding = padding,
        blue = color::Fg(color::Blue),
        divider = divider,
        reset = color::Fg(color::Reset)
      )).expect("could not write to terminal");
  }

  // Renders one frame of the log portion of the screen.
  fn render_logs(&mut self, max_entries: usize) -> usize {
    let cursor_start = self.cursor_start;
    let printable_logs: Vec<String> = self.logs.iter().take(max_entries).cloned().collect();

    let mut counter: usize = 0;
    for (n, log_entry) in printable_logs.iter().rev().enumerate() {
      counter += 1;
      let line_shortened_log_entry: String = format!(
        "{padding}{log_entry}",
        padding = self.padding,
        log_entry = log_entry
      ).graphemes(true)
      .take(self.terminal_size.0 as usize)
      .collect();

      self
        .write(&format!(
          "{pos}{clear_line}{entry}",
          pos = cursor::Goto(1, cursor_start.1 + n as u16),
          clear_line = clear::CurrentLine,
          entry = line_shortened_log_entry
        )).expect("could not write to terminal");
    }

    if counter > 0 {
      self.render_divider(counter as u16);
      counter += 1;
    }
    counter
  }

  // Renders one frame of the action portion of the screen.
  fn render_actions(&mut self, start_row: usize) {
    let cursor_start = self.cursor_start;
    let worker_states = self.action_map.clone();

    // For every active worker in the action map, jump to the exact cursor
    // representing the swimlane for this worker and lay down a text label.
    for (n, (_worker_id, action)) in worker_states.iter().enumerate() {
      let line_shortened_output: String = format!(
        "{padding}{blue}{sigil}{reset}{action}",
        padding = self.padding,
        blue = color::Fg(color::LightBlue),
        sigil = self.sigil,
        reset = color::Fg(color::Reset),
        action = action
      ).graphemes(true)
      // Account for control characters.
      .take(self.terminal_size.0 as usize + 14)
      .collect();

      self
        .write(&format!(
          "{pos}{entry}",
          pos = cursor::Goto(1, cursor_start.1 + start_row as u16 + n as u16),
          entry = line_shortened_output
        )).expect("could not write to terminal");
    }
  }

  // Paints one screen of rendering.
  fn render_for_tty(&mut self) {
    self.set_size();
    self.clear();
    let max_log_rows = self.get_max_log_rows();
    let rendered_count = self.render_logs(max_log_rows);
    self.render_actions(rendered_count);
    self.flush().expect("could not flush terminal!");
  }

  // Paints one screen of rendering.
  pub fn render(&mut self) {
    self.render_for_tty()
  }

  // Paints one screen of rendering and sleeps for the poll interval.
  pub fn render_and_sleep(&mut self) {
    self.render();
    thread::sleep(self.poll_interval_ms);
  }

  // Starts the EngineDisplay at the current cursor position.
  pub fn start(&mut self) {
    self.running = true;
    let cursor_start = self.cursor_start;
    self
      .write(&format!(
        "{hide_cursor}{cursor_init}{clear_after_cursor}",
        hide_cursor = termion::cursor::Hide,
        cursor_init = cursor::Goto(cursor_start.0, cursor_start.1),
        clear_after_cursor = clear::AfterCursor
      )).expect("could not write to terminal");
  }

  // Adds a worker/thread to the visual representation.
  pub fn add_worker(&mut self, worker_name: String) {
    let action_msg = format!("booting {}", worker_name);
    self.update(worker_name, action_msg);
  }

  // Updates the status of a worker/thread.
  pub fn update(&mut self, worker_name: String, action: String) {
    self.action_map.insert(worker_name, action);
  }

  // Removes a worker/thread from the visual representation.
  pub fn remove_worker(&mut self, worker_id: &str) {
    self.action_map.remove(worker_id);
  }

  // Adds a log entry for display.
  pub fn log(&mut self, log_entry: String) {
    self.logs.push_front(log_entry)
  }

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

  // Terminates the EngineDisplay and returns the cursor to a static position.
  pub fn finish(&mut self) {
    self.running = false;
    let current_pos = self.get_cursor_pos();
    let action_count = self.action_map.len() as u16;
    self
      .write(&format!(
        "{park_cursor}{clear_after_cursor}{reveal_cursor}",
        park_cursor = cursor::Goto(1, current_pos.1 - action_count),
        clear_after_cursor = clear::AfterCursor,
        reveal_cursor = termion::cursor::Show
      )).expect("could not write to terminal");
  }
}
<|endoftext|>


<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */
extern crate rand;
use self::rand::distributions::{Normal, Range, Sample};
use self::rand::Rng;

use std::usize;
use std::f64;

use super::MCMove;
use super::select_molecule;

use types::Vector3D;
use universe::Universe;

/// Monte-Carlo move for rotating a rigid molecule
pub struct Rotate {
    /// Type of molecule to rotate. `None` means all molecules.
    moltype: Option<u64>,
    /// Index of the molecule to rotate
    molid: usize,
    /// Previous positions for all the particles in the molecule
    prevpos: Vec<Vector3D>,
    /// Normal distribution, for generation of the axis
    axis_rng: Normal,
    /// Range distribution, for generation of the angle
    angle_rng: Range<f64>,
    /// Potential energy before the move
    e_before: f64,
}

impl Rotate {
    /// Create a new `Rotate` move, with maximum angular displacement of `theta`,
    /// rotating all the molecules in the system.
    pub fn new(theta: f64) -> Rotate {
        Rotate::create(theta, None)
    }

    /// Create a new `Rotate` move, with maximum angular displacement of `theta`,
    /// rotating only molecules with `moltype` type.
    pub fn with_moltype(theta: f64, moltype: u64) -> Rotate {
        Rotate::create(theta, Some(moltype))
    }

    // Factorizing the constructors
    fn create(theta: f64, moltype: Option<u64>) -> Rotate {
        assert!(theta > 0.0, "theta must be positive in Rotate move");
        Rotate {
            moltype: moltype,
            molid: usize::MAX,
            prevpos: Vec::new(),
            axis_rng: Normal::new(0.0, 1.0),
            angle_rng: Range::new(-theta, theta),
            e_before: 0.0,
        }
    }
}

impl Default for Rotate {
    fn default() -> Rotate {
        Rotate::new(0.2)
    }
}

impl MCMove for Rotate {
    fn describe(&self) -> &str {
        "molecular rotation"
    }

    fn prepare(&mut self, universe: &mut Universe, rng: &mut Box<Rng>) -> bool {
        if let Some(id) = select_molecule(universe, self.moltype, rng) {
            self.molid = id;
        } else {
            warn!("Can not rotate molecule: no molecule of this type in the universe.");
            return false;
        }

        self.e_before = universe.potential_energy();

        // Getting values from a 3D normal distribution gives an uniform
        // distribution on the R3 sphere.
        let axis = Vector3D::new(
            self.axis_rng.sample(rng),
            self.axis_rng.sample(rng),
            self.axis_rng.sample(rng)
        ).normalized();
        let theta = self.angle_rng.sample(rng);

        self.prevpos = vec![Vector3D::new(0.0, 0.0, 0.0); universe.molecule(self.molid).size()];
        for (i, idx) in universe.molecule(self.molid).iter().enumerate() {
            self.prevpos[i] = universe[idx].position;
        }

        rotate_molecule_around_axis(universe, self.molid, axis, theta);
        return true;
    }

    fn cost(&self, universe: &Universe, beta: f64) -> f64 {
        let e_after = universe.potential_energy();
        return (e_after - self.e_before)/beta;
    }

    fn apply(&mut self, _: &mut Universe) {
        // Nothing to do
    }

    fn restore(&mut self, universe: &mut Universe) {
        for (i, idx) in universe.molecule(self.molid).iter().enumerate() {
            universe[idx].position = self.prevpos[i];
        }
    }
}

/// Rotate the molecule at index `molid` in universe around the `axis` axis by
/// `angle`.
fn rotate_molecule_around_axis(universe: &mut Universe, molid: usize, axis: Vector3D, angle: f64) {
    let molecule = universe.molecule(molid).clone();

    // Get center of mass (com) of the molecule
    let total_mass = molecule.iter().fold(0.0, |total_mass, i| total_mass + universe[i].mass);
    let com = molecule.iter().fold(Vector3D::new(0.0, 0.0, 0.0), |com, i| com + universe[i].position / total_mass);

    for i in &molecule {
        let oldpos = universe[i].position.clone() - com;
        let newpos = com + f64::cos(angle) * oldpos
                         + f64::sin(angle) * axis ^ oldpos
                         + (axis * oldpos) * (1.0 - f64::cos(angle)) * axis;
        universe[i].position = newpos;
    }
}
<commit_msg>Fix rotation of molecules<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */
extern crate rand;
use self::rand::distributions::{Normal, Range, Sample};
use self::rand::Rng;

use std::usize;
use std::f64;

use super::MCMove;
use super::select_molecule;

use types::{Matrix3, Vector3D};
use universe::Universe;

/// Monte-Carlo move for rotating a rigid molecule
pub struct Rotate {
    /// Type of molecule to rotate. `None` means all molecules.
    moltype: Option<u64>,
    /// Index of the molecule to rotate
    molid: usize,
    /// Previous positions for all the particles in the molecule
    prevpos: Vec<Vector3D>,
    /// Normal distribution, for generation of the axis
    axis_rng: Normal,
    /// Range distribution, for generation of the angle
    angle_rng: Range<f64>,
    /// Potential energy before the move
    e_before: f64,
}

impl Rotate {
    /// Create a new `Rotate` move, with maximum angular displacement of `theta`,
    /// rotating all the molecules in the system.
    pub fn new(theta: f64) -> Rotate {
        Rotate::create(theta, None)
    }

    /// Create a new `Rotate` move, with maximum angular displacement of `theta`,
    /// rotating only molecules with `moltype` type.
    pub fn with_moltype(theta: f64, moltype: u64) -> Rotate {
        Rotate::create(theta, Some(moltype))
    }

    // Factorizing the constructors
    fn create(theta: f64, moltype: Option<u64>) -> Rotate {
        assert!(theta > 0.0, "theta must be positive in Rotate move");
        Rotate {
            moltype: moltype,
            molid: usize::MAX,
            prevpos: Vec::new(),
            axis_rng: Normal::new(0.0, 1.0),
            angle_rng: Range::new(-theta, theta),
            e_before: 0.0,
        }
    }
}

impl Default for Rotate {
    fn default() -> Rotate {
        Rotate::new(0.2)
    }
}

impl MCMove for Rotate {
    fn describe(&self) -> &str {
        "molecular rotation"
    }

    fn prepare(&mut self, universe: &mut Universe, rng: &mut Box<Rng>) -> bool {
        if let Some(id) = select_molecule(universe, self.moltype, rng) {
            self.molid = id;
        } else {
            warn!("Can not rotate molecule: no molecule of this type in the universe.");
            return false;
        }

        self.e_before = universe.potential_energy();

        // Getting values from a 3D normal distribution gives an uniform
        // distribution on the R3 sphere.
        let axis = Vector3D::new(
            self.axis_rng.sample(rng),
            self.axis_rng.sample(rng),
            self.axis_rng.sample(rng)
        ).normalized();
        let theta = self.angle_rng.sample(rng);

        self.prevpos = vec![Vector3D::new(0.0, 0.0, 0.0); universe.molecule(self.molid).size()];
        for (i, idx) in universe.molecule(self.molid).iter().enumerate() {
            self.prevpos[i] = universe[idx].position;
        }

        rotate_molecule_around_axis(universe, self.molid, axis, theta);
        return true;
    }

    fn cost(&self, universe: &Universe, beta: f64) -> f64 {
        let e_after = universe.potential_energy();
        return (e_after - self.e_before)/beta;
    }

    fn apply(&mut self, _: &mut Universe) {
        // Nothing to do
    }

    fn restore(&mut self, universe: &mut Universe) {
        for (i, idx) in universe.molecule(self.molid).iter().enumerate() {
            universe[idx].position = self.prevpos[i];
        }
    }
}

/// Rotate the molecule at index `molid` in universe around the `axis` axis by
/// `angle`.
fn rotate_molecule_around_axis(universe: &mut Universe, molid: usize, axis: Vector3D, angle: f64) {
    let molecule = universe.molecule(molid).clone();

    // Get center of mass (com) of the molecule
    let total_mass = molecule.iter().fold(0.0,
        |total_mass, i| total_mass + universe[i].mass
    );
    let com = molecule.iter().fold(Vector3D::new(0.0, 0.0, 0.0),
        |com, i| com + universe[i].position * universe[i].mass / total_mass
    );

    let rotation = rotation_matrix(&axis, angle);
    for i in &molecule {
        let oldpos = universe[i].position.clone() - com;
        universe[i].position = com + rotation * oldpos;
    }
}

fn rotation_matrix(axis: &Vector3D, angle: f64) -> Matrix3 {
    let sn = f64::sin(angle);
    let cs = f64::cos(angle);

    let x_sin = axis.x * sn;
    let y_sin = axis.y * sn;
    let z_sin = axis.z * sn;
    let one_cos = 1.0 - cs;
    let xym = axis.x * axis.y * one_cos;
    let xzm = axis.x * axis.z * one_cos;
    let yzm = axis.y * axis.z * one_cos;

    // Build the rotation matrix
    let rotation = Matrix3::new(
        (axis.x * axis.x) * one_cos + cs,
        xym + z_sin,
        xzm - y_sin,
        xym - z_sin,
        (axis.y * axis.y) * one_cos + cs,
        yzm + x_sin,
        xzm + y_sin,
        yzm - x_sin,
        (axis.z * axis.z) * one_cos + cs
    );

    return rotation;
}
<|endoftext|>


<commit_before>use std::str;
use std::ascii::AsciiExt;
use std::path::{Path, PathBuf};

use kailua_diag::Stop;
use kailua_syntax::Chunk;

pub trait Options {
    // all of those methods return `Err(None)` if the error occurred and has not been reported,
    // or `Err(Some(Stop))` if the error occurred and the caller wants to bail out.
    // if the implementation has a handle to the reporter and wants to do its own reporting,
    // it can report and return `Ok` (recovery) or `Err(Some(Stop))` (error propagation).

    fn set_package_path(&mut self, _path: &[u8]) -> Result<(), Option<Stop>> { Ok(()) }
    fn set_package_cpath(&mut self, _path: &[u8]) -> Result<(), Option<Stop>> { Ok(()) }

    fn require_chunk(&mut self, _path: &[u8]) -> Result<Chunk, Option<Stop>> {
        Err(None)
    }
}

pub trait FsSource {
    // `Ok(Some(chunk))` normally; `Ok(None)` if path doesn't exist and search should continue;
    // `Err(None)` and `Err(Some(Stop))` follow the convention of `Options`.
    fn chunk_from_path(&self, resolved_path: &Path) -> Result<Option<Chunk>, Option<Stop>>;

    fn to_path_buf(&self, path: &[u8]) -> Result<PathBuf, Option<Stop>> {
        // by default we avoid parsing multibyte paths as it depends on the system encoding
        if path.is_ascii() {
            Ok(Path::new(str::from_utf8(path).unwrap()).to_owned())
        } else {
            Err(None)
        }
    }
}

pub struct FsOptions<S> {
    source: S,
    root: PathBuf,
    package_path: Vec<Vec<u8>>,
    package_cpath: Vec<Vec<u8>>,
}

impl<S: FsSource> FsOptions<S> {
    pub fn new(source: S, root: PathBuf) -> FsOptions<S> {
        FsOptions {
            source: source,
            root: root,

            // by default, local files only
            package_path: vec![b"?.lua".to_vec()],
            package_cpath: vec![],
        }
    }

    fn search_file(&self, path: &[u8], search_paths: &[Vec<u8>],
                   suffix: &[u8]) -> Result<Option<Chunk>, Option<Stop>> {
        for template in search_paths {
            let mut newpath = Vec::new();
            for (i, e) in template.split(|&b| b == b'?').enumerate() {
                if i > 0 { newpath.extend_from_slice(path); }
                newpath.extend_from_slice(e);
            }
            newpath.extend_from_slice(suffix);

            let resolved_path = self.root.join(self.source.to_path_buf(&newpath)?);
            debug!("trying to load {:?}", path);

            if let Some(chunk) = self.source.chunk_from_path(&resolved_path)? {
                return Ok(Some(chunk));
            }
        }
        Ok(None)
    }
}

impl<S: FsSource> Options for FsOptions<S> {
    fn set_package_path(&mut self, path: &[u8]) -> Result<(), Option<Stop>> {
        self.package_path = path.split(|&b| b == b';').map(|s| s.to_owned()).collect();
        Ok(())
    }

    fn set_package_cpath(&mut self, path: &[u8]) -> Result<(), Option<Stop>> {
        self.package_cpath = path.split(|&b| b == b';').map(|s| s.to_owned()).collect();
        Ok(())
    }

    fn require_chunk(&mut self, path: &[u8]) -> Result<Chunk, Option<Stop>> {
        if let Some(chunk) = self.search_file(&path, &self.package_path, b".kailua")? {
            return Ok(chunk);
        }
        if let Some(chunk) = self.search_file(&path, &self.package_path, b"")? {
            return Ok(chunk);
        }
        if let Some(chunk) = self.search_file(&path, &self.package_cpath, b".kailua")? {
            return Ok(chunk);
        }
        // avoid loading the native libraries as is

        Err(None)
    }
}

<commit_msg>Fixed `require` behavior on dotted paths.<commit_after>use std::str;
use std::ascii::AsciiExt;
use std::path::{Path, PathBuf, MAIN_SEPARATOR};

use kailua_diag::Stop;
use kailua_syntax::Chunk;

pub trait Options {
    // all of those methods return `Err(None)` if the error occurred and has not been reported,
    // or `Err(Some(Stop))` if the error occurred and the caller wants to bail out.
    // if the implementation has a handle to the reporter and wants to do its own reporting,
    // it can report and return `Ok` (recovery) or `Err(Some(Stop))` (error propagation).

    fn set_package_path(&mut self, _path: &[u8]) -> Result<(), Option<Stop>> { Ok(()) }
    fn set_package_cpath(&mut self, _path: &[u8]) -> Result<(), Option<Stop>> { Ok(()) }

    fn require_chunk(&mut self, _path: &[u8]) -> Result<Chunk, Option<Stop>> {
        Err(None)
    }
}

pub trait FsSource {
    // `Ok(Some(chunk))` normally; `Ok(None)` if path doesn't exist and search should continue;
    // `Err(None)` and `Err(Some(Stop))` follow the convention of `Options`.
    fn chunk_from_path(&self, resolved_path: &Path) -> Result<Option<Chunk>, Option<Stop>>;

    fn to_path_buf(&self, path: &[u8]) -> Result<PathBuf, Option<Stop>> {
        // by default we avoid parsing multibyte paths as it depends on the system encoding
        if path.is_ascii() {
            Ok(Path::new(str::from_utf8(path).unwrap()).to_owned())
        } else {
            Err(None)
        }
    }
}

pub struct FsOptions<S> {
    source: S,
    root: PathBuf,
    package_path: Vec<Vec<u8>>,
    package_cpath: Vec<Vec<u8>>,
}

impl<S: FsSource> FsOptions<S> {
    pub fn new(source: S, root: PathBuf) -> FsOptions<S> {
        FsOptions {
            source: source,
            root: root,

            // by default, local files only
            package_path: vec![b"?.lua".to_vec()],
            package_cpath: vec![],
        }
    }

    fn search_file(&self, path: &[u8], search_paths: &[Vec<u8>],
                   suffix: &[u8]) -> Result<Option<Chunk>, Option<Stop>> {
        for template in search_paths {
            let mut newpath = Vec::new();
            for (i, e) in template.split(|&b| b == b'?').enumerate() {
                if i > 0 {
                    newpath.extend(path.iter().map(|&b| {
                        if b == b'.' { MAIN_SEPARATOR as u8 } else { b }
                    }));
                }
                newpath.extend_from_slice(e);
            }
            newpath.extend_from_slice(suffix);

            let resolved_path = self.root.join(self.source.to_path_buf(&newpath)?);
            debug!("trying to load {:?}", path);

            if let Some(chunk) = self.source.chunk_from_path(&resolved_path)? {
                return Ok(Some(chunk));
            }
        }
        Ok(None)
    }
}

impl<S: FsSource> Options for FsOptions<S> {
    fn set_package_path(&mut self, path: &[u8]) -> Result<(), Option<Stop>> {
        self.package_path = path.split(|&b| b == b';').map(|s| s.to_owned()).collect();
        Ok(())
    }

    fn set_package_cpath(&mut self, path: &[u8]) -> Result<(), Option<Stop>> {
        self.package_cpath = path.split(|&b| b == b';').map(|s| s.to_owned()).collect();
        Ok(())
    }

    fn require_chunk(&mut self, path: &[u8]) -> Result<Chunk, Option<Stop>> {
        if let Some(chunk) = self.search_file(&path, &self.package_path, b".kailua")? {
            return Ok(chunk);
        }
        if let Some(chunk) = self.search_file(&path, &self.package_path, b"")? {
            return Ok(chunk);
        }
        if let Some(chunk) = self.search_file(&path, &self.package_cpath, b".kailua")? {
            return Ok(chunk);
        }
        // avoid loading the native libraries as is

        Err(None)
    }
}

<|endoftext|>


<commit_before>use anyhow::*;
use ape;
use id3;
use lewton::inside_ogg::OggStreamReader;
use log::error;
use metaflac;
use mp3_duration;
use mp4ameta;
use regex::Regex;
use std::fs;
use std::path::Path;
use opus_headers;

use crate::utils;
use crate::utils::AudioFormat;

#[derive(Debug, Clone, PartialEq)]
pub struct SongTags {
	pub disc_number: Option<u32>,
	pub track_number: Option<u32>,
	pub title: Option<String>,
	pub duration: Option<u32>,
	pub artist: Option<String>,
	pub album_artist: Option<String>,
	pub album: Option<String>,
	pub year: Option<i32>,
}

#[cfg_attr(feature = "profile-index", flame)]
pub fn read(path: &Path) -> Option<SongTags> {
	let data = match utils::get_audio_format(path) {
		Some(AudioFormat::FLAC) => Some(read_flac(path)),
		Some(AudioFormat::MP3) => Some(read_id3(path)),
		Some(AudioFormat::MP4) => Some(read_mp4(path)),
		Some(AudioFormat::MPC) => Some(read_ape(path)),
		Some(AudioFormat::OGG) => Some(read_vorbis(path)),
		Some(AudioFormat::OPUS) => Some(read_opus(path)),
		_ => None,
	};
	match data {
		Some(Ok(d)) => Some(d),
		Some(Err(e)) => {
			error!("Error while reading file metadata for '{:?}': {}", path, e);
			None
		}
		None => None,
	}
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_id3(path: &Path) -> Result<SongTags> {
	let tag = {
		#[cfg(feature = "profile-index")]
		let _guard = flame::start_guard("id3_tag_read");
		match id3::Tag::read_from_path(&path) {
			Ok(t) => Ok(t),
			Err(e) => {
				if let Some(t) = e.partial_tag {
					Ok(t)
				} else {
					Err(e)
				}
			}
		}?
	};
	let duration = {
		#[cfg(feature = "profile-index")]
		let _guard = flame::start_guard("mp3_duration");
		mp3_duration::from_path(&path)
			.map(|d| d.as_secs() as u32)
			.ok()
	};

	let artist = tag.artist().map(|s| s.to_string());
	let album_artist = tag.album_artist().map(|s| s.to_string());
	let album = tag.album().map(|s| s.to_string());
	let title = tag.title().map(|s| s.to_string());
	let disc_number = tag.disc();
	let track_number = tag.track();
	let year = tag
		.year()
		.map(|y| y as i32)
		.or_else(|| tag.date_released().and_then(|d| Some(d.year)))
		.or_else(|| tag.date_recorded().and_then(|d| Some(d.year)));

	Ok(SongTags {
		artist,
		album_artist,
		album,
		title,
		duration,
		disc_number,
		track_number,
		year,
	})
}

fn read_ape_string(item: &ape::Item) -> Option<String> {
	match item.value {
		ape::ItemValue::Text(ref s) => Some(s.clone()),
		_ => None,
	}
}

fn read_ape_i32(item: &ape::Item) -> Option<i32> {
	match item.value {
		ape::ItemValue::Text(ref s) => s.parse::<i32>().ok(),
		_ => None,
	}
}

fn read_ape_x_of_y(item: &ape::Item) -> Option<u32> {
	match item.value {
		ape::ItemValue::Text(ref s) => {
			let format = Regex::new(r#"^\d+"#).unwrap();
			if let Some(m) = format.find(s) {
				s[m.start()..m.end()].parse().ok()
			} else {
				None
			}
		}
		_ => None,
	}
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_ape(path: &Path) -> Result<SongTags> {
	let tag = ape::read(path)?;
	let artist = tag.item("Artist").and_then(read_ape_string);
	let album = tag.item("Album").and_then(read_ape_string);
	let album_artist = tag.item("Album artist").and_then(read_ape_string);
	let title = tag.item("Title").and_then(read_ape_string);
	let year = tag.item("Year").and_then(read_ape_i32);
	let disc_number = tag.item("Disc").and_then(read_ape_x_of_y);
	let track_number = tag.item("Track").and_then(read_ape_x_of_y);
	Ok(SongTags {
		artist,
		album_artist,
		album,
		title,
		duration: None,
		disc_number,
		track_number,
		year,
	})
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_vorbis(path: &Path) -> Result<SongTags> {
	let file = fs::File::open(path)?;
	let source = OggStreamReader::new(file)?;

	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};

	for (key, value) in source.comment_hdr.comment_list {
		match key.as_str() {
			"TITLE" => tags.title = Some(value),
			"ALBUM" => tags.album = Some(value),
			"ARTIST" => tags.artist = Some(value),
			"ALBUMARTIST" => tags.album_artist = Some(value),
			"TRACKNUMBER" => tags.track_number = value.parse::<u32>().ok(),
			"DISCNUMBER" => tags.disc_number = value.parse::<u32>().ok(),
			"DATE" => tags.year = value.parse::<i32>().ok(),
			_ => (),
		}
	}

	Ok(tags)
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_opus(path: &Path) -> Result<SongTags> {
	let headers = opus_headers::parse_from_path(path)?;

	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};

	for (key, value) in headers.comments.user_comments {
		if "TITLE".eq_ignore_ascii_case(key.as_str()) {
			tags.title = Some(value);
		} else if "ALBUM".eq_ignore_ascii_case(key.as_str()) {
			tags.album = Some(value);
		} else if "ARTIST".eq_ignore_ascii_case(key.as_str()) {
			tags.artist = Some(value);
		} else if "ALBUMARTIST".eq_ignore_ascii_case(key.as_str()) {
			tags.album_artist = Some(value);
		} else if "TRACKNUMBER".eq_ignore_ascii_case(key.as_str()) {
			tags.track_number = value.parse::<u32>().ok();
		} else if "DISCNUMBER".eq_ignore_ascii_case(key.as_str()) {
			tags.disc_number = value.parse::<u32>().ok();
		} else if "DATE".eq_ignore_ascii_case(key.as_str()) {
			tags.year = value.parse::<i32>().ok();
		}
	}

	Ok(tags)
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_flac(path: &Path) -> Result<SongTags> {
	let tag = metaflac::Tag::read_from_path(path)?;
	let vorbis = tag
		.vorbis_comments()
		.ok_or(anyhow!("Missing Vorbis comments"))?;
	let disc_number = vorbis
		.get("DISCNUMBER")
		.and_then(|d| d[0].parse::<u32>().ok());
	let year = vorbis.get("DATE").and_then(|d| d[0].parse::<i32>().ok());
	let mut streaminfo = tag.get_blocks(metaflac::BlockType::StreamInfo);
	let duration = match streaminfo.next() {
		Some(&metaflac::Block::StreamInfo(ref s)) => {
			Some((s.total_samples as u32 / s.sample_rate) as u32)
		}
		_ => None,
	};

	Ok(SongTags {
		artist: vorbis.artist().map(|v| v[0].clone()),
		album_artist: vorbis.album_artist().map(|v| v[0].clone()),
		album: vorbis.album().map(|v| v[0].clone()),
		title: vorbis.title().map(|v| v[0].clone()),
		duration,
		disc_number,
		track_number: vorbis.track(),
		year,
	})
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_mp4(path: &Path) -> Result<SongTags> {
	let tag = mp4ameta::Tag::read_from_path(path)?;
	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};
	tags.artist = tag.artist().map(|v| v.to_string());
	tags.album_artist = tag.album_artist().map(|v| v.to_string());
	tags.album = tag.album().map(|v| v.to_string());
	tags.title = tag.title().map(|v| v.to_string());
	tags.duration = tag.duration().map(|v| v as u32);
	tags.disc_number = tag.disk_number().0.and_then(|d| Some(d as u32));
	tags.track_number = tag.track_number().0.and_then(|d| Some(d as u32));
	tags.year = tag.year().and_then(|v| v.parse::<i32>().ok());

	Ok(tags)
}

#[test]
fn test_read_metadata() {
	let sample_tags = SongTags {
		disc_number: Some(3),
		track_number: Some(1),
		title: Some("TEST TITLE".into()),
		artist: Some("TEST ARTIST".into()),
		album_artist: Some("TEST ALBUM ARTIST".into()),
		album: Some("TEST ALBUM".into()),
		duration: None,
		year: Some(2016),
	};
	let flac_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	let mp3_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	let m4a_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	assert_eq!(read(Path::new("test/sample.mp3")).unwrap(), mp3_sample_tag);
	assert_eq!(read(Path::new("test/sample.ogg")).unwrap(), sample_tags);
	assert_eq!(read(Path::new("test/sample.flac")).unwrap(), flac_sample_tag);
	assert_eq!(read(Path::new("test/sample.m4a")).unwrap(), m4a_sample_tag);
}
<commit_msg>Update src/index/metadata.rs<commit_after>use anyhow::*;
use ape;
use id3;
use lewton::inside_ogg::OggStreamReader;
use log::error;
use metaflac;
use mp3_duration;
use mp4ameta;
use regex::Regex;
use std::fs;
use std::path::Path;
use opus_headers;

use crate::utils;
use crate::utils::AudioFormat;

#[derive(Debug, Clone, PartialEq)]
pub struct SongTags {
	pub disc_number: Option<u32>,
	pub track_number: Option<u32>,
	pub title: Option<String>,
	pub duration: Option<u32>,
	pub artist: Option<String>,
	pub album_artist: Option<String>,
	pub album: Option<String>,
	pub year: Option<i32>,
}

#[cfg_attr(feature = "profile-index", flame)]
pub fn read(path: &Path) -> Option<SongTags> {
	let data = match utils::get_audio_format(path) {
		Some(AudioFormat::FLAC) => Some(read_flac(path)),
		Some(AudioFormat::MP3) => Some(read_id3(path)),
		Some(AudioFormat::MP4) => Some(read_mp4(path)),
		Some(AudioFormat::MPC) => Some(read_ape(path)),
		Some(AudioFormat::OGG) => Some(read_vorbis(path)),
		Some(AudioFormat::OPUS) => Some(read_opus(path)),
		_ => None,
	};
	match data {
		Some(Ok(d)) => Some(d),
		Some(Err(e)) => {
			error!("Error while reading file metadata for '{:?}': {}", path, e);
			None
		}
		None => None,
	}
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_id3(path: &Path) -> Result<SongTags> {
	let tag = {
		#[cfg(feature = "profile-index")]
		let _guard = flame::start_guard("id3_tag_read");
		match id3::Tag::read_from_path(&path) {
			Ok(t) => Ok(t),
			Err(e) => {
				if let Some(t) = e.partial_tag {
					Ok(t)
				} else {
					Err(e)
				}
			}
		}?
	};
	let duration = {
		#[cfg(feature = "profile-index")]
		let _guard = flame::start_guard("mp3_duration");
		mp3_duration::from_path(&path)
			.map(|d| d.as_secs() as u32)
			.ok()
	};

	let artist = tag.artist().map(|s| s.to_string());
	let album_artist = tag.album_artist().map(|s| s.to_string());
	let album = tag.album().map(|s| s.to_string());
	let title = tag.title().map(|s| s.to_string());
	let disc_number = tag.disc();
	let track_number = tag.track();
	let year = tag
		.year()
		.map(|y| y as i32)
		.or_else(|| tag.date_released().and_then(|d| Some(d.year)))
		.or_else(|| tag.date_recorded().and_then(|d| Some(d.year)));

	Ok(SongTags {
		artist,
		album_artist,
		album,
		title,
		duration,
		disc_number,
		track_number,
		year,
	})
}

fn read_ape_string(item: &ape::Item) -> Option<String> {
	match item.value {
		ape::ItemValue::Text(ref s) => Some(s.clone()),
		_ => None,
	}
}

fn read_ape_i32(item: &ape::Item) -> Option<i32> {
	match item.value {
		ape::ItemValue::Text(ref s) => s.parse::<i32>().ok(),
		_ => None,
	}
}

fn read_ape_x_of_y(item: &ape::Item) -> Option<u32> {
	match item.value {
		ape::ItemValue::Text(ref s) => {
			let format = Regex::new(r#"^\d+"#).unwrap();
			if let Some(m) = format.find(s) {
				s[m.start()..m.end()].parse().ok()
			} else {
				None
			}
		}
		_ => None,
	}
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_ape(path: &Path) -> Result<SongTags> {
	let tag = ape::read(path)?;
	let artist = tag.item("Artist").and_then(read_ape_string);
	let album = tag.item("Album").and_then(read_ape_string);
	let album_artist = tag.item("Album artist").and_then(read_ape_string);
	let title = tag.item("Title").and_then(read_ape_string);
	let year = tag.item("Year").and_then(read_ape_i32);
	let disc_number = tag.item("Disc").and_then(read_ape_x_of_y);
	let track_number = tag.item("Track").and_then(read_ape_x_of_y);
	Ok(SongTags {
		artist,
		album_artist,
		album,
		title,
		duration: None,
		disc_number,
		track_number,
		year,
	})
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_vorbis(path: &Path) -> Result<SongTags> {
	let file = fs::File::open(path)?;
	let source = OggStreamReader::new(file)?;

	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};

	for (key, value) in source.comment_hdr.comment_list {
		match key.as_str() {
			"TITLE" => tags.title = Some(value),
			"ALBUM" => tags.album = Some(value),
			"ARTIST" => tags.artist = Some(value),
			"ALBUMARTIST" => tags.album_artist = Some(value),
			"TRACKNUMBER" => tags.track_number = value.parse::<u32>().ok(),
			"DISCNUMBER" => tags.disc_number = value.parse::<u32>().ok(),
			"DATE" => tags.year = value.parse::<i32>().ok(),
			_ => (),
		}
	}

	Ok(tags)
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_opus(path: &Path) -> Result<SongTags> {
	let headers = opus_headers::parse_from_path(path)?;

	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};

	for (key, value) in headers.comments.user_comments {
		if "TITLE".eq_ignore_ascii_case(&key) {
			tags.title = Some(value);
		} else if "ALBUM".eq_ignore_ascii_case(key.as_str()) {
			tags.album = Some(value);
		} else if "ARTIST".eq_ignore_ascii_case(key.as_str()) {
			tags.artist = Some(value);
		} else if "ALBUMARTIST".eq_ignore_ascii_case(key.as_str()) {
			tags.album_artist = Some(value);
		} else if "TRACKNUMBER".eq_ignore_ascii_case(key.as_str()) {
			tags.track_number = value.parse::<u32>().ok();
		} else if "DISCNUMBER".eq_ignore_ascii_case(key.as_str()) {
			tags.disc_number = value.parse::<u32>().ok();
		} else if "DATE".eq_ignore_ascii_case(key.as_str()) {
			tags.year = value.parse::<i32>().ok();
		}
	}

	Ok(tags)
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_flac(path: &Path) -> Result<SongTags> {
	let tag = metaflac::Tag::read_from_path(path)?;
	let vorbis = tag
		.vorbis_comments()
		.ok_or(anyhow!("Missing Vorbis comments"))?;
	let disc_number = vorbis
		.get("DISCNUMBER")
		.and_then(|d| d[0].parse::<u32>().ok());
	let year = vorbis.get("DATE").and_then(|d| d[0].parse::<i32>().ok());
	let mut streaminfo = tag.get_blocks(metaflac::BlockType::StreamInfo);
	let duration = match streaminfo.next() {
		Some(&metaflac::Block::StreamInfo(ref s)) => {
			Some((s.total_samples as u32 / s.sample_rate) as u32)
		}
		_ => None,
	};

	Ok(SongTags {
		artist: vorbis.artist().map(|v| v[0].clone()),
		album_artist: vorbis.album_artist().map(|v| v[0].clone()),
		album: vorbis.album().map(|v| v[0].clone()),
		title: vorbis.title().map(|v| v[0].clone()),
		duration,
		disc_number,
		track_number: vorbis.track(),
		year,
	})
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_mp4(path: &Path) -> Result<SongTags> {
	let tag = mp4ameta::Tag::read_from_path(path)?;
	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};
	tags.artist = tag.artist().map(|v| v.to_string());
	tags.album_artist = tag.album_artist().map(|v| v.to_string());
	tags.album = tag.album().map(|v| v.to_string());
	tags.title = tag.title().map(|v| v.to_string());
	tags.duration = tag.duration().map(|v| v as u32);
	tags.disc_number = tag.disk_number().0.and_then(|d| Some(d as u32));
	tags.track_number = tag.track_number().0.and_then(|d| Some(d as u32));
	tags.year = tag.year().and_then(|v| v.parse::<i32>().ok());

	Ok(tags)
}

#[test]
fn test_read_metadata() {
	let sample_tags = SongTags {
		disc_number: Some(3),
		track_number: Some(1),
		title: Some("TEST TITLE".into()),
		artist: Some("TEST ARTIST".into()),
		album_artist: Some("TEST ALBUM ARTIST".into()),
		album: Some("TEST ALBUM".into()),
		duration: None,
		year: Some(2016),
	};
	let flac_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	let mp3_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	let m4a_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	assert_eq!(read(Path::new("test/sample.mp3")).unwrap(), mp3_sample_tag);
	assert_eq!(read(Path::new("test/sample.ogg")).unwrap(), sample_tags);
	assert_eq!(read(Path::new("test/sample.flac")).unwrap(), flac_sample_tag);
	assert_eq!(read(Path::new("test/sample.m4a")).unwrap(), m4a_sample_tag);
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::boxed::Box;

use sql::tokenizer::Tokenizer;

#[test]
fn test_one_word_in_line() {
    let tokens = vec!["one"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    let actual = t.next();
    assert!(actual.is_some());
}

#[test]
fn test_simple_whitespace_delimeter() {
    let tokens = vec!["one", " ", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

fn build_tokens_string<'a>(tokens: &Vec<&'a str>) -> Box<String> {
    let mut s = "".to_string();
    for &token in (*tokens).iter() {
        s = s + token;
    }
    Box::new(s)
}

fn test_tokens<'a>(expected_tokens: &Vec<&'a str>, actual_tokens: &mut Tokenizer<'a>) {
    for &expected in (*expected_tokens).iter() {
        let actual = actual_tokens.next();
        assert_eq!(actual.unwrap(), expected);
    }
}

#[test]
#[ignore]
fn test_simple_tabulation_delimeter() {
    let mut t = Tokenizer::new("one\ttwo");
    let one = t.next();
    assert_eq!(one.unwrap(), "one");
    // let tabulation = t.next();
    // assert_eq!(tabulation.unwrap(), "\t");
    let two = t.next();
    assert_eq!(two.unwrap(), "two");
}

#[test]
#[ignore]
fn test_simple_new_line_delimeter() {
    let mut t = Tokenizer::new("one\ntwo");
    let one = t.next();
    assert_eq!(one.unwrap(), "one");
    // let new_line = t.next();
    // assert_eq!(new_line.unwrap(), "\n");
    let two = t.next();
    assert_eq!(two.unwrap(), "two");
}
<commit_msg>add new line and tabulation delimiters tests<commit_after>use std::vec::Vec;
use std::boxed::Box;

use sql::tokenizer::Tokenizer;

#[test]
fn test_one_word_in_line() {
    let tokens = vec!["one"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    let actual = t.next();
    assert!(actual.is_some());
}

fn build_tokens_string<'a>(tokens: &Vec<&'a str>) -> Box<String> {
    let mut s = "".to_string();
    for &token in (*tokens).iter() {
        s = s + token;
    }
    Box::new(s)
}

#[test]
fn test_simple_whitespace_delimeter() {
    let tokens = vec!["one", " ", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

fn test_tokens<'a>(expected_tokens: &Vec<&'a str>, actual_tokens: &mut Tokenizer<'a>) {
    for &expected in (*expected_tokens).iter() {
        let actual = actual_tokens.next();
        assert_eq!(actual.unwrap(), expected);
    }
}

#[test]
fn test_simple_tabulation_delimeter() {
    let tokens = vec!["one", "\t", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_simple_new_line_delimeter() {
    let tokens = vec!["one", "\n", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Rolf Morel <rolfmorel@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) inval

use std::cmp::max;
use std::str::FromStr;

use crate::display::Quotable;

#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Range {
    pub low: usize,
    pub high: usize,
}

impl FromStr for Range {
    type Err = &'static str;

    /// Parse a string of the form `a-b` into a `Range`
    ///
    /// ```
    /// use std::str::FromStr;
    /// use uucore::ranges::Range;
    /// assert_eq!(Range::from_str("5"), Ok(Range { low: 5, high: 5 }));
    /// assert_eq!(Range::from_str("4-"), Ok(Range { low: 4, high: usize::MAX - 1 }));
    /// assert_eq!(Range::from_str("-4"), Ok(Range { low: 1, high: 4 }));
    /// assert_eq!(Range::from_str("2-4"), Ok(Range { low: 2, high: 4 }));
    /// assert!(Range::from_str("0-4").is_err());
    /// assert!(Range::from_str("4-2").is_err());
    /// assert!(Range::from_str("-").is_err());
    /// assert!(Range::from_str("a").is_err());
    /// assert!(Range::from_str("a-b").is_err());
    /// ```
    fn from_str(s: &str) -> Result<Self, &'static str> {
        fn parse(s: &str) -> Result<usize, &'static str> {
            match s.parse::<usize>() {
                Ok(0) => Err("fields and positions are numbered from 1"),
                Ok(n) => Ok(n),
                Err(_) => Err("failed to parse range"),
            }
        }

        Ok(match s.split_once('-') {
            None => {
                let n = parse(s)?;
                Self { low: n, high: n }
            }
            Some(("", "")) => return Err("invalid range with no endpoint"),
            Some((low, "")) => Self {
                low: parse(low)?,
                high: usize::MAX - 1,
            },
            Some(("", high)) => Self {
                low: 1,
                high: parse(high)?,
            },
            Some((low, high)) => {
                let (low, high) = (parse(low)?, parse(high)?);
                if low <= high {
                    Self { low, high }
                } else {
                    return Err("high end of range less than low end");
                }
            }
        })
    }
}

impl Range {
    pub fn from_list(list: &str) -> Result<Vec<Self>, String> {
        let mut ranges = Vec::new();

        for item in list.split(',') {
            let range_item = FromStr::from_str(item)
                .map_err(|e| format!("range {} was invalid: {}", item.quote(), e))?;
            ranges.push(range_item);
        }

        Ok(Range::merge(ranges))
    }

    /// Merge any overlapping ranges
    ///
    /// Is guaranteed to return only disjoint ranges in a sorted order.
    fn merge(mut ranges: Vec<Self>) -> Vec<Self> {
        ranges.sort();

        // merge overlapping ranges
        for i in 0..ranges.len() {
            let j = i + 1;

            // The +1 is a small optimization, because we can merge adjacent Ranges.
            // For example (1,3) and (4,6), because in the integers, there are no
            // possible values between 3 and 4, this is equivalent to (1,6).
            while j < ranges.len() && ranges[j].low <= ranges[i].high + 1 {
                let j_high = ranges.remove(j).high;
                ranges[i].high = max(ranges[i].high, j_high);
            }
        }
        ranges
    }
}

pub fn complement(ranges: &[Range]) -> Vec<Range> {
    let mut complements = Vec::with_capacity(ranges.len() + 1);

    if !ranges.is_empty() && ranges[0].low > 1 {
        complements.push(Range {
            low: 1,
            high: ranges[0].low - 1,
        });
    }

    let mut ranges_iter = ranges.iter().peekable();
    loop {
        match (ranges_iter.next(), ranges_iter.peek()) {
            (Some(left), Some(right)) => {
                if left.high + 1 != right.low {
                    complements.push(Range {
                        low: left.high + 1,
                        high: right.low - 1,
                    });
                }
            }
            (Some(last), None) => {
                if last.high < usize::MAX - 1 {
                    complements.push(Range {
                        low: last.high + 1,
                        high: usize::MAX - 1,
                    });
                }
            }
            _ => break,
        }
    }

    complements
}

/// Test if at least one of the given Ranges contain the supplied value.
///
/// Examples:
///
/// ```
/// let ranges = uucore::ranges::Range::from_list("11,2,6-8").unwrap();
///
/// assert!(!uucore::ranges::contain(&ranges, 0));
/// assert!(!uucore::ranges::contain(&ranges, 1));
/// assert!(!uucore::ranges::contain(&ranges, 5));
/// assert!(!uucore::ranges::contain(&ranges, 10));
///
/// assert!(uucore::ranges::contain(&ranges, 2));
/// assert!(uucore::ranges::contain(&ranges, 6));
/// assert!(uucore::ranges::contain(&ranges, 7));
/// assert!(uucore::ranges::contain(&ranges, 8));
/// assert!(uucore::ranges::contain(&ranges, 11));
/// ```
pub fn contain(ranges: &[Range], n: usize) -> bool {
    for range in ranges {
        if n >= range.low && n <= range.high {
            return true;
        }
    }

    false
}

#[cfg(test)]
mod test {
    use super::Range;

    fn m(a: Vec<Range>, b: Vec<Range>) {
        assert_eq!(Range::merge(a), b);
    }

    fn r(low: usize, high: usize) -> Range {
        Range { low, high }
    }

    #[test]
    fn merging() {
        // Single element
        m(vec![r(1, 2)], vec![r(1, 2)]);

        // Disjoint in wrong order
        m(vec![r(4, 5), r(1, 2)], vec![r(1, 2), r(4, 5)]);

        // Two elements must be merged
        m(vec![r(1, 3), r(2, 4), r(6, 7)], vec![r(1, 4), r(6, 7)]);

        // Two merges and a duplicate
        m(
            vec![r(1, 3), r(6, 7), r(2, 4), r(6, 7)],
            vec![r(1, 4), r(6, 7)],
        );

        // One giant
        m(
            vec![
                r(110, 120),
                r(10, 20),
                r(100, 200),
                r(130, 140),
                r(150, 160),
            ],
            vec![r(10, 20), r(100, 200)],
        );

        // Last one joins the previous two
        m(
            vec![
                r(10,20),
                r(30,40),
                r(20,30),
            ],
            vec![r(10,40)]
        );

        m(
            vec![
                r(10,20),
                r(30,40),
                r(50,60),
                r(20,30),
            ],
            vec![r(10,40), r(50,60)]
        );

        // Merge adjacent ranges
        m(vec![r(1, 3), r(4, 6)], vec![r(1, 6)])
    }
}<commit_msg>uucore/ranges: refactor and test complement<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Rolf Morel <rolfmorel@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) inval

use std::cmp::max;
use std::str::FromStr;

use crate::display::Quotable;

#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Range {
    pub low: usize,
    pub high: usize,
}

impl FromStr for Range {
    type Err = &'static str;

    /// Parse a string of the form `a-b` into a `Range`
    ///
    /// ```
    /// use std::str::FromStr;
    /// use uucore::ranges::Range;
    /// assert_eq!(Range::from_str("5"), Ok(Range { low: 5, high: 5 }));
    /// assert_eq!(Range::from_str("4-"), Ok(Range { low: 4, high: usize::MAX - 1 }));
    /// assert_eq!(Range::from_str("-4"), Ok(Range { low: 1, high: 4 }));
    /// assert_eq!(Range::from_str("2-4"), Ok(Range { low: 2, high: 4 }));
    /// assert!(Range::from_str("0-4").is_err());
    /// assert!(Range::from_str("4-2").is_err());
    /// assert!(Range::from_str("-").is_err());
    /// assert!(Range::from_str("a").is_err());
    /// assert!(Range::from_str("a-b").is_err());
    /// ```
    fn from_str(s: &str) -> Result<Self, &'static str> {
        fn parse(s: &str) -> Result<usize, &'static str> {
            match s.parse::<usize>() {
                Ok(0) => Err("fields and positions are numbered from 1"),
                Ok(n) => Ok(n),
                Err(_) => Err("failed to parse range"),
            }
        }

        Ok(match s.split_once('-') {
            None => {
                let n = parse(s)?;
                Self { low: n, high: n }
            }
            Some(("", "")) => return Err("invalid range with no endpoint"),
            Some((low, "")) => Self {
                low: parse(low)?,
                high: usize::MAX - 1,
            },
            Some(("", high)) => Self {
                low: 1,
                high: parse(high)?,
            },
            Some((low, high)) => {
                let (low, high) = (parse(low)?, parse(high)?);
                if low <= high {
                    Self { low, high }
                } else {
                    return Err("high end of range less than low end");
                }
            }
        })
    }
}

impl Range {
    pub fn from_list(list: &str) -> Result<Vec<Self>, String> {
        let mut ranges = Vec::new();

        for item in list.split(',') {
            let range_item = FromStr::from_str(item)
                .map_err(|e| format!("range {} was invalid: {}", item.quote(), e))?;
            ranges.push(range_item);
        }

        Ok(Self::merge(ranges))
    }

    /// Merge any overlapping ranges
    ///
    /// Is guaranteed to return only disjoint ranges in a sorted order.
    fn merge(mut ranges: Vec<Self>) -> Vec<Self> {
        ranges.sort();

        // merge overlapping ranges
        for i in 0..ranges.len() {
            let j = i + 1;

            // The +1 is a small optimization, because we can merge adjacent Ranges.
            // For example (1,3) and (4,6), because in the integers, there are no
            // possible values between 3 and 4, this is equivalent to (1,6).
            while j < ranges.len() && ranges[j].low <= ranges[i].high + 1 {
                let j_high = ranges.remove(j).high;
                ranges[i].high = max(ranges[i].high, j_high);
            }
        }
        ranges
    }
}

pub fn complement(ranges: &[Range]) -> Vec<Range> {
    let mut prev_high = 0;
    let mut complements = Vec::with_capacity(ranges.len() + 1);

    for range in ranges {
        if range.low > prev_high + 1 {
            complements.push(Range {
                low: prev_high + 1,
                high: range.low - 1,
            });
        }
        prev_high = range.high;
    }

    if prev_high < usize::MAX - 1 {
        complements.push(Range {
            low: prev_high + 1,
            high: usize::MAX - 1,
        });
    }

    complements
}

/// Test if at least one of the given Ranges contain the supplied value.
///
/// Examples:
///
/// ```
/// let ranges = uucore::ranges::Range::from_list("11,2,6-8").unwrap();
///
/// assert!(!uucore::ranges::contain(&ranges, 0));
/// assert!(!uucore::ranges::contain(&ranges, 1));
/// assert!(!uucore::ranges::contain(&ranges, 5));
/// assert!(!uucore::ranges::contain(&ranges, 10));
///
/// assert!(uucore::ranges::contain(&ranges, 2));
/// assert!(uucore::ranges::contain(&ranges, 6));
/// assert!(uucore::ranges::contain(&ranges, 7));
/// assert!(uucore::ranges::contain(&ranges, 8));
/// assert!(uucore::ranges::contain(&ranges, 11));
/// ```
pub fn contain(ranges: &[Range], n: usize) -> bool {
    for range in ranges {
        if n >= range.low && n <= range.high {
            return true;
        }
    }

    false
}

#[cfg(test)]
mod test {
    use super::{complement, Range};

    fn m(a: Vec<Range>, b: Vec<Range>) {
        assert_eq!(Range::merge(a), b);
    }

    fn r(low: usize, high: usize) -> Range {
        Range { low, high }
    }

    #[test]
    fn merging() {
        // Single element
        m(vec![r(1, 2)], vec![r(1, 2)]);

        // Disjoint in wrong order
        m(vec![r(4, 5), r(1, 2)], vec![r(1, 2), r(4, 5)]);

        // Two elements must be merged
        m(vec![r(1, 3), r(2, 4), r(6, 7)], vec![r(1, 4), r(6, 7)]);

        // Two merges and a duplicate
        m(
            vec![r(1, 3), r(6, 7), r(2, 4), r(6, 7)],
            vec![r(1, 4), r(6, 7)],
        );

        // One giant
        m(
            vec![
                r(110, 120),
                r(10, 20),
                r(100, 200),
                r(130, 140),
                r(150, 160),
            ],
            vec![r(10, 20), r(100, 200)],
        );

        // Last one joins the previous two
        m(vec![r(10, 20), r(30, 40), r(20, 30)], vec![r(10, 40)]);

        m(
            vec![r(10, 20), r(30, 40), r(50, 60), r(20, 30)],
            vec![r(10, 40), r(50, 60)],
        );

        // Merge adjacent ranges
        m(vec![r(1, 3), r(4, 6)], vec![r(1, 6)])
    }

    #[test]
    fn complementing() {
        // Simple
        assert_eq!(complement(&[r(3, 4)]), vec![r(1, 2), r(5, usize::MAX - 1)]);

        // With start
        assert_eq!(
            complement(&[r(1, 3), r(6, 10)]),
            vec![r(4, 5), r(11, usize::MAX - 1)]
        );

        // With end
        assert_eq!(
            complement(&[r(2, 4), r(6, usize::MAX - 1)]),
            vec![r(1, 1), r(5, 5)]
        );

        // With start and end
        assert_eq!(complement(&[r(1, 4), r(6, usize::MAX - 1)]), vec![r(5, 5)]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(unix, not(target_os = "ios"))]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use collections::Collection;
    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::MutableSlice;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use core_collections::Collection;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use rt::stack;
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::MutableSlice;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
    static NTE_BAD_SIGNATURE: DWORD = 0x80090006;

    #[allow(non_snake_case_functions)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let mut ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            // FIXME #13259:
            // It turns out that if we can't acquire a context with the
            // NTE_BAD_SIGNATURE error code, the documentation states:
            //
            //     The provider DLL signature could not be verified. Either the
            //     DLL or the digital signature has been tampered with.
            //
            // Sounds fishy, no? As it turns out, our signature can be bad
            // because our Thread Information Block (TIB) isn't exactly what it
            // expects. As to why, I have no idea. The only data we store in the
            // TIB is the stack limit for each thread, but apparently that's
            // enough to make the signature valid.
            //
            // Furthermore, this error only happens the *first* time we call
            // CryptAcquireContext, so we don't have to worry about future
            // calls.
            //
            // Anyway, the fix employed here is that if we see this error, we
            // pray that we're not close to the end of the stack, temporarily
            // set the stack limit to 0 (what the TIB originally was), acquire a
            // context, and then reset the stack limit.
            //
            // Again, I'm not sure why this is the fix, nor why we're getting
            // this error. All I can say is that this seems to allow libnative
            // to progress where it otherwise would be hindered. Who knew?
            if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
                unsafe {
                    let limit = stack::get_sp_limit();
                    stack::record_sp_limit(0);
                    ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                               PROV_RSA_FULL,
                                               CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
                    stack::record_sp_limit(limit);
                }
            }

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::*;

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>Unify non-snake-case lints and non-uppercase statics lints<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(unix, not(target_os = "ios"))]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use collections::Collection;
    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::MutableSlice;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use core_collections::Collection;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use rt::stack;
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::MutableSlice;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
    static NTE_BAD_SIGNATURE: DWORD = 0x80090006;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let mut ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            // FIXME #13259:
            // It turns out that if we can't acquire a context with the
            // NTE_BAD_SIGNATURE error code, the documentation states:
            //
            //     The provider DLL signature could not be verified. Either the
            //     DLL or the digital signature has been tampered with.
            //
            // Sounds fishy, no? As it turns out, our signature can be bad
            // because our Thread Information Block (TIB) isn't exactly what it
            // expects. As to why, I have no idea. The only data we store in the
            // TIB is the stack limit for each thread, but apparently that's
            // enough to make the signature valid.
            //
            // Furthermore, this error only happens the *first* time we call
            // CryptAcquireContext, so we don't have to worry about future
            // calls.
            //
            // Anyway, the fix employed here is that if we see this error, we
            // pray that we're not close to the end of the stack, temporarily
            // set the stack limit to 0 (what the TIB originally was), acquire a
            // context, and then reset the stack limit.
            //
            // Again, I'm not sure why this is the fix, nor why we're getting
            // this error. All I can say is that this seems to allow libnative
            // to progress where it otherwise would be hindered. Who knew?
            if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
                unsafe {
                    let limit = stack::get_sp_limit();
                    stack::record_sp_limit(0);
                    ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                               PROV_RSA_FULL,
                                               CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
                    stack::record_sp_limit(limit);
                }
            }

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::*;

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>use num::{Num, Zero, One};
use rustc_serialize::{Encodable, Decodable};
use std::fmt::Debug;

/// Vector whose dimension is known at runtime
///
/// Assumes the `Vector` is represented as a
/// tuple of numbers representing its projection
/// along orthogonal base vectors
pub trait Vector: Clone {
    /// Underlying scalar type of `Vector` type
    type Scalar: Num + Zero + One + Copy + Encodable + Decodable + Default + Debug;
    /// Maximum allowed index for `at` and `mut_at`
    fn dimension(&self) -> usize;
    /// Length of projection along `i`-th base
    fn at(&self, i: usize) -> Self::Scalar;
    /// Mutable access to length of projection along `i`-th base
    fn mut_at(&mut self, i: usize) -> &mut Self::Scalar;
    /// Scalar product
    ///
    /// Default implementation using `at` and `dimension` is provided
    fn dot(&self, other: &Self) -> Self::Scalar {
        let mut result = Self::Scalar::zero();
        for i in 0..self.dimension() {
            result = result + self.at(i) * other.at(i)
        }
        result
    }
}

impl Vector for f64 {
    type Scalar = f64;

    fn dimension(&self) -> usize {
        1
    }

    fn at(&self, _: usize) -> f64 {
        *self
    }

    fn mut_at(&mut self, _: usize) -> &mut f64 {
        self
    }

    fn dot(&self, other: &f64) -> f64 {
        self * other
    }
}

impl Vector for [f64; 2] {
    type Scalar = f64;

    fn dimension(&self) -> usize {
        2
    }

    fn at(&self, index: usize) -> f64 {
        self[index]
    }

    fn mut_at(&mut self, index: usize) -> &mut f64 {
        &mut self[index]
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn dot() {

        use linear_algebra::Vector;

        let a = [1.0, 2.0];
        let b = [3.0, 4.0];

        assert_eq!(11.0, a.dot(&b))
    }
}
<commit_msg>implemented vec for [f64; 1..32]<commit_after>use num::{Num, Zero, One};
use rustc_serialize::{Encodable, Decodable};
use std::fmt::Debug;

/// Vector whose dimension is known at runtime
///
/// Assumes the `Vector` is represented as a
/// tuple of numbers representing its projection
/// along orthogonal base vectors
pub trait Vector: Clone {
    /// Underlying scalar type of `Vector` type
    type Scalar: Num + Zero + One + Copy + Encodable + Decodable + Default + Debug;
    /// Maximum allowed index for `at` and `mut_at`
    fn dimension(&self) -> usize;
    /// Length of projection along `i`-th base
    fn at(&self, i: usize) -> Self::Scalar;
    /// Mutable access to length of projection along `i`-th base
    fn mut_at(&mut self, i: usize) -> &mut Self::Scalar;
    /// Scalar product
    ///
    /// Default implementation using `at` and `dimension` is provided
    fn dot(&self, other: &Self) -> Self::Scalar {
        let mut result = Self::Scalar::zero();
        for i in 0..self.dimension() {
            result = result + self.at(i) * other.at(i)
        }
        result
    }
}

impl Vector for f64 {
    type Scalar = f64;

    fn dimension(&self) -> usize {
        1
    }

    fn at(&self, _: usize) -> f64 {
        *self
    }

    fn mut_at(&mut self, _: usize) -> &mut f64 {
        self
    }

    fn dot(&self, other: &f64) -> f64 {
        self * other
    }
}

macro_rules! vec_impl_for_array {
    ($v:expr) => {
        impl Vector for [f64; $v] {

            type Scalar = f64;

            fn dimension(&self) -> usize{ $v }

            fn at(&self, index: usize) -> f64 {
                self[index]
            }

            fn mut_at(&mut self, index: usize) -> &mut f64 {
                &mut self[index]
            }
        }
    }
}

vec_impl_for_array! { 1 }
vec_impl_for_array! { 2 }
vec_impl_for_array! { 3 }
vec_impl_for_array! { 4 }
vec_impl_for_array! { 5 }
vec_impl_for_array! { 6 }
vec_impl_for_array! { 7 }
vec_impl_for_array! { 8 }
vec_impl_for_array! { 9 }
vec_impl_for_array! { 10 }
vec_impl_for_array! { 11 }
vec_impl_for_array! { 12 }
vec_impl_for_array! { 13 }
vec_impl_for_array! { 14 }
vec_impl_for_array! { 15 }
vec_impl_for_array! { 16 }
vec_impl_for_array! { 17 }
vec_impl_for_array! { 18 }
vec_impl_for_array! { 19 }
vec_impl_for_array! { 20 }
vec_impl_for_array! { 21 }
vec_impl_for_array! { 22 }
vec_impl_for_array! { 23 }
vec_impl_for_array! { 24 }
vec_impl_for_array! { 25 }
vec_impl_for_array! { 26 }
vec_impl_for_array! { 27 }
vec_impl_for_array! { 28 }
vec_impl_for_array! { 29 }
vec_impl_for_array! { 30 }
vec_impl_for_array! { 31 }
vec_impl_for_array! { 32 }

#[cfg(test)]
mod tests {

    #[test]
    fn dot() {

        use linear_algebra::Vector;

        let a = [1.0, 2.0];
        let b = [3.0, 4.0];

        assert_eq!(11.0, a.dot(&b))
    }
}
<|endoftext|>