<commit_before>use std::uint;
use std::os;
use std::vec;
use std::str;
use ptrie::PTrie;

/// Word with its frequency and the distance from a reference word.
pub struct Word
{
  /// The actual word.
  word: ~str,
  /// Word aparition frequency on the internet.
  freq: uint,
  /// Distance between this word and a referance word.
  dist: uint
}

impl Word
{
  /// Creates a new word.
  pub fn new(word: ~str, freq: uint, dist: uint) -> Word
  {
    Word {
      word: word,
      freq: freq,
      dist: dist
    }
  }
}

impl Eq for Word
{
  fn eq(&self, other: &Word) -> bool
  { self.dist == other.dist && self.freq == other.freq && self.word == other.word }
}

impl Ord for Word
{
  fn lt(&self, other: &Word) -> bool
  {
    self.dist < other.dist ||
    (self.dist == other.dist && (self.freq > other.freq ||
                                 (self.freq == other.freq && self.word < other.word)))
  }
}

impl ToStr for Word
{
  pub fn to_str(&self) -> ~str
  {
    "{\"word\":\"" + self.word +
    "\",\"freq\":" + self.freq.to_str() +
    ",\"distance\":" + self.dist.to_str() +
    "}"
  }
}

#[deriving(ToStr)]
struct PTrieHeader
{
  nb_succ: u64,
  key_len: u64,
  freq:    u64
}

/// Rebuilds the patricia trie from its compact version
pub fn rebuild_ptrie(mem: &~os::MemoryMap) -> ~PTrie
{ do_rebuild_ptrie(mem.data as *u64, mem.data as *u64) }

fn do_rebuild_ptrie(start: *u64, curr: *u64) -> ~PTrie
{
  unsafe {
    let header = curr as *PTrieHeader;

    let kbegin    = curr + 3;
    let succbegin = curr + 3 + (*header).key_len;

    /*
     * Extract key
     */
    let mut key = ~"";

    for uint::iterate(0u, (*header).key_len as uint) |i|
    {
      key.push_char(*(kbegin + i) as char);
    }

    /*
     * Build the new node with the key
     */
    let mut ptrie = ~PTrie::new(key);
    ptrie.freq = (*header).freq as uint;

    /*
     * Build successors array
     */
    for uint::iterate(0u, (*header).nb_succ as uint) |i|
    {
      // We have to lookup the first character of the successor
      let child_addr = start + *(succbegin + i);

      ptrie.push(do_rebuild_ptrie(start,child_addr));
      //ptrie.succ[child_first_letter] = Some(do_rebuild_ptrie(start, child_addr))
    }

    ptrie
  }
}

struct DLDist
{
  original: ~str,
  current:  ~[u8],
  table:    ~[uint],
  max_dist: uint
}

impl ToStr for DLDist
{
  fn to_str(&self) -> ~str
  {
    let mut res = ~"";

    res = res + "< " + self.original + " > vs < " + str::from_bytes(self.current) + " >\n";

    res = res + "Table:\n";

    for uint::iterate(0u, self.current.len() + 1) |i|
    {
      for uint::iterate(0u, self.original.len() + 1) |j|
      {
        let idx = i * (self.original.len() + 1) + j;
        if  idx < self.table.len() // FIXME: this is verry dummy…
        { res = res + " " + self.table[idx].to_str() }
      }

      res = res + "\n";
    }

    res = res + "### raw: " + self.table.to_str();

    res
  }
}

impl DLDist
{
  /// XXX: fix doc
  pub fn new(original: ~str, distance: uint) -> DLDist
  {
    let olen      = original.len() + 1;
    let mut table = vec::with_capacity(olen * olen);

    for uint::iterate(0u, olen) |i|
    { table.push(i) }

    DLDist {
      current:  ~[],
      table:    table,
      original: original,
      max_dist: distance
    }
  }

  /// XXX: fix doc
  pub fn truncate(&mut self, new_len: uint)
  {
    self.current.truncate(new_len);
    self.table.truncate((new_len + 1) * (self.original.len() + 1));
  }

  /// XXX: fix doc
  pub fn take(&mut self, c: u8) -> (bool, bool)
  {
    let mut should_stop = true;

    self.current.push(c);

    self.table.push(self.current.len());

    for uint::iterate(0u, self.original.len()) |j|
    {
      let i    = self.current.len();
      let l    = self.table[self.table.len() - 1];
      let u    = self.table[self.table.len() - (self.original.len() + 1)];
      let ul   = self.table[self.table.len() - (self.original.len() + 1) - 1];

      let sub_weight = if c == self.original[j]
      { 0 }
      else
      { 1 };

      let distance = (l + 1).min(&(u + 1)).min(&(ul + sub_weight));

      if self.current.len() > 1 && j > 1
      {
        let uull = self.table[self.table.len() - 2 * (self.original.len() + 1) - 2];

        let trans_weight = if self.current[i - 1] == self.original[j - 1] &&
                              self.current[i - 2] == self.original[j - 2]
        { 1 }
        else
        { Bounded::max_value::<uint>() - uull };

        self.table.push(distance.min(&(uull + trans_weight)));
      }
      else
      {
        self.table.push(distance);
      }

      if distance <= self.max_dist
      { should_stop = false }
    }

    (should_stop, self.dist() <= self.max_dist)
  }

  /// Damerau-Levenshtein distance between `self.curr` and `self.original`.
  pub fn dist(&self) -> uint
  { *self.table.last() }
}

/// XXX Fix doc
pub fn find_candidates(mem: &os::MemoryMap, word: ~str, distance: uint) -> ~[Word]
{
  let mut res  = ~[];
  let mut algo = DLDist::new(word, distance);

  do_find_candidates(mem.data as *u64, mem.data as *u64, &mut algo, &mut res);

  res
}

fn do_find_candidates(start: *u64, curr: *u64, algo: &mut DLDist, out: &mut ~[Word])
{
  unsafe {
    let header    = curr as *PTrieHeader;
    let kbegin    = curr + 3;
    let succbegin = curr + 3 + (*header).key_len;

    /*
     * Consume the current word’s letters
     */
    let mut accept = false;

    for uint::iterate(0u, (*header).key_len as uint) |i|
    {

      let (should_stop, accept_this) = algo.take(*(kbegin + i) as u8);

      accept = accept_this; // FIXME: uggly!

      if should_stop
      { return }
    }

    if accept && (*header).freq != 0
    { out.push(Word::new(str::from_bytes(algo.current), (*header).freq as uint, algo.dist())) }

    /*
     * Go to the children (recursive call)
     */
    let curr_len = algo.current.len();

    for uint::iterate(0u, (*header).nb_succ as uint) |i|
    {
      // first, partially reinitialise the algorithm
      algo.truncate(curr_len);

      let child_addr = start + *(succbegin + i);

      // and start the recursion on the next branch
      do_find_candidates(start, child_addr, algo, out);
    }
  }
}
<commit_msg>Fix permutation handling on the distance computation.<commit_after>use std::uint;
use std::os;
use std::vec;
use std::str;
use ptrie::PTrie;

/// Word with its frequency and the distance from a reference word.
pub struct Word
{
  /// The actual word.
  word: ~str,
  /// Word aparition frequency on the internet.
  freq: uint,
  /// Distance between this word and a referance word.
  dist: uint
}

impl Word
{
  /// Creates a new word.
  pub fn new(word: ~str, freq: uint, dist: uint) -> Word
  {
    Word {
      word: word,
      freq: freq,
      dist: dist
    }
  }
}

impl Eq for Word
{
  fn eq(&self, other: &Word) -> bool
  { self.dist == other.dist && self.freq == other.freq && self.word == other.word }
}

impl Ord for Word
{
  fn lt(&self, other: &Word) -> bool
  {
    self.dist < other.dist ||
    (self.dist == other.dist && (self.freq > other.freq ||
                                 (self.freq == other.freq && self.word < other.word)))
  }
}

impl ToStr for Word
{
  pub fn to_str(&self) -> ~str
  {
    "{\"word\":\"" + self.word +
    "\",\"freq\":" + self.freq.to_str() +
    ",\"distance\":" + self.dist.to_str() +
    "}"
  }
}

#[deriving(ToStr)]
struct PTrieHeader
{
  nb_succ: u64,
  key_len: u64,
  freq:    u64
}

/// Rebuilds the patricia trie from its compact version
pub fn rebuild_ptrie(mem: &~os::MemoryMap) -> ~PTrie
{ do_rebuild_ptrie(mem.data as *u64, mem.data as *u64) }

fn do_rebuild_ptrie(start: *u64, curr: *u64) -> ~PTrie
{
  unsafe {
    let header = curr as *PTrieHeader;

    let kbegin    = curr + 3;
    let succbegin = curr + 3 + (*header).key_len;

    /*
     * Extract key
     */
    let mut key = ~"";

    for uint::iterate(0u, (*header).key_len as uint) |i|
    {
      key.push_char(*(kbegin + i) as char);
    }

    /*
     * Build the new node with the key
     */
    let mut ptrie = ~PTrie::new(key);
    ptrie.freq = (*header).freq as uint;

    /*
     * Build successors array
     */
    for uint::iterate(0u, (*header).nb_succ as uint) |i|
    {
      // We have to lookup the first character of the successor
      let child_addr = start + *(succbegin + i);

      ptrie.push(do_rebuild_ptrie(start,child_addr));
      //ptrie.succ[child_first_letter] = Some(do_rebuild_ptrie(start, child_addr))
    }

    ptrie
  }
}

