<commit_before>use std::default::Default;
use std::env;
use std::fmt;
use std::time::{SystemTime, UNIX_EPOCH};

use crate::Value;
use r2d2_redis::{r2d2, redis, RedisConnectionManager};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use serde_json;

const REDIS_URL_ENV: &str = "REDIS_URL";
const REDIS_URL_DEFAULT: &str = "redis://127.0.0.1/";
pub type RedisPooledConnection = r2d2::PooledConnection<RedisConnectionManager>;
pub type RedisPool = r2d2::Pool<RedisConnectionManager>;

#[derive(Debug)]
pub struct ClientError {
    kind: ErrorKind,
}

#[derive(Debug)]
enum ErrorKind {
    Redis(redis::RedisError),
    PoolInit(r2d2::Error),
}

pub fn create_redis_pool() -> Result<RedisPool, ClientError> {
    let redis_url =
        &env::var(&REDIS_URL_ENV.to_owned()).unwrap_or_else(|_| REDIS_URL_DEFAULT.to_owned());
    let url = redis::parse_redis_url(redis_url).unwrap();
    let manager = RedisConnectionManager::new(url).unwrap();
    r2d2::Pool::new(manager).map_err(|err| ClientError {
        kind: ErrorKind::PoolInit(err),
    })
}

pub struct Job {
    pub class: String,
    pub args: Vec<Value>,
    pub retry: i64,
    pub queue: String,
    pub jid: String,
    pub created_at: u64,
    pub enqueued_at: u64,
}

impl fmt::Display for ClientError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::Redis(ref err) => err.fmt(f),
            ErrorKind::PoolInit(ref err) => err.fmt(f),
        }
    }
}

impl From<redis::RedisError> for ClientError {
    fn from(error: redis::RedisError) -> ClientError {
        ClientError {
            kind: ErrorKind::Redis(error),
        }
    }
}

impl From<r2d2::Error> for ClientError {
    fn from(error: r2d2::Error) -> ClientError {
        ClientError {
            kind: ErrorKind::PoolInit(error),
        }
    }
}

impl Default for JobOpts {
    fn default() -> JobOpts {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs() as u64;
        let jid = thread_rng()
            .sample_iter(&Alphanumeric)
            .take(24)
            .collect::<String>();
        JobOpts {
            retry: 25,
            queue: "default".to_string(),
            jid,
            created_at: now,
            enqueued_at: now,
        }
    }
}

pub struct JobOpts {
    pub retry: i64,
    pub queue: String,
    pub jid: String,
    pub created_at: u64,
    pub enqueued_at: u64,
}

/// # Examples
///
/// ```
/// use std::default::Default;
/// use sidekiq::Value;
/// use sidekiq::{Job, JobOpts};
///
/// // Create a job
/// let class = "MyClass".to_string();
/// let job_opts = JobOpts {
///     queue: "test".to_string(),
///     ..Default::default()
/// };
/// let job = Job::new(class, vec![sidekiq::Value::Null], job_opts);
/// ```
impl Job {
    pub fn new(class: String, args: Vec<Value>, opts: JobOpts) -> Job {
        Job {
            class,
            args,
            retry: opts.retry,
            queue: opts.queue,
            jid: opts.jid,
            created_at: opts.created_at,
            enqueued_at: opts.enqueued_at,
        }
    }
}

impl Serialize for Job {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut s = serializer.serialize_struct("Job", 7)?;
        s.serialize_field("class", &self.class)?;
        s.serialize_field("args", &self.args)?;
        s.serialize_field("retry", &self.retry)?;
        s.serialize_field("queue", &self.queue)?;
        s.serialize_field("jid", &self.jid)?;
        s.serialize_field("created_at", &self.created_at)?;
        s.serialize_field("enqueued_at", &self.enqueued_at)?;
        s.end()
    }
}

pub struct ClientOpts {
    pub namespace: Option<String>,
}

impl Default for ClientOpts {
    fn default() -> ClientOpts {
        ClientOpts { namespace: None }
    }
}

pub struct Client {
    pub redis_pool: RedisPool,
    pub namespace: Option<String>,
}

/// # Examples
///
/// ```
///
/// use sidekiq::{Job, Value};
/// use sidekiq::{Client, ClientOpts, create_redis_pool};
///
/// let ns = "test";
/// let client_opts = ClientOpts {
///     namespace: Some(ns.to_string()),
///     ..Default::default()
/// };
/// let pool = create_redis_pool().unwrap();
/// let client = Client::new(pool, client_opts);
/// let class = "MyClass".to_string();
/// let job = Job::new(class, vec![sidekiq::Value::Null], Default::default());
/// match client.push(job) {
///     Ok(_) => {},
///     Err(err) => {
///         println!("Sidekiq push failed: {}", err);
///     },
/// }
/// ```
impl Client {
    pub fn new(redis_pool: RedisPool, opts: ClientOpts) -> Client {
        Client {
            redis_pool,
            namespace: opts.namespace,
        }
    }

    fn connect(&self) -> Result<RedisPooledConnection, ClientError> {
        match self.redis_pool.get() {
            Ok(conn) => Ok(conn),
            Err(err) => Err(ClientError {
                kind: ErrorKind::PoolInit(err),
            }),
        }
    }

    pub fn push(&self, job: Job) -> Result<(), ClientError> {
        self.raw_push(&[job])
    }

    pub fn push_bulk(&self, jobs: &[Job]) -> Result<(), ClientError> {
        self.raw_push(jobs)
    }

    fn raw_push(&self, payloads: &[Job]) -> Result<(), ClientError> {
        let payload = &payloads[0];
        let to_push = payloads
            .iter()
            .map(|entry| serde_json::to_string(&entry).unwrap())
            .collect::<Vec<_>>();
        match self.connect() {
            Ok(mut conn) => redis::pipe()
                .atomic()
                .cmd("SADD")
                .arg("queues")
                .arg(payload.queue.to_string())
                .ignore()
                .cmd("LPUSH")
                .arg(self.queue_name(&payload.queue))
                .arg(to_push)
                .query(&mut *conn)
                .map_err(|err| ClientError {
                    kind: ErrorKind::Redis(err),
                }),
            Err(err) => Err(err),
        }
    }

    fn queue_name(&self, queue: &str) -> String {
        if let Some(ref ns) = self.namespace {
            format!("{}:queue:{}", ns, queue)
        } else {
            format!("queue:{}", queue)
        }
    }
}
<commit_msg>Implement std::error::Error for ClientError<commit_after>use std::default::Default;
use std::env;
use std::fmt;
use std::time::{SystemTime, UNIX_EPOCH};

use crate::Value;
use r2d2_redis::{r2d2, redis, RedisConnectionManager};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use serde_json;

const REDIS_URL_ENV: &str = "REDIS_URL";
const REDIS_URL_DEFAULT: &str = "redis://127.0.0.1/";
pub type RedisPooledConnection = r2d2::PooledConnection<RedisConnectionManager>;
pub type RedisPool = r2d2::Pool<RedisConnectionManager>;

#[derive(Debug)]
pub struct ClientError {
    kind: ErrorKind,
}

#[derive(Debug)]
enum ErrorKind {
    Redis(redis::RedisError),
    PoolInit(r2d2::Error),
}

impl std::error::Error for ClientError {}

pub fn create_redis_pool() -> Result<RedisPool, ClientError> {
    let redis_url =
        &env::var(&REDIS_URL_ENV.to_owned()).unwrap_or_else(|_| REDIS_URL_DEFAULT.to_owned());
    let url = redis::parse_redis_url(redis_url).unwrap();
    let manager = RedisConnectionManager::new(url).unwrap();
    r2d2::Pool::new(manager).map_err(|err| ClientError {
        kind: ErrorKind::PoolInit(err),
    })
}

pub struct Job {
    pub class: String,
    pub args: Vec<Value>,
    pub retry: i64,
    pub queue: String,
    pub jid: String,
    pub created_at: u64,
    pub enqueued_at: u64,
}

impl fmt::Display for ClientError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::Redis(ref err) => err.fmt(f),
            ErrorKind::PoolInit(ref err) => err.fmt(f),
        }
    }
}

impl From<redis::RedisError> for ClientError {
    fn from(error: redis::RedisError) -> ClientError {
        ClientError {
            kind: ErrorKind::Redis(error),
        }
    }
}

impl From<r2d2::Error> for ClientError {
    fn from(error: r2d2::Error) -> ClientError {
        ClientError {
            kind: ErrorKind::PoolInit(error),
        }
    }
}

impl Default for JobOpts {
    fn default() -> JobOpts {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs() as u64;
        let jid = thread_rng()
            .sample_iter(&Alphanumeric)
            .take(24)
            .collect::<String>();
        JobOpts {
            retry: 25,
            queue: "default".to_string(),
            jid,
            created_at: now,
            enqueued_at: now,
        }
    }
}

pub struct JobOpts {
    pub retry: i64,
    pub queue: String,
    pub jid: String,
    pub created_at: u64,
    pub enqueued_at: u64,
}

/// # Examples
///
/// ```
/// use std::default::Default;
/// use sidekiq::Value;
/// use sidekiq::{Job, JobOpts};
///
/// // Create a job
/// let class = "MyClass".to_string();
/// let job_opts = JobOpts {
///     queue: "test".to_string(),
///     ..Default::default()
/// };
/// let job = Job::new(class, vec![sidekiq::Value::Null], job_opts);
/// ```
impl Job {
    pub fn new(class: String, args: Vec<Value>, opts: JobOpts) -> Job {
        Job {
            class,
            args,
            retry: opts.retry,
            queue: opts.queue,
            jid: opts.jid,
            created_at: opts.created_at,
            enqueued_at: opts.enqueued_at,
        }
    }
}

