<commit_before>extern crate toml;
extern crate shellexpand;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate error_chain;

use config::Config;

/// run ghq application
pub fn run() -> errors::Result<()> {
  let config = Config::load()?;
  warn!("{:?}", config);
  Ok(())
}

/// defines error types (automatically generated by error_chain)
pub mod errors {
  error_chain!{
    errors {
      LoadConfig {
        description("cannot load configuration")
      }
    }
    foreign_links {
      Io(::std::io::Error);
      ShellExpand(::shellexpand::LookupError<::std::env::VarError>);
    }
  }
}

/// defines configuration
pub mod config {
  use std::fs::File;
  use std::io::Read;
  use std::path::{Path, PathBuf};
  use toml;
  use shellexpand;

  use errors::{Result, ErrorKind};

  const CANDIDATES: &'static [&'static str] =
    &["~/.config/rhq/config", "~/.rhqconfig", "rhqconfig"];

  #[derive(Default, Deserialize)]
  struct RawConfig {
    root: Option<String>,
  }

  impl RawConfig {
    fn from_file<P: AsRef<Path>>(path: P) -> Result<Option<RawConfig>> {
      if !path.as_ref().is_file() {
        return Ok(None);
      }

      let mut content = String::new();
      File::open(path)?.read_to_string(&mut content)?;
      Ok(Some(toml::from_str(&content).ok().unwrap_or_default()))
    }

    fn merge(&mut self, other: RawConfig) {
      if let Some(root) = other.root {
        self.root = Some(root);
      }
    }
  }

  /// configuration load from config.toml
  #[derive(Debug)]
  pub struct Config {
    pub root: PathBuf,
  }

  impl Config {
    pub fn load() -> Result<Config> {
      let mut raw_config: Option<RawConfig> = None;
      for path in CANDIDATES {
        let path = shellexpand::full(path)?.into_owned();
        if let Some(conf) = RawConfig::from_file(path)? {
          if let Some(ref mut raw_config) = raw_config {
            raw_config.merge(conf);
          } else {
            raw_config = Some(conf);
          }
        }
      }
      let raw_config = raw_config.ok_or(ErrorKind::LoadConfig)?;

      let root = raw_config.root.unwrap_or("~/.rhq".to_owned());
      let root = PathBuf::from(shellexpand::full(&root)?.into_owned());

      Ok(Config { root: root })
    }
  }
}
<commit_msg>refactor<commit_after>extern crate toml;
extern crate shellexpand;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate error_chain;

use config::Config;

/// run ghq application
pub fn run() -> errors::Result<()> {
  let config = Config::load()?;
  warn!("{:?}", config);
  Ok(())
}

/// defines error types (automatically generated by error_chain)
pub mod errors {
  error_chain!{
    errors {
      LoadConfig {
        description("cannot load configuration")
      }
    }
    foreign_links {
      Io(::std::io::Error);
      ShellExpand(::shellexpand::LookupError<::std::env::VarError>);
    }
  }
}

/// defines configuration
pub mod config {
  use std::fs::File;
  use std::io::Read;
  use std::path::{Path, PathBuf};
  use toml;
  use shellexpand;
  use errors::{Result, ErrorKind};

  #[derive(Default, Deserialize)]
  struct RawConfig {
    root: Option<String>,
  }

  impl RawConfig {
    fn from_file<P: AsRef<Path>>(path: P) -> Result<Option<RawConfig>> {
      if !path.as_ref().is_file() {
        return Ok(None);
      }

      let mut content = String::new();
      File::open(path)?.read_to_string(&mut content)?;
      Ok(Some(toml::from_str(&content).ok().unwrap_or_default()))
    }

    fn merge(&mut self, other: RawConfig) {
      if let Some(root) = other.root {
        self.root = Some(root);
      }
    }
  }

  fn read_all_config() -> Result<RawConfig> {
    const CANDIDATES: &'static [&'static str] =
      &["~/.config/rhq/config", "~/.rhqconfig", "rhqconfig"];

    let mut config: Option<RawConfig> = None;

    for path in CANDIDATES {
      let path = shellexpand::full(path).unwrap().into_owned();
      let conf = match RawConfig::from_file(path)? {
        Some(conf) => conf,
        None => continue,
      };

      match config {
        Some(ref mut config) => config.merge(conf),
        None => config = Some(conf),
      }
    }

    config.ok_or(ErrorKind::LoadConfig).map_err(Into::into)
  }

  /// configuration load from config.toml
  #[derive(Debug)]
  pub struct Config {
    pub root: PathBuf,
  }

  impl Config {
    pub fn load() -> Result<Config> {
      let raw_config = read_all_config()?;

      let root = raw_config.root.unwrap_or("~/.rhq".to_owned());
      let root = PathBuf::from(shellexpand::full(&root)?.into_owned());

      Ok(Config { root: root })
    }
  }
}
<|endoftext|>


<commit_before>
pub fn puzzle(input: &str) -> u32 {
    0
}

pub fn supports_tls(candidate: &str) -> bool {
    let mut start_index = 0;
    let end_index = candidate.len();

    let mut abba_outside = false;

    while let Some((i, c)) = candidate.match_indices(|c| c == '[' || c == ']').next() {
        if c == "[" {
            abba_outside = abba_outside || contains_abba(&candidate[start_index..i]);
        } else {
            if contains_abba(&candidate[start_index..i]) {
                return false;
            }
        }
        start_index = i + 1;
    }

    abba_outside = abba_outside || contains_abba(&candidate[start_index..end_index]);

    abba_outside
}

pub fn contains_abba(candidate: &str) -> bool {
    let by_chars: Vec<char> = candidate.chars().collect();

    for (i, &c) in by_chars.iter().enumerate() {
        if i + 3 < by_chars.len() &&
            c != by_chars[i + 1] &&
            by_chars[i + 1] == by_chars[i + 2] &&
            by_chars[i + 3] == c {
            return true
        }
    }
    false
}

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

    #[test]
    fn does_support_tls() {
        assert!(supports_tls("abba[mnop]qrst"));
        assert!(supports_tls("ioxxoj[asdfgh]zxcvbn"));
        assert!(supports_tls("abcd[efgh]ijk[lmn]oppo"))
    }

    #[test]
    fn does_not_support_tls() {
        assert!( ! supports_tls("abcd[bddb]xyyx") );
        assert!( ! supports_tls("aaaa[qwer]tyui") );
        assert!( ! supports_tls("aaaa[qwer]tyui[foof]poop") );
    }

    #[test]
    fn does_contain_abba() {
        assert!(contains_abba("abba"));
        assert!(contains_abba("ioxxoj"));
    }

    #[test]
    fn does_not_contain_abba() {
        assert!( ! contains_abba("mnop") );
        assert!( ! contains_abba("aaaa") );
    }
}
<commit_msg>LOL i was always checking the first element in the iter<commit_after>
pub fn puzzle(input: &str) -> u32 {
    0
}

pub fn supports_tls(candidate: &str) -> bool {
    println!("considering {}", candidate);
    let mut start_index = 0;
    let end_index = candidate.len();

    let mut abba_outside = false;

    for (i, c) in candidate.match_indices(|c| c == '[' || c == ']') {
        println!("looking at slice ending in {}, [{}..{}]", c, start_index, i);
        println!("slice is {}", &candidate[start_index..i]);
        println!("abba_outside = {}", abba_outside);
        if c == "[" {
            abba_outside = abba_outside || contains_abba(&candidate[start_index..i]);
            println!("after looking, abba_outside = {}", abba_outside);
        } else {
            if contains_abba(&candidate[start_index..i]) {
                println!("womp womp, found an abba inside");
                return false;
            }
        }
        start_index = i + 1;
        println!("start_index = {}", start_index);
    }
    println!("looking at final slice [{}..{}]: '{}", start_index, end_index, &candidate[start_index..end_index]);

    abba_outside = abba_outside || contains_abba(&candidate[start_index..end_index]);

    println!("final answer: {}", abba_outside);

    abba_outside
}

pub fn contains_abba(candidate: &str) -> bool {
    let by_chars: Vec<char> = candidate.chars().collect();

    for (i, &c) in by_chars.iter().enumerate() {
        if i + 3 < by_chars.len() &&
            c != by_chars[i + 1] &&
            by_chars[i + 1] == by_chars[i + 2] &&
            by_chars[i + 3] == c {
            return true
        }
    }
    false
}

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

    #[test]
    fn does_support_tls() {
        assert!(supports_tls("abba[mnop]qrst"));
        assert!(supports_tls("ioxxoj[asdfgh]zxcvbn"));
        assert!(supports_tls("abcd[efgh]ijk[lmn]oppo"))
    }

    #[test]
    fn does_not_support_tls() {
        assert!( ! supports_tls("abcd[bddb]xyyx") );
        assert!( ! supports_tls("aaaa[qwer]tyui") );
        assert!( ! supports_tls("aaaa[qwer]tyui[foof]poop") );
    }

    #[test]
    fn does_contain_abba() {
        assert!(contains_abba("abba"));
        assert!(contains_abba("ioxxoj"));
    }

    #[test]
    fn does_not_contain_abba() {
        assert!( ! contains_abba("mnop") );
        assert!( ! contains_abba("aaaa") );
    }
}
<|endoftext|>


<commit_before>//! Promises in Rust.
//! See the `Promise` struct for more details.

#![warn(missing_docs)]

#[cfg(test)]
mod tests;

use std::thread;
use std::sync::mpsc::channel;
//use std::thread::JoinHandle;
use std::marker::{Send};
use std::sync::mpsc::{Sender, Receiver, TryRecvError};

/// A promise is a way of doing work in the background. The promises in
/// this library have the same featureset as those in Ecmascript 5.
///
/// # Promises
/// Promises (sometimes known as "futures") are objects that represent
/// asynchronous tasks being run in the background, or results which
/// will exist in the future.
/// A promise will be in state of running, fulfilled, or done. In order to
/// use the results of a fulfilled promise, one attaches another promise
/// to it (i.e. via `then`). Like their Javascript counterparts, promises can
/// return an error (of type `E`).
///
/// # Panics
/// If the function being executed by a promise panics, it does so silently.
/// The panic will not resurface in the thread which created the promise,
/// and promises waiting on its result will never be called. In addition,
/// the `all` and `race` proimse methods will _ignore_ "dead" promises. They
/// will remove promises from their lists, and if there aren't any left
/// they will silently exit without doing anything.
///
/// Unfortunately, panics must be ignored for two reasons:
/// * Panic messages don't have a concrete type yet in Rust. If they did,
/// promiess would be able to inspect their predecessors' errors.
/// * Although a `Receiver` can correctly handle its paired `Sender` being
/// dropped, such as during a panic, for reasons stated above the "message"
/// of the panic is not relayed.
///
/// Finally, Ecmascript promises themselves do have the ability to return
/// and error type, represented as a `Result<T, E>` here. Thus, one should
/// use `try!` and other error handling rather than calls to `unwrap()`.
pub struct Promise<T: Send, E: Send> {
    receiver: Receiver<Result<T, E>>
}

impl<T: Send + 'static, E: Send + 'static> Promise<T, E> {