/// XXX: fix doc
pub struct DLDist
{
  /// XXX: fix doc
  original: ~str,
  /// XXX: fix doc
  current:  ~[u8],
  /// XXX: fix doc
  table:    ~[uint],
  /// XXX: fix doc
  max_dist: uint
}

impl ToStr for DLDist
{
  fn to_str(&self) -> ~str
  {
    let mut res = ~"";

    res = res + "< " + self.original + " > vs < " + str::from_bytes(self.current) + " >\n";

    res = res + "Table:\n";

    for uint::iterate(0u, self.current.len() + 1) |i|
    {
      for uint::iterate(0u, self.original.len() + 1) |j|
      {
        let idx = i * (self.original.len() + 1) + j;
        if  idx < self.table.len() // FIXME: this is verry dummy…
        { res = res + " " + self.table[idx].to_str() }
      }

      res = res + "\n";
    }

    res = res + "### raw: " + self.table.to_str();

    res
  }
}

impl DLDist
{
  /// XXX: fix doc
  pub fn new(original: ~str, distance: uint) -> DLDist
  {
    let olen      = original.len() + 1;
    let mut table = vec::with_capacity(olen * olen);

    for uint::iterate(0u, olen) |i|
    { table.push(i) }

    DLDist {
      current:  ~[],
      table:    table,
      original: original,
      max_dist: distance
    }
  }

  /// XXX: fix doc
  pub fn truncate(&mut self, new_len: uint)
  {
    self.current.truncate(new_len);
    self.table.truncate((new_len + 1) * (self.original.len() + 1));
  }

  /// XXX: fix doc
  pub fn take(&mut self, c: u8) -> (bool, bool)
  {
    let mut should_stop = true;

    self.current.push(c);

    self.table.push(self.current.len());

    for uint::iterate(0u, self.original.len()) |j|
    {
      let i    = self.current.len();
      let l    = self.table[self.table.len() - 1];
      let u    = self.table[self.table.len() - (self.original.len() + 1)];
      let ul   = self.table[self.table.len() - (self.original.len() + 1) - 1];

      let sub_weight = if c == self.original[j]
      { 0 }
      else
      { 1 };

      let distance = (l + 1).min(&(u + 1)).min(&(ul + sub_weight));

      if i > 1 && j > 0
      {
        let uull = self.table[self.table.len() - 2 * (self.original.len() + 1) - 2];

        let trans_weight = if self.current[i - 1] == self.original[j - 1] &&
                              self.current[i - 2] == self.original[j]
        { 1 }
        else
        { Bounded::max_value::<uint>() - uull };

        self.table.push(distance.min(&(uull + trans_weight)));
      }
      else
      {
        self.table.push(distance);
      }

      if distance <= self.max_dist
      { should_stop = false }
    }

    (should_stop, self.dist() <= self.max_dist)
  }

  /// Damerau-Levenshtein distance between `self.curr` and `self.original`.
  pub fn dist(&self) -> uint
  { *self.table.last() }
}

/// XXX Fix doc
pub fn find_candidates(mem: &os::MemoryMap, word: ~str, distance: uint) -> ~[Word]
{
  let mut res  = ~[];
  let mut algo = DLDist::new(word, distance);

  do_find_candidates(mem.data as *u64, mem.data as *u64, &mut algo, &mut res);

  res
}

fn do_find_candidates(start: *u64, curr: *u64, algo: &mut DLDist, out: &mut ~[Word])
{
  unsafe {
    let header    = curr as *PTrieHeader;
    let kbegin    = curr + 3;
    let succbegin = curr + 3 + (*header).key_len;

    /*
     * Consume the current word’s letters
     */
    let mut accept = false;

    for uint::iterate(0u, (*header).key_len as uint) |i|
    {

      let (should_stop, accept_this) = algo.take(*(kbegin + i) as u8);

      accept = accept_this; // FIXME: uggly!

      if should_stop
      { return }
    }

    if accept && (*header).freq != 0
    { out.push(Word::new(str::from_bytes(algo.current), (*header).freq as uint, algo.dist())) }

    /*
     * Go to the children (recursive call)
     */
    let curr_len = algo.current.len();

    for uint::iterate(0u, (*header).nb_succ as uint) |i|
    {
      // first, partially reinitialise the algorithm
      algo.truncate(curr_len);

      let child_addr = start + *(succbegin + i);

      // and start the recursion on the next branch
      do_find_candidates(start, child_addr, algo, out);
    }
  }
}
<|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/
 */
#![allow(unused_variables)]

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

use ::universe::Universe;
use ::potentials::*;

use super::yaml::{YamlLoader, Yaml};
use super::{Error, Result};

trait FromYaml where Self: Sized {
    fn from_yaml(node: &Yaml) -> Result<Self>;
}

// TODO: Add support for * in atoms sections.

/// Read a interactions from a Yaml file at `path`, and add these interactions
/// to the `universe`.
///
/// The following format is accepted:
///
/// ```YAML
/// pairs:  # Non bonded atoms pairs
///   - atoms: [He, He]
///     type: LennardJones
///     sigma: 3.4 A
///     epsilon: 0.45 kJ/mol
///     # computations specification is optional
///     computation:
///       type: table
///       numpoints: 5000
///       max: 20.0 A
///   - atoms: [He, Ar]
///     type: LennardJones
///     sigma: 3.8 A
///     epsilon: 0.67 kJ/mol
///     computation:
///       type: cutoff
///       cutoff: 10 A
///   - atoms: [He, Ar]
///     type: NullPotential
/// bond: # Bonded atoms pairs
///   - atoms: [C, C]
///     type: Harmonic
///     k: 67 kJ/mol/A^2
///     x0: 1.20 A
/// angles: # Molecular angles
///   - atoms: [O, C, C]
///     type: CosineHarmonic
///     k: 67 kJ/mol/deg^2
///     x0: 120 deg
///   - atoms: [C, C, C]
///     type: harmonic
///     k: 300 kJ/mol/deg^2
///     x0: 120 deg
/// dihedrals: # Molecular angles
///   - atoms: [O, C, C, O]
///     type: harmonic
///     k: 42 kJ/mol/deg^2
///     x0: 180 deg
/// ```
///
/// The main items are the `"pairs"`, `"bonds"`, `"angles"` and `"dihedrals"`;
/// which contains the data for pair potentials, bonds, angles and dihedral
/// angles potential. This data is orgnised as a vector of hash maps. Each maps
/// has at least a vector of `"atoms"` defining which particles will get this
/// interaction applied to, and a `"type"` parameter defining the type of the
/// potential. Others keys may be supplied depending on the potential type.
pub fn read_potentials<P: AsRef<Path>>(universe: &mut Universe, path: P) -> Result<()> {
    let mut file = try!(File::open(path));
    let mut buff = String::new();
    try!(file.read_to_string(&mut buff));

    let doc = &try!(YamlLoader::load_from_str(&buff))[0];
    if let Some(config) = doc["pairs"].as_vec() {
        try!(read_pairs(universe, config, true));
    }

    if let Some(config) = doc["bonds"].as_vec() {
        try!(read_pairs(universe, config, false));
    }

    if let Some(config) = doc["angles"].as_vec() {
        try!(read_angles(universe, config));
    }

    if let Some(config) = doc["dihedrals"].as_vec() {
        try!(read_dihedrals(universe, config));
    }

    Ok(())
}

/// Read the "pairs" or the "bonds" section in the file. If `pair_potentials`
/// is `true`, then the interactions are added to the pair interactions. Else,
/// the interaction are added to the bond interactions.
fn read_pairs(universe: &mut Universe, pairs: &Vec<Yaml>, pair_potentials: bool) -> Result<()> {
    for potential in pairs {
        let (a, b) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 2 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in pair potentials. Should be 2, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b)) = (vec[0].as_str(), vec[1].as_str()) {
                    (a, b)
                } else {
                    return Err(Error::from("The atoms names are not strings in pair potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in pair potential"));
            }
        };

        let potential = if potential["computation"].as_hash().is_some() {
            try!(read_pair_computation(potential))
        } else {
            try!(read_pair_potential(potential))
        };

        if pair_potentials {
            universe.add_pair_interaction(a, b, potential);
        } else {
            universe.add_bond_interaction(a, b, potential);
        }
    }
    Ok(())
}

fn read_pair_potential(node: &Yaml) -> Result<Box<PairPotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from("Missing 'type' section in pair potential"))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "lennard-jones" | "lennardjones" => Ok(Box::new(try!(LennardJones::from_yaml(node)))),
                "null" | "nullpotential" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