impl Serialize for Job {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut s = serializer.serialize_struct("Job", 7)?;
        s.serialize_field("class", &self.class)?;
        s.serialize_field("args", &self.args)?;
        s.serialize_field("retry", &self.retry)?;
        s.serialize_field("queue", &self.queue)?;
        s.serialize_field("jid", &self.jid)?;
        s.serialize_field("created_at", &self.created_at)?;
        s.serialize_field("enqueued_at", &self.enqueued_at)?;
        s.end()
    }
}

pub struct ClientOpts {
    pub namespace: Option<String>,
}

impl Default for ClientOpts {
    fn default() -> ClientOpts {
        ClientOpts { namespace: None }
    }
}

pub struct Client {
    pub redis_pool: RedisPool,
    pub namespace: Option<String>,
}

/// # Examples
///
/// ```
///
/// use sidekiq::{Job, Value};
/// use sidekiq::{Client, ClientOpts, create_redis_pool};
///
/// let ns = "test";
/// let client_opts = ClientOpts {
///     namespace: Some(ns.to_string()),
///     ..Default::default()
/// };
/// let pool = create_redis_pool().unwrap();
/// let client = Client::new(pool, client_opts);
/// let class = "MyClass".to_string();
/// let job = Job::new(class, vec![sidekiq::Value::Null], Default::default());
/// match client.push(job) {
///     Ok(_) => {},
///     Err(err) => {
///         println!("Sidekiq push failed: {}", err);
///     },
/// }
/// ```
impl Client {
    pub fn new(redis_pool: RedisPool, opts: ClientOpts) -> Client {
        Client {
            redis_pool,
            namespace: opts.namespace,
        }
    }

    fn connect(&self) -> Result<RedisPooledConnection, ClientError> {
        match self.redis_pool.get() {
            Ok(conn) => Ok(conn),
            Err(err) => Err(ClientError {
                kind: ErrorKind::PoolInit(err),
            }),
        }
    }

    pub fn push(&self, job: Job) -> Result<(), ClientError> {
        self.raw_push(&[job])
    }

    pub fn push_bulk(&self, jobs: &[Job]) -> Result<(), ClientError> {
        self.raw_push(jobs)
    }

    fn raw_push(&self, payloads: &[Job]) -> Result<(), ClientError> {
        let payload = &payloads[0];
        let to_push = payloads
            .iter()
            .map(|entry| serde_json::to_string(&entry).unwrap())
            .collect::<Vec<_>>();
        match self.connect() {
            Ok(mut conn) => redis::pipe()
                .atomic()
                .cmd("SADD")
                .arg("queues")
                .arg(payload.queue.to_string())
                .ignore()
                .cmd("LPUSH")
                .arg(self.queue_name(&payload.queue))
                .arg(to_push)
                .query(&mut *conn)
                .map_err(|err| ClientError {
                    kind: ErrorKind::Redis(err),
                }),
            Err(err) => Err(err),
        }
    }

    fn queue_name(&self, queue: &str) -> String {
        if let Some(ref ns) = self.namespace {
            format!("{}:queue:{}", ns, queue)
        } else {
            format!("queue:{}", queue)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Buffer whose content is read-written by the GPU only.
//!
//! Each access from the CPU or from the GPU locks the whole buffer for either reading or writing.
//! You can read the buffer multiple times simultaneously from multiple queues. Trying to read and
//! write simultaneously, or write and write simultaneously will block with a semaphore.

use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use smallvec::SmallVec;

use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::sys::Usage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
use buffer::traits::TypedBuffer;
use buffer::traits::TypedBufferAccess;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use instance::QueueFamily;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::Sharing;

use OomError;
use SafeDeref;

/// Buffer whose content is accessible by the CPU.
#[derive(Debug)]
pub struct DeviceLocalBuffer<T: ?Sized, A = Arc<StdMemoryPool>> where A: MemoryPool {
    // Inner content.
    inner: UnsafeBuffer,

    // The memory held by the buffer.
    memory: A::Alloc,

    // Queue families allowed to access this buffer.
    queue_families: SmallVec<[u32; 4]>,

    // Number of times this buffer is locked on the GPU side.
    gpu_lock: AtomicUsize,

    // Necessary to make it compile.
    marker: PhantomData<Box<T>>,
}

impl<T> DeviceLocalBuffer<T> {
    /// Builds a new buffer. Only allowed for sized data.
    #[inline]
    pub fn new<'a, I>(device: &Arc<Device>, usage: &Usage, queue_families: I)
                      -> Result<Arc<DeviceLocalBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            DeviceLocalBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
        }
    }
}

impl<T> DeviceLocalBuffer<[T]> {
    /// Builds a new buffer. Can be used for arrays.
    #[inline]
    pub fn array<'a, I>(device: &Arc<Device>, len: usize, usage: &Usage, queue_families: I)
                      -> Result<Arc<DeviceLocalBuffer<[T]>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            DeviceLocalBuffer::raw(device, len * mem::size_of::<T>(), usage, queue_families)
        }
    }
}

impl<T: ?Sized> DeviceLocalBuffer<T> {
    /// Builds a new buffer without checking the size.
    ///
    /// # Safety
    ///
    /// You must ensure that the size that you pass is correct for `T`.
    ///
    pub unsafe fn raw<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, queue_families: I)
                             -> Result<Arc<DeviceLocalBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        let queue_families = queue_families.into_iter().map(|f| f.id())
                                           .collect::<SmallVec<[u32; 4]>>();

        let (buffer, mem_reqs) = {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
                Ok(b) => b,
                Err(BufferCreationError::OomError(err)) => return Err(err),
                Err(_) => unreachable!()        // We don't use sparse binding, therefore the other
                                                // errors can't happen
            }
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment, AllocLayout::Linear));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        try!(buffer.bind_memory(mem.memory(), mem.offset()));

        Ok(Arc::new(DeviceLocalBuffer {
            inner: buffer,
            memory: mem,
            queue_families: queue_families,
            gpu_lock: AtomicUsize::new(0),
            marker: PhantomData,
        }))
    }
}

impl<T: ?Sized, A> DeviceLocalBuffer<T, A> where A: MemoryPool {
    /// Returns the device used to create this buffer.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }

    /// Returns the queue families this buffer can be used on.
    // TODO: use a custom iterator
    #[inline]
    pub fn queue_families(&self) -> Vec<QueueFamily> {
        self.queue_families.iter().map(|&num| {
            self.device().physical_device().queue_family_by_id(num).unwrap()
        }).collect()
    }
}

/// Access to a device local buffer.
// FIXME: add destructor
#[derive(Debug, Copy, Clone)]
pub struct DeviceLocalBufferAccess
(P);

unsafe impl<T: ?Sized, A> Buffer for Arc<DeviceLocalBuffer<T, A>>
    where T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Access = DeviceLocalBufferAccess<Arc<DeviceLocalBuffer<T, A>>>;

    #[inline]
    fn access(self) -> Self::Access {
        DeviceLocalBufferAccess(self)
    }

    #[inline]
    fn size(&self) -> usize {
        self.inner.size()
    }
}

unsafe impl<T: ?Sized, A> TypedBuffer for Arc<DeviceLocalBuffer<T, A>>
    where T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Content = T;
}

unsafe impl
 BufferAccess for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    #[inline]
    fn inner(&self) -> BufferInner {
        BufferInner {
            buffer: &self.0.inner,
            offset: 0,
        }
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        self.0.inner.key()
    }

    #[inline]
    fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
        let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
        if val == 1 {
            true
        } else {
            self.0.gpu_lock.fetch_sub(1, Ordering::SeqCst);
            false
        }
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
        debug_assert!(val >= 1);
    }
}

unsafe impl
 TypedBufferAccess for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Content = T;
}

unsafe impl
 DeviceOwned for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.0.inner.device()
    }
}
<commit_msg>Disable GPU locking for device local buffer for now<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Buffer whose content is read-written by the GPU only.
//!
//! Each access from the CPU or from the GPU locks the whole buffer for either reading or writing.
//! You can read the buffer multiple times simultaneously from multiple queues. Trying to read and
//! write simultaneously, or write and write simultaneously will block with a semaphore.

use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use smallvec::SmallVec;

use buffer::sys::BufferCreationError;
use buffer::sys::SparseLevel;
use buffer::sys::UnsafeBuffer;
use buffer::sys::Usage;
use buffer::traits::BufferAccess;
use buffer::traits::BufferInner;
use buffer::traits::Buffer;
use buffer::traits::TypedBuffer;
use buffer::traits::TypedBufferAccess;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use instance::QueueFamily;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::Sharing;

use OomError;
use SafeDeref;

/// Buffer whose content is accessible by the CPU.
#[derive(Debug)]
pub struct DeviceLocalBuffer<T: ?Sized, A = Arc<StdMemoryPool>> where A: MemoryPool {
    // Inner content.
    inner: UnsafeBuffer,

    // The memory held by the buffer.
    memory: A::Alloc,

    // Queue families allowed to access this buffer.
    queue_families: SmallVec<[u32; 4]>,

    // Number of times this buffer is locked on the GPU side.
    gpu_lock: AtomicUsize,

    // Necessary to make it compile.
    marker: PhantomData<Box<T>>,
}

impl<T> DeviceLocalBuffer<T> {
    /// Builds a new buffer. Only allowed for sized data.
    #[inline]
    pub fn new<'a, I>(device: &Arc<Device>, usage: &Usage, queue_families: I)
                      -> Result<Arc<DeviceLocalBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            DeviceLocalBuffer::raw(device, mem::size_of::<T>(), usage, queue_families)
        }
    }
}

impl<T> DeviceLocalBuffer<[T]> {
    /// Builds a new buffer. Can be used for arrays.
    #[inline]
    pub fn array<'a, I>(device: &Arc<Device>, len: usize, usage: &Usage, queue_families: I)
                      -> Result<Arc<DeviceLocalBuffer<[T]>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        unsafe {
            DeviceLocalBuffer::raw(device, len * mem::size_of::<T>(), usage, queue_families)
        }
    }
}

