<commit_before>/// A comonoid in a monoidal category is a monoid
/// in the dual category, what is the problem?
///
/// Being the dual to a monoid, it consists of:
///
/// - The dual to unit, a function from `T` to `()` called `counit`.
/// - The dual to multiplication, a function from `T` to `(T, T)` called `comult`.
///
/// It is useful within Rust's ownership type system,
/// to represent a type that can be both cloned and destroyed.
///
/// There is a trivial implementation of this trait for every
/// type that implements `Clone`, as reflected by the `Comonoidal`
/// newtype wrapper, with `discard` as `counit`, and `duplicate` as `comult`.
/// The behaviour of `counit` and `comult` can be altered by the
/// implementation of [`Drop`](http://doc.rust-lang.org/std/ops/trait.Drop.html)
/// and [`Clone`](http://doc.rust-lang.org/std/clone/trait.Clone.html),
/// respectively.
pub trait Comonoid {
    /// The dual to the monoidal unit.
    fn counit(self) -> ();
    /// The dual to the monoidal multiplication.
    fn comult(self) -> (Self, Self);
}

/// Takes ownership of a value and returns `()`,
/// rendering it unusable.
pub fn discard<T>(_: T) -> () {}
/// Takes ownership of a value and returns a tuple of
/// clones.
pub fn duplicate<T>(a: T) -> (T, T) where T: Clone {
(a.clone(), a)
}

/// A newtype wrapper to make a comonoid out of any
/// cloneable type.
pub struct Comonoidal<T>(T);

impl<T> From<T> for Comonoidal<T> {
    fn from(a: T) -> Comonoidal<T> { Comonoidal(a) }
}

impl<T> AsRef<T> for Comonoidal<T> {
    fn as_ref(&self) -> &T { &self.0 }
}

impl<T> AsMut<T> for Comonoidal<T> {
    fn as_mut(&mut self) -> &mut T { &mut self.0 }
}

impl<T> Clone for Comonoidal<T> where T: Clone {
    fn clone(&self) -> Self {
        let a = self.0.clone();
        Comonoidal(a)
    }
}

impl<T> Comonoid for Comonoidal<T> where T: Clone {
    fn counit(self) -> () { discard(self) }
    fn comult(self) -> (Self, Self) { duplicate(self) }
}

#[test]
fn test_counit() {
    let x = Comonoidal(42);
    assert_eq!(x.counit(), ());
}

#[test]
fn test_comult() {
    let x = Comonoidal(42);
    let (y, z) = x.comult();
    assert_eq!(y.0, 42);
    assert_eq!(z.0, 42);
}
<commit_msg>Add a `Sized` bound to the `Comonoid` trait<commit_after>/// A comonoid in a monoidal category is a monoid
/// in the dual category, what is the problem?
///
/// Being the dual to a monoid, it consists of:
///
/// - The dual to unit, a function from `T` to `()` called `counit`.
/// - The dual to multiplication, a function from `T` to `(T, T)` called `comult`.
///
/// It is useful within Rust's ownership type system,
/// to represent a type that can be both cloned and destroyed.
///
/// There is a trivial implementation of this trait for every
/// type that implements `Clone`, as reflected by the `Comonoidal`
/// newtype wrapper, with `discard` as `counit`, and `duplicate` as `comult`.
/// The behaviour of `counit` and `comult` can be altered by the
/// implementation of [`Drop`](http://doc.rust-lang.org/std/ops/trait.Drop.html)
/// and [`Clone`](http://doc.rust-lang.org/std/clone/trait.Clone.html),
/// respectively.
pub trait Comonoid: Sized {
    /// The dual to the monoidal unit.
    fn counit(self) -> ();
    /// The dual to the monoidal multiplication.
    fn comult(self) -> (Self, Self);
}

/// Takes ownership of a value and returns `()`,
/// rendering it unusable.
pub fn discard<T>(_: T) -> () {}
/// Takes ownership of a value and returns a tuple of
/// clones.
pub fn duplicate<T>(a: T) -> (T, T) where T: Clone {
(a.clone(), a)
}

/// A newtype wrapper to make a comonoid out of any
/// cloneable type.
pub struct Comonoidal<T>(T);

impl<T> From<T> for Comonoidal<T> {
    fn from(a: T) -> Comonoidal<T> { Comonoidal(a) }
}

impl<T> AsRef<T> for Comonoidal<T> {
    fn as_ref(&self) -> &T { &self.0 }
}

impl<T> AsMut<T> for Comonoidal<T> {
    fn as_mut(&mut self) -> &mut T { &mut self.0 }
}

impl<T> Clone for Comonoidal<T> where T: Clone {
    fn clone(&self) -> Self {
        let a = self.0.clone();
        Comonoidal(a)
    }
}

impl<T> Comonoid for Comonoidal<T> where T: Clone {
    fn counit(self) -> () { discard(self) }
    fn comult(self) -> (Self, Self) { duplicate(self) }
}

#[test]
fn test_counit() {
    let x = Comonoidal(42);
    assert_eq!(x.counit(), ());
}

#[test]
fn test_comult() {
    let x = Comonoidal(42);
    let (y, z) = x.comult();
    assert_eq!(y.0, 42);
    assert_eq!(z.0, 42);
}
<|endoftext|>


<commit_before>// Copyright 2015  Emmanuele Bassi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![crate_name = "taglib"]
#![crate_type = "lib"]

extern crate libc;
extern crate taglib_sys as sys;

use libc::{c_char};
use std::ffi::{CString, CStr};

use sys as ll;

fn c_str_to_str(c_str: *const c_char) -> String {
  if c_str.is_null() {
    String::new()
  }
  else {
    let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() };
    String::from_utf8_lossy(bytes).to_string()
  }
}

/// A representation of an audio file, with meta-data and properties.
pub struct File {
  raw: *mut ll::TagLib_File,
}

/// The abstract meta-data container for audio files
///
/// Each `Tag` instance can only be created by the `taglib::File::tag()`
/// method.
#[allow(dead_code)]
pub struct Tag<'a> {
  raw: *mut ll::TagLib_Tag,
  file: &'a File,
}

/// Common audio file properties.
///
/// Instances of `AudioProperties` can only be created through the
/// `taglib::File::audioproperties()` method.
#[allow(dead_code)]
pub struct AudioProperties<'a> {
  raw: *const ll::TagLib_AudioProperties,
  file: &'a File,
}

