<commit_before>//! Interrupt description and set-up code.

use VirtualAddress;
use segmentation::{self, SegmentSelector};
use core::fmt;
use bit_field::BitField;

/// An Interrupt Descriptor Table entry.
///
/// See AMD64 Vol 2, Section 4.8.4 for details.
#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct IdtEntry {
    /// Lower 16 bits of ISR pointer.
    pub pointer_low: u16,
    /// Segment selector.
    pub selector: SegmentSelector,
    // Flags and IST index.
    pub options: IdtEntryOptions,
    /// Bits 16-31 of ISR pointer.
    pub pointer_middle: u16,
    /// Bits 32-63 of ISR pointer.
    pub pointer_high: u32,
    /// Must be zero.
    reserved: u32,
}

impl IdtEntry {
    /// A "missing" IdtEntry.
    ///
    /// If the CPU tries to invoke a missing interrupt, it will instead
    /// send a Segment-Not-Present Exception (11), with the segment descriptor as error code.
    pub fn missing() -> IdtEntry {
        IdtEntry {
            selector: SegmentSelector::new(0, ::PrivilegeLevel::Ring0),
            pointer_low: 0,
            pointer_middle: 0,
            pointer_high: 0,
            options: IdtEntryOptions::minimal(),
            reserved: 0,
        }
    }

    /// Create a new IdtEntry pointing at `handler`, which must be a function
    /// with interrupt calling conventions.  (This must be currently defined in
    /// assembly language.)  The `gdt_code_selector` value must be the offset of
    /// code segment entry in the GDT.
    ///
    /// This function sets the "Present" flag, which is the most common case. It also
    /// sets the GDT selector to the currently active code segment. All defaults can
    /// be overwritten through the provided methods.
    pub fn new(handler: VirtualAddress) -> IdtEntry {
        let pointer = handler.as_usize();
        let selector = segmentation::cs();
        let options = IdtEntryOptions::new();

        IdtEntry {
            selector: selector,
            pointer_low: pointer as u16,
            pointer_middle: (pointer >> 16) as u16,
            pointer_high: (pointer >> 32) as u32,
            options: options,
            reserved: 0,
        }
    }
}

/// Describes options of an IDT entry.
#[derive(Debug, Clone, Copy)]
pub struct IdtEntryOptions(u16);

impl IdtEntryOptions {
    /// A minimal set of flags. Only the bits to define a interrupt gate are set.
    fn minimal() -> Self {
        let mut options = 0;
        options.set_range(9..12, 0b111); // 'must-be-one' bits
        IdtEntryOptions(options)
    }

    /// A default set of options that includes the `present` bit and disables interrupts (trap gate).
    fn new() -> Self {
        let mut options = Self::minimal();
        options.set_present(true).disable_interrupts(true);
        options
    }

    /// Update the `present` bit.
    pub fn set_present(&mut self, present: bool) -> &mut Self {
        self.0.set_bit(15, present);
        self
    }

    /// Control if interrupts should be disabled when the handler function is called.
    pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
        self.0.set_bit(8, !disable);
        self
    }

    /// Set the minimal privilege level required to invoke this interrupt.
    #[allow(dead_code)]
    pub fn set_privilege_level(&mut self, dpl: u8) -> &mut Self {
        self.0.set_range(13..15, dpl.into());
        self
    }

    /// Set the IST index. If `None` is passed, the stack switching mechanism is disabled. If
    /// `Some(i)` is passed, the CPU will switch to the i-th stack in the IST of the loaded TSS
    /// (index starts at 0).
    #[allow(dead_code)]
    pub fn set_stack_index(&mut self, index: Option<u8>) -> &mut Self {
        let value = match index {
            Some(i) => (i + 1).into(), // the IST index field starts at index 1
            None => 0,
        };
        self.0.set_range(0..3, value);
        self
    }
}

bitflags!{
    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
    pub flags PageFaultError: u32 {
        /// 0: The fault was caused by a non-present page.
        /// 1: The fault was caused by a page-level protection violation
        const PFAULT_ERROR_P = bit!(0),

        /// 0: The access causing the fault was a read.
        /// 1: The access causing the fault was a write.
        const PFAULT_ERROR_WR = bit!(1),

        /// 0: The access causing the fault originated when the processor
        /// was executing in supervisor mode.
        /// 1: The access causing the fault originated when the processor
        /// was executing in user mode.
        const PFAULT_ERROR_US = bit!(2),

        /// 0: The fault was not caused by reserved bit violation.
        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
        const PFAULT_ERROR_RSVD = bit!(3),

        /// 0: The fault was not caused by an instruction fetch.
        /// 1: The fault was caused by an instruction fetch.
        const PFAULT_ERROR_ID = bit!(4),

        /// 0: The fault was not by protection keys.
        /// 1: There was a protection key violation.
        const PFAULT_ERROR_PK = bit!(5),
    }
}

impl fmt::Display for PageFaultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.contains(PFAULT_ERROR_P) {
            false => "The fault was caused by a non-present page.",
            true => "The fault was caused by a page-level protection violation.",
        };
        let wr = match self.contains(PFAULT_ERROR_WR) {
            false => "The access causing the fault was a read.",
            true => "The access causing the fault was a write.",
        };
        let us = match self.contains(PFAULT_ERROR_US) {
            false => {
                "The access causing the fault originated when the processor was executing in \
                 supervisor mode."
            }
            true => {
                "The access causing the fault originated when the processor was executing in user \
                 mode."
            }
        };
        let rsvd = match self.contains(PFAULT_ERROR_RSVD) {
            false => "The fault was not caused by reserved bit violation.",
            true => "The fault was caused by reserved bits set to 1 in a page directory.",
        };
        let id = match self.contains(PFAULT_ERROR_ID) {
            false => "The fault was not caused by an instruction fetch.",
            true => "The fault was caused by an instruction fetch.",
        };

        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
    }
}

#[test]
fn bit_macro() {
    assert!(PFAULT_ERROR_PK.bits() == 0b100000);
    assert!(PFAULT_ERROR_ID.bits() == 0b10000);
    assert!(PFAULT_ERROR_RSVD.bits() == 0b1000);
    assert!(PFAULT_ERROR_US.bits() == 0b100);
    assert!(PFAULT_ERROR_WR.bits() == 0b10);
    assert!(PFAULT_ERROR_P.bits() == 0b1);
}

/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
#[derive(Debug)]
pub struct InterruptDescription {
    pub vector: u8,
    pub mnemonic: &'static str,
    pub description: &'static str,
    pub irqtype: &'static str,
    pub source: &'static str,
}

impl fmt::Display for InterruptDescription {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{} ({}, vec={}) {}",
               self.mnemonic,
               self.irqtype,
               self.vector,
               self.description)
    }
}

/// x86 External Interrupts (1-16).
pub static EXCEPTIONS: [InterruptDescription; 21] =
    [InterruptDescription {
         vector: 0,
         mnemonic: "#DE",
         description: "Divide Error",
         irqtype: "Fault",
         source: "DIV and IDIV instructions.",
     },
     InterruptDescription {
         vector: 1,
         mnemonic: "#DB",
         description: "Debug",
         irqtype: "Fault/ Trap",
         source: "Debug condition",
     },
     InterruptDescription {
         vector: 2,
         mnemonic: "NMI",
         description: "Nonmaskable Interrupt",
         irqtype: "Interrupt",
         source: "Nonmaskable external interrupt.",
     },
     InterruptDescription {
         vector: 3,
         mnemonic: "#BP",
         description: "Breakpoint",
         irqtype: "Trap",
         source: "INT 3 instruction.",
     },
     InterruptDescription {
         vector: 4,
         mnemonic: "#OF",
         description: "Overflow",
         irqtype: "Trap",
         source: "INTO instruction.",
     },
     InterruptDescription {
         vector: 5,
         mnemonic: "#BR",
         description: "BOUND Range Exceeded",
         irqtype: "Fault",
         source: "BOUND instruction.",
     },
     InterruptDescription {
         vector: 6,
         mnemonic: "#UD",
         description: "Invalid Opcode (Undefined Opcode)",
         irqtype: "Fault",
         source: "UD2 instruction or reserved opcode.",
     },
     InterruptDescription {
         vector: 7,
         mnemonic: "#NM",
         description: "Device Not Available (No Math Coprocessor)",
         irqtype: "Fault",
         source: "Floating-point or WAIT/FWAIT instruction.",
     },
     InterruptDescription {
         vector: 8,
         mnemonic: "#DF",
         description: "Double Fault",
         irqtype: "Abort",
         source: "Any instruction that can generate an exception, an NMI, or an INTR.",
     },
     InterruptDescription {
         vector: 9,
         mnemonic: "",
         description: "Coprocessor Segment Overrun",
         irqtype: "Fault",
         source: "Floating-point instruction.",
     },
     InterruptDescription {
         vector: 10,
         mnemonic: "#TS",
         description: "Invalid TSS",
         irqtype: "Fault",
         source: "Task switch or TSS access.",
     },
     InterruptDescription {
         vector: 11,
         mnemonic: "#NP",
         description: "Segment Not Present",
         irqtype: "Fault",
         source: "Loading segment registers or accessing system segments.",
     },
     InterruptDescription {
         vector: 12,
         mnemonic: "#SS",
         description: "Stack-Segment Fault",
         irqtype: "Fault",
         source: "Stack operations and SS register loads.",
     },
     InterruptDescription {
         vector: 13,
         mnemonic: "#GP",
         description: "General Protection",
         irqtype: "Fault",
         source: "Any memory reference and other protection checks.",
     },
     InterruptDescription {
         vector: 14,
         mnemonic: "#PF",
         description: "Page Fault",
         irqtype: "Fault",
         source: "Any memory reference.",
     },
     InterruptDescription {
         vector: 15,
         mnemonic: "",
         description: "RESERVED",
         irqtype: "",
         source: "None.",
     },
     InterruptDescription {
         vector: 16,
         mnemonic: "#MF",
         description: "x87 FPU Floating-Point",
         irqtype: "Fault",
         source: "x87 FPU instructions.",
     },
     InterruptDescription {
         vector: 17,
         mnemonic: "#AC",
         description: "Alignment Check",
         irqtype: "Fault",
         source: "Unaligned memory access.",
     },
     InterruptDescription {
         vector: 18,
         mnemonic: "#MC",
         description: "Machine Check",
         irqtype: "Abort",
         source: "Internal machine error.",
     },
     InterruptDescription {
         vector: 19,
         mnemonic: "#XM",
         description: "SIMD Floating-Point",
         irqtype: "Fault",
         source: "SSE SIMD instructions.",
     },
     InterruptDescription {
         vector: 20,
         mnemonic: "#VE",
         description: "Virtualization",
         irqtype: "Fault",
         source: "EPT violation.",
     }];