impl<T: ?Sized> DeviceLocalBuffer<T> {
    /// Builds a new buffer without checking the size.
    ///
    /// # Safety
    ///
    /// You must ensure that the size that you pass is correct for `T`.
    ///
    pub unsafe fn raw<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, queue_families: I)
                             -> Result<Arc<DeviceLocalBuffer<T>>, OomError>
        where I: IntoIterator<Item = QueueFamily<'a>>
    {
        let queue_families = queue_families.into_iter().map(|f| f.id())
                                           .collect::<SmallVec<[u32; 4]>>();

        let (buffer, mem_reqs) = {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
                Ok(b) => b,
                Err(BufferCreationError::OomError(err)) => return Err(err),
                Err(_) => unreachable!()        // We don't use sparse binding, therefore the other
                                                // errors can't happen
            }
        };

        let mem_ty = {
            let device_local = device.physical_device().memory_types()
                                     .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                                     .filter(|t| t.is_device_local());
            let any = device.physical_device().memory_types()
                            .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = try!(MemoryPool::alloc(&Device::standard_pool(device), mem_ty,
                                         mem_reqs.size, mem_reqs.alignment, AllocLayout::Linear));
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        try!(buffer.bind_memory(mem.memory(), mem.offset()));

        Ok(Arc::new(DeviceLocalBuffer {
            inner: buffer,
            memory: mem,
            queue_families: queue_families,
            gpu_lock: AtomicUsize::new(0),
            marker: PhantomData,
        }))
    }
}

impl<T: ?Sized, A> DeviceLocalBuffer<T, A> where A: MemoryPool {
    /// Returns the device used to create this buffer.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        self.inner.device()
    }

    /// Returns the queue families this buffer can be used on.
    // TODO: use a custom iterator
    #[inline]
    pub fn queue_families(&self) -> Vec<QueueFamily> {
        self.queue_families.iter().map(|&num| {
            self.device().physical_device().queue_family_by_id(num).unwrap()
        }).collect()
    }
}

/// Access to a device local buffer.
// FIXME: add destructor
#[derive(Debug, Copy, Clone)]
pub struct DeviceLocalBufferAccess
(P);

unsafe impl<T: ?Sized, A> Buffer for Arc<DeviceLocalBuffer<T, A>>
    where T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Access = DeviceLocalBufferAccess<Arc<DeviceLocalBuffer<T, A>>>;

    #[inline]
    fn access(self) -> Self::Access {
        DeviceLocalBufferAccess(self)
    }

    #[inline]
    fn size(&self) -> usize {
        self.inner.size()
    }
}

unsafe impl<T: ?Sized, A> TypedBuffer for Arc<DeviceLocalBuffer<T, A>>
    where T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Content = T;
}

unsafe impl
 BufferAccess for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    #[inline]
    fn inner(&self) -> BufferInner {
        BufferInner {
            buffer: &self.0.inner,
            offset: 0,
        }
    }

    #[inline]
    fn conflict_key(&self, self_offset: usize, self_size: usize) -> u64 {
        self.0.inner.key()
    }

    #[inline]
    fn try_gpu_lock(&self, _: bool, _: &Queue) -> bool {
        // FIXME: not implemented correctly
        /*let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
        if val == 1 {
            true
        } else {
            self.0.gpu_lock.fetch_sub(1, Ordering::SeqCst);
            false
        }*/
        true
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        // FIXME: not implemented correctly
        /*let val = self.0.gpu_lock.fetch_add(1, Ordering::SeqCst);
        debug_assert!(val >= 1);*/
    }
}

unsafe impl
 TypedBufferAccess for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    type Content = T;
}

unsafe impl
 DeviceOwned for DeviceLocalBufferAccess

    where P: SafeDeref<Target = DeviceLocalBuffer<T, A>>,
          T: 'static + Send + Sync,
          A: MemoryPool + 'static
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.0.inner.device()
    }
}
<|endoftext|>


<commit_before>/// One of the 8 base colors.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BaseColor {
    /// Black color
    ///
    /// Color #0
    Black,
    /// Red color
    ///
    /// Color #1
    Red,
    /// Green color
    ///
    /// Color #2
    Green,
    /// Yellow color (Red + Green)
    ///
    /// Color #3
    Yellow,
    /// Blue color
    ///
    /// Color #4
    Blue,
    /// Magenta color (Red + Blue)
    ///
    /// Color #5
    Magenta,
    /// Cyan color (Green + Blue)
    ///
    /// Color #6
    Cyan,
    /// White color (Red + Green + Blue)
    ///
    /// Color #7
    White,
}

impl From<u8> for BaseColor {
    fn from(n: u8) -> Self {
        match n % 8 {
            0 => BaseColor::Black,
            1 => BaseColor::Red,
            2 => BaseColor::Green,
            3 => BaseColor::Yellow,
            4 => BaseColor::Blue,
            5 => BaseColor::Magenta,
            6 => BaseColor::Cyan,
            7 => BaseColor::White,
            _ => unreachable!(),
        }
    }
}

/// Represents a color used by the theme.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Color {
    /// Represents a color, preset by terminal.
    TerminalDefault,
    /// One of the 8 base colors.
    Dark(BaseColor),
    /// Lighter version of a base color.
    Light(BaseColor),
    /// True-color, 24-bit.
    Rgb(u8, u8, u8),
    /// Low-resolution
    ///
    /// Each value should be `<= 5` (you'll get panics otherwise).
    ///
    /// These 216 possible colors are part of the default color palette.
    RgbLowRes(u8, u8, u8),
}

impl Color {
    /// Creates a color from its ID in the 256 colors list.
    ///
    /// * Colors 0-7 are base dark colors.
    /// * Colors 8-15 are base light colors.
    /// * Colors 16-255 are rgb colors with 6 values per channel.
    pub fn from_256colors(n: u8) -> Self {
        if n < 8 {
            Color::Dark(BaseColor::from(n))
        } else if n < 16 {
            Color::Light(BaseColor::from(n))
        } else {
            let n = n - 16;

            let r = n / 36;
            let g = (n % 36) / 6;
            let b = n % 6;

            Color::RgbLowRes(r, g, b)
        }
    }

    pub(crate) fn parse(value: &str) -> Option<Self> {
        Some(match value {
            "black" => Color::Dark(BaseColor::Black),
            "red" => Color::Dark(BaseColor::Red),
            "green" => Color::Dark(BaseColor::Green),
            "yellow" => Color::Dark(BaseColor::Yellow),
            "blue" => Color::Dark(BaseColor::Blue),
            "magenta" => Color::Dark(BaseColor::Magenta),
            "cyan" => Color::Dark(BaseColor::Cyan),
            "white" => Color::Dark(BaseColor::White),
            "light black" => Color::Light(BaseColor::Black),
            "light red" => Color::Light(BaseColor::Red),
            "light green" => Color::Light(BaseColor::Green),
            "light yellow" => Color::Light(BaseColor::Yellow),
            "light blue" => Color::Light(BaseColor::Blue),
            "light magenta" => Color::Light(BaseColor::Magenta),
            "light cyan" => Color::Light(BaseColor::Cyan),
            "light white" => Color::Light(BaseColor::White),
            "default" => Color::TerminalDefault,
            value => return Color::parse_special(value),
        })
    }