impl<'a> Tag<'a> {
  /// Returns the track name, or an empty string if no track name is present.
  pub fn title(&self) -> String {
    let res = unsafe { ll::taglib_tag_title(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the track name.
  pub fn set_title(&mut self, title: &str) {
    let s = CString::new(title).unwrap().as_ptr();
    unsafe { ll::taglib_tag_set_title(self.raw, s); }
  }

  /// Returns the artist name, or an empty string if no artist name is present.
  pub fn artist(&self) -> String {
    let res = unsafe { ll::taglib_tag_artist(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the artist name.
  pub fn set_artist(&mut self, artist: &str) {
    let s = CString::new(artist).unwrap().as_ptr();
    unsafe { ll::taglib_tag_set_artist(self.raw, s); }
  }

  /// Returns the album name, or an empty string if no album name is present.
  pub fn album(&self) -> String {
    let res = unsafe { ll::taglib_tag_album(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the album name.
  pub fn set_album(&mut self, album: &str) {
    let s = CString::new(album).unwrap().as_ptr();
    unsafe { ll::taglib_tag_set_album(self.raw, s); }
  }

  /// Returns the track comment, or an empty string if no track comment is
  /// present.
  pub fn comment(&self) -> String {
    let res = unsafe { ll::taglib_tag_comment(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the track comment.
  pub fn set_comment(&mut self, comment: &str) {
    let s = CString::new(comment).unwrap().as_ptr();
    unsafe { ll::taglib_tag_set_comment(self.raw, s); }
  }

  /// Returns the genre name, or an empty string if no genre name is present.
  pub fn genre(&self) -> String {
    let res = unsafe { ll::taglib_tag_genre(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the genre name.
  pub fn set_genre(&mut self, genre: &str) {
    let s = CString::new(genre).unwrap().as_ptr();
    unsafe { ll::taglib_tag_set_genre(self.raw, s); }
  }

  /// Returns the year, or 0 if no year is present.
  pub fn year(&self) -> u32 {
    unsafe { ll::taglib_tag_year(self.raw) as u32 }
  }

  /// Sets the year.
  pub fn set_year(&mut self, year: u32) {
    unsafe { ll::taglib_tag_set_year(self.raw, year); }
  }

  /// Returns the track number, or 0 if no track number is present.
  pub fn track(&self) -> u32 {
    unsafe { ll::taglib_tag_track(self.raw) as u32 }
  }

  /// Sets the track number.
  pub fn set_track(&mut self, track: u32) {
    unsafe { ll::taglib_tag_set_track(self.raw, track); }
  }
}

impl<'a> AudioProperties<'a> {
  /// Returns the length, in seconds, of the track.
  pub fn length(&self) -> u32 {
    unsafe { ll::taglib_audioproperties_length(self.raw) as u32 }
  }

  /// Returns the most appropriate bit rate for the track, in kB/s.
  /// For constant bit rate formats, the returned value is the bit
  /// rate of the file; for variable bit rate formats this is either
  /// the average or the nominal bit rate.
  pub fn bitrate(&self) -> u32 {
    unsafe { ll::taglib_audioproperties_bitrate(self.raw) as u32 }
  }

  /// Returns the sample rate, in Hz.
  pub fn samplerate(&self) -> u32 {
    unsafe { ll::taglib_audioproperties_samplerate(self.raw) as u32 }
  }

  /// Returns the number of audio channels.
  pub fn channels(&self) -> u32 {
    unsafe { ll::taglib_audioproperties_channels(self.raw) as u32 }
  }
}

#[derive(Copy, Clone, PartialEq)]
pub enum FileType {
  /// MPEG file
  MPEG = ll::TAGLIB_FILE_MPEG as isize,
  /// Ogg/Vorbis file
  OggVorbis = ll::TAGLIB_FILE_OGG_VORBIS as isize,
  /// FLAC file
  FLAC = ll::TAGLIB_FILE_FLAC as isize,
  /// MPC file
  MPC = ll::TAGLIB_FILE_MPC as isize,
  /// Ogg/FLAC file
  OggFlac = ll::TAGLIB_FILE_OGG_FLAC as isize,
  /// WavPack file
  WavPack = ll::TAGLIB_FILE_WAV_PACK as isize,
  /// Ogg/Speex file
  Speex = ll::TAGLIB_FILE_SPEEX as isize,
  /// TrueAudio file
  TrueAudio = ll::TAGLIB_FILE_TRUE_AUDIO as isize,
  /// MP4 file
  MP4 = ll::TAGLIB_FILE_MP4 as isize,
  /// ASF file
  ASF = ll::TAGLIB_FILE_ASF as isize
}

#[derive(Debug)]
pub enum FileError {
  /// The file is an invalid or an unrecognized audio container
  InvalidFile,
  /// The file name is invalid
  InvalidFileName,
  /// No meta-data is available
  NoAvailableTag,
  /// No audio properties are available
  NoAvailableAudioProperties
}

impl Drop for File {
  fn drop(&mut self) {
    unsafe { ll::taglib_file_free(self.raw); }
  }
}

impl File {
  /// Creates a new `taglib::File` for the given `filename`.
  pub fn new(filename: &str) -> Result<File, FileError> {
    let filename_c =
      match CString::new(filename) {
        Ok(s) => s.as_ptr(),
        _ => return Err(FileError::InvalidFileName)
      };

    let f = unsafe { ll::taglib_file_new(filename_c) };
    if f.is_null() {
      return Err(FileError::InvalidFile);
    }

    Ok(File { raw: f })
  }

  /// Creates a new `taglib::File` for the given `filename` and type of file.
  pub fn new_type(filename: &str, filetype: FileType) -> Result<File, FileError> {
    let filename_c =
      match CString::new(filename) {
        Ok(s) => s.as_ptr(),
        _ => return Err(FileError::InvalidFileName)
      };

    let f = unsafe { ll::taglib_file_new_type(filename_c, filetype as u32) };
    if f.is_null() {
      return Err(FileError::InvalidFile);
    }

    Ok(File { raw: f })
  }

  /// Returns the `taglib::Tag` instance for the given file.
  pub fn tag(&self) -> Result<Tag, FileError> {
    let res = unsafe { ll::taglib_file_tag(self.raw) };

    if res.is_null() {
      Err(FileError::NoAvailableTag)
    }
    else {
      Ok(Tag { raw: res, file: self })
    }
  }

  /// Returns whether the file is valid.
  pub fn is_valid(&self) -> bool {
    unsafe { ll::taglib_file_is_valid(self.raw) != 0 }
  }

  /// Returns the `taglib::AudioProperties` instance for the given file.
  pub fn audioproperties(&self) -> Result<AudioProperties, FileError> {
    let res = unsafe { ll::taglib_file_audioproperties(self.raw) };

    if res.is_null() {
      Err(FileError::NoAvailableAudioProperties)
    }
    else {
      Ok(AudioProperties { raw: res, file: self })
    }
  }

  /// Updates the meta-data of the file.
  pub fn save(&self) -> bool {
    unsafe { ll::taglib_file_save(self.raw) != 0 }
  }
}
<commit_msg>Fix CString usages<commit_after>// Copyright 2015  Emmanuele Bassi. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![crate_name = "taglib"]
#![crate_type = "lib"]

extern crate libc;
extern crate taglib_sys as sys;

use libc::{c_char};
use std::ffi::{CString, CStr};

use sys as ll;

fn c_str_to_str(c_str: *const c_char) -> String {
  if c_str.is_null() {
    String::new()
  }
  else {
    let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() };
    String::from_utf8_lossy(bytes).to_string()
  }
}

/// A representation of an audio file, with meta-data and properties.
pub struct File {
  raw: *mut ll::TagLib_File,
}

/// The abstract meta-data container for audio files
///
/// Each `Tag` instance can only be created by the `taglib::File::tag()`
/// method.
#[allow(dead_code)]
pub struct Tag<'a> {
  raw: *mut ll::TagLib_Tag,
  file: &'a File,
}

/// Common audio file properties.
///
/// Instances of `AudioProperties` can only be created through the
/// `taglib::File::audioproperties()` method.
#[allow(dead_code)]
pub struct AudioProperties<'a> {
  raw: *const ll::TagLib_AudioProperties,
  file: &'a File,
}

impl<'a> Tag<'a> {
  /// Returns the track name, or an empty string if no track name is present.
  pub fn title(&self) -> String {
    let res = unsafe { ll::taglib_tag_title(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the track name.
  pub fn set_title(&mut self, title: &str) {
    let cs = CString::new(title).unwrap();
    let s = cs.as_ptr();
    unsafe { ll::taglib_tag_set_title(self.raw, s); }
  }

  /// Returns the artist name, or an empty string if no artist name is present.
  pub fn artist(&self) -> String {
    let res = unsafe { ll::taglib_tag_artist(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the artist name.
  pub fn set_artist(&mut self, artist: &str) {
    let cs = CString::new(artist).unwrap();
    let s = cs.as_ptr();
    unsafe { ll::taglib_tag_set_artist(self.raw, s); }
  }

  /// Returns the album name, or an empty string if no album name is present.
  pub fn album(&self) -> String {
    let res = unsafe { ll::taglib_tag_album(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the album name.
  pub fn set_album(&mut self, album: &str) {
    let cs = CString::new(album).unwrap();
    let s = cs.as_ptr();
    unsafe { ll::taglib_tag_set_album(self.raw, s); }
  }

  /// Returns the track comment, or an empty string if no track comment is
  /// present.
  pub fn comment(&self) -> String {
    let res = unsafe { ll::taglib_tag_comment(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the track comment.
  pub fn set_comment(&mut self, comment: &str) {
    let cs = CString::new(comment).unwrap();
    let s = cs.as_ptr();
    unsafe { ll::taglib_tag_set_comment(self.raw, s); }
  }

  /// Returns the genre name, or an empty string if no genre name is present.
  pub fn genre(&self) -> String {
    let res = unsafe { ll::taglib_tag_genre(self.raw) };
    c_str_to_str(res)
  }

  /// Sets the genre name.
  pub fn set_genre(&mut self, genre: &str) {
    let cs = CString::new(genre).unwrap();
    let s = cs.as_ptr();
    unsafe { ll::taglib_tag_set_genre(self.raw, s); }
  }

  /// Returns the year, or 0 if no year is present.
  pub fn year(&self) -> u32 {
    unsafe { ll::taglib_tag_year(self.raw) as u32 }
  }

  /// Sets the year.
  pub fn set_year(&mut self, year: u32) {
    unsafe { ll::taglib_tag_set_year(self.raw, year); }
  }

  /// Returns the track number, or 0 if no track number is present.
  pub fn track(&self) -> u32 {
    unsafe { ll::taglib_tag_track(self.raw) as u32 }
  }

  /// Sets the track number.
  pub fn set_track(&mut self, track: u32) {
    unsafe { ll::taglib_tag_set_track(self.raw, track); }
  }
}

impl<'a> AudioProperties<'a> {
  /// Returns the length, in seconds, of the track.
  pub fn length(&self) -> u32 {
    unsafe { ll::taglib_audioproperties_length(self.raw) as u32 }
  }

  /// Returns the most appropriate bit rate for the track, in kB/s.
  /// For constant bit rate formats, the returned value is the bit
  /// rate of the file; for variable bit rate formats this is either
  /// the average or the nominal bit rate.
  pub fn bitrate(&self) -> u32 {
    unsafe { ll::taglib_audioproperties_bitrate(self.raw) as u32 }
  }

  /// Returns the sample rate, in Hz.
  pub fn samplerate(&self) -> u32 {
    unsafe { ll::taglib_audioproperties_samplerate(self.raw) as u32 }
  }

  /// Returns the number of audio channels.
  pub fn channels(&self) -> u32 {
    unsafe { ll::taglib_audioproperties_channels(self.raw) as u32 }
  }
}

#[derive(Copy, Clone, PartialEq)]
pub enum FileType {
  /// MPEG file
  MPEG = ll::TAGLIB_FILE_MPEG as isize,
  /// Ogg/Vorbis file
  OggVorbis = ll::TAGLIB_FILE_OGG_VORBIS as isize,
  /// FLAC file
  FLAC = ll::TAGLIB_FILE_FLAC as isize,
  /// MPC file
  MPC = ll::TAGLIB_FILE_MPC as isize,
  /// Ogg/FLAC file
  OggFlac = ll::TAGLIB_FILE_OGG_FLAC as isize,
  /// WavPack file
  WavPack = ll::TAGLIB_FILE_WAV_PACK as isize,
  /// Ogg/Speex file
  Speex = ll::TAGLIB_FILE_SPEEX as isize,
  /// TrueAudio file
  TrueAudio = ll::TAGLIB_FILE_TRUE_AUDIO as isize,
  /// MP4 file
  MP4 = ll::TAGLIB_FILE_MP4 as isize,
  /// ASF file
  ASF = ll::TAGLIB_FILE_ASF as isize
}

#[derive(Debug)]
pub enum FileError {
  /// The file is an invalid or an unrecognized audio container
  InvalidFile,
  /// The file name is invalid
  InvalidFileName,
  /// No meta-data is available
  NoAvailableTag,
  /// No audio properties are available
  NoAvailableAudioProperties
}

impl Drop for File {
  fn drop(&mut self) {
    unsafe { ll::taglib_file_free(self.raw); }
  }
}

impl File {
  /// Creates a new `taglib::File` for the given `filename`.
  pub fn new(filename: &str) -> Result<File, FileError> {
    let filename_c =
      match CString::new(filename) {
        Ok(s) => s,
        _ => return Err(FileError::InvalidFileName)
      };

    let filename_c_ptr = filename_c.as_ptr();

    let f = unsafe { ll::taglib_file_new(filename_c_ptr) };
    if f.is_null() {
      return Err(FileError::InvalidFile);
    }

    Ok(File { raw: f })
  }

  /// Creates a new `taglib::File` for the given `filename` and type of file.
  pub fn new_type(filename: &str, filetype: FileType) -> Result<File, FileError> {
    let filename_c =
      match CString::new(filename) {
        Ok(s) => s,
        _ => return Err(FileError::InvalidFileName)
      };

    let filename_c_ptr = filename_c.as_ptr();
    let f = unsafe { ll::taglib_file_new_type(filename_c_ptr, filetype as u32) };
    if f.is_null() {
      return Err(FileError::InvalidFile);
    }

    Ok(File { raw: f })
  }

  /// Returns the `taglib::Tag` instance for the given file.
  pub fn tag(&self) -> Result<Tag, FileError> {
    let res = unsafe { ll::taglib_file_tag(self.raw) };

    if res.is_null() {
      Err(FileError::NoAvailableTag)
    }
    else {
      Ok(Tag { raw: res, file: self })
    }
  }

  /// Returns whether the file is valid.
  pub fn is_valid(&self) -> bool {
    unsafe { ll::taglib_file_is_valid(self.raw) != 0 }
  }

  /// Returns the `taglib::AudioProperties` instance for the given file.
  pub fn audioproperties(&self) -> Result<AudioProperties, FileError> {
    let res = unsafe { ll::taglib_file_audioproperties(self.raw) };

    if res.is_null() {
      Err(FileError::NoAvailableAudioProperties)
    }
    else {
      Ok(AudioProperties { raw: res, file: self })
    }
  }

  /// Updates the meta-data of the file.
  pub fn save(&self) -> bool {
    unsafe { ll::taglib_file_save(self.raw) != 0 }
  }
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate semver;
extern crate conduit;

use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::MemReader;
use std::collections::HashMap;
use std::fmt::Show;
use std::path::BytesContainer;

use semver::Version;
use conduit::{Method, Scheme, Host, Extensions, Headers, TypeMap};

pub struct MockRequest {
    path: String,
    method: Method,
    query_string: Option<String>,
    body: Option<Vec<u8>>,
    build_headers: HashMap<String, String>,
    headers: MockHeaders,
    extensions: TypeMap,
    reader: Option<MemReader>
}

impl MockRequest {
    pub fn new(method: Method, path: &str) -> MockRequest {
        let headers = HashMap::new();

        MockRequest {
            path: path.to_string(),
            extensions: TypeMap::new(),
            query_string: None,
            body: None,
            build_headers: headers,
            headers: MockHeaders { headers: HashMap::new() },
            method: method,
            reader: None
        }
    }

    pub fn with_method(&mut self, method: Method) -> &mut MockRequest {
        self.method = method;
        self
    }

    pub fn with_path(&mut self, path: &str) -> &mut MockRequest {
        self.path = path.to_string();
        self
    }

    pub fn with_query<'a, S: Show>(&'a mut self, string: S) -> &'a mut MockRequest {
        self.query_string = Some(string.to_string());
        self
    }

    pub fn with_body<'a, S: BytesContainer>(&'a mut self, string: S) -> &'a mut MockRequest {
        self.body = Some(string.container_as_bytes().to_vec());
        self.reader = None;
        self
    }

    pub fn header<'a, S1: Show, S2: Show>(&'a mut self, name: S1, value: S2) -> &'a mut MockRequest {
        self.build_headers.insert(name.to_string(), value.to_string());
        let headers = MockHeaders { headers: self.build_headers.clone() };
        self.headers = headers;

        self
    }
}

pub struct MockHeaders {
    headers: HashMap<String, String>
}

impl Headers for MockHeaders {
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>> {
        self.headers.find_equiv(&key).map(|v| vec!(v.as_slice()))
    }

    fn has(&self, key: &str) -> bool {
        self.headers.contains_key_equiv(&key)
    }

    fn iter<'a>(&'a self) -> conduit::HeaderEntries<'a> {
        box self.headers.iter().map(|(k,v)| (k.as_slice(), vec!(v.as_slice()))) as conduit::HeaderEntries<'a>
    }
}

impl<'a> conduit::Request for MockRequest {
    fn http_version(&self) -> Version {
        Version::parse("1.1.0").unwrap()
    }

    fn conduit_version(&self) -> Version {
        Version::parse("0.1.0").unwrap()
    }

    fn method(&self) -> Method { self.method }
    fn scheme(&self) -> Scheme { conduit::Http }
    fn host<'a>(&'a self) -> Host<'a> { conduit::HostName("example.com") }
    fn virtual_root<'a>(&'a self) -> Option<&'a str> { None }

    fn path<'a>(&'a self) -> &'a str {
        self.path.as_slice()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.query_string.as_ref().map(|s| s.as_slice())
    }

    fn remote_ip(&self) -> IpAddr {
        Ipv4Addr(127, 0, 0, 1)
    }

    fn content_length(&self) -> Option<uint> {
        self.body.as_ref().map(|b| b.len())
    }

    fn headers<'a>(&'a self) -> &'a Headers {
        &self.headers as &Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        if self.reader.is_none() {
            let body = self.body.clone().unwrap_or(Vec::new());
            self.reader = Some(MemReader::new(body));
        }
        self.reader.as_mut().unwrap() as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        &mut self.extensions
    }
}

#[cfg(test)]
mod tests {
    use super::MockRequest;
    use conduit;
    use semver::Version;

    use std::io::net::ip::Ipv4Addr;

    use conduit::Request;

    #[test]
    fn simple_request_test() {
        let mut req = MockRequest::new(conduit::Get, "/");

        assert_eq!(req.http_version(), Version::parse("1.1.0").unwrap());
        assert_eq!(req.conduit_version(), Version::parse("0.1.0").unwrap());
        assert_eq!(req.method(), conduit::Get);
        assert_eq!(req.scheme(), conduit::Http);
        assert_eq!(req.host(), conduit::HostName("example.com"));
        assert_eq!(req.virtual_root(), None);
        assert_eq!(req.path(), "/");
        assert_eq!(req.query_string(), None);
        assert_eq!(req.remote_ip(), Ipv4Addr(127, 0, 0, 1));
        assert_eq!(req.content_length(), None);
        assert_eq!(req.headers().iter().count(), 0);
        assert_eq!(req.body().read_to_string().ok().expect("No body"),
                   "".to_string());
    }

    #[test]
    fn request_body_test() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.with_body("Hello world");

        assert_eq!(req.method(), conduit::Post);
        assert_eq!(req.path(), "/articles");
        assert_eq!(req.body().read_to_string().ok().expect("No body"),
                   "Hello world".to_string());
        assert_eq!(req.content_length(), Some(11));
    }

    #[test]
    fn request_query_test() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.with_query("foo=bar");

        assert_eq!(req.query_string().expect("No query string"), "foo=bar");
    }

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.header("User-Agent", "lulz");
        req.header("DNT", "1");

        assert_eq!(req.headers().iter().count(), 2);
        assert_eq!(req.headers().find("User-Agent").unwrap(), vec!("lulz"));
        assert_eq!(req.headers().find("DNT").unwrap(), vec!("1"));
    }
}
<commit_msg>Update to conduit master<commit_after>#![feature(globs)]

extern crate semver;
extern crate conduit;

use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::MemReader;
use std::collections::HashMap;
use std::fmt::Show;
use std::path::BytesContainer;

use semver::Version;
use conduit::{Method, Scheme, Host, Extensions, Headers, TypeMap};

pub struct MockRequest {
    path: String,
    method: Method,
    query_string: Option<String>,
    body: Option<Vec<u8>>,
    build_headers: HashMap<String, String>,
    headers: MockHeaders,
    extensions: TypeMap,
    reader: Option<MemReader>
}

impl MockRequest {
    pub fn new(method: Method, path: &str) -> MockRequest {
        let headers = HashMap::new();

        MockRequest {
            path: path.to_string(),
            extensions: TypeMap::new(),
            query_string: None,
            body: None,
            build_headers: headers,
            headers: MockHeaders { headers: HashMap::new() },
            method: method,
            reader: None
        }
    }

    pub fn with_method(&mut self, method: Method) -> &mut MockRequest {
        self.method = method;
        self
    }

    pub fn with_path(&mut self, path: &str) -> &mut MockRequest {
        self.path = path.to_string();
        self
    }

    pub fn with_query<'a, S: Show>(&'a mut self, string: S) -> &'a mut MockRequest {
        self.query_string = Some(string.to_string());
        self
    }

    pub fn with_body<'a, S: BytesContainer>(&'a mut self, string: S) -> &'a mut MockRequest {
        self.body = Some(string.container_as_bytes().to_vec());
        self.reader = None;
        self
    }

    pub fn header<'a, S1: Show, S2: Show>(&'a mut self, name: S1, value: S2) -> &'a mut MockRequest {
        self.build_headers.insert(name.to_string(), value.to_string());
        let headers = MockHeaders { headers: self.build_headers.clone() };
        self.headers = headers;

        self
    }
}

pub struct MockHeaders {
    headers: HashMap<String, String>
}

impl Headers for MockHeaders {
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>> {
        self.headers.find_equiv(&key).map(|v| vec!(v.as_slice()))
    }