/// Enable Interrupts.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro because the argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ( $x:expr ) => {
        {
            asm!("int $0" :: "N" ($x));
        }
    };
}
<commit_msg>Fix doc comment for IdtEntry. (#4)<commit_after>//! Interrupt description and set-up code.

use VirtualAddress;
use segmentation::{self, SegmentSelector};
use core::fmt;
use bit_field::BitField;

/// An Interrupt Descriptor Table entry.
///
/// See AMD64 Vol 2, Section 4.8.4 for details.
#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct IdtEntry {
    /// Lower 16 bits of ISR pointer.
    pub pointer_low: u16,
    /// Segment selector.
    pub selector: SegmentSelector,
    // Flags and IST index.
    pub options: IdtEntryOptions,
    /// Bits 16-31 of ISR pointer.
    pub pointer_middle: u16,
    /// Bits 32-63 of ISR pointer.
    pub pointer_high: u32,
    /// Must be zero.
    reserved: u32,
}

impl IdtEntry {
    /// A "missing" IdtEntry.
    ///
    /// If the CPU tries to invoke a missing interrupt, it will instead
    /// send a Segment-Not-Present Exception (11), with the segment descriptor as error code.
    pub fn missing() -> IdtEntry {
        IdtEntry {
            selector: SegmentSelector::new(0, ::PrivilegeLevel::Ring0),
            pointer_low: 0,
            pointer_middle: 0,
            pointer_high: 0,
            options: IdtEntryOptions::minimal(),
            reserved: 0,
        }
    }

    /// Create a new IdtEntry pointing at `handler`, which must be a function
    /// with interrupt calling conventions.  (This must be currently defined in
    /// assembly language.)
    ///
    /// This function sets the "Present" flag, which is the most common case. It also
    /// sets the GDT selector to the currently active code segment. All defaults can
    /// be overwritten through the provided methods.
    pub fn new(handler: VirtualAddress) -> IdtEntry {
        let pointer = handler.as_usize();
        let selector = segmentation::cs();
        let options = IdtEntryOptions::new();

        IdtEntry {
            selector: selector,
            pointer_low: pointer as u16,
            pointer_middle: (pointer >> 16) as u16,
            pointer_high: (pointer >> 32) as u32,
            options: options,
            reserved: 0,
        }
    }
}

/// Describes options of an IDT entry.
#[derive(Debug, Clone, Copy)]
pub struct IdtEntryOptions(u16);

impl IdtEntryOptions {
    /// A minimal set of flags. Only the bits to define a interrupt gate are set.
    fn minimal() -> Self {
        let mut options = 0;
        options.set_range(9..12, 0b111); // 'must-be-one' bits
        IdtEntryOptions(options)
    }

    /// A default set of options that includes the `present` bit and disables interrupts (trap gate).
    fn new() -> Self {
        let mut options = Self::minimal();
        options.set_present(true).disable_interrupts(true);
        options
    }

    /// Update the `present` bit.
    pub fn set_present(&mut self, present: bool) -> &mut Self {
        self.0.set_bit(15, present);
        self
    }

    /// Control if interrupts should be disabled when the handler function is called.
    pub fn disable_interrupts(&mut self, disable: bool) -> &mut Self {
        self.0.set_bit(8, !disable);
        self
    }

    /// Set the minimal privilege level required to invoke this interrupt.
    #[allow(dead_code)]
    pub fn set_privilege_level(&mut self, dpl: u8) -> &mut Self {
        self.0.set_range(13..15, dpl.into());
        self
    }

    /// Set the IST index. If `None` is passed, the stack switching mechanism is disabled. If
    /// `Some(i)` is passed, the CPU will switch to the i-th stack in the IST of the loaded TSS
    /// (index starts at 0).
    #[allow(dead_code)]
    pub fn set_stack_index(&mut self, index: Option<u8>) -> &mut Self {
        let value = match index {
            Some(i) => (i + 1).into(), // the IST index field starts at index 1
            None => 0,
        };
        self.0.set_range(0..3, value);
        self
    }
}

bitflags!{
    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
    pub flags PageFaultError: u32 {
        /// 0: The fault was caused by a non-present page.
        /// 1: The fault was caused by a page-level protection violation
        const PFAULT_ERROR_P = bit!(0),

        /// 0: The access causing the fault was a read.
        /// 1: The access causing the fault was a write.
        const PFAULT_ERROR_WR = bit!(1),

        /// 0: The access causing the fault originated when the processor
        /// was executing in supervisor mode.
        /// 1: The access causing the fault originated when the processor
        /// was executing in user mode.
        const PFAULT_ERROR_US = bit!(2),

        /// 0: The fault was not caused by reserved bit violation.
        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
        const PFAULT_ERROR_RSVD = bit!(3),

        /// 0: The fault was not caused by an instruction fetch.
        /// 1: The fault was caused by an instruction fetch.
        const PFAULT_ERROR_ID = bit!(4),

        /// 0: The fault was not by protection keys.
        /// 1: There was a protection key violation.
        const PFAULT_ERROR_PK = bit!(5),
    }
}

impl fmt::Display for PageFaultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.contains(PFAULT_ERROR_P) {
            false => "The fault was caused by a non-present page.",
            true => "The fault was caused by a page-level protection violation.",
        };
        let wr = match self.contains(PFAULT_ERROR_WR) {
            false => "The access causing the fault was a read.",
            true => "The access causing the fault was a write.",
        };
        let us = match self.contains(PFAULT_ERROR_US) {
            false => {
                "The access causing the fault originated when the processor was executing in \
                 supervisor mode."
            }
            true => {
                "The access causing the fault originated when the processor was executing in user \
                 mode."
            }
        };
        let rsvd = match self.contains(PFAULT_ERROR_RSVD) {
            false => "The fault was not caused by reserved bit violation.",
            true => "The fault was caused by reserved bits set to 1 in a page directory.",
        };
        let id = match self.contains(PFAULT_ERROR_ID) {
            false => "The fault was not caused by an instruction fetch.",
            true => "The fault was caused by an instruction fetch.",
        };

        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
    }
}

#[test]
fn bit_macro() {
    assert!(PFAULT_ERROR_PK.bits() == 0b100000);
    assert!(PFAULT_ERROR_ID.bits() == 0b10000);
    assert!(PFAULT_ERROR_RSVD.bits() == 0b1000);
    assert!(PFAULT_ERROR_US.bits() == 0b100);
    assert!(PFAULT_ERROR_WR.bits() == 0b10);
    assert!(PFAULT_ERROR_P.bits() == 0b1);
}

/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
#[derive(Debug)]
pub struct InterruptDescription {
    pub vector: u8,
    pub mnemonic: &'static str,
    pub description: &'static str,
    pub irqtype: &'static str,
    pub source: &'static str,
}

impl fmt::Display for InterruptDescription {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{} ({}, vec={}) {}",
               self.mnemonic,
               self.irqtype,
               self.vector,
               self.description)
    }
}