    fn parse_special(value: &str) -> Option<Color> {
        if value.starts_with('#') {
            let value = &value[1..];
            // Compute per-color length, and amplitude
            let (l, multiplier) = match value.len() {
                6 => (2, 1),
                3 => (1, 17),
                _ => panic!("Cannot parse color: {}", value),
            };
            let r = load_hex(&value[0..l]) * multiplier;
            let g = load_hex(&value[l..2 * l]) * multiplier;
            let b = load_hex(&value[2 * l..3 * l]) * multiplier;
            Some(Color::Rgb(r as u8, g as u8, b as u8))
        } else if value.len() == 3 {
            // RGB values between 0 and 5 maybe?
            let rgb: Vec<_> =
                value.chars().map(|c| c as i16 - '0' as i16).collect();
            if rgb.iter().all(|&i| i >= 0 && i < 6) {
                Some(Color::RgbLowRes(
                    rgb[0] as u8,
                    rgb[1] as u8,
                    rgb[2] as u8,
                ))
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Loads a hexadecimal code
fn load_hex(s: &str) -> u16 {
    let mut sum = 0;
    for c in s.chars() {
        sum *= 16;
        sum += match c {
            n @ '0'...'9' => n as i16 - '0' as i16,
            n @ 'a'...'f' => n as i16 - 'a' as i16 + 10,
            n @ 'A'...'F' => n as i16 - 'A' as i16 + 10,
            _ => 0,
        };
    }

    sum as u16
}
<commit_msg>Correctly parse colors 232-255<commit_after>/// One of the 8 base colors.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BaseColor {
    /// Black color
    ///
    /// Color #0
    Black,
    /// Red color
    ///
    /// Color #1
    Red,
    /// Green color
    ///
    /// Color #2
    Green,
    /// Yellow color (Red + Green)
    ///
    /// Color #3
    Yellow,
    /// Blue color
    ///
    /// Color #4
    Blue,
    /// Magenta color (Red + Blue)
    ///
    /// Color #5
    Magenta,
    /// Cyan color (Green + Blue)
    ///
    /// Color #6
    Cyan,
    /// White color (Red + Green + Blue)
    ///
    /// Color #7
    White,
}

impl From<u8> for BaseColor {
    fn from(n: u8) -> Self {
        match n % 8 {
            0 => BaseColor::Black,
            1 => BaseColor::Red,
            2 => BaseColor::Green,
            3 => BaseColor::Yellow,
            4 => BaseColor::Blue,
            5 => BaseColor::Magenta,
            6 => BaseColor::Cyan,
            7 => BaseColor::White,
            _ => unreachable!(),
        }
    }
}

/// Represents a color used by the theme.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Color {
    /// Represents a color, preset by terminal.
    TerminalDefault,
    /// One of the 8 base colors.
    Dark(BaseColor),
    /// Lighter version of a base color.
    Light(BaseColor),
    /// True-color, 24-bit.
    Rgb(u8, u8, u8),
    /// Low-resolution
    ///
    /// Each value should be `<= 5` (you'll get panics otherwise).
    ///
    /// These 216 possible colors are part of the default color palette.
    RgbLowRes(u8, u8, u8),
}

impl Color {
    /// Creates a color from its ID in the 256 colors list.
    ///
    /// * Colors 0-7 are base dark colors.
    /// * Colors 8-15 are base light colors.
    /// * Colors 16-231 are rgb colors with 6 values per channel (216 colors).
    /// * Colors 232-255 are grayscale colors.
    pub fn from_256colors(n: u8) -> Self {
        if n < 8 {
            Color::Dark(BaseColor::from(n))
        } else if n < 16 {
            Color::Light(BaseColor::from(n))
        } else if n >= 232 {
            let n = n - 232;
            let value = 8 + 10 * n;

            // TODO: returns a Grayscale value?
            Color::Rgb(value, value, value)
        } else {
            let n = n - 16;

            let r = n / 36;
            let g = (n % 36) / 6;
            let b = n % 6;

            assert!(r < 5);
            assert!(g < 5);
            assert!(b < 5);

            Color::RgbLowRes(r, g, b)
        }
    }

    pub(crate) fn parse(value: &str) -> Option<Self> {
        Some(match value {
            "black" => Color::Dark(BaseColor::Black),
            "red" => Color::Dark(BaseColor::Red),
            "green" => Color::Dark(BaseColor::Green),
            "yellow" => Color::Dark(BaseColor::Yellow),
            "blue" => Color::Dark(BaseColor::Blue),
            "magenta" => Color::Dark(BaseColor::Magenta),
            "cyan" => Color::Dark(BaseColor::Cyan),
            "white" => Color::Dark(BaseColor::White),
            "light black" => Color::Light(BaseColor::Black),
            "light red" => Color::Light(BaseColor::Red),
            "light green" => Color::Light(BaseColor::Green),
            "light yellow" => Color::Light(BaseColor::Yellow),
            "light blue" => Color::Light(BaseColor::Blue),
            "light magenta" => Color::Light(BaseColor::Magenta),
            "light cyan" => Color::Light(BaseColor::Cyan),
            "light white" => Color::Light(BaseColor::White),
            "default" => Color::TerminalDefault,
            value => return Color::parse_special(value),
        })
    }

    fn parse_special(value: &str) -> Option<Color> {
        if value.starts_with('#') {
            let value = &value[1..];
            // Compute per-color length, and amplitude
            let (l, multiplier) = match value.len() {
                6 => (2, 1),
                3 => (1, 17),
                _ => panic!("Cannot parse color: {}", value),
            };
            let r = load_hex(&value[0..l]) * multiplier;
            let g = load_hex(&value[l..2 * l]) * multiplier;
            let b = load_hex(&value[2 * l..3 * l]) * multiplier;
            Some(Color::Rgb(r as u8, g as u8, b as u8))
        } else if value.len() == 3 {
            // RGB values between 0 and 5 maybe?
            let rgb: Vec<_> =
                value.chars().map(|c| c as i16 - '0' as i16).collect();
            if rgb.iter().all(|&i| i >= 0 && i < 6) {
                Some(Color::RgbLowRes(
                    rgb[0] as u8,
                    rgb[1] as u8,
                    rgb[2] as u8,
                ))
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Loads a hexadecimal code
fn load_hex(s: &str) -> u16 {
    let mut sum = 0;
    for c in s.chars() {
        sum *= 16;
        sum += match c {
            n @ '0'...'9' => n as i16 - '0' as i16,
            n @ 'a'...'f' => n as i16 - 'a' as i16 + 10,
            n @ 'A'...'F' => n as i16 - 'A' as i16 + 10,
            _ => 0,
        };
    }

    sum as u16
}
<|endoftext|>


<commit_before>// DOCS

#![feature(plugin)]
#[plugin] extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

pub struct Property {
    params: HashMap<String, String>,
    raw_value: String,
    prop_group: Option<String>
}

impl Property {
    fn new(params: HashMap<String, String>, raw_value: String, prop_group: Option<String>) -> Property {
        Property {
            params: params,
            raw_value: raw_value,
            prop_group: prop_group
        }
    }

    #[doc="Get property group. E.g. a contentline like `foo.FN:Markus` would result in the group \
    being `\"foo\"`."]
    pub fn get_prop_group(&self) -> &Option<String> {
        &self.prop_group
    }

    #[doc="Get parameters."]
    pub fn get_params(&self) -> &HashMap<String, String> {
        &self.params
    }

    #[doc="Get value as unparsed string."]
    pub fn get_raw_value(&self) -> &String {
        &self.raw_value
    }

    #[doc="Get value as unescaped string."]
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.get_raw_value())
    }
}

pub struct Component {
    #[doc="The name of the component, such as `VCARD` or `VEVENT`."]
    pub name: String,

    #[doc="The component's properties."]
    pub props: HashMap<String, Vec<Property>>,

    #[doc="The component's child- or sub-components."]
    pub subcomponents: Vec<Component>
}

impl Component {
    fn new(name: String) -> Component {
        Component {
            name: name,
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    #[doc="Retrieve one property (from many) by key.
        Returns `None` if nothing is found."]
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    #[doc="Retrieve a mutable vector of properties for this key.
        Creates one (and inserts it into the component) if none exists."]
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.set(vec![])
        }
    }

    #[doc="Retrieve properties by key.
        Returns an empty slice if key doesn't exist."]
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

#[pub]
component -> Component
    = name:component_begin
      ps:props
      cs:components?
      component_end {
        let mut rv = Component::new(name);

        match cs {
            Some(components) => { rv.subcomponents = components; },
            None => ()
        };

        for (k, v) in ps.into_iter() {
            rv.all_props_mut(k).push(v);
        };

        rv
    }

component_begin -> String
    = "BEGIN:" v:value __ { v.into_string() }

component_end -> String
    = "END:" v:value __ { v.into_string() }

components -> Vec<Component>
    = cs:component ++ eols __ { cs }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

prop -> (&'input str, Property)
    = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
        (k, Property::new(p, v, g))
    }

group -> String
    = g:group_name "." { g }

group_name -> String
    = group_char+ { match_str.into_string() }

name -> &'input str
    = iana_token+ { match_str }

params -> HashMap<String, String>
    = ps:(";" p:param {p})* {
        let mut rv: HashMap<String, String> = HashMap::new();
        for (k, v) in ps.into_iter() {
            rv.insert(k.into_string(), v.into_string());
        };
        rv
    }

param -> (&'input str, &'input str)
    // FIXME: Doesn't handle comma-separated values
    = k:param_name v:("=" v:param_value { v })? {
        (k, match v {
            Some(x) => x,
            None => ""
        })
    }

param_name -> &'input str
    = iana_token+ { match_str }

param_value -> &'input str
    = x:(quoted_string / param_text) { x }

param_text -> &'input str
    = safe_char* { match_str }

value -> String
    = value_char+ { match_str.into_string() }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
safe_char = !";" !":" !"," value_char
qsafe_char = !dquote value_char // FIXME

value_char = !eol .

eol = "\n" / "\r\n" / "\r"
dquote = "\""
eols = eol+
whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);

#[doc="Parse a component. The error value is a human-readable message."]
pub fn parse_component(s: &String) -> Result<Component, String> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = s
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\r ", "").replace("\r\t", "");

    parser::component(unfolded.as_slice())
}

#[doc="Escape text for a VObject property value."]
pub fn escape_chars(s: &String) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

#[doc="Unescape text from a VObject property value."]
pub fn unescape_chars(s: &String) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}
<commit_msg>More rust alpha fixes<commit_after>// DOCS

#![feature(plugin)]
#[plugin] extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

pub struct Property {
    params: HashMap<String, String>,
    raw_value: String,
    prop_group: Option<String>
}

impl Property {
    fn new(params: HashMap<String, String>, raw_value: String, prop_group: Option<String>) -> Property {
        Property {
            params: params,
            raw_value: raw_value,
            prop_group: prop_group
        }
    }

    #[doc="Get property group. E.g. a contentline like `foo.FN:Markus` would result in the group \
    being `\"foo\"`."]
    pub fn get_prop_group(&self) -> &Option<String> {
        &self.prop_group
    }

    #[doc="Get parameters."]
    pub fn get_params(&self) -> &HashMap<String, String> {
        &self.params
    }

    #[doc="Get value as unparsed string."]
    pub fn get_raw_value(&self) -> &String {
        &self.raw_value
    }

    #[doc="Get value as unescaped string."]
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.get_raw_value())
    }
}

pub struct Component {
    #[doc="The name of the component, such as `VCARD` or `VEVENT`."]
    pub name: String,

    #[doc="The component's properties."]
    pub props: HashMap<String, Vec<Property>>,

    #[doc="The component's child- or sub-components."]
    pub subcomponents: Vec<Component>
}

impl Component {
    fn new(name: String) -> Component {
        Component {
            name: name,
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    #[doc="Retrieve one property (from many) by key.
        Returns `None` if nothing is found."]
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    #[doc="Retrieve a mutable vector of properties for this key.
        Creates one (and inserts it into the component) if none exists."]
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    #[doc="Retrieve properties by key.
        Returns an empty slice if key doesn't exist."]
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

#[pub]
component -> Component
    = name:component_begin
      ps:props
      cs:components?
      component_end {
        let mut rv = Component::new(name);

        match cs {
            Some(components) => { rv.subcomponents = components; },
            None => ()
        };

        for (k, v) in ps.into_iter() {
            rv.all_props_mut(k).push(v);
        };

        rv
    }

component_begin -> String
    = "BEGIN:" v:value __ { v.to_string() }

component_end -> String
    = "END:" v:value __ { v.to_string() }

components -> Vec<Component>
    = cs:component ++ eols __ { cs }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

prop -> (&'input str, Property)
    = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
        (k, Property::new(p, v, g))
    }

group -> String
    = g:group_name "." { g }

group_name -> String
    = group_char+ { match_str.to_string() }

name -> &'input str
    = iana_token+ { match_str }

params -> HashMap<String, String>
    = ps:(";" p:param {p})* {
        let mut rv: HashMap<String, String> = HashMap::new();
        for (k, v) in ps.into_iter() {
            rv.insert(k.to_string(), v.to_string());
        };
        rv
    }

param -> (&'input str, &'input str)
    // FIXME: Doesn't handle comma-separated values
    = k:param_name v:("=" v:param_value { v })? {
        (k, match v {
            Some(x) => x,
            None => ""
        })
    }

param_name -> &'input str
    = iana_token+ { match_str }

param_value -> &'input str
    = x:(quoted_string / param_text) { x }

param_text -> &'input str
    = safe_char* { match_str }

value -> String
    = value_char+ { match_str.to_string() }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
safe_char = !";" !":" !"," value_char
qsafe_char = !dquote value_char // FIXME

value_char = !eol .

eol = "\n" / "\r\n" / "\r"
dquote = "\""
eols = eol+
whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);

#[doc="Parse a component. The error value is a human-readable message."]
pub fn parse_component(s: &String) -> Result<Component, String> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = s
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\r ", "").replace("\r\t", "");

    parser::component(unfolded.as_slice())
}

#[doc="Escape text for a VObject property value."]
pub fn escape_chars(s: &String) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

#[doc="Unescape text from a VObject property value."]
pub fn unescape_chars(s: &String) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}
<|endoftext|>


<commit_before>use serde::{Serialize, Deserialize};

use de::Deserializer;
use error::Error;
use ser::Serializer;
use token::Token;

use std::fmt::Debug;

pub fn assert_tokens<T>(value: &T, tokens: &[Token<'static>])
    where T: Serialize + Deserialize + PartialEq + Debug,
{
    assert_ser_tokens(value, tokens);
    assert_de_tokens(value, tokens);
}

pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
    where T: Serialize,
{
    let mut ser = Serializer::new(tokens.iter());
    assert_eq!(Serialize::serialize(value, &mut ser), Ok(()));
    assert_eq!(ser.next_token(), None);
}

// Expect an error serializing T
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: Error)
    where T: Serialize + PartialEq + Debug,
{
    let mut ser = Serializer::new(tokens.iter());
    let v: Result<(), Error> = Serialize::serialize(value, &mut ser);
    assert_eq!(v.as_ref(), Err(&error));
    assert_eq!(ser.next_token(), None);
}

pub fn assert_de_tokens<T>(value: &T, tokens: &[Token<'static>])
    where T: Deserialize + PartialEq + Debug,
{
    let mut de = Deserializer::new(tokens.to_vec().into_iter());
    let v: Result<T, Error> = Deserialize::deserialize(&mut de);
    assert_eq!(v.as_ref(), Ok(value));
    assert_eq!(de.next_token(), None);
}

// Expect an error deserializing tokens into a T
pub fn assert_de_tokens_error<T>(tokens: &[Token<'static>], error: Error)
    where T: Deserialize + PartialEq + Debug,
{
    let mut de = Deserializer::new(tokens.to_vec().into_iter());
    let v: Result<T, Error> = Deserialize::deserialize(&mut de);
    assert_eq!(v, Err(error));
    // There may be one token left if a peek caused the error
    de.next_token();
    assert_eq!(de.next_token(), None);
}
<commit_msg>Turn comments into doc comments<commit_after>use serde::{Serialize, Deserialize};

use de::Deserializer;
use error::Error;
use ser::Serializer;
use token::Token;

use std::fmt::Debug;

pub fn assert_tokens<T>(value: &T, tokens: &[Token<'static>])
    where T: Serialize + Deserialize + PartialEq + Debug,
{
    assert_ser_tokens(value, tokens);
    assert_de_tokens(value, tokens);
}

pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
    where T: Serialize,
{
    let mut ser = Serializer::new(tokens.iter());
    assert_eq!(Serialize::serialize(value, &mut ser), Ok(()));
    assert_eq!(ser.next_token(), None);
}

/// Expect an error serializing `T`.
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: Error)
    where T: Serialize + PartialEq + Debug,
{
    let mut ser = Serializer::new(tokens.iter());
    let v: Result<(), Error> = Serialize::serialize(value, &mut ser);
    assert_eq!(v.as_ref(), Err(&error));
    assert_eq!(ser.next_token(), None);
}

pub fn assert_de_tokens<T>(value: &T, tokens: &[Token<'static>])
    where T: Deserialize + PartialEq + Debug,
{
    let mut de = Deserializer::new(tokens.to_vec().into_iter());
    let v: Result<T, Error> = Deserialize::deserialize(&mut de);
    assert_eq!(v.as_ref(), Ok(value));
    assert_eq!(de.next_token(), None);
}

/// Expect an error deserializing tokens into a `T`.
pub fn assert_de_tokens_error<T>(tokens: &[Token<'static>], error: Error)
    where T: Deserialize + PartialEq + Debug,
{
    let mut de = Deserializer::new(tokens.to_vec().into_iter());
    let v: Result<T, Error> = Deserialize::deserialize(&mut de);
    assert_eq!(v, Err(error));
    // There may be one token left if a peek caused the error
    de.next_token();
    assert_eq!(de.next_token(), None);
}
<|endoftext|>


<commit_before>use diesel::connection::SimpleConnection;
use diesel::migration::*;

use std::fmt;
use std::path::{Path, PathBuf};

#[allow(missing_debug_implementations)]
#[derive(Clone, Copy)]
pub struct MigrationName<'a> {
    pub migration: &'a dyn Migration,
}

pub fn name(migration: &dyn Migration) -> MigrationName {
    MigrationName { migration }
}

impl<'a> fmt::Display for MigrationName<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let file_name = self
            .migration
            .file_path()
            .and_then(|file_path| file_path.file_name()?.to_str());
        if let Some(name) = file_name {
            f.write_str(name)?;
        } else {
            f.write_str(self.migration.version())?;
        }
        Ok(())
    }
}

#[allow(missing_debug_implementations)]
#[derive(Clone, Copy)]
pub struct MigrationFileName<'a> {
    pub migration: &'a dyn Migration,
    pub sql_file: &'a str,
}

pub fn file_name<'a>(migration: &'a dyn Migration, sql_file: &'a str) -> MigrationFileName<'a> {
    MigrationFileName {
        migration,
        sql_file,
    }
}

impl<'a> fmt::Display for MigrationFileName<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let fpath = match self.migration.file_path() {
            None => return Err(fmt::Error),
            Some(v) => v.join(self.sql_file),
        };
        f.write_str(fpath.to_str().unwrap_or("Invalid utf8 in filename"))?;
        Ok(())
    }
}

pub fn migration_from(path: PathBuf) -> Result<Box<dyn Migration>, MigrationError> {
    #[cfg(feature = "barrel")]
    match ::barrel::integrations::diesel::migration_from(&path) {
        Some(migration) => return Ok(migration),
        None => {}
    }

    if valid_sql_migration_directory(&path) {
        let version = version_from_path(&path)?;
        Ok(Box::new(SqlFileMigration(path, version)))
    } else {
        Err(MigrationError::UnknownMigrationFormat(path))
    }
}

fn valid_sql_migration_directory(path: &Path) -> bool {
    file_names(path)
        .map(|files| files.contains(&"down.sql".into()) && files.contains(&"up.sql".into()))
        .unwrap_or(false)
}

fn file_names(path: &Path) -> Result<Vec<String>, MigrationError> {
    path.read_dir()?
        .map(|entry| {
            let file_name = entry?.file_name();

            // FIXME(killercup): Decide whether to add MigrationError variant for this
            match file_name.into_string() {
                Ok(utf8_file_name) => Ok(utf8_file_name),
                Err(original_os_string) => panic!(
                    "Can't convert file name `{:?}` into UTF8 string",
                    original_os_string
                ),
            }
        })
        .filter(|file_name| match *file_name {
            Ok(ref name) => !name.starts_with('.'),
            _ => true,
        })
        .collect()
}

#[doc(hidden)]
pub fn version_from_path(path: &Path) -> Result<String, MigrationError> {
    path.file_name()
        .unwrap_or_else(|| panic!("Can't get file name from path `{:?}`", path))
        .to_string_lossy()
        .split('_')
        .nth(0)
        .map(|s| Ok(s.replace('-', "")))
        .unwrap_or_else(|| Err(MigrationError::UnknownMigrationFormat(path.to_path_buf())))
}

use std::fs::File;
use std::io::Read;

struct SqlFileMigration(PathBuf, String);

impl Migration for SqlFileMigration {
    fn file_path(&self) -> Option<&Path> {
        Some(self.0.as_path())
    }

    fn version(&self) -> &str {
        &self.1
    }

    fn run(&self, conn: &dyn SimpleConnection) -> Result<(), RunMigrationsError> {
        run_sql_from_file(conn, &self.0.join("up.sql"))
    }

    fn revert(&self, conn: &dyn SimpleConnection) -> Result<(), RunMigrationsError> {
        run_sql_from_file(conn, &self.0.join("down.sql"))
    }
}

fn run_sql_from_file(conn: &dyn SimpleConnection, path: &Path) -> Result<(), RunMigrationsError> {
    let mut sql = String::new();
    let mut file = File::open(path)?;
    file.read_to_string(&mut sql)?;

    if sql.is_empty() {
        return Err(RunMigrationsError::EmptyMigration);
    }

    conn.batch_execute(&sql)?;
    Ok(())
}

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::{valid_sql_migration_directory, version_from_path};

    use self::tempdir::TempDir;
    use std::fs;
    use std::path::PathBuf;

    #[test]
    fn files_are_not_valid_sql_file_migrations() {
        let dir = TempDir::new("diesel").unwrap();
        let file_path = dir.path().join("12345");

        fs::File::create(&file_path).unwrap();

        assert!(!valid_sql_migration_directory(&file_path));
    }

    #[test]
    fn directory_containing_exactly_up_sql_and_down_sql_is_valid_migration_dir() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();
        fs::File::create(folder.join("up.sql")).unwrap();
        fs::File::create(folder.join("down.sql")).unwrap();

        assert!(valid_sql_migration_directory(&folder));
    }

    #[test]
    fn directory_containing_unknown_files_is_valid_migration_dir() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();
        fs::File::create(folder.join("up.sql")).unwrap();
        fs::File::create(folder.join("down.sql")).unwrap();
        fs::File::create(folder.join("foo")).unwrap();

        assert!(valid_sql_migration_directory(&folder));
    }

    #[test]
    fn files_beginning_with_dot_are_allowed() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();
        fs::File::create(folder.join("up.sql")).unwrap();
        fs::File::create(folder.join("down.sql")).unwrap();
        fs::File::create(folder.join(".foo")).unwrap();

        assert!(valid_sql_migration_directory(&folder));
    }

    #[test]
    fn empty_directory_is_not_valid_migration_dir() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();

        assert!(!valid_sql_migration_directory(&folder));
    }

    #[test]
    fn directory_with_only_up_sql_is_not_valid_migration_dir() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();
        fs::File::create(folder.join("up.sql")).unwrap();

        assert!(!valid_sql_migration_directory(&folder));
    }

    #[test]
    fn migration_version_is_based_on_folder_name() {
        let path = PathBuf::new().join("migrations").join("12345");

        assert_eq!(Ok("12345".into()), version_from_path(&path));
    }

    #[test]
    fn migration_version_allows_additional_naming() {
        let path = PathBuf::new().join("migrations").join("54321_create_stuff");

        assert_eq!(Ok("54321".into()), version_from_path(&path));
    }

    #[test]
    fn migration_version_when_dir_doesnt_start_with_num_is_allowed() {
        let path = PathBuf::new().join("migrations").join("create_stuff_12345");

        assert_eq!(Ok("create".into()), version_from_path(&path));
    }
}
<commit_msg>Fix formatting error with embedded migrations<commit_after>use diesel::connection::SimpleConnection;
use diesel::migration::*;

use std::fmt;
use std::path::{Path, PathBuf};

#[allow(missing_debug_implementations)]
#[derive(Clone, Copy)]
pub struct MigrationName<'a> {
    pub migration: &'a dyn Migration,
}

pub fn name(migration: &dyn Migration) -> MigrationName {
    MigrationName { migration }
}

impl<'a> fmt::Display for MigrationName<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let file_name = self
            .migration
            .file_path()
            .and_then(|file_path| file_path.file_name()?.to_str());
        if let Some(name) = file_name {
            f.write_str(name)?;
        } else {
            f.write_str(self.migration.version())?;
        }
        Ok(())
    }
}

#[allow(missing_debug_implementations)]
#[derive(Clone, Copy)]
pub struct MigrationFileName<'a> {
    pub migration: &'a dyn Migration,
    pub sql_file: &'a str,
}

pub fn file_name<'a>(migration: &'a dyn Migration, sql_file: &'a str) -> MigrationFileName<'a> {
    MigrationFileName {
        migration,
        sql_file,
    }
}

impl<'a> fmt::Display for MigrationFileName<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(path) = self.migration.file_path() {
            let fpath = path.join(self.sql_file);
            f.write_str(fpath.to_str().unwrap_or("Invalid utf8 in filename"))
        } else {
            write!(f, "{}/{}", self.migration.version(), self.sql_file)
        }
    }
}

pub fn migration_from(path: PathBuf) -> Result<Box<dyn Migration>, MigrationError> {
    #[cfg(feature = "barrel")]
    match ::barrel::integrations::diesel::migration_from(&path) {
        Some(migration) => return Ok(migration),
        None => {}
    }

    if valid_sql_migration_directory(&path) {
        let version = version_from_path(&path)?;
        Ok(Box::new(SqlFileMigration(path, version)))
    } else {
        Err(MigrationError::UnknownMigrationFormat(path))
    }
}

fn valid_sql_migration_directory(path: &Path) -> bool {
    file_names(path)
        .map(|files| files.contains(&"down.sql".into()) && files.contains(&"up.sql".into()))
        .unwrap_or(false)
}

fn file_names(path: &Path) -> Result<Vec<String>, MigrationError> {
    path.read_dir()?
        .map(|entry| {
            let file_name = entry?.file_name();

            // FIXME(killercup): Decide whether to add MigrationError variant for this
            match file_name.into_string() {
                Ok(utf8_file_name) => Ok(utf8_file_name),
                Err(original_os_string) => panic!(
                    "Can't convert file name `{:?}` into UTF8 string",
                    original_os_string
                ),
            }
        })
        .filter(|file_name| match *file_name {
            Ok(ref name) => !name.starts_with('.'),
            _ => true,
        })
        .collect()
}

#[doc(hidden)]
pub fn version_from_path(path: &Path) -> Result<String, MigrationError> {
    path.file_name()
        .unwrap_or_else(|| panic!("Can't get file name from path `{:?}`", path))
        .to_string_lossy()
        .split('_')
        .nth(0)
        .map(|s| Ok(s.replace('-', "")))
        .unwrap_or_else(|| Err(MigrationError::UnknownMigrationFormat(path.to_path_buf())))
}

use std::fs::File;
use std::io::Read;

struct SqlFileMigration(PathBuf, String);

impl Migration for SqlFileMigration {
    fn file_path(&self) -> Option<&Path> {
        Some(self.0.as_path())
    }

    fn version(&self) -> &str {
        &self.1
    }

    fn run(&self, conn: &dyn SimpleConnection) -> Result<(), RunMigrationsError> {
        run_sql_from_file(conn, &self.0.join("up.sql"))
    }

    fn revert(&self, conn: &dyn SimpleConnection) -> Result<(), RunMigrationsError> {
        run_sql_from_file(conn, &self.0.join("down.sql"))
    }
}

fn run_sql_from_file(conn: &dyn SimpleConnection, path: &Path) -> Result<(), RunMigrationsError> {
    let mut sql = String::new();
    let mut file = File::open(path)?;
    file.read_to_string(&mut sql)?;

    if sql.is_empty() {
        return Err(RunMigrationsError::EmptyMigration);
    }

    conn.batch_execute(&sql)?;
    Ok(())
}

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::{valid_sql_migration_directory, version_from_path};

    use self::tempdir::TempDir;
    use std::fs;
    use std::path::PathBuf;

    #[test]
    fn files_are_not_valid_sql_file_migrations() {
        let dir = TempDir::new("diesel").unwrap();
        let file_path = dir.path().join("12345");

        fs::File::create(&file_path).unwrap();

        assert!(!valid_sql_migration_directory(&file_path));
    }

    #[test]
    fn directory_containing_exactly_up_sql_and_down_sql_is_valid_migration_dir() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();
        fs::File::create(folder.join("up.sql")).unwrap();
        fs::File::create(folder.join("down.sql")).unwrap();

        assert!(valid_sql_migration_directory(&folder));
    }

    #[test]
    fn directory_containing_unknown_files_is_valid_migration_dir() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();
        fs::File::create(folder.join("up.sql")).unwrap();
        fs::File::create(folder.join("down.sql")).unwrap();
        fs::File::create(folder.join("foo")).unwrap();

        assert!(valid_sql_migration_directory(&folder));
    }

    #[test]
    fn files_beginning_with_dot_are_allowed() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();
        fs::File::create(folder.join("up.sql")).unwrap();
        fs::File::create(folder.join("down.sql")).unwrap();
        fs::File::create(folder.join(".foo")).unwrap();

        assert!(valid_sql_migration_directory(&folder));
    }

    #[test]
    fn empty_directory_is_not_valid_migration_dir() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();

        assert!(!valid_sql_migration_directory(&folder));
    }

    #[test]
    fn directory_with_only_up_sql_is_not_valid_migration_dir() {
        let tempdir = TempDir::new("diesel").unwrap();
        let folder = tempdir.path().join("12345");

        fs::create_dir(&folder).unwrap();
        fs::File::create(folder.join("up.sql")).unwrap();

        assert!(!valid_sql_migration_directory(&folder));
    }

    #[test]
    fn migration_version_is_based_on_folder_name() {
        let path = PathBuf::new().join("migrations").join("12345");

        assert_eq!(Ok("12345".into()), version_from_path(&path));
    }

    #[test]
    fn migration_version_allows_additional_naming() {
        let path = PathBuf::new().join("migrations").join("54321_create_stuff");

        assert_eq!(Ok("54321".into()), version_from_path(&path));
    }

    #[test]
    fn migration_version_when_dir_doesnt_start_with_num_is_allowed() {
        let path = PathBuf::new().join("migrations").join("create_stuff_12345");

        assert_eq!(Ok("create".into()), version_from_path(&path));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Utilities for working with packets, eg. checksumming.

use ip::IpNextHeaderProtocol;
use pnet_macros_support::types::u16be;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::u8;
use std::u16;
use std::convert::TryInto;

/// Convert a value to a byte array.
pub trait Octets {
    /// Output type - bytes array.
    type Output;

    /// Return a value as bytes (big-endian order).
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8,
         (*self >> 48) as u8,
         (*self >> 40) as u8,
         (*self >> 32) as u8,
         (*self >> 24) as u8,
         (*self >> 16) as u8,
         (*self >> 8) as u8,
         *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: usize) -> u16be {
    if data.len() == 0 { return 0 }
    let sum = sum_be_words(data, skipword);
    finalize_checksum(sum)
}

fn finalize_checksum(mut sum: u32) -> u16be {
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by UDP and TCP.
pub fn ipv4_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv4Addr,
                     destination: &Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(source);
    sum += ipv4_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv4_word_sum(ip: &Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Calculate the checksum for a packet built on IPv6.
pub fn ipv6_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv6Addr,
                     destination: &Ipv6Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv6_word_sum(source);
    sum += ipv6_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv6_word_sum(ip: &Ipv6Addr) -> u32 {
    ip.segments().iter().map(|x| *x as u32).sum()
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset
/// `skipword` will be skipped. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: usize) -> u32 {
    if data.len() == 0 { return 0 }
    let len = data.len();
    let mut cur_data = &data[..];
    let mut sum = 0u32;
    let mut i = 0;
    while cur_data.len() >= 2 {
        if i != skipword {
            // It's safe to unwrap because we verified there are at least 2 bytes
            sum += u16::from_be_bytes(cur_data[0..2].try_into().unwrap()) as u32;
        }
        cur_data = &cur_data[2..];
        i += 1;
    }

    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

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

    #[test]
    fn sum_be_words_different_skipwords() {
        let data = (0..11).collect::<Vec<u8>>();
        assert_eq!(7190, sum_be_words(&data, 1));
        assert_eq!(6676, sum_be_words(&data, 2));
        // Assert having the skipword outside the range gives correct and equal
        // results
        assert_eq!(7705, sum_be_words(&data, 99));
        assert_eq!(7705, sum_be_words(&data, 101));
    }
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), 5));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), 5));
    }
}

<commit_msg>Add unit tests for misaligned data to verify the sum function can handle misaligned data.<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Utilities for working with packets, eg. checksumming.

use ip::IpNextHeaderProtocol;
use pnet_macros_support::types::u16be;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::u8;
use std::u16;
use std::convert::TryInto;

/// Convert a value to a byte array.
pub trait Octets {
    /// Output type - bytes array.
    type Output;

    /// Return a value as bytes (big-endian order).
    fn octets(&self) -> Self::Output;
}

impl Octets for u64 {
    type Output = [u8; 8];

    fn octets(&self) -> Self::Output {
        [(*self >> 56) as u8,
         (*self >> 48) as u8,
         (*self >> 40) as u8,
         (*self >> 32) as u8,
         (*self >> 24) as u8,
         (*self >> 16) as u8,
         (*self >> 8) as u8,
         *self as u8]
    }
}

impl Octets for u32 {
    type Output = [u8; 4];

    fn octets(&self) -> Self::Output {
        [(*self >> 24) as u8, (*self >> 16) as u8, (*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u16 {
    type Output = [u8; 2];

    fn octets(&self) -> Self::Output {
        [(*self >> 8) as u8, *self as u8]
    }
}

impl Octets for u8 {
    type Output = [u8; 1];

    fn octets(&self) -> Self::Output {
        [*self]
    }
}

/// Calculates a checksum. Used by ipv4 and icmp. The two bytes starting at `skipword * 2` will be
/// ignored. Supposed to be the checksum field, which is regarded as zero during calculation.
pub fn checksum(data: &[u8], skipword: usize) -> u16be {
    if data.len() == 0 { return 0 }
    let sum = sum_be_words(data, skipword);
    finalize_checksum(sum)
}

fn finalize_checksum(mut sum: u32) -> u16be {
    while sum >> 16 != 0 {
        sum = (sum >> 16) + (sum & 0xFFFF);
    }
    !sum as u16
}

/// Calculate the checksum for a packet built on IPv4. Used by UDP and TCP.
pub fn ipv4_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv4Addr,
                     destination: &Ipv4Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv4_word_sum(source);
    sum += ipv4_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv4_word_sum(ip: &Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 8 | octets[1] as u32) + ((octets[2] as u32) << 8 | octets[3] as u32)
}

/// Calculate the checksum for a packet built on IPv6.
pub fn ipv6_checksum(data: &[u8],
                     skipword: usize,
                     extra_data: &[u8],
                     source: &Ipv6Addr,
                     destination: &Ipv6Addr,
                     next_level_protocol: IpNextHeaderProtocol)
    -> u16be {
    let mut sum = 0u32;

    // Checksum pseudo-header
    sum += ipv6_word_sum(source);
    sum += ipv6_word_sum(destination);

    let IpNextHeaderProtocol(next_level_protocol) = next_level_protocol;
    sum += next_level_protocol as u32;

    let len = data.len() + extra_data.len();
    sum += len as u32;

    // Checksum packet header and data
    sum += sum_be_words(data, skipword);
    sum += sum_be_words(extra_data, extra_data.len() / 2);

    finalize_checksum(sum)
}

fn ipv6_word_sum(ip: &Ipv6Addr) -> u32 {
    ip.segments().iter().map(|x| *x as u32).sum()
}

/// Sum all words (16 bit chunks) in the given data. The word at word offset
/// `skipword` will be skipped. Each word is treated as big endian.
fn sum_be_words(data: &[u8], skipword: usize) -> u32 {
    if data.len() == 0 { return 0 }
    let len = data.len();
    let mut cur_data = &data[..];
    let mut sum = 0u32;
    let mut i = 0;
    while cur_data.len() >= 2 {
        if i != skipword {
            // It's safe to unwrap because we verified there are at least 2 bytes
            sum += u16::from_be_bytes(cur_data[0..2].try_into().unwrap()) as u32;
        }
        cur_data = &cur_data[2..];
        i += 1;
    }

    // If the length is odd, make sure to checksum the final byte
    if len & 1 != 0 {
        sum += (data[len - 1] as u32) << 8;
    }

    sum
}

#[cfg(test)]
mod tests {
    use super::sum_be_words;
    use std::slice;

    #[test]
    fn sum_be_words_different_skipwords() {
        let data = (0..11).collect::<Vec<u8>>();
        assert_eq!(7190, sum_be_words(&data, 1));
        assert_eq!(6676, sum_be_words(&data, 2));
        // Assert having the skipword outside the range gives correct and equal
        // results
        assert_eq!(7705, sum_be_words(&data, 99));
        assert_eq!(7705, sum_be_words(&data, 101));
    }

    #[test]
    fn sum_be_words_misaligned_ptr() {
        let mut data = vec![0; 13];
        let ptr = match data.as_ptr() as usize % 2 {
            0 => {
                unsafe { data.as_mut_ptr().offset(1) }
            }
            _ => data.as_mut_ptr(),
        };
        unsafe {
            let slice_data = slice::from_raw_parts_mut(ptr, 12);
            for i in 0..11 {
                slice_data[i] = i as u8;
            }
            assert_eq!(7190, sum_be_words(&slice_data, 1));
            assert_eq!(6676, sum_be_words(&slice_data, 2));
            // Assert having the skipword outside the range gives correct and equal
            // results
            assert_eq!(7705, sum_be_words(&slice_data, 99));
            assert_eq!(7705, sum_be_words(&slice_data, 101));
        }
    }
}

#[cfg(all(test, feature = "benchmark"))]
mod checksum_benchmarks {
    use super::checksum;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_checksum_small(b: &mut Bencher) {
        let data = vec![99u8; 20];
        b.iter(|| checksum(black_box(&data), 5));
    }

    #[bench]
    fn bench_checksum_large(b: &mut Bencher) {
        let data = vec![123u8; 1024];
        b.iter(|| checksum(black_box(&data), 5));
    }
}

<|endoftext|>


<commit_before>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
extern crate nalgebra;
extern crate ncollide_transformation;
extern crate ordered_float;

use nalgebra::{Vector2, Point2, Vector3, Vector4, Point3, Isometry3, Perspective3, Matrix4};
pub use nalgebra::{Dot, ToHomogeneous, Norm, Inverse, Rotate};
use std::f32::consts::PI;

pub type N = f32;
pub type V2 = Vector2<N>;
pub type P2 = Point2<N>;
pub type V3 = Vector3<N>;
pub type V4 = Vector4<N>;
pub type P3 = Point3<N>;
pub type M4 = Matrix4<N>;
pub type Iso3 = Isometry3<N>;
pub type Persp3 = Perspective3<N>;

// Thickness radius
const THICKNESS: N = 0.001;
const ROUGH_TOLERANCE: N = 0.0000001;

mod primitives;
mod path;
mod intersect;
mod shapes;

pub use self::primitives::*;
pub use self::path::{Path, convex_hull};
pub use self::intersect::*;
pub use self::shapes::*;

pub fn angle_to(a: V2, b: V2) -> N {
    let theta: N = a.dot(&b) / (a.norm() * b.norm());
    theta.min(1.0).max(-1.0).acos()
}

pub fn angle_along_to(a: V2, a_direction: V2, b: V2) -> N {
    let simple_angle = angle_to(a, b);
    let linear_direction = (b - a).normalize();

    if a_direction.dot(&linear_direction) >= 0.0 {
        simple_angle
    } else {
        2.0 * PI - simple_angle
    }
}

pub trait WithUniqueOrthogonal {
    fn orthogonal(&self) -> Self;
}

impl WithUniqueOrthogonal for V2 {
    fn orthogonal(&self) -> V2 {
        V2::new(self.y, -self.x)
    }
}

pub trait RelativeToBasis {
    fn to_basis(self, basis_x: Self) -> Self;
    fn from_basis(self, basis_x: Self) -> Self;
}

impl RelativeToBasis for V2 {
    fn to_basis(self, basis_x: V2) -> V2 {
        V2::new(basis_x.dot(&self), basis_x.orthogonal().dot(&self))
    }

    fn from_basis(self, basis_x: V2) -> V2 {
        self.x * basis_x + self.y * basis_x.orthogonal()
    }
}

pub trait Into2d {
    type Target;
    fn into_2d(self) -> Self::Target;
}

impl Into2d for V3 {
    type Target = V2;
    fn into_2d(self) -> V2 {
        V2::new(self.x, self.y)
    }
}

impl Into2d for P3 {
    type Target = P2;
    fn into_2d(self) -> P2 {
        P2::new(self.x, self.y)
    }
}

pub trait Into3d {
    type Target;
    fn into_3d(self) -> Self::Target;
}

impl Into3d for V2 {
    type Target = V3;
    fn into_3d(self) -> V3 {
        V3::new(self.x, self.y, 0.0)
    }
}

impl Into3d for P2 {
    type Target = P3;
    fn into_3d(self) -> P3 {
        P3::new(self.x, self.y, 0.0)
    }
}

pub trait RoughlyComparable: Sized {
    fn is_roughly(&self, other: Self) -> bool {
        self.is_roughly_within(other, ROUGH_TOLERANCE)
    }
    fn is_roughly_within(&self, other: Self, tolerance: N) -> bool;
}

impl RoughlyComparable for N {
    fn is_roughly_within(&self, other: N, tolerance: N) -> bool {
        (self - other).abs() <= tolerance
    }
}

impl RoughlyComparable for P2 {
    fn is_roughly_within(&self, other: P2, tolerance: N) -> bool {
        (*self - other).norm() <= tolerance
    }
}

impl RoughlyComparable for V2 {
    fn is_roughly_within(&self, other: V2, tolerance: N) -> bool {
        (*self - other).norm() <= tolerance
    }
}

pub trait Curve: Sized {
    fn project_with_max_distance(&self, point: P2, max_distance: N, tolerance: N) -> Option<N> {
        self.project_with_tolerance(point, tolerance)
            .and_then(|offset| if self.distance_to(point) < max_distance {
                          Some(offset)
                      } else {
                          None
                      })
    }
    fn project_with_tolerance(&self, point: P2, tolerance: N) -> Option<N>;
    fn project(&self, point: P2) -> Option<N> {
        self.project_with_tolerance(point, THICKNESS)
    }
    fn includes(&self, point: P2) -> bool {
        self.distance_to(point) < THICKNESS / 2.0
    }
    fn distance_to(&self, point: P2) -> N;
}

pub trait FiniteCurve: Curve {
    fn length(&self) -> N;
    fn along(&self, distance: N) -> P2;
    fn direction_along(&self, distance: N) -> V2;
    fn start(&self) -> P2;
    fn start_direction(&self) -> V2 {
        self.direction_along(0.0)
    }
    fn end(&self) -> P2;
    fn end_direction(&self) -> V2 {
        self.direction_along(self.length())
    }
    fn reverse(&self) -> Self;
    fn subsection(&self, start: N, end: N) -> Option<Self>;
    fn shift_orthogonally(&self, shift_to_right: N) -> Option<Self>;
}

pub trait Shape {
    fn contains(&self, point: P2) -> bool;
}

#[derive(Copy, Clone)]
pub struct BoundingBox {
    pub min: P2,
    pub max: P2,
}

impl BoundingBox {
    pub fn infinite() -> Self {
        BoundingBox {
            min: P2::new(std::f32::INFINITY, std::f32::INFINITY),
            max: P2::new(std::f32::INFINITY, std::f32::INFINITY),
        }
    }

    pub fn overlaps(&self, other: &BoundingBox) -> bool {
        self.max.x >= other.min.x && other.max.x >= self.min.x && self.max.y >= other.min.y &&
        other.max.y >= self.min.y
    }

    pub fn point(p: P2) -> Self {
        BoundingBox { min: p, max: p }
    }

    pub fn grown_by(&self, offset: N) -> Self {
        BoundingBox {
            min: self.min - V2::new(offset, offset),
            max: self.max + V2::new(offset, offset),
        }
    }
}

impl ::std::iter::Sum<BoundingBox> for BoundingBox {
    fn sum<I: IntoIterator<Item = BoundingBox>>(iter: I) -> Self {
        let mut bb = BoundingBox::infinite();

        for other_bb in iter {
            bb.min = P2::new(bb.min.x.min(other_bb.min.x), bb.min.y.min(other_bb.min.y));
            bb.max = P2::new(bb.max.x.max(other_bb.max.x), bb.max.y.max(other_bb.max.y));
        }

        bb
    }
}

pub trait HasBoundingBox {
    fn bounding_box(&self) -> BoundingBox;
}
<commit_msg>remove broken bbox code<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
extern crate nalgebra;
extern crate ncollide_transformation;
extern crate ordered_float;

use nalgebra::{Vector2, Point2, Vector3, Vector4, Point3, Isometry3, Perspective3, Matrix4};
pub use nalgebra::{Dot, ToHomogeneous, Norm, Inverse, Rotate};
use std::f32::consts::PI;

pub type N = f32;
pub type V2 = Vector2<N>;
pub type P2 = Point2<N>;
pub type V3 = Vector3<N>;
pub type V4 = Vector4<N>;
pub type P3 = Point3<N>;
pub type M4 = Matrix4<N>;
pub type Iso3 = Isometry3<N>;
pub type Persp3 = Perspective3<N>;

// Thickness radius
const THICKNESS: N = 0.001;
const ROUGH_TOLERANCE: N = 0.0000001;

mod primitives;
mod path;
mod intersect;
mod shapes;

pub use self::primitives::*;
pub use self::path::{Path, convex_hull};
pub use self::intersect::*;
pub use self::shapes::*;

pub fn angle_to(a: V2, b: V2) -> N {
    let theta: N = a.dot(&b) / (a.norm() * b.norm());
    theta.min(1.0).max(-1.0).acos()
}

pub fn angle_along_to(a: V2, a_direction: V2, b: V2) -> N {
    let simple_angle = angle_to(a, b);
    let linear_direction = (b - a).normalize();

    if a_direction.dot(&linear_direction) >= 0.0 {
        simple_angle
    } else {
        2.0 * PI - simple_angle
    }
}

pub trait WithUniqueOrthogonal {
    fn orthogonal(&self) -> Self;
}

impl WithUniqueOrthogonal for V2 {
    fn orthogonal(&self) -> V2 {
        V2::new(self.y, -self.x)
    }
}

pub trait RelativeToBasis {
    fn to_basis(self, basis_x: Self) -> Self;
    fn from_basis(self, basis_x: Self) -> Self;
}

impl RelativeToBasis for V2 {
    fn to_basis(self, basis_x: V2) -> V2 {
        V2::new(basis_x.dot(&self), basis_x.orthogonal().dot(&self))
    }

    fn from_basis(self, basis_x: V2) -> V2 {
        self.x * basis_x + self.y * basis_x.orthogonal()
    }
}

pub trait Into2d {
    type Target;
    fn into_2d(self) -> Self::Target;
}

impl Into2d for V3 {
    type Target = V2;
    fn into_2d(self) -> V2 {
        V2::new(self.x, self.y)
    }
}

impl Into2d for P3 {
    type Target = P2;
    fn into_2d(self) -> P2 {
        P2::new(self.x, self.y)
    }
}

pub trait Into3d {
    type Target;
    fn into_3d(self) -> Self::Target;
}

impl Into3d for V2 {
    type Target = V3;
    fn into_3d(self) -> V3 {
        V3::new(self.x, self.y, 0.0)
    }
}

impl Into3d for P2 {
    type Target = P3;
    fn into_3d(self) -> P3 {
        P3::new(self.x, self.y, 0.0)
    }
}

pub trait RoughlyComparable: Sized {
    fn is_roughly(&self, other: Self) -> bool {
        self.is_roughly_within(other, ROUGH_TOLERANCE)
    }
    fn is_roughly_within(&self, other: Self, tolerance: N) -> bool;
}

impl RoughlyComparable for N {
    fn is_roughly_within(&self, other: N, tolerance: N) -> bool {
        (self - other).abs() <= tolerance
    }
}

impl RoughlyComparable for P2 {
    fn is_roughly_within(&self, other: P2, tolerance: N) -> bool {
        (*self - other).norm() <= tolerance
    }
}

impl RoughlyComparable for V2 {
    fn is_roughly_within(&self, other: V2, tolerance: N) -> bool {
        (*self - other).norm() <= tolerance
    }
}

pub trait Curve: Sized {
    fn project_with_max_distance(&self, point: P2, max_distance: N, tolerance: N) -> Option<N> {
        self.project_with_tolerance(point, tolerance).and_then(
            |offset| {
                if self.distance_to(point) < max_distance {
                    Some(offset)
                } else {
                    None
                }
            },
        )
    }
    fn project_with_tolerance(&self, point: P2, tolerance: N) -> Option<N>;
    fn project(&self, point: P2) -> Option<N> {
        self.project_with_tolerance(point, THICKNESS)
    }
    fn includes(&self, point: P2) -> bool {
        self.distance_to(point) < THICKNESS / 2.0
    }
    fn distance_to(&self, point: P2) -> N;
}

pub trait FiniteCurve: Curve {
    fn length(&self) -> N;
    fn along(&self, distance: N) -> P2;
    fn direction_along(&self, distance: N) -> V2;
    fn start(&self) -> P2;
    fn start_direction(&self) -> V2 {
        self.direction_along(0.0)
    }
    fn end(&self) -> P2;
    fn end_direction(&self) -> V2 {
        self.direction_along(self.length())
    }
    fn reverse(&self) -> Self;
    fn subsection(&self, start: N, end: N) -> Option<Self>;
    fn shift_orthogonally(&self, shift_to_right: N) -> Option<Self>;
}

pub trait Shape {
    fn contains(&self, point: P2) -> bool;
}

#[derive(Copy, Clone)]
pub struct BoundingBox {
    pub min: P2,
    pub max: P2,
}

impl BoundingBox {
    pub fn infinite() -> Self {
        BoundingBox {
            min: P2::new(std::f32::NEG_INFINITY, std::f32::NEG_INFINITY),
            max: P2::new(std::f32::INFINITY, std::f32::INFINITY),
        }
    }

    pub fn overlaps(&self, other: &BoundingBox) -> bool {
        self.max.x >= other.min.x && other.max.x >= self.min.x && self.max.y >= other.min.y &&
            other.max.y >= self.min.y
    }

    pub fn point(p: P2) -> Self {
        BoundingBox { min: p, max: p }
    }

    pub fn grown_by(&self, offset: N) -> Self {
        BoundingBox {
            min: self.min - V2::new(offset, offset),
            max: self.max + V2::new(offset, offset),
        }
    }
}

pub trait HasBoundingBox {
    fn bounding_box(&self) -> BoundingBox;
}
<|endoftext|>