fn read_angles(universe: &mut Universe, angles: &Vec<Yaml>) -> Result<()> {
    for potential in angles {
        let (a, b, c) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 3 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in angle potential. Should be 3, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b), Some(c)) = (vec[0].as_str(), vec[1].as_str(), vec[2].as_str()) {
                    (a, b, c)
                } else {
                    return Err(Error::from("The atoms names are not strings in angle potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in angles potential"));
            }
        };

        let potential = try!(read_angle_potential(potential));
        universe.add_angle_interaction(a, b, c, potential);
    }
    Ok(())
}

fn read_angle_potential(node: &Yaml) -> Result<Box<AnglePotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "cosine-harmonic" | "cosineharmonic" => Ok(Box::new(try!(CosineHarmonic::from_yaml(node)))),
                "null" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

fn read_dihedrals(universe: &mut Universe, dihedrals: &Vec<Yaml>) -> Result<()> {
    for potential in dihedrals {
        let (a, b, c, d) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 4 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in dihedral potential. Should be 4, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b), Some(c), Some(d)) = (vec[0].as_str(), vec[1].as_str(), vec[2].as_str(), vec[3].as_str()) {
                    (a, b, c, d)
                } else {
                    return Err(Error::from("The atoms names are not strings in dihedral potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in dihedral potential"));
            }
        };

        let potential = try!(read_dihedral_potential(potential));
        universe.add_dihedral_interaction(a, b, c, d, potential);
    }
    Ok(())
}

fn read_dihedral_potential(node: &Yaml) -> Result<Box<DihedralPotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "cosine-harmonic" | "cosineharmonic" => Ok(Box::new(try!(CosineHarmonic::from_yaml(node)))),
                "null" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

impl FromYaml for NullPotential {
    fn from_yaml(node: &Yaml) -> Result<NullPotential> {
        Ok(NullPotential)
    }
}

impl FromYaml for Harmonic {
    fn from_yaml(node: &Yaml) -> Result<Harmonic> {
        if let (Some(k), Some(x0)) = (node["k"].as_str(), node["x0"].as_str()) {
            let k = try!(::units::from_str(k));
            let x0 = try!(::units::from_str(x0));
            Ok(Harmonic{k: k, x0: x0})
        } else {
            Err(
                Error::from("Missing 'k' or 'x0' in harmonic potential")
            )
        }
    }
}

impl FromYaml for LennardJones {
    fn from_yaml(node: &Yaml) -> Result<LennardJones> {
        if let (Some(sigma), Some(epsilon)) = (node["sigma"].as_str(), node["epsilon"].as_str()) {
            let sigma = try!(::units::from_str(sigma));
            let epsilon = try!(::units::from_str(epsilon));
            Ok(LennardJones{sigma: sigma, epsilon: epsilon})
        } else {
            Err(
                Error::from("Missing 'sigma' or 'espilon' in Lennard-Jones potential")
            )
        }
    }
}

impl FromYaml for CosineHarmonic {
    fn from_yaml(node: &Yaml) -> Result<CosineHarmonic> {
        if let (Some(k), Some(x0)) = (node["k"].as_str(), node["x0"].as_str()) {
            let k = try!(::units::from_str(k));
            let x0 = try!(::units::from_str(x0));
            Ok(CosineHarmonic::new(k, x0))
        } else {
            Err(
                Error::from("Missing 'k' or 'x0' in cosine harmonic potential")
            )
        }
    }
}

/******************************************************************************/

fn read_pair_computation(node: &Yaml) -> Result<Box<PairPotential>> {
    let pot = try!(read_pair_potential(node));
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section for potential computation in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "cutoff" => Ok(Box::new(try!(CutoffComputation::from_yaml(node, pot)))),
                "table" => Ok(Box::new(try!(TableComputation::from_yaml(node, pot)))),
                val => Err(
                    Error::from(format!("Unknown computation type '{}'", val))
                ),
            }
        }
    }
}

trait FromYamlWithPairPotential where Self: Sized {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<Self>;
}

impl FromYamlWithPairPotential for CutoffComputation {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<CutoffComputation> {
        if let Some(cutoff) = node["cutoff"].as_str() {
            let cutoff = try!(::units::from_str(cutoff));
            Ok(CutoffComputation::new(potential, cutoff))
        } else {
            Err(
                Error::from("Missing 'cutoff' value in cutoff computation")
            )
        }
    }
}

impl FromYamlWithPairPotential for TableComputation {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<TableComputation> {
        if let (Some(n), Some(max)) = (node["n"].as_i64(), node["max"].as_str()) {
            let max = try!(::units::from_str(max));
            Ok(TableComputation::new(potential, n as usize, max))
        } else {
            Err(
                Error::from("Missing 'max' or 'n' value in cutoff computation")
            )
        }
    }
}
<commit_msg>Add coulomb section support in potential input files<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/
 */
#![allow(unused_variables)]

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

use ::universe::Universe;
use ::potentials::*;

use super::yaml::{YamlLoader, Yaml};
use super::{Error, Result};

trait FromYaml where Self: Sized {
    fn from_yaml(node: &Yaml) -> Result<Self>;
}

// TODO: Add support for * in atoms sections.

/// Read a interactions from a Yaml file at `path`, and add these interactions
/// to the `universe`.
///
/// The following format is accepted:
///
/// ```YAML
/// pairs:  # Non bonded atoms pairs
///   - atoms: [He, He]
///     type: LennardJones
///     sigma: 3.4 A
///     epsilon: 0.45 kJ/mol
///     # computations specification is optional
///     computation:
///       type: table
///       numpoints: 5000
///       max: 20.0 A
///   - atoms: [He, Ar]
///     type: LennardJones
///     sigma: 3.8 A
///     epsilon: 0.67 kJ/mol
///     computation:
///       type: cutoff
///       cutoff: 10 A
///   - atoms: [He, Ar]
///     type: NullPotential
/// bond: # Bonded atoms pairs
///   - atoms: [C, C]
///     type: Harmonic
///     k: 67 kJ/mol/A^2
///     x0: 1.20 A
/// angles: # Molecular angles
///   - atoms: [O, C, C]
///     type: CosineHarmonic
///     k: 67 kJ/mol/deg^2
///     x0: 120 deg
///   - atoms: [C, C, C]
///     type: harmonic
///     k: 300 kJ/mol/deg^2
///     x0: 120 deg
/// dihedrals: # Molecular angles
///   - atoms: [O, C, C, O]
///     type: harmonic
///     k: 42 kJ/mol/deg^2
///     x0: 180 deg
/// coulomb:
///   - type: wolf
///     cutoff: 10 A
///     charges:
///         O: -1.8
///         Na: 0.9
/// ```
///
/// The main items are the `"pairs"`, `"bonds"`, `"angles"` and `"dihedrals"`;
/// which contains the data for pair potentials, bonds, angles and dihedral
/// angles potential. This data is orgnised as a vector of hash maps. Each maps
/// has at least a vector of `"atoms"` defining which particles will get this
/// interaction applied to, and a `"type"` parameter defining the type of the
/// potential. Others keys may be supplied depending on the potential type.
///
/// The `"coulomb"` section specify how to compute the coulombic interactions.
/// It should contains the `type` and `charge` key, with data about charges to
/// assign to the system, and which method to use to compute these interactions.
pub fn read_potentials<P: AsRef<Path>>(universe: &mut Universe, path: P) -> Result<()> {
    let mut file = try!(File::open(path));
    let mut buff = String::new();
    try!(file.read_to_string(&mut buff));

    let doc = &try!(YamlLoader::load_from_str(&buff))[0];
    if let Some(config) = doc["pairs"].as_vec() {
        try!(read_pairs(universe, config, true));
    }

    if let Some(config) = doc["bonds"].as_vec() {
        try!(read_pairs(universe, config, false));
    }

    if let Some(config) = doc["angles"].as_vec() {
        try!(read_angles(universe, config));
    }

    if let Some(config) = doc["dihedrals"].as_vec() {
        try!(read_dihedrals(universe, config));
    }

    if doc["coulomb"].as_hash().is_some() {
        try!(read_coulomb(universe, &doc["coulomb"]));
    }

    Ok(())
}

/// Read the "pairs" or the "bonds" section in the file. If `pair_potentials`
/// is `true`, then the interactions are added to the pair interactions. Else,
/// the interaction are added to the bond interactions.
fn read_pairs(universe: &mut Universe, pairs: &Vec<Yaml>, pair_potentials: bool) -> Result<()> {
    for potential in pairs {
        let (a, b) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 2 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in pair potentials. Should be 2, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b)) = (vec[0].as_str(), vec[1].as_str()) {
                    (a, b)
                } else {
                    return Err(Error::from("The atoms names are not strings in pair potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in pair potential"));
            }
        };

        let potential = if potential["computation"].as_hash().is_some() {
            try!(read_pair_computation(potential))
        } else {
            try!(read_pair_potential(potential))
        };

        if pair_potentials {
            universe.add_pair_interaction(a, b, potential);
        } else {
            universe.add_bond_interaction(a, b, potential);
        }
    }
    Ok(())
}