/// x86 External Interrupts (1-16).
pub static EXCEPTIONS: [InterruptDescription; 21] =
    [InterruptDescription {
         vector: 0,
         mnemonic: "#DE",
         description: "Divide Error",
         irqtype: "Fault",
         source: "DIV and IDIV instructions.",
     },
     InterruptDescription {
         vector: 1,
         mnemonic: "#DB",
         description: "Debug",
         irqtype: "Fault/ Trap",
         source: "Debug condition",
     },
     InterruptDescription {
         vector: 2,
         mnemonic: "NMI",
         description: "Nonmaskable Interrupt",
         irqtype: "Interrupt",
         source: "Nonmaskable external interrupt.",
     },
     InterruptDescription {
         vector: 3,
         mnemonic: "#BP",
         description: "Breakpoint",
         irqtype: "Trap",
         source: "INT 3 instruction.",
     },
     InterruptDescription {
         vector: 4,
         mnemonic: "#OF",
         description: "Overflow",
         irqtype: "Trap",
         source: "INTO instruction.",
     },
     InterruptDescription {
         vector: 5,
         mnemonic: "#BR",
         description: "BOUND Range Exceeded",
         irqtype: "Fault",
         source: "BOUND instruction.",
     },
     InterruptDescription {
         vector: 6,
         mnemonic: "#UD",
         description: "Invalid Opcode (Undefined Opcode)",
         irqtype: "Fault",
         source: "UD2 instruction or reserved opcode.",
     },
     InterruptDescription {
         vector: 7,
         mnemonic: "#NM",
         description: "Device Not Available (No Math Coprocessor)",
         irqtype: "Fault",
         source: "Floating-point or WAIT/FWAIT instruction.",
     },
     InterruptDescription {
         vector: 8,
         mnemonic: "#DF",
         description: "Double Fault",
         irqtype: "Abort",
         source: "Any instruction that can generate an exception, an NMI, or an INTR.",
     },
     InterruptDescription {
         vector: 9,
         mnemonic: "",
         description: "Coprocessor Segment Overrun",
         irqtype: "Fault",
         source: "Floating-point instruction.",
     },
     InterruptDescription {
         vector: 10,
         mnemonic: "#TS",
         description: "Invalid TSS",
         irqtype: "Fault",
         source: "Task switch or TSS access.",
     },
     InterruptDescription {
         vector: 11,
         mnemonic: "#NP",
         description: "Segment Not Present",
         irqtype: "Fault",
         source: "Loading segment registers or accessing system segments.",
     },
     InterruptDescription {
         vector: 12,
         mnemonic: "#SS",
         description: "Stack-Segment Fault",
         irqtype: "Fault",
         source: "Stack operations and SS register loads.",
     },
     InterruptDescription {
         vector: 13,
         mnemonic: "#GP",
         description: "General Protection",
         irqtype: "Fault",
         source: "Any memory reference and other protection checks.",
     },
     InterruptDescription {
         vector: 14,
         mnemonic: "#PF",
         description: "Page Fault",
         irqtype: "Fault",
         source: "Any memory reference.",
     },
     InterruptDescription {
         vector: 15,
         mnemonic: "",
         description: "RESERVED",
         irqtype: "",
         source: "None.",
     },
     InterruptDescription {
         vector: 16,
         mnemonic: "#MF",
         description: "x87 FPU Floating-Point",
         irqtype: "Fault",
         source: "x87 FPU instructions.",
     },
     InterruptDescription {
         vector: 17,
         mnemonic: "#AC",
         description: "Alignment Check",
         irqtype: "Fault",
         source: "Unaligned memory access.",
     },
     InterruptDescription {
         vector: 18,
         mnemonic: "#MC",
         description: "Machine Check",
         irqtype: "Abort",
         source: "Internal machine error.",
     },
     InterruptDescription {
         vector: 19,
         mnemonic: "#XM",
         description: "SIMD Floating-Point",
         irqtype: "Fault",
         source: "SSE SIMD instructions.",
     },
     InterruptDescription {
         vector: 20,
         mnemonic: "#VE",
         description: "Virtualization",
         irqtype: "Fault",
         source: "EPT violation.",
     }];

/// Enable Interrupts.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro because the argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ( $x:expr ) => {
        {
            asm!("int $0" :: "N" ($x));
        }
    };
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(slicing_syntax)]

extern crate "rust-md2" as md2;

use md2::{SBOX, SBOXI};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::range_inclusive;
use std::slice::bytes::{copy_memory, MutableByteVector};

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

struct ByteRange {
  v: Vec<u8>
}

impl ByteRange {
  fn new(n: uint) -> ByteRange {
    ByteRange { v: Vec::from_elem(n, 0u8) }
  }
}

impl Iterator<Vec<u8>> for ByteRange {
  fn next(&mut self) -> Option<Vec<u8>> {
    for i in range(0, self.v.len()).rev() {
      if self.v[i] == 255 {
        continue;
      }

      // Increase.
      self.v[i] += 1;

      // Zero all bytes right of the current index.
      self.v[mut i+1..].set_memory(0);

      return Some(self.v.clone());
    }

    None
  }
}

fn find_collisions(state: [[u8, ..49], ..19], k: uint) -> Collisions {
  let rows = 16 - k;
  let mut state = state;
  let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

  for bytes in ByteRange::new(k) {
    copy_memory(state[rows][mut 17..17+k], bytes[]);
    copy_memory(state[rows][mut 17+16..17+k+16], bytes[]);

    for row in range(rows + 1, 18) {
      // Fill row.
      for i in range(1, 49) {
        state[row][i] = SBOX[state[row][i - 1] as uint] ^ state[row - 1][i];
      }

      // Next t value.
      state[row + 1][0] = state[row][48] + (row as u8) - 1;
    }

    let key = Vec::from_fn(17 - rows, |row| state[rows + 2 + row][0]);

    match collisions.entry(key) {
      Vacant(entry) => { entry.set(vec!(bytes)); },
      Occupied(mut entry) => { entry.get_mut().push(bytes); }
    };
  }

  // Compute original messages for each collision.
  collisions.values().filter(|x| x.len() > 1).map(|collision| {
    collision.iter().map(|bytes| {
      copy_memory(state[rows][mut 17..17+k], bytes[]);
      copy_memory(state[rows][mut 17+16..17+k+16], bytes[]);

      // Fill upper rectangles.
      for row in range_inclusive(1, rows).rev() {
        for col in range(17, 32 - row + 2) {
          state[row - 1][col] = SBOX[state[row][col - 1] as uint] ^ state[row][col];
        }
      }

      state[0][17..33].to_vec()
    }).collect()
  }).collect()
}

fn create_initial_state(k: uint) -> [[u8, ..49], ..19] {
  let rows = 16 - k;
  let mut state = [[0u8, ..49], ..19];

  for row in range_inclusive(1, rows) {
    // Fill row of T1.
    for i in range(1, 17) {
      state[row][i] = SBOX[state[row][i - 1] as uint] ^ state[row - 1][i];
    }

    // Last bytes are equal.
    state[row][32] = state[row][16];
    state[row][48] = state[row][16];

    // Next t value.
    state[row + 1][0] = state[row][48] + (row as u8) - 1;
  }

  // Compute triangles.
  for col in range(0, rows) {
    for row in range_inclusive(2 + col, rows).rev() {
      state[row][32 - col - 1] = SBOXI[(state[row][32 - col] ^ state[row - 1][32 - col]) as uint];
      state[row][48 - col - 1] = SBOXI[(state[row][48 - col] ^ state[row - 1][48 - col]) as uint];
    }
  }

  state
}

pub fn find(k: uint) -> Vec<Vec<Vec<u8>>> {
  find_collisions(create_initial_state(k), k)
}

#[cfg(test)]
mod test {
  use find;
  use Collision;
  use md2::compress;

  fn check_collision(collision: &Collision) -> bool {
    let empty = [0u8, ..16];
    let mut first_hash: Option<[u8, ..16]> = None;
    let hashes = collision.iter().map(|msg| compress(&empty, msg[]));

    hashes.all(|md2| {
      first_hash.map_or_else(|| { first_hash = Some(md2); true }, |v| v == md2)
    })
  }

  #[test]
  fn test_k2() {
    let collisions = find(2);
    assert!(collisions.iter().all(check_collision));
    assert_eq!(collisions.iter().count(), 141);
  }

  #[test]
  fn test_k3() {
    let collisions = find(3);
    assert!(collisions.iter().all(check_collision));
    assert_eq!(collisions.iter().count(), 32784);
  }
}
<commit_msg>fix expected collision numbers in tests<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(slicing_syntax)]

extern crate "rust-md2" as md2;

use md2::{SBOX, SBOXI};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::range_inclusive;
use std::slice::bytes::{copy_memory, MutableByteVector};

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

struct ByteRange {
  v: Vec<u8>
}

impl ByteRange {
  fn new(n: uint) -> ByteRange {
    ByteRange { v: Vec::from_elem(n, 0u8) }
  }
}

impl Iterator<Vec<u8>> for ByteRange {
  fn next(&mut self) -> Option<Vec<u8>> {
    for i in range(0, self.v.len()).rev() {
      if self.v[i] == 255 {
        continue;
      }

      // Increase.
      self.v[i] += 1;

      // Zero all bytes right of the current index.
      self.v[mut i+1..].set_memory(0);

      return Some(self.v.clone());
    }

    None
  }
}

fn find_collisions(state: [[u8, ..49], ..19], k: uint) -> Collisions {
  let rows = 16 - k;
  let mut state = state;
  let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

  for bytes in ByteRange::new(k) {
    copy_memory(state[rows][mut 17..17+k], bytes[]);
    copy_memory(state[rows][mut 17+16..17+k+16], bytes[]);

    for row in range(rows + 1, 18) {
      // Fill row.
      for i in range(1, 49) {
        state[row][i] = SBOX[state[row][i - 1] as uint] ^ state[row - 1][i];
      }

      // Next t value.
      state[row + 1][0] = state[row][48] + (row as u8) - 1;
    }

    let key = Vec::from_fn(17 - rows, |row| state[rows + 2 + row][0]);

    match collisions.entry(key) {
      Vacant(entry) => { entry.set(vec!(bytes)); },
      Occupied(mut entry) => { entry.get_mut().push(bytes); }
    };
  }

  // Compute original messages for each collision.
  collisions.values().filter(|x| x.len() > 1).map(|collision| {
    collision.iter().map(|bytes| {
      copy_memory(state[rows][mut 17..17+k], bytes[]);
      copy_memory(state[rows][mut 17+16..17+k+16], bytes[]);

      // Fill upper rectangles.
      for row in range_inclusive(1, rows).rev() {
        for col in range(17, 32 - row + 2) {
          state[row - 1][col] = SBOX[state[row][col - 1] as uint] ^ state[row][col];
        }
      }

      state[0][17..33].to_vec()
    }).collect()
  }).collect()
}

fn create_initial_state(k: uint) -> [[u8, ..49], ..19] {
  let rows = 16 - k;
  let mut state = [[0u8, ..49], ..19];

  for row in range_inclusive(1, rows) {
    // Fill row of T1.
    for i in range(1, 17) {
      state[row][i] = SBOX[state[row][i - 1] as uint] ^ state[row - 1][i];
    }

    // Last bytes are equal.
    state[row][32] = state[row][16];
    state[row][48] = state[row][16];

    // Next t value.
    state[row + 1][0] = state[row][48] + (row as u8) - 1;
  }

  // Compute triangles.
  for col in range(0, rows) {
    for row in range_inclusive(2 + col, rows).rev() {
      state[row][32 - col - 1] = SBOXI[(state[row][32 - col] ^ state[row - 1][32 - col]) as uint];
      state[row][48 - col - 1] = SBOXI[(state[row][48 - col] ^ state[row - 1][48 - col]) as uint];
    }
  }

  state
}