    /// Chains a function to be called after this promise resolves.
    pub fn then<T2, E2>(self, callback: fn(t: T) -> Result<T2, E2>,
                              errback:  fn(e: E) -> Result<T2, E2>)
                        -> Promise<T2, E2>
    where T2: Send + 'static, E2: Send + 'static {
        let recv = self.receiver;
        let (tx, rx) = channel();

        thread::spawn(move || {
            Promise::impl_then(tx, recv, callback, errback);
        });

        Promise { receiver: rx }
    }

    /// Chains a function to be called after this promise resolves,
    /// using a `Result` type.
    pub fn then_result<T2, E2>(self,
                               callback: fn(r: Result<T, E>) -> Result<T2, E2>)
                               -> Promise<T2, E2>
    where T2: Send + 'static, E2: Send + 'static {
        let recv = self.receiver;
        let (tx, rx) = channel();

        thread::spawn(move || {
            Promise::impl_then_result(tx, recv, callback);
        });

        Promise { receiver: rx }
    }

    /// Creates a new promsie, which will eventually resolve to one of the
    /// values of the `Result<T, E>` type.
    pub fn new<F>(func: fn() -> Result<T, E>) -> Promise<T, E> {
        let (tx, rx) = channel();

        thread::spawn(move || {
            Promise::impl_new(tx, func);
        });

        Promise { receiver: rx }
    }

    /// Applies a promise to the first of some promises to become fulfilled.
    pub fn race(promises: Vec<Promise<T, E>>) -> Promise<T, E> {
        let recs = promises.into_iter().map(|p| p.receiver).collect();
        let (tx, rx) = channel::<Result<T, E>>();

        thread::spawn(move || {
            Promise::impl_race(tx, recs);
        });

        Promise { receiver: rx }
    }

    /// Calls a function with the result of all of the promises, or the error
    /// of the first promise to error.
    pub fn all(promises: Vec<Promise<T, E>>) -> Promise<Vec<T>, E> {
        let receivers: Vec<Receiver<Result<T, E>>> =
            promises.into_iter().map(|p| p.receiver).collect();
        let (tx, rx) = channel();

        thread::spawn(move || {
            Promise::impl_all(tx, receivers);
        });

        return Promise { receiver: rx };
    }

    /// Creates a promise that resolves to a value
    pub fn resolve(val: T) -> Promise<T, E> {
        Promise::from_result(Ok(val))
    }

    /// Creates a promise that resolves to an error.
    pub fn reject(val: E) -> Promise<T, E> {
        Promise::from_result(Err(val))
    }

    /// Creates a new promise that will resolve to the result value.
    pub fn from_result(result: Result<T, E>) -> Promise<T, E> {
        let (tx, rx) = channel();
        tx.send(result).unwrap();

        Promise { receiver: rx }
    }

    // Implementation Functions

    fn impl_new(tx: Sender<Result<T, E>>,
                func: fn() -> Result<T, E>) {
        let result = func();
        tx.send(result).unwrap_or(());
    }

    fn impl_then<T2, E2>(tx: Sender<Result<T2, E2>>,
                            rx: Receiver<Result<T, E>>,
                            callback: fn(T) -> Result<T2, E2>,
                            errback: fn(E) -> Result<T2, E2>)
    where T2: Send + 'static, E2: Send + 'static {
        if let Ok(message) = rx.recv() {
            match message {
                Ok(val) => tx.send(callback(val)).unwrap_or(()),
                Err(err) => tx.send(errback(err)).unwrap_or(())
            };
        }
    }

    fn impl_then_result<T2, E2>(tx: Sender<Result<T2, E2>>,
                                rx: Receiver<Result<T, E>>,
                                callback: fn(Result<T, E>) -> Result<T2, E2>)
    where T2: Send + 'static, E2: Send + 'static {

        if let Ok(result) = rx.recv() {
            tx.send(callback(result)).unwrap_or(());
        }
    }

    // Static methods

    fn impl_race(tx: Sender<Result<T, E>>,
                 mut recs: Vec<Receiver<Result<T, E>>>) {
        'outer: loop {
            // Don't get stuck in an infinite loop
            if recs.len() == 0 { return; }
            for i in 0..recs.len() {
                match recs[i].try_recv() {
                    Ok(val) => {
                        tx.send(val).unwrap_or(());
                        return;
                    }
                    Err(err) => {
                        if err == TryRecvError::Disconnected {
                            recs.remove(i);
                        }
                    }
                }
            }
        }
    }

    fn impl_all(tx: Sender<Result<Vec<T>, E>>,
                recs: Vec<Receiver<Result<T, E>>>) {
        let mut values: Vec<T> = Vec::with_capacity(recs.len());
        let mut mut_receivers = recs;
        'outer: loop {
            for i in 0..mut_receivers.len() {
                match mut_receivers[i].try_recv() {
                    Ok(val) => {
                        match val {
                            Ok(t) => values.push(t),
                            Err(e) => {
                                tx.send(Err(e)).unwrap_or(());
                                return;
                            }
                        }
                        mut_receivers.remove(i);
                    }
                    Err(err) => {
                        if err == TryRecvError::Disconnected {
                            mut_receivers.remove(i);
                        }
                    }
                }
            }
            // Check if we are finished waiting for promises
            // This can also happen if all promises panic
            if mut_receivers.len() == 0 {
                let result = Ok(values);
                tx.send(result).unwrap_or(());
                return; // Break from outer loop
            }
        }
    }
}
<commit_msg>Updated doc terminology<commit_after>//! Promises in Rust.
//! See the `Promise` struct for more details.

#![warn(missing_docs)]

#[cfg(test)]
mod tests;

use std::thread;
use std::sync::mpsc::channel;
//use std::thread::JoinHandle;
use std::marker::{Send};
use std::sync::mpsc::{Sender, Receiver, TryRecvError};

/// A promise is a way of doing work in the background. The promises in
/// this library have the same featureset as those in Ecmascript 5.
///
/// # Promises
/// Promises (sometimes known as "futures") are objects that represent
/// asynchronous tasks being run in the background, or results which
/// will exist in the future.
/// A promise will be in state of running, fulfilled, failed, or done. In order
/// to use the results of a fulfilled promise, one attaches another promise
/// to it (i.e. via `then`). Like their Javascript counterparts, promises can
/// return an error (of type `E`). Unlike Javascript, success or failure is indicated
/// by a `Result` type. This is much more Rustic and allows existing functions which
/// return `Result<T, E>` to be used.
///
/// # Panics
/// If the function being executed by a promise panics, it does so silently.
/// The panic will not resurface in the thread which created the promise,
/// and promises waiting on its result will never be called. In addition,
/// the `all` and `race` proimse methods will _ignore_ "dead" promises. They
/// will remove promises from their lists, and if there aren't any left
/// they will silently exit without doing anything.
///
/// Unfortunately, panics must be ignored for two reasons:
/// * Panic messages don't have a concrete type yet in Rust. If they did,
/// promiess would be able to inspect their predecessors' errors.
/// * Although a `Receiver` can correctly handle its paired `Sender` being
/// dropped, such as during a panic, for reasons stated above the "message"
/// of the panic is not relayed.
///
/// Finally, Ecmascript promises themselves do have the ability to return
/// and error type, represented as a `Result<T, E>` here. Thus, one should
/// use `try!` and other error handling rather than calls to `unwrap()`.
pub struct Promise<T: Send, E: Send> {
    receiver: Receiver<Result<T, E>>
}

impl<T: Send + 'static, E: Send + 'static> Promise<T, E> {

    /// Chains a function to be called after this promise resolves.
    pub fn then<T2, E2>(self, callback: fn(t: T) -> Result<T2, E2>,
                              errback:  fn(e: E) -> Result<T2, E2>)
                        -> Promise<T2, E2>
    where T2: Send + 'static, E2: Send + 'static {
        let recv = self.receiver;
        let (tx, rx) = channel();

        thread::spawn(move || {
            Promise::impl_then(tx, recv, callback, errback);
        });

        Promise { receiver: rx }
    }

    /// Chains a function to be called after this promise resolves,
    /// using a `Result` type.
    pub fn then_result<T2, E2>(self,
                               callback: fn(r: Result<T, E>) -> Result<T2, E2>)
                               -> Promise<T2, E2>
    where T2: Send + 'static, E2: Send + 'static {
        let recv = self.receiver;
        let (tx, rx) = channel();

        thread::spawn(move || {
            Promise::impl_then_result(tx, recv, callback);
        });

        Promise { receiver: rx }
    }

    /// Creates a new promsie, which will eventually resolve to one of the
    /// values of the `Result<T, E>` type.
    pub fn new<F>(func: fn() -> Result<T, E>) -> Promise<T, E> {
        let (tx, rx) = channel();

        thread::spawn(move || {
            Promise::impl_new(tx, func);
        });

        Promise { receiver: rx }
    }

    /// Applies a promise to the first of some promises to become fulfilled.
    pub fn race(promises: Vec<Promise<T, E>>) -> Promise<T, E> {
        let recs = promises.into_iter().map(|p| p.receiver).collect();
        let (tx, rx) = channel::<Result<T, E>>();

        thread::spawn(move || {
            Promise::impl_race(tx, recs);
        });

        Promise { receiver: rx }
    }

    /// Calls a function with the result of all of the promises, or the error
    /// of the first promise to error.
    pub fn all(promises: Vec<Promise<T, E>>) -> Promise<Vec<T>, E> {
        let receivers: Vec<Receiver<Result<T, E>>> =
            promises.into_iter().map(|p| p.receiver).collect();
        let (tx, rx) = channel();

        thread::spawn(move || {
            Promise::impl_all(tx, receivers);
        });

        return Promise { receiver: rx };
    }

    /// Creates a promise that resolves to a value
    pub fn resolve(val: T) -> Promise<T, E> {
        Promise::from_result(Ok(val))
    }

    /// Creates a promise that resolves to an error.
    pub fn reject(val: E) -> Promise<T, E> {
        Promise::from_result(Err(val))
    }

    /// Creates a new promise that will resolve to the result value.
    pub fn from_result(result: Result<T, E>) -> Promise<T, E> {
        let (tx, rx) = channel();
        tx.send(result).unwrap();

        Promise { receiver: rx }
    }

    // Implementation Functions

    fn impl_new(tx: Sender<Result<T, E>>,
                func: fn() -> Result<T, E>) {
        let result = func();
        tx.send(result).unwrap_or(());
    }

    fn impl_then<T2, E2>(tx: Sender<Result<T2, E2>>,
                            rx: Receiver<Result<T, E>>,
                            callback: fn(T) -> Result<T2, E2>,
                            errback: fn(E) -> Result<T2, E2>)
    where T2: Send + 'static, E2: Send + 'static {
        if let Ok(message) = rx.recv() {
            match message {
                Ok(val) => tx.send(callback(val)).unwrap_or(()),
                Err(err) => tx.send(errback(err)).unwrap_or(())
            };
        }
    }

    fn impl_then_result<T2, E2>(tx: Sender<Result<T2, E2>>,
                                rx: Receiver<Result<T, E>>,
                                callback: fn(Result<T, E>) -> Result<T2, E2>)
    where T2: Send + 'static, E2: Send + 'static {

        if let Ok(result) = rx.recv() {
            tx.send(callback(result)).unwrap_or(());
        }
    }

    // Static methods