fn read_pair_potential(node: &Yaml) -> Result<Box<PairPotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from("Missing 'type' section in pair potential"))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "lennard-jones" | "lennardjones" => Ok(Box::new(try!(LennardJones::from_yaml(node)))),
                "null" | "nullpotential" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

fn read_angles(universe: &mut Universe, angles: &Vec<Yaml>) -> Result<()> {
    for potential in angles {
        let (a, b, c) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 3 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in angle potential. Should be 3, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b), Some(c)) = (vec[0].as_str(), vec[1].as_str(), vec[2].as_str()) {
                    (a, b, c)
                } else {
                    return Err(Error::from("The atoms names are not strings in angle potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in angles potential"));
            }
        };

        let potential = try!(read_angle_potential(potential));
        universe.add_angle_interaction(a, b, c, potential);
    }
    Ok(())
}

fn read_angle_potential(node: &Yaml) -> Result<Box<AnglePotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "cosine-harmonic" | "cosineharmonic" => Ok(Box::new(try!(CosineHarmonic::from_yaml(node)))),
                "null" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

fn read_dihedrals(universe: &mut Universe, dihedrals: &Vec<Yaml>) -> Result<()> {
    for potential in dihedrals {
        let (a, b, c, d) = match potential["atoms"].as_vec() {
            Some(vec) => {
                if vec.len() != 4 {
                    return Err(Error::from(
                        format!("Wrong size for 'atoms' section in dihedral potential. Should be 4, is {}", vec.len())
                    ));
                }
                if let (Some(a), Some(b), Some(c), Some(d)) = (vec[0].as_str(), vec[1].as_str(), vec[2].as_str(), vec[3].as_str()) {
                    (a, b, c, d)
                } else {
                    return Err(Error::from("The atoms names are not strings in dihedral potential"));
                }
            },
            None => {
                return Err(Error::from("Missing 'atoms' section in dihedral potential"));
            }
        };

        let potential = try!(read_dihedral_potential(potential));
        universe.add_dihedral_interaction(a, b, c, d, potential);
    }
    Ok(())
}

fn read_dihedral_potential(node: &Yaml) -> Result<Box<DihedralPotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "harmonic" => Ok(Box::new(try!(Harmonic::from_yaml(node)))),
                "cosine-harmonic" | "cosineharmonic" => Ok(Box::new(try!(CosineHarmonic::from_yaml(node)))),
                "null" => Ok(Box::new(try!(NullPotential::from_yaml(node)))),
                val => Err(
                    Error::from(format!("Unknown potential type '{}'", val))
                ),
            }
        }
    }
}

/******************************************************************************/

impl FromYaml for NullPotential {
    fn from_yaml(node: &Yaml) -> Result<NullPotential> {
        Ok(NullPotential)
    }
}

impl FromYaml for Harmonic {
    fn from_yaml(node: &Yaml) -> Result<Harmonic> {
        if let (Some(k), Some(x0)) = (node["k"].as_str(), node["x0"].as_str()) {
            let k = try!(::units::from_str(k));
            let x0 = try!(::units::from_str(x0));
            Ok(Harmonic{k: k, x0: x0})
        } else {
            Err(
                Error::from("Missing 'k' or 'x0' in harmonic potential")
            )
        }
    }
}

impl FromYaml for LennardJones {
    fn from_yaml(node: &Yaml) -> Result<LennardJones> {
        if let (Some(sigma), Some(epsilon)) = (node["sigma"].as_str(), node["epsilon"].as_str()) {
            let sigma = try!(::units::from_str(sigma));
            let epsilon = try!(::units::from_str(epsilon));
            Ok(LennardJones{sigma: sigma, epsilon: epsilon})
        } else {
            Err(
                Error::from("Missing 'sigma' or 'espilon' in Lennard-Jones potential")
            )
        }
    }
}

impl FromYaml for CosineHarmonic {
    fn from_yaml(node: &Yaml) -> Result<CosineHarmonic> {
        if let (Some(k), Some(x0)) = (node["k"].as_str(), node["x0"].as_str()) {
            let k = try!(::units::from_str(k));
            let x0 = try!(::units::from_str(x0));
            Ok(CosineHarmonic::new(k, x0))
        } else {
            Err(
                Error::from("Missing 'k' or 'x0' in cosine harmonic potential")
            )
        }
    }
}

/******************************************************************************/

fn read_pair_computation(node: &Yaml) -> Result<Box<PairPotential>> {
    let pot = try!(read_pair_potential(node));
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section for potential computation in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "cutoff" => Ok(Box::new(try!(CutoffComputation::from_yaml(node, pot)))),
                "table" => Ok(Box::new(try!(TableComputation::from_yaml(node, pot)))),
                val => Err(
                    Error::from(format!("Unknown computation type '{}'", val))
                ),
            }
        }
    }
}

trait FromYamlWithPairPotential where Self: Sized {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<Self>;
}

impl FromYamlWithPairPotential for CutoffComputation {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<CutoffComputation> {
        if let Some(cutoff) = node["cutoff"].as_str() {
            let cutoff = try!(::units::from_str(cutoff));
            Ok(CutoffComputation::new(potential, cutoff))
        } else {
            Err(
                Error::from("Missing 'cutoff' value in cutoff computation")
            )
        }
    }
}

impl FromYamlWithPairPotential for TableComputation {
    fn from_yaml(node: &Yaml, potential: Box<PairPotential>) -> Result<TableComputation> {
        if let (Some(n), Some(max)) = (node["n"].as_i64(), node["max"].as_str()) {
            let max = try!(::units::from_str(max));
            Ok(TableComputation::new(potential, n as usize, max))
        } else {
            Err(
                Error::from("Missing 'max' or 'n' value in cutoff computation")
            )
        }
    }
}

/******************************************************************************/

fn read_coulomb(universe: &mut Universe, config: &Yaml) -> Result<()> {
    let potential = try!(read_global_potential(config));
    universe.add_global_interaction(potential);

    if config["charges"].as_hash().is_some() {
        try!(assign_charges(universe, &config["charges"]));
    }
    Ok(())
}

fn read_global_potential(node: &Yaml) -> Result<Box<GlobalPotential>> {
    match node["type"].as_str() {
        None => {
            Err(Error::from(
                format!("Missing 'type' section for coulomb section in: {:?}", node)
            ))
        }
        Some(val) => {
            let val: &str = &val.to_lowercase();
            match val {
                "wolf" => Ok(Box::new(try!(Wolf::from_yaml(node)))),
                val => Err(Error::from(format!("Unknown coulomb type '{}'", val))),
            }
        }
    }
}

impl FromYaml for Wolf {
    fn from_yaml(node: &Yaml) -> Result<Wolf> {
        if let Some(cutoff) = node["cutoff"].as_str() {
            let cutoff = try!(::units::from_str(cutoff));
            Ok(Wolf::new(cutoff))
        } else {
            Err(Error::from("Missing 'cutoff' value in Wolf potential"))
        }
    }
}