pub fn find(k: uint) -> Vec<Vec<Vec<u8>>> {
  find_collisions(create_initial_state(k), k)
}

#[cfg(test)]
mod test {
  use find;
  use md2::compress;

  fn check_collision(collision: &Vec<Vec<u8>>) -> bool {
    let empty = [0u8, ..16];
    let mut first_hash: Option<[u8, ..16]> = None;
    let hashes = collision.iter().map(|msg| compress(&empty, msg[]));

    hashes.all(|md2| {
      first_hash.map_or_else(|| { first_hash = Some(md2); true }, |v| v == md2)
    })
  }

  fn check_collisions(k: uint, num: uint, num_total: uint) {
    let collisions = find(k);
    assert!(collisions.iter().all(check_collision));
    assert_eq!(collisions.iter().count(), num);
    assert_eq!(collisions.iter().fold(0u, |acc, coll| acc + coll.len() - 1), num_total);
  }

  #[test]
  fn test() {
    check_collisions(2, 141, 141);
    check_collisions(3, 32744, 32784);
  }
}
<|endoftext|>


<commit_before>
#[cfg(test)]
#[macro_use]
extern crate lazy_static;

use std::ptr;
use std::mem;
use std::cmp::{Ord, Ordering};

pub trait MapInPlace<A, B>: Sized {
    /// Should be of the same base type as the implementor.
    /// E.g. `Vec<B>` when implementing for `Vec<A>`
    type Output;

    /// Apply a mapping function to `self` without allocating.
    /// Makes best effort to maintain the invariant
    ///
    /// `self.as_ptr() as *const () == self.map_in_place(..).as_ptr() as *const ()`
    ///
    /// An example of a case where this isn't possible is for Vec where B is zero-sized but A is not.
    fn map_in_place<F>(self, f: F) -> Self::Output where F: FnMut(A) -> B;
}

unsafe fn map_in_place<A, B, F>(ptr_a: *const A, ptr_b: *mut B, len: usize, mut f: F)
    where F: FnMut(A) -> B
{
    for i in 0..len {
        let ptr_a = ptr_a.offset(i as isize);
        let ptr_b = ptr_b.offset(i as isize);

        ptr::write(ptr_b, f(ptr::read(ptr_a)));
    }
}

impl<A, B> MapInPlace<A, B> for Vec<A> {
    type Output = Vec<B>;

    #[inline]
    fn map_in_place<F>(mut self, mut f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                // map_loop!();
                self.as_mut_slice().map_in_place(f);

                unsafe { mem::transmute(self) }
            }
            Ordering::Greater => {
                if b_size == 0 {
                    // doesn't preserve address invariant
                    let mut v = Vec::with_capacity(0);

                    for e in self.into_iter() {
                        v.push(f(e));
                    }

                    v
                } else {
                    let cap = self.capacity().checked_mul(a_size).map(|x| x / b_size).unwrap();
                    let ptr_a = self.as_ptr();
                    let ptr_b = ptr_a as *mut B;
                    let len = self.len();

                    unsafe {
                        map_in_place(ptr_a, ptr_b, len, f);
                        mem::forget(self);
                        Vec::from_raw_parts(ptr_b, len, cap)
                    }
                }
            }
            Ordering::Less => {
                panic!("map_in_place(Vec<A>): Size of A must be greater than or equal to size of B")
            }
        }
    }
}

impl<'a, A, B: 'a> MapInPlace<A, B> for &'a mut [A] {
    type Output = &'a mut [B];

    #[inline]
    fn map_in_place<F>(self, f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                let ptr_a = self.as_ptr();
                let ptr_b = ptr_a as *mut B;

                unsafe {
                    map_in_place(ptr_a, ptr_b, self.len(), f);
                    mem::transmute(self)
                }
            }
            _ => panic!("map_in_place(&mut [A]): Size of A must be equal to size of B"),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::MapInPlace;

    use std::mem;
    use std::sync::Mutex;

    #[test]
    fn vec_elements_drop() {
        lazy_static! {
            static ref DROPS: Mutex<Vec<String>> = Mutex::new(vec![]);
        }

        #[derive(Debug, PartialEq, Clone)]
        struct X(usize);

        impl Drop for X {
            fn drop(&mut self) {
                DROPS.lock().unwrap().push(format!("X({})", self.0));
            }
        }

        #[derive(Debug, PartialEq, Clone)]
        struct Y(usize);

        impl Drop for Y {
            fn drop(&mut self) {
                DROPS.lock().unwrap().push(format!("Y({})", self.0));
            }
        }

        assert_eq!(mem::size_of::<X>(), mem::size_of::<Y>()); // will use slice impl

        let v = vec![X(0), X(1), X(2), X(3)];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|X(v)| Y(v));

        {
            let drops = DROPS.lock().unwrap().clone();
            assert_eq!(drops, vec!["X(0)", "X(1)", "X(2)", "X(3)"]);
        }

        let ap = v.as_ptr() as *const ();
        let expected = vec![Y(0), Y(1), Y(2), Y(3)];

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, expected);

        mem::drop(v);

        {
            let drops = DROPS.lock().unwrap().clone();
            assert_eq!(drops,
                       vec!["X(0)", "X(1)", "X(2)", "X(3)", "Y(0)", "Y(1)", "Y(2)", "Y(3)"]);
        }

        mem::drop(expected);
    }

    #[test]
    fn same_size_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn different_sizes_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_vec() {
        #[derive(Debug)]
        struct Zst;

        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    fn nzst_to_zst_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_vec() {
        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    // //////

    #[test]
    fn same_size_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    #[should_panic]
    fn different_sizes_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_slice() {
        #[derive(Debug)]
        struct Zst;

        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    #[should_panic]
    fn nzst_to_zst_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_slice() {
        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }
}
<commit_msg>Assert for capacity divisibility constraint<commit_after>
#[cfg(test)]
#[macro_use]
extern crate lazy_static;

use std::ptr;
use std::mem;
use std::cmp::{Ord, Ordering};

pub trait MapInPlace<A, B>: Sized {
    /// Should be of the same base type as the implementor.
    /// E.g. `Vec<B>` when implementing for `Vec<A>`
    type Output;

    /// Apply a mapping function to `self` without allocating.
    /// Makes best effort to maintain the invariant
    ///
    /// `self.as_ptr() as *const () == self.map_in_place(..).as_ptr() as *const ()`
    ///
    /// An example of a case where this isn't possible is for Vec where B is zero-sized but A is not.
    fn map_in_place<F>(self, f: F) -> Self::Output where F: FnMut(A) -> B;
}

unsafe fn map_in_place<A, B, F>(ptr_a: *const A, ptr_b: *mut B, len: usize, mut f: F)
    where F: FnMut(A) -> B
{
    for i in 0..len {
        let ptr_a = ptr_a.offset(i as isize);
        let ptr_b = ptr_b.offset(i as isize);

        ptr::write(ptr_b, f(ptr::read(ptr_a)));
    }
}

impl<A, B> MapInPlace<A, B> for Vec<A> {
    type Output = Vec<B>;

    #[inline]
    fn map_in_place<F>(mut self, mut f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                self.as_mut_slice().map_in_place(f);

                unsafe { mem::transmute(self) }
            }
            Ordering::Greater => {
                if b_size == 0 {
                    // doesn't preserve address invariant
                    let mut v = Vec::with_capacity(0);

                    for e in self.into_iter() {
                        v.push(f(e));
                    }

                    v
                } else {
                    // nA * bytes/A = nbytes
                    // nbytes / bytes/B = nbytes * B/bytes = nB
                    // (assuming bytes/B divides evenly into nbytes)
                    let cap = {
                        let tmp = self.capacity().checked_mul(a_size).unwrap();
                        // TODO: don't require the divisibility constraint
                        assert_eq!(tmp % b_size, 0);
                        tmp / b_size
                    };
                    let ptr_a = self.as_ptr();
                    let ptr_b = ptr_a as *mut B;
                    let len = self.len();

                    unsafe {
                        map_in_place(ptr_a, ptr_b, len, f);
                        mem::forget(self);
                        Vec::from_raw_parts(ptr_b, len, cap)
                    }
                }
            }
            Ordering::Less => {
                panic!("map_in_place(Vec<A>): Size of A must be greater than or equal to size of B")
            }
        }
    }
}