    fn has(&self, key: &str) -> bool {
        self.headers.contains_key_equiv(&key)
    }

    fn all(&self) -> Vec<(&str, Vec<&str>)> {
        self.headers.iter().map(|(k,v)| (k.as_slice(), vec![v.as_slice()]))
                    .collect()
    }
}

impl<'a> conduit::Request for MockRequest {
    fn http_version(&self) -> Version {
        Version::parse("1.1.0").unwrap()
    }

    fn conduit_version(&self) -> Version {
        Version::parse("0.1.0").unwrap()
    }

    fn method(&self) -> Method { self.method }
    fn scheme(&self) -> Scheme { conduit::Http }
    fn host<'a>(&'a self) -> Host<'a> { conduit::HostName("example.com") }
    fn virtual_root<'a>(&'a self) -> Option<&'a str> { None }

    fn path<'a>(&'a self) -> &'a str {
        self.path.as_slice()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.query_string.as_ref().map(|s| s.as_slice())
    }

    fn remote_ip(&self) -> IpAddr {
        Ipv4Addr(127, 0, 0, 1)
    }

    fn content_length(&self) -> Option<uint> {
        self.body.as_ref().map(|b| b.len())
    }

    fn headers<'a>(&'a self) -> &'a Headers {
        &self.headers as &Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        if self.reader.is_none() {
            let body = self.body.clone().unwrap_or(Vec::new());
            self.reader = Some(MemReader::new(body));
        }
        self.reader.as_mut().unwrap() as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        &mut self.extensions
    }
}

#[cfg(test)]
mod tests {
    use super::MockRequest;
    use conduit;
    use semver::Version;

    use std::io::net::ip::Ipv4Addr;

    use conduit::Request;

    #[test]
    fn simple_request_test() {
        let mut req = MockRequest::new(conduit::Get, "/");

        assert_eq!(req.http_version(), Version::parse("1.1.0").unwrap());
        assert_eq!(req.conduit_version(), Version::parse("0.1.0").unwrap());
        assert_eq!(req.method(), conduit::Get);
        assert_eq!(req.scheme(), conduit::Http);
        assert_eq!(req.host(), conduit::HostName("example.com"));
        assert_eq!(req.virtual_root(), None);
        assert_eq!(req.path(), "/");
        assert_eq!(req.query_string(), None);
        assert_eq!(req.remote_ip(), Ipv4Addr(127, 0, 0, 1));
        assert_eq!(req.content_length(), None);
        assert_eq!(req.headers().all().len(), 0);
        assert_eq!(req.body().read_to_string().ok().expect("No body"),
                   "".to_string());
    }

    #[test]
    fn request_body_test() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.with_body("Hello world");

        assert_eq!(req.method(), conduit::Post);
        assert_eq!(req.path(), "/articles");
        assert_eq!(req.body().read_to_string().ok().expect("No body"),
                   "Hello world".to_string());
        assert_eq!(req.content_length(), Some(11));
    }

    #[test]
    fn request_query_test() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.with_query("foo=bar");

        assert_eq!(req.query_string().expect("No query string"), "foo=bar");
    }

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.header("User-Agent", "lulz");
        req.header("DNT", "1");

        assert_eq!(req.headers().all().len(), 2);
        assert_eq!(req.headers().find("User-Agent").unwrap(), vec!("lulz"));
        assert_eq!(req.headers().find("DNT").unwrap(), vec!("1"));
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate hyper;
extern crate serde_json;

use std::io::Read;

use hyper::Client;
use hyper::header::Connection;

header! { (XStarfighterAuthorization, "X-Starfighter-Authorization") => [String] }

fn get<U: hyper::client::IntoUrl>(url: U) -> serde_json::Value {
    // Create a client.
    let client = Client::new();

    // Creating an outgoing request.
    let mut res = client.get(url)
        // set a header
        .header(Connection::close())
        // let 'er go!
        .send().unwrap();

    // Read the Response.
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let value: serde_json::Value = serde_json::from_str(&body).unwrap();
    value
}

pub fn test_api() {
    let value = get("http://api.stockfighter.io/ob/api/heartbeat");
    println!("Response: {}", value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap());
}

pub fn test_venue(venue: &str) {
    let url = format!("https://api.stockfighter.io/ob/api/venues/{}/heartbeat", venue);
    let value = get(&url);
    println!("Response: {}", value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap());
}

pub fn quote(venue: &str, stock: &str) -> bool {

    let url = format!("https://api.stockfighter.io/ob/api/venues/{}/stocks/{}/quote", venue, stock);

    let client = Client::new();

    let mut res = client
        .get(&url)
        .header(XStarfighterAuthorization("b6eb6d0a2b606c02c8b027fca35383fb2dc741d3".to_owned()))
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let value: serde_json::Value = serde_json::from_str(&body).unwrap();
    value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap()
}

mod test {
    use super::*;

    #[test]
    fn test_quote() {
        assert_eq!(true, quote("TESTEX", "FOOBAR"));
    }
}
<commit_msg>Use #[cfg(test)]<commit_after>#[macro_use]
extern crate hyper;
extern crate serde_json;

use std::io::Read;

use hyper::Client;
use hyper::header::Connection;

header! { (XStarfighterAuthorization, "X-Starfighter-Authorization") => [String] }

fn get<U: hyper::client::IntoUrl>(url: U) -> serde_json::Value {
    // Create a client.
    let client = Client::new();

    // Creating an outgoing request.
    let mut res = client.get(url)
        // set a header
        .header(Connection::close())
        // let 'er go!
        .send().unwrap();

    // Read the Response.
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let value: serde_json::Value = serde_json::from_str(&body).unwrap();
    value
}

pub fn test_api() {
    let value = get("http://api.stockfighter.io/ob/api/heartbeat");
    println!("Response: {}", value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap());
}

pub fn test_venue(venue: &str) {
    let url = format!("https://api.stockfighter.io/ob/api/venues/{}/heartbeat", venue);
    let value = get(&url);
    println!("Response: {}", value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap());
}

pub fn quote(venue: &str, stock: &str) -> bool {

    let url = format!("https://api.stockfighter.io/ob/api/venues/{}/stocks/{}/quote", venue, stock);

    let client = Client::new();

    let mut res = client
        .get(&url)
        .header(XStarfighterAuthorization("b6eb6d0a2b606c02c8b027fca35383fb2dc741d3".to_owned()))
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let value: serde_json::Value = serde_json::from_str(&body).unwrap();
    value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap()
}

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

    #[test]
    fn test_quote() {
        assert_eq!(true, quote("TESTEX", "FOOBAR"));
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]
#![allow(dead_code)]

//! # Rules
//! Rules uses regular expressions to do pattern matching using syntax
//! based upon the Perl 6 regex grammar. The Perl 6 grammar has been heavily
//! revised from Perl 5 and should not be equated with it. This may look
//! nothing like any regex you have seen before.
//!
//! # Syntax
//!
//! Currently, this is designed for ASCII and may not behave properly
//! with Unicode.
//!
//! Whitespace is generally ignored so that a regex can be more readable
//! and less dense.
//!
//! ```plain
//! r"fred"    // Normal way
//! r"f r e d" // Completely equivalent
//! // Will match `apples_oranges` or any other deliminator
//! r"apples . oranges"
//! ```
//!
//! # Set operators
//!
//! These operators can be applied to groups which will be analyzed later:
//!
//! ```plain
//! +       Union                // [123] + [345] = [12345]
//! |       Union                // Same
//! &       Intersection         // [123] & [345] = [3]
//! -       Difference           // [123] - [345] = [12]
//! ^       Symmetric difference // [123] ^ [345] = [1245]
//! ```
//!
//! # Character classes
//!
//! ## Default character classes
//!
//! Character | Matches               | Inverse
//! ----------|-----------------------|--------
//! `.`       | Any character         | N/A
//! `\d`      | Digit                 | `\D`
//! `\h`      | Horizontal whitespace | `\H`
//! `\n`      | Newline               | `\N`
//! `\s`      | Any whitespace        | `\S`
//! `\t`      | Tab                   | `\T`
//! `\w`      | Alphanumeric or `_`   | `\W`
//!
//! ## Custom character classes
//!
//! Characters inside a set of `<[ ]>` form a custom character
//! class:
//!
//! ```plain
//! // Matches `a` or `b` or `c`
//! <[ a b c ]>
//!
//! // `..` expresses a range so this matches
//! // from `a` to `g` or a digit
//! <[ a .. g \d ]>
//!
//! // The `[]` bind the sets together into (non-capturing)
//! // groups so set operators can be used.
//! <[0-9] - [13579]> // Matches an even number
//! <\d - [13579]>    // Same
//! <[0-6] ^ [5-9]>   // Matches a `5` or `6`
//! <-[0-6]>          // Negation: anything but 0-6
//! ```
//!
//! # Comments
//!
//! Comments are allowed inside a regex.
//!
//! ```plain
//! // This matches `myregex`
//! r"my // This is a comment which goes to the end of the line
//! regex"
//! ```

pub mod parse;
pub mod re;
mod unicode;

<commit_msg>Document literals<commit_after>#![allow(unused_variables)]
#![allow(dead_code)]

//! # Rules
//! Rules uses regular expressions to do pattern matching using syntax
//! based upon the Perl 6 regex grammar. The Perl 6 grammar has been heavily
//! revised from Perl 5 and should not be equated with it. This may look
//! nothing like any regex you have seen before.
//!
//! # Syntax
//!
//! Currently, this is designed for ASCII and may not behave properly
//! with Unicode.
//!
//! Whitespace is generally ignored so that a regex can be more readable
//! and less dense.
//!
//! ```plain
//! r"fred"    // Normal way
//! r"f r e d" // Completely equivalent
//! // Will match `apples_oranges` or any other deliminator
//! r"apples . oranges"
//! ```
//!
//! # Literals
//!
//! Alphanumerics, underscores (`_`), and everything enclosed within
//! quotes (`"`) and ticks (`'`) are the only literals.
//!
//! ```plain
//! hello_world   // Matches `hello_world`.
//! "carrot cake" // Matches `carrot cake`.
//! 'apple pie'   // Matches `apple pie`.
//! ```
//!
//! Everything else must be escaped with a backslash (`\*`) to literally match.
//!
//! ```plain
//! it\'s\ my\ birthday // Matches `it's my birthday`.
//! ```
//!
//! # Set operators
//!
//! These operators can be applied to groups which will be analyzed later:
//!
//! ```plain
//! +       Union                // [123] + [345] = [12345]
//! |       Union                // Same
//! &       Intersection         // [123] & [345] = [3]
//! -       Difference           // [123] - [345] = [12]
//! ^       Symmetric difference // [123] ^ [345] = [1245]
//! ```
//!
//! # Character classes
//!
//! ## Default character classes
//!
//! Character | Matches               | Inverse
//! ----------|-----------------------|--------
//! `.`       | Any character         | N/A
//! `\d`      | Digit                 | `\D`
//! `\h`      | Horizontal whitespace | `\H`
//! `\n`      | Newline               | `\N`
//! `\s`      | Any whitespace        | `\S`
//! `\t`      | Tab                   | `\T`
//! `\w`      | Alphanumeric or `_`   | `\W`
//!
//! ## Custom character classes
//!
//! Characters inside a set of `<[ ]>` form a custom character
//! class:
//!
//! ```plain
//! // Matches `a` or `b` or `c`
//! <[ a b c ]>
//!
//! // `..` expresses a range so this matches
//! // from `a` to `g` or a digit
//! <[ a .. g \d ]>
//!
//! // The `[]` bind the sets together into (non-capturing)
//! // groups so set operators can be used.
//! <[0-9] - [13579]> // Matches an even number
//! <\d - [13579]>    // Same
//! <[0-6] ^ [5-9]>   // Matches a `5` or `6`
//! <-[0-6]>          // Negation: anything but 0-6
//! ```
//!
//! # Comments
//!
//! Comments are allowed inside a regex.
//!
//! ```plain
//! // This matches `myregex`
//! r"my // This is a comment which goes to the end of the line
//! regex"
//! ```

pub mod parse;
pub mod re;
mod unicode;

<|endoftext|>


<commit_before>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//! A crate used for calculating offsets of struct members and their spans.
//!
//! This functionality currently can not be used in compile time code such as `const` or `const fn` definitions.
//!
//! ## Examples
//! ```
//! #[macro_use]
//! extern crate memoffset;
//!
//! #[repr(C, packed)]
//! struct HelpMeIAmTrappedInAStructFactory {
//!     help_me_before_they_: [u8; 15],
//!     a: u32
//! }
//!
//! fn main() {
//!     assert_eq!(offset_of!(HelpMeIAmTrappedInAStructFactory, a), 15);
//!     assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, a), 15..19);
//!     assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, help_me_before_they_ .. a), 0..15);
//! }
//! ```
//!
//! This functionality can be useful, for example, for checksum calculations:
//!
//! ```ignore
//! #[repr(C, packed)]
//! struct Message {
//!     header: MessageHeader,
//!     fragment_index: u32,
//!     fragment_count: u32,
//!     payload: [u8; 1024],
//!     checksum: u16
//! }
//!
//! let checksum_range = &raw[span_of!(Message, header..checksum)];
//! let checksum = crc16(checksum_range);
//! ```

#![no_std]
#![cfg_attr(
    feature = "unstable_const",
    feature(
        ptr_offset_from,
        const_fn,
        const_ptr_offset_from,
        const_maybe_uninit_as_ptr,
        const_raw_ptr_deref,
    )
)]

#[macro_use]
#[cfg(doctests)]
#[cfg(doctest)]
extern crate doc_comment;
#[cfg(doctests)]
#[cfg(doctest)]
doctest!("../README.md");

/// Hiden module for things the macros need to access.
#[doc(hidden)]
pub mod __priv {
    #[doc(hidden)]
    pub use core::mem;
    #[doc(hidden)]
    pub use core::ptr;

    /// Use type inference to obtain the size of the pointee (without actually using the pointer).
    #[doc(hidden)]
    pub fn size_of_pointee<T>(_ptr: *const T) -> usize {
        core::mem::size_of::<T>()
    }
}

#[macro_use]
mod raw_field;
#[macro_use]
mod offset_of;
#[macro_use]
mod span_of;
<commit_msg>fix build on old rustc<commit_after>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//! A crate used for calculating offsets of struct members and their spans.
//!
//! This functionality currently can not be used in compile time code such as `const` or `const fn` definitions.
//!
//! ## Examples
//! ```
//! #[macro_use]
//! extern crate memoffset;
//!
//! #[repr(C, packed)]
//! struct HelpMeIAmTrappedInAStructFactory {
//!     help_me_before_they_: [u8; 15],
//!     a: u32
//! }
//!
//! fn main() {
//!     assert_eq!(offset_of!(HelpMeIAmTrappedInAStructFactory, a), 15);
//!     assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, a), 15..19);
//!     assert_eq!(span_of!(HelpMeIAmTrappedInAStructFactory, help_me_before_they_ .. a), 0..15);
//! }
//! ```
//!
//! This functionality can be useful, for example, for checksum calculations:
//!
//! ```ignore
//! #[repr(C, packed)]
//! struct Message {
//!     header: MessageHeader,
//!     fragment_index: u32,
//!     fragment_count: u32,
//!     payload: [u8; 1024],
//!     checksum: u16
//! }
//!
//! let checksum_range = &raw[span_of!(Message, header..checksum)];
//! let checksum = crc16(checksum_range);
//! ```

#![no_std]
#![cfg_attr(
    feature = "unstable_const",
    feature(
        ptr_offset_from,
        const_fn,
        const_ptr_offset_from,
        const_maybe_uninit_as_ptr,
        const_raw_ptr_deref,
    )
)]

#[macro_use]
#[cfg(doctests)]
#[cfg(doctest)]
extern crate doc_comment;
#[cfg(doctests)]
#[cfg(doctest)]
doctest!("../README.md");

/// Hiden module for things the macros need to access.
#[doc(hidden)]
pub mod __priv {
    #[doc(hidden)]
    pub use core::mem;
    #[doc(hidden)]
    pub use core::ptr;

    /// Use type inference to obtain the size of the pointee (without actually using the pointer).
    #[doc(hidden)]
    pub fn size_of_pointee<T>(_ptr: *const T) -> usize {
        mem::size_of::<T>()
    }
}

#[macro_use]
mod raw_field;
#[macro_use]
mod offset_of;
#[macro_use]
mod span_of;
<|endoftext|>


<commit_before>extern crate rustc_serialize;
use std::fmt;
use rustc_serialize::json;

enum Change {
    Remove(Vec<String>, json::Json),
    Add(Vec<String>, json::Json),
    Insert(Vec<String>, json::Json),
    Rename(Vec<String>, String),
    Replace(Vec<String>, json::Json),
}

impl fmt::Debug for Change {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Change::Remove(ref kp, ref j) => write!(f, "Remove()"),
            &Change::Add(ref kp, ref j) => write!(f, "Add()"),
            &Change::Insert(ref kp, ref j) => write!(f, "Insert()"),
            &Change::Rename(ref kp, ref j) => write!(f, "Rename()"),
            &Change::Replace(ref kp, ref j) => write!(f, "Replace()"),
        }
    }
}

fn json_diff(left: &json::Json, right: &json::Json) -> Vec<Change> {
    Vec::new()
}

#[test]
fn it_works() {
    let left = json::Json::from_str("{\"a\": 100, \"b\": [1, 2, 3]}").unwrap();
    let right = json::Json::from_str("{\"a\": 100, \"b\": [1, 2, 3, 4]}").unwrap();
    let changes = json_diff(&left, &right);
    assert_eq!(0, changes.len());
}
<commit_msg>Got everything running<commit_after>extern crate rustc_serialize;
use std::fmt;
use rustc_serialize::json;

enum Change {
    Remove(Vec<String>, json::Json),
    Add(Vec<String>, json::Json),
    Insert(Vec<String>, json::Json),
    Rename(Vec<String>, String),
    Replace(Vec<String>, json::Json),
}

impl Change {
    fn write(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Change::Remove(ref kp, ref j) => write!(f, "Remove({})", j),
            &Change::Add(ref kp, ref j) => write!(f, "Add({})", j),
            &Change::Insert(ref kp, ref j) => write!(f, "Insert({})", j),
            &Change::Rename(ref kp, ref j) => write!(f, "Rename({})", j),
            &Change::Replace(ref kp, ref j) => write!(f, "Replace({})", j),
        }
    }
}

impl fmt::Debug for Change {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.write(f)
    }
}

fn json_diff(left: &json::Json, right: &json::Json) -> Vec<Change> {
    vec!(Change::Remove(Vec::new(), json::Json::Null))
}

#[test]
fn it_works() {
    let left = json::Json::from_str("{\"a\": 100, \"b\": [1, 2, 3]}").unwrap();
    let right = json::Json::from_str("{\"a\": 100, \"b\": [1, 2, 3, 4]}").unwrap();
    let changes = json_diff(&left, &right);
    assert_eq!("[Remove(null)]", format!("{:?}", changes));
}
<|endoftext|>


<commit_before>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

pub type Idx = u32;

trait Edges {
    fn len(&self) -> usize;
    fn nth_node(&self, n: usize) -> usize;
}

impl<'a> Edges for &'a [Idx] {
    fn len(&self) -> usize {
        let x: &[Idx] = self;
        x.len()
    }
    fn nth_node(&self, n: usize) -> usize {
        self[n] as usize
    }
}

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next<T: Edges>(n_i: T, n_j: T, x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i.nth_node(a), n_j.nth_node(b));

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[inline]
/// Calculates x[k+1]
///
/// `node_color_scale((i,j))`: If two nodes `i` (of graph A) and `j` (of graph B)
/// are of different color, this can be set to return 0.0. Alternatively a
/// node-color distance (within 0...1) could be used to penalize.
fn next_x<F>(x: &DMat<f32>,
             new_x: &mut DMat<f32>,
             in_a: &[Vec<Idx>],
             in_b: &[Vec<Idx>],
             out_a: &[Vec<Idx>],
             out_b: &[Vec<Idx>],
             node_color_scale: F)
    where F: Fn((usize, usize)) -> f32
{
    let shape = x.shape();
    assert!(shape == new_x.shape());

    for i in 0..shape.0 {
        for j in 0..shape.1 {
            let in_i: &[Idx] = &in_a[i];
            let in_j: &[Idx] = &in_b[j];
            let out_i: &[Idx] = &out_a[i];
            let out_j: &[Idx] = &out_b[j];
            new_x[(i, j)] = node_color_scale((i, j)) *
                            (s_next(in_i, in_j, x) + s_next(out_i, out_j, x)) /
                            2.0;
        }
    }
}

#[inline]
/// Calculates the similarity matrix for two graphs A and B.
///
/// `in_a`:  Incoming edge list for each node of graph A
/// `in_b`:  Incoming edge list for each node of graph B
/// `out_a`: Outgoing edge list for each node of graph A
/// `out_b`: Outgoing edge list for each node of graph B
/// `eps`:   When to stop the iteration
/// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
///
/// Returns (number of iterations, similarity matrix `x`)
pub fn neighbor_matching_matrix<F>(in_a: &[Vec<Idx>],
                                   in_b: &[Vec<Idx>],
                                   out_a: &[Vec<Idx>],
                                   out_b: &[Vec<Idx>],
                                   eps: f32,
                                   stop_after_iter: usize,
                                   node_color_scale: &F)
                                   -> (usize, DMat<f32>)
    where F: Fn((usize, usize)) -> f32
{
    let (na, nb) = (in_a.len(), in_b.len());
    assert!((na, nb) == (out_a.len(), out_b.len()));

    // `x` is the node-similarity matrix.
    // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
    // B.edges().
    let mut x: DMat<f32> = DMat::from_fn(na, nb, |i, j| {
        node_color_scale((i, j)) *
        if in_a[i].len() + out_a[i].len() > 0 && in_b[j].len() + out_b[j].len() > 0 {
            1.0
        } else {
            0.0
        }
    });

    let mut iter = 0;
    let mut new_x: DMat<f32> = DMat::new_zeros(na, nb);

    loop {
        if x.approx_eq_eps(&new_x, &eps) || iter >= stop_after_iter {
            break;
        }

        next_x(&x, &mut new_x, in_a, in_b, out_a, out_b, node_color_scale);
        mem::swap(&mut new_x, &mut x);
        iter += 1;
    }

    (iter, x)
}

/// Different similarity measures can be constructed from the node similarity matrix.
pub enum ScoreMethod {
    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    SumNormMinDegree,

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    SumNormMaxDegree,

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    Average,
}

#[inline]
/// Calculates the similiarity of two graphs.
///
/// For parameters see `neighbor_matching_matrix`.
pub fn neighbor_matching_score<F>(in_a: &[Vec<Idx>],
                                  in_b: &[Vec<Idx>],
                                  out_a: &[Vec<Idx>],
                                  out_b: &[Vec<Idx>],
                                  eps: f32,
                                  stop_after_iter: usize,
                                  node_color_scale: &F,
                                  score_method: ScoreMethod)
                                  -> (usize, f32)
    where F: Fn((usize, usize)) -> f32
{
    let (iter, x) = neighbor_matching_matrix(in_a,
                                             in_b,
                                             out_a,
                                             out_b,
                                             eps,
                                             stop_after_iter,
                                             node_color_scale);
    let n = cmp::min(x.nrows(), x.ncols());
    let m = cmp::max(x.nrows(), x.ncols());
    if n == 0 {
        return (iter, 0.0);
    }

    match score_method {
        ScoreMethod::SumNormMinDegree | ScoreMethod::SumNormMaxDegree => {
            let norm = match score_method {
                ScoreMethod::SumNormMinDegree => n as f32,
                ScoreMethod::SumNormMaxDegree => m as f32,
                _ => unreachable!(),
            };

            let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
            let assignment = solve_assignment(&mut w);
            assert!(assignment.len() == n);
            let score: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[ab]);
            (iter, score / norm)
        }
        ScoreMethod::Average => {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            (iter, sum / len as f32)
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 100, &|_| 1.0);
    println!("{:?}", mat);
    assert_eq!(iter, 1);
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 1, &|_| 1.0);
    assert_eq!(iter, 1);
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMinDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMaxDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);
}
<commit_msg>Rename nth_node to nth_edge, and comment.<commit_after>/// A graph similarity score using neighbor matching according to [this paper][1].
///
/// [1]: http://arxiv.org/abs/1009.5290 "2010, Mladen Nikolic, Measuring Similarity
///      of Graph Nodes by Neighbor Matching"

extern crate nalgebra;
extern crate munkres;

use nalgebra::{DMat, Shape, ApproxEq};
use munkres::{WeightMatrix, solve_assignment};
use std::cmp;
use std::mem;

pub type Idx = u32;

trait Edges {
    /// The number of edges
    fn len(&self) -> usize;

    /// Returns the target node of the nth-edge
    fn nth_edge(&self, n: usize) -> usize;
}

impl<'a> Edges for &'a [Idx] {
    fn len(&self) -> usize {
        let x: &[Idx] = self;
        x.len()
    }
    fn nth_edge(&self, n: usize) -> usize {
        self[n] as usize
    }
}

#[inline]
/// Calculates the similarity of two nodes `i` and `j`.
///
/// `n_i` contains the neighborhood of i (either in or out neighbors, not both)
/// `n_j` contains the neighborhood of j (either in or out neighbors, not both)
/// `x`   the similarity matrix.
fn s_next<T: Edges>(n_i: T, n_j: T, x: &DMat<f32>) -> f32 {
    let max_deg = cmp::max(n_i.len(), n_j.len());
    let min_deg = cmp::min(n_i.len(), n_j.len());

    if min_deg == 0 {
        // in the paper, 0/0 is defined as 1.0
        return 1.0;
    }

    assert!(min_deg > 0 && max_deg > 0);

    // map indicies from 0..min(degree) to the node indices
    let mapidx = |(a, b)| (n_i.nth_edge(a), n_j.nth_edge(b));

    let mut w = WeightMatrix::from_fn(min_deg, |ab| x[mapidx(ab)]);

    let assignment = solve_assignment(&mut w);
    assert!(assignment.len() == min_deg);

    let sum: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[mapidx(ab)]);

    return sum / max_deg as f32;
}

#[inline]
/// Calculates x[k+1]
///
/// `node_color_scale((i,j))`: If two nodes `i` (of graph A) and `j` (of graph B)
/// are of different color, this can be set to return 0.0. Alternatively a
/// node-color distance (within 0...1) could be used to penalize.
fn next_x<F>(x: &DMat<f32>,
             new_x: &mut DMat<f32>,
             in_a: &[Vec<Idx>],
             in_b: &[Vec<Idx>],
             out_a: &[Vec<Idx>],
             out_b: &[Vec<Idx>],
             node_color_scale: F)
    where F: Fn((usize, usize)) -> f32
{
    let shape = x.shape();
    assert!(shape == new_x.shape());

    for i in 0..shape.0 {
        for j in 0..shape.1 {
            let in_i: &[Idx] = &in_a[i];
            let in_j: &[Idx] = &in_b[j];
            let out_i: &[Idx] = &out_a[i];
            let out_j: &[Idx] = &out_b[j];
            new_x[(i, j)] = node_color_scale((i, j)) *
                            (s_next(in_i, in_j, x) + s_next(out_i, out_j, x)) /
                            2.0;
        }
    }
}

#[inline]
/// Calculates the similarity matrix for two graphs A and B.
///
/// `in_a`:  Incoming edge list for each node of graph A
/// `in_b`:  Incoming edge list for each node of graph B
/// `out_a`: Outgoing edge list for each node of graph A
/// `out_b`: Outgoing edge list for each node of graph B
/// `eps`:   When to stop the iteration
/// `stop_after_iter`: Stop after iteration (Calculate x(stop_after_iter))
///
/// Returns (number of iterations, similarity matrix `x`)
pub fn neighbor_matching_matrix<F>(in_a: &[Vec<Idx>],
                                   in_b: &[Vec<Idx>],
                                   out_a: &[Vec<Idx>],
                                   out_b: &[Vec<Idx>],
                                   eps: f32,
                                   stop_after_iter: usize,
                                   node_color_scale: &F)
                                   -> (usize, DMat<f32>)
    where F: Fn((usize, usize)) -> f32
{
    let (na, nb) = (in_a.len(), in_b.len());
    assert!((na, nb) == (out_a.len(), out_b.len()));

    // `x` is the node-similarity matrix.
    // we initialize `x`, so that x[i,j]=1 for all i in A.edges() and j in
    // B.edges().
    let mut x: DMat<f32> = DMat::from_fn(na, nb, |i, j| {
        node_color_scale((i, j)) *
        if in_a[i].len() + out_a[i].len() > 0 && in_b[j].len() + out_b[j].len() > 0 {
            1.0
        } else {
            0.0
        }
    });

    let mut iter = 0;
    let mut new_x: DMat<f32> = DMat::new_zeros(na, nb);

    loop {
        if x.approx_eq_eps(&new_x, &eps) || iter >= stop_after_iter {
            break;
        }

        next_x(&x, &mut new_x, in_a, in_b, out_a, out_b, node_color_scale);
        mem::swap(&mut new_x, &mut x);
        iter += 1;
    }

    (iter, x)
}

/// Different similarity measures can be constructed from the node similarity matrix.
pub enum ScoreMethod {
    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Used as default in the paper.
    SumNormMinDegree,

    /// Sums the optimal assignment of the node similarities and normalizes (divides)
    /// by the min degree of both graphs.
    /// Penalizes the difference in size of graphs.
    SumNormMaxDegree,

    /// Calculates the average over the whole node similarity matrix. This is faster,
    /// as no assignment has to be found. "Graphs with greater number of automorphisms
    /// would be considered to be more self-similar than graphs without automorphisms."
    Average,
}

#[inline]
/// Calculates the similiarity of two graphs.
///
/// For parameters see `neighbor_matching_matrix`.
pub fn neighbor_matching_score<F>(in_a: &[Vec<Idx>],
                                  in_b: &[Vec<Idx>],
                                  out_a: &[Vec<Idx>],
                                  out_b: &[Vec<Idx>],
                                  eps: f32,
                                  stop_after_iter: usize,
                                  node_color_scale: &F,
                                  score_method: ScoreMethod)
                                  -> (usize, f32)
    where F: Fn((usize, usize)) -> f32
{
    let (iter, x) = neighbor_matching_matrix(in_a,
                                             in_b,
                                             out_a,
                                             out_b,
                                             eps,
                                             stop_after_iter,
                                             node_color_scale);
    let n = cmp::min(x.nrows(), x.ncols());
    let m = cmp::max(x.nrows(), x.ncols());
    if n == 0 {
        return (iter, 0.0);
    }

    match score_method {
        ScoreMethod::SumNormMinDegree | ScoreMethod::SumNormMaxDegree => {
            let norm = match score_method {
                ScoreMethod::SumNormMinDegree => n as f32,
                ScoreMethod::SumNormMaxDegree => m as f32,
                _ => unreachable!(),
            };

            let mut w = WeightMatrix::from_fn(n, |ij| x[ij]);
            let assignment = solve_assignment(&mut w);
            assert!(assignment.len() == n);
            let score: f32 = assignment.iter().fold(0.0, |acc, &ab| acc + x[ab]);
            (iter, score / norm)
        }
        ScoreMethod::Average => {
            let sum: f32 = x.as_vec().iter().fold(0.0, |acc, &v| acc + v);
            let len = x.as_vec().len();
            assert!(len > 0);
            (iter, sum / len as f32)
        }
    }
}

#[test]
fn test_matrix() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 100, &|_| 1.0);
    println!("{:?}", mat);
    assert_eq!(iter, 1);
    assert_eq!(2, mat.nrows());
    assert_eq!(2, mat.ncols());

    // A and B are isomorphic
    assert_eq!(1.0, mat[(0, 0)]);
    assert_eq!(1.0, mat[(0, 1)]);
    assert_eq!(1.0, mat[(1, 0)]);
    assert_eq!(1.0, mat[(1, 1)]);
}

#[test]
fn test_matrix_iter1() {
    let in_a = vec![vec![0, 0, 0]];
    let out_a = vec![vec![0, 0, 0]];

    let in_b = vec![vec![0, 0, 0, 0, 0]];
    let out_b = vec![vec![0, 0, 0, 0, 0]];

    let (iter, mat) = neighbor_matching_matrix(&in_a, &in_b, &out_a, &out_b, 0.1, 1, &|_| 1.0);
    assert_eq!(iter, 1);
    assert_eq!(3.0 / 5.0, mat[(0, 0)]);
}

#[test]
fn test_score() {
    // A: 0 --> 1
    let in_a = vec![vec![], vec![0]];
    let out_a = vec![vec![1], vec![]];

    // B: 0 <-- 1
    let in_b = vec![vec![1], vec![]];
    let out_b = vec![vec![], vec![0]];

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMinDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);

    let (iter, score) = neighbor_matching_score(&in_a,
                                                &in_b,
                                                &out_a,
                                                &out_b,
                                                0.1,
                                                100,
                                                &|_| 1.0,
                                                ScoreMethod::SumNormMaxDegree);
    assert_eq!(iter, 1);

    // The score is 1.0 <=> A and B are isomorphic
    assert_eq!(1.0, score);
}
<|endoftext|>


<commit_before>extern crate md5;

pub fn puzzle(door_id: &str) -> String {
    let door_id = door_id.trim();

    let mut answer = String::new();
    let mut index = 0;

    for i in 0..8 {
        let (new_index, char_index, next_char) = next_interesting_md5(door_id, index);
        index = new_index + 1;
        answer.push(next_char);
        println!("found {} char: {}", i + 1, next_char);
    }
    answer
}

pub fn next_interesting_md5(door_id: &str, mut index: u32) -> (u32, usize, char) {
    let mut digest = String::with_capacity(2 * 16);

    loop {
        if index % 1000000 == 0 {
            println!("at index {}", index);
        }
        let candidate = format!("{}{}", door_id, index);
        digest.clear();

        for b in &md5::compute(candidate.as_bytes())[..] {
            digest.push_str(&format!("{:02x}", b));
        }

        if digest.starts_with("00000") {
            let mut chars = digest.chars();
            let char_index = chars.nth(5).expect("no 5th char");

            if is_valid_index(char_index) {
                let mut s = String::new();
                s.push(char_index);
                return (
                    index,
                    s.parse().expect("can't parse"),
                    chars.next().expect("no 6th char")
                )
            } else {
                index += 1;
            }
        } else {
            index += 1;
        }
    }
}

pub fn is_valid_index(candidate: char) -> bool {
    match candidate {
        '0'...'9' => true,
        _ => false
    }
}

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

    #[test]
    fn once() {
        assert_eq!(next_interesting_md5("abc", 0), (3231929, 1, '5'));
    }

    #[test]
    fn valid_index() {
        assert!(is_valid_index('9'));
    }

}
<commit_msg>Whew, day 5 part 2 works!<commit_after>use std::collections::HashSet;

extern crate md5;

pub fn puzzle(door_id: &str) -> String {
    let door_id = door_id.trim();

    let mut seen_indices = HashSet::new();
    let mut answer = vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '];
    let mut index = 0;

    while seen_indices.len() < 8 {
        let (new_index, char_index, next_char) = next_interesting_md5(door_id, index);
        index = new_index + 1;

        if answer[char_index] == ' ' {
            answer[char_index] = next_char;
            seen_indices.insert(char_index);

            println!("found {} char, answer[{}] = {}", seen_indices.len(), char_index, next_char);
            println!("answer is now {:?}", answer);
        }
    }

    let mut ans_str = String::new();
    for c in answer {
        ans_str.push(c);
    }
    ans_str
}

pub fn next_interesting_md5(door_id: &str, mut index: u32) -> (u32, usize, char) {
    let mut digest = String::with_capacity(2 * 16);

    loop {
        if index % 1000000 == 0 {
            println!("at index {}", index);
        }
        let candidate = format!("{}{}", door_id, index);
        digest.clear();

        for b in &md5::compute(candidate.as_bytes())[..] {
            digest.push_str(&format!("{:02x}", b));
        }

        if digest.starts_with("00000") {
            let mut chars = digest.chars();
            let char_index = chars.nth(5).expect("no 5th char");

            if is_valid_index(char_index) {
                let mut s = String::new();
                s.push(char_index);
                return (
                    index,
                    s.parse().expect("can't parse"),
                    chars.next().expect("no 6th char")
                )
            } else {
                index += 1;
            }
        } else {
            index += 1;
        }
    }
}

pub fn is_valid_index(candidate: char) -> bool {
    match candidate {
        '0'...'7' => true,
        _ => false
    }
}

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

    // #[test]
    // fn once() {
    //     assert_eq!(next_interesting_md5("abc", 0), (3231929, 1, '5'));
    // }

    #[test]
    fn valid_index() {
        assert!( ! is_valid_index('9') );
        assert!( ! is_valid_index('8') );
        assert!(is_valid_index('7'));
    }

    #[test]
    fn sample() {
        assert_eq!(puzzle("abc"), String::from("05ace8e3"));
    }

}
<|endoftext|>


<commit_before>//! A simple but effective sign library, written in Rust.
//!
//! Ported from [nobi](https://github.com/cyx/nobi),
//! which itself is a port of [itsdangerous](http://pythonhosted.org/itsdangerous/).
//!
//! # Possible use cases
//!
//! * Creating an activation link for users
//! * Creating a password reset link
//!
//! # Basic Example:
//!
//! ```rust
//! use nobsign::Signer;
//! let signer = Signer::new(b"my secret");
//!
//! // Let's say the user's ID is 101
//! let signed = signer.sign("101");
//!
//! // You can now email this url to your users!
//! let url = format!("http://yoursite.com/activate/?key={}", signed);
//!
//! // Later check the signature and get the value back
//! let unsigned = signer.unsign(&signed).unwrap();
//! ```
//!
//! # Example with timestamped signatures
//!
//! ```rust
//! use nobsign::TimestampSigner;
//! let signer = TimestampSigner::new(b"my secret");
//!
//! // Let's say the user's ID is 101
//! let signed = signer.sign("101");
//!
//! // You can now email this url to your users!
//! let url = format!("http://yoursite.com/activate/?key={}", signed);
//!
//! // In your code, you can verify the expiration:
//! signer.unsign(&signed, 86400).unwrap(); // 1 day expiration
//! ```
extern crate rustc_serialize;
extern crate ring;
extern crate time;
extern crate byteorder;

// Use same EPOCH as nobi, the Ruby implementation
const EPOCH : i32 = 1293840000;

use ring::{digest, hmac};
use rustc_serialize::base64::{ToBase64, FromBase64, URL_SAFE};
use byteorder::{ByteOrder, LittleEndian};

static ALGORITHM: &'static digest::Algorithm = &digest::SHA1;

#[derive(Debug,PartialEq)]
pub enum Error {
    BadData,
    BadSignature,
    BadTimeSignature,
    SignatureExpired,
}

pub struct Signer {
    separator: char,
    s_key: hmac::SigningKey,
    v_key: hmac::VerificationKey,
}

pub struct TimestampSigner {
    signer: Signer,
}

fn int_to_bytes(n: i32) -> [u8; 4] {
    let mut out = [0; 4];

    LittleEndian::write_i32(&mut out, n);
    out
}
fn bytes_to_int(n: &[u8]) -> i32 {
    assert!(n.len() == 4);
    LittleEndian::read_i32(n)
}

impl Signer {
    pub fn new(secret: &[u8]) -> Signer {
        let initial_key = hmac::SigningKey::new(ALGORITHM, secret);
        let derived_key = hmac::sign(&initial_key, b"nobi.Signer");

        Signer {
            separator: '.',
            s_key: hmac::SigningKey::new(ALGORITHM, derived_key.as_ref()),
            v_key: hmac::VerificationKey::new(ALGORITHM, derived_key.as_ref()),
        }
    }

    pub fn sign(&self, value: &str) -> String {
        format!("{}{}{}", value, self.separator, &self.signature(value))
    }

    pub fn unsign(&self, value: &str) -> Result<String, Error> {
        let mut splitted = value.rsplitn(2, |c| c == self.separator);

        let sig = match splitted.next() {
            Some(val) => val,
            None => return Err(Error::BadSignature),
        };
        let value = match splitted.next() {
            Some(val) => val,
            None => return Err(Error::BadSignature),
        };

        let sig = try!(sig.from_base64().map_err(|_| Error::BadSignature));
        try!(hmac::verify(&self.v_key, value.as_bytes(), &sig)
                .map_err(|_| Error::BadSignature));

        Ok(value.into())
    }

    fn signature(&self, value: &str) -> String {
        let sig = hmac::sign(&self.s_key, value.as_bytes());
        sig.as_ref().to_base64(URL_SAFE)
    }
}

impl TimestampSigner {
    pub fn new(secret: &[u8]) -> TimestampSigner {
        TimestampSigner { signer: Signer::new(secret) }
    }

    fn get_timestamp(&self) -> i32 {
        let now = time::now_utc().to_timespec();
        now.sec as i32 - EPOCH
    }

    pub fn sign(&self, value: &str) -> String {
        let timestamp = self.get_timestamp();
        let timestamp = int_to_bytes(timestamp);
        let timestamp = timestamp.to_base64(URL_SAFE);
        let value = format!("{}{}{}", value, self.signer.separator, timestamp);

        format!("{}{}{}",
                value,
                self.signer.separator,
                &self.signature(&value))
    }

    pub fn unsign(&self, value: &str, max_age: u32) -> Result<String, Error> {
        let result = try!(self.signer.unsign(value));

        if !result.contains(self.signer.separator) {
            return Err(Error::BadTimeSignature);
        }

        let mut splitted = result.rsplitn(2, |c| c == self.signer.separator);

        let timestamp = match splitted.next() {
            Some(val) => val,
            None => return Err(Error::BadSignature),
        };
        let value = match splitted.next() {
            Some(val) => val,
            None => return Err(Error::BadSignature),
        };

        let timestamp = match timestamp.from_base64() {
            Err(_) => return Err(Error::BadTimeSignature),
            Ok(timestamp) => timestamp,
        };
        if timestamp.len() != 4 {
            return Err(Error::BadTimeSignature);
        }
        let timestamp = bytes_to_int(&timestamp);
        let age = self.get_timestamp() - timestamp;

        if age > max_age as i32 {
            return Err(Error::SignatureExpired);
        }

        Ok(value.into())
    }

    fn signature(&self, value: &str) -> String {
        self.signer.signature(value)
    }
}

#[test]
fn signs() {
    let signer = Signer::new(b"my-key");

    let signed = signer.sign("value");
    assert_eq!("value.EWkF3-80sipsPgLQ01NuTuPb0jQ".to_owned(), signed);

    assert_eq!("value".to_owned(), signer.unsign(&signed).unwrap());
}

#[test]
fn bad_unsign() {
    let signer = Signer::new(b"my-key");

    let signed = "value.ABCDEF";
    assert_eq!(Err(Error::BadSignature), signer.unsign(&signed));
}

#[test]
fn signs_with_timestamp() {
    let signer = TimestampSigner::new(b"my-key");

    let signed = signer.sign("value");

    assert_eq!("value".to_owned(), signer.unsign(&signed, 100).unwrap());
}

#[test]
fn bad_unsign_with_timestamp() {
    let signer = TimestampSigner::new(b"my-key");

    let signed = "value.ABCDEF";
    assert_eq!(Err(Error::BadSignature), signer.unsign(&signed, 10));

    let signed = "value.EWkF3-80sipsPgLQ01NuTuPb0jQ";
    assert_eq!(Err(Error::BadTimeSignature), signer.unsign(&signed, 10));

    let signed = "value.AB.HHdWpuF7QVDZ_02wvECHvtV8vIc";
    assert_eq!(Err(Error::BadTimeSignature), signer.unsign(&signed, 10));
}

#[test]
fn unsign_expired() {
    use std::thread::sleep_ms;
    let signer = TimestampSigner::new(b"my-key");
    let signed = signer.sign("value");
    sleep_ms(1000);
    assert_eq!(Err(Error::SignatureExpired), signer.unsign(&signed, 0));
}

#[test]
fn with_secure_secret() {
    use ring::rand;
    let mut key = vec![0u8; ALGORITHM.digest_len];
    rand::fill_secure_random(&mut key).unwrap();

    let signer = Signer::new(&key);
    let signed = signer.sign("Hello world!");

    assert_eq!("Hello world!", signer.unsign(&signed).unwrap());
}
<commit_msg>Auto merge of #5 - badboy:pr-4, r=badboy<commit_after>//! A simple but effective sign library, written in Rust.
//!
//! Ported from [nobi](https://github.com/cyx/nobi),
//! which itself is a port of [itsdangerous](http://pythonhosted.org/itsdangerous/).
//!
//! # Possible use cases
//!
//! * Creating an activation link for users
//! * Creating a password reset link
//!
//! # Basic Example:
//!
//! ```rust
//! use nobsign::Signer;
//! let signer = Signer::new(b"my secret");
//!
//! // Let's say the user's ID is 101
//! let signed = signer.sign("101");
//!
//! // You can now email this url to your users!
//! let url = format!("http://yoursite.com/activate/?key={}", signed);
//!
//! // Later check the signature and get the value back
//! let unsigned = signer.unsign(&signed).unwrap();
//! ```
//!
//! # Example with timestamped signatures
//!
//! ```rust
//! use nobsign::TimestampSigner;
//! let signer = TimestampSigner::new(b"my secret");
//!
//! // Let's say the user's ID is 101
//! let signed = signer.sign("101");
//!
//! // You can now email this url to your users!
//! let url = format!("http://yoursite.com/activate/?key={}", signed);
//!
//! // In your code, you can verify the expiration:
//! signer.unsign(&signed, 86400).unwrap(); // 1 day expiration
//! ```
extern crate rustc_serialize;
extern crate ring;
extern crate time;
extern crate byteorder;

// Use same EPOCH as nobi, the Ruby implementation
const EPOCH : i32 = 1293840000;

use ring::{digest, hmac};
use rustc_serialize::base64::{ToBase64, FromBase64, URL_SAFE};
use byteorder::{ByteOrder, LittleEndian};

static ALGORITHM: &'static digest::Algorithm = &digest::SHA1;

#[derive(Debug,PartialEq)]
pub enum Error {
    BadData,
    BadSignature,
    BadTimeSignature,
    SignatureExpired,
}

pub struct Signer {
    separator: char,
    key: hmac::SigningKey,
}

pub struct TimestampSigner {
    signer: Signer,
}

fn int_to_bytes(n: i32) -> [u8; 4] {
    let mut out = [0; 4];

    LittleEndian::write_i32(&mut out, n);
    out
}
fn bytes_to_int(n: &[u8]) -> i32 {
    assert!(n.len() == 4);
    LittleEndian::read_i32(n)
}

impl Signer {
    pub fn new(secret: &[u8]) -> Signer {
        let initial_key = hmac::SigningKey::new(ALGORITHM, secret);
        let derived_key = hmac::sign(&initial_key, b"nobi.Signer");

        Signer {
            separator: '.',
            key: hmac::SigningKey::new(ALGORITHM, derived_key.as_ref()),
        }
    }

    pub fn sign(&self, value: &str) -> String {
        format!("{}{}{}", value, self.separator, &self.signature(value))
    }

    pub fn unsign(&self, value: &str) -> Result<String, Error> {
        let mut splitted = value.rsplitn(2, |c| c == self.separator);

        let sig = match splitted.next() {
            Some(val) => val,
            None => return Err(Error::BadSignature),
        };
        let value = match splitted.next() {
            Some(val) => val,
            None => return Err(Error::BadSignature),
        };

        let sig = try!(sig.from_base64().map_err(|_| Error::BadSignature));
        try!(hmac::verify_with_own_key(&self.key, value.as_bytes(), &sig)
                .map_err(|_| Error::BadSignature));

        Ok(value.into())
    }

    fn signature(&self, value: &str) -> String {
        let sig = hmac::sign(&self.key, value.as_bytes());
        sig.as_ref().to_base64(URL_SAFE)
    }
}

impl TimestampSigner {
    pub fn new(secret: &[u8]) -> TimestampSigner {
        TimestampSigner { signer: Signer::new(secret) }
    }

    fn get_timestamp(&self) -> i32 {
        let now = time::now_utc().to_timespec();
        now.sec as i32 - EPOCH
    }

    pub fn sign(&self, value: &str) -> String {
        let timestamp = self.get_timestamp();
        let timestamp = int_to_bytes(timestamp);
        let timestamp = timestamp.to_base64(URL_SAFE);
        let value = format!("{}{}{}", value, self.signer.separator, timestamp);

        format!("{}{}{}",
                value,
                self.signer.separator,
                &self.signature(&value))
    }

    pub fn unsign(&self, value: &str, max_age: u32) -> Result<String, Error> {
        let result = try!(self.signer.unsign(value));

        if !result.contains(self.signer.separator) {
            return Err(Error::BadTimeSignature);
        }

        let mut splitted = result.rsplitn(2, |c| c == self.signer.separator);

        let timestamp = match splitted.next() {
            Some(val) => val,
            None => return Err(Error::BadSignature),
        };
        let value = match splitted.next() {
            Some(val) => val,
            None => return Err(Error::BadSignature),
        };

        let timestamp = match timestamp.from_base64() {
            Err(_) => return Err(Error::BadTimeSignature),
            Ok(timestamp) => timestamp,
        };
        if timestamp.len() != 4 {
            return Err(Error::BadTimeSignature);
        }
        let timestamp = bytes_to_int(&timestamp);
        let age = self.get_timestamp() - timestamp;

        if age > max_age as i32 {
            return Err(Error::SignatureExpired);
        }

        Ok(value.into())
    }

    fn signature(&self, value: &str) -> String {
        self.signer.signature(value)
    }
}

#[test]
fn signs() {
    let signer = Signer::new(b"my-key");

    let signed = signer.sign("value");
    assert_eq!("value.EWkF3-80sipsPgLQ01NuTuPb0jQ".to_owned(), signed);

    assert_eq!("value".to_owned(), signer.unsign(&signed).unwrap());
}

#[test]
fn bad_unsign() {
    let signer = Signer::new(b"my-key");

    let signed = "value.ABCDEF";
    assert_eq!(Err(Error::BadSignature), signer.unsign(&signed));
}

#[test]
fn signs_with_timestamp() {
    let signer = TimestampSigner::new(b"my-key");

    let signed = signer.sign("value");

    assert_eq!("value".to_owned(), signer.unsign(&signed, 100).unwrap());
}

#[test]
fn bad_unsign_with_timestamp() {
    let signer = TimestampSigner::new(b"my-key");

    let signed = "value.ABCDEF";
    assert_eq!(Err(Error::BadSignature), signer.unsign(&signed, 10));

    let signed = "value.EWkF3-80sipsPgLQ01NuTuPb0jQ";
    assert_eq!(Err(Error::BadTimeSignature), signer.unsign(&signed, 10));

    let signed = "value.AB.HHdWpuF7QVDZ_02wvECHvtV8vIc";
    assert_eq!(Err(Error::BadTimeSignature), signer.unsign(&signed, 10));
}

#[test]
fn unsign_expired() {
    use std::thread::sleep_ms;
    let signer = TimestampSigner::new(b"my-key");
    let signed = signer.sign("value");
    sleep_ms(1000);
    assert_eq!(Err(Error::SignatureExpired), signer.unsign(&signed, 0));
}

#[test]
fn with_secure_secret() {
    use ring::rand;
    let mut key = vec![0u8; ALGORITHM.digest_len];
    rand::fill_secure_random(&mut key).unwrap();

    let signer = Signer::new(&key);
    let signed = signer.sign("Hello world!");

    assert_eq!("Hello world!", signer.unsign(&signed).unwrap());
}
<|endoftext|>


<commit_before>//! # Test CLI Applications
//!
//! Currently, this crate only includes basic functionality to check the output of a child process
//! is as expected.
//!
//! ## Example
//!
//! Here's a trivial example:
//!
//! ```rust
//! # extern crate assert_cli;
//!
//! assert_cli::assert_cli_output("echo", &["42"], "42").unwrap();
//! ```
//!
//! And here is one that will fail:
//!
//! ```rust,should_panic
//! assert_cli::assert_cli_output("echo", &["42"], "1337").unwrap();
//! ```
//!
//! this will show a nice, colorful diff in your terminal, like this:
//!
//! ```diff
//! -1337
//! +42
//! ```
//!
//! Alternatively, you can use the `assert_cli!` macro:
//!
//! ```rust,ignore
//! assert_cli!("echo 42" => Success, "42").unwrap();
//! ```
//!
//! Make sure to include the crate as `#[macro_use] extern crate assert_cli;`.

#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

#![deny(missing_docs)]

extern crate ansi_term;
extern crate difference;

use std::process::{Command, Output};
use std::error::Error;
use std::ffi::OsStr;

mod cli_error;
mod diff;

use cli_error::CliError;

/// Assert a CLI call returns the expected output.
///
/// To test that
///
/// ```sh
/// bash -c $BLACK_BOX
/// ```
///
/// returns
///
/// ```plain
/// Launch sequence initiated.
/// ```
///
/// you would call it like this:
///
/// ```rust
/// # extern crate assert_cli;
/// # const BLACK_BOX: &'static str = r#"function test_helper() {\
/// # echo "Launch sequence initiated."; return 0; }; test_helper"#;
/// assert_cli::assert_cli_output("bash", &["-c", BLACK_BOX], "Launch sequence initiated.");
/// ```
pub fn assert_cli_output<S>(cmd: &str, args: &[S], expected_output: &str) -> Result<(), Box<Error>>
    where S: AsRef<OsStr>
{
    let call: Result<Output, Box<Error>> = Command::new(cmd)
                                               .args(args)
                                               .output()
                                               .map_err(From::from);

    call.and_then(|output| {
            if !output.status.success() {
                return Err(From::from(CliError::WrongExitCode(output)));
            }

            let stdout = String::from_utf8_lossy(&output.stdout);
            let (distance, changes) = difference::diff(expected_output.trim(),
                                                       &stdout.trim(),
                                                       "\n");
            if distance > 0 {
                return Err(From::from(CliError::OutputMissmatch(changes)));
            }

            Ok(())
        })
        .map_err(From::from)
}

/// Assert a CLI call that fails the expected `stderr` output and error code.
///
/// To test that
///
/// ```sh
/// bash -c $BLACK_BOX
/// ```
///
/// fails with an exit code of `42` after printing this to `stderr`
///
/// ```plain
/// error no 42!
/// ```
///
/// you would call it like this:
///
/// ```rust
/// # extern crate assert_cli;
/// # const BLACK_BOX: &'static str = r#"function test_helper() {\
/// # >&2 echo "error no 42!"; return 42; }; test_helper"#;
/// assert_cli::assert_cli_output_error("bash", &["-c", BLACK_BOX], Some(42), "error no 42!");
/// ```
pub fn assert_cli_output_error<S>(cmd: &str,
                                  args: &[S],
                                  error_code: Option<i32>,
                                  expected_output: &str)
                                  -> Result<(), Box<Error>>
    where S: AsRef<OsStr>
{
    let call: Result<Output, Box<Error>> = Command::new(cmd)
                                               .args(args)
                                               .output()
                                               .map_err(From::from);

    call.and_then(|output| {
            if output.status.success() {
                return Err(From::from(CliError::WrongExitCode(output)));
            }

            match (error_code, output.status.code()) {
                (Some(a), Some(b)) if a != b =>
                    return Err(From::from(CliError::WrongExitCode(output))),
                _ => {}
            }

            let stdout = String::from_utf8_lossy(&output.stderr);
            let (distance, changes) = difference::diff(expected_output.trim(),
                                                       &stdout.trim(),
                                                       "\n");
            if distance > 0 {
                return Err(From::from(CliError::OutputMissmatch(changes)));
            }

            Ok(())
        })
        .map_err(From::from)
}

/// The `assert_cli!` macro combines the functionality of the other functions in this crate in one
/// short macro.
///
/// ```rust,ignore
/// assert_cli!("echo 42" => Success, "42").unwrap();
/// assert_cli!("exit 11" => Error 11, "").unwrap();
/// ```
///
/// Make sure to include the crate as `#[macro_use] extern crate assert_cli;`.
#[macro_export]
macro_rules! assert_cli {
    ($cmd:expr, $args:expr => Success, $output:expr) => {{
        $crate::assert_cli_output($cmd, $args, $output)
    }};
    ($cmd:expr, $args:expr => Error, $output:expr) => {{
        $crate::assert_cli_output_error($cmd, $args, None, $output)
    }};
    ($cmd:expr, $args:expr => Error $err:expr, $output:expr) => {{
        $crate::assert_cli_output_error($cmd, $args, Some($err), $output)
    }};
}
<commit_msg>feat(tests): Enable Doc Tests for Macros<commit_after>//! # Test CLI Applications
//!
//! Currently, this crate only includes basic functionality to check the output of a child process
//! is as expected.
//!
//! ## Example
//!
//! Here's a trivial example:
//!
//! ```rust
//! # extern crate assert_cli;
//!
//! assert_cli::assert_cli_output("echo", &["42"], "42").unwrap();
//! ```
//!
//! And here is one that will fail:
//!
//! ```rust,should_panic
//! assert_cli::assert_cli_output("echo", &["42"], "1337").unwrap();
//! ```
//!
//! this will show a nice, colorful diff in your terminal, like this:
//!
//! ```diff
//! -1337
//! +42
//! ```
//!
//! Alternatively, you can use the `assert_cli!` macro:
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! assert_cli!("echo", &["42"] => Success, "42").unwrap();
//! # }
//! ```
//!
//! Make sure to include the crate as `#[macro_use] extern crate assert_cli;`.

#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

#![deny(missing_docs)]

extern crate ansi_term;
extern crate difference;

use std::process::{Command, Output};
use std::error::Error;
use std::ffi::OsStr;

mod cli_error;
mod diff;

use cli_error::CliError;

/// Assert a CLI call returns the expected output.
///
/// To test that
///
/// ```sh
/// bash -c $BLACK_BOX
/// ```
///
/// returns
///
/// ```plain
/// Launch sequence initiated.
/// ```
///
/// you would call it like this:
///
/// ```rust
/// # extern crate assert_cli;
/// # const BLACK_BOX: &'static str = r#"function test_helper() {\
/// # echo "Launch sequence initiated."; return 0; }; test_helper"#;
/// assert_cli::assert_cli_output("bash", &["-c", BLACK_BOX], "Launch sequence initiated.");
/// ```
pub fn assert_cli_output<S>(cmd: &str, args: &[S], expected_output: &str) -> Result<(), Box<Error>>
    where S: AsRef<OsStr>
{
    let call: Result<Output, Box<Error>> = Command::new(cmd)
                                               .args(args)
                                               .output()
                                               .map_err(From::from);

    call.and_then(|output| {
            if !output.status.success() {
                return Err(From::from(CliError::WrongExitCode(output)));
            }

            let stdout = String::from_utf8_lossy(&output.stdout);
            let (distance, changes) = difference::diff(expected_output.trim(),
                                                       &stdout.trim(),
                                                       "\n");
            if distance > 0 {
                return Err(From::from(CliError::OutputMissmatch(changes)));
            }

            Ok(())
        })
        .map_err(From::from)
}

/// Assert a CLI call that fails the expected `stderr` output and error code.
///
/// To test that
///
/// ```sh
/// bash -c $BLACK_BOX
/// ```
///
/// fails with an exit code of `42` after printing this to `stderr`
///
/// ```plain
/// error no 42!
/// ```
///
/// you would call it like this:
///
/// ```rust
/// # extern crate assert_cli;
/// # const BLACK_BOX: &'static str = r#"function test_helper() {\
/// # >&2 echo "error no 42!"; return 42; }; test_helper"#;
/// assert_cli::assert_cli_output_error("bash", &["-c", BLACK_BOX], Some(42), "error no 42!");
/// ```
pub fn assert_cli_output_error<S>(cmd: &str,
                                  args: &[S],
                                  error_code: Option<i32>,
                                  expected_output: &str)
                                  -> Result<(), Box<Error>>
    where S: AsRef<OsStr>
{
    let call: Result<Output, Box<Error>> = Command::new(cmd)
                                               .args(args)
                                               .output()
                                               .map_err(From::from);

    call.and_then(|output| {
            if output.status.success() {
                return Err(From::from(CliError::WrongExitCode(output)));
            }

            match (error_code, output.status.code()) {
                (Some(a), Some(b)) if a != b =>
                    return Err(From::from(CliError::WrongExitCode(output))),
                _ => {}
            }

            let stdout = String::from_utf8_lossy(&output.stderr);
            let (distance, changes) = difference::diff(expected_output.trim(),
                                                       &stdout.trim(),
                                                       "\n");
            if distance > 0 {
                return Err(From::from(CliError::OutputMissmatch(changes)));
            }

            Ok(())
        })
        .map_err(From::from)
}

/// The `assert_cli!` macro combines the functionality of the other functions in this crate in one
/// short macro.
///
/// ```rust
/// #[macro_use] extern crate assert_cli;
/// # const BLACK_BOX: &'static str = r#"function test_helper() {\
/// # >&2 echo "error no 66!"; return 66; }; test_helper"#;
///
/// fn main() {
///     assert_cli!("echo", &["42"] => Success, "42").unwrap();
///     assert_cli!("bash", &["-c", BLACK_BOX] => Error 66, "error no 66!").unwrap();
/// }
/// ```
///
/// Make sure to include the crate as `#[macro_use] extern crate assert_cli;`.
#[macro_export]
macro_rules! assert_cli {
    ($cmd:expr, $args:expr => Success, $output:expr) => {{
        $crate::assert_cli_output($cmd, $args, $output)
    }};
    ($cmd:expr, $args:expr => Error, $output:expr) => {{
        $crate::assert_cli_output_error($cmd, $args, None, $output)
    }};
    ($cmd:expr, $args:expr => Error $err:expr, $output:expr) => {{
        $crate::assert_cli_output_error($cmd, $args, Some($err), $output)
    }};
}
<|endoftext|>


<commit_before>extern crate termion;
mod disambiguation_map;
mod mode;
mod mode_map;
mod op;
mod ordered_vec_map;
mod state;
mod typeahead;
<commit_msg>make mode and state public<commit_after>extern crate termion;

mod disambiguation_map;
mod mode_map;
mod op;
mod ordered_vec_map;
mod typeahead;

pub mod mode;
pub mod state;
<|endoftext|>