fn assign_charges(universe: &mut Universe, config: &Yaml) -> Result<()> {
    let charges = config.as_hash().unwrap();
    for (name, charge) in charges {
        if let (Some(name), Some(charge)) = (name.as_str(), charge.as_f64()) {
            let mut changed = 0;
            for particle in universe.iter_mut() {
                if particle.name() == name {
                    particle.set_charge(charge);
                    changed += 1;
                }
            }
            if changed == 0 {
                return Err(Error::from(format!("No particle with the name {} was found", name)));
            } else {
                info!("Charge was set for {} particles", changed);
            }
        } else {
            return Err(
                Error::from(format!("Bad Yaml format in charges section: {:?}, {:?}", name, charge))
            );
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use artano::{self, Canvas, Typeface};
use config::{Options, OutputFormat};
use error::Error;
use std::path::Path;
use std::result;

type Result<T> = result::Result<T, Error>;

pub struct App;

impl App {
    pub fn run(&self, options: &Options) -> Result<()> {
        let font = build_font(&options.font_path)?;
        let mut canvas = options
            .base_image
            .get()
            .map_err(|e| Error::not_found("Base image not found", e))
            .and_then(|buf| {
                Canvas::read_from_buffer(&buf).map_err(|e| Error::bad_image(e))
            })?;

        for annotation in &options.annotations {
            canvas.add_annotation(annotation, &font, options.scale_mult);
        }

        canvas.render();
        save_pixels(&options.output_path, &canvas, options.output_format)
    }
}

fn build_font(path: &Path) -> Result<Typeface> {
    use std::fs::File;
    use std::io::BufReader;

    let data = File::open(path).map_err(
        |e| Error::not_found("Font not found", e),
    )?;

    artano::load_typeface(&mut BufReader::new(data)).map_err(
        |e| {
            Error::io("Unable to read font", e)
        },
    )
}

fn save_pixels<P: AsRef<Path>>(path: P, canvas: &Canvas, format: OutputFormat) -> Result<()> {
    use std::fs::OpenOptions;

    let mut out = OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(path.as_ref())
        .map_err(|e| Error::io("Unable to write to output", e))?;

    let result = match format {
        OutputFormat::Png => canvas.save_png(&mut out),
        OutputFormat::Jpg => canvas.save_jpg(&mut out),
    };

    result.map_err(|e| Error::io("Unable to save image to output", e))
}
<commit_msg>Clippy lints<commit_after>use artano::{self, Canvas, Typeface};
use config::{Options, OutputFormat};
use error::Error;
use std::path::Path;
use std::result;

type Result<T> = result::Result<T, Error>;

pub struct App;

impl App {
    pub fn run(&self, options: &Options) -> Result<()> {
        let font = build_font(&options.font_path)?;
        let mut canvas = options
            .base_image
            .get()
            .map_err(|e| Error::not_found("Base image not found", e))
            .and_then(|buf| {
                Canvas::read_from_buffer(&buf).map_err(Error::bad_image)
            })?;

        for annotation in &options.annotations {
            canvas.add_annotation(annotation, &font, options.scale_mult);
        }

        canvas.render();
        save_pixels(&options.output_path, &canvas, options.output_format)
    }
}

fn build_font(path: &Path) -> Result<Typeface> {
    use std::fs::File;
    use std::io::BufReader;

    let data = File::open(path).map_err(
        |e| Error::not_found("Font not found", e),
    )?;

    artano::load_typeface(&mut BufReader::new(data)).map_err(
        |e| {
            Error::io("Unable to read font", e)
        },
    )
}

fn save_pixels<P: AsRef<Path>>(path: P, canvas: &Canvas, format: OutputFormat) -> Result<()> {
    use std::fs::OpenOptions;

    let mut out = OpenOptions::new()
        .write(true)
        .create(true)
        .truncate(true)
        .open(path.as_ref())
        .map_err(|e| Error::io("Unable to write to output", e))?;

    let result = match format {
        OutputFormat::Png => canvas.save_png(&mut out),
        OutputFormat::Jpg => canvas.save_jpg(&mut out),
    };

    result.map_err(|e| Error::io("Unable to save image to output", e))
}
<|endoftext|>


<commit_before>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);
const MATRIX: Token = Token(1);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seenEvents: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        println!("Got message from matrix! {:?}", msg);
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![]
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                for ref user in &self.members {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                if self.canonical_alias != None {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
                self.members.push(user);
            },
            matrix::events::RoomEvent::Message(user, text) => {
                callback(irc::protocol::Message {
                    prefix: Some(format!("{}@anony.oob", user.nickname)),
                    command: irc::protocol::Command::Privmsg,
                    args: vec![self.canonical_alias.clone().unwrap()],
                    suffix: Some(text)
                });
            },
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases => (),
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => ()
        };
    }
}

impl Bridge {
    pub fn room(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seenEvents: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seenEvents.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let appendMsg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room(&room_id).handle_event(room_event, appendMsg);
                    },
                    _ => println!("Unhandled {:?}", evt)
                }
            }
            match evt.id {
                Some(id) =>
                    self.seenEvents.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg);
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) -> thread::JoinHandle<()> {
        let poll = self.matrix.pollAsync();
        thread::spawn(move|| {
            for evt in poll.send() {
                channel.send(Event::Matrix(evt));
            };
            channel.send(Event::EndPoll);
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) {
        self.matrix.sync(|evt: matrix::events::Event| {
            channel.send(Event::Matrix(evt));
        });
        self.poll_matrix(channel);
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    println!("Got a message! {:?}", message);
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            println!("User logged in: {}", message.args[0]);
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim());
                                    self.client.welcome(username.trim());
                                    self.start_matrix(events.channel());
                                    println!("Logged in {:?}", username);
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]);
                        },
                        Command::Ping => {
                            self.client.pong();
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let uid = matrix::events::UserID::from_str("@tdfischer:localhost");
                            let roomid = matrix::events::RoomID::from_str("!SNCDinqFeGteFrlCoN:localhost");
                            let evt = matrix::events::EventData::Room(
                                roomid,
                                matrix::events::RoomEvent::Message(
                                    uid, message.suffix.unwrap()));
                            self.seenEvents.push(self.matrix.send(evt));
                        },
                        _ =>
                            println!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<commit_msg>bridge: handle name change event<commit_after>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);
const MATRIX: Token = Token(1);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seenEvents: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        println!("Got message from matrix! {:?}", msg);
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![]
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                for ref user in &self.members {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                if self.canonical_alias != None {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
                self.members.push(user);
            },
            matrix::events::RoomEvent::Message(user, text) => {
                callback(irc::protocol::Message {
                    prefix: Some(format!("{}@anony.oob", user.nickname)),
                    command: irc::protocol::Command::Privmsg,
                    args: vec![self.canonical_alias.clone().unwrap()],
                    suffix: Some(text)
                });
            },
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases => (),
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => ()
        };
    }
}

impl Bridge {
    pub fn room(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seenEvents: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seenEvents.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let appendMsg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room(&room_id).handle_event(room_event, appendMsg);
                    },
                    _ => println!("Unhandled {:?}", evt)
                }
            }
            match evt.id {
                Some(id) =>
                    self.seenEvents.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg);
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) -> thread::JoinHandle<()> {
        let poll = self.matrix.pollAsync();
        thread::spawn(move|| {
            for evt in poll.send() {
                channel.send(Event::Matrix(evt));
            };
            channel.send(Event::EndPoll);
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) {
        self.matrix.sync(|evt: matrix::events::Event| {
            channel.send(Event::Matrix(evt));
        });
        self.poll_matrix(channel);
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    println!("Got a message! {:?}", message);
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            println!("User logged in: {}", message.args[0]);
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim());
                                    self.client.welcome(username.trim());
                                    self.start_matrix(events.channel());
                                    println!("Logged in {:?}", username);
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]);
                        },
                        Command::Ping => {
                            self.client.pong();
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let uid = matrix::events::UserID::from_str("@tdfischer:localhost");
                            let roomid = matrix::events::RoomID::from_str("!SNCDinqFeGteFrlCoN:localhost");
                            let evt = matrix::events::EventData::Room(
                                roomid,
                                matrix::events::RoomEvent::Message(
                                    uid, message.suffix.unwrap()));
                            self.seenEvents.push(self.matrix.send(evt));
                        },
                        _ =>
                            println!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>use toml:: { Parser, Decoder, Value };
use rustc_serialize:: { Decodable };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
use std::convert:: { From };

#[derive(RustcDecodable)]
pub struct Configuration {
    server: Server
}

#[derive(RustcDecodable)]
pub struct Server {
    host: String,
    port: u16
}

impl<'a> From<&'a Path> for Configuration {
    fn from(path: &'a Path) -> Self {
        from_toml_file(path).unwrap()
    }
}

impl Default for Server {
    fn default() -> Self {
        Server {
            host: "127.0.0.1".to_string(),
            port: 6767
        }
    }
}

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            server: Server::default()
        }
    }
}

pub fn from_toml_file(path: &Path) -> Result<Configuration> {
    let content = read_file(path).unwrap();
    let toml = &content[..];
    let value = Parser::new(toml).parse().unwrap();
    let mut decoder = Decoder::new(Value::Table(value));
    let configuration = Configuration::decode(&mut decoder).unwrap();
    Ok(configuration)
}

pub fn read_file(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(buffer.clone())
}

#[cfg(test)]
mod tests {
    use std::path:: { Path };
    use std::env:: { current_dir };
    use configuration:: { read_file, Server, Configuration };

    #[test]
    fn test_read_file() {
        let cwd = current_dir().unwrap();
        let path = Path::new(&cwd).join("tests/fixtures/server.toml");
        let content = read_file(path.as_path());
        let expected = r#"[server]
host = "127.0.0.1"
port = 3000
"#;

        assert_eq!(content.unwrap(), expected.to_string());
    }

    #[test]
    fn test_server_default() {
        let server = Server::default();

        assert_eq!(server.host, "127.0.0.1".to_string());
        assert_eq!(server.port, 6767);
    }

    #[test]
    fn test_config_default() {
        let config = Configuration::default();

        assert_eq!(config.server.host, "127.0.0.1".to_string());
        assert_eq!(config.server.port, 6767);
    }

}
<commit_msg>impl ToSocketAddrs<commit_after>use toml:: { Parser, Decoder, Value };
use rustc_serialize:: { Decodable };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
use std::convert:: { From };
use std::net:: { ToSocketAddrs, SocketAddr };
use std::vec:: { IntoIter };

#[derive(RustcDecodable)]
pub struct Configuration {
    server: Server
}

#[derive(RustcDecodable)]
pub struct Server {
    host: String,
    port: u16
}

impl<'a> From<&'a Path> for Configuration {
    fn from(path: &'a Path) -> Self {
        from_toml_file(path).unwrap()
    }
}

impl Default for Server {
    fn default() -> Self {
        Server {
            host: "127.0.0.1".to_string(),
            port: 6767
        }
    }
}

impl ToSocketAddrs for Server {
    type Iter = IntoIter<SocketAddr>;

    fn to_socket_addrs(&self) -> Result<Self::Iter> {
        let address = format!("{}:{}", self.host, self.port);
        address[..].to_socket_addrs()
    }
}

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            server: Server::default()
        }
    }
}

pub fn from_toml_file(path: &Path) -> Result<Configuration> {
    let content = read_file(path).unwrap();
    let toml = &content[..];
    let value = Parser::new(toml).parse().unwrap();
    let mut decoder = Decoder::new(Value::Table(value));
    let configuration = Configuration::decode(&mut decoder).unwrap();
    Ok(configuration)
}

pub fn read_file(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(buffer.clone())
}

#[cfg(test)]
mod tests {
    use std::path:: { Path };
    use std::env:: { current_dir };
    use configuration:: { read_file, Server, Configuration };

    #[test]
    fn test_read_file() {
        let cwd = current_dir().unwrap();
        let path = Path::new(&cwd).join("tests/fixtures/server.toml");
        let content = read_file(path.as_path());
        let expected = r#"[server]
host = "127.0.0.1"
port = 3000
"#;

        assert_eq!(content.unwrap(), expected.to_string());
    }

    #[test]
    fn test_server_default() {
        let server = Server::default();

        assert_eq!(server.host, "127.0.0.1".to_string());
        assert_eq!(server.port, 6767);
    }

    #[test]
    fn test_config_default() {
        let config = Configuration::default();

        assert_eq!(config.server.host, "127.0.0.1".to_string());
        assert_eq!(config.server.port, 6767);
    }

}
<|endoftext|>


<commit_before>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[feature(globs)];

#[feature(globs)];

extern crate cgmath;
extern crate test;

// pub mod array;
pub mod matrix;
// pub mod quaternion;
//pub mod vector;

//pub mod angle;
//pub mod plane;
//pub mod point;
// pub mod ray;
// pub mod rotation;
//pub mod transform;

// pub mod projection;

// pub mod aabb;
// pub mod cylinder;
// pub mod frustum;
// pub mod intersect;
// pub mod obb;
//pub mod sphere;
<commit_msg>Update crate attribute.<commit_after>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![feature(globs)]

extern crate cgmath;
extern crate test;

// pub mod array;
pub mod matrix;
// pub mod quaternion;
//pub mod vector;

//pub mod angle;
//pub mod plane;
//pub mod point;
// pub mod ray;
// pub mod rotation;
//pub mod transform;

// pub mod projection;

// pub mod aabb;
// pub mod cylinder;
// pub mod frustum;
// pub mod intersect;
// pub mod obb;
//pub mod sphere;
<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, Arg};

fn main() {

    let matches = App::new("aux2bib")
                        .version("0.1.0")
                        .author("Nathan Musoke")
                        .about("gets BibTeX keys from Inspire")
                        .arg(Arg::with_name("INPUT")
                             .help("Sets the input file to use")
                             .index(1))
                        .arg(Arg::with_name("OUTPUT")
                            .help("Sets the output file to use")
                            .index(2))
                        .get_matches();
}
<commit_msg>Use clap macros for version and author<commit_after>#[macro_use(crate_version, crate_authors)]
extern crate clap;

use clap::{App, Arg};

fn main() {

    let matches = App::new("aux2bib")
                        .version(crate_version!())
                        .author(crate_authors!(",\n"))
                        .about("gets BibTeX keys from Inspire")
                        .arg(Arg::with_name("INPUT")
                             .help("Sets the input file to use")
                             .index(1))
                        .arg(Arg::with_name("OUTPUT")
                            .help("Sets the output file to use")
                            .index(2))
                        .get_matches();
}
<|endoftext|>


<commit_before>//! Support for capturing a stack backtrace of an OS thread
//!
//! This module contains the support necessary to capture a stack backtrace of a
//! running OS thread from the OS thread itself. The `Backtrace` type supports
//! capturing a stack trace via the `Backtrace::capture` and
//! `Backtrace::force_capture` functions.
//!
//! A backtrace is typically quite handy to attach to errors (e.g. types
//! implementing `std::error::Error`) to get a causal chain of where an error
//! was generated.
//!
//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
//! > can learn more about its status in the [tracking issue].
//!
//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
//!
//! ## Accuracy
//!
//! Backtraces are attempted to be as accurate as possible, but no guarantees
//! are provided about the exact accuracy of a backtrace. Instruction pointers,
//! symbol names, filenames, line numbers, etc, may all be incorrect when
//! reported. Accuracy is attempted on a best-effort basis, however, and bugs
//! are always welcome to indicate areas of improvement!
//!
//! For most platforms a backtrace with a filename/line number requires that
//! programs be compiled with debug information. Without debug information
//! filenames/line numbers will not be reported.
//!
//! ## Platform support
//!
//! Not all platforms that libstd compiles for support capturing backtraces.
//! Some platforms simply do nothing when capturing a backtrace. To check
//! whether the platform supports capturing backtraces you can consult the
//! `BacktraceStatus` enum as a result of `Backtrace::status`.
//!
//! Like above with accuracy platform support is done on a best effort basis.
//! Sometimes libraries may not be available at runtime or something may go
//! wrong which would cause a backtrace to not be captured. Please feel free to
//! report issues with platforms where a backtrace cannot be captured though!
//!
//! ## Environment Variables
//!
//! The `Backtrace::capture` function may not actually capture a backtrace by
//! default. Its behavior is governed by two environment variables:
//!
//! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture`
//!   will never capture a backtrace. Any other value this is set to will enable
//!   `Backtrace::capture`.
//!
//! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable
//!   is consulted with the same rules of `RUST_LIB_BACKTRACE`.
//!
//! * If neither of the above env vars are set, then `Backtrace::capture` will
//!   be disabled.
//!
//! Capturing a backtrace can be a quite expensive runtime operation, so the
//! environment variables allow either forcibly disabling this runtime
//! performance hit or allow selectively enabling it in some programs.
//!
//! Note that the `Backtrace::force_capture` function can be used to ignore
//! these environment variables. Also note that the state of environment
//! variables is cached once the first backtrace is created, so altering
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime may not actually change
//! how backtraces are captured.

#![unstable(feature = "backtrace", issue = "53487")]

// NB: A note on resolution of a backtrace:
//
// Backtraces primarily happen in two steps, one is where we actually capture
// the stack backtrace, giving us a list of instruction pointers corresponding
// to stack frames. Next we take these instruction pointers and, one-by-one,
// turn them into a human readable name (like `main`).
//
// The first phase can be somewhat expensive (walking the stack), especially
// on MSVC where debug information is consulted to return inline frames each as
// their own frame. The second phase, however, is almost always extremely
// expensive (on the order of milliseconds sometimes) when it's consulting debug
// information.
//
// We attempt to amortize this cost as much as possible by delaying resolution
// of an address to a human readable name for as long as possible. When
// `Backtrace::create` is called to capture a backtrace it doesn't actually
// perform any symbol resolution, but rather we lazily resolve symbols only just
// before they're needed for printing. This way we can make capturing a
// backtrace and throwing it away much cheaper, but actually printing a
// backtrace is still basically the same cost.
//
// This strategy comes at the cost of some synchronization required inside of a
// `Backtrace`, but that's a relatively small price to pay relative to capturing
// a backtrace or actually symbolizing it.

use crate::env;
use crate::fmt;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sync::Mutex;
use crate::sys_common::backtrace::{lock, output_filename};
use crate::vec::Vec;
use backtrace::BytesOrWideString;
use backtrace_rs as backtrace;

/// A captured OS thread stack backtrace.
///
/// This type represents a stack backtrace for an OS thread captured at a
/// previous point in time. In some instances the `Backtrace` type may
/// internally be empty due to configuration. For more information see
/// `Backtrace::capture`.
pub struct Backtrace {
    inner: Inner,
}

/// The current status of a backtrace, indicating whether it was captured or
/// whether it is empty for some other reason.
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
pub enum BacktraceStatus {
    /// Capturing a backtrace is not supported, likely because it's not
    /// implemented for the current platform.
    Unsupported,
    /// Capturing a backtrace has been disabled through either the
    /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
    Disabled,
    /// A backtrace has been captured and the `Backtrace` should print
    /// reasonable information when rendered.
    Captured,
}

enum Inner {
    Unsupported,
    Disabled,
    Captured(Mutex<Capture>),
}

struct Capture {
    actual_start: usize,
    resolved: bool,
    frames: Vec<BacktraceFrame>,
}

fn _assert_send_sync() {
    fn _assert<T: Send + Sync>() {}
    _assert::<Backtrace>();
}

struct BacktraceFrame {
    frame: backtrace::Frame,
    symbols: Vec<BacktraceSymbol>,
}

struct BacktraceSymbol {
    name: Option<Vec<u8>>,
    filename: Option<BytesOrWide>,
    lineno: Option<u32>,
}

enum BytesOrWide {
    Bytes(Vec<u8>),
    Wide(Vec<u16>),
}

impl Backtrace {
    /// Returns whether backtrace captures are enabled through environment
    /// variables.
    fn enabled() -> bool {
        // Cache the result of reading the environment variables to make
        // backtrace captures speedy, because otherwise reading environment
        // variables every time can be somewhat slow.
        static ENABLED: AtomicUsize = AtomicUsize::new(0);
        match ENABLED.load(SeqCst) {
            0 => {}
            1 => return false,
            _ => return true,
        }
        let enabled = match env::var("RUST_LIB_BACKTRACE") {
            Ok(s) => s != "0",
            Err(_) => match env::var("RUST_BACKTRACE") {
                Ok(s) => s != "0",
                Err(_) => false,
            },
        };
        ENABLED.store(enabled as usize + 1, SeqCst);
        return enabled;
    }

    /// Capture a stack backtrace of the current thread.
    ///
    /// This function will capture a stack backtrace of the current OS thread of
    /// execution, returning a `Backtrace` type which can be later used to print
    /// the entire stack trace or render it to a string.
    ///
    /// This function will be a noop if the `RUST_BACKTRACE` or
    /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either
    /// environment variable is set and enabled then this function will actually
    /// capture a backtrace. Capturing a backtrace can be both memory intensive
    /// and slow, so these environment variables allow liberally using
    /// `Backtrace::capture` and only incurring a slowdown when the environment
    /// variables are set.
    ///
    /// To forcibly capture a backtrace regardless of environment variables, use
    /// the `Backtrace::force_capture` function.
    #[inline(never)] // want to make sure there's a frame here to remove
    pub fn capture() -> Backtrace {
        if !Backtrace::enabled() {
            return Backtrace { inner: Inner::Disabled };
        }
        Backtrace::create(Backtrace::capture as usize)
    }

    /// Forcibly captures a full backtrace, regardless of environment variable
    /// configuration.
    ///
    /// This function behaves the same as `capture` except that it ignores the
    /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment
    /// variables, always capturing a backtrace.
    ///
    /// Note that capturing a backtrace can be an expensive operation on some
    /// platforms, so this should be used with caution in performance-sensitive
    /// parts of code.
    #[inline(never)] // want to make sure there's a frame here to remove
    pub fn force_capture() -> Backtrace {
        Backtrace::create(Backtrace::force_capture as usize)
    }

    // Capture a backtrace which start just before the function addressed by
    // `ip`
    fn create(ip: usize) -> Backtrace {
        let _lock = lock();
        let mut frames = Vec::new();
        let mut actual_start = None;
        unsafe {
            backtrace::trace_unsynchronized(|frame| {
                frames.push(BacktraceFrame { frame: frame.clone(), symbols: Vec::new() });
                if frame.symbol_address() as usize == ip && actual_start.is_none() {
                    actual_start = Some(frames.len());
                }
                true
            });
        }

        // If no frames came out assume that this is an unsupported platform
        // since `backtrace` doesn't provide a way of learning this right now,
        // and this should be a good enough approximation.
        let inner = if frames.len() == 0 {
            Inner::Unsupported
        } else {
            Inner::Captured(Mutex::new(Capture {
                actual_start: actual_start.unwrap_or(0),
                frames,
                resolved: false,
            }))
        };

        Backtrace { inner }
    }

    /// Returns the status of this backtrace, indicating whether this backtrace
    /// request was unsupported, disabled, or a stack trace was actually
    /// captured.
    pub fn status(&self) -> BacktraceStatus {
        match self.inner {
            Inner::Unsupported => BacktraceStatus::Unsupported,
            Inner::Disabled => BacktraceStatus::Disabled,
            Inner::Captured(_) => BacktraceStatus::Captured,
        }
    }
}

impl fmt::Display for Backtrace {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self, fmt)
    }
}

impl fmt::Debug for Backtrace {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut capture = match &self.inner {
            Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
            Inner::Disabled => return fmt.write_str("disabled backtrace"),
            Inner::Captured(c) => c.lock().unwrap(),
        };
        capture.resolve();

        let full = fmt.alternate();
        let (frames, style) = if full {
            (&capture.frames[..], backtrace::PrintFmt::Full)
        } else {
            (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short)
        };

        // When printing paths we try to strip the cwd if it exists, otherwise
        // we just print the path as-is. Note that we also only do this for the
        // short format, because if it's full we presumably want to print
        // everything.
        let cwd = crate::env::current_dir();
        let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
            output_filename(fmt, path, style, cwd.as_ref().ok())
        };

        let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path);
        f.add_context()?;
        for frame in frames {
            let mut f = f.frame();
            if frame.symbols.is_empty() {
                f.print_raw(frame.frame.ip(), None, None, None)?;
            } else {
                for symbol in frame.symbols.iter() {
                    f.print_raw(
                        frame.frame.ip(),
                        symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)),
                        symbol.filename.as_ref().map(|b| match b {
                            BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                            BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
                        }),
                        symbol.lineno,
                    )?;
                }
            }
        }
        f.finish()?;
        Ok(())
    }
}

impl Capture {
    fn resolve(&mut self) {
        // If we're already resolved, nothing to do!
        if self.resolved {
            return;
        }
        self.resolved = true;

        // Use the global backtrace lock to synchronize this as it's a
        // requirement of the `backtrace` crate, and then actually resolve
        // everything.
        let _lock = lock();
        for frame in self.frames.iter_mut() {
            let symbols = &mut frame.symbols;
            unsafe {
                backtrace::resolve_frame_unsynchronized(&frame.frame, |symbol| {
                    symbols.push(BacktraceSymbol {
                        name: symbol.name().map(|m| m.as_bytes().to_vec()),
                        filename: symbol.filename_raw().map(|b| match b {
                            BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
                            BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
                        }),
                        lineno: symbol.lineno(),
                    });
                });
            }
        }
    }
}
<commit_msg>Rollup merge of #69038 - yaahc:backtrace-debug, r=dtolnay<commit_after>//! Support for capturing a stack backtrace of an OS thread
//!
//! This module contains the support necessary to capture a stack backtrace of a
//! running OS thread from the OS thread itself. The `Backtrace` type supports
//! capturing a stack trace via the `Backtrace::capture` and
//! `Backtrace::force_capture` functions.
//!
//! A backtrace is typically quite handy to attach to errors (e.g. types
//! implementing `std::error::Error`) to get a causal chain of where an error
//! was generated.
//!
//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
//! > can learn more about its status in the [tracking issue].
//!
//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
//!
//! ## Accuracy
//!
//! Backtraces are attempted to be as accurate as possible, but no guarantees
//! are provided about the exact accuracy of a backtrace. Instruction pointers,
//! symbol names, filenames, line numbers, etc, may all be incorrect when
//! reported. Accuracy is attempted on a best-effort basis, however, and bugs
//! are always welcome to indicate areas of improvement!
//!
//! For most platforms a backtrace with a filename/line number requires that
//! programs be compiled with debug information. Without debug information
//! filenames/line numbers will not be reported.
//!
//! ## Platform support
//!
//! Not all platforms that libstd compiles for support capturing backtraces.
//! Some platforms simply do nothing when capturing a backtrace. To check
//! whether the platform supports capturing backtraces you can consult the
//! `BacktraceStatus` enum as a result of `Backtrace::status`.
//!
//! Like above with accuracy platform support is done on a best effort basis.
//! Sometimes libraries may not be available at runtime or something may go
//! wrong which would cause a backtrace to not be captured. Please feel free to
//! report issues with platforms where a backtrace cannot be captured though!
//!
//! ## Environment Variables
//!
//! The `Backtrace::capture` function may not actually capture a backtrace by
//! default. Its behavior is governed by two environment variables:
//!
//! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture`
//!   will never capture a backtrace. Any other value this is set to will enable
//!   `Backtrace::capture`.
//!
//! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable
//!   is consulted with the same rules of `RUST_LIB_BACKTRACE`.
//!
//! * If neither of the above env vars are set, then `Backtrace::capture` will
//!   be disabled.
//!
//! Capturing a backtrace can be a quite expensive runtime operation, so the
//! environment variables allow either forcibly disabling this runtime
//! performance hit or allow selectively enabling it in some programs.
//!
//! Note that the `Backtrace::force_capture` function can be used to ignore
//! these environment variables. Also note that the state of environment
//! variables is cached once the first backtrace is created, so altering
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime may not actually change
//! how backtraces are captured.

#![unstable(feature = "backtrace", issue = "53487")]

// NB: A note on resolution of a backtrace:
//
// Backtraces primarily happen in two steps, one is where we actually capture
// the stack backtrace, giving us a list of instruction pointers corresponding
// to stack frames. Next we take these instruction pointers and, one-by-one,
// turn them into a human readable name (like `main`).
//
// The first phase can be somewhat expensive (walking the stack), especially
// on MSVC where debug information is consulted to return inline frames each as
// their own frame. The second phase, however, is almost always extremely
// expensive (on the order of milliseconds sometimes) when it's consulting debug
// information.
//
// We attempt to amortize this cost as much as possible by delaying resolution
// of an address to a human readable name for as long as possible. When
// `Backtrace::create` is called to capture a backtrace it doesn't actually
// perform any symbol resolution, but rather we lazily resolve symbols only just
// before they're needed for printing. This way we can make capturing a
// backtrace and throwing it away much cheaper, but actually printing a
// backtrace is still basically the same cost.
//
// This strategy comes at the cost of some synchronization required inside of a
// `Backtrace`, but that's a relatively small price to pay relative to capturing
// a backtrace or actually symbolizing it.

use crate::env;
use crate::fmt;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sync::Mutex;
use crate::sys_common::backtrace::{lock, output_filename};
use crate::vec::Vec;
use backtrace::BytesOrWideString;
use backtrace_rs as backtrace;

/// A captured OS thread stack backtrace.
///
/// This type represents a stack backtrace for an OS thread captured at a
/// previous point in time. In some instances the `Backtrace` type may
/// internally be empty due to configuration. For more information see
/// `Backtrace::capture`.
pub struct Backtrace {
    inner: Inner,
}

/// The current status of a backtrace, indicating whether it was captured or
/// whether it is empty for some other reason.
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
pub enum BacktraceStatus {
    /// Capturing a backtrace is not supported, likely because it's not
    /// implemented for the current platform.
    Unsupported,
    /// Capturing a backtrace has been disabled through either the
    /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
    Disabled,
    /// A backtrace has been captured and the `Backtrace` should print
    /// reasonable information when rendered.
    Captured,
}

enum Inner {
    Unsupported,
    Disabled,
    Captured(Mutex<Capture>),
}

struct Capture {
    actual_start: usize,
    resolved: bool,
    frames: Vec<BacktraceFrame>,
}

fn _assert_send_sync() {
    fn _assert<T: Send + Sync>() {}
    _assert::<Backtrace>();
}

struct BacktraceFrame {
    frame: backtrace::Frame,
    symbols: Vec<BacktraceSymbol>,
}

struct BacktraceSymbol {
    name: Option<Vec<u8>>,
    filename: Option<BytesOrWide>,
    lineno: Option<u32>,
}

enum BytesOrWide {
    Bytes(Vec<u8>),
    Wide(Vec<u16>),
}

impl fmt::Debug for Backtrace {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut capture = match &self.inner {
            Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
            Inner::Disabled => return fmt.write_str("disabled backtrace"),
            Inner::Captured(c) => c.lock().unwrap(),
        };
        capture.resolve();

        let frames = &capture.frames[capture.actual_start..];

        write!(fmt, "Backtrace ")?;

        let mut dbg = fmt.debug_list();

        for frame in frames {
            if frame.frame.ip().is_null() {
                continue;
            }

            dbg.entries(&frame.symbols);
        }

        dbg.finish()
    }
}

impl fmt::Debug for BacktraceSymbol {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{{ ")?;

        if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
            write!(fmt, "fn: \"{:#}\"", fn_name)?;
        } else {
            write!(fmt, "fn: \"<unknown>\"")?;
        }

        if let Some(fname) = self.filename.as_ref() {
            write!(fmt, ", file: {:?}", fname)?;
        }

        if let Some(line) = self.lineno.as_ref() {
            write!(fmt, ", line: {:?}", line)?;
        }

        write!(fmt, " }}")
    }
}

impl fmt::Debug for BytesOrWide {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        output_filename(
            fmt,
            match self {
                BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
            },
            backtrace::PrintFmt::Short,
            crate::env::current_dir().as_ref().ok(),
        )
    }
}

impl Backtrace {
    /// Returns whether backtrace captures are enabled through environment
    /// variables.
    fn enabled() -> bool {
        // Cache the result of reading the environment variables to make
        // backtrace captures speedy, because otherwise reading environment
        // variables every time can be somewhat slow.
        static ENABLED: AtomicUsize = AtomicUsize::new(0);
        match ENABLED.load(SeqCst) {
            0 => {}
            1 => return false,
            _ => return true,
        }
        let enabled = match env::var("RUST_LIB_BACKTRACE") {
            Ok(s) => s != "0",
            Err(_) => match env::var("RUST_BACKTRACE") {
                Ok(s) => s != "0",
                Err(_) => false,
            },
        };
        ENABLED.store(enabled as usize + 1, SeqCst);
        return enabled;
    }

    /// Capture a stack backtrace of the current thread.
    ///
    /// This function will capture a stack backtrace of the current OS thread of
    /// execution, returning a `Backtrace` type which can be later used to print
    /// the entire stack trace or render it to a string.
    ///
    /// This function will be a noop if the `RUST_BACKTRACE` or
    /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either
    /// environment variable is set and enabled then this function will actually
    /// capture a backtrace. Capturing a backtrace can be both memory intensive
    /// and slow, so these environment variables allow liberally using
    /// `Backtrace::capture` and only incurring a slowdown when the environment
    /// variables are set.
    ///
    /// To forcibly capture a backtrace regardless of environment variables, use
    /// the `Backtrace::force_capture` function.
    #[inline(never)] // want to make sure there's a frame here to remove
    pub fn capture() -> Backtrace {
        if !Backtrace::enabled() {
            return Backtrace { inner: Inner::Disabled };
        }
        Backtrace::create(Backtrace::capture as usize)
    }

    /// Forcibly captures a full backtrace, regardless of environment variable
    /// configuration.
    ///
    /// This function behaves the same as `capture` except that it ignores the
    /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment
    /// variables, always capturing a backtrace.
    ///
    /// Note that capturing a backtrace can be an expensive operation on some
    /// platforms, so this should be used with caution in performance-sensitive
    /// parts of code.
    #[inline(never)] // want to make sure there's a frame here to remove
    pub fn force_capture() -> Backtrace {
        Backtrace::create(Backtrace::force_capture as usize)
    }

    // Capture a backtrace which start just before the function addressed by
    // `ip`
    fn create(ip: usize) -> Backtrace {
        let _lock = lock();
        let mut frames = Vec::new();
        let mut actual_start = None;
        unsafe {
            backtrace::trace_unsynchronized(|frame| {
                frames.push(BacktraceFrame { frame: frame.clone(), symbols: Vec::new() });
                if frame.symbol_address() as usize == ip && actual_start.is_none() {
                    actual_start = Some(frames.len());
                }
                true
            });
        }

        // If no frames came out assume that this is an unsupported platform
        // since `backtrace` doesn't provide a way of learning this right now,
        // and this should be a good enough approximation.
        let inner = if frames.len() == 0 {
            Inner::Unsupported
        } else {
            Inner::Captured(Mutex::new(Capture {
                actual_start: actual_start.unwrap_or(0),
                frames,
                resolved: false,
            }))
        };

        Backtrace { inner }
    }

    /// Returns the status of this backtrace, indicating whether this backtrace
    /// request was unsupported, disabled, or a stack trace was actually
    /// captured.
    pub fn status(&self) -> BacktraceStatus {
        match self.inner {
            Inner::Unsupported => BacktraceStatus::Unsupported,
            Inner::Disabled => BacktraceStatus::Disabled,
            Inner::Captured(_) => BacktraceStatus::Captured,
        }
    }
}

impl fmt::Display for Backtrace {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut capture = match &self.inner {
            Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
            Inner::Disabled => return fmt.write_str("disabled backtrace"),
            Inner::Captured(c) => c.lock().unwrap(),
        };
        capture.resolve();

        let full = fmt.alternate();
        let (frames, style) = if full {
            (&capture.frames[..], backtrace::PrintFmt::Full)
        } else {
            (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short)
        };

        // When printing paths we try to strip the cwd if it exists, otherwise
        // we just print the path as-is. Note that we also only do this for the
        // short format, because if it's full we presumably want to print
        // everything.
        let cwd = crate::env::current_dir();
        let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
            output_filename(fmt, path, style, cwd.as_ref().ok())
        };

        let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path);
        f.add_context()?;
        for frame in frames {
            let mut f = f.frame();
            if frame.symbols.is_empty() {
                f.print_raw(frame.frame.ip(), None, None, None)?;
            } else {
                for symbol in frame.symbols.iter() {
                    f.print_raw(
                        frame.frame.ip(),
                        symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)),
                        symbol.filename.as_ref().map(|b| match b {
                            BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                            BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
                        }),
                        symbol.lineno,
                    )?;
                }
            }
        }
        f.finish()?;
        Ok(())
    }
}

impl Capture {
    fn resolve(&mut self) {
        // If we're already resolved, nothing to do!
        if self.resolved {
            return;
        }
        self.resolved = true;

        // Use the global backtrace lock to synchronize this as it's a
        // requirement of the `backtrace` crate, and then actually resolve
        // everything.
        let _lock = lock();
        for frame in self.frames.iter_mut() {
            let symbols = &mut frame.symbols;
            unsafe {
                backtrace::resolve_frame_unsynchronized(&frame.frame, |symbol| {
                    symbols.push(BacktraceSymbol {
                        name: symbol.name().map(|m| m.as_bytes().to_vec()),
                        filename: symbol.filename_raw().map(|b| match b {
                            BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
                            BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
                        }),
                        lineno: symbol.lineno(),
                    });
                });
            }
        }
    }
}
<|endoftext|>