<commit_before>extern crate libc;
use self::libc::*;

use low_level as ll;
use error::Error;
use device::Device;
use context::Context;
use event::{Event, EventStatus, EventLike};
use kernel::Kernel;
use mem::Mem;

use std::ptr;
use std::mem::{size_of, transmute};

pub struct CommandQueue {
    pub id: ll::CommandQueue,
}

pub struct ReadLock<'a, T: Sized + 'a> {
    #[allow(dead_code)]
    sl: &'a [T],
    evt: Event,
}

pub struct WriteLock<'a, T: Sized + 'a> {
    #[allow(dead_code)]
    sl: &'a mut [T],
    evt: Event,
}

impl<'a, T: Sized> Drop for ReadLock<'a, T> {
    fn drop(self: &mut Self) -> () {
        self.evt.wait().ok().expect(
            "error waiting to finish write for ReadLock");
    }
}

impl<'a, T: Sized> EventLike for ReadLock<'a, T> {
    fn status(self: &Self) -> Result<EventStatus, Error> {
        self.evt.status()
    }

    fn wait(self: &Self) -> Result<(), Error> {
        self.evt.wait()
    }
}

impl<'a, T: Sized> Drop for WriteLock<'a, T> {
    fn drop(self: &mut Self) -> () {
        self.evt.wait().ok().expect(
            "error waiting to finish write for ReadLock");
    }
}

impl<'a, T: Sized> EventLike for WriteLock<'a, T> {
    fn status(self: &Self) -> Result<EventStatus, Error> {
        self.evt.status()
    }

    fn wait(self: &Self) -> Result<(), Error> {
        self.evt.wait()
    }
}

impl CommandQueue {
    pub fn new(context: Context,
               device: Device) -> Result<CommandQueue, Error> {
        let props: c_ulong = if try!(device.out_of_order_supported()) {
            1
        } else {
            0
        };
        let id = unsafe {
            let mut err: i32 = 0;
            let id = ll::clCreateCommandQueue(context.id,
                                              device.id,
                                              props,
                                              &mut err);
            try!(Error::check(err));
            id
        };
        Ok(CommandQueue{ id: id })
    }

    fn get_info(self: &Self, param: u32) -> Result<*mut c_void, Error> {
        let mut tr: *mut c_void = ptr::null_mut();
        unsafe {
            try!(Error::check(ll::clGetCommandQueueInfo(self.id,
                                                   param,
                                                   size_of::<*mut c_void>() as size_t,
                                                   transmute(&mut tr),
                                                   ptr::null_mut())));
        }
        Ok(tr)
    }

    pub fn context(self: &Self) -> Result<Context, Error> {
        let val = try!(self.get_info(0x1090));
        let id = unsafe { transmute(val) };
        unsafe {
            try!(Error::check(ll::clRetainContext(id)));
        }
        Ok(Context{id: id})
    }

    pub fn device(self: &Self) -> Result<Device, Error> {
        let val = try!(self.get_info(0x1091));
        let id = unsafe { transmute(val) };
        Ok(Device{id: id})
    }

    fn alloc_ll_buffer(self: &Self,
                    flags: c_ulong,
                    size_bytes: usize) -> Result<ll::Mem, Error> {
        let context = try!(self.context());
        let id = unsafe {
            let mut err: i32 = 0;
            let id = ll::clCreateBuffer(context.id,
                                        flags,
                                        size_bytes as size_t,
                                        ptr::null_mut(),
                                        &mut err);
            try!(Error::check(err));
            id
        };
        Ok(id)
    }

    fn write_buffer_raw<T: Sized>(self: &Self,
                       buf: &mut Mem,
                       offset: usize,
                       size: usize,
                       data: &[T]) -> Result<Event, Error> {
        let mut event_id: ll::Event = ptr::null_mut();
        let host_ptr = &data[0] as *const T;
        let wait_list: Vec<ll::Event> = buf.write_events();
        let wait_size = wait_list.len() as u32;

        let wait_list_ptr: *const ll::Event = match wait_size {
            0 => ptr::null(),
            _ => &wait_list[0],
        };

        unsafe {
            try!(Error::check(ll::clEnqueueWriteBuffer(self.id,
                                                       buf.id,
                                                       0, // don't block
                                                       offset as size_t,
                                                       size as size_t,
                                                       transmute(host_ptr),
                                                       wait_size,
                                                       wait_list_ptr,
                                                       &mut event_id)));
        }

        let event = Event{id: event_id};
        buf.register_write(event.clone());
        Ok(event)
    }

    fn read_buffer_raw<T: Sized>(self: &Self,
                                 buf: &Mem,
                                 offset: usize,
                                 size: usize,
                                 data: &mut [T]) -> Result<Event, Error> {
        let mut event_id: ll::Event = ptr::null_mut();
        let host_ptr = &mut data[0] as *mut T;
        let wait_list: Vec<ll::Event> = buf.read_events();
        let wait_size = wait_list.len() as u32;

        let wait_list_ptr: *const ll::Event = match wait_size {
            0 => ptr::null(),
            _ => &wait_list[0],
        };

        unsafe {
            try!(Error::check(ll::clEnqueueReadBuffer(self.id,
                                                      buf.id,
                                                      0, // don't block,
                                                      offset as size_t,
                                                      size as size_t,
                                                      transmute(host_ptr),
                                                      wait_size,
                                                      wait_list_ptr,
                                                      &mut event_id)));
        }

        let event = Event{id: event_id};
        buf.register_read(event.clone());
        Ok(event)
    }

    pub fn create_buffer(self: &Self,
                               size_bytes: usize) -> Result<Mem, Error> {
        let id = try!(self.alloc_ll_buffer(0, size_bytes));
        let mut tr = Mem::new(id);
        // one-byte write to place buffer on device and ensure
        // allocated memory is okay
        let _ = try!(self.write_buffer_raw(&mut tr,
                                           0,
                                           1,
                                           &[self]));
        Ok(tr)
    }

    pub fn write_buffer<'a, 'b, T: Sized + 'a>(self: &Self,
                                  mem: &'b mut Mem,
                                  slice: &'a [T]) -> Result<ReadLock<'a, T>, Error> {
        let size_bytes = size_of::<T>()*slice.len();
        let evt = try!(self.write_buffer_raw(mem,
                                             0,
                                             size_bytes,
                                             slice));
        Ok(ReadLock{ evt: evt, sl: slice })
    }

    pub fn read_buffer<'a, T: Sized>(self: &Self,
                                 mem: &Mem,
                                 slice: &'a mut [T]) -> Result<WriteLock<'a, T>, Error> {
        let size_bytes = size_of::<T>()*slice.len();
        let evt = try!(self.read_buffer_raw(mem,
                                            0,
                                            size_bytes,
                                            slice));
        Ok(WriteLock{ evt: evt, sl: slice })
    }

    fn next_mul(self: &Self, global: usize, local: usize) -> usize {
        if local % global == 0 {
            global
        } else {
            ((global/local)+1)*local
        }
    }

    pub fn run( self: &Self,
                kernel: &mut Kernel,
                local_size: (usize, usize, usize),
                global_size: (usize, usize, usize)) -> Result<Event, Error> {
        let events = kernel.run_events();
        let global_size_fixed = (self.next_mul(global_size.0, local_size.0),
                                self.next_mul(global_size.1, local_size.1),
                                self.next_mul(global_size.2, local_size.2));

        let local_vec = vec!(local_size.0 as size_t,
                             local_size.1 as size_t,
                             local_size.2 as size_t);
        let global_vec = vec!(global_size_fixed.0 as size_t,
                              global_size_fixed.1 as size_t,
                              global_size_fixed.2 as size_t);

        println!("{:?}, {:?}", local_vec, global_vec);

        let mut event_id: ll::Event = ptr::null_mut();
        unsafe {
            try!(Error::check(ll::clEnqueueNDRangeKernel(self.id,
                                                         kernel.id,
                                                         3,
                                                         ptr::null(),
                                                         &global_vec[0],
                                                         &local_vec[0],
                                                         events.len() as u32,
                                                         &events[0],
                                                         &mut event_id)));
        }
        let event = Event{id: event_id};

        try!(kernel.register_run(event.clone()));
        Ok(event)
    }
}

impl Drop for CommandQueue {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseCommandQueue(self.id))
                .ok().expect("Error releasing command queue");
        }
    }
}

impl Clone for CommandQueue {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainCommandQueue(self.id))
                .ok().expect("Error retaining command queue");
        }
        CommandQueue{ id: self.id }
    }
}

<commit_msg>removes debugging println<commit_after>extern crate libc;
use self::libc::*;

use low_level as ll;
use error::Error;
use device::Device;
use context::Context;
use event::{Event, EventStatus, EventLike};
use kernel::Kernel;
use mem::Mem;

use std::ptr;
use std::mem::{size_of, transmute};

pub struct CommandQueue {
    pub id: ll::CommandQueue,
}

pub struct ReadLock<'a, T: Sized + 'a> {
    #[allow(dead_code)]
    sl: &'a [T],
    evt: Event,
}

pub struct WriteLock<'a, T: Sized + 'a> {
    #[allow(dead_code)]
    sl: &'a mut [T],
    evt: Event,
}

impl<'a, T: Sized> Drop for ReadLock<'a, T> {
    fn drop(self: &mut Self) -> () {
        self.evt.wait().ok().expect(
            "error waiting to finish write for ReadLock");
    }
}

impl<'a, T: Sized> EventLike for ReadLock<'a, T> {
    fn status(self: &Self) -> Result<EventStatus, Error> {
        self.evt.status()
    }

    fn wait(self: &Self) -> Result<(), Error> {
        self.evt.wait()
    }
}

impl<'a, T: Sized> Drop for WriteLock<'a, T> {
    fn drop(self: &mut Self) -> () {
        self.evt.wait().ok().expect(
            "error waiting to finish write for ReadLock");
    }
}

impl<'a, T: Sized> EventLike for WriteLock<'a, T> {
    fn status(self: &Self) -> Result<EventStatus, Error> {
        self.evt.status()
    }

    fn wait(self: &Self) -> Result<(), Error> {
        self.evt.wait()
    }
}

impl CommandQueue {
    pub fn new(context: Context,
               device: Device) -> Result<CommandQueue, Error> {
        let props: c_ulong = if try!(device.out_of_order_supported()) {
            1
        } else {
            0
        };
        let id = unsafe {
            let mut err: i32 = 0;
            let id = ll::clCreateCommandQueue(context.id,
                                              device.id,
                                              props,
                                              &mut err);
            try!(Error::check(err));
            id
        };
        Ok(CommandQueue{ id: id })
    }

    fn get_info(self: &Self, param: u32) -> Result<*mut c_void, Error> {
        let mut tr: *mut c_void = ptr::null_mut();
        unsafe {
            try!(Error::check(ll::clGetCommandQueueInfo(self.id,
                                                   param,
                                                   size_of::<*mut c_void>() as size_t,
                                                   transmute(&mut tr),
                                                   ptr::null_mut())));
        }
        Ok(tr)
    }

    pub fn context(self: &Self) -> Result<Context, Error> {
        let val = try!(self.get_info(0x1090));
        let id = unsafe { transmute(val) };
        unsafe {
            try!(Error::check(ll::clRetainContext(id)));
        }
        Ok(Context{id: id})
    }