impl<'a, A, B: 'a> MapInPlace<A, B> for &'a mut [A] {
    type Output = &'a mut [B];

    #[inline]
    fn map_in_place<F>(self, f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                let ptr_a = self.as_ptr();
                let ptr_b = ptr_a as *mut B;

                unsafe {
                    map_in_place(ptr_a, ptr_b, self.len(), f);
                    mem::transmute(self)
                }
            }
            _ => panic!("map_in_place(&mut [A]): Size of A must be equal to size of B"),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::MapInPlace;

    use std::mem;
    use std::sync::Mutex;

    #[test]
    fn vec_elements_drop() {
        lazy_static! {
            static ref DROPS: Mutex<Vec<String>> = Mutex::new(vec![]);
        }

        #[derive(Debug, PartialEq, Clone)]
        struct X(usize);

        impl Drop for X {
            fn drop(&mut self) {
                DROPS.lock().unwrap().push(format!("X({})", self.0));
            }
        }

        #[derive(Debug, PartialEq, Clone)]
        struct Y(usize);

        impl Drop for Y {
            fn drop(&mut self) {
                DROPS.lock().unwrap().push(format!("Y({})", self.0));
            }
        }

        assert_eq!(mem::size_of::<X>(), mem::size_of::<Y>()); // will use slice impl

        let v = vec![X(0), X(1), X(2), X(3)];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|X(v)| Y(v));

        {
            let drops = DROPS.lock().unwrap().clone();
            assert_eq!(drops, vec!["X(0)", "X(1)", "X(2)", "X(3)"]);
        }

        let ap = v.as_ptr() as *const ();
        let expected = vec![Y(0), Y(1), Y(2), Y(3)];

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, expected);

        mem::drop(v);

        {
            let drops = DROPS.lock().unwrap().clone();
            assert_eq!(drops,
                       vec!["X(0)", "X(1)", "X(2)", "X(3)", "Y(0)", "Y(1)", "Y(2)", "Y(3)"]);
        }

        mem::drop(expected);
    }

    #[test]
    fn same_size_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn different_sizes_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_vec() {
        #[derive(Debug)]
        struct Zst;

        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    fn nzst_to_zst_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_vec() {
        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    // //////

    #[test]
    fn same_size_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    #[should_panic]
    fn different_sizes_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_slice() {
        #[derive(Debug)]
        struct Zst;

        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    #[should_panic]
    fn nzst_to_zst_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_slice() {
        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }
}
<|endoftext|>


<commit_before>#![crate_name = "graphics"]
#![deny(missing_docs)]
#![feature(default_type_params)]
#![feature(globs)]
#![feature(if_let)]

//! A library for 2D graphics that works with multiple back-ends.

extern crate "vecmath" as vecmath_lib;
extern crate texture;
extern crate read_color;
extern crate current;

pub use texture::ImageSize;

pub use back_end::BackEnd;
pub use relative::{
    RelativeColor,
    RelativeRectangle,
    RelativeSourceRectangle,
    RelativeTransform,
    RelativeViewTransform,
};
pub use rectangle::Rectangle;
pub use line::Line;
pub use ellipse::Ellipse;
pub use image::Image;
pub use polygon::Polygon;

pub use context::Context as Context;

use current::{ Get, Set };

/// Any triangulation method called on the back-end
/// never exceeds this number of vertices.
/// This can be used to initialize buffers that fit the chunk size.
pub static BACK_END_MAX_VERTEX_COUNT: uint = 1024;

mod back_end;
mod relative;

pub mod context;
pub mod color;
pub mod polygon;
pub mod line;
pub mod ellipse;
pub mod rectangle;
pub mod image;
pub mod internal;
pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;
pub mod deform;
pub mod grid;
pub mod radians;

/// A color property
pub struct Color(pub internal::Color);

/// Wrapper trait for `Get<Color>`
pub trait GetColor: Get<Color> {
    /// Get color
    #[inline(always)]
    fn get_color(&self) -> Color {
        self.get()
    }
}

impl<T: Get<Color>> GetColor for T {}

/// Wrapper trait for `Set<Color>`
pub trait SetColor: Set<Color> {
    /// Set color
    #[inline(always)]
    fn set_color(&mut self, val: Color) {
        self.set_mut(val);
    }
}

impl<T: Set<Color>> SetColor for T {}

/// A rectangle property
pub struct Rect(pub internal::Rectangle);

/// Wrapper trait for `Get<Rect>`
pub trait GetRect: Get<Rect> {
    /// Get rectangle
    #[inline(always)]
    fn get_rect(&self) -> Rect {
        self.get()
    }
}

impl<T: Get<Rect>> GetRect for T {}

/// Wrapper trait for `Set<Rect>`
pub trait SetRect: Set<Rect> {
    /// Set rectangle
    #[inline(always)]
    fn set_rect(&mut self, val: Rect) {
        self.set_mut(val);
    }
}

impl<T: Set<Rect>> SetRect for T {}

/// A source rectangle property
pub struct SrcRect(pub internal::SourceRectangle);

/// Wrapper trait for `Get<SrcRect>`
pub trait GetSrcRect: Get<SrcRect> {
    /// Get source rectangle
    #[inline(always)]
    fn get_src_rect(&self) -> SrcRect {
        self.get()
    }
}

impl<T: Get<SrcRect>> GetSrcRect for T {}

/// Wrapper trait for `Set<SrcRect>`
pub trait SetSrcRect: Set<SrcRect> {
    /// Set source rectangle
    #[inline(always)]
    fn set_src_rect(&mut self, val: SrcRect) {
        self.set_mut(val);
    }
}

impl<T: Set<SrcRect>> SetSrcRect for T {}

/// Clears the screen.
pub fn clear<B: BackEnd<I>, I: ImageSize>(
    color: internal::Color, back_end: &mut B
) {
    back_end.clear(color);
}

<commit_msg>Added `image` function at top level<commit_after>#![crate_name = "graphics"]
#![deny(missing_docs)]
#![feature(default_type_params)]
#![feature(globs)]
#![feature(if_let)]

//! A library for 2D graphics that works with multiple back-ends.

extern crate "vecmath" as vecmath_lib;
extern crate texture;
extern crate read_color;
extern crate current;

pub use texture::ImageSize;

pub use back_end::BackEnd;
pub use relative::{
    RelativeColor,
    RelativeRectangle,
    RelativeSourceRectangle,
    RelativeTransform,
    RelativeViewTransform,
};
pub use rectangle::Rectangle;
pub use line::Line;
pub use ellipse::Ellipse;
pub use image::Image;
pub use polygon::Polygon;

pub use context::Context as Context;

use current::{ Get, Set };

/// Any triangulation method called on the back-end
/// never exceeds this number of vertices.
/// This can be used to initialize buffers that fit the chunk size.
pub static BACK_END_MAX_VERTEX_COUNT: uint = 1024;

mod back_end;
mod relative;

pub mod context;
pub mod color;
pub mod polygon;
pub mod line;
pub mod ellipse;
pub mod rectangle;
pub mod image;
pub mod internal;
pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;
pub mod deform;
pub mod grid;
pub mod radians;

/// A color property
pub struct Color(pub internal::Color);

/// Wrapper trait for `Get<Color>`
pub trait GetColor: Get<Color> {
    /// Get color
    #[inline(always)]
    fn get_color(&self) -> Color {
        self.get()
    }
}

impl<T: Get<Color>> GetColor for T {}

/// Wrapper trait for `Set<Color>`
pub trait SetColor: Set<Color> {
    /// Set color
    #[inline(always)]
    fn set_color(&mut self, val: Color) {
        self.set_mut(val);
    }
}

impl<T: Set<Color>> SetColor for T {}

/// A rectangle property
pub struct Rect(pub internal::Rectangle);

/// Wrapper trait for `Get<Rect>`
pub trait GetRect: Get<Rect> {
    /// Get rectangle
    #[inline(always)]
    fn get_rect(&self) -> Rect {
        self.get()
    }
}

impl<T: Get<Rect>> GetRect for T {}

/// Wrapper trait for `Set<Rect>`
pub trait SetRect: Set<Rect> {
    /// Set rectangle
    #[inline(always)]
    fn set_rect(&mut self, val: Rect) {
        self.set_mut(val);
    }
}

impl<T: Set<Rect>> SetRect for T {}

/// A source rectangle property
pub struct SrcRect(pub internal::SourceRectangle);

/// Wrapper trait for `Get<SrcRect>`
pub trait GetSrcRect: Get<SrcRect> {
    /// Get source rectangle
    #[inline(always)]
    fn get_src_rect(&self) -> SrcRect {
        self.get()
    }
}

impl<T: Get<SrcRect>> GetSrcRect for T {}

/// Wrapper trait for `Set<SrcRect>`
pub trait SetSrcRect: Set<SrcRect> {
    /// Set source rectangle
    #[inline(always)]
    fn set_src_rect(&mut self, val: SrcRect) {
        self.set_mut(val);
    }
}

impl<T: Set<SrcRect>> SetSrcRect for T {}

/// Clears the screen.
pub fn clear<B: BackEnd<I>, I: ImageSize>(
    color: internal::Color, back_end: &mut B
) {
    back_end.clear(color);
}

/// Draws image.
pub fn image<B: BackEnd<I>, I: ImageSize>(
    image: &I, c: &Context, back_end: &mut B
) {
    Image::new().draw(image, c, back_end);
}

<|endoftext|>


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

//! Extensions to `std::net` networking types.
//!
//! This crate implements a number of extensions to the standard `std::net`
//! networking types, hopefully being slated for inclusion into the standard
//! library in the future. The goal of this crate is to expose all sorts of
//! cross-platform and platform-specific configuration options of UDP/TCP
//! sockets. System APIs are wrapped with as thin a layer as possible instead of
//! bundling multiple actions into one API call.
//!
//! More information about the design of this crate can be found in the
//! [associated rfc][rfc]
//!
//! [rfc]: https://github.com/rust-lang/rfcs/pull/1158
//!
//! # Examples
//!
//! ```no_run
//! use net2::TcpBuilder;
//!
//! let tcp = TcpBuilder::new_v4().unwrap();
//! tcp.reuse_address(true).unwrap()
//!    .only_v6(false).unwrap();
//!
//! let mut stream = tcp.connect("127.0.0.1:80").unwrap();
//!
//! // use `stream` as a TcpStream
//! ```

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/net2-rs")]
#![deny(missing_docs, warnings)]

#![cfg_attr(target_os = "wasi", feature(wasi_ext))]

#[cfg(any(target_os = "redox", target_os = "wasi", unix))] extern crate libc;

#[cfg(windows)] extern crate winapi;

#[macro_use] extern crate cfg_if;

use std::io;
use std::ops::Neg;
use std::net::{ToSocketAddrs, SocketAddr};

use utils::{One, NetInt};

mod tcp;
mod udp;
mod socket;
mod ext;
mod utils;

#[cfg(target_os="redox")] #[path = "sys/redox/mod.rs"] mod sys;
#[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys;
#[cfg(windows)] #[path = "sys/windows/mod.rs"] mod sys;
#[cfg(target_os = "wasi")] #[path = "sys/wasi/mod.rs"] mod sys;
#[cfg(all(unix, not(any(target_os = "solaris"))))] pub mod unix;

pub use tcp::TcpBuilder;
pub use udp::UdpBuilder;
pub use ext::{TcpStreamExt, TcpListenerExt, UdpSocketExt};

fn one_addr<T: ToSocketAddrs>(tsa: T) -> io::Result<SocketAddr> {
    let mut addrs = try!(tsa.to_socket_addrs());
    let addr = match addrs.next() {
        Some(addr) => addr,
        None => return Err(io::Error::new(io::ErrorKind::Other,
                                          "no socket addresses could be resolved"))
    };
    if addrs.next().is_none() {
        Ok(addr)
    } else {
        Err(io::Error::new(io::ErrorKind::Other,
                           "more than one address resolved"))
    }
}

fn cvt<T: One + PartialEq + Neg<Output=T>>(t: T) -> io::Result<T> {
    let one: T = T::one();
    if t == -one {
        Err(io::Error::last_os_error())
    } else {
        Ok(t)
    }
}

#[cfg(windows)]
fn cvt_win<T: PartialEq + utils::Zero>(t: T) -> io::Result<T> {
    if t == T::zero() {
        Err(io::Error::last_os_error())
    } else {
        Ok(t)
    }
}

fn hton<I: NetInt>(i: I) -> I { i.to_be() }

fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }

trait AsInner {
    type Inner;
    fn as_inner(&self) -> &Self::Inner;
}

trait FromInner {
    type Inner;
    fn from_inner(inner: Self::Inner) -> Self;
}

trait IntoInner {
    type Inner;
    fn into_inner(self) -> Self::Inner;
}
<commit_msg>Silence try!() deprecation warnings<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Extensions to `std::net` networking types.
//!
//! This crate implements a number of extensions to the standard `std::net`
//! networking types, hopefully being slated for inclusion into the standard
//! library in the future. The goal of this crate is to expose all sorts of
//! cross-platform and platform-specific configuration options of UDP/TCP
//! sockets. System APIs are wrapped with as thin a layer as possible instead of
//! bundling multiple actions into one API call.
//!
//! More information about the design of this crate can be found in the
//! [associated rfc][rfc]
//!
//! [rfc]: https://github.com/rust-lang/rfcs/pull/1158
//!
//! # Examples
//!
//! ```no_run
//! use net2::TcpBuilder;
//!
//! let tcp = TcpBuilder::new_v4().unwrap();
//! tcp.reuse_address(true).unwrap()
//!    .only_v6(false).unwrap();
//!
//! let mut stream = tcp.connect("127.0.0.1:80").unwrap();
//!
//! // use `stream` as a TcpStream
//! ```

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/net2-rs")]
#![deny(missing_docs, warnings)]

// Silence warnings about deprecated try!() usage
#![allow(deprecated)]

#![cfg_attr(target_os = "wasi", feature(wasi_ext))]

#[cfg(any(target_os = "redox", target_os = "wasi", unix))] extern crate libc;

#[cfg(windows)] extern crate winapi;

#[macro_use] extern crate cfg_if;

use std::io;
use std::ops::Neg;
use std::net::{ToSocketAddrs, SocketAddr};

use utils::{One, NetInt};

mod tcp;
mod udp;
mod socket;
mod ext;
mod utils;

#[cfg(target_os="redox")] #[path = "sys/redox/mod.rs"] mod sys;
#[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys;
#[cfg(windows)] #[path = "sys/windows/mod.rs"] mod sys;
#[cfg(target_os = "wasi")] #[path = "sys/wasi/mod.rs"] mod sys;
#[cfg(all(unix, not(any(target_os = "solaris"))))] pub mod unix;

pub use tcp::TcpBuilder;
pub use udp::UdpBuilder;
pub use ext::{TcpStreamExt, TcpListenerExt, UdpSocketExt};

fn one_addr<T: ToSocketAddrs>(tsa: T) -> io::Result<SocketAddr> {
    let mut addrs = try!(tsa.to_socket_addrs());
    let addr = match addrs.next() {
        Some(addr) => addr,
        None => return Err(io::Error::new(io::ErrorKind::Other,
                                          "no socket addresses could be resolved"))
    };
    if addrs.next().is_none() {
        Ok(addr)
    } else {
        Err(io::Error::new(io::ErrorKind::Other,
                           "more than one address resolved"))
    }
}

fn cvt<T: One + PartialEq + Neg<Output=T>>(t: T) -> io::Result<T> {
    let one: T = T::one();
    if t == -one {
        Err(io::Error::last_os_error())
    } else {
        Ok(t)
    }
}

#[cfg(windows)]
fn cvt_win<T: PartialEq + utils::Zero>(t: T) -> io::Result<T> {
    if t == T::zero() {
        Err(io::Error::last_os_error())
    } else {
        Ok(t)
    }
}

fn hton<I: NetInt>(i: I) -> I { i.to_be() }

fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }

trait AsInner {
    type Inner;
    fn as_inner(&self) -> &Self::Inner;
}

trait FromInner {
    type Inner;
    fn from_inner(inner: Self::Inner) -> Self;
}

trait IntoInner {
    type Inner;
    fn into_inner(self) -> Self::Inner;
}
<|endoftext|>


<commit_before>#![feature(default_type_params)]

extern crate url;
extern crate openssl;
extern crate serialize;

#[cfg(test)]
extern crate test;

#[cfg(test)]
use test::Bencher;

use url::Url;
use std::io;
use std::io::{Buffer, Reader, Writer, IoResult, BufferedStream, standard_error};
use std::io::net::tcp::TcpStream;
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::net::get_host_addresses;
use std::fmt::{Show, Formatter, FormatError};
use std::collections::TreeMap;
use serialize::json;
use serialize::json::{Json, ToJson};
use openssl::ssl;
use openssl::ssl::{SslStream, SslContext};

enum NetworkStream {
    NormalStream(TcpStream),
    SslProtectedStream(SslStream<TcpStream>)
}

impl Reader for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            NormalStream(ref mut s) => s.read(buf),
            SslProtectedStream(ref mut s) => s.read(buf)
        }
    }
}

impl Writer for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.write(buf),
            SslProtectedStream(ref mut s) => s.write(buf)
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.flush(),
            SslProtectedStream(ref mut s) => s.flush()
        }
    }
}

static WEBSOCKET_GUID: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

bitflags! {
    #[deriving(Show)] flags WSHeader: u16 {
        static WS_FIN     = 0b1000000000000000,
        static WS_OPCODE  = 0b0000111100000000,
        static WS_MASK    = 0b0000000010000000,
        static WS_LEN     = 0b0000000001111111,

        static WS_LEN16   = 0b0000000001111110,
        static WS_LEN64   = 0b0000000001111111,

        static WS_OPCONT  = 0b0000000000000000,
        static WS_OPTEXT  = 0b0000000100000000,
        static WS_OPBIN   = 0b0000001000000000,
        static WS_OPTERM  = 0b0000100000000000,
        static WS_OPPING  = 0b0000100100000000,
        static WS_OPPONG  = 0b0000101000000000,
    }
}

#[allow(visible_private_types)]
#[allow(dead_code)]
pub struct WebSocket<S = NetworkStream> {
    stream: Option<BufferedStream<S>>,
    handshake_finished: bool,
    pub remote_addr: Option<SocketAddr>,
    pub url: Url,
    use_ssl: bool,
}

#[allow(dead_code)]
impl WebSocket {
    fn new(url: Url) -> IoResult<WebSocket> {
        let addr = match try!(url.domain()
            .map(|h| get_host_addresses(h)
                 .map(|v| v.move_iter().find(|&a| {
                     match a {
                         Ipv4Addr(..) => true,
                         _ => false
                     }
                 })))
            .unwrap_or(Err(standard_error(io::InvalidInput)))) {
                Some(a) => a,
                None => return Err(standard_error(io::FileNotFound))
            };

        let use_ssl = url.scheme.as_slice() == "wss";

        let port = match url.port() {
            Some(p) => p,
            None if use_ssl => 443,
            _ => 80
        };

        Ok(WebSocket {
            stream: None,
            handshake_finished: false,
            remote_addr: Some(SocketAddr{ ip: addr, port: port }),
            url: url,
            use_ssl: use_ssl
        })
    }

    fn connect(&mut self) -> IoResult<()> {
        let s = try!(self.remote_addr.map(|ref a| TcpStream::connect(format!("{}", a.ip).as_slice(), a.port)).unwrap_or_else(|| Err(standard_error(io::InvalidInput))));
        self.stream = Some(BufferedStream::new(
            if self.use_ssl {
                SslProtectedStream(try!(SslStream::new(&try!(SslContext::new(ssl::Sslv23).map_err(|e| standard_error(io::OtherIoError))), s)
                                        .map_err(|e| standard_error(io::OtherIoError))))
            } else {
                NormalStream(s)
            }));
        Ok(())
    }

    fn send_headers(&mut self) -> IoResult<()> {
        let mut s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        try!(s.write(format!("GET {} HTTP/1.1\r\n", self.url.serialize_path().unwrap_or("/".to_string())).as_bytes()));
        try!(s.write(format!("Host: {}\r\n", self.url.host().unwrap()).as_bytes()));
        try!(s.write("Upgrade: websocket\r\n".as_bytes()));
        try!(s.write("Connection: Upgrade\r\n".as_bytes()));
        try!(s.write(format!("Origin: {}\r\n", self.url.serialize_no_fragment()).as_bytes()));
        try!(s.write("Sec-WebSocket-Protocol: char, superchat\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Version: 13\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Key: {}\r\n".as_bytes()));
        try!(s.write("\r\n".as_bytes()));
        s.flush()
    }

    fn read_response(&mut self) -> IoResult<()> {
        let spaces: &[_] = &[' ', '\t', '\r', '\n'];
        let mut s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        let status = try!(s.read_line()).as_slice().splitn(2, ' ').nth(1).and_then(|s| from_str::<uint>(s));

        match status {
            Some(101) => (),
            _ => return Err(standard_error(io::InvalidInput))
        }

        let headers = s.lines().map(|r| r.unwrap_or("\r\n".to_string())) .take_while(|l| l.as_slice() != "\r\n")
            .map(|s| s.as_slice().splitn(1, ':').map(|s| s.trim_chars(spaces).to_string()).collect::<Vec<String>>())
            .map(|p| (p[0].to_string(), p[1].to_string()))
            .collect::<TreeMap<String, String>>();

        try!(s.flush());

        if WebSocket::check_nonce("{}", headers.find(&"Sec-WebSocket-Accept".to_string()).unwrap_or(&"".to_string()).as_slice()) {
            Ok(())
        } else {
            Err(standard_error(io::InvalidInput))
        }
    }

    fn check_nonce(nonce: &str, response: &str) -> bool {
        true
    }

    fn handshake(&mut self) -> IoResult<()> {
        try!(self.connect());
        try!(self.send_headers());
        try!(self.read_response());

        self.handshake_finished = true;
        Ok(())
    }

    fn read_header(&mut self) -> IoResult<WSHeader> {
        // XXX: this is a bug, WSHeader should accept u16
        Ok(WSHeader { bits: try!(self.read_be_u16()) as u32 })
    }

    fn read_length(&mut self, header: &WSHeader) -> IoResult<uint> {
        let len = header & WS_LEN;

        match header & WS_LEN {
            WS_LEN16 => self.read_be_u16().map(|v| v as uint),
            WS_LEN64 => self.read_be_u64().map(|v| v as uint),
            len => Ok(len.bits as uint)
        }
    }

    fn read_message(&mut self) -> IoResult<WSMessage> {
        let header = try!(self.read_header());
        let len = try!(self.read_length(&header));
        let mask = if header.contains(WS_MASK) { Some(try!(self.read_be_u32())) } else { None };
        let data = try!(self.read_exact(len));
        // TODO: unmask data
        Ok(WSMessage { header: header, data: data })
    }

    // TODO: send_message(&mut self, &WSMessage) -> IoResult<()>

    fn iter(&mut self) -> WSMessages {
        WSMessages { sock: self }
    }

    fn unmask_data(data: &mut [u8], mask: u32) -> &[u8] {
        data
    }
}

#[deriving(Show)]
struct WSMessage {
    header: WSHeader,
    data: Vec<u8>
}

impl WSMessage {
    fn to_string(&self) -> String {
        String::from_utf8_lossy(self.data.as_slice()).into_string()
    }
}

impl ToJson for WSMessage {
    fn to_json(&self) -> Json {
        from_str::<Json>(self.to_string().as_slice()).unwrap()
    }
}

struct WSMessages<'a> {
    sock: &'a mut WebSocket
}

impl<'a> Iterator<WSMessage> for WSMessages<'a> {
    fn next(&mut self) -> Option<WSMessage> {
        self.sock.read_message().ok()
    }
}

impl Reader for WebSocket {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self.stream {
            Some(ref mut s) => s.read(buf),
            None => Err(standard_error(io::NotConnected))
        }
    }
}

impl Buffer for WebSocket {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        match self.stream {
            Some(ref mut s) => s.fill_buf(),
            None => Err(standard_error(io::NotConnected))
        }
    }

    fn consume(&mut self, amt: uint) {
        match self.stream {
            Some(ref mut s) => s.consume(amt),
            None => ()
        }
    }
}

#[bench]
fn test_connect(b: &mut Bencher) {
    let url = Url::parse("wss://stream.pushbullet.com/websocket/").unwrap();
    let mut ws = WebSocket::new(url).unwrap();

    match ws.handshake() {
        Err(e) => fail!("error: {}", e),
        _ => ()
    }
    let msg = ws.read_message().unwrap();
    println!("received: {} {} {}", msg, msg.to_string(), msg.to_json());
    for msg in ws.iter() {
        println!("{}", msg.to_string());
    }
}
<commit_msg>code cleanup<commit_after>#![feature(default_type_params)]

extern crate url;
extern crate openssl;
extern crate serialize;

#[cfg(test)]
extern crate test;

#[cfg(test)]
use test::Bencher;

use url::Url;
use std::io;
use std::io::{Buffer, Reader, Writer, IoResult, BufferedStream, standard_error};
use std::io::net::tcp::TcpStream;
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::net::get_host_addresses;
use std::collections::TreeMap;
use serialize::json::{Json, ToJson};
use openssl::ssl;
use openssl::ssl::{SslStream, SslContext};

enum NetworkStream {
    NormalStream(TcpStream),
    SslProtectedStream(SslStream<TcpStream>)
}

impl Reader for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            NormalStream(ref mut s) => s.read(buf),
            SslProtectedStream(ref mut s) => s.read(buf)
        }
    }
}

impl Writer for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.write(buf),
            SslProtectedStream(ref mut s) => s.write(buf)
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.flush(),
            SslProtectedStream(ref mut s) => s.flush()
        }
    }
}

static WEBSOCKET_GUID: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

bitflags! {
    #[deriving(Show)] flags WSHeader: u16 {
        static WS_FIN     = 0b1000000000000000,
        static WS_OPCODE  = 0b0000111100000000,
        static WS_MASK    = 0b0000000010000000,
        static WS_LEN     = 0b0000000001111111,

        static WS_LEN16   = 0b0000000001111110,
        static WS_LEN64   = 0b0000000001111111,

        static WS_OPCONT  = 0b0000000000000000,
        static WS_OPTEXT  = 0b0000000100000000,
        static WS_OPBIN   = 0b0000001000000000,
        static WS_OPTERM  = 0b0000100000000000,
        static WS_OPPING  = 0b0000100100000000,
        static WS_OPPONG  = 0b0000101000000000,
    }
}

#[allow(visible_private_types)]
#[allow(dead_code)]
pub struct WebSocket<S = NetworkStream> {
    stream: Option<BufferedStream<S>>,
    handshake_finished: bool,
    pub remote_addr: Option<SocketAddr>,
    pub url: Url,
    use_ssl: bool,
}

#[allow(dead_code)]
impl WebSocket {
    fn new(url: Url) -> IoResult<WebSocket> {
        let addr = match try!(url.domain()
            .map(|h| get_host_addresses(h)
                 .map(|v| v.move_iter().find(|&a| {
                     match a {
                         Ipv4Addr(..) => true,
                         _ => false
                     }
                 })))
            .unwrap_or(Err(standard_error(io::InvalidInput)))) {
                Some(a) => a,
                None => return Err(standard_error(io::FileNotFound))
            };

        let use_ssl = url.scheme.as_slice() == "wss";

        let port = match url.port() {
            Some(p) => p,
            None if use_ssl => 443,
            _ => 80
        };

        Ok(WebSocket {
            stream: None,
            handshake_finished: false,
            remote_addr: Some(SocketAddr{ ip: addr, port: port }),
            url: url,
            use_ssl: use_ssl
        })
    }

    #[allow(unused_variable)]
    fn connect(&mut self) -> IoResult<()> {
        let s = try!(self.remote_addr.map(|ref a| TcpStream::connect(format!("{}", a.ip).as_slice(), a.port)).unwrap_or_else(|| Err(standard_error(io::InvalidInput))));
        self.stream = Some(BufferedStream::new(
            if self.use_ssl {
                SslProtectedStream(try!(SslStream::new(&try!(SslContext::new(ssl::Sslv23).map_err(|e| standard_error(io::OtherIoError))), s)
                                        .map_err(|e| standard_error(io::OtherIoError))))
            } else {
                NormalStream(s)
            }));
        Ok(())
    }

    fn send_headers(&mut self) -> IoResult<()> {
        let s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        try!(s.write(format!("GET {} HTTP/1.1\r\n", self.url.serialize_path().unwrap_or("/".to_string())).as_bytes()));
        try!(s.write(format!("Host: {}\r\n", self.url.host().unwrap()).as_bytes()));
        try!(s.write("Upgrade: websocket\r\n".as_bytes()));
        try!(s.write("Connection: Upgrade\r\n".as_bytes()));
        try!(s.write(format!("Origin: {}\r\n", self.url.serialize_no_fragment()).as_bytes()));
        try!(s.write("Sec-WebSocket-Protocol: char, superchat\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Version: 13\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Key: {}\r\n".as_bytes()));
        try!(s.write("\r\n".as_bytes()));
        s.flush()
    }

    fn read_response(&mut self) -> IoResult<()> {
        let spaces: &[_] = &[' ', '\t', '\r', '\n'];
        let s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        let status = try!(s.read_line()).as_slice().splitn(2, ' ').nth(1).and_then(|s| from_str::<uint>(s));

        match status {
            Some(101) => (),
            _ => return Err(standard_error(io::InvalidInput))
        }

        let headers = s.lines().map(|r| r.unwrap_or("\r\n".to_string())) .take_while(|l| l.as_slice() != "\r\n")
            .map(|s| s.as_slice().splitn(1, ':').map(|s| s.trim_chars(spaces).to_string()).collect::<Vec<String>>())
            .map(|p| (p[0].to_string(), p[1].to_string()))
            .collect::<TreeMap<String, String>>();

        try!(s.flush());

        if WebSocket::check_nonce("{}", headers.find(&"Sec-WebSocket-Accept".to_string()).unwrap_or(&"".to_string()).as_slice()) {
            Ok(())
        } else {
            Err(standard_error(io::InvalidInput))
        }
    }

    fn check_nonce(nonce: &str, response: &str) -> bool {
        true
    }

    fn handshake(&mut self) -> IoResult<()> {
        try!(self.connect());
        try!(self.send_headers());
        try!(self.read_response());

        self.handshake_finished = true;
        Ok(())
    }

    fn read_header(&mut self) -> IoResult<WSHeader> {
        // XXX: this is a bug, WSHeader should accept u16
        Ok(WSHeader { bits: try!(self.read_be_u16()) as u32 })
    }

    fn read_length(&mut self, header: &WSHeader) -> IoResult<uint> {
        match header & WS_LEN {
            WS_LEN16 => self.read_be_u16().map(|v| v as uint),
            WS_LEN64 => self.read_be_u64().map(|v| v as uint),
            len => Ok(len.bits as uint)
        }
    }

    fn read_message(&mut self) -> IoResult<WSMessage> {
        let header = try!(self.read_header());
        let len = try!(self.read_length(&header));
        let mask = if header.contains(WS_MASK) { Some(try!(self.read_be_u32())) } else { None };
        let data = try!(self.read_exact(len));
        // TODO: unmask data
        Ok(WSMessage { header: header, data: data })
    }

    // TODO: send_message(&mut self, &WSMessage) -> IoResult<()>

    fn iter(&mut self) -> WSMessages {
        WSMessages { sock: self }
    }

    fn unmask_data(data: &mut [u8], mask: u32) -> &[u8] {
        data
    }
}

#[deriving(Show)]
struct WSMessage {
    header: WSHeader,
    data: Vec<u8>
}

impl WSMessage {
    fn to_string(&self) -> String {
        String::from_utf8_lossy(self.data.as_slice()).into_string()
    }
}

impl ToJson for WSMessage {
    fn to_json(&self) -> Json {
        from_str::<Json>(self.to_string().as_slice()).unwrap()
    }
}

#[allow(dead_code)]
struct WSMessages<'a> {
    sock: &'a mut WebSocket
}

impl<'a> Iterator<WSMessage> for WSMessages<'a> {
    fn next(&mut self) -> Option<WSMessage> {
        self.sock.read_message().ok()
    }
}

impl Reader for WebSocket {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self.stream {
            Some(ref mut s) => s.read(buf),
            None => Err(standard_error(io::NotConnected))
        }
    }
}

impl Buffer for WebSocket {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        match self.stream {
            Some(ref mut s) => s.fill_buf(),
            None => Err(standard_error(io::NotConnected))
        }
    }

    fn consume(&mut self, amt: uint) {
        match self.stream {
            Some(ref mut s) => s.consume(amt),
            None => ()
        }
    }
}

#[bench]
#[allow(dead_code)]
fn test_connect(b: &mut Bencher) {
    let url = Url::parse("wss://stream.pushbullet.com/websocket/").unwrap();
    let mut ws = WebSocket::new(url).unwrap();

    match ws.handshake() {
        Err(e) => fail!("error: {}", e),
        _ => ()
    }
    let msg = ws.read_message().unwrap();
    println!("received: {} {} {}", msg, msg.to_string(), msg.to_json());
    for msg in ws.iter() {
        println!("{}", msg.to_string());
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(phase)]

#![unstable]

#[phase(plugin)]
extern crate compile_msg;

extern crate libc;

use std::sync::Mutex;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {
    EventUp,
    EventDown,
    EventMove(i32, i32),
}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android")

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, proc() super::$main());
            }
        }
    )
)

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2(app: *mut (), main_function: proc(): Send) {
    use std::task::TaskBuilder;
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // creating the context that will be passed to the callback
    let context = Context { senders: Mutex::new(Vec::new()) };
    app.onAppCmd = commands_callback;
    app.onInputEvent = inputs_callback;
    app.userData = unsafe { std::mem::transmute(&context) };

    // executing the main function in parallel
    spawn(proc() {
        std::io::stdio::set_stdout(box std::io::LineBufferedWriter::new(ToLogWriter));
        std::io::stdio::set_stderr(box std::io::LineBufferedWriter::new(ToLogWriter));
        main_function()
    });

    // polling for events forever
    // note that this must be done in the same thread as android_main because ALooper are
    //  thread-local
    unsafe {
        loop {
            let mut events = mem::uninitialized();
            let mut source = mem::uninitialized();

            // passing -1 means that we are blocking
            let ident = ffi::ALooper_pollAll(-1, ptr::null_mut(), &mut events,
                &mut source);

            // processing the event
            if !source.is_null() {
                let source: *mut ffi::android_poll_source = mem::transmute(source);
                ((*source).process)(ANDROID_APP, source);
            }
        }
    }

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// Writer that will redirect what is written to it to the logs.
struct ToLogWriter;

impl Writer for ToLogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::IoResult<()> {
        buf.with_c_str(|message| {
            b"RustAndroidGlueStdouterr".with_c_str(|tag| {
                unsafe { ffi::__android_log_write(3, tag, message) };
            });
        });
        Ok(())
    }
}

/// The callback for inputs.
pub extern fn inputs_callback(_: *mut ffi::android_app, event: *const ffi::AInputEvent)
    -> libc::int32_t
{
    fn send_event(event: Event) {
        for sender in get_context().senders.lock().iter() {
            sender.send(event);
        }
    }
    let action = unsafe { ffi::AMotionEvent_getAction(event) };
    let action_code = action & ffi::AMOTION_EVENT_ACTION_MASK;
    match action_code {
        ffi::AMOTION_EVENT_ACTION_UP
            | ffi::AMOTION_EVENT_ACTION_OUTSIDE
            | ffi::AMOTION_EVENT_ACTION_CANCEL
            | ffi::AMOTION_EVENT_ACTION_POINTER_UP =>
        {
            send_event(Event::EventUp);
        },
        ffi::AMOTION_EVENT_ACTION_DOWN
            | ffi::AMOTION_EVENT_ACTION_POINTER_DOWN =>
        {
            send_event(Event::EventDown);
        },
        _ => {
            let x = unsafe { ffi::AMotionEvent_getX(event, 0) };
            let y = unsafe { ffi::AMotionEvent_getY(event, 0) };
            send_event(Event::EventMove(x as i32, y as i32));
        },
    }
    0
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(_: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },

        ffi::APP_CMD_SAVE_STATE => {

        },

        ffi::APP_CMD_TERM_WINDOW => {

        },

        ffi::APP_CMD_GAINED_FOCUS => {

        },

        ffi::APP_CMD_LOST_FOCUS => {

        },

        _ => ()
    }
}

/// Returns the current Context.
fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        panic!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    message.with_c_str(|message| {
        b"RustAndroidGlue".with_c_str(|tag| {
            unsafe { ffi::__android_log_write(3, tag, message) };
        });
    });
}
<commit_msg>android: Updated for rust 99d6956c3 2014-12-18 20:32:07<commit_after>#![feature(macro_rules)]
#![feature(phase)]

#![unstable]

#[phase(plugin)]
extern crate compile_msg;

extern crate libc;

use std::sync::Mutex;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {
    EventUp,
    EventDown,
    EventMove(i32, i32),
}

impl Copy for Event {}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android");

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, move|| super::$main());
            }
        }
    )
);

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2<F>(app: *mut (), main_function: F)
    where F: FnOnce(), F: Send
{
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // creating the context that will be passed to the callback
    let context = Context { senders: Mutex::new(Vec::new()) };
    app.onAppCmd = commands_callback;
    app.onInputEvent = inputs_callback;
    app.userData = unsafe { std::mem::transmute(&context) };

    // executing the main function in parallel
    spawn(move|| {
        std::io::stdio::set_stdout(box std::io::LineBufferedWriter::new(ToLogWriter));
        std::io::stdio::set_stderr(box std::io::LineBufferedWriter::new(ToLogWriter));
        main_function()
    });

    // polling for events forever
    // note that this must be done in the same thread as android_main because ALooper are
    //  thread-local
    unsafe {
        loop {
            let mut events = mem::uninitialized();
            let mut source = mem::uninitialized();

            // passing -1 means that we are blocking
            let ident = ffi::ALooper_pollAll(-1, ptr::null_mut(), &mut events,
                &mut source);

            // processing the event
            if !source.is_null() {
                let source: *mut ffi::android_poll_source = mem::transmute(source);
                ((*source).process)(ANDROID_APP, source);
            }
        }
    }

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// Writer that will redirect what is written to it to the logs.
struct ToLogWriter;

impl Writer for ToLogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::IoResult<()> {
        buf.with_c_str(|message| {
            b"RustAndroidGlueStdouterr".with_c_str(|tag| {
                unsafe { ffi::__android_log_write(3, tag, message) };
            });
        });
        Ok(())
    }
}

/// The callback for inputs.
pub extern fn inputs_callback(_: *mut ffi::android_app, event: *const ffi::AInputEvent)
    -> libc::int32_t
{
    fn send_event(event: Event) {
        for sender in get_context().senders.lock().iter() {
            sender.send(event);
        }
    }
    let action = unsafe { ffi::AMotionEvent_getAction(event) };
    let action_code = action & ffi::AMOTION_EVENT_ACTION_MASK;
    match action_code {
        ffi::AMOTION_EVENT_ACTION_UP
            | ffi::AMOTION_EVENT_ACTION_OUTSIDE
            | ffi::AMOTION_EVENT_ACTION_CANCEL
            | ffi::AMOTION_EVENT_ACTION_POINTER_UP =>
        {
            send_event(Event::EventUp);
        },
        ffi::AMOTION_EVENT_ACTION_DOWN
            | ffi::AMOTION_EVENT_ACTION_POINTER_DOWN =>
        {
            send_event(Event::EventDown);
        },
        _ => {
            let x = unsafe { ffi::AMotionEvent_getX(event, 0) };
            let y = unsafe { ffi::AMotionEvent_getY(event, 0) };
            send_event(Event::EventMove(x as i32, y as i32));
        },
    }
    0
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(_: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },

        ffi::APP_CMD_SAVE_STATE => {

        },

        ffi::APP_CMD_TERM_WINDOW => {

        },

        ffi::APP_CMD_GAINED_FOCUS => {

        },

        ffi::APP_CMD_LOST_FOCUS => {

        },

        _ => ()
    }
}

/// Returns the current Context.
fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        panic!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    message.with_c_str(|message| {
        b"RustAndroidGlue".with_c_str(|tag| {
            unsafe { ffi::__android_log_write(3, tag, message) };
        });
    });
}
<|endoftext|>