    fn impl_race(tx: Sender<Result<T, E>>,
                 mut recs: Vec<Receiver<Result<T, E>>>) {
        'outer: loop {
            // Don't get stuck in an infinite loop
            if recs.len() == 0 { return; }
            for i in 0..recs.len() {
                match recs[i].try_recv() {
                    Ok(val) => {
                        tx.send(val).unwrap_or(());
                        return;
                    }
                    Err(err) => {
                        if err == TryRecvError::Disconnected {
                            recs.remove(i);
                        }
                    }
                }
            }
        }
    }

    fn impl_all(tx: Sender<Result<Vec<T>, E>>,
                recs: Vec<Receiver<Result<T, E>>>) {
        let mut values: Vec<T> = Vec::with_capacity(recs.len());
        let mut mut_receivers = recs;
        'outer: loop {
            for i in 0..mut_receivers.len() {
                match mut_receivers[i].try_recv() {
                    Ok(val) => {
                        match val {
                            Ok(t) => values.push(t),
                            Err(e) => {
                                tx.send(Err(e)).unwrap_or(());
                                return;
                            }
                        }
                        mut_receivers.remove(i);
                    }
                    Err(err) => {
                        if err == TryRecvError::Disconnected {
                            mut_receivers.remove(i);
                        }
                    }
                }
            }
            // Check if we are finished waiting for promises
            // This can also happen if all promises panic
            if mut_receivers.len() == 0 {
                let result = Ok(values);
                tx.send(result).unwrap_or(());
                return; // Break from outer loop
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(collections, unboxed_closures, core)]
extern crate itertools;
extern crate rustc_serialize;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::hash_map::IntoIter;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::iter;
use std::ops;

use itertools::{GroupBy, Itertools};

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Eq, Debug, RustcEncodable, RustcDecodable)]
pub struct Document {
    id: String,
    content: String,
}

impl Document {
    /// Construct a new Document from an id and content.
    /// Both two arguments can be anything that can be turned into a String.
    pub fn new<S, T>(id: S, content: T) -> Document
        where S: Into<String>,
              T: Into<String>
    {
        Document { id: id.into(), content: content.into(), }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl Hash for Document {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write(self.id.as_bytes());
    }
}

impl PartialEq<Document> for Document {
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct IndexedDocument {
    pub doc: Arc<Document>,
    pub highlighted: (usize, usize),
}

fn ngrams((_, chars): (bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams> {
    (1..chars.len() + 1).map(Ngrams::new(chars))
}

fn not_whitespace(&(is_whitespace, _): &(bool, Vec<(usize, char)>)) -> bool {
    !is_whitespace
}

fn is_whitespace(&(_, c): &(usize, char)) -> bool {
    c.is_whitespace()
}

struct Ngrams {
    chars: Vec<(usize, char)>
}

impl Ngrams {
    fn new(chars: Vec<(usize, char)>) -> Ngrams {
        Ngrams { chars: chars }
    }
}

impl Fn<(usize,)> for Ngrams {
    extern "rust-call" fn call(&self, (to,): (usize,)) -> (String, (usize, usize)) {
        let word = self.chars[..to].iter().flat_map(|&(_, c)| c.to_lowercase()).collect();
        let start = self.chars[0].0;
        let (last_idx, last_char) = self.chars[to - 1];
        let finish = last_idx + last_char.len_utf8();
        (word, (start, finish))
    }
}

impl FnMut<(usize,)> for Ngrams {
    extern "rust-call" fn call_mut(&mut self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

impl FnOnce<(usize,)> for Ngrams {
    type Output = (String, (usize, usize));
    extern "rust-call" fn call_once(self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

fn analyze_doc(doc: &str)
-> iter::FlatMap<
    iter::Filter<
        GroupBy<bool, std::str::CharIndices, fn(&(usize, char)) -> bool>,
        fn(&(bool, Vec<(usize, char)>)) -> bool>,
    iter::Map<ops::Range<usize>, Ngrams>,
    fn((bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams>>
{
    doc.char_indices()
        .group_by(is_whitespace as fn(&(usize, char)) -> bool)
        .filter(not_whitespace as fn(&(bool, Vec<(usize, char)>)) -> bool)
        .flat_map(ngrams)
}

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to sets of Documents.
#[derive(Debug)]
pub struct InvertedIndex {
    index: BTreeMap<String, HashSet<IndexedDocument>>,
    docs: BTreeMap<String, Arc<Document>>,
}

impl InvertedIndex {
    pub fn new() -> InvertedIndex {
        InvertedIndex {
            index: BTreeMap::new(),
            docs: BTreeMap::new(),
        }
    }

    /// A basic implementation of index, splits the document's content into whitespace-separated
    /// words, and inserts each word-document pair into the map.
    pub fn index(&mut self, doc: Document) {
        let doc = Arc::new(doc);
        let analyzed  = analyze_doc(doc.content());
        let previous_version = self.docs.insert(doc.id.clone(), doc.clone());
        if let Some(previous_version) = previous_version {
            let previous_analyzed = analyze_doc(previous_version.content());
            for (ngram, highlights) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&IndexedDocument { doc: doc.clone(), highlighted: highlights });
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        for (ngram, highlighted) in analyzed {
            self.index.entry(ngram).or_insert_with(|| HashSet::new())
                .insert(IndexedDocument { doc: doc.clone(), highlighted: highlighted });
        }
    }

    /// A basic search implementation that splits the query's content into whitespace-separated
    /// words, looks up the set of Documents for each word, and then concatenates the sets.
    pub fn search(&self, query: &str) -> SearchResults {
        let map = query.split_whitespace()
            .flat_map(|word| self.index.get(&word.to_lowercase()))
            .flat_map(|doc| doc)
            .cloned()
            .fold(HashMap::new(), |mut map, search_result| {
                map.entry(search_result.doc)
                    .or_insert(Vec::new())
                    .push(search_result.highlighted);
                map
            });
        let results = map.into_iter()
            .map(SearchResult::new_ as fn((Arc<Document>, Vec<(usize, usize)>)) -> SearchResult);
        SearchResults { it: results }
    }
}

pub struct SearchResults {
    it: iter::Map<
            IntoIter<Arc<Document>, Vec<(usize, usize)>>,
            fn((Arc<Document>, Vec<(usize, usize)>)) -> SearchResult>
}

impl Iterator for SearchResults {
    type Item = SearchResult;
    fn next(&mut self) -> Option<SearchResult> {
        self.it.next()
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug, RustcEncodable)]
pub struct SearchResult {
    doc: Arc<Document>,
    highlights: Vec<(usize, usize)>,
}

impl SearchResult {
    fn new_((doc, highlights): (Arc<Document>, Vec<(usize, usize)>)) -> SearchResult {
        SearchResult::new(doc, highlights)
    }

    fn new(doc: Arc<Document>, mut highlights: Vec<(usize, usize)>) -> SearchResult {
        highlights.sort();
        SearchResult {
            doc: doc,
            highlights: highlights,
        }
    }

    pub fn doc(&self) -> &Arc<Document> {
        &self.doc
    }

    pub fn highlights(&self) -> &Vec<(usize, usize)> {
        &self.highlights
    }

    pub fn highlighted_content(&self) -> String {
        let &SearchResult {ref doc, ref highlights} = self;
        let content = doc.content();
        let mut begin_idx = 0;
        let mut parts = vec![];
        for &(begin, end) in highlights {
            parts.push(&content[begin_idx..begin]);
            parts.push("");
            parts.push(&content[begin..end]);
            parts.push("");
            begin_idx = end;
        }
        parts.push(&content[begin_idx..]);
        parts.into_iter().join("")
    }
}

#[test]
fn test_search1() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    index.index(doc1.clone());
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc2.clone());
    let search_results = index.search("today");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(25, 30)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 18)])
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());
}

#[test]
fn test_ngrams() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());

}

#[test]
fn test_search2() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("2", "what to do today");
    let doc2 = Document::new("3", "hey today");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(5, 7), (11, 13)]),
        SearchResult::new(Arc::new(doc2), vec![(4, 6)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!(expected[0].highlighted_content(), "what to do today");
}

#[test]
fn test_unicode() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc.clone());
    let to_search = "å";
    let search_results = index.search(to_search);
    let &SearchResult { ref doc, ref highlights } = search_results.iter().next().unwrap();
    let (begin, end) = highlights[0];
    assert_eq!(&doc.content()[begin..end], to_search);
}

#[test]
fn test_update_doc() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc);
    let doc = Document::new("0", "different");
    index.index(doc);
    let search_results = index.search("å");
    assert!(search_results.is_empty());
    assert_eq!(index.docs.len(), 1);
}
<commit_msg>Change highlighting<commit_after>#![feature(collections, unboxed_closures, core)]
extern crate itertools;
extern crate rustc_serialize;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::hash_map::IntoIter;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::iter;
use std::ops;

use itertools::{GroupBy, Itertools};

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Eq, Debug, RustcEncodable, RustcDecodable)]
pub struct Document {
    id: String,
    content: String,
}

impl Document {
    /// Construct a new Document from an id and content.
    /// Both two arguments can be anything that can be turned into a String.
    pub fn new<S, T>(id: S, content: T) -> Document
        where S: Into<String>,
              T: Into<String>
    {
        Document { id: id.into(), content: content.into(), }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl Hash for Document {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write(self.id.as_bytes());
    }
}

impl PartialEq<Document> for Document {
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct IndexedDocument {
    pub doc: Arc<Document>,
    pub highlighted: (usize, usize),
}

fn ngrams((_, chars): (bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams> {
    (1..chars.len() + 1).map(Ngrams::new(chars))
}

fn not_whitespace(&(is_whitespace, _): &(bool, Vec<(usize, char)>)) -> bool {
    !is_whitespace
}

fn is_whitespace(&(_, c): &(usize, char)) -> bool {
    c.is_whitespace()
}

struct Ngrams {
    chars: Vec<(usize, char)>
}

impl Ngrams {
    fn new(chars: Vec<(usize, char)>) -> Ngrams {
        Ngrams { chars: chars }
    }
}

impl Fn<(usize,)> for Ngrams {
    extern "rust-call" fn call(&self, (to,): (usize,)) -> (String, (usize, usize)) {
        let word = self.chars[..to].iter().flat_map(|&(_, c)| c.to_lowercase()).collect();
        let start = self.chars[0].0;
        let (last_idx, last_char) = self.chars[to - 1];
        let finish = last_idx + last_char.len_utf8();
        (word, (start, finish))
    }
}

impl FnMut<(usize,)> for Ngrams {
    extern "rust-call" fn call_mut(&mut self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

impl FnOnce<(usize,)> for Ngrams {
    type Output = (String, (usize, usize));
    extern "rust-call" fn call_once(self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

fn analyze_doc(doc: &str)
-> iter::FlatMap<
    iter::Filter<
        GroupBy<bool, std::str::CharIndices, fn(&(usize, char)) -> bool>,
        fn(&(bool, Vec<(usize, char)>)) -> bool>,
    iter::Map<ops::Range<usize>, Ngrams>,
    fn((bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams>>
{
    doc.char_indices()
        .group_by(is_whitespace as fn(&(usize, char)) -> bool)
        .filter(not_whitespace as fn(&(bool, Vec<(usize, char)>)) -> bool)
        .flat_map(ngrams)
}

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to sets of Documents.
#[derive(Debug)]
pub struct InvertedIndex {
    index: BTreeMap<String, HashSet<IndexedDocument>>,
    docs: BTreeMap<String, Arc<Document>>,
}

impl InvertedIndex {
    pub fn new() -> InvertedIndex {
        InvertedIndex {
            index: BTreeMap::new(),
            docs: BTreeMap::new(),
        }
    }

    /// A basic implementation of index, splits the document's content into whitespace-separated
    /// words, and inserts each word-document pair into the map.
    pub fn index(&mut self, doc: Document) {
        let doc = Arc::new(doc);
        let analyzed  = analyze_doc(doc.content());
        let previous_version = self.docs.insert(doc.id.clone(), doc.clone());
        if let Some(previous_version) = previous_version {
            let previous_analyzed = analyze_doc(previous_version.content());
            for (ngram, highlights) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&IndexedDocument { doc: doc.clone(), highlighted: highlights });
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        for (ngram, highlighted) in analyzed {
            self.index.entry(ngram).or_insert_with(|| HashSet::new())
                .insert(IndexedDocument { doc: doc.clone(), highlighted: highlighted });
        }
    }

    /// A basic search implementation that splits the query's content into whitespace-separated
    /// words, looks up the set of Documents for each word, and then concatenates the sets.
    pub fn search(&self, query: &str) -> SearchResults {
        let map = query.split_whitespace()
            .flat_map(|word| self.index.get(&word.to_lowercase()))
            .flat_map(|doc| doc)
            .cloned()
            .fold(HashMap::new(), |mut map, search_result| {
                map.entry(search_result.doc)
                    .or_insert(Vec::new())
                    .push(search_result.highlighted);
                map
            });
        let results = map.into_iter()
            .map(SearchResult::new_ as fn((Arc<Document>, Vec<(usize, usize)>)) -> SearchResult);
        SearchResults { it: results }
    }
}

pub struct SearchResults {
    it: iter::Map<
            IntoIter<Arc<Document>, Vec<(usize, usize)>>,
            fn((Arc<Document>, Vec<(usize, usize)>)) -> SearchResult>
}

impl Iterator for SearchResults {
    type Item = SearchResult;
    fn next(&mut self) -> Option<SearchResult> {
        self.it.next()
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug, RustcEncodable)]
pub struct SearchResult {
    doc: Arc<Document>,
    highlights: Vec<(usize, usize)>,
}

impl SearchResult {
    fn new_((doc, highlights): (Arc<Document>, Vec<(usize, usize)>)) -> SearchResult {
        SearchResult::new(doc, highlights)
    }

    fn new(doc: Arc<Document>, mut highlights: Vec<(usize, usize)>) -> SearchResult {
        highlights.sort();
        SearchResult {
            doc: doc,
            highlights: highlights,
        }
    }

    pub fn doc(&self) -> &Arc<Document> {
        &self.doc
    }

    pub fn highlights(&self) -> &Vec<(usize, usize)> {
        &self.highlights
    }

    pub fn highlighted_content(&self) -> String {
        let &SearchResult {ref doc, ref highlights} = self;
        let content = doc.content();
        let mut begin_idx = 0;
        let mut parts = vec![];
        for &(begin, end) in highlights {
            parts.push(&content[begin_idx..begin]);
            parts.push("");
            parts.push(&content[begin..end]);
            parts.push("");
            begin_idx = end;
        }
        parts.push(&content[begin_idx..]);
        parts.into_iter().join("")
    }
}

#[test]
fn test_search1() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    index.index(doc1.clone());
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc2.clone());
    let search_results = index.search("today");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(25, 30)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 18)])
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());
}

#[test]
fn test_ngrams() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!("learn to program in rust today", expected[0].highlighted_content());

}

#[test]
fn test_search2() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("2", "what to do today");
    let doc2 = Document::new("3", "hey today");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(5, 7), (11, 13)]),
        SearchResult::new(Arc::new(doc2), vec![(4, 6)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect());
    assert_eq!(expected[0].highlighted_content(), "what to do today");
}

#[test]
fn test_unicode() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc.clone());
    let to_search = "å";
    let search_results = index.search(to_search);
    let &SearchResult { ref doc, ref highlights } = search_results.iter().next().unwrap();
    let (begin, end) = highlights[0];
    assert_eq!(&doc.content()[begin..end], to_search);
}

#[test]
fn test_update_doc() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    index.index(doc);
    let doc = Document::new("0", "different");
    index.index(doc);
    let search_results = index.search("å");
    assert!(search_results.is_empty());
    assert_eq!(index.docs.len(), 1);
}
<|endoftext|>


<commit_before>
#![feature(phase)]
#[phase(plugin, link)]
extern crate stainless;

pub fn xor(source: &[u8], key: &[u8]) -> Vec<u8> {
    if source.len() == 0 || key.len() == 0 {
        return source.to_vec();
    }

    let key_iter = InfiniteByteIterator::new(key);
    source.iter().zip(key_iter).map(|(&a, b)| a ^ b).collect()
}

struct InfiniteByteIterator {
    bytes: Vec<u8>,
    index: uint
}

impl InfiniteByteIterator {
    pub fn new(bytes: &[u8]) -> InfiniteByteIterator {
        InfiniteByteIterator {
            bytes: bytes.to_vec(),
            index: 0
        }
    }
}

impl Iterator<u8> for InfiniteByteIterator {
    fn next(&mut self) -> Option<u8> {
        let byte = self.bytes[self.index];
        self.index = next_index(self.index, self.bytes.len());
        Some(byte)
    }
}

fn next_index(current: uint, count: uint) -> uint {
    let index = current + 1;
    if index < count {
        index
    } else {
        0
    }
}

describe! test_xor {
    it "should return right result" {
        let source = [0, 1, 2, 3];
        let key = [34, 52];
        assert!(xor(source, key).as_slice() == [34, 53, 32, 55]);
    }

    it "should return source if key is empty" {
        let source = [0, 1, 2, 3];
        let key = [];
        assert!(xor(source, key).as_slice() == [0, 1, 2, 3]);
    }

    it "should return empty result if source is empty" {
        let source = [];
        let key = [45, 32, 56];
        assert!(xor(source, key).as_slice() == []);
    }
}
<commit_msg>Minor changes.<commit_after>
#![feature(phase)]
#[phase(plugin, link)]
extern crate stainless;

pub fn xor(source: &[u8], key: &[u8]) -> Vec<u8> {
    if source.len() == 0 || key.len() == 0 {
        return source.to_vec();
    }

    let key_iter = InfiniteByteIterator::new(key);
    source.iter().zip(key_iter).map(|(&a, b)| a ^ b).collect()
}

struct InfiniteByteIterator {
    bytes: Vec<u8>,
    index: uint
}

impl InfiniteByteIterator {
    pub fn new(bytes: &[u8]) -> InfiniteByteIterator {
        InfiniteByteIterator {
            bytes: bytes.to_vec(),
            index: 0
        }
    }
}

impl Iterator<u8> for InfiniteByteIterator {
    fn next(&mut self) -> Option<u8> {
        let byte = self.bytes[self.index];
        self.index = next_index(self.index, self.bytes.len());
        Some(byte)
    }
}

fn next_index(index: uint, count: uint) -> uint {
    if index + 1 < count { index + 1 } else { 0 }
}

describe! test_xor {
    it "should return right result" {
        let source = [0, 1, 2, 3];
        let key = [34, 52];
        assert!(xor(source, key).as_slice() == [34, 53, 32, 55]);
    }

    it "should return source if key is empty" {
        let source = [0, 1, 2, 3];
        let key = [];
        assert!(xor(source, key).as_slice() == [0, 1, 2, 3]);
    }

    it "should return empty result if source is empty" {
        let source = [];
        let key = [45, 32, 56];
        assert!(xor(source, key).as_slice() == []);
    }
}
<|endoftext|>


<commit_before>
use std::mem;

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, Default)]
pub struct f16(u16);

// TODO Endianness *should* be fine -- except in archs the differ on int/fp endianness

impl f16 {
    pub fn from_bits(bits: u16) -> f16 {
        f16(bits)
    }

    pub fn from_f32(value: f32) -> f16 {
        // Convert to raw bytes
        let x: u32 = unsafe { mem::transmute(value) };

        // Check for signed zero
        if x & 0x7FFFFFFFu32 == 0 {
            return f16::from_bits((x >> 16) as u16);
        }

        // Extract IEEE754 components
        let sign = x & 0x80000000u32;
        let exp  = x & 0x7F800000u32;
        let man  = x & 0x007FFFFFu32;

        // Denormals will underflow, so return signed zero
        if exp == 0 {
            return f16::from_bits(x as u16);
        }

        // Check for all exponent bits being set, which is Infinity or NaN
        if exp == 0x7F800000u32 {
            // A mantissa of zero is a signed Infinity
            if man == 0 {
                return f16::from_bits(((x >> 16) | 0x7C00u32) as u16);
            }
            // Otherwise, this is NaN
            return f16::from_bits(0xFE00u16);
        }

        // The number is normalized, start assembling half precision version
        let half_sign = sign >> 16;
        // Unbias the exponent, then bias for half precision
        let unbiased_exp = (exp >> 23) - 127;
        let half_exp = unbiased_exp + 15;

        // Check for exponent overflow, return +infinity
        if half_exp >= 0x1F {
            return f16::from_bits((half_sign | 0x7C00u32) as u16);
        }

        // Check for underflow
        if half_sign <= 0 {
            // Check mantissa for what we can do
            if 14 - half_exp > 24 {
                // No rounding possibility, so this is a full underflow, return signed zero
                return f16::from_bits(half_sign as u16);
            }
            // Don't forget about hidden leading mantissa bit when assembling mantissa
            let man = man | 0x00800000u32;
            let mut half_man = man >> (14 - half_exp);
            // Check for rounding
            if (man >> (13 - half_exp)) & 0x1u32 != 0 {
                half_man += 1;
            }
            // No exponent for denormals
            return f16::from_bits((half_sign | half_man) as u16);
        }

        // Rebias the exponent
        let half_exp = half_exp << 10;
        let half_man = man >> 13;
        // Check for rounding
        if man & 0x00001000u32 != 0 {
            // Round it
            f16::from_bits(((half_sign | half_exp | half_man) + 1) as u16)
        } else {
            f16::from_bits((half_sign | half_exp | half_man) as u16)
        }
    }

    pub fn from_f64(value: f64) -> f16 {
        // Convert to raw bytes, truncating the last 32-bits of mantissa; that precision will always
        // be lost on half-precision.
        let val: u64 = unsafe { mem::transmute(value) };
        let x = (val >> 32) as u32;

        // Check for signed zero
        if x & 0x7FFFFFFFu32 == 0 {
            return f16::from_bits((x >> 16) as u16);
        }

        // Extract IEEE754 components
        let sign = x & 0x80000000u32;
        let exp  = x & 0x7FF00000u32;
        let man  = x & 0x000FFFFFu32;

        // Denormals will underflow, so return signed zero
        if exp == 0 {
            return f16::from_bits(x as u16);
        }

        // Check for all exponent bits being set, which is Infinity or NaN
        if exp == 0x7FF00000u32 {
            // A mantissa of zero is a signed Infinity
            if man == 0 {
                return f16::from_bits(((x >> 16) | 0x7C00u32) as u16);
            }
            // Otherwise, this is NaN
            return f16::from_bits(0xFE00u16);
        }

        // The number is normalized, start assembling half precision version
        let half_sign = sign >> 16;
        // Unbias the exponent, then bias for half precision
        let unbiased_exp = (exp >> 20) - 1023;
        let half_exp = unbiased_exp + 15;

        // Check for exponent overflow, return +infinity
        if half_exp >= 0x1F {
            return f16::from_bits((half_sign | 0x7C00u32) as u16);
        }

        // Check for underflow
        if half_sign <= 0 {
            // Check mantissa for what we can do
            if 10 - half_exp > 21 {
                // No rounding possibility, so this is a full underflow, return signed zero
                return f16::from_bits(half_sign as u16);
            }
            // Don't forget about hidden leading mantissa bit when assembling mantissa
            let man = man | 0x00100000u32;
            let mut half_man = man >> (11 - half_exp);
            // Check for rounding
            if (man >> (10 - half_exp)) & 0x1u32 != 0 {
                half_man += 1;
            }
            // No exponent for denormals
            return f16::from_bits((half_sign | half_man) as u16);
        }

        // Rebias the exponent
        let half_exp = half_exp << 10;
        let half_man = man >> 10;
        // Check for rounding
        if man & 0x00000200u32 != 0 {
            // Round it
            f16::from_bits(((half_sign | half_exp | half_man) + 1) as u16)
        } else {
            f16::from_bits((half_sign | half_exp | half_man) as u16)
        }
    }

    pub fn as_bits(&self) -> u16 {
        self.0
    }

    pub fn to_f32(&self) -> f32 {
        // Check for signed zero
        if self.0 & 0x7FFFu16 == 0 {
            return unsafe { mem::transmute((self.0 as u32) << 16) };
        }

        let half_sign = (self.0 & 0x8000u16) as u32;
        let half_exp  = (self.0 & 0x7C00u16) as u32;
        let half_man  = (self.0 & 0x03FFu16) as u32;

        // Check for an infinity or NaN when all exponent bits set
        if half_exp == 0x7C00u32 {
            // Check for signed infinity if mantissa is zero
            if half_man == 0 {
                return unsafe { mem::transmute((half_sign << 16) | 0x7F800000u32) };
            } else {
                // NaN, only 1st mantissa bit is set
                return unsafe { mem::transmute(0xFFC00000u32) };
            }
        }

        // Calculate single-precision components with adjusted exponent
        let sign = half_sign << 16;
        // Unbias exponent
        let unbiased_exp = ((half_exp as i32) >> 10) - 15;
        let man = (half_man & 0x03FFu32) << 13;

        // Check for denormals, which will be normalized by adjusting exponent
        if half_exp == 0 {
            // Calculate how much to adjust the exponent by
            let e = {
                let mut e_adj = 0;
                let mut hm_adj = half_man << 1;
                while hm_adj & 0x0400u32 == 0 {
                    e_adj += 1;
                    hm_adj <<= 1;
                }
                e_adj
            };

            // Rebias and adjust exponent
            let exp = ((unbiased_exp + 127 - e) << 23) as u32;
            return unsafe { mem::transmute(sign | exp | man) };
        }

        // Rebias exponent for a normalized normal
        let exp = ((unbiased_exp + 127) << 23) as u32;
        unsafe { mem::transmute(sign | exp | man) }
    }

    pub fn to_f64(&self) -> f64 {
        // Check for signed zero
        if self.0 & 0x7FFFu16 == 0 {
            return unsafe { mem::transmute((self.0 as u64) << 48) };
        }

        let half_sign = (self.0 & 0x8000u16) as u64;
        let half_exp  = (self.0 & 0x7C00u16) as u64;
        let half_man  = (self.0 & 0x03FFu16) as u64;

        // Check for an infinity or NaN when all exponent bits set
        if half_exp == 0x7C00u64 {
            // Check for signed infinity if mantissa is zero
            if half_man == 0 {
                return unsafe { mem::transmute((half_sign << 48) | 0x7FF0000000000000u64) };
            } else {
                // NaN, only 1st mantissa bit is set
                return unsafe { mem::transmute(0xFFF8000000000000u64) };
            }
        }

        // Calculate double-precision components with adjusted exponent
        let sign = half_sign << 48;
        // Unbias exponent
        let unbiased_exp = ((half_exp as i64) >> 10) - 15;
        let man = (half_man & 0x03FFu64) << 42;

        // Check for denormals, which will be normalized by adjusting exponent
        if half_exp == 0 {
            // Calculate how much to adjust the exponent by
            let e = {
                let mut e_adj = 0;
                let mut hm_adj = half_man << 1;
                while hm_adj & 0x0400u64 == 0 {
                    e_adj += 1;
                    hm_adj <<= 1;
                }
                e_adj
            };

            // Rebias and adjust exponent
            let exp = ((unbiased_exp + 1023 - e) << 52) as u64;
            return unsafe { mem::transmute(sign | exp | man) };
        }

        // Rebias exponent for a normalized normal
        let exp = ((unbiased_exp + 1023) << 52) as u64;
        unsafe { mem::transmute(sign | exp | man) }
    }
}

//
impl From<f16> for f32 {
    fn from(x: f16) -> f32 {
        x.to_f32()
    }
}

impl From<f16> for f64 {
    fn from(x: f16) -> f64 {
        x.to_f64()
    }
}<commit_msg>Filled out traits and constants<commit_after>use std::mem;
use std::num::{FpCategory, ParseFloatError};
use std::cmp::Ordering;
use std::str::FromStr;
use std::fmt::{Display, LowerExp, UpperExp, Formatter, Error};

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, Default)]
pub struct f16(u16);

pub const DIGITS: u32 = 3;
pub const EPSILON: f16 = f16(0x1700u16); // 0.00097656;
pub const INFINITY: f16 = f16(0x7C00u16);
pub const MANTISSA_DIGITS: u32 = 11;
pub const MAX: f16 = f16(0x7BFF);
pub const MAX_10_EXP: i32 = 9;
pub const MAX_EXP: i32 = 15;
pub const MIN: f16 = f16(0xFBFF);
pub const MIN_10_EXP: i32 = -9;
pub const MIN_EXP: i32 = -14;
pub const MIN_POSITIVE: f16 = f16(0x0400u16);
pub const NAN: f16 = f16(0xFE00u16);
pub const NEG_INFINITY: f16 = f16(0xFC00u16);
pub const RADIX: u32 = 2;

// TODO Endianness *should* be fine -- except in archs the differ on int/fp endianness

impl f16 {
    #[inline(always)]
    pub fn from_bits(bits: u16) -> f16 {
        f16(bits)
    }

    pub fn from_f32(value: f32) -> f16 {
        // Convert to raw bytes
        let x: u32 = unsafe { mem::transmute(value) };

        // Check for signed zero
        if x & 0x7FFFFFFFu32 == 0 {
            return f16((x >> 16) as u16);
        }

        // Extract IEEE754 components
        let sign = x & 0x80000000u32;
        let exp  = x & 0x7F800000u32;
        let man  = x & 0x007FFFFFu32;

        // Denormals will underflow, so return signed zero
        if exp == 0 {
            return f16((sign >> 16) as u16);
        }

        // Check for all exponent bits being set, which is Infinity or NaN
        if exp == 0x7F800000u32 {
            // A mantissa of zero is a signed Infinity
            if man == 0 {
                return f16(((x >> 16) | 0x7C00u32) as u16);
            }
            // Otherwise, this is NaN
            return NAN;
        }

        // The number is normalized, start assembling half precision version
        let half_sign = sign >> 16;
        // Unbias the exponent, then bias for half precision
        let unbiased_exp = (exp >> 23) - 127;
        let half_exp = unbiased_exp + 15;

        // Check for exponent overflow, return +infinity
        if half_exp >= 0x1F {
            return f16((half_sign | 0x7C00u32) as u16);
        }

        // Check for underflow
        if half_exp <= 0 {
            // Check mantissa for what we can do
            if 14 - half_exp > 24 {
                // No rounding possibility, so this is a full underflow, return signed zero
                return f16(half_sign as u16);
            }
            // Don't forget about hidden leading mantissa bit when assembling mantissa
            let man = man | 0x00800000u32;
            let mut half_man = man >> (14 - half_exp);
            // Check for rounding
            if (man >> (13 - half_exp)) & 0x1u32 != 0 {
                half_man += 1;
            }
            // No exponent for denormals
            return f16((half_sign | half_man) as u16);
        }

        // Rebias the exponent
        let half_exp = half_exp << 10;
        let half_man = man >> 13;
        // Check for rounding
        if man & 0x00001000u32 != 0 {
            // Round it
            f16(((half_sign | half_exp | half_man) + 1) as u16)
        } else {
            f16((half_sign | half_exp | half_man) as u16)
        }
    }

    pub fn from_f64(value: f64) -> f16 {
        // Convert to raw bytes, truncating the last 32-bits of mantissa; that precision will always
        // be lost on half-precision.
        let val: u64 = unsafe { mem::transmute(value) };
        let x = (val >> 32) as u32;

        // Check for signed zero
        if x & 0x7FFFFFFFu32 == 0 {
            return f16((x >> 16) as u16);
        }

        // Extract IEEE754 components
        let sign = x & 0x80000000u32;
        let exp  = x & 0x7FF00000u32;
        let man  = x & 0x000FFFFFu32;

        // Denormals will underflow, so return signed zero
        if exp == 0 {
            return f16((sign >> 16) as u16);
        }

        // Check for all exponent bits being set, which is Infinity or NaN
        if exp == 0x7FF00000u32 {
            // A mantissa of zero is a signed Infinity
            if man == 0 {
                return f16(((x >> 16) | 0x7C00u32) as u16);
            }
            // Otherwise, this is NaN
            return NAN;
        }

        // The number is normalized, start assembling half precision version
        let half_sign = sign >> 16;
        // Unbias the exponent, then bias for half precision
        let unbiased_exp = (exp >> 20) - 1023;
        let half_exp = unbiased_exp + 15;

        // Check for exponent overflow, return +infinity
        if half_exp >= 0x1F {
            return f16((half_sign | 0x7C00u32) as u16);
        }

        // Check for underflow
        if half_exp <= 0 {
            // Check mantissa for what we can do
            if 10 - half_exp > 21 {
                // No rounding possibility, so this is a full underflow, return signed zero
                return f16(half_sign as u16);
            }
            // Don't forget about hidden leading mantissa bit when assembling mantissa
            let man = man | 0x00100000u32;
            let mut half_man = man >> (11 - half_exp);
            // Check for rounding
            if (man >> (10 - half_exp)) & 0x1u32 != 0 {
                half_man += 1;
            }
            // No exponent for denormals
            return f16((half_sign | half_man) as u16);
        }

        // Rebias the exponent
        let half_exp = half_exp << 10;
        let half_man = man >> 10;
        // Check for rounding
        if man & 0x00000200u32 != 0 {
            // Round it
            f16(((half_sign | half_exp | half_man) + 1) as u16)
        } else {
            f16((half_sign | half_exp | half_man) as u16)
        }
    }

    #[inline(always)]
    pub fn as_bits(self) -> u16 {
        self.0
    }

    fn to_f32(self) -> f32 {
        // Check for signed zero
        if self.0 & 0x7FFFu16 == 0 {
            return unsafe { mem::transmute((self.0 as u32) << 16) };
        }

        let half_sign = (self.0 & 0x8000u16) as u32;
        let half_exp  = (self.0 & 0x7C00u16) as u32;
        let half_man  = (self.0 & 0x03FFu16) as u32;

        // Check for an infinity or NaN when all exponent bits set
        if half_exp == 0x7C00u32 {
            // Check for signed infinity if mantissa is zero
            if half_man == 0 {
                return unsafe { mem::transmute((half_sign << 16) | 0x7F800000u32) };
            } else {
                // NaN, only 1st mantissa bit is set
                return unsafe { mem::transmute(0xFFC00000u32) };
            }
        }

        // Calculate single-precision components with adjusted exponent
        let sign = half_sign << 16;
        // Unbias exponent
        let unbiased_exp = ((half_exp as i32) >> 10) - 15;
        let man = (half_man & 0x03FFu32) << 13;

        // Check for denormals, which will be normalized by adjusting exponent
        if half_exp == 0 {
            // Calculate how much to adjust the exponent by
            let e = {
                let mut e_adj = 0;
                let mut hm_adj = half_man << 1;
                while hm_adj & 0x0400u32 == 0 {
                    e_adj += 1;
                    hm_adj <<= 1;
                }
                e_adj
            };

            // Rebias and adjust exponent
            let exp = ((unbiased_exp + 127 - e) << 23) as u32;
            return unsafe { mem::transmute(sign | exp | man) };
        }

        // Rebias exponent for a normalized normal
        let exp = ((unbiased_exp + 127) << 23) as u32;
        unsafe { mem::transmute(sign | exp | man) }
    }

    fn to_f64(self) -> f64 {
        // Check for signed zero
        if self.0 & 0x7FFFu16 == 0 {
            return unsafe { mem::transmute((self.0 as u64) << 48) };
        }

        let half_sign = (self.0 & 0x8000u16) as u64;
        let half_exp  = (self.0 & 0x7C00u16) as u64;
        let half_man  = (self.0 & 0x03FFu16) as u64;

        // Check for an infinity or NaN when all exponent bits set
        if half_exp == 0x7C00u64 {
            // Check for signed infinity if mantissa is zero
            if half_man == 0 {
                return unsafe { mem::transmute((half_sign << 48) | 0x7FF0000000000000u64) };
            } else {
                // NaN, only 1st mantissa bit is set
                return unsafe { mem::transmute(0xFFF8000000000000u64) };
            }
        }

        // Calculate double-precision components with adjusted exponent
        let sign = half_sign << 48;
        // Unbias exponent
        let unbiased_exp = ((half_exp as i64) >> 10) - 15;
        let man = (half_man & 0x03FFu64) << 42;

        // Check for denormals, which will be normalized by adjusting exponent
        if half_exp == 0 {
            // Calculate how much to adjust the exponent by
            let e = {
                let mut e_adj = 0;
                let mut hm_adj = half_man << 1;
                while hm_adj & 0x0400u64 == 0 {
                    e_adj += 1;
                    hm_adj <<= 1;
                }
                e_adj
            };

            // Rebias and adjust exponent
            let exp = ((unbiased_exp + 1023 - e) << 52) as u64;
            return unsafe { mem::transmute(sign | exp | man) };
        }

        // Rebias exponent for a normalized normal
        let exp = ((unbiased_exp + 1023) << 52) as u64;
        unsafe { mem::transmute(sign | exp | man) }
    }

    #[inline]
    pub fn is_nan(self) -> bool {
        (self.0 & 0x7C00u16 == 0x7C00u16) && (self.0 & 0x03FFu16 != 0)
    }

    #[inline]
    pub fn is_infinite(self) -> bool {
        (self.0 & 0x7C00u16 == 0x7C00u16) && (self.0 & 0x03FFu16 == 0)
    }

    #[inline]
    pub fn is_finite(self) -> bool {
        self.0 & 0x7C00u16 != 0x7C00u16
    }

    #[inline]
    pub fn is_normal(self) -> bool {
        let exp = self.0 & 0x7C00u16;
        exp != 0x7C00u16 && exp != 0
    }

    pub fn classify(self) -> FpCategory {
        let exp = self.0 & 0x7C00u16;
        let man = self.0 & 0x03FFu16;
        if exp == 0 {
            if man == 0 {
                FpCategory::Zero
            } else {
                FpCategory::Subnormal
            }
        } else if exp == 0x7C00u16 {
            if man == 0 {
                FpCategory::Infinite
            } else {
                FpCategory::Nan
            }
        } else {
            FpCategory::Normal
        }
    }

    pub fn signum(self) -> f16 {
        if self.is_nan() {
            self
        } else {
            f16(self.0 & 0x8000u16)
        }
    }

    #[inline]
    pub fn is_sign_positive(self) -> bool {
        self.0 & 0x8000u16 == 0
    }

    #[inline]
    pub fn is_sign_negative(self) -> bool {
        self.0 & 0x8000u16 != 0
    }
}

impl From<f16> for f32 {
    fn from(x: f16) -> f32 {
        x.to_f32()
    }
}

impl From<f16> for f64 {
    fn from(x: f16) -> f64 {
        x.to_f64()
    }
}

impl From<i8> for f16 {
    fn from(x: i8) -> f16 {
        // Convert to f32, then to f16
        f16::from_f32(f32::from(x))
    }
}

impl From<u8> for f16 {
    fn from(x: u8) -> f16 {
        // Convert to f32, then to f16
        f16::from_f32(f32::from(x))
    }
}

impl PartialEq for f16 {
    fn eq(&self, other: &f16) -> bool {
        !self.is_nan() && !other.is_nan() && self.0 == other.0
    }
}

impl PartialOrd for f16 {
    fn partial_cmp(&self, other: &f16) -> Option<Ordering> {
        if self.is_nan() || other.is_nan() {
            None
        } else if self.0 == other.0 {
            Some(Ordering::Equal)
        } else if self.0 < other.0 {
            Some(Ordering::Less)
        } else {
            Some(Ordering::Greater)
        }
    }

    fn lt(&self, other: &f16) -> bool {
        !self.is_nan() && !other.is_nan() && self.0 < other.0
    }

    fn le(&self, other: &f16) -> bool {
        !self.is_nan() && !other.is_nan() && self.0 <= other.0
    }

    fn gt(&self, other: &f16) -> bool {
        !self.is_nan() && !other.is_nan() && self.0 > other.0
    }

    fn ge(&self, other: &f16) -> bool {
        !self.is_nan() && !other.is_nan() && self.0 >= other.0
    }
}

impl FromStr for f16 {
    type Err = ParseFloatError;
    fn from_str(src: &str) -> Result<f16, ParseFloatError> {
        f32::from_str(src).map(|x| f16::from_f32(x))
    }
}

impl Display for f16 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{}", self.to_f32())
    }
}

impl LowerExp for f16 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{:e}", self.to_f32())
    }
}

impl UpperExp for f16 {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{:E}", self.to_f32())
    }
}<|endoftext|>


<commit_before>//! # Plist
//!
//! A rusty plist parser.
//!
//! ## Usage
//!
//! Put this in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! plist = "1"
//! ```
//!
//! And put this in your crate root:
//!
//! ```rust
//! extern crate plist;
//! ```
//!
//! ## Examples
//!
//! ### Using `serde`
//!
//! ```rust
//! extern crate plist;
//! # #[cfg(feature = "serde")]
//! #[macro_use]
//! extern crate serde_derive;
//!
//! # #[cfg(feature = "serde")]
//! # fn main() {
//! #[derive(Deserialize)]
//! #[serde(rename_all = "PascalCase")]
//! struct Book {
//!     title: String,
//!     author: String,
//!     excerpt: String,
//!     copies_sold: u64,
//! }
//!
//! let book: Book = plist::from_file("tests/data/book.plist")
//!     .expect("failed to read book.plist");
//!
//! assert_eq!(book.title, "Great Expectations");
//! # }
//! #
//! # #[cfg(not(feature = "serde"))]
//! # fn main() {}
//! ```
//!
//! ### Using `Value`
//!
//! ```rust
//! use plist::Value;
//!
//! let book = Value::from_file("tests/data/book.plist")
//!     .expect("failed to read book.plist");
//!
//! let title = book
//!     .as_dictionary()
//!     .and_then(|dict| dict.get("Title"))
//!     .and_then(|title| title.as_string());
//!
//! assert_eq!(title, Some("Great Expectations"));
//! ```
//!
//! ## Unstable Features
//!
//! Many features from previous versions are now hidden behind the
//! `enable_unstable_features_that_may_break_with_minor_version_bumps` feature. These will break in
//! minor version releases after the 1.0 release. If you really really must use them you should
//! specify a tilde requirement e.g. `plist = "~1.0.3"` in you `Cargo.toml` so that the plist crate
//! is not automatically updated to version 1.1.

pub mod dictionary;

#[cfg(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps")]
pub mod stream;
#[cfg(not(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"))]
mod stream;

mod date;
mod error;
mod integer;
mod uid;
mod value;

pub use date::{Date, InvalidXmlDate};
pub use dictionary::Dictionary;
pub use error::Error;
pub use integer::Integer;
pub use stream::XmlWriteOptions;
pub use uid::Uid;
pub use value::Value;

// Optional serde module
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;
#[cfg(feature = "serde")]
mod de;
#[cfg(feature = "serde")]
mod ser;
#[cfg(all(
    feature = "serde",
    any(
        test,
        feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
    )
))]
pub use self::{de::Deserializer, ser::Serializer};
#[cfg(feature = "serde")]
pub use self::{
    de::{from_bytes, from_file, from_reader, from_reader_xml},
    ser::{
        to_file_binary, to_file_xml, to_writer_binary, to_writer_xml, to_writer_xml_with_options,
    },
};

#[cfg(all(test, feature = "serde"))]
#[macro_use]
extern crate serde_derive;

#[cfg(all(test, feature = "serde"))]
mod serde_tests;

fn u64_to_usize(len_u64: u64) -> Option<usize> {
    let len = len_u64 as usize;
    if len as u64 != len_u64 {
        return None; // Too long
    }
    Some(len)
}
<commit_msg>Treat all warnings as errors<commit_after>//! # Plist
//!
//! A rusty plist parser.
//!
//! ## Usage
//!
//! Put this in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! plist = "1"
//! ```
//!
//! And put this in your crate root:
//!
//! ```rust
//! extern crate plist;
//! ```
//!
//! ## Examples
//!
//! ### Using `serde`
//!
//! ```rust
//! extern crate plist;
//! # #[cfg(feature = "serde")]
//! #[macro_use]
//! extern crate serde_derive;
//!
//! # #[cfg(feature = "serde")]
//! # fn main() {
//! #[derive(Deserialize)]
//! #[serde(rename_all = "PascalCase")]
//! struct Book {
//!     title: String,
//!     author: String,
//!     excerpt: String,
//!     copies_sold: u64,
//! }
//!
//! let book: Book = plist::from_file("tests/data/book.plist")
//!     .expect("failed to read book.plist");
//!
//! assert_eq!(book.title, "Great Expectations");
//! # }
//! #
//! # #[cfg(not(feature = "serde"))]
//! # fn main() {}
//! ```
//!
//! ### Using `Value`
//!
//! ```rust
//! use plist::Value;
//!
//! let book = Value::from_file("tests/data/book.plist")
//!     .expect("failed to read book.plist");
//!
//! let title = book
//!     .as_dictionary()
//!     .and_then(|dict| dict.get("Title"))
//!     .and_then(|title| title.as_string());
//!
//! assert_eq!(title, Some("Great Expectations"));
//! ```
//!
//! ## Unstable Features
//!
//! Many features from previous versions are now hidden behind the
//! `enable_unstable_features_that_may_break_with_minor_version_bumps` feature. These will break in
//! minor version releases after the 1.0 release. If you really really must use them you should
//! specify a tilde requirement e.g. `plist = "~1.0.3"` in you `Cargo.toml` so that the plist crate
//! is not automatically updated to version 1.1.

// Treat all warnings as errors.
#![deny(warnings)]

pub mod dictionary;

#[cfg(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps")]
pub mod stream;
#[cfg(not(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"))]
mod stream;

mod date;
mod error;
mod integer;
mod uid;
mod value;

pub use date::{Date, InvalidXmlDate};
pub use dictionary::Dictionary;
pub use error::Error;
pub use integer::Integer;
pub use stream::XmlWriteOptions;
pub use uid::Uid;
pub use value::Value;

// Optional serde module
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;
#[cfg(feature = "serde")]
mod de;
#[cfg(feature = "serde")]
mod ser;
#[cfg(all(
    feature = "serde",
    any(
        test,
        feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
    )
))]
pub use self::{de::Deserializer, ser::Serializer};
#[cfg(feature = "serde")]
pub use self::{
    de::{from_bytes, from_file, from_reader, from_reader_xml},
    ser::{
        to_file_binary, to_file_xml, to_writer_binary, to_writer_xml, to_writer_xml_with_options,
    },
};

#[cfg(all(test, feature = "serde"))]
#[macro_use]
extern crate serde_derive;

#[cfg(all(test, feature = "serde"))]
mod serde_tests;

fn u64_to_usize(len_u64: u64) -> Option<usize> {
    let len = len_u64 as usize;
    if len as u64 != len_u64 {
        return None; // Too long
    }
    Some(len)
}
<|endoftext|>


<commit_before>// tag_safe
//
// A linting plugin to flag calls to methods not marked "tag_safe"
// from methods marked "tag_safe".
//
// Author: John Hodge (thePowersGang/Mutabah)
//
// TODO: Support '#[tag_unsafe(type)]' which is used when a method has no marker
// - Allows default safe fallback, with upwards propagation.
//
#![crate_name="tag_safe"]
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]

#[macro_use]
extern crate log;

extern crate syntax;
#[macro_use]
extern crate rustc;

#[macro_use]
extern crate rustc_plugin;

use syntax::ast;
use rustc::hir::def_id::DefId;
use rustc::hir::def;
use syntax::codemap::Span;
use rustc::lint::{self, LintContext, LintPass, LateLintPass, LintArray};
use rustc_plugin::Registry;
use rustc::ty::{self, TyCtxt};
use rustc::hir;

declare_lint!(NOT_TAGGED_SAFE, Warn, "Warn about use of non-tagged methods within tagged function");

#[derive(Copy,Clone,Debug)]
enum SafetyType
{
    Safe,
    Unsafe,
    Unknown,
}

#[derive(Default)]
struct Pass
{
    /// Cache of flag types
    flag_types: Vec<String>,
    /// Node => (Type => IsSafe)
    flag_cache: ::rustc::util::nodemap::NodeMap< ::rustc::util::nodemap::FnvHashMap<usize, SafetyType> >,

    lvl: usize,
}

struct Visitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a, F: FnMut(&Span) + 'a>
{
    pass: &'a mut Pass,
    tcx: &'a TyCtxt<'a, 'gcx, 'tcx>,
    name: &'a str,
    unknown_assume: bool,
    cb: F,
}

// Hack to provide indenting in debug calls
struct Indent(usize);
impl ::std::fmt::Display for Indent {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        for s in ::std::iter::repeat(" ").take(self.0) {
            try!(write!(f, "{}", s));
        }
        Ok( () )
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NOT_TAGGED_SAFE)
    }
}

impl LateLintPass for Pass {
    fn check_fn(&mut self, cx: &lint::LateContext, _kind: ::rustc::hir::intravisit::FnKind, _decl: &hir::FnDecl, body: &hir::Block, _: Span, id: ast::NodeId) {
        let attrs = cx.tcx.map.attrs(id);
        for ty in attrs.iter()
            .filter(|a| a.check_name("tag_safe"))
            .filter_map(|a| a.meta_item_list())
            .flat_map(|x| x.iter())
        {
            if let Some(ty_name) = ty.name()
            {
                // Search body for calls to non safe methods
                let mut v = Visitor{
                        pass: self, tcx: &cx.tcx, name: &ty_name,
                        // - Assumes an untagged method is unsafe
                        unknown_assume: false,
                        cb: |span| {
                                cx.span_lint(NOT_TAGGED_SAFE, *span,
                                    &format!("Calling {}-unsafe method from a #[tag_safe({})] method", ty_name, ty_name)[..]
                                    );
                            },
                        };
                debug!("Method {:?} is marked safe '{}'", id, ty_name);
                hir::intravisit::walk_block(&mut v, body);
            }
        }
    }
}

impl Pass
{
    // Searches for the relevant marker
    fn check_for_marker(tcx: &TyCtxt, id: ast::NodeId, marker: &str, name: &str) -> bool
    {
        debug!("Checking for marker {}({}) on {:?}", marker, name, id);
        tcx.map.attrs(id).iter()
            .filter_map( |a| if a.check_name(marker) { a.meta_item_list() } else { None })
            .flat_map(|x| x.iter())
            .any(|a| a.name().as_ref().map(|x| &x[..]) == Some(name))
    }

    /// Recursively check that the provided function is either safe or unsafe.
    // Used to avoid excessive annotating
    fn recurse_fcn_body(&mut self, tcx: &TyCtxt, node_id: ast::NodeId, name_id: usize, name: &str, unknown_assume: bool) -> bool
    {
        // Cache this method as unknown (to prevent infinite recursion)
        self.flag_cache.entry(node_id)
            .or_insert(Default::default())
            .insert(name_id, SafetyType::Unknown)
            ;

        // and apply a visitor to all
        match tcx.map.get(node_id)
        {
        rustc::hir::map::NodeItem(i) =>
            match i.node {
            hir::ItemFn(_, _, _, _, _, ref body) => {
                // Enumerate this function's code, recursively checking for a call to an unsafe method
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, tcx: tcx, name: name,
                        unknown_assume: true,
                        cb: |_| { is_safe = false; }
                        };
                    hir::intravisit::walk_block(&mut v, body);
                }
                is_safe
                },
            _ => unknown_assume,
            },
        rustc::hir::map::NodeImplItem(i) =>
            match i.node {
            hir::ImplItemKind::Method(_, ref body) => {
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, tcx: tcx, name: name,
                        unknown_assume: true,
                        cb: |_| { is_safe = false; }
                        };
                    hir::intravisit::walk_block(&mut v, body);
                }
                is_safe
                },
            _ => unknown_assume,
            },
        rustc::hir::map::NodeForeignItem(i) =>
            if Self::check_for_marker(tcx, i.id, "tag_safe", name) {
                true
            }
            else if Self::check_for_marker(tcx, i.id, "tag_unsafe", name) {
                false
            }
            else {
                unknown_assume
            },
        v @ _ => {
            error!("Node ID {} points to non-item {:?}", node_id, v);
            unknown_assume
            }
        }
    }

    /// Check that a method within this crate is safe with the provided tag
    fn crate_method_is_safe(&mut self, tcx: &TyCtxt, node_id: ast::NodeId, name: &str, unknown_assume: bool) -> bool
    {
        // Obtain tag name ID (avoids storing a string in the map)
        let name_id =
            match self.flag_types.iter().position(|a| *a == name)
            {
            Some(v) => v,
            None => {
                self.flag_types.push( String::from(name) );
                self.flag_types.len() - 1
                },
            };

        // Check cache first
        if let Some(&st) = self.flag_cache.get(&node_id).and_then(|a| a.get(&name_id))
        {
            match st
            {
            SafetyType::Safe => true,
            SafetyType::Unsafe => false,
            SafetyType::Unknown => unknown_assume,
            }
        }
        else
        {
            // Search for a safety marker, possibly recursing
            let is_safe =
                if Self::check_for_marker(tcx, node_id, "tag_safe", name) {
                    true
                }
                else if Self::check_for_marker(tcx, node_id, "tag_unsafe", name) {
                    false
                }
                else {
                    self.recurse_fcn_body(tcx, node_id, name_id, name, unknown_assume)
                };
            // Save resultant value
            self.flag_cache.entry(node_id)
                .or_insert(Default::default())
                .insert(name_id, if is_safe { SafetyType::Safe } else { SafetyType::Unsafe })
                ;
            is_safe
        }
    }

    /// Locate a #[tag_safe(<name>)] attribute on the passed item
    pub fn method_is_safe(&mut self, tcx: &TyCtxt, id: DefId, name: &str, unknown_assume: bool) -> bool
    {
        debug!("{}Checking method {:?} (A {})", Indent(self.lvl), id, unknown_assume);
        self.lvl += 1;
        let rv = if id.krate == 0 {
                self.crate_method_is_safe(tcx, tcx.map.as_local_node_id(id).unwrap(), name, unknown_assume)
            }
            else {
                for a in tcx.get_attrs(id).iter()
                {
                    if a.check_name("tag_safe") {
                        if a.meta_item_list().iter().flat_map(|a| a.iter()).any(|a| a.name().as_ref().map(|x| &x[..]) == Some(name)) {
                            return true;
                        }
                    }
                    if a.check_name("tag_unsafe") {
                        if a.meta_item_list().iter().flat_map(|a| a.iter()).any(|a| a.name().as_ref().map(|x| &x[..]) == Some(name)) {
                            return false;
                        }
                    }
                }
                warn!("TODO: Crate ID non-zero {:?} (assuming safe)", id);
                // TODO: Check the crate import for an annotation
                true
            };
        self.lvl -= 1;
        debug!("{}Checking method {:?} = {}", Indent(self.lvl), id, rv);
        rv
    }
}

impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, F: FnMut(&Span)> hir::intravisit::Visitor<'a> for Visitor<'a,'gcx, 'tcx, F>
{
    // Locate function/method calls in a code block
    // - uses visit_expr_post because it doesn't _need_ to do anything
    fn visit_expr_post(&mut self, ex: &'a hir::Expr) {
        match ex.node
        {
        // Call expressions - check that it's a path call
        hir::ExprCall(ref fcn, _) =>
            match fcn.node
            {
            hir::ExprPath(ref _qs, ref _p) => {
                    if let def::Def::Fn(did) = self.tcx.expect_def(fcn.id) {
                        // Check for a safety tag
                        if !self.pass.method_is_safe(self.tcx, did, self.name, self.unknown_assume)
                        {
                            (self.cb)(&ex.span);
                        }
                    }
                },
            _ => {},
            },

        // Method call expressions - get the relevant method
        hir::ExprMethodCall(ref _id, ref _tys, ref _exprs) =>
            {
                let tables = self.tcx.tables.borrow();
                let mm = &tables.method_map;

                let callee = mm.get( &ty::MethodCall::expr(ex.id) ).unwrap();
                let id = callee.def_id;

                //if let ty::MethodStatic(id) = callee.origin {
                        // Check for a safety tag
                        if !self.pass.method_is_safe(self.tcx, id, self.name, self.unknown_assume) {
                            (self.cb)(&ex.span);
                        }
                //}
            },

        // Ignore any other type of node
        _ => {},
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    use syntax::feature_gate::AttributeType;
    reg.register_late_lint_pass( Box::new(Pass::default()) );

    reg.register_attribute(String::from("tag_safe"),   AttributeType::Whitelisted);
    reg.register_attribute(String::from("tag_unsafe"), AttributeType::Whitelisted);
}

// vim: ts=4 expandtab sw=4
<commit_msg>Fix nightly error due to CrateNum<commit_after>// tag_safe
//
// A linting plugin to flag calls to methods not marked "tag_safe"
// from methods marked "tag_safe".
//
// Author: John Hodge (thePowersGang/Mutabah)
//
// TODO: Support '#[tag_unsafe(type)]' which is used when a method has no marker
// - Allows default safe fallback, with upwards propagation.
//
#![crate_name="tag_safe"]
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]

#[macro_use]
extern crate log;

extern crate syntax;
#[macro_use]
extern crate rustc;

#[macro_use]
extern crate rustc_plugin;

use syntax::ast;
use rustc::hir::def_id::{self,DefId};
use rustc::hir::def;
use syntax::codemap::Span;
use rustc::lint::{self, LintContext, LintPass, LateLintPass, LintArray};
use rustc_plugin::Registry;
use rustc::ty::{self, TyCtxt};
use rustc::hir;

declare_lint!(NOT_TAGGED_SAFE, Warn, "Warn about use of non-tagged methods within tagged function");

#[derive(Copy,Clone,Debug)]
enum SafetyType
{
    Safe,
    Unsafe,
    Unknown,
}

#[derive(Default)]
struct Pass
{
    /// Cache of flag types
    flag_types: Vec<String>,
    /// Node => (Type => IsSafe)
    flag_cache: ::rustc::util::nodemap::NodeMap< ::rustc::util::nodemap::FnvHashMap<usize, SafetyType> >,

    lvl: usize,
}

struct Visitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a, F: FnMut(&Span) + 'a>
{
    pass: &'a mut Pass,
    tcx: &'a TyCtxt<'a, 'gcx, 'tcx>,
    name: &'a str,
    unknown_assume: bool,
    cb: F,
}

// Hack to provide indenting in debug calls
struct Indent(usize);
impl ::std::fmt::Display for Indent {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        for s in ::std::iter::repeat(" ").take(self.0) {
            try!(write!(f, "{}", s));
        }
        Ok( () )
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NOT_TAGGED_SAFE)
    }
}

impl LateLintPass for Pass {
    fn check_fn(&mut self, cx: &lint::LateContext, _kind: ::rustc::hir::intravisit::FnKind, _decl: &hir::FnDecl, body: &hir::Block, _: Span, id: ast::NodeId) {
        let attrs = cx.tcx.map.attrs(id);
        for ty in attrs.iter()
            .filter(|a| a.check_name("tag_safe"))
            .filter_map(|a| a.meta_item_list())
            .flat_map(|x| x.iter())
        {
            if let Some(ty_name) = ty.name()
            {
                // Search body for calls to non safe methods
                let mut v = Visitor{
                        pass: self, tcx: &cx.tcx, name: &ty_name,
                        // - Assumes an untagged method is unsafe
                        unknown_assume: false,
                        cb: |span| {
                                cx.span_lint(NOT_TAGGED_SAFE, *span,
                                    &format!("Calling {}-unsafe method from a #[tag_safe({})] method", ty_name, ty_name)[..]
                                    );
                            },
                        };
                debug!("Method {:?} is marked safe '{}'", id, ty_name);
                hir::intravisit::walk_block(&mut v, body);
            }
        }
    }
}

impl Pass
{
    // Searches for the relevant marker
    fn check_for_marker(tcx: &TyCtxt, id: ast::NodeId, marker: &str, name: &str) -> bool
    {
        debug!("Checking for marker {}({}) on {:?}", marker, name, id);
        tcx.map.attrs(id).iter()
            .filter_map( |a| if a.check_name(marker) { a.meta_item_list() } else { None })
            .flat_map(|x| x.iter())
            .any(|a| a.name().as_ref().map(|x| &x[..]) == Some(name))
    }

    /// Recursively check that the provided function is either safe or unsafe.
    // Used to avoid excessive annotating
    fn recurse_fcn_body(&mut self, tcx: &TyCtxt, node_id: ast::NodeId, name_id: usize, name: &str, unknown_assume: bool) -> bool
    {
        // Cache this method as unknown (to prevent infinite recursion)
        self.flag_cache.entry(node_id)
            .or_insert(Default::default())
            .insert(name_id, SafetyType::Unknown)
            ;

        // and apply a visitor to all
        match tcx.map.get(node_id)
        {
        rustc::hir::map::NodeItem(i) =>
            match i.node {
            hir::ItemFn(_, _, _, _, _, ref body) => {
                // Enumerate this function's code, recursively checking for a call to an unsafe method
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, tcx: tcx, name: name,
                        unknown_assume: true,
                        cb: |_| { is_safe = false; }
                        };
                    hir::intravisit::walk_block(&mut v, body);
                }
                is_safe
                },
            _ => unknown_assume,
            },
        rustc::hir::map::NodeImplItem(i) =>
            match i.node {
            hir::ImplItemKind::Method(_, ref body) => {
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, tcx: tcx, name: name,
                        unknown_assume: true,
                        cb: |_| { is_safe = false; }
                        };
                    hir::intravisit::walk_block(&mut v, body);
                }
                is_safe
                },
            _ => unknown_assume,
            },
        rustc::hir::map::NodeForeignItem(i) =>
            if Self::check_for_marker(tcx, i.id, "tag_safe", name) {
                true
            }
            else if Self::check_for_marker(tcx, i.id, "tag_unsafe", name) {
                false
            }
            else {
                unknown_assume
            },
        v @ _ => {
            error!("Node ID {} points to non-item {:?}", node_id, v);
            unknown_assume
            }
        }
    }

    /// Check that a method within this crate is safe with the provided tag
    fn crate_method_is_safe(&mut self, tcx: &TyCtxt, node_id: ast::NodeId, name: &str, unknown_assume: bool) -> bool
    {
        // Obtain tag name ID (avoids storing a string in the map)
        let name_id =
            match self.flag_types.iter().position(|a| *a == name)
            {
            Some(v) => v,
            None => {
                self.flag_types.push( String::from(name) );
                self.flag_types.len() - 1
                },
            };

        // Check cache first
        if let Some(&st) = self.flag_cache.get(&node_id).and_then(|a| a.get(&name_id))
        {
            match st
            {
            SafetyType::Safe => true,
            SafetyType::Unsafe => false,
            SafetyType::Unknown => unknown_assume,
            }
        }
        else
        {
            // Search for a safety marker, possibly recursing
            let is_safe =
                if Self::check_for_marker(tcx, node_id, "tag_safe", name) {
                    true
                }
                else if Self::check_for_marker(tcx, node_id, "tag_unsafe", name) {
                    false
                }
                else {
                    self.recurse_fcn_body(tcx, node_id, name_id, name, unknown_assume)
                };
            // Save resultant value
            self.flag_cache.entry(node_id)
                .or_insert(Default::default())
                .insert(name_id, if is_safe { SafetyType::Safe } else { SafetyType::Unsafe })
                ;
            is_safe
        }
    }

    /// Locate a #[tag_safe(<name>)] attribute on the passed item
    pub fn method_is_safe(&mut self, tcx: &TyCtxt, id: DefId, name: &str, unknown_assume: bool) -> bool
    {
        debug!("{}Checking method {:?} (A {})", Indent(self.lvl), id, unknown_assume);
        self.lvl += 1;
        let rv = if id.krate == def_id::LOCAL_CRATE {
                self.crate_method_is_safe(tcx, tcx.map.as_local_node_id(id).unwrap(), name, unknown_assume)
            }
            else {
                for a in tcx.get_attrs(id).iter()
                {
                    if a.check_name("tag_safe") {
                        if a.meta_item_list().iter().flat_map(|a| a.iter()).any(|a| a.name().as_ref().map(|x| &x[..]) == Some(name)) {
                            return true;
                        }
                    }
                    if a.check_name("tag_unsafe") {
                        if a.meta_item_list().iter().flat_map(|a| a.iter()).any(|a| a.name().as_ref().map(|x| &x[..]) == Some(name)) {
                            return false;
                        }
                    }
                }
                warn!("TODO: Crate ID non-zero {:?} (assuming safe)", id);
                // TODO: Check the crate import for an annotation
                true
            };
        self.lvl -= 1;
        debug!("{}Checking method {:?} = {}", Indent(self.lvl), id, rv);
        rv
    }
}

impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, F: FnMut(&Span)> hir::intravisit::Visitor<'a> for Visitor<'a,'gcx, 'tcx, F>
{
    // Locate function/method calls in a code block
    // - uses visit_expr_post because it doesn't _need_ to do anything
    fn visit_expr_post(&mut self, ex: &'a hir::Expr) {
        match ex.node
        {
        // Call expressions - check that it's a path call
        hir::ExprCall(ref fcn, _) =>
            match fcn.node
            {
            hir::ExprPath(ref _qs, ref _p) => {
                    if let def::Def::Fn(did) = self.tcx.expect_def(fcn.id) {
                        // Check for a safety tag
                        if !self.pass.method_is_safe(self.tcx, did, self.name, self.unknown_assume)
                        {
                            (self.cb)(&ex.span);
                        }
                    }
                },
            _ => {},
            },

        // Method call expressions - get the relevant method
        hir::ExprMethodCall(ref _id, ref _tys, ref _exprs) =>
            {
                let tables = self.tcx.tables.borrow();
                let mm = &tables.method_map;

                let callee = mm.get( &ty::MethodCall::expr(ex.id) ).unwrap();
                let id = callee.def_id;

                //if let ty::MethodStatic(id) = callee.origin {
                        // Check for a safety tag
                        if !self.pass.method_is_safe(self.tcx, id, self.name, self.unknown_assume) {
                            (self.cb)(&ex.span);
                        }
                //}
            },

        // Ignore any other type of node
        _ => {},
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    use syntax::feature_gate::AttributeType;
    reg.register_late_lint_pass( Box::new(Pass::default()) );

    reg.register_attribute(String::from("tag_safe"),   AttributeType::Whitelisted);
    reg.register_attribute(String::from("tag_unsafe"), AttributeType::Whitelisted);
}

// vim: ts=4 expandtab sw=4
<|endoftext|>