    pub fn device(self: &Self) -> Result<Device, Error> {
        let val = try!(self.get_info(0x1091));
        let id = unsafe { transmute(val) };
        Ok(Device{id: id})
    }

    fn alloc_ll_buffer(self: &Self,
                    flags: c_ulong,
                    size_bytes: usize) -> Result<ll::Mem, Error> {
        let context = try!(self.context());
        let id = unsafe {
            let mut err: i32 = 0;
            let id = ll::clCreateBuffer(context.id,
                                        flags,
                                        size_bytes as size_t,
                                        ptr::null_mut(),
                                        &mut err);
            try!(Error::check(err));
            id
        };
        Ok(id)
    }

    fn write_buffer_raw<T: Sized>(self: &Self,
                       buf: &mut Mem,
                       offset: usize,
                       size: usize,
                       data: &[T]) -> Result<Event, Error> {
        let mut event_id: ll::Event = ptr::null_mut();
        let host_ptr = &data[0] as *const T;
        let wait_list: Vec<ll::Event> = buf.write_events();
        let wait_size = wait_list.len() as u32;

        let wait_list_ptr: *const ll::Event = match wait_size {
            0 => ptr::null(),
            _ => &wait_list[0],
        };

        unsafe {
            try!(Error::check(ll::clEnqueueWriteBuffer(self.id,
                                                       buf.id,
                                                       0, // don't block
                                                       offset as size_t,
                                                       size as size_t,
                                                       transmute(host_ptr),
                                                       wait_size,
                                                       wait_list_ptr,
                                                       &mut event_id)));
        }

        let event = Event{id: event_id};
        buf.register_write(event.clone());
        Ok(event)
    }

    fn read_buffer_raw<T: Sized>(self: &Self,
                                 buf: &Mem,
                                 offset: usize,
                                 size: usize,
                                 data: &mut [T]) -> Result<Event, Error> {
        let mut event_id: ll::Event = ptr::null_mut();
        let host_ptr = &mut data[0] as *mut T;
        let wait_list: Vec<ll::Event> = buf.read_events();
        let wait_size = wait_list.len() as u32;

        let wait_list_ptr: *const ll::Event = match wait_size {
            0 => ptr::null(),
            _ => &wait_list[0],
        };

        unsafe {
            try!(Error::check(ll::clEnqueueReadBuffer(self.id,
                                                      buf.id,
                                                      0, // don't block,
                                                      offset as size_t,
                                                      size as size_t,
                                                      transmute(host_ptr),
                                                      wait_size,
                                                      wait_list_ptr,
                                                      &mut event_id)));
        }

        let event = Event{id: event_id};
        buf.register_read(event.clone());
        Ok(event)
    }

    pub fn create_buffer(self: &Self,
                               size_bytes: usize) -> Result<Mem, Error> {
        let id = try!(self.alloc_ll_buffer(0, size_bytes));
        let mut tr = Mem::new(id);
        // one-byte write to place buffer on device and ensure
        // allocated memory is okay
        let _ = try!(self.write_buffer_raw(&mut tr,
                                           0,
                                           1,
                                           &[self]));
        Ok(tr)
    }

    pub fn write_buffer<'a, 'b, T: Sized + 'a>(self: &Self,
                                  mem: &'b mut Mem,
                                  slice: &'a [T]) -> Result<ReadLock<'a, T>, Error> {
        let size_bytes = size_of::<T>()*slice.len();
        let evt = try!(self.write_buffer_raw(mem,
                                             0,
                                             size_bytes,
                                             slice));
        Ok(ReadLock{ evt: evt, sl: slice })
    }

    pub fn read_buffer<'a, T: Sized>(self: &Self,
                                 mem: &Mem,
                                 slice: &'a mut [T]) -> Result<WriteLock<'a, T>, Error> {
        let size_bytes = size_of::<T>()*slice.len();
        let evt = try!(self.read_buffer_raw(mem,
                                            0,
                                            size_bytes,
                                            slice));
        Ok(WriteLock{ evt: evt, sl: slice })
    }

    fn next_mul(self: &Self, global: usize, local: usize) -> usize {
        if local % global == 0 {
            global
        } else {
            ((global/local)+1)*local
        }
    }

    pub fn run( self: &Self,
                kernel: &mut Kernel,
                local_size: (usize, usize, usize),
                global_size: (usize, usize, usize)) -> Result<Event, Error> {
        let events = kernel.run_events();
        let global_size_fixed = (self.next_mul(global_size.0, local_size.0),
                                self.next_mul(global_size.1, local_size.1),
                                self.next_mul(global_size.2, local_size.2));

        let local_vec = vec!(local_size.0 as size_t,
                             local_size.1 as size_t,
                             local_size.2 as size_t);
        let global_vec = vec!(global_size_fixed.0 as size_t,
                              global_size_fixed.1 as size_t,
                              global_size_fixed.2 as size_t);

        let mut event_id: ll::Event = ptr::null_mut();
        unsafe {
            try!(Error::check(ll::clEnqueueNDRangeKernel(self.id,
                                                         kernel.id,
                                                         3,
                                                         ptr::null(),
                                                         &global_vec[0],
                                                         &local_vec[0],
                                                         events.len() as u32,
                                                         &events[0],
                                                         &mut event_id)));
        }
        let event = Event{id: event_id};

        try!(kernel.register_run(event.clone()));
        Ok(event)
    }
}

impl Drop for CommandQueue {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseCommandQueue(self.id))
                .ok().expect("Error releasing command queue");
        }
    }
}

impl Clone for CommandQueue {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainCommandQueue(self.id))
                .ok().expect("Error retaining command queue");
        }
        CommandQueue{ id: self.id }
    }
}

<|endoftext|>


<commit_before>//! A type that can be treated as a mathematical ring.

use std::ops::{Add, Sub, Neg, Mul};

use abomonation::Abomonation;
use ::Data;

/// A type that can be treated as a mathematical ring.
pub trait Ring : Add<Self, Output=Self> + Sub<Self, Output=Self> + Neg<Output=Self> + Mul<Self, Output=Self> + ::std::marker::Sized + Data + Copy {
	/// Returns true if the element is the additive identity.
	fn is_zero(&self) -> bool;
	/// The additive identity.
	fn zero() -> Self;
}

impl Ring for isize {
	#[inline(always)] fn is_zero(&self) -> bool { *self == 0 }
	#[inline(always)] fn zero() -> Self { 0 }
}

/// The ring defined by a pair of ring elements.
#[derive(Copy, Ord, PartialOrd, Eq, PartialEq, Debug, Clone)]
pub struct RingPair<R1: Ring, R2: Ring> {
	element1: R1,
	element2: R2,
}

impl<R1: Ring, R2: Ring> RingPair<R1, R2> {
	/// Creates a new ring pair from two elements.
	#[inline(always)] pub fn new(elt1: R1, elt2: R2) -> Self {
		RingPair {
			element1: elt1,
			element2: elt2,
		}
	}
}

impl<R1: Ring, R2: Ring> Ring for RingPair<R1, R2> {
	#[inline(always)] fn is_zero(&self) -> bool { self.element1.is_zero() && self.element2.is_zero() }
	#[inline(always)] fn zero() -> Self { RingPair { element1: R1::zero(), element2: R2::zero() } }
}

impl<R1: Ring, R2: Ring> Add<RingPair<R1, R2>> for RingPair<R1, R2> {
	type Output = Self;
	#[inline(always)] fn add(self, rhs: Self) -> Self {
		RingPair {
			element1: self.element1 + rhs.element1,
			element2: self.element2 + rhs.element2,
		}
	}
}

impl<R1: Ring, R2: Ring> Sub<RingPair<R1, R2>> for RingPair<R1, R2> {
	type Output = RingPair<R1, R2>;
	#[inline(always)] fn sub(self, rhs: Self) -> Self {
		RingPair {
			element1: self.element1 - rhs.element1,
			element2: self.element2 - rhs.element2,
		}
	}
}

impl<R1: Ring, R2: Ring> Neg for RingPair<R1, R2> {
	type Output = Self;
	#[inline(always)] fn neg(self) -> Self {
		RingPair {
			element1: -self.element1,
			element2: -self.element2,
		}
	}
}

impl<R1: Ring, R2: Ring> Mul<RingPair<R1, R2>> for RingPair<R1, R2> {
	type Output = Self;
	#[inline(always)] fn mul(self, rhs: Self) -> Self {
		RingPair {
			element1: self.element1 * rhs.element1,
			element2: self.element2 * rhs.element2,
		}
	}
}

impl<R1: Ring, R2: Ring> Abomonation for RingPair<R1, R2> { }
<commit_msg>added i32 and i64<commit_after>//! A type that can be treated as a mathematical ring.

use std::ops::{Add, Sub, Neg, Mul};

use abomonation::Abomonation;
use ::Data;

/// A type that can be treated as a mathematical ring.
pub trait Ring : Add<Self, Output=Self> + Sub<Self, Output=Self> + Neg<Output=Self> + Mul<Self, Output=Self> + ::std::marker::Sized + Data + Copy {
	/// Returns true if the element is the additive identity.
	fn is_zero(&self) -> bool;
	/// The additive identity.
	fn zero() -> Self;
}

impl Ring for isize {
	#[inline(always)] fn is_zero(&self) -> bool { *self == 0 }
	#[inline(always)] fn zero() -> Self { 0 }
}

impl Ring for i64 {
	#[inline(always)] fn is_zero(&self) -> bool { *self == 0 }
	#[inline(always)] fn zero() -> Self { 0 }
}

impl Ring for i32 {
	#[inline(always)] fn is_zero(&self) -> bool { *self == 0 }
	#[inline(always)] fn zero() -> Self { 0 }
}

/// The ring defined by a pair of ring elements.
#[derive(Copy, Ord, PartialOrd, Eq, PartialEq, Debug, Clone)]
pub struct RingPair<R1: Ring, R2: Ring> {
	element1: R1,
	element2: R2,
}

impl<R1: Ring, R2: Ring> RingPair<R1, R2> {
	/// Creates a new ring pair from two elements.
	#[inline(always)] pub fn new(elt1: R1, elt2: R2) -> Self {
		RingPair {
			element1: elt1,
			element2: elt2,
		}
	}
}

impl<R1: Ring, R2: Ring> Ring for RingPair<R1, R2> {
	#[inline(always)] fn is_zero(&self) -> bool { self.element1.is_zero() && self.element2.is_zero() }
	#[inline(always)] fn zero() -> Self { RingPair { element1: R1::zero(), element2: R2::zero() } }
}

impl<R1: Ring, R2: Ring> Add<RingPair<R1, R2>> for RingPair<R1, R2> {
	type Output = Self;
	#[inline(always)] fn add(self, rhs: Self) -> Self {
		RingPair {
			element1: self.element1 + rhs.element1,
			element2: self.element2 + rhs.element2,
		}
	}
}

impl<R1: Ring, R2: Ring> Sub<RingPair<R1, R2>> for RingPair<R1, R2> {
	type Output = RingPair<R1, R2>;
	#[inline(always)] fn sub(self, rhs: Self) -> Self {
		RingPair {
			element1: self.element1 - rhs.element1,
			element2: self.element2 - rhs.element2,
		}
	}
}

impl<R1: Ring, R2: Ring> Neg for RingPair<R1, R2> {
	type Output = Self;
	#[inline(always)] fn neg(self) -> Self {
		RingPair {
			element1: -self.element1,
			element2: -self.element2,
		}
	}
}

impl<R1: Ring, R2: Ring> Mul<RingPair<R1, R2>> for RingPair<R1, R2> {
	type Output = Self;
	#[inline(always)] fn mul(self, rhs: Self) -> Self {
		RingPair {
			element1: self.element1 * rhs.element1,
			element2: self.element2 * rhs.element2,
		}
	}
}

impl<R1: Ring, R2: Ring> Abomonation for RingPair<R1, R2> { }
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::hash::Hash;
use std::rc::Rc;
// use std::cell::RefCell;

struct Rlru<K, V>
    where K: Eq + Hash
{
    cache: HashMap<K, Rc<Node<V>>>,
    head: Link<V>,
    tail: Link<V>,
    max_length: u32,
}

struct Node<T> {
    elem: T,
    prev: Link<T>,
    next: Link<T>,
}

impl<T> Node<T> {
    fn new(elem: T) -> Self {
        Node {
            elem: elem,
            prev: None,
            next: None,
        }
    }
}

type Link<T> = Option<Rc<Node<T>>>;

impl<K, V> Rlru<K, V>
    where K: Eq + Hash
{
    pub fn new() -> Self {
        Rlru {
            cache: HashMap::new(),
            head: None,
            tail: None,
            max_length: 0,
        }
    }

    fn length_upkeep(&mut self) -> &mut Self {
        let max = self.max_length as usize;
        match self.cache.len() {
            0...max => self,
            // placeholder. Will pop off LRU key.
            _ => self
        }
    }

    fn splice_node(&mut self, node: Node<V>) {
        // update node's prev/next pointers to link to each other
        // insert node at head of rlru.
    }

    fn push(&mut self, node: Node<V>) -> &mut Self {
        let node = Rc::new(node);
        self.head.take().map(|prev_head| {
            prev_head.prev = Some(node.clone());
            node.next = Some(prev_head);
        });
        self.head = Some(node.clone());
        self
    }

    fn pop(&mut self) {
        self.tail.take().map(|node| {
            if node.prev.is_none() {
                // have to worry about updating head.
                self.head.take();
            }
            self.tail = node.prev;
        });
    }

    pub fn get(&mut self, key: K) -> Option<&V> {
        match self.cache.entry(key) {
            Entry::Occupied(node) => {
                // splice node to front
            },
            Entry::Vacant(_) => None
        }
    }

    pub fn set(&mut self, key: K, elem: V) -> &mut Self {
        match self.cache.entry(key) {
            Entry::Occupied(node) => {
                // splice node to front & update value
                self
            },
            Entry::Vacant(_) =>  {
                // insert node to front & do ln upkeep
                self
            }
        }
    }
}
<commit_msg>internal list splicing<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::hash::Hash;
use std::rc::Rc;
use std::cell::RefCell;

struct Rlru<K, V>
    where K: Eq + Hash
{
    cache: HashMap<K, Rc<RefCell<Node<V>>>>,
    head: Link<V>,
    tail: Link<V>,
    max_length: u32,
}

struct Node<T> {
    elem: T,
    prev: Link<T>,
    next: Link<T>,
}

impl<T> Node<T> {
    fn new(elem: T) -> Self {
        Node {
            elem: elem,
            prev: None,
            next: None,
        }
    }
}

type Link<T> = Option<Rc<RefCell<Node<T>>>>;

impl<K, V> Rlru<K, V>
    where K: Eq + Hash
{
    pub fn new() -> Self {
        Rlru {
            cache: HashMap::new(),
            head: None,
            tail: None,
            max_length: 0,
        }
    }

    fn length_upkeep(&mut self) -> &mut Self {
        let max = self.max_length as usize;
        match self.cache.len() {
            0...max => self,
            // placeholder. Will pop off LRU key.
            _ => self
        }
    }

    fn splice_node(&mut self, node: Rc<RefCell<Node<V>>>) {
        // update node's prev/next pointers to link to each other
        {
            let node = node.borrow_mut();
            node.prev.map(|prev_node| {
                prev_node.borrow_mut().next = node.next.clone();
            });
            node.next.take().map(|next_node| {
                next_node.borrow_mut().prev = node.prev.take();
            });
        }
        // insert node at head of rlru.
        self.push(node);
    }

    fn push(&mut self, node: Rc<RefCell<Node<V>>>) -> &mut Self {
        self.head.take().map(|prev_head| {
            prev_head.borrow_mut().prev = Some(node.clone());
            node.borrow_mut().next = Some(prev_head);
        });
        self.head = Some(node.clone());
        self
    }

    fn pop(&mut self) {
        self.tail.take().map(|node| {
            if node.borrow_mut().prev.is_none() {
                // have to worry about updating head.
                self.head.take();
            }
            self.tail = node.borrow_mut().prev;
        });
    }

    pub fn get(&mut self, key: K) -> Option<&V> {
        match self.cache.entry(key) {
            Entry::Occupied(entry) => {
                // splice node to front
                let found = entry.get();
                self.splice_node(found.clone());
                Some(&found.as_ref().borrow().elem)
            },
            Entry::Vacant(_) => None
        }
    }

    pub fn set(&mut self, key: K, elem: V) -> &mut Self {
        match self.cache.entry(key) {
            Entry::Occupied(node) => {
                // splice node to front & update value
                self
            },
            Entry::Vacant(_) =>  {
                // insert node to front & do ln upkeep
                self
            }
        }
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use core::marker::PhantomData;
use core::ops::{Index, IndexMut};
use core::mem;

/// The number of entries in a page table.
pub const N_ENTRIES: usize = 512;

/// PML4 table
pub const PML4: *mut Table<PML4Level>
    = 0o177777_777_777_777_777_0000 as *mut _;

pub struct Table<L>
where L: TableLevel { entries: [Entry; N_ENTRIES]
                    , level_marker: PhantomData<L>
                    }

pub trait TableLevel {}
pub enum PML4Level {}
pub enum PDPTLevel {}
pub enum PDLevel   {}
pub enum PTLevel   {}

impl TableLevel for PML4Level {}
impl TableLevel for PDPTLevel {}
impl TableLevel for PDLevel   {}
impl TableLevel for PTLevel   {}

pub trait Sublevel: TableLevel {
    type NextLevel: TableLevel;
}
impl Sublevel for PML4Level {
    type NextLevel = PDPTLevel;
}
impl Sublevel for PDPTLevel {
    type NextLevel = PDLevel;
}
impl Sublevel for PDLevel {
    type NextLevel = PTLevel;
}

impl<L: TableLevel> Index<usize> for Table<L> {
    type Output = Entry;

    #[inline] fn index(&self, index: usize) -> &Entry {
        &self.entries[index]
    }
}

impl<L: TableLevel> IndexMut<usize> for Table<L> {
    #[inline] fn index_mut(&mut self, index: usize) -> &mut Entry {
        &mut self.entries[index]
    }
}

impl<L: TableLevel> Table<L>  {

    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused()
        }
    }

}

impl<L: Sublevel> Table<L> {

    fn next_table_addr(&self, index: usize) -> Option<usize> {
        let flags = self[index].flags();
        if flags.contains(PRESENT) && !flags.contains(HUGE_PAGE) {
            Some(((self as *const _ as usize) << 9) | (index << 12))
        } else {
            None
        }
    }

    pub fn next_table(&self, index: usize) -> Option<&Table<L::NextLevel>> {
        self.next_table_addr(index)
            .map(|addr| unsafe { &*(addr as *const _) })
    }

    pub fn next_table_mut(&self, index: usize)
                         -> Option<& mut Table<L::NextLevel>> {
        self.next_table_addr(index)
            .map(|addr| unsafe { &mut *(addr as *mut _) })
    }
}

// pub type PML4  = [PML4Entry; 512];
//
// /// A page directory pointer table.
// pub type PDPT  = [PDPTEntry; 512];
//
// /// A page directory.
// pub type PD    = [PDEntry; 512];
//
// /// A page table.
// pub type PT    = [PTEntry; 512];
pub struct Entry(u64);

bitflags! {
    flags EntryFlags: u64 {
        /// Present flag.
        /// Must be 1 to map a 2-MByte page or reference a page table.
        const PRESENT =         1 << 0,
        /// Writable flag.
        /// If 0, writes may not be allowed to the 2-MB region controlled
        /// by this entry
        const WRITABLE =        1 << 1
      , const USER_ACCESSIBLE = 1 << 2
      , const WRITE_THROUGH =   1 << 3
      , const NO_CACHE =        1 << 4
      , const ACCESSED =        1 << 5
      , const DIRTY =           1 << 6
      , const HUGE_PAGE =       1 << 7
      , const GLOBAL =          1 << 8
      , const NO_EXECUTE =      1 << 63
    }
}

impl Entry {
    #[inline] pub fn is_unused(&self) -> bool {
        self.0 == 0
    }
    #[inline] pub fn set_unused(&mut self) {
        self.0 = 0;
    }
    #[inline] pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    pub fn pointed_frame(&self) -> Option<*mut u8> {
        unsafe {
            if self.flags().contains(PRESENT) {
                Some(mem::transmute(self.0 & 0x000fffff_fffff000))
            } else { None }
        }
    }

    pub fn set(&mut self, frame: *mut u8, flags: EntryFlags) {
        assert!(frame as u64 & !0x000fffff_fffff000 == 0);
        self.0 = (frame as u64) | flags.bits();
    }

}
<commit_msg>[x86_64] Add Table.create_next() function to x86_64 page tables<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use alloc::{Allocator, PAGE_SIZE};

use core::marker::PhantomData;
use core::ops::{Index, IndexMut};
use core::mem;

/// The number of entries in a page table.
pub const N_ENTRIES: usize = 512;
pub const PAGE_TABLE_SIZE: usize = N_ENTRIES * PAGE_SIZE;

/// PML4 table
pub const PML4: *mut Table<PML4Level>
    = 0o177777_777_777_777_777_0000 as *mut _;

pub struct Table<L>
where L: TableLevel { entries: [Entry; N_ENTRIES]
                    , level_marker: PhantomData<L>
                    }

pub trait TableLevel {}
pub enum PML4Level {}
pub enum PDPTLevel {}
pub enum PDLevel   {}
pub enum PTLevel   {}

impl TableLevel for PML4Level {}
impl TableLevel for PDPTLevel {}
impl TableLevel for PDLevel   {}
impl TableLevel for PTLevel   {}

pub trait Sublevel: TableLevel {
    type NextLevel: TableLevel;
}
impl Sublevel for PML4Level {
    type NextLevel = PDPTLevel;
}
impl Sublevel for PDPTLevel {
    type NextLevel = PDLevel;
}
impl Sublevel for PDLevel {
    type NextLevel = PTLevel;
}

impl<L: TableLevel> Index<usize> for Table<L> {
    type Output = Entry;

    #[inline] fn index(&self, index: usize) -> &Entry {
        &self.entries[index]
    }
}

impl<L: TableLevel> IndexMut<usize> for Table<L> {
    #[inline] fn index_mut(&mut self, index: usize) -> &mut Entry {
        &mut self.entries[index]
    }
}

impl<L: TableLevel> Table<L>  {

    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused()
        }
    }

}

impl<L: Sublevel> Table<L> {

    fn next_table_addr(&self, index: usize) -> Option<usize> {
        let flags = self[index].flags();
        if flags.contains(PRESENT) && !flags.contains(HUGE_PAGE) {
            Some(((self as *const _ as usize) << 9) | (index << 12))
        } else {
            None
        }
    }

    pub fn next_table(&self, index: usize) -> Option<&Table<L::NextLevel>> {
        self.next_table_addr(index)
            .map(|addr| unsafe { &*(addr as *const _) })
    }

    pub fn next_table_mut(&self, index: usize)
                         -> Option<& mut Table<L::NextLevel>> {
        self.next_table_addr(index)
            .map(|addr| unsafe { &mut *(addr as *mut _) })
    }

    pub fn create_next<A>(&mut self, index: usize, alloc: &mut A)
                         -> &mut Table<L::NextLevel>
    where A: Allocator {
        if self.next_table(index).is_none() {
            assert!( !self.entries[index].flags().contains(HUGE_PAGE)
                   , "Couldn't create next table: huge pages not \
                      currently supported.");

            let frame = unsafe {
                alloc.allocate(PAGE_SIZE, PAGE_SIZE)// I hope that's right
                     .expect("Couldn't create next table: no \
                             frames  available!")
            };

            self.entries[index].set(frame, PRESENT | WRITABLE);
            self.next_table_mut(index).unwrap().zero();
        }
        self.next_table_mut(index).unwrap()
    }
}

// pub type PML4  = [PML4Entry; 512];
//
// /// A page directory pointer table.
// pub type PDPT  = [PDPTEntry; 512];
//
// /// A page directory.
// pub type PD    = [PDEntry; 512];
//
// /// A page table.
// pub type PT    = [PTEntry; 512];
pub struct Entry(u64);

bitflags! {
    flags EntryFlags: u64 {
        /// Present flag.
        /// Must be 1 to map a 2-MByte page or reference a page table.
        const PRESENT =         1 << 0,
        /// Writable flag.
        /// If 0, writes may not be allowed to the 2-MB region controlled
        /// by this entry
        const WRITABLE =        1 << 1
      , const USER_ACCESSIBLE = 1 << 2
      , const WRITE_THROUGH =   1 << 3
      , const NO_CACHE =        1 << 4
      , const ACCESSED =        1 << 5
      , const DIRTY =           1 << 6
      , const HUGE_PAGE =       1 << 7
      , const GLOBAL =          1 << 8
      , const NO_EXECUTE =      1 << 63
    }
}

impl Entry {
    #[inline] pub fn is_unused(&self) -> bool {
        self.0 == 0
    }
    #[inline] pub fn set_unused(&mut self) {
        self.0 = 0;
    }
    #[inline] pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    pub fn pointed_frame(&self) -> Option<*mut u8> {
        unsafe {
            if self.flags().contains(PRESENT) {
                Some(mem::transmute(self.0 & 0x000fffff_fffff000))
            } else { None }
        }
    }

    pub fn set(&mut self, frame: *mut u8, flags: EntryFlags) {
        assert!(frame as u64 & !0x000fffff_fffff000 == 0);
        self.0 = (frame as u64) | flags.bits();
    }

}
<|endoftext|>


<commit_before>// Copyright 2012 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.

use ast;
use codemap::{spanned, Spanned, mk_sp};
use parse::common::*; //resolve bug?
use parse::token;
use parse::parser::Parser;
use parse::token::INTERPOLATED;

// a parser that can parse attributes.
pub trait ParserAttr {
    fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> ;
    fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
    fn parse_inner_attrs_and_next(&mut self)
                                  -> (Vec<ast::Attribute> , Vec<ast::Attribute> );
    fn parse_meta_item(&mut self) -> @ast::MetaItem;
    fn parse_meta_seq(&mut self) -> Vec<@ast::MetaItem> ;
    fn parse_optional_meta(&mut self) -> Vec<@ast::MetaItem> ;
}

impl<'a> ParserAttr for Parser<'a> {
    // Parse attributes that appear before an item
    fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        loop {
            debug!("parse_outer_attributes: self.token={:?}",
                   self.token);
            match self.token {
              token::POUND => {
                attrs.push(self.parse_attribute(false));
              }
              token::DOC_COMMENT(s) => {
                let attr = ::attr::mk_sugared_doc_attr(
                    self.id_to_interned_str(s),
                    self.span.lo,
                    self.span.hi
                );
                if attr.node.style != ast::AttrOuter {
                  self.fatal("expected outer comment");
                }
                attrs.push(attr);
                self.bump();
              }
              _ => break
            }
        }
        return attrs;
    }

    // matches attribute = # ! [ meta_item ]
    //
    // if permit_inner is true, then a leading `!` indicates an inner
    // attribute
    fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute {
        debug!("parse_attributes: permit_inner={:?} self.token={:?}",
               permit_inner, self.token);
        let (span, value, mut style) = match self.token {
            token::POUND => {
                let lo = self.span.lo;
                self.bump();

                let style = if self.eat(&token::NOT) {
                    if !permit_inner {
                        self.span_err(self.span,
                                      "an inner attribute is not permitted in \
                                       this context");
                    }
                    ast::AttrInner
                } else {
                    ast::AttrOuter
                };

                self.expect(&token::LBRACKET);
                let meta_item = self.parse_meta_item();
                self.expect(&token::RBRACKET);

                let hi = self.span.hi;
                (mk_sp(lo, hi), meta_item, style)
            }
            _ => {
                let token_str = self.this_token_to_str();
                self.fatal(format!("expected `\\#` but found `{}`",
                                   token_str));
            }
        };

        if permit_inner && self.eat(&token::SEMI) {
            self.span_warn(span, "this inner attribute syntax is deprecated. \
                           The new syntax is `#![foo]`, with a bang and no semicolon.");
            style = ast::AttrInner;
        }

        return Spanned {
            span: span,
            node: ast::Attribute_ {
                style: style,
                value: value,
                is_sugared_doc: false
            }
        };
    }

    // Parse attributes that appear after the opening of an item. These should
    // be preceded by an exclaimation mark, but we accept and warn about one
    // terminated by a semicolon. In addition to a vector of inner attributes,
    // this function also returns a vector that may contain the first outer
    // attribute of the next item (since we can't know whether the attribute
    // is an inner attribute of the containing item or an outer attribute of
    // the first contained item until we see the semi).

    // matches inner_attrs* outer_attr?
    // you can make the 'next' field an Option, but the result is going to be
    // more useful as a vector.
    fn parse_inner_attrs_and_next(&mut self)
                                  -> (Vec<ast::Attribute> , Vec<ast::Attribute> ) {
        let mut inner_attrs: Vec<ast::Attribute> = Vec::new();
        let mut next_outer_attrs: Vec<ast::Attribute> = Vec::new();
        loop {
            let attr = match self.token {
                token::POUND => {
                    self.parse_attribute(true)
                }
                token::DOC_COMMENT(s) => {
                    self.bump();
                    ::attr::mk_sugared_doc_attr(self.id_to_interned_str(s),
                                                self.span.lo,
                                                self.span.hi)
                }
                _ => {
                    break;
                }
            };
            if attr.node.style == ast::AttrInner {
                inner_attrs.push(attr);
            } else {
                next_outer_attrs.push(attr);
                break;
            }
        }
        (inner_attrs, next_outer_attrs)
    }

    // matches meta_item = IDENT
    // | IDENT = lit
    // | IDENT meta_seq
    fn parse_meta_item(&mut self) -> @ast::MetaItem {
        match self.token {
            token::INTERPOLATED(token::NtMeta(e)) => {
                self.bump();
                return e
            }
            _ => {}
        }

        let lo = self.span.lo;
        let ident = self.parse_ident();
        let name = self.id_to_interned_str(ident);
        match self.token {
            token::EQ => {
                self.bump();
                let lit = self.parse_lit();
                // FIXME #623 Non-string meta items are not serialized correctly;
                // just forbid them for now
                match lit.node {
                    ast::LitStr(..) => {}
                    _ => {
                        self.span_err(
                            lit.span,
                            "non-string literals are not allowed in meta-items");
                    }
                }
                let hi = self.span.hi;
                @spanned(lo, hi, ast::MetaNameValue(name, lit))
            }
            token::LPAREN => {
                let inner_items = self.parse_meta_seq();
                let hi = self.span.hi;
                @spanned(lo, hi, ast::MetaList(name, inner_items))
            }
            _ => {
                let hi = self.last_span.hi;
                @spanned(lo, hi, ast::MetaWord(name))
            }
        }
    }

    // matches meta_seq = ( COMMASEP(meta_item) )
    fn parse_meta_seq(&mut self) -> Vec<@ast::MetaItem> {
        self.parse_seq(&token::LPAREN,
                       &token::RPAREN,
                       seq_sep_trailing_disallowed(token::COMMA),
                       |p| p.parse_meta_item()).node
    }

    fn parse_optional_meta(&mut self) -> Vec<@ast::MetaItem> {
        match self.token {
            token::LPAREN => self.parse_meta_seq(),
            _ => Vec::new()
        }
    }
}
<commit_msg>syntax: put the correct span on doc-comments inside a module.<commit_after>// Copyright 2012 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.

use ast;
use codemap::{spanned, Spanned, mk_sp, Span};
use parse::common::*; //resolve bug?
use parse::token;
use parse::parser::Parser;
use parse::token::INTERPOLATED;

// a parser that can parse attributes.
pub trait ParserAttr {
    fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> ;
    fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
    fn parse_inner_attrs_and_next(&mut self)
                                  -> (Vec<ast::Attribute> , Vec<ast::Attribute> );
    fn parse_meta_item(&mut self) -> @ast::MetaItem;
    fn parse_meta_seq(&mut self) -> Vec<@ast::MetaItem> ;
    fn parse_optional_meta(&mut self) -> Vec<@ast::MetaItem> ;
}

impl<'a> ParserAttr for Parser<'a> {
    // Parse attributes that appear before an item
    fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        loop {
            debug!("parse_outer_attributes: self.token={:?}",
                   self.token);
            match self.token {
              token::POUND => {
                attrs.push(self.parse_attribute(false));
              }
              token::DOC_COMMENT(s) => {
                let attr = ::attr::mk_sugared_doc_attr(
                    self.id_to_interned_str(s),
                    self.span.lo,
                    self.span.hi
                );
                if attr.node.style != ast::AttrOuter {
                  self.fatal("expected outer comment");
                }
                attrs.push(attr);
                self.bump();
              }
              _ => break
            }
        }
        return attrs;
    }

    // matches attribute = # ! [ meta_item ]
    //
    // if permit_inner is true, then a leading `!` indicates an inner
    // attribute
    fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute {
        debug!("parse_attributes: permit_inner={:?} self.token={:?}",
               permit_inner, self.token);
        let (span, value, mut style) = match self.token {
            token::POUND => {
                let lo = self.span.lo;
                self.bump();

                let style = if self.eat(&token::NOT) {
                    if !permit_inner {
                        self.span_err(self.span,
                                      "an inner attribute is not permitted in \
                                       this context");
                    }
                    ast::AttrInner
                } else {
                    ast::AttrOuter
                };

                self.expect(&token::LBRACKET);
                let meta_item = self.parse_meta_item();
                self.expect(&token::RBRACKET);

                let hi = self.span.hi;
                (mk_sp(lo, hi), meta_item, style)
            }
            _ => {
                let token_str = self.this_token_to_str();
                self.fatal(format!("expected `\\#` but found `{}`",
                                   token_str));
            }
        };

        if permit_inner && self.eat(&token::SEMI) {
            self.span_warn(span, "this inner attribute syntax is deprecated. \
                           The new syntax is `#![foo]`, with a bang and no semicolon.");
            style = ast::AttrInner;
        }

        return Spanned {
            span: span,
            node: ast::Attribute_ {
                style: style,
                value: value,
                is_sugared_doc: false
            }
        };
    }

    // Parse attributes that appear after the opening of an item. These should
    // be preceded by an exclaimation mark, but we accept and warn about one
    // terminated by a semicolon. In addition to a vector of inner attributes,
    // this function also returns a vector that may contain the first outer
    // attribute of the next item (since we can't know whether the attribute
    // is an inner attribute of the containing item or an outer attribute of
    // the first contained item until we see the semi).

    // matches inner_attrs* outer_attr?
    // you can make the 'next' field an Option, but the result is going to be
    // more useful as a vector.
    fn parse_inner_attrs_and_next(&mut self)
                                  -> (Vec<ast::Attribute> , Vec<ast::Attribute> ) {
        let mut inner_attrs: Vec<ast::Attribute> = Vec::new();
        let mut next_outer_attrs: Vec<ast::Attribute> = Vec::new();
        loop {
            let attr = match self.token {
                token::POUND => {
                    self.parse_attribute(true)
                }
                token::DOC_COMMENT(s) => {
                    // we need to get the position of this token before we bump.
                    let Span { lo, hi, .. } = self.span;
                    self.bump();
                    ::attr::mk_sugared_doc_attr(self.id_to_interned_str(s), lo, hi)
                }
                _ => {
                    break;
                }
            };
            if attr.node.style == ast::AttrInner {
                inner_attrs.push(attr);
            } else {
                next_outer_attrs.push(attr);
                break;
            }
        }
        (inner_attrs, next_outer_attrs)
    }

    // matches meta_item = IDENT
    // | IDENT = lit
    // | IDENT meta_seq
    fn parse_meta_item(&mut self) -> @ast::MetaItem {
        match self.token {
            token::INTERPOLATED(token::NtMeta(e)) => {
                self.bump();
                return e
            }
            _ => {}
        }

        let lo = self.span.lo;
        let ident = self.parse_ident();
        let name = self.id_to_interned_str(ident);
        match self.token {
            token::EQ => {
                self.bump();
                let lit = self.parse_lit();
                // FIXME #623 Non-string meta items are not serialized correctly;
                // just forbid them for now
                match lit.node {
                    ast::LitStr(..) => {}
                    _ => {
                        self.span_err(
                            lit.span,
                            "non-string literals are not allowed in meta-items");
                    }
                }
                let hi = self.span.hi;
                @spanned(lo, hi, ast::MetaNameValue(name, lit))
            }
            token::LPAREN => {
                let inner_items = self.parse_meta_seq();
                let hi = self.span.hi;
                @spanned(lo, hi, ast::MetaList(name, inner_items))
            }
            _ => {
                let hi = self.last_span.hi;
                @spanned(lo, hi, ast::MetaWord(name))
            }
        }
    }

    // matches meta_seq = ( COMMASEP(meta_item) )
    fn parse_meta_seq(&mut self) -> Vec<@ast::MetaItem> {
        self.parse_seq(&token::LPAREN,
                       &token::RPAREN,
                       seq_sep_trailing_disallowed(token::COMMA),
                       |p| p.parse_meta_item()).node
    }

    fn parse_optional_meta(&mut self) -> Vec<@ast::MetaItem> {
        match self.token {
            token::LPAREN => self.parse_meta_seq(),
            _ => Vec::new()
        }
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::collections::HashSet;

use rand::{thread_rng, Rng};

use serialize::base64::FromBase64;
use serialize::hex::ToHex;

use ssl::crypto::symm::{self, encrypt, decrypt};

fn pad_pkcs7(mut data: Vec<u8>, blocksize: usize) -> Vec<u8> {
    assert!(blocksize < 256);

    let len = data.len();
    let rem = len % blocksize;
    let pad = (blocksize - rem) as u8;

    for _ in 0..pad {
        data.push(pad);
    }

    data
}

fn unpad_pkcs7(mut data: Vec<u8>) -> Vec<u8> {
    let len = data.len();
    let pad = data[len - 1] as usize;
    data.truncate(len - pad);
    data
}

#[test]
fn set_2_9() {
    let mut data = "YELLOW SUBMARINE".to_string().into_bytes();
    data = pad_pkcs7(data, 20);
    assert_eq!("YELLOW SUBMARINE\x04\x04\x04\x04", &String::from_utf8_lossy(&data));
    data = "AAAABBBBCC".to_string().into_bytes();
    data = pad_pkcs7(data, 4);
    assert_eq!("AAAABBBBCC\x02\x02", &String::from_utf8_lossy(&data));
    data = "AAAABBBB".to_string().into_bytes();
    data = pad_pkcs7(data, 4);
    assert_eq!("AAAABBBB\x04\x04\x04\x04", &String::from_utf8_lossy(&data));
}

#[test]
fn test_unpad_pkcs7() {
    let mut data = "AAAABBBB\x04\x04\x04\x04".to_string().into_bytes();
    data = unpad_pkcs7(data);
    assert_eq!("AAAABBBB", &String::from_utf8_lossy(&data));
    data = "AAAABBBBCCC\x01".to_string().into_bytes();
    data = unpad_pkcs7(data);
    assert_eq!("AAAABBBBCCC", &String::from_utf8_lossy(&data));
}

fn encrypt_cbc(data: &[u8], key: &[u8], iv: &[u8], blocksize: usize) -> Vec<u8> {
    let mut data_ = data.to_vec();
    data_ = pad_pkcs7(data_, blocksize);

    let len = data_.len();
    let blocks = len / blocksize;
    let zeros = vec![0_u8; key.len()];
    let mut out: Vec<u8> = Vec::with_capacity(len);

    for i in 0..blocks {
        let mut m_i: Vec<u8> = Vec::with_capacity(blocksize);

        let data_view = &data_[i*blocksize..(i+1)*blocksize];
        if i == 0 {
            for j in 0..blocksize {
                m_i.push(data_view[j] ^ iv[j]);
            }
        } else {
            let out_view = &out[(i-1)*blocksize..i*blocksize];
            for j in 0..blocksize {
                m_i.push(data_view[j] ^ out_view[j]);
            }
        }

        m_i = encrypt(symm::Type::AES_128_ECB, key, &zeros, &m_i);
        m_i.truncate(blocksize);
        out.extend_from_slice(&m_i);
    }

    out
}

fn decrypt_cbc(data: &[u8], key: &[u8], iv: &[u8], blocksize: usize) -> Vec<u8> {
    assert!(data.len() % blocksize == 0, "data must be multiple length of blocksize");

    let blocks = data.len() / blocksize;
    let zeros = vec![0_u8; key.len()];
    let mut out: Vec<u8> = Vec::with_capacity(data.len());

    for i in 0..blocks {
        let iv_ = if i == 0 { iv } else { &zeros };

        let mut m_i =
            if i == blocks - 1 {
                let mut block = data[i*blocksize..(i+1)*blocksize].to_vec();
                block.extend_from_slice(&zeros);
                decrypt(symm::Type::AES_128_ECB, key, iv_, &block)
            } else {
                decrypt(symm::Type::AES_128_ECB, key, iv_, &data[i*blocksize..(i+2)*blocksize])
            };

        if i == 0 {
            for j in 0..blocksize {
                m_i[j] ^= iv[j];
            }
        } else {
            let data_view = &data[(i-1)*blocksize..i*blocksize];
            for j in 0..blocksize {
                m_i[j] ^= data_view[j];
            }
        }

        out.extend_from_slice(&m_i);
    }

    unpad_pkcs7(out)
}

pub fn set_2_10() {
    let mut f = File::open("./data/10.txt").unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    let bytes = s.from_base64().unwrap();

    let key = "YELLOW SUBMARINE".as_bytes();
    let iv = vec![0_u8; key.len()];

    let out1 = decrypt(symm::Type::AES_128_CBC, key, &iv, &bytes);
    let out2 = decrypt_cbc(&bytes, key, &iv, 16);

    let m1 = String::from_utf8_lossy(&out1);
    let m2 = String::from_utf8_lossy(&out2);

    assert_eq!(&m1, &m2);
}

#[test]
fn test_encrypt_cbc() {
    let data = "DOST THOU JEER AND T-TAUNT ME IN THE TEETH?".as_bytes();

    let key = "YELLOW SUBMARINE".as_bytes();
    let iv = vec![0_u8; key.len()];

    let out1 = encrypt(symm::Type::AES_128_CBC, key, &iv, data).to_hex();
    let out2 = encrypt_cbc(data, key, &iv, 16).to_hex();

    assert_eq!(&out1, &out2);
}

#[test]
fn test_encrypt_decrypt_cbc() {
    let data = "DOS'T THOU JEER AND T-TAUNT ME IN THE TEETH?".as_bytes();

    let key = "YELLOW SUBMARINE".as_bytes();
    let iv = vec![0_u8; key.len()];

    let cipher1 = encrypt(symm::Type::AES_128_CBC, key, &iv, data);
    let cipher2 = encrypt_cbc(data, key, &iv, 16);

    assert_eq!(cipher1.to_hex(), cipher2.to_hex());

    let out1 = decrypt(symm::Type::AES_128_CBC, key, &iv, &cipher1);
    let out2 = decrypt_cbc(&cipher2, key, &iv, 16);

    assert_eq!(out1.to_hex(), out2.to_hex());
}

#[derive(PartialEq, Eq, Debug)]
enum AESMode {
    EBC,
    CBC,
}

fn encryption_oracle(input: &[u8]) -> (AESMode, Vec<u8>) {
    let mut rng = thread_rng();

    let mut key = [0_u8; 16];
    rng.fill_bytes(&mut key);

    let mut iv = [0_u8; 16];
    rng.fill_bytes(&mut iv);

    let mut m: Vec<u8> = Vec::new();

    let pad_left_len: usize = rng.gen_range(5, 10);
    let pad_left = (0..pad_left_len).map(|_| rng.gen::<u8>()).collect::<Vec<_>>();

    let pad_right_len: usize = rng.gen_range(5, 10);
    let pad_right = (0..pad_right_len).map(|_| rng.gen::<u8>()).collect::<Vec<_>>();

    m.extend_from_slice(&pad_left);
    m.extend_from_slice(input);
    m.extend_from_slice(&pad_right);

    let mode = if rng.gen::<bool>() { AESMode::EBC } else { AESMode::CBC };

    let out = match mode {
            AESMode::EBC => decrypt(symm::Type::AES_128_ECB, &key, &iv, &m),
            AESMode::CBC => decrypt(symm::Type::AES_128_CBC, &key, &iv, &m),
        };

    (mode, out)
}

fn guess_mode(ciphertext: &[u8]) -> AESMode {
    let mut set = HashSet::new();
    for chunk in ciphertext.chunks(16) {
        let hex = chunk.to_hex();
        if set.contains(&hex) {
            return AESMode::EBC;
        }
        set.insert(hex);
    }
    AESMode::CBC
}

pub fn set_2_11() {
    // choose a plaintext which will force a repeated block only in EBC mode, regardless of
    // key, iv, and (small) random padding.
    let controlled_plaintext = "[AAAAAAAAAAAAAA][AAAAAAAAAAAAAA][AAAAAAAAAAAAAA]".as_bytes();
    let runs = 1000;

    for _ in 0..runs {
        let (mode, ciphertext) = encryption_oracle(controlled_plaintext);
        assert_eq!(mode, guess_mode(&ciphertext));
    }

    println!("Successfully guessed the correct AES 128 Mode {} times!", runs);
}

fn encryption_oracle_2(input: &[u8], unknown: &[u8], key: &[u8]) -> Vec<u8> {
    let iv = [0_u8; 16];

    let mut data: Vec<u8> = Vec::with_capacity(input.len() + unknown.len());
    data.extend_from_slice(input);
    data.extend_from_slice(unknown);

    encrypt(symm::Type::AES_128_ECB, key, &iv, &data)
}

pub fn set_2_12() {
    let mut rng = thread_rng();
    let unknown = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg\
                   aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq\
                   dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg\
                   YnkK".from_base64().unwrap();
    let mut key = [0_u8; 16];
    rng.fill_bytes(&mut key);

    // Determine blocksize
    let mut i = 1;
    let mut blocksize = 0;
    loop {
        let input = vec!['A' as u8; 2*i];
        let out = encryption_oracle_2(&input, &unknown, &key);

        let block1 = &out[0..i];
        let block2 = &out[i..2*i];
        if block1 == block2 {
            blocksize = i;
            break;
        }
        i += 1;
    }

    // Determine ciphertext length
    let len = encryption_oracle_2("".as_bytes(), &unknown, &key).len();
    let mut ctxt_len = 0;
    for i in 1..blocksize+1 {
        let input = vec!['A' as u8; i];
        let new_len = encryption_oracle_2(&input, &unknown, &key).len();
        if new_len != len {
            ctxt_len = new_len - blocksize - i;
            break;
        }
    }

    println!("blocksize = {}", blocksize);
    println!("ciphertext length = {}", ctxt_len);

    let mut queries = 0;

    // Decrypt ciphertext byte-by-byte
    let mut plaintext: Vec<u8> = Vec::with_capacity(ctxt_len);
    for i in 0..ctxt_len {
        for char_guess in 0...255 {
            let mut input: Vec<u8> = Vec::new();

            let k = (i as i32) - (blocksize as i32) + 1;

            for j in k..(i as i32) {
                if j < 0 {
                    input.push('A' as u8);
                } else {
                    input.push(plaintext[j as usize]);
                }
            }

            input.push(char_guess);

            for _ in 0..(blocksize - (i % blocksize)) - 1 {
                input.push('A' as u8);
            }

            let out = encryption_oracle_2(&input, &unknown, &key);
            queries += 1;

            let b_i = (i / blocksize) + 1;

            let block1 = &out[0..blocksize];
            let block2 = &out[b_i*blocksize..(b_i+1)*blocksize];

            if block1 == block2 {
                plaintext.push(char_guess);
                break;
            }
        }
    }

    println!("queries = {}", queries);
    println!("===");
    println!("{}", String::from_utf8_lossy(&plaintext));
}
<commit_msg>Finish Set 2.13 and improve 2.12 solution<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::collections::{HashSet, BTreeMap};

use rand::{thread_rng, Rng};

use serialize::base64::FromBase64;
use serialize::hex::ToHex;
use serialize::json::{Json, ToJson};

use ssl::crypto::symm::{self, encrypt, decrypt};

fn pad_pkcs7(mut data: Vec<u8>, blocksize: usize) -> Vec<u8> {
    assert!(blocksize < 256);

    let len = data.len();
    let rem = len % blocksize;
    let pad = (blocksize - rem) as u8;

    for _ in 0..pad {
        data.push(pad);
    }

    data
}

fn unpad_pkcs7(mut data: Vec<u8>) -> Vec<u8> {
    let len = data.len();
    let pad = data[len - 1] as usize;
    data.truncate(len - pad);
    data
}

#[test]
fn set_2_9() {
    let mut data = "YELLOW SUBMARINE".to_string().into_bytes();
    data = pad_pkcs7(data, 20);
    assert_eq!("YELLOW SUBMARINE\x04\x04\x04\x04", &String::from_utf8_lossy(&data));
    data = "AAAABBBBCC".to_string().into_bytes();
    data = pad_pkcs7(data, 4);
    assert_eq!("AAAABBBBCC\x02\x02", &String::from_utf8_lossy(&data));
    data = "AAAABBBB".to_string().into_bytes();
    data = pad_pkcs7(data, 4);
    assert_eq!("AAAABBBB\x04\x04\x04\x04", &String::from_utf8_lossy(&data));
}

#[test]
fn test_unpad_pkcs7() {
    let mut data = "AAAABBBB\x04\x04\x04\x04".to_string().into_bytes();
    data = unpad_pkcs7(data);
    assert_eq!("AAAABBBB", &String::from_utf8_lossy(&data));
    data = "AAAABBBBCCC\x01".to_string().into_bytes();
    data = unpad_pkcs7(data);
    assert_eq!("AAAABBBBCCC", &String::from_utf8_lossy(&data));
}

fn encrypt_cbc(data: &[u8], key: &[u8], iv: &[u8], blocksize: usize) -> Vec<u8> {
    let mut data_ = data.to_vec();
    data_ = pad_pkcs7(data_, blocksize);

    let len = data_.len();
    let blocks = len / blocksize;
    let zeros = vec![0_u8; key.len()];
    let mut out: Vec<u8> = Vec::with_capacity(len);

    for i in 0..blocks {
        let mut m_i: Vec<u8> = Vec::with_capacity(blocksize);

        let data_view = &data_[i*blocksize..(i+1)*blocksize];
        if i == 0 {
            for j in 0..blocksize {
                m_i.push(data_view[j] ^ iv[j]);
            }
        } else {
            let out_view = &out[(i-1)*blocksize..i*blocksize];
            for j in 0..blocksize {
                m_i.push(data_view[j] ^ out_view[j]);
            }
        }

        m_i = encrypt(symm::Type::AES_128_ECB, key, &zeros, &m_i);
        m_i.truncate(blocksize);
        out.extend_from_slice(&m_i);
    }

    out
}

fn decrypt_cbc(data: &[u8], key: &[u8], iv: &[u8], blocksize: usize) -> Vec<u8> {
    assert!(data.len() % blocksize == 0, "data must be multiple length of blocksize");

    let blocks = data.len() / blocksize;
    let zeros = vec![0_u8; key.len()];
    let mut out: Vec<u8> = Vec::with_capacity(data.len());

    for i in 0..blocks {
        let iv_ = if i == 0 { iv } else { &zeros };

        let mut m_i =
            if i == blocks - 1 {
                let mut block = data[i*blocksize..(i+1)*blocksize].to_vec();
                block.extend_from_slice(&zeros);
                decrypt(symm::Type::AES_128_ECB, key, iv_, &block)
            } else {
                decrypt(symm::Type::AES_128_ECB, key, iv_, &data[i*blocksize..(i+2)*blocksize])
            };

        if i == 0 {
            for j in 0..blocksize {
                m_i[j] ^= iv[j];
            }
        } else {
            let data_view = &data[(i-1)*blocksize..i*blocksize];
            for j in 0..blocksize {
                m_i[j] ^= data_view[j];
            }
        }

        out.extend_from_slice(&m_i);
    }

    unpad_pkcs7(out)
}

pub fn set_2_10() {
    let mut f = File::open("./data/10.txt").unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    let bytes = s.from_base64().unwrap();

    let key = "YELLOW SUBMARINE".as_bytes();
    let iv = vec![0_u8; key.len()];

    let out1 = decrypt(symm::Type::AES_128_CBC, key, &iv, &bytes);
    let out2 = decrypt_cbc(&bytes, key, &iv, 16);

    let m1 = String::from_utf8_lossy(&out1);
    let m2 = String::from_utf8_lossy(&out2);

    assert_eq!(&m1, &m2);
}

#[test]
fn test_encrypt_cbc() {
    let data = "DOST THOU JEER AND T-TAUNT ME IN THE TEETH?".as_bytes();

    let key = "YELLOW SUBMARINE".as_bytes();
    let iv = vec![0_u8; key.len()];

    let out1 = encrypt(symm::Type::AES_128_CBC, key, &iv, data).to_hex();
    let out2 = encrypt_cbc(data, key, &iv, 16).to_hex();

    assert_eq!(&out1, &out2);
}

#[test]
fn test_encrypt_decrypt_cbc() {
    let data = "DOS'T THOU JEER AND T-TAUNT ME IN THE TEETH?".as_bytes();

    let key = "YELLOW SUBMARINE".as_bytes();
    let iv = vec![0_u8; key.len()];

    let cipher1 = encrypt(symm::Type::AES_128_CBC, key, &iv, data);
    let cipher2 = encrypt_cbc(data, key, &iv, 16);

    assert_eq!(cipher1.to_hex(), cipher2.to_hex());

    let out1 = decrypt(symm::Type::AES_128_CBC, key, &iv, &cipher1);
    let out2 = decrypt_cbc(&cipher2, key, &iv, 16);

    assert_eq!(out1.to_hex(), out2.to_hex());
}

#[derive(PartialEq, Eq, Debug)]
enum AESMode {
    EBC,
    CBC,
}

fn encryption_oracle(input: &[u8]) -> (AESMode, Vec<u8>) {
    let mut rng = thread_rng();

    let mut key = [0_u8; 16];
    rng.fill_bytes(&mut key);

    let mut iv = [0_u8; 16];
    rng.fill_bytes(&mut iv);

    let mut m: Vec<u8> = Vec::new();

    let pad_left_len: usize = rng.gen_range(5, 10);
    let pad_left = (0..pad_left_len).map(|_| rng.gen::<u8>()).collect::<Vec<_>>();

    let pad_right_len: usize = rng.gen_range(5, 10);
    let pad_right = (0..pad_right_len).map(|_| rng.gen::<u8>()).collect::<Vec<_>>();

    m.extend_from_slice(&pad_left);
    m.extend_from_slice(input);
    m.extend_from_slice(&pad_right);

    let mode = if rng.gen::<bool>() { AESMode::EBC } else { AESMode::CBC };

    let out = match mode {
            AESMode::EBC => decrypt(symm::Type::AES_128_ECB, &key, &iv, &m),
            AESMode::CBC => decrypt(symm::Type::AES_128_CBC, &key, &iv, &m),
        };

    (mode, out)
}

fn guess_mode(ciphertext: &[u8]) -> AESMode {
    let mut set = HashSet::new();
    for chunk in ciphertext.chunks(16) {
        let hex = chunk.to_hex();
        if set.contains(&hex) {
            return AESMode::EBC;
        }
        set.insert(hex);
    }
    AESMode::CBC
}

pub fn set_2_11() {
    // choose a plaintext which will force a repeated block only in EBC mode, regardless of
    // key, iv, and (small) random padding.
    let controlled_plaintext = "[AAAAAAAAAAAAAA][AAAAAAAAAAAAAA][AAAAAAAAAAAAAA]".as_bytes();
    let runs = 1000;

    for _ in 0..runs {
        let (mode, ciphertext) = encryption_oracle(controlled_plaintext);
        assert_eq!(mode, guess_mode(&ciphertext));
    }

    println!("Successfully guessed the correct AES 128 Mode {} times!", runs);
}

fn encryption_oracle_2(input: &[u8], unknown: &[u8], key: &[u8]) -> Vec<u8> {
    let iv = [0_u8; 16];

    let mut data: Vec<u8> = Vec::with_capacity(input.len() + unknown.len());
    data.extend_from_slice(input);
    data.extend_from_slice(unknown);

    encrypt(symm::Type::AES_128_ECB, key, &iv, &data)
}

pub fn set_2_12() {
    // unknown text we will attempt to decode with attacker controlled input
    // to the encryption oracle
    let unknown = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg\
                   aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq\
                   dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg\
                   YnkK".from_base64().unwrap();
    let mut rng = thread_rng();
    let mut key = [0_u8; 16];
    rng.fill_bytes(&mut key);

    // Determine blocksize
    let mut i = 1;
    let blocksize;
    loop {
        let input = vec!['A' as u8; 2*i];
        let out = encryption_oracle_2(&input, &unknown, &key);

        let block1 = &out[0..i];
        let block2 = &out[i..2*i];
        if block1 == block2 {
            blocksize = i;
            break;
        }
        i += 1;
    }

    // Determine ciphertext length
    let len = encryption_oracle_2("".as_bytes(), &unknown, &key).len();
    let mut ctxt_len = 0;
    for i in 1..blocksize+1 {
        let input = vec!['A' as u8; i];
        let new_len = encryption_oracle_2(&input, &unknown, &key).len();
        if new_len != len {
            ctxt_len = new_len - blocksize - i;
            break;
        }
    }

    println!("blocksize = {}", blocksize);
    println!("ciphertext length = {}", ctxt_len);

    let mut queries = 0;

    // Decrypt ciphertext byte-by-byte
    let mut plaintext: Vec<u8> = Vec::with_capacity(ctxt_len);
    for i in 0..ctxt_len {
        let mut input: Vec<u8> = Vec::new();

        for char_guess in 0...255 {
            let k = (i as i32) - (blocksize as i32) + 1;

            for j in k..(i as i32) {
                if j < 0 {
                    input.push('A' as u8);
                } else {
                    input.push(plaintext[j as usize]);
                }
            }

            input.push(char_guess);
        }

        for _ in 0..(blocksize - (i % blocksize)) - 1 {
            input.push('A' as u8);
        }

        let out = encryption_oracle_2(&input, &unknown, &key);
        queries += 1;

        let b_i = (i / blocksize) + 256;
        let cipher_block = &out[b_i*blocksize..(b_i+1)*blocksize];

        // search for input block with same AES ECB output
        for char_guess in 0...255 {
            let j = char_guess as usize;
            let guess_block = &out[j*blocksize..(j+1)*blocksize];
            if guess_block == cipher_block {
                plaintext.push(char_guess);
                break;
            }
        }
    }

    println!("queries = {}", queries);
    println!("===");
    println!("{}", String::from_utf8_lossy(&plaintext));
}

fn parse_querystr(input: &str) -> Result<Json, ()> {
    let mut obj = BTreeMap::new();
    for pair in input.split('&') {
        let mut items = pair.split('=');
        match (items.next(), items.next(), items.next()) {
            (Some(key), Some(val), None) => {
                obj.insert(key.to_string(), Json::String(val.to_string()));
            },
            _ => {
                return Err(());
            }
        };
    }
    Ok(Json::Object(obj))
}

#[test]
fn test_parse_queryst() {
    let json = parse_querystr("foo=bar&baz=wanker@foobar.com").unwrap();
    let obj = json.as_object().unwrap();
    assert_eq!(obj["foo"], "bar".to_json());
    assert_eq!(obj["baz"], "wanker@foobar.com".to_json());
}

fn profile_for(email: &str) -> String {
    let email_clean = email.replace(|c| c == '=' || c == '&', "");
    format!("email={}&uid={}&role=user", email_clean, 10)
}

fn encryption_oracle_3(key: &[u8], input: &str) -> Vec<u8> {
    let plaintext = profile_for(input);
    let data = plaintext.as_bytes();
    let iv = [0_u8; 16];
    encrypt(symm::Type::AES_128_ECB, key, &iv, data)
}

fn decryption_oracle_3(key: &[u8], data: &[u8]) -> Json {
    let iv = [0_u8; 16];
    let plaintext = decrypt(symm::Type::AES_128_ECB, key, &iv, data);
    let string = String::from_utf8_lossy(&plaintext);
    parse_querystr(&string).unwrap()
}

#[test]
fn set_2_13() {
    let blocksize = 16;
    let mut rng = thread_rng();
    let mut key = [0_u8; 16];
    rng.fill_bytes(&mut key);

    // 0123456789012345|0123456789012345|0123456789012345|012345678912345
    // email=AAAAAAAAAA|adminPPPPPPPPPPP|AAA&uid=10&role=|userPPPPPPPPPPP
    //       ^^^^^^^^^^|^^^^^^^^^^^^^^^^|^^^
    //                     input

    let input = "AAAAAAAAAAadmin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0bAAA";
    let mut ciphertext = encryption_oracle_3(&key, input);

    // substitute the block with admin text in it to make an admin profile!
    let admin_block = &ciphertext[1*blocksize..2*blocksize].to_vec();
    &mut ciphertext[3*blocksize..4*blocksize].copy_from_slice(&admin_block);

    let json = decryption_oracle_3(&key, &ciphertext);
    let obj = json.as_object().unwrap();
    assert_eq!(obj["role"], "admin".to_json());
}
<|endoftext|>


<commit_before>use std::fmt;

use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};

struct Printer<'a, 'b> {
    output: &'a mut fmt::Formatter<'b>,
    stack: Vec<&'a str>,
}

impl fmt::Show for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            String(ref s) => {
                try!(write!(f, "\""));
                for ch in s.as_slice().chars() {
                    match ch {
                        '\u0008' => try!(write!(f, "\\b")),
                        '\u0009' => try!(write!(f, "\\t")),
                        '\u000a' => try!(write!(f, "\\n")),
                        '\u000c' => try!(write!(f, "\\f")),
                        '\u000d' => try!(write!(f, "\\r")),
                        '\u0022' => try!(write!(f, "\\\"")),
                        '\u005c' => try!(write!(f, "\\\\")),
                        ch => try!(write!(f, "{}", ch)),
                    }
                }
                write!(f, "\"")
            }
            Integer(i) => write!(f, "{}", i),
            Float(fp) => {
                try!(write!(f, "{}", fp));
                if fp % 1.0 == 0.0 { try!(write!(f, ".0")) }
                Ok(())
            }
            Boolean(b) => write!(f, "{}", b),
            Datetime(ref s) => write!(f, "{}", s),
            Array(ref a) => {
                match a.as_slice().head() {
                    Some(&Table(..)) => fail!("invalid toml array of tables"),
                    _ => {}
                }
                write!(f, "{}", a)
            }
            Table(ref t) => {
                let mut p = Printer { output: f, stack: Vec::new() };
                p.print(t)
            }
        }
    }
}

impl<'a, 'b> Printer<'a, 'b> {
    fn print(&mut self, table: &'a Table) -> fmt::Result {
        for (k, v) in table.iter() {
            match *v {
                Table(..) => continue,
                Array(ref a) => {
                    match a.as_slice().head() {
                        Some(&Table(..)) => continue,
                        _ => {}
                    }
                }
                _ => {}
            }
            try!(writeln!(self.output, "{} = {}", k, v));
        }
        for (k, v) in table.iter() {
            match *v {
                Table(ref inner) => {
                    self.stack.push(k.as_slice());
                    try!(writeln!(self.output, "\n[{}]",
                                  self.stack.connect(".")));
                    try!(self.print(inner));
                    self.stack.pop();
                }
                Array(ref inner) => {
                    match inner.as_slice().head() {
                        Some(&Table(..)) => {}
                        _ => continue
                    }
                    self.stack.push(k.as_slice());
                    for inner in inner.iter() {
                        try!(writeln!(self.output, "\n[[{}]]",
                                      self.stack.connect(".")));
                        match *inner {
                            Table(ref inner) => try!(self.print(inner)),
                            _ => fail!("non-heterogeneous toml array"),
                        }
                    }
                    self.stack.pop();
                }
                _ => {},
            }
        }
        Ok(())
    }
}

#[cfg(test)]
#[allow(warnings)]
mod tests {
    use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};
    use std::collections::TreeMap;

    macro_rules! map( ($($k:expr: $v:expr),*) => ({
        let mut _m = TreeMap::new();
        $(_m.insert($k.to_string(), $v);)*
        _m
    }) )

    #[test]
    fn simple_show() {
        assert_eq!(String("foo".to_string()).to_string().as_slice(),
                   "\"foo\"")
        assert_eq!(Integer(10).to_string().as_slice(),
                   "10")
        assert_eq!(Float(10.0).to_string().as_slice(),
                   "10.0")
        assert_eq!(Float(2.4).to_string().as_slice(),
                   "2.4")
        assert_eq!(Boolean(true).to_string().as_slice(),
                   "true")
        assert_eq!(Datetime("test".to_string()).to_string().as_slice(),
                   "test")
        assert_eq!(Array(vec![]).to_string().as_slice(),
                   "[]")
        assert_eq!(Array(vec![Integer(1), Integer(2)]).to_string().as_slice(),
                   "[1, 2]")
    }

    #[test]
    fn table() {
        assert_eq!(Table(map! { }).to_string().as_slice(),
                   "")
        assert_eq!(Table(map! { "test": Integer(2) }).to_string().as_slice(),
                   "test = 2\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Table(map! {
                            "test": String("wut".to_string())
                        })
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [test2]\n\
                    test = \"wut\"\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Table(map! {
                            "test": String("wut".to_string())
                        })
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [test2]\n\
                    test = \"wut\"\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Array(vec![Table(map! {
                            "test": String("wut".to_string())
                        })])
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [[test2]]\n\
                    test = \"wut\"\n")
    }
}

<commit_msg>Fix build break due to generalized type parameter bounds<commit_after>use std::fmt;

use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};

struct Printer<'a, 'b:'a> {
    output: &'a mut fmt::Formatter<'b>,
    stack: Vec<&'a str>,
}

impl fmt::Show for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            String(ref s) => {
                try!(write!(f, "\""));
                for ch in s.as_slice().chars() {
                    match ch {
                        '\u0008' => try!(write!(f, "\\b")),
                        '\u0009' => try!(write!(f, "\\t")),
                        '\u000a' => try!(write!(f, "\\n")),
                        '\u000c' => try!(write!(f, "\\f")),
                        '\u000d' => try!(write!(f, "\\r")),
                        '\u0022' => try!(write!(f, "\\\"")),
                        '\u005c' => try!(write!(f, "\\\\")),
                        ch => try!(write!(f, "{}", ch)),
                    }
                }
                write!(f, "\"")
            }
            Integer(i) => write!(f, "{}", i),
            Float(fp) => {
                try!(write!(f, "{}", fp));
                if fp % 1.0 == 0.0 { try!(write!(f, ".0")) }
                Ok(())
            }
            Boolean(b) => write!(f, "{}", b),
            Datetime(ref s) => write!(f, "{}", s),
            Array(ref a) => {
                match a.as_slice().head() {
                    Some(&Table(..)) => fail!("invalid toml array of tables"),
                    _ => {}
                }
                write!(f, "{}", a)
            }
            Table(ref t) => {
                let mut p = Printer { output: f, stack: Vec::new() };
                p.print(t)
            }
        }
    }
}

impl<'a, 'b> Printer<'a, 'b> {
    fn print(&mut self, table: &'a Table) -> fmt::Result {
        for (k, v) in table.iter() {
            match *v {
                Table(..) => continue,
                Array(ref a) => {
                    match a.as_slice().head() {
                        Some(&Table(..)) => continue,
                        _ => {}
                    }
                }
                _ => {}
            }
            try!(writeln!(self.output, "{} = {}", k, v));
        }
        for (k, v) in table.iter() {
            match *v {
                Table(ref inner) => {
                    self.stack.push(k.as_slice());
                    try!(writeln!(self.output, "\n[{}]",
                                  self.stack.connect(".")));
                    try!(self.print(inner));
                    self.stack.pop();
                }
                Array(ref inner) => {
                    match inner.as_slice().head() {
                        Some(&Table(..)) => {}
                        _ => continue
                    }
                    self.stack.push(k.as_slice());
                    for inner in inner.iter() {
                        try!(writeln!(self.output, "\n[[{}]]",
                                      self.stack.connect(".")));
                        match *inner {
                            Table(ref inner) => try!(self.print(inner)),
                            _ => fail!("non-heterogeneous toml array"),
                        }
                    }
                    self.stack.pop();
                }
                _ => {},
            }
        }
        Ok(())
    }
}

#[cfg(test)]
#[allow(warnings)]
mod tests {
    use {Value, String, Integer, Float, Boolean, Datetime, Array, Table};
    use std::collections::TreeMap;

    macro_rules! map( ($($k:expr: $v:expr),*) => ({
        let mut _m = TreeMap::new();
        $(_m.insert($k.to_string(), $v);)*
        _m
    }) )

    #[test]
    fn simple_show() {
        assert_eq!(String("foo".to_string()).to_string().as_slice(),
                   "\"foo\"")
        assert_eq!(Integer(10).to_string().as_slice(),
                   "10")
        assert_eq!(Float(10.0).to_string().as_slice(),
                   "10.0")
        assert_eq!(Float(2.4).to_string().as_slice(),
                   "2.4")
        assert_eq!(Boolean(true).to_string().as_slice(),
                   "true")
        assert_eq!(Datetime("test".to_string()).to_string().as_slice(),
                   "test")
        assert_eq!(Array(vec![]).to_string().as_slice(),
                   "[]")
        assert_eq!(Array(vec![Integer(1), Integer(2)]).to_string().as_slice(),
                   "[1, 2]")
    }

    #[test]
    fn table() {
        assert_eq!(Table(map! { }).to_string().as_slice(),
                   "")
        assert_eq!(Table(map! { "test": Integer(2) }).to_string().as_slice(),
                   "test = 2\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Table(map! {
                            "test": String("wut".to_string())
                        })
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [test2]\n\
                    test = \"wut\"\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Table(map! {
                            "test": String("wut".to_string())
                        })
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [test2]\n\
                    test = \"wut\"\n")
        assert_eq!(Table(map! {
                        "test": Integer(2),
                        "test2": Array(vec![Table(map! {
                            "test": String("wut".to_string())
                        })])
                   }).to_string().as_slice(),
                   "test = 2\n\
                    \n\
                    [[test2]]\n\
                    test = \"wut\"\n")
    }
}

<|endoftext|>


<commit_before>use std::fmt;
use std::io::{self, Read};

use hyper;
use hyper::mime;
use hyper::client::Client;
use hyper::error::Error as HyperError;
use hyper::header::{Header, HeaderFormat, ContentType};

#[derive(Clone, Debug)]
pub struct Action(String);

impl Action {

    pub fn new(action: &str) -> Action {
        Action(action.into())
    }

}

impl Header for Action {

    fn header_name() -> &'static str {
        "SOAPAction"
    }

    #[allow(unused_variables)]
    fn parse_header(raw: &[Vec<u8>]) -> hyper::Result<Action> {
        // Leave unimplemented as we shouldn't need it.
        unimplemented!();
    }

}

impl HeaderFormat for Action {

    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.0)
    }

}

pub enum Error {
    HttpError(HyperError),
    IoError(io::Error),
}

impl From<HyperError> for Error {
    fn from(err: HyperError) -> Error {
        Error::HttpError(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

pub fn send(url: &str, action: Action, body: &str) -> Result<String, Error>  {
    let client = Client::new();
    let mut resp = try!(client.post(url)
        .header(action)
        .header(ContentType(mime::Mime(mime::TopLevel::Text, mime::SubLevel::Xml, Vec::new())))
        .body(body)
        .send());

    let mut text = String::new();
    try!(resp.read_to_string(&mut text));
    Ok(text)
}
<commit_msg>Implement async soap requests<commit_after>use std::fmt;
use std::string::FromUtf8Error;
use std::io::{self};

use futures::{Future,Stream};
use futures::future;
use tokio_core::reactor::{Core,Handle};
use hyper;
use hyper::{Client,Request,Post};
use hyper::error::Error as HyperError;
use hyper::header::{Header, ContentType, Raw, Formatter};

#[derive(Clone, Debug)]
pub struct Action(String);

impl Action {

    pub fn new(action: &str) -> Action {
        Action(action.into())
    }

}

impl Header for Action {

    fn header_name() -> &'static str {
        "SOAPAction"
    }

    #[allow(unused_variables)]
    fn parse_header(raw: &Raw) -> hyper::Result<Action> {
        // Leave unimplemented as we shouldn't need it.
        unimplemented!();
    }

    fn fmt_header(&self, f: &mut Formatter) -> fmt::Result {
        f.fmt_line(&self.0)
    }

}

pub enum Error {
    HttpError(HyperError),
    IoError(io::Error),
}

impl From<HyperError> for Error {
    fn from(err: HyperError) -> Error {
        Error::HttpError(err)
    }
}

impl From<hyper::error::UriError> for Error {
    fn from(err: hyper::error::UriError) -> Error {
        Error::HttpError(HyperError::from(err))
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::HttpError(HyperError::from(err))
    }
}

pub fn send(url: &str, action: Action, body: &str) -> Result<String, Error>  {
    let mut core = Core::new()?;
    let handle = core.handle();
    core.run( send_async(url, action, body, &handle) )
}

pub fn send_async(url: &str, action: Action, body: &str, handle: &Handle) -> Box<Future<Item=String, Error=Error>>   {
    let client = Client::new(&handle);
    let uri = match url.parse() {
        Ok(uri) => uri,
        Err(err) => return Box::new(future::err(Error::from(err)))
    };
    let mut req = Request::new(Post, uri);
    req.headers_mut().set(action);
    req.headers_mut().set(ContentType::xml());
    req.set_body(body.to_owned());
    let future = client.request(req)
        .and_then(|resp| resp.body().concat2() )
        .map_err(|err| Error::from(err) )
        .and_then(|bytes| String::from_utf8(bytes.to_vec()).map_err(|err| Error::from(err) ) );
    Box::new(future)
}
<|endoftext|>


<commit_before>use std::fmt;
use std::string::FromUtf8Error;
use std::io;

use futures::{Future, Stream};
use futures::future;
use tokio_core::reactor::Handle;
use hyper;
use hyper::{Client, Request, Post};
use hyper::error::Error as HyperError;
use hyper::header::{Header, ContentType, Raw, Formatter};

#[derive(Clone, Debug)]
pub struct Action(String);

impl Action {
    pub fn new(action: &str) -> Action {
        Action(action.into())
    }
}

impl Header for Action {
    fn header_name() -> &'static str {
        "SOAPAction"
    }

    #[allow(unused_variables)]
    fn parse_header(raw: &Raw) -> hyper::Result<Action> {
        // Leave unimplemented as we shouldn't need it.
        unimplemented!();
    }

    fn fmt_header(&self, f: &mut Formatter) -> fmt::Result {
        f.fmt_line(&self.0)
    }
}

pub enum Error {
    HttpError(HyperError),
    IoError(io::Error),
}

impl From<HyperError> for Error {
    fn from(err: HyperError) -> Error {
        Error::HttpError(err)
    }
}

impl From<hyper::error::UriError> for Error {
    fn from(err: hyper::error::UriError) -> Error {
        Error::HttpError(HyperError::from(err))
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::HttpError(HyperError::from(err))
    }
}

pub fn send_async(
    url: &str,
    action: Action,
    body: &str,
    handle: &Handle,
) -> Box<Future<Item = String, Error = Error>> {
    let client = Client::new(&handle);
    let uri = match url.parse() {
        Ok(uri) => uri,
        Err(err) => return Box::new(future::err(Error::from(err))),
    };
    let mut req = Request::new(Post, uri);
    req.headers_mut().set(action);
    req.headers_mut().set(ContentType::xml());
    req.set_body(body.to_owned());
    let future = client
        .request(req)
        .and_then(|resp| resp.body().concat2())
        .map_err(|err| Error::from(err))
        .and_then(|bytes| {
            String::from_utf8(bytes.to_vec()).map_err(|err| Error::from(err))
        });
    Box::new(future)
}
<commit_msg>Set content length, FritzBox requires this<commit_after>use std::fmt;
use std::string::FromUtf8Error;
use std::io;

use futures::{Future, Stream};
use futures::future;
use tokio_core::reactor::Handle;
use hyper;
use hyper::{Client, Request, Post};
use hyper::error::Error as HyperError;
use hyper::header::{Header, ContentType, ContentLength, Raw, Formatter};

#[derive(Clone, Debug)]
pub struct Action(String);

impl Action {
    pub fn new(action: &str) -> Action {
        Action(action.into())
    }
}

impl Header for Action {
    fn header_name() -> &'static str {
        "SOAPAction"
    }

    #[allow(unused_variables)]
    fn parse_header(raw: &Raw) -> hyper::Result<Action> {
        // Leave unimplemented as we shouldn't need it.
        unimplemented!();
    }

    fn fmt_header(&self, f: &mut Formatter) -> fmt::Result {
        f.fmt_line(&self.0)
    }
}

pub enum Error {
    HttpError(HyperError),
    IoError(io::Error),
}

impl From<HyperError> for Error {
    fn from(err: HyperError) -> Error {
        Error::HttpError(err)
    }
}

impl From<hyper::error::UriError> for Error {
    fn from(err: hyper::error::UriError) -> Error {
        Error::HttpError(HyperError::from(err))
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(err: FromUtf8Error) -> Error {
        Error::HttpError(HyperError::from(err))
    }
}

pub fn send_async(
    url: &str,
    action: Action,
    body: &str,
    handle: &Handle,
) -> Box<Future<Item = String, Error = Error>> {
    let client = Client::new(&handle);
    let uri = match url.parse() {
        Ok(uri) => uri,
        Err(err) => return Box::new(future::err(Error::from(err))),
    };
    let mut req = Request::new(Post, uri);
    req.headers_mut().set(action);
    req.headers_mut().set(ContentType::xml());
    req.headers_mut().set(ContentLength(body.len() as u64));
    req.set_body(body.to_owned());
    let future = client
        .request(req)
        .and_then(|resp| resp.body().concat2())
        .map_err(|err| Error::from(err))
        .and_then(|bytes| {
            String::from_utf8(bytes.to_vec()).map_err(|err| Error::from(err))
        });
    Box::new(future)
}
<|endoftext|>