<commit_before>#![feature(libc)]
#![feature(plugin)]

#![allow(dead_code)]
#![allow(unused_imports)]

extern crate libc;
#[macro_use] extern crate bitflags;

mod nginx;

use std::ffi::CString;
use std::ptr;
use std::mem;
use std::boxed;

use nginx::ffi::{
   ngx_str_t, ngx_http_request_t, ngx_pcalloc, ngx_palloc, ngx_conf_t, ngx_command_t, ngx_http_core_module,
   ngx_http_conf_ctx_t, ngx_int_t, ngx_http_output_filter, ngx_chain_t, ngx_http_send_header, ngx_buf_t,
   ngx_uint_t, ngx_http_core_loc_conf_t, ngx_log_error_core,
};
use nginx::Status;

use libc::{size_t, c_void, c_uchar, c_char};

const NGX_CONF_OK: *const c_char = 0 as *const c_char;
const NGX_CONF_ERROR: *const c_char = -1 as *const c_char;

macro_rules! ngx_http_conf_get_module_loc_conf {
   ($cf:expr, $module:expr) => ({
      (*
         (
            (*
               (
                  (*$cf).ctx as *mut ngx_http_conf_ctx_t
               )
            ).loc_conf
         ).offset($module.ctx_index as isize)
      ) as *mut ngx_http_core_loc_conf_t
   })
}

macro_rules! ngx_alloc_buf {
   ($pool:expr) => (
      ngx_palloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! ngx_calloc_buf {
   ($pool:expr) => (
      ngx_pcalloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! log_error_core {
   ($level:expr, $log:expr, $err:expr, $fmt:expr, $( $arg:expr ),*) => (
      ngx_log_error_core($level, $log.raw(), $err, $fmt, $( $arg ),*)
   )
}

bitflags! {
   flags BufFlags: u32 {
      const FLAG_TEMPORARY        = 0b0000000000000001,
      const FLAG_MEMORY           = 0b0000000000000010,
      const FLAG_MMAP             = 0b0000000000000100,
      const FLAG_RECYCLED         = 0b0000000000001000,
      const FLAG_IN_FILE          = 0b0000000000010000,
      const FLAG_FLUSH            = 0b0000000000100000,
      const FLAG_SYNC             = 0b0000000001000000,
      const FLAG_LAST_BUF         = 0b0000000010000000,
      const FLAG_LAST_IN_CHAIN    = 0b0000000100000000,
      const FLAG_LAST_SHADOW      = 0b0000001000000000,
      const FLAG_TEMP_FILE        = 0b0000010000000000,
   }
}

macro_rules! simple_http_module_command {
   ($command:ident, $handler:ident) => (
      #[no_mangle]
      pub extern fn $command(
         cf: *mut ngx_conf_t,
         _: *mut ngx_command_t,
         _: *mut c_void
      ) -> *const c_char {
         unsafe {
            let clcf = ngx_http_conf_get_module_loc_conf!(cf, ngx_http_core_module);
            (*clcf).handler = Some($handler);
         }

         NGX_CONF_OK
      }
   )
}

simple_http_module_command!(ngx_http_sample_module_command, ngx_http_sample_handler);

#[no_mangle]
pub extern fn ngx_http_sample_handler(r: *mut ngx_http_request_t) -> ngx_int_t
{
   let mut request = nginx::HttpRequest::from_raw(r);

   let mut connection = request.connection().unwrap();

   let mut log = connection.log().unwrap();

   let ngx_http_sample_text: ngx_str_t = sample_text_from_rust(r);

   let mut headers_out = request.headers_out();

   headers_out.set_status(200);
   headers_out.set_content_length_n(ngx_http_sample_text.len as i64);

   match request.http_send_header() {
      Status::Error => {
         return Status::Error.rc();
      }
      Status::Http(http_status) => {
         return Status::Http(http_status).rc();
      }
      _ => {}
   }
   //if rc == NGX_ERROR || rc > NGX_OK { //|| (*r).header_only) {

   let mut pool = request.pool().unwrap();

   let mut buf = pool.calloc_buf().unwrap(); // return 500 on error

   unsafe {
      let mut chain = ngx_chain_t {
         buf: buf.raw(),
         next: ptr::null_mut()
      };

      let out: *mut ngx_chain_t = (&mut chain) as *mut ngx_chain_t;

      let headers_in = (*r).headers_in;

      let cstr_template = CString::new("BITS: \"%s\"").unwrap();
      let b1 = CString::new(format!("{:032b}", headers_in._bindgen_bitfield_1_)).unwrap();

      log_error_core!(
         2, log, 0,
         cstr_template.as_ptr(),
         b1.as_ptr()
      );

      (*buf.raw()).start = ngx_http_sample_text.data;
      (*buf.raw()).pos = (*buf.raw()).start;

      (*buf.raw()).end = ngx_http_sample_text.data.offset(ngx_http_sample_text.len as isize);
      (*buf.raw()).last = (*buf.raw()).end;

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      (*buf.raw())._bindgen_bitfield_1_ = buf_flags.bits();

      ngx_http_output_filter(r, out)
   }
}

fn sample_text_from_rust(r: *mut ngx_http_request_t) -> ngx_str_t
{
   let s = CString::new("<meta charset=\"utf-8\">Здравейте!".to_string()).unwrap();
   let len = s.to_bytes().len() as size_t;

   let result = ngx_str_t {
      len: len,
      data: unsafe {
         ngx_pcalloc((*r).pool, len) as *mut u8
      },
   };

   unsafe {
      ptr::copy_nonoverlapping(result.data, s.as_ptr() as *const u8, len as usize);
   }

   result
}

#[no_mangle]
pub extern fn dump_request(r: *mut ngx_http_request_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "REQ: \
         method=\"%ud\" \
         http_version=\"%ud\" \
         request_line=\"%V\" \
         uri=\"%V\" \
         args=\"%V\" \
         exten=\"%V\" \
         unparsed_uri=\"%V\" \
         method_name=\"%V\" \
         http_protocol=\"%V\" \
         bit1=\"%s\" \
         bit2=\"%s\" \
         bit3=\"%s\" \
         bit4=\"%s\" \
         bits=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_1_)).unwrap();
      let b2 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_2_)).unwrap();
      let b3 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_3_)).unwrap();
      let b4 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_4_)).unwrap();

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      let bits = CString::new(format!("{:032b}", buf_flags.bits())).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*r).method,
         (*r).http_version,
         &((*r).request_line),
         &((*r).uri),
         &((*r).args),
         &((*r).exten),
         &((*r).unparsed_uri),
         &((*r).method_name),
         &((*r).http_protocol),
         b1.as_ptr(),
         b2.as_ptr(),
         b3.as_ptr(),
         b4.as_ptr(),
         bits.as_ptr(),
      );
   }
}

#[no_mangle]
pub extern fn dump_buffer(r: *mut ngx_http_request_t, b: *mut ngx_buf_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "BUF: \
         pos=\"%p\" \
         last=\"%p\" \
         start=\"%p\" \
         end=\"%p\" \
         num=\"%d\" \
         bit1=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:064b}", (*b)._bindgen_bitfield_1_)).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*b).pos,
         (*b).last,
         (*b).start,
         (*b).end,
         (*b).num,
         b1.as_ptr(),
      );
   }
}
<commit_msg>Removing the logging, so that the focus is shifted on pure functionality.<commit_after>#![feature(libc)]
#![feature(plugin)]

#![allow(dead_code)]
#![allow(unused_imports)]

extern crate libc;
#[macro_use] extern crate bitflags;

mod nginx;

use std::ffi::CString;
use std::ptr;
use std::mem;
use std::boxed;

use nginx::ffi::{
   ngx_str_t, ngx_http_request_t, ngx_pcalloc, ngx_palloc, ngx_conf_t, ngx_command_t, ngx_http_core_module,
   ngx_http_conf_ctx_t, ngx_int_t, ngx_http_output_filter, ngx_chain_t, ngx_http_send_header, ngx_buf_t,
   ngx_uint_t, ngx_http_core_loc_conf_t, ngx_log_error_core,
};
use nginx::Status;

use libc::{size_t, c_void, c_uchar, c_char};

const NGX_CONF_OK: *const c_char = 0 as *const c_char;
const NGX_CONF_ERROR: *const c_char = -1 as *const c_char;

macro_rules! ngx_http_conf_get_module_loc_conf {
   ($cf:expr, $module:expr) => ({
      (*
         (
            (*
               (
                  (*$cf).ctx as *mut ngx_http_conf_ctx_t
               )
            ).loc_conf
         ).offset($module.ctx_index as isize)
      ) as *mut ngx_http_core_loc_conf_t
   })
}

macro_rules! ngx_alloc_buf {
   ($pool:expr) => (
      ngx_palloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! ngx_calloc_buf {
   ($pool:expr) => (
      ngx_pcalloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! log_error_core {
   ($level:expr, $log:expr, $err:expr, $fmt:expr, $( $arg:expr ),*) => (
      ngx_log_error_core($level, $log.raw(), $err, $fmt, $( $arg ),*)
   )
}

bitflags! {
   flags BufFlags: u32 {
      const FLAG_TEMPORARY        = 0b0000000000000001,
      const FLAG_MEMORY           = 0b0000000000000010,
      const FLAG_MMAP             = 0b0000000000000100,
      const FLAG_RECYCLED         = 0b0000000000001000,
      const FLAG_IN_FILE          = 0b0000000000010000,
      const FLAG_FLUSH            = 0b0000000000100000,
      const FLAG_SYNC             = 0b0000000001000000,
      const FLAG_LAST_BUF         = 0b0000000010000000,
      const FLAG_LAST_IN_CHAIN    = 0b0000000100000000,
      const FLAG_LAST_SHADOW      = 0b0000001000000000,
      const FLAG_TEMP_FILE        = 0b0000010000000000,
   }
}

macro_rules! simple_http_module_command {
   ($command:ident, $handler:ident) => (
      #[no_mangle]
      pub extern fn $command(
         cf: *mut ngx_conf_t,
         _: *mut ngx_command_t,
         _: *mut c_void
      ) -> *const c_char {
         unsafe {
            let clcf = ngx_http_conf_get_module_loc_conf!(cf, ngx_http_core_module);
            (*clcf).handler = Some($handler);
         }

         NGX_CONF_OK
      }
   )
}

simple_http_module_command!(ngx_http_sample_module_command, ngx_http_sample_handler);

#[no_mangle]
pub extern fn ngx_http_sample_handler(r: *mut ngx_http_request_t) -> ngx_int_t
{
   let mut request = nginx::HttpRequest::from_raw(r);

   let ngx_http_sample_text: ngx_str_t = sample_text_from_rust(r);

   let mut headers_out = request.headers_out();

   headers_out.set_status(200);
   headers_out.set_content_length_n(ngx_http_sample_text.len as i64);

   match request.http_send_header() {
      Status::Error => {
         return Status::Error.rc();
      }
      Status::Http(http_status) => {
         return Status::Http(http_status).rc();
      }
      _ => {}
   }
   //if rc == NGX_ERROR || rc > NGX_OK { //|| (*r).header_only) {

   let mut pool = request.pool().unwrap();

   let mut buf = pool.calloc_buf().unwrap(); // return 500 on error

   unsafe {
      let mut chain = ngx_chain_t {
         buf: buf.raw(),
         next: ptr::null_mut()
      };

      let out: *mut ngx_chain_t = (&mut chain) as *mut ngx_chain_t;

      (*buf.raw()).start = ngx_http_sample_text.data;
      (*buf.raw()).pos = (*buf.raw()).start;

      (*buf.raw()).end = ngx_http_sample_text.data.offset(ngx_http_sample_text.len as isize);
      (*buf.raw()).last = (*buf.raw()).end;

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      (*buf.raw())._bindgen_bitfield_1_ = buf_flags.bits();

      ngx_http_output_filter(r, out)
   }
}

fn sample_text_from_rust(r: *mut ngx_http_request_t) -> ngx_str_t
{
   let s = CString::new("<meta charset=\"utf-8\">Здравейте!".to_string()).unwrap();
   let len = s.to_bytes().len() as size_t;

   let result = ngx_str_t {
      len: len,
      data: unsafe {
         ngx_pcalloc((*r).pool, len) as *mut u8
      },
   };

   unsafe {
      ptr::copy_nonoverlapping(result.data, s.as_ptr() as *const u8, len as usize);
   }

   result
}
<|endoftext|>


<commit_before>//! A scoped linear allocator.
//! This is useful for reusing a block of memory for temporary allocations within
//! a tight inner loop. Multiple nested scopes can be used if desired.
//!
//! # Examples
//! ```rust
//! use scoped_allocator::ScopedAllocator;
//! struct Bomb(u8);
//! impl Drop for Bomb {
//!     fn drop(&mut self) {
//!         println!("Boom! {}", self.0);
//!     }
//! }
//! // new allocator with a kilobyte of memory.
//! let alloc = ScopedAllocator::new(1024);
//!
//! alloc.scope(|inner| {
//!     let mut bombs = Vec::new();
//!     for i in 0..100 { bombs.push(inner.allocate(Bomb(i)).ok().unwrap())}
//!     // watch the bombs go off!
//! });
//!
//! let my_int = alloc.allocate(23).ok().unwrap();
//! println!("My int: {}", *my_int);
//! ```
#![feature(alloc, heap_api, ptr_as_ref)]

use std::cell::Cell;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

use alloc::heap;

extern crate alloc;

/// An item allocated by a custom allocator.
pub struct Allocated<'a, T: 'a> {
    item: &'a mut T,
}

impl<'a, T> Deref for Allocated<'a, T> {
    type Target = T;

    fn deref<'b>(&'b self) -> &'b T {
        &*self.item
    }
}

impl<'a, T> DerefMut for Allocated<'a, T> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut T {
        self.item
    }
}

impl<'a, T> Drop for Allocated<'a, T> {
    #[inline]
    fn drop(&mut self) {
        // could also use ptr::read_and_drop
        unsafe { let _ = ptr::read(self.item as *mut T); }
    }
}

/// A scoped linear allocator
pub struct ScopedAllocator {
    current: Cell<*mut u8>,
    end: *mut u8,
    start: *mut u8,
}

impl ScopedAllocator {
    /// Creates a new `ScopedAllocator` backed by `size` bytes.
    pub fn new(size: usize) -> Self {
        // Create a memory buffer with the desired size and maximal align.
        let start = if size != 0 {
            unsafe { heap::allocate(size, mem::align_of::<usize>()) }
        } else {
            heap::EMPTY as *mut u8
        };

        if start.is_null() {
            // do result-based error management instead?
            panic!("Out of memory!");
        }

        ScopedAllocator {
            current: Cell::new(start),
            end: unsafe { start.offset(size as isize) },
            start: start,
        }

    }

    /// Attempts to allocate space for the T supplied to it.
    ///
    /// This function is most definitely not thread-safe.
    /// Returns either the allocated object or `val` back on failure.
    ///
    /// # Panics
    ///
    /// Panics if this is called on a currently scoped allocator.
    pub fn allocate<'a, T>(&'a self, val: T) -> Result<Allocated<'a, T>, T> {
        match unsafe { self.allocate_raw(mem::size_of::<T>(), mem::align_of::<T>()) } {
            Ok(ptr) => {
                let item = ptr as *mut T;
                unsafe { ptr::write(item, val) };

                Ok(Allocated {
                    item: unsafe { item.as_mut().expect("allocate returned null ptr") },
                })
            }
            Err(_) => Err(val)
        }
    }

    /// Attempts to allocate some bytes directly.
    /// Returns either a pointer to the start of the allocated block or nothing.
    ///
    /// # Panics
    ///
    /// Panics if this is called on a currently scoped allocator.
    pub unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<*mut u8, ()> {
        self.ensure_not_scoped();
        let current_ptr = self.current.get();
        let aligned_ptr = ((current_ptr as usize + align - 1) & !(align - 1)) as *mut u8;
        let end_ptr = aligned_ptr.offset(size as isize);

        if end_ptr > self.end {
            Err(())
        } else {
            self.current.set(end_ptr);
            Ok(aligned_ptr)
        }
    }

    /// Calls the supplied function with a new scope of the allocator.
    ///
    /// # Panics
    ///
    /// Panics if this is called on a currently scoped allocator.
    pub fn scope<F, U>(&self, f: F) -> U where F: FnMut(&ScopedAllocator) -> U {
        self.ensure_not_scoped();
        let mut f = f;
        let old = self.current.get();
        let alloc = ScopedAllocator {
            current: self.current.clone(),
            end: self.end,
            start: self.start,
        };

        // set the current pointer to null as a flag to indicate
        // that this allocator is being scoped.
        self.current.set(ptr::null_mut());
        let u = f(&alloc);
        self.current.set(old);

        mem::forget(alloc);
        u
    }

    fn ensure_not_scoped(&self) {
        debug_assert!(
            !self.current.get().is_null(),
            "Called method on currently scoped allocator"
        );
    }
}

impl Drop for ScopedAllocator {
    /// Drops the `ScopedAllocator`
    fn drop(&mut self) {
        let size = self.end as usize - self.start as usize;
        // if the allocator is scoped, the memory will be freed by the child.
        if !self.current.get().is_null() && size > 0 {
            unsafe { heap::deallocate(self.start, size, mem::align_of::<usize>()) }
        }
    }
}

#[test]
#[should_panic]
fn use_outer() {
    let alloc = ScopedAllocator::new(4);
    alloc.scope(|_inner| {
        // using outer allocator is dangerous and should fail.
        let _val = alloc.allocate(1i32).ok().unwrap();
    })
}
<commit_msg>Implemented unsizing and helper traits for Allocated.<commit_after>//! A scoped linear allocator.
//! This is useful for reusing a block of memory for temporary allocations within
//! a tight inner loop. Multiple nested scopes can be used if desired.
//!
//! # Examples
//! ```rust
//! use scoped_allocator::ScopedAllocator;
//! struct Bomb(u8);
//! impl Drop for Bomb {
//!     fn drop(&mut self) {
//!         println!("Boom! {}", self.0);
//!     }
//! }
//! // new allocator with a kilobyte of memory.
//! let alloc = ScopedAllocator::new(1024);
//!
//! alloc.scope(|inner| {
//!     let mut bombs = Vec::new();
//!     for i in 0..100 { bombs.push(inner.allocate(Bomb(i)).ok().unwrap())}
//!     // watch the bombs go off!
//! });
//!
//! let my_int = alloc.allocate(23).ok().unwrap();
//! println!("My int: {}", *my_int);
//! ```

#![feature(
    alloc,
    coerce_unsized,
    core_intrinsics,
    heap_api,
    ptr_as_ref,
    raw,
    unsize
)]

use std::any::Any;
use std::borrow::{Borrow, BorrowMut};
use std::cell::Cell;
use std::intrinsics::drop_in_place;
use std::marker::Unsize;
use std::mem;
use std::ops::{CoerceUnsized, Deref, DerefMut};
use std::raw::TraitObject;
use std::ptr;

use alloc::heap;

extern crate alloc;

/// An item allocated by a custom allocator.
pub struct Allocated<'a, T: 'a + ?Sized> {
    item: &'a mut T,
}

impl<'a, T: ?Sized> Deref for Allocated<'a, T> {
    type Target = T;

    fn deref<'b>(&'b self) -> &'b T {
        &*self.item
    }
}

impl<'a, T: ?Sized> DerefMut for Allocated<'a, T> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut T {
        self.item
    }
}

// Allocated can store trait objects!
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Allocated<'a, U>> for Allocated<'a, T> {}

impl<'a> Allocated<'a, Any> {
    /// Attempts to downcast this `Allocated` to a concrete type.
    pub fn downcast<T: Any>(self) -> Result<Allocated<'a, T>, Allocated<'a, Any>> {
        if self.item.is::<T>() {
            let obj: TraitObject = unsafe { mem::transmute(self.item as *mut Any) };
            mem::forget(self);
            Ok(Allocated { item: unsafe { mem::transmute(obj.data) } })
        } else {
            Err(self)
        }
    }
}

impl<'a, T: ?Sized> Borrow<T> for Allocated<'a, T> {
    fn borrow(&self) -> &T { &**self }
}

impl<'a, T: ?Sized> BorrowMut<T> for Allocated<'a, T> {
    fn borrow_mut(&mut self) -> &mut T { &mut **self }
}

impl<'a, T: ?Sized> Drop for Allocated<'a, T> {
    #[inline]
    fn drop(&mut self) {
        unsafe { let _ = drop_in_place(self.item as *mut T); }
    }
}

/// A scoped linear allocator
pub struct ScopedAllocator {
    current: Cell<*mut u8>,
    end: *mut u8,
    start: *mut u8,
}

impl ScopedAllocator {
    /// Creates a new `ScopedAllocator` backed by `size` bytes.
    pub fn new(size: usize) -> Self {
        // Create a memory buffer with the desired size and maximal align.
        let start = if size != 0 {
            unsafe { heap::allocate(size, mem::align_of::<usize>()) }
        } else {
            heap::EMPTY as *mut u8
        };

        if start.is_null() {
            // do result-based error management instead?
            panic!("Out of memory!");
        }

        ScopedAllocator {
            current: Cell::new(start),
            end: unsafe { start.offset(size as isize) },
            start: start,
        }

    }

    /// Attempts to allocate space for the T supplied to it.
    ///
    /// This function is most definitely not thread-safe.
    /// Returns either the allocated object or `val` back on failure.
    ///
    /// # Panics
    ///
    /// Panics if this is called on a currently scoped allocator.
    pub fn allocate<'a, T>(&'a self, val: T) -> Result<Allocated<'a, T>, T> {
        match unsafe { self.allocate_raw(mem::size_of::<T>(), mem::align_of::<T>()) } {
            Ok(ptr) => {
                let item = ptr as *mut T;
                unsafe { ptr::write(item, val) };

                Ok(Allocated {
                    item: unsafe { item.as_mut().expect("allocate returned null ptr") },
                })
            }
            Err(_) => Err(val)
        }
    }

    /// Attempts to allocate some bytes directly.
    /// Returns either a pointer to the start of the allocated block or nothing.
    ///
    /// # Panics
    ///
    /// Panics if this is called on a currently scoped allocator.
    pub unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<*mut u8, ()> {
        self.ensure_not_scoped();
        let current_ptr = self.current.get();
        let aligned_ptr = ((current_ptr as usize + align - 1) & !(align - 1)) as *mut u8;
        let end_ptr = aligned_ptr.offset(size as isize);

        if end_ptr > self.end {
            Err(())
        } else {
            self.current.set(end_ptr);
            Ok(aligned_ptr)
        }
    }

    /// Calls the supplied function with a new scope of the allocator.
    ///
    /// # Panics
    ///
    /// Panics if this is called on a currently scoped allocator.
    pub fn scope<F, U>(&self, f: F) -> U where F: FnMut(&ScopedAllocator) -> U {
        self.ensure_not_scoped();
        let mut f = f;
        let old = self.current.get();
        let alloc = ScopedAllocator {
            current: self.current.clone(),
            end: self.end,
            start: self.start,
        };

        // set the current pointer to null as a flag to indicate
        // that this allocator is being scoped.
        self.current.set(ptr::null_mut());
        let u = f(&alloc);
        self.current.set(old);

        mem::forget(alloc);
        u
    }

    fn ensure_not_scoped(&self) {
        debug_assert!(
            !self.current.get().is_null(),
            "Called method on currently scoped allocator"
        );
    }
}

impl Drop for ScopedAllocator {
    /// Drops the `ScopedAllocator`
    fn drop(&mut self) {
        let size = self.end as usize - self.start as usize;
        // if the allocator is scoped, the memory will be freed by the child.
        if !self.current.get().is_null() && size > 0 {
            unsafe { heap::deallocate(self.start, size, mem::align_of::<usize>()) }
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    #[should_panic]
    fn use_outer() {
        let alloc = ScopedAllocator::new(4);
        alloc.scope(|_inner| {
            // using outer allocator is dangerous and should fail.
            let _val = alloc.allocate(1i32).ok().unwrap();
        })
    }

    #[test]
    fn test_unsizing() {
        struct Bomb;
        impl Drop for Bomb {
            fn drop(&mut self) { println!("Boom") }
        }

        let alloc = ScopedAllocator::new(4);
        let my_foo: Allocated<Any> = alloc.allocate(Bomb).ok().unwrap();
        let _: Allocated<Bomb> = my_foo.downcast().ok().unwrap();
    }
}<|endoftext|>


<commit_before>// Module for parsing ISO Base Media Format aka video/mp4 streams.

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

/// Basic ISO box structure.
pub struct BoxHeader {
    /// Four character box type
pub name: u32,
    /// Size of the box in bytes
pub size: u64,
    /// Offset to the start of the contained data (or header size).
pub offset: u64,
}

/// File type box 'ftyp'.
pub struct FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

/// Movie header box 'mvhd'.
pub struct MovieHeaderBox {
    pub name: u32,
    pub size: u64,
    pub timescale: u32,
    pub duration: u64,
    // Ignore other fields.
}

pub struct TrackHeaderBox {
    pub name: u32,
    pub size: u64,
    pub track_id: u32,
    pub duration: u64,
    pub width: u32,
    pub height: u32,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Read, Result, Seek, SeekFrom, Take};
use std::io::Cursor;

/// Parse a box out of a data buffer.
pub fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
    let tmp_size = try!(src.read_u32::<BigEndian>());
    let name = try!(src.read_u32::<BigEndian>());
    let size = match tmp_size {
        1 => try!(src.read_u64::<BigEndian>()),
        _ => tmp_size as u64,
    };
    assert!(size >= 8);
    if tmp_size == 1 {
        assert!(size >= 16);
    }
    let offset = match tmp_size {
        1 => 4 + 4 + 8,
        _ => 4 + 4,
    };
    assert!(offset <= size);
    Ok(BoxHeader{
      name: name,
      size: size,
      offset: offset,
    })
}

/// Parse the extra header fields for a full box.
fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> (u8, u32) {
    let version = src.read_u8().unwrap();
    let flags_a = src.read_u8().unwrap();
    let flags_b = src.read_u8().unwrap();
    let flags_c = src.read_u8().unwrap();
    (version, (flags_a as u32) << 16 |
              (flags_b as u32) <<  8 |
              (flags_c as u32))
}

/// Skip over the contents of a box.
pub fn skip_box_content<T: ReadBytesExt + Seek>
  (src: &mut T, header: &BoxHeader)
  -> std::io::Result<u64>
{
    src.seek(SeekFrom::Current((header.size - header.offset) as i64))
}

/// Helper to construct a Take over the contents of a box.
fn limit<'a, T: Read>(f: &'a mut T, h: &BoxHeader) -> Take<&'a mut T> {
    f.take(h.size - h.offset)
}

/// Helper to construct a Cursor over the contents of a box.
fn recurse<T: Read>(f: &mut T, h: &BoxHeader) {
    println!("{} -- recursing", h);
    // FIXME: I couldn't figure out how to do this without copying.
    // We use Seek on the Read we return in skip_box_content, but
    // that trait isn't implemented for a Take like our limit()
    // returns. Slurping the buffer and wrapping it in a Cursor
    // functions as a work around.
    let buf: Vec<u8> = limit(f, &h)
        .bytes()
        .map(|u| u.unwrap())
        .collect();
    let mut content = Cursor::new(buf);
    loop {
        read_box(&mut content).unwrap();
    }
    println!("{} -- end", h);
}

/// Read the contents of a box, including sub boxes.
/// Right now it just prints the box value rather than
/// returning anything.
pub fn read_box<T: Read + Seek>(f: &mut T) -> Result<()> {
    read_box_header(f).and_then(|h| {
        match &(fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                let ftyp = read_ftyp(&mut content, &h).unwrap();
                println!("{}", ftyp);
            },
            "moov" => recurse(f, &h),
            "mvhd" => {
                let mut content = limit(f, &h);
                let mvhd = read_mvhd(&mut content, &h).unwrap();
                println!("  {}", mvhd);
            },
            "trak" => recurse(f, &h),
            "tkhd" => {
                let mut content = limit(f, &h);
                let tkhd = read_tkhd(&mut content, &h).unwrap();
                println!("  {}", tkhd);
            },
            _ => {
                // Skip the contents of unknown chunks.
                println!("{} (skipped)", h);
                skip_box_content(f, &h).unwrap();
            },
        };
        Ok(()) // and_then needs a Result to return.
    })
}

/// Entry point for C language callers.
/// Take a buffer and call read_box() on it.
#[no_mangle]
pub unsafe extern fn read_box_from_buffer(buffer: *const u8, size: usize)
  -> bool {
    use std::slice;
    use std::thread;

    // Validate arguments from C.
    if buffer.is_null() || size < 8 {
        return false;
    }

    // Wrap the buffer we've been give in a slice.
    let b = slice::from_raw_parts(buffer, size);
    let mut c = Cursor::new(b);

    // Parse in a subthread.
    let task = thread::spawn(move || {
        read_box(&mut c).unwrap();
    });
    // Catch any panics.
    task.join().is_ok()
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<FileTypeBox> {
    let major = src.read_u32::<BigEndian>().unwrap();
    let minor = src.read_u32::<BigEndian>().unwrap();
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push(src.read_u32::<BigEndian>().unwrap());
    }
    Some(FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

/// Parse an mvhd box.
pub fn read_mvhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<MovieHeaderBox> {
    let (version, _) = read_fullbox_extra(src);
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        _ => panic!("invalid mhdr version"),
    }
    let timescale = src.read_u32::<BigEndian>().unwrap();
    let duration = match version {
        1 => src.read_u64::<BigEndian>().unwrap(),
        0 => src.read_u32::<BigEndian>().unwrap() as u64,
        _ => panic!("invalid mhdr version"),
    };
    // Skip remaining fields.
    let mut skip: Vec<u8> = vec![0; 80];
    let r = src.read(&mut skip).unwrap();
    assert!(r == skip.len());
    Some(MovieHeaderBox {
        name: head.name,
        size: head.size,
        timescale: timescale,
        duration: duration,
    })
}

/// Parse a tkhd box.
pub fn read_tkhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<TrackHeaderBox> {
    let (version, flags) = read_fullbox_extra(src);
    if flags & 0x1u32 == 0 || flags & 0x2u32 == 0 {
        // Track is disabled.
        return None;
    }
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        _ => panic!("invalid tkhd version"),
    }
    let track_id = src.read_u32::<BigEndian>().unwrap();
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    assert!(_reserved == 0);
    let duration = match version {
        1 => {
            src.read_u64::<BigEndian>().unwrap()
        },
        0 => src.read_u32::<BigEndian>().unwrap() as u64,
        _ => panic!("invalid tkhd version"),
    };
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    // Skip uninterested fields.
    let mut skip: Vec<u8> = vec![0; 44];
    let r = src.read(&mut skip).unwrap();
    assert!(r == skip.len());
    let width = src.read_u32::<BigEndian>().unwrap();
    let height = src.read_u32::<BigEndian>().unwrap();
    Some(TrackHeaderBox {
        name: head.name,
        size: head.size,
        track_id: track_id,
        duration: duration,
        width: width,
        height: height,
    })
}

/// Convert the iso box type or other 4-character value to a string.
fn fourcc_to_string(name: u32) -> String {
    let u32_to_vec = |u| {
        vec!((u >> 24 & 0xffu32) as u8,
             (u >> 16 & 0xffu32) as u8,
             (u >>  8 & 0xffu32) as u8,
             (u & 0xffu32) as u8)
    };
    let name_bytes = u32_to_vec(name);
    String::from_utf8_lossy(&name_bytes).into_owned()
}

use std::fmt;
impl fmt::Display for BoxHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "'{}' {} bytes", fourcc_to_string(self.name), self.size)
    }
}

impl fmt::Display for FileTypeBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        let brand = fourcc_to_string(self.major_brand);
        write!(f, "'{}' {} bytes '{}' v{}", name, self.size,
            brand, self.minor_version)
    }
}

impl fmt::Display for MovieHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        write!(f, "'{}' {} bytes duration {}s", name, self.size,
            (self.duration as f64)/(self.timescale as f64))
    }
}

use std::u16;
impl fmt::Display for TrackHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        // Dimensions are 16.16 fixed-point.
        let base = u16::MAX as f64 + 1.0;
        let width = (self.width as f64) / base;
        let height = (self.height as f64) / base;
        write!(f, "'{}' {} bytes duration {} id {} {}x{}",
            name, self.size, self.duration, self.track_id,
            width, height)
    }
}

#[test]
fn test_read_box_header() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_header_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let header = read_box_header(&mut stream).unwrap();
    let parsed = read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    println!("box {}", parsed);
}
<commit_msg>Add some error handling.<commit_after>// Module for parsing ISO Base Media Format aka video/mp4 streams.

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

/// Basic ISO box structure.
pub struct BoxHeader {
    /// Four character box type
pub name: u32,
    /// Size of the box in bytes
pub size: u64,
    /// Offset to the start of the contained data (or header size).
pub offset: u64,
}

/// File type box 'ftyp'.
pub struct FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

/// Movie header box 'mvhd'.
pub struct MovieHeaderBox {
    pub name: u32,
    pub size: u64,
    pub timescale: u32,
    pub duration: u64,
    // Ignore other fields.
}

pub struct TrackHeaderBox {
    pub name: u32,
    pub size: u64,
    pub track_id: u32,
    pub duration: u64,
    pub width: u32,
    pub height: u32,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Read, Result, Seek, SeekFrom, Take};
use std::io::Cursor;

/// Parse a box out of a data buffer.
pub fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
    let tmp_size = try!(src.read_u32::<BigEndian>());
    let name = try!(src.read_u32::<BigEndian>());
    let size = match tmp_size {
        1 => try!(src.read_u64::<BigEndian>()),
        _ => tmp_size as u64,
    };
    assert!(size >= 8);
    if tmp_size == 1 {
        assert!(size >= 16);
    }
    let offset = match tmp_size {
        1 => 4 + 4 + 8,
        _ => 4 + 4,
    };
    assert!(offset <= size);
    Ok(BoxHeader{
      name: name,
      size: size,
      offset: offset,
    })
}

/// Parse the extra header fields for a full box.
fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> (u8, u32) {
    let version = src.read_u8().unwrap();
    let flags_a = src.read_u8().unwrap();
    let flags_b = src.read_u8().unwrap();
    let flags_c = src.read_u8().unwrap();
    (version, (flags_a as u32) << 16 |
              (flags_b as u32) <<  8 |
              (flags_c as u32))
}

/// Skip over the contents of a box.
pub fn skip_box_content<T: ReadBytesExt + Seek>
  (src: &mut T, header: &BoxHeader)
  -> std::io::Result<u64>
{
    src.seek(SeekFrom::Current((header.size - header.offset) as i64))
}

/// Helper to construct a Take over the contents of a box.
fn limit<'a, T: Read>(f: &'a mut T, h: &BoxHeader) -> Take<&'a mut T> {
    f.take(h.size - h.offset)
}

/// Helper to construct a Cursor over the contents of a box.
fn recurse<T: Read>(f: &mut T, h: &BoxHeader) {
    println!("{} -- recursing", h);
    // FIXME: I couldn't figure out how to do this without copying.
    // We use Seek on the Read we return in skip_box_content, but
    // that trait isn't implemented for a Take like our limit()
    // returns. Slurping the buffer and wrapping it in a Cursor
    // functions as a work around.
    let buf: Vec<u8> = limit(f, &h)
        .bytes()
        .map(|u| u.unwrap())
        .collect();
    let mut content = Cursor::new(buf);
    loop {
        match read_box(&mut content) {
            Ok(_) => {},
            Err(e) => {
                println!("Error '{:?}' reading box", e.kind());
                break;
            },
        }
    }
    println!("{} -- end", h);
}

/// Read the contents of a box, including sub boxes.
/// Right now it just prints the box value rather than
/// returning anything.
pub fn read_box<T: Read + Seek>(f: &mut T) -> Result<()> {
    read_box_header(f).and_then(|h| {
        match &(fourcc_to_string(h.name))[..] {
            "ftyp" => {
                let mut content = limit(f, &h);
                let ftyp = read_ftyp(&mut content, &h).unwrap();
                println!("{}", ftyp);
            },
            "moov" => recurse(f, &h),
            "mvhd" => {
                let mut content = limit(f, &h);
                let mvhd = read_mvhd(&mut content, &h).unwrap();
                println!("  {}", mvhd);
            },
            "trak" => recurse(f, &h),
            "tkhd" => {
                let mut content = limit(f, &h);
                let tkhd = read_tkhd(&mut content, &h).unwrap();
                println!("  {}", tkhd);
            },
            _ => {
                // Skip the contents of unknown chunks.
                println!("{} (skipped)", h);
                skip_box_content(f, &h).unwrap();
            },
        };
        Ok(()) // and_then needs a Result to return.
    })
}

/// Entry point for C language callers.
/// Take a buffer and call read_box() on it.
#[no_mangle]
pub unsafe extern fn read_box_from_buffer(buffer: *const u8, size: usize)
  -> bool {
    use std::slice;
    use std::thread;

    // Validate arguments from C.
    if buffer.is_null() || size < 8 {
        return false;
    }

    // Wrap the buffer we've been give in a slice.
    let b = slice::from_raw_parts(buffer, size);
    let mut c = Cursor::new(b);

    // Parse in a subthread.
    let task = thread::spawn(move || {
        read_box(&mut c).unwrap();
    });
    // Catch any panics.
    task.join().is_ok()
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<FileTypeBox> {
    let major = src.read_u32::<BigEndian>().unwrap();
    let minor = src.read_u32::<BigEndian>().unwrap();
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push(src.read_u32::<BigEndian>().unwrap());
    }
    Some(FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

/// Parse an mvhd box.
pub fn read_mvhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<MovieHeaderBox> {
    let (version, _) = read_fullbox_extra(src);
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        _ => panic!("invalid mhdr version"),
    }
    let timescale = src.read_u32::<BigEndian>().unwrap();
    let duration = match version {
        1 => src.read_u64::<BigEndian>().unwrap(),
        0 => src.read_u32::<BigEndian>().unwrap() as u64,
        _ => panic!("invalid mhdr version"),
    };
    // Skip remaining fields.
    let mut skip: Vec<u8> = vec![0; 80];
    let r = src.read(&mut skip).unwrap();
    assert!(r == skip.len());
    Some(MovieHeaderBox {
        name: head.name,
        size: head.size,
        timescale: timescale,
        duration: duration,
    })
}

/// Parse a tkhd box.
pub fn read_tkhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
  -> Option<TrackHeaderBox> {
    let (version, flags) = read_fullbox_extra(src);
    if flags & 0x1u32 == 0 || flags & 0x2u32 == 0 {
        // Track is disabled.
        return None;
    }
    match version {
        1 => {
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 16];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        0 => {
            // 32 bit creation and modification times.
            // 64 bit creation and modification times.
            let mut skip: Vec<u8> = vec![0; 8];
            let r = src.read(&mut skip).unwrap();
            assert!(r == skip.len());
        },
        _ => panic!("invalid tkhd version"),
    }
    let track_id = src.read_u32::<BigEndian>().unwrap();
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    assert!(_reserved == 0);
    let duration = match version {
        1 => {
            src.read_u64::<BigEndian>().unwrap()
        },
        0 => src.read_u32::<BigEndian>().unwrap() as u64,
        _ => panic!("invalid tkhd version"),
    };
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    let _reserved = src.read_u32::<BigEndian>().unwrap();
    // Skip uninterested fields.
    let mut skip: Vec<u8> = vec![0; 44];
    let r = src.read(&mut skip).unwrap();
    assert!(r == skip.len());
    let width = src.read_u32::<BigEndian>().unwrap();
    let height = src.read_u32::<BigEndian>().unwrap();
    Some(TrackHeaderBox {
        name: head.name,
        size: head.size,
        track_id: track_id,
        duration: duration,
        width: width,
        height: height,
    })
}

/// Convert the iso box type or other 4-character value to a string.
fn fourcc_to_string(name: u32) -> String {
    let u32_to_vec = |u| {
        vec!((u >> 24 & 0xffu32) as u8,
             (u >> 16 & 0xffu32) as u8,
             (u >>  8 & 0xffu32) as u8,
             (u & 0xffu32) as u8)
    };
    let name_bytes = u32_to_vec(name);
    String::from_utf8_lossy(&name_bytes).into_owned()
}

use std::fmt;
impl fmt::Display for BoxHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "'{}' {} bytes", fourcc_to_string(self.name), self.size)
    }
}

impl fmt::Display for FileTypeBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        let brand = fourcc_to_string(self.major_brand);
        write!(f, "'{}' {} bytes '{}' v{}", name, self.size,
            brand, self.minor_version)
    }
}

impl fmt::Display for MovieHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        write!(f, "'{}' {} bytes duration {}s", name, self.size,
            (self.duration as f64)/(self.timescale as f64))
    }
}

use std::u16;
impl fmt::Display for TrackHeaderBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = fourcc_to_string(self.name);
        // Dimensions are 16.16 fixed-point.
        let base = u16::MAX as f64 + 1.0;
        let width = (self.width as f64) / base;
        let height = (self.height as f64) / base;
        write!(f, "'{}' {} bytes duration {} id {} {}x{}",
            name, self.size, self.duration, self.track_id,
            width, height)
    }
}

#[test]
fn test_read_box_header() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_header_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let header = read_box_header(&mut stream).unwrap();
    let parsed = read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    println!("box {}", parsed);
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library 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. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(missing_docs)]

//! glTF 2.0 loader
//!
//! This crate is intended to load [glTF 2.0], a file format designed for the
//! efficient runtime transmission of 3D scenes. The crate aims to provide
//! rustic utilities that make working with glTF simple and intuitive.
//!
//! [glTF 2.0]: https://www.khronos.org/gltf
//!
//! ## Installation
//!
//! Add `gltf` version 0.8 to your `Cargo.toml`.
//!
//! ```toml
//! [dependencies.gltf]
//! version = "0.8"
//! ```
//!
//! ## Examples
//!
//! ### Walking the node hierarchy
//!
//! Below demonstates visiting the root [`Node`]s of every [`Scene`], printing the
//! number of children each node has.
//!
//! [`Node`]: scene/struct.Node.html
//! [`Scene`]: scene/struct.Scene.html
//! ```
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! let file = std::fs::File::open("examples/Box.gltf")?;
//! let reader = std::io::BufReader::new(file);
//! let json = gltf::json::from_reader(reader)?;
//! let gltf = gltf::Gltf::from_json(json);
//! for scene in gltf.scenes() {
//!     for node in scene.nodes() {
//!         // Do something with this node.
//!         println!(
//!             "Node {} has {} children",
//!             node.index(),
//!             node.children().count(),
//!         );
//!     }
//! }
//! # Ok(())
//! # }
//! # fn main() {
//! #    let _ = run().expect("No runtime errors");
//! # }
//! ```
//!
//! ### Providing `Gltf` with external buffer data
//!
//! The [`Source`] trait provides `glTF` objects with their buffer data. This allows
//! the crate to provide more abstractions such as iterating over the positions of
//! a `Primitive`. See the documentation of [`Loaded`] for all the methods available
//! for loaded `glTF`.
//!
//! The `gltf-importer` crate contains the reference implementation of the
//! `Source` trait and may be used to read buffer data from the file system.
//!
//! [`Source`]: trait.Source.html
//! [`Loaded`]: struct.Loaded.html
//! ```
//! # use gltf::json;
//! # use gltf::Gltf;
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! # let path = "./glTF-Sample-Models/2.0/Box/glTF/Box.gltf";
//! # let file = std::fs::File::open(path)?;
//! # let reader = std::io::BufReader::new(file);
//! # let json = json::from_reader(reader)?;
//! # let gltf = Gltf::from_json(json);
//! #[derive(Debug)]
//! struct BoxExampleData(&'static [u8]);
//!
//! impl gltf::Source for BoxExampleData {
//!     fn source_buffer(&self, _: &gltf::Buffer) -> &[u8] {
//!         // In a real implementation, the `Source` must provide all the data
//!         // necessary to load the object, and must not fail.
//!         //
//!         // This example meets the above criteria, since it provides all the data
//!         // for the 'Box' sample model, which has exactly one external buffer.
//!         self.0
//!     }
//! }
//!
//! let data = BoxExampleData(include_bytes!("examples/Box0.bin"));
//! let loaded_gltf = gltf.loaded(&data);
//! for mesh in loaded_gltf.meshes() {
//!     for primitive in mesh.primitives() {
//!         if let Some(iter) = primitive.indices_u32() {
//!             // Do something with the primitive data.
//!             let indices: Vec<u32> = iter.collect();
//!             println!("{:?}", indices);
//!         }
//!     }
//! }
//! # Ok(())
//! # }
//! # fn main() {
//! #    let _ = run().expect("No runtime errors");
//! # }
//! ```

#[macro_use]
extern crate lazy_static;

/// Contains (de)serializable data structures that match the glTF JSON text.
pub extern crate gltf_json as json;

/// Contains `Accessor` and other related data structures.
pub mod accessor;

/// Contains `Animation` and other related data structures.
pub mod animation;

/// Contains `Buffer`, `View`, and other related data structures.
pub mod buffer;

/// Contains `Camera` and other related data structures.
pub mod camera;

/// Contains `Glb` and its parsing implementation.
pub mod glb;

/// Contains `Gltf`, and other related data structures.
pub mod gltf;

/// Contains `Image` and other related data structures.
pub mod image;

/// Contains `Material` and other related data structures.
pub mod material;

/// Contains `Mesh` and other related data structures.
pub mod mesh;

/// Contains `Root`.
pub mod root;

/// Contains `Scene`, `Node`, and other related data structures.
pub mod scene;

/// Contains `Skin` and other related data structures.
pub mod skin;

/// Contains `Texture`, `Sampler`, and other related data structures.
pub mod texture;

pub use self::animation::Animation;
pub use self::accessor::Accessor;
pub use self::buffer::Buffer;
pub use self::camera::Camera;
pub use self::glb::Glb;
pub use self::gltf::{Gltf, Unvalidated};
pub use self::image::Image;
pub use self::material::Material;
pub use self::mesh::{Attribute, Mesh, Primitive, Semantic};
pub use self::scene::{Node, Scene};
pub use self::skin::Skin;
pub use self::texture::Texture;

/// Returns `true` if the data begins with the `b"glTF"` magic string.
pub fn is_glb(slice: &[u8]) -> bool {
    slice.starts_with(b"glTF")
}

/// Represents a runtime error.
#[derive(Debug)]
pub enum Error {
    /// JSON deserialization error.
    Deserialize(json::Error),

    /// GLB parsing error.
    Glb(String),

    /// `glTF` validation error.
    Validation(Vec<(json::Path, json::validation::Error)>),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
         match *self {
            Error::Deserialize(_) => "deserialization error",
            Error::Glb(_) => "invalid .glb format",
            Error::Validation(_) => "invalid glTF JSON",
        }
    }
}

impl From<json::Error> for Error {
    fn from(err: json::Error) -> Self {
        Error::Deserialize(err)
    }
}

impl From<Vec<(json::Path, json::validation::Error)>> for Error {
    fn from(errs: Vec<(json::Path, json::validation::Error)>) -> Self {
        Error::Validation(errs)
    }
}
<commit_msg>Remove duplicated is_glb function<commit_after>
// Copyright 2017 The gltf Library 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. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(missing_docs)]

//! glTF 2.0 loader
//!
//! This crate is intended to load [glTF 2.0], a file format designed for the
//! efficient runtime transmission of 3D scenes. The crate aims to provide
//! rustic utilities that make working with glTF simple and intuitive.
//!
//! [glTF 2.0]: https://www.khronos.org/gltf
//!
//! ## Installation
//!
//! Add `gltf` version 0.8 to your `Cargo.toml`.
//!
//! ```toml
//! [dependencies.gltf]
//! version = "0.8"
//! ```
//!
//! ## Examples
//!
//! ### Walking the node hierarchy
//!
//! Below demonstates visiting the root [`Node`]s of every [`Scene`], printing the
//! number of children each node has.
//!
//! [`Node`]: scene/struct.Node.html
//! [`Scene`]: scene/struct.Scene.html
//! ```
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! let file = std::fs::File::open("examples/Box.gltf")?;
//! let reader = std::io::BufReader::new(file);
//! let json = gltf::json::from_reader(reader)?;
//! let gltf = gltf::Gltf::from_json(json);
//! for scene in gltf.scenes() {
//!     for node in scene.nodes() {
//!         // Do something with this node.
//!         println!(
//!             "Node {} has {} children",
//!             node.index(),
//!             node.children().count(),
//!         );
//!     }
//! }
//! # Ok(())
//! # }
//! # fn main() {
//! #    let _ = run().expect("No runtime errors");
//! # }
//! ```
//!
//! ### Providing `Gltf` with external buffer data
//!
//! The [`Source`] trait provides `glTF` objects with their buffer data. This allows
//! the crate to provide more abstractions such as iterating over the positions of
//! a `Primitive`. See the documentation of [`Loaded`] for all the methods available
//! for loaded `glTF`.
//!
//! The `gltf-importer` crate contains the reference implementation of the
//! `Source` trait and may be used to read buffer data from the file system.
//!
//! [`Source`]: trait.Source.html
//! [`Loaded`]: struct.Loaded.html
//! ```
//! # use gltf::json;
//! # use gltf::Gltf;
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! # let path = "./glTF-Sample-Models/2.0/Box/glTF/Box.gltf";
//! # let file = std::fs::File::open(path)?;
//! # let reader = std::io::BufReader::new(file);
//! # let json = json::from_reader(reader)?;
//! # let gltf = Gltf::from_json(json);
//! #[derive(Debug)]
//! struct BoxExampleData(&'static [u8]);
//!
//! impl gltf::Source for BoxExampleData {
//!     fn source_buffer(&self, _: &gltf::Buffer) -> &[u8] {
//!         // In a real implementation, the `Source` must provide all the data
//!         // necessary to load the object, and must not fail.
//!         //
//!         // This example meets the above criteria, since it provides all the data
//!         // for the 'Box' sample model, which has exactly one external buffer.
//!         self.0
//!     }
//! }
//!
//! let data = BoxExampleData(include_bytes!("examples/Box0.bin"));
//! let loaded_gltf = gltf.loaded(&data);
//! for mesh in loaded_gltf.meshes() {
//!     for primitive in mesh.primitives() {
//!         if let Some(iter) = primitive.indices_u32() {
//!             // Do something with the primitive data.
//!             let indices: Vec<u32> = iter.collect();
//!             println!("{:?}", indices);
//!         }
//!     }
//! }
//! # Ok(())
//! # }
//! # fn main() {
//! #    let _ = run().expect("No runtime errors");
//! # }
//! ```

#[macro_use]
extern crate lazy_static;

/// Contains (de)serializable data structures that match the glTF JSON text.
pub extern crate gltf_json as json;

/// Contains `Accessor` and other related data structures.
pub mod accessor;

/// Contains `Animation` and other related data structures.
pub mod animation;

/// Contains `Buffer`, `View`, and other related data structures.
pub mod buffer;

/// Contains `Camera` and other related data structures.
pub mod camera;

/// Contains `Glb` and its parsing implementation.
pub mod glb;

/// Contains `Gltf`, and other related data structures.
pub mod gltf;

/// Contains `Image` and other related data structures.
pub mod image;

/// Contains `Material` and other related data structures.
pub mod material;

/// Contains `Mesh` and other related data structures.
pub mod mesh;

/// Contains `Root`.
pub mod root;

/// Contains `Scene`, `Node`, and other related data structures.
pub mod scene;

/// Contains `Skin` and other related data structures.
pub mod skin;

/// Contains `Texture`, `Sampler`, and other related data structures.
pub mod texture;

pub use self::animation::Animation;
pub use self::accessor::Accessor;
pub use self::buffer::Buffer;
pub use self::camera::Camera;
pub use self::glb::Glb;
pub use self::gltf::{Gltf, Unvalidated};
pub use self::image::Image;
pub use self::material::Material;
pub use self::mesh::{Attribute, Mesh, Primitive, Semantic};
pub use self::scene::{Node, Scene};
pub use self::skin::Skin;
pub use self::texture::Texture;

/// Represents a runtime error.
#[derive(Debug)]
pub enum Error {
    /// JSON deserialization error.
    Deserialize(json::Error),

    /// GLB parsing error.
    Glb(String),

    /// `glTF` validation error.
    Validation(Vec<(json::Path, json::validation::Error)>),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use std::error::Error;
        write!(f, "{}", self.description())
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
         match *self {
            Error::Deserialize(_) => "deserialization error",
            Error::Glb(_) => "invalid .glb format",
            Error::Validation(_) => "invalid glTF JSON",
        }
    }
}

impl From<json::Error> for Error {
    fn from(err: json::Error) -> Self {
        Error::Deserialize(err)
    }
}

impl From<Vec<(json::Path, json::validation::Error)>> for Error {
    fn from(errs: Vec<(json::Path, json::validation::Error)>) -> Self {
        Error::Validation(errs)
    }
}
<|endoftext|>


<commit_before>//! Double is a fully-featured mocking library for mocking `trait`
//! implementations.
//!
//! The `Mock` struct tracks function call arguments and specifies return
//! values or function overrides.
//!
//! This library is based off iredelmeier's initial mocking implementation.
//! Massive thanks to her implementation for inpsiring me to work on this. Her
//! repo can be found here:
//!
//! https://github.com/iredelmeier/pseudo
//!
//! If you're interested in testing, check out her other repositories too!
//!
//! # Examples
//!
//! ```
//! #[macro_use]
//! extern crate double;
//!
//! // Code under test
//! trait BalanceSheet {
//!     fn profit(&self, revenue: u32, costs: u32) -> i32;
//! }
//!
//! fn double_profit(revenue: u32, costs: u32, balance_sheet: &BalanceSheet) -> i32 {
//!     balance_sheet.profit(revenue, costs) * 2
//! }
//!
//! // Test which uses a mock BalanceSheet
//! mock_trait!(
//!     MockBalanceSheet,
//!     profit(u32, u32) -> i32);
//! impl BalanceSheet for MockBalanceSheet {
//!     mock_method!(profit(&self, revenue: u32, costs: u32) -> i32);
//! }
//!
//! fn test_doubling_a_sheets_profit() {
//!     // GIVEN:
//!     let sheet = MockBalanceSheet::default();
//!     sheet.profit.return_value(250);
//!     // WHEN:
//!     let profit = double_profit(500, 250, &sheet);
//!     // THEN:
//!     // mock return 250, which was double
//!     assert_eq!(500, profit);
//!     // assert that the revenue and costs were correctly passed to the mock
//!     sheet.profit.has_calls_exactly_in_order(vec!((500, 250)));
//! }
//!
//! // Executing test
//! fn main() {
//!     test_doubling_a_sheets_profit();
//! }
//! ```

pub use mock::Mock;

mod macros;
mod mock;
<commit_msg>Remove extra details from README<commit_after>//! Double is a fully-featured mocking library for mocking `trait`
//! implementations.
//!
//! The `Mock` struct tracks function call arguments and specifies return
//! values or function overrides.
//!
//! # Examples
//!
//! ```
//! #[macro_use]
//! extern crate double;
//!
//! // Code under test
//! trait BalanceSheet {
//!     fn profit(&self, revenue: u32, costs: u32) -> i32;
//! }
//!
//! fn double_profit(revenue: u32, costs: u32, balance_sheet: &BalanceSheet) -> i32 {
//!     balance_sheet.profit(revenue, costs) * 2
//! }
//!
//! // Test which uses a mock BalanceSheet
//! mock_trait!(
//!     MockBalanceSheet,
//!     profit(u32, u32) -> i32);
//! impl BalanceSheet for MockBalanceSheet {
//!     mock_method!(profit(&self, revenue: u32, costs: u32) -> i32);
//! }
//!
//! fn test_doubling_a_sheets_profit() {
//!     // GIVEN:
//!     let sheet = MockBalanceSheet::default();
//!     sheet.profit.return_value(250);
//!     // WHEN:
//!     let profit = double_profit(500, 250, &sheet);
//!     // THEN:
//!     // mock return 250, which was double
//!     assert_eq!(500, profit);
//!     // assert that the revenue and costs were correctly passed to the mock
//!     sheet.profit.has_calls_exactly_in_order(vec!((500, 250)));
//! }
//!
//! // Executing test
//! fn main() {
//!     test_doubling_a_sheets_profit();
//! }
//! ```

pub use mock::Mock;

mod macros;
mod mock;
<|endoftext|>


<commit_before>//! [![github]](https://github.com/dtolnay/serde-yaml) [![crates-io]](https://crates.io/crates/serde-yaml) [![docs-rs]](https://docs.rs/serde-yaml)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//!

//!
//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.13")]
#![deny(missing_docs)]
#![deny(clippy::all, clippy::pedantic)]
// Suppressed clippy_pedantic lints
#![allow(
    // private Deserializer::next
    clippy::should_implement_trait,
    // things are often more readable this way
    clippy::cast_lossless,
    clippy::module_name_repetitions,
    clippy::single_match_else,
    clippy::use_self,
    // code is acceptable
    clippy::cast_possible_wrap,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss,
    // not practical
    clippy::indexing_slicing,
    clippy::missing_docs_in_private_items,
    // not stable
    clippy::checked_conversions,
    clippy::empty_enum,
    // meh, some things won't fail
    clippy::unwrap_used,
    // noisy
    clippy::missing_errors_doc,
    clippy::must_use_candidate,
)]

pub use crate::de::{from_reader, from_slice, from_str};
pub use crate::error::{Error, Location, Result};
pub use crate::ser::{to_string, to_vec, to_writer};
pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value};

#[doc(inline)]
pub use crate::mapping::Mapping;

/// Entry points for deserializing with pre-existing state.
///
/// These functions are only exposed this way because we don't yet expose a
/// Deserializer type. Data formats that have a public Deserializer should not
/// copy these signatures.
pub mod seed {
    pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed};
}

mod de;
mod error;
pub mod mapping;
mod number;
mod path;
mod ser;
mod value;
<commit_msg>Suppress match_like_matches_macro clippy lint<commit_after>//! [![github]](https://github.com/dtolnay/serde-yaml) [![crates-io]](https://crates.io/crates/serde-yaml) [![docs-rs]](https://docs.rs/serde-yaml)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//!

//!
//! This crate is a Rust library for using the [Serde] serialization framework
//! with data in [YAML] file format.
//!
//! This library does not reimplement a YAML parser; it uses [yaml-rust] which
//! is a pure Rust YAML 1.2 implementation.
//!
//! [Serde]: https://github.com/serde-rs/serde
//! [YAML]: http://yaml.org
//! [yaml-rust]: https://github.com/chyh1990/yaml-rust
//!
//! # Examples
//!
//! ```
//! use std::collections::BTreeMap;
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     // You have some type.
//!     let mut map = BTreeMap::new();
//!     map.insert("x".to_string(), 1.0);
//!     map.insert("y".to_string(), 2.0);
//!
//!     // Serialize it to a YAML string.
//!     let s = serde_yaml::to_string(&map)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     // Deserialize it back to a Rust type.
//!     let deserialized_map: BTreeMap<String, f64> = serde_yaml::from_str(&s)?;
//!     assert_eq!(map, deserialized_map);
//!     Ok(())
//! }
//! ```
//!
//! ## Using Serde derive
//!
//! It can also be used with Serde's serialization code generator `serde_derive` to
//! handle structs and enums defined in your own program.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Point {
//!     x: f64,
//!     y: f64,
//! }
//!
//! fn main() -> Result<(), serde_yaml::Error> {
//!     let point = Point { x: 1.0, y: 2.0 };
//!
//!     let s = serde_yaml::to_string(&point)?;
//!     assert_eq!(s, "---\nx: 1.0\ny: 2.0");
//!
//!     let deserialized_point: Point = serde_yaml::from_str(&s)?;
//!     assert_eq!(point, deserialized_point);
//!     Ok(())
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_yaml/0.8.13")]
#![deny(missing_docs)]
#![deny(clippy::all, clippy::pedantic)]
// Suppressed clippy_pedantic lints
#![allow(
    // private Deserializer::next
    clippy::should_implement_trait,
    // things are often more readable this way
    clippy::cast_lossless,
    clippy::module_name_repetitions,
    clippy::single_match_else,
    clippy::use_self,
    // code is acceptable
    clippy::cast_possible_wrap,
    clippy::cast_precision_loss,
    clippy::cast_sign_loss,
    // not practical
    clippy::indexing_slicing,
    clippy::missing_docs_in_private_items,
    // not stable
    clippy::checked_conversions,
    clippy::empty_enum,
    // meh, some things won't fail
    clippy::unwrap_used,
    // noisy
    clippy::missing_errors_doc,
    clippy::must_use_candidate,
    // we support older compilers
    clippy::match_like_matches_macro,
)]

pub use crate::de::{from_reader, from_slice, from_str};
pub use crate::error::{Error, Location, Result};
pub use crate::ser::{to_string, to_vec, to_writer};
pub use crate::value::{from_value, to_value, Index, Number, Sequence, Value};

#[doc(inline)]
pub use crate::mapping::Mapping;

/// Entry points for deserializing with pre-existing state.
///
/// These functions are only exposed this way because we don't yet expose a
/// Deserializer type. Data formats that have a public Deserializer should not
/// copy these signatures.
pub mod seed {
    pub use super::de::{from_reader_seed, from_slice_seed, from_str_seed};
}

mod de;
mod error;
pub mod mapping;
mod number;
mod path;
mod ser;
mod value;
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(io)]
#![feature(path)]
#![feature(test)]

//! # cargopants
//! Cargopants exposes an client interface for crates.io

extern crate core;
extern crate hyper;
extern crate mime;
extern crate "rustc-serialize" as rustc_serialize;
extern crate test;
extern crate url;

use core::ops::DerefMut;
use hyper::Url;
use hyper::client;
use hyper::header::{ Accept, Authorization, ContentType, UserAgent, qitem };
use hyper::method::Method;
use mime::{ Attr, Mime, Value };
use mime::TopLevel::Application;
use mime::SubLevel::Json;
use rustc_serialize::{ Decoder, Decodable, json };
use std::collections::HashMap;
use std::fs::{ self, File };
use std::io::prelude::*;
use std::io::{ Cursor, Error };
use std::path::Path;
use std::result;

pub type Result<T> = result::Result<T, Error>;

/// Entry point for accessing crates.io
pub struct Client {
  host: String,
  token: Option<String>
}

#[derive(RustcDecodable)]
struct Status {
  ok: bool
}

#[derive(RustcDecodable)]
struct Following {
  following: bool
}

/// Representation of a crates.io User
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct User {
  pub id: u32,
  pub login: String,
  pub avatar: String,
  pub email: Option<String>,
  pub name: Option<String>,
}

#[derive(RustcDecodable)]
struct Users {
  users: Vec<User>
}

/// Representation of a crates.io Crate
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct Crate {
  pub name: String,
  pub description: Option<String>,
  pub max_version: String
}

// RustcDecodable be derived because the key used in json is `crate`,
// a reserved word
struct CrateReq {
  krate: Crate
}

impl Decodable for CrateReq {
  fn decode<D: Decoder>(d: &mut D) -> result::Result<CrateReq, D::Error> {
    d.read_struct("CrateReq", 1usize, |_d| {
      Ok(CrateReq {
        krate: try!(_d.read_struct_field("crate", 0usize, |_d| Decodable::decode(_d)))
      })
    })
  }
}

/// Representation of the downloads of a version on a given date
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct Download {
  pub date: String,
  pub downloads: u32
}

#[derive(RustcDecodable)]
struct VersionDownloads {
  version_downloads: Vec<Download>
}

#[derive(RustcDecodable)]
struct ExtraDownloads {
  extra_downloads: Vec<Download>
}

#[derive(RustcDecodable)]
struct MetaDownloads {
  meta: ExtraDownloads
}

/// Representation of a crate dependency
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct Dependency {
  pub crate_id: String,
  pub default_features: bool,
  pub features: String,
  pub kind: String,
  pub optional: bool,
  pub req: String
}

#[derive(RustcDecodable)]
struct Dependencies {
  dependencies: Vec<Dependency>
}

/// Representation of a crate version
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct Version {
  // crate: String,
  pub created_at: String,
  pub dl_path: String,
  pub downloads: u32,
  pub num: String,
  pub updated_at: String,
  pub yanked: bool
}

#[derive(RustcDecodable)]
struct VersionReq {
  version: Version
}

#[derive(RustcDecodable)]
struct Versions {
  versions: Vec<Version>
}

#[derive(RustcDecodable)]
struct Meta {
  names: Vec<String>
}

#[derive(RustcDecodable)]
struct Authors {
  meta: Meta
}

/// Interface for creating a new crate
#[derive(RustcEncodable)]
pub struct NewCrate {
  pub name: String,
  pub vers: String,
  pub deps: Vec<NewCrateDependency>,
  pub features: HashMap<String, Vec<String>>,
  pub authors: Vec<String>,
  pub description: Option<String>,
  pub documentation: Option<String>,
  pub homepage: Option<String>,
  pub readme: Option<String>,
  pub keywords: Vec<String>,
  pub license: Option<String>,
  pub license_file: Option<String>,
  pub repository: Option<String>,
}

/// Representation of a new crate dependency
#[derive(RustcEncodable)]
pub struct NewCrateDependency {
  pub optional: bool,
  pub default_features: bool,
  pub name: String,
  pub features: Vec<String>,
  pub version_req: String,
  pub target: Option<String>,
  pub kind: String,
}

#[derive(RustcEncodable)]
struct OwnersReq<'a> {
  users: &'a [&'a str]
}

#[derive(RustcDecodable)]
struct Crates {
  crates: Vec<Crate>
}

struct Body<'a> {
 read: &'a mut Box<&'a mut Read>,
 size: u64
}

impl<'a> Body<'a> {
  pub fn new(read: &'a mut Box<&'a mut Read>, size: u64) -> Body<'a> {
    Body { read: read, size: size }
  }
}

/// Client interface for a given crate version
pub struct KrateVersion<'a, 'b, 'c> {
  client: &'a mut Client,
  name: &'b str,
  version: &'c str
}

impl<'a, 'b, 'c> KrateVersion<'a, 'b, 'c> {
  pub fn new(client:&'a mut Client, name: &'b str, version: &'c str) -> KrateVersion<'a, 'b, 'c> {
    KrateVersion { client: client, name: name, version: version }
  }

  pub fn get(self) -> Result<Version> {
    let body = try!(self.client.get(format!("/crates/{}/{}", self.name, self.version)));
    Ok(json::decode::<VersionReq>(&body).unwrap().version)
  }

  pub fn dependencies(self) -> Result<Vec<Dependency>> {
    let body = try!(self.client.get(format!("/crates/{}/{}/dependencies", self.name, self.version)));
    Ok(json::decode::<Dependencies>(&body).unwrap().dependencies)
  }

  pub fn downloads(self) -> Result<Vec<Download>> {
    let body = try!(self.client.get(format!("/crates/{}/{}/downloads", self.name, self.version)));
    Ok(json::decode::<VersionDownloads>(&body).unwrap().version_downloads)
  }

  pub fn authors(self) -> Result<Vec<String>> {
    let body = try!(self.client.get(format!("/crates/{}/{}/authors", self.name, self.version)));
    Ok(json::decode::<Authors>(&body).unwrap().meta.names)
  }

  pub fn yank(self) -> Result<()> {
    let body = try!(self.client.delete(format!("/crates/{}/{}/yank", self.name, self.version), None));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn unyank(self) -> Result<()> {
    let body = try!(self.client.put(format!("/crates/{}/{}/unyank", self.name, self.version), None));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }
}

/// Client interface for a given crate
pub struct Krate<'a, 'b> {
  client: &'a mut Client,
  name: &'b str
}

impl<'a, 'b> Krate<'a, 'b> {
  pub fn new(client:&'a mut Client, name: &'b str) -> Krate<'a,'b> {
    Krate { client: client, name: name }
  }

  pub fn downloads(self) -> Result<Vec<Download>> {
    let body = try!(self.client.get(format!("/crates/{}/downloads", self.name)));
    Ok(json::decode::<MetaDownloads>(&body).unwrap().meta.extra_downloads)
  }

  pub fn follow(self) -> Result<()> {
    let body = try!(self.client.put(format!("/crates/{}/follow", self.name), None));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn unfollow(self) -> Result<()> {
    let body = try!(self.client.delete(format!("/crates/{}/follow", self.name), None));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn following(self) -> Result<bool> {
    let body = try!(self.client.get(format!("/crates/{}/following", self.name)));
    Ok(json::decode::<Following>(&body).unwrap().following)
  }

  pub fn get(self) -> Result<Crate> {
    let body = try!(self.client.get(format!("/crates/{}", self.name)));
    Ok(json::decode::<CrateReq>(&body).unwrap().krate)
  }

  pub fn owners(self) -> Result<Vec<User>> {
    let body = try!(self.client.get(format!("/crates/{}/owners", self.name)));
    Ok(json::decode::<Users>(&body).unwrap().users)
  }

  pub fn add_owners(self, owners: &[&str]) -> Result<()> {
    let data = json::encode(&OwnersReq { users: owners }).unwrap();
    let mut bytes = data.as_bytes();
    let body = try!(self.client.put(format!("/crates/{}/owners", self.name),
                             Some(Body::new(&mut Box::new(&mut bytes), bytes.len() as u64))));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn remove_owners(self, owners: &[&str]) -> Result<()> {
    let data = json::encode(&OwnersReq { users: owners }).unwrap();
    let mut bytes = data.as_bytes();
    let body = try!(self.client.delete(format!("/crates/{}/owners", self.name),
                                Some(Body::new(&mut Box::new(&mut bytes), bytes.len() as u64))));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn reverse_dependencies(&mut self) -> Result<Vec<Dependency>> {
    let body = try!(self.client.get(format!("/crates/{}/reverse_dependencies", self.name)));
    Ok(json::decode::<Dependencies>(&body).unwrap().dependencies)
  }

  pub fn version<'c>(&'c mut self, version: &'c str) -> KrateVersion {
    KrateVersion::new(self.client, self.name, version)
  }

  pub fn versions(self) -> Result<Vec<Version>> {
    let body = try!(self.client.get(format!("/crates/{}/versions", self.name)));
    let versions: Vec<Version> = json::decode::<Versions>(&body).unwrap().versions;
    Ok(versions)
  }
}

impl Client {
  pub fn new() -> Client {
    Client::host("https://crates.io")
  }

  pub fn host(addr: &str) -> Client {
    Client {
      host: addr.to_string(),
      token: None
    }
  }

  pub fn token(self, auth: &str) -> Client {
    Client {
      host: self.host,
      token: Some(auth.to_string())
    }
  }

  pub fn krate<'a>(&'a mut self, name: &'a str) -> Krate {
    Krate::new(self, name)
  }

  // todo: sort (downloads|name), by letter/keyword/user_id/following
  pub fn find(&mut self, query: &str) -> Result<Vec<Crate>> {
    let body = try!(self.get(format!("/crates?q={}&sort={}", query, "name")));
    Ok(json::decode::<Crates>(&body).unwrap().crates)
  }

  // todo: publish -- https://github.com/rust-lang/crates.io/blob/dabd8778c1a515ea7572c59096da76e562afe2e2/src/lib.rs#L76
  pub fn publish(&mut self, krate: &NewCrate, tarball: &Path) -> Result<()> {
    let json = json::encode(krate).unwrap();
    let stat = try!(fs::metadata(tarball));
    let header = {
      let mut w = Vec::new();
      w.extend([
        (json.len() >>  0) as u8,
        (json.len() >>  8) as u8,
        (json.len() >> 16) as u8,
        (json.len() >> 24) as u8,
      ].iter().cloned());
      w.extend(json.as_bytes().iter().cloned());
      w.extend([
        (stat.len() >>  0) as u8,
        (stat.len() >>  8) as u8,
        (stat.len() >> 16) as u8,
        (stat.len() >> 24) as u8,
      ].iter().cloned());
      w
    };
    let size = stat.len() as usize + header.len();
    let tarball = try!(File::open(tarball));
    let mut body = Cursor::new(header).chain(tarball);
    let _ = try!(self.put("/crates/new".to_string(), Some(Body::new(&mut Box::new(&mut body), size as u64))));
    Ok(())
  }

  // todo: version download -- https://github.com/rust-lang/crates.io/blob/dabd8778c1a515ea7572c59096da76e562afe2e2/src/lib.rs#L78

  fn get(&mut self, path: String) -> Result<String> {
    self.req(Method::Get, path, None)
  }

  fn delete(&mut self, path: String, body: Option<Body>) -> Result<String> {
    self.req(Method::Delete, path, body)
  }

  fn put(&mut self, path: String, body: Option<Body>) -> Result<String> {
    self.req(Method::Put, path, body)
  }

  fn req(&mut self, method: Method, path: String, body: Option<Body>) -> Result<String> {
    let uri = Url::parse(&format!("{}/api/v1{}", self.host, path)).ok().expect("invalid url");
    let mut client = hyper::Client::new();
    let content_type: Mime = Mime(Application, Json, vec![(Attr::Charset, Value::Utf8)]);
    let bound = client.request(method, uri)
      .header(UserAgent("cargopants/0.1.0".to_string()))
      .header(Accept(vec![qitem(content_type.clone())]))
      .header(ContentType(content_type));
    let authenticated = match self.token.clone() {
      Some(auth) => bound.header(Authorization(auth)),
               _ => bound
    };
    let embodied = match body {
      Some(Body { read: r, size: l }) => {
        let reader: &mut Read  = *r.deref_mut();
        authenticated.body(client::Body::SizedBody(reader, l))
      },
      _  => authenticated
    };
    let mut res = match embodied.send() {
      Ok(r)    => r,
      Err(err) => panic!("failed request: {:?}", err)
    };
    let mut body = String::new();
    res.read_to_string(&mut body).map(|_| body)
  }
}

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

  #[test]
  fn it_parses_crate_req() {

  }

  #[bench]
  fn it_benches(b: &mut Bencher) {

  }
}
<commit_msg>update features<commit_after>#![feature(core, test)]

//! # cargopants
//! Cargopants exposes an client interface for crates.io

extern crate core;
extern crate hyper;
extern crate mime;
extern crate "rustc-serialize" as rustc_serialize;
extern crate test;
extern crate url;

use core::ops::DerefMut;
use hyper::Url;
use hyper::client;
use hyper::header::{ Accept, Authorization, ContentType, UserAgent, qitem };
use hyper::method::Method;
use mime::{ Attr, Mime, Value };
use mime::TopLevel::Application;
use mime::SubLevel::Json;
use rustc_serialize::{ Decoder, Decodable, json };
use std::collections::HashMap;
use std::fs::{ self, File };
use std::io::prelude::*;
use std::io::{ Cursor, Error };
use std::path::Path;
use std::result;

pub type Result<T> = result::Result<T, Error>;

/// Entry point for accessing crates.io
pub struct Client {
  host: String,
  token: Option<String>
}

#[derive(RustcDecodable)]
struct Status {
  ok: bool
}

#[derive(RustcDecodable)]
struct Following {
  following: bool
}

/// Representation of a crates.io User
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct User {
  pub id: u32,
  pub login: String,
  pub avatar: String,
  pub email: Option<String>,
  pub name: Option<String>,
}

#[derive(RustcDecodable)]
struct Users {
  users: Vec<User>
}

/// Representation of a crates.io Crate
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct Crate {
  pub name: String,
  pub description: Option<String>,
  pub max_version: String
}

// RustcDecodable be derived because the key used in json is `crate`,
// a reserved word
struct CrateReq {
  krate: Crate
}

impl Decodable for CrateReq {
  fn decode<D: Decoder>(d: &mut D) -> result::Result<CrateReq, D::Error> {
    d.read_struct("CrateReq", 1usize, |_d| {
      Ok(CrateReq {
        krate: try!(_d.read_struct_field("crate", 0usize, |_d| Decodable::decode(_d)))
      })
    })
  }
}

/// Representation of the downloads of a version on a given date
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct Download {
  pub date: String,
  pub downloads: u32
}

#[derive(RustcDecodable)]
struct VersionDownloads {
  version_downloads: Vec<Download>
}

#[derive(RustcDecodable)]
struct ExtraDownloads {
  extra_downloads: Vec<Download>
}

#[derive(RustcDecodable)]
struct MetaDownloads {
  meta: ExtraDownloads
}

/// Representation of a crate dependency
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct Dependency {
  pub crate_id: String,
  pub default_features: bool,
  pub features: String,
  pub kind: String,
  pub optional: bool,
  pub req: String
}

#[derive(RustcDecodable)]
struct Dependencies {
  dependencies: Vec<Dependency>
}

/// Representation of a crate version
#[derive(RustcDecodable)]
#[derive(Debug)]
pub struct Version {
  // crate: String,
  pub created_at: String,
  pub dl_path: String,
  pub downloads: u32,
  pub num: String,
  pub updated_at: String,
  pub yanked: bool
}

#[derive(RustcDecodable)]
struct VersionReq {
  version: Version
}

#[derive(RustcDecodable)]
struct Versions {
  versions: Vec<Version>
}

#[derive(RustcDecodable)]
struct Meta {
  names: Vec<String>
}

#[derive(RustcDecodable)]
struct Authors {
  meta: Meta
}

/// Interface for creating a new crate
#[derive(RustcEncodable)]
pub struct NewCrate {
  pub name: String,
  pub vers: String,
  pub deps: Vec<NewCrateDependency>,
  pub features: HashMap<String, Vec<String>>,
  pub authors: Vec<String>,
  pub description: Option<String>,
  pub documentation: Option<String>,
  pub homepage: Option<String>,
  pub readme: Option<String>,
  pub keywords: Vec<String>,
  pub license: Option<String>,
  pub license_file: Option<String>,
  pub repository: Option<String>,
}

/// Representation of a new crate dependency
#[derive(RustcEncodable)]
pub struct NewCrateDependency {
  pub optional: bool,
  pub default_features: bool,
  pub name: String,
  pub features: Vec<String>,
  pub version_req: String,
  pub target: Option<String>,
  pub kind: String,
}

#[derive(RustcEncodable)]
struct OwnersReq<'a> {
  users: &'a [&'a str]
}

#[derive(RustcDecodable)]
struct Crates {
  crates: Vec<Crate>
}

struct Body<'a> {
 read: &'a mut Box<&'a mut Read>,
 size: u64
}

impl<'a> Body<'a> {
  pub fn new(read: &'a mut Box<&'a mut Read>, size: u64) -> Body<'a> {
    Body { read: read, size: size }
  }
}

/// Client interface for a given crate version
pub struct KrateVersion<'a, 'b, 'c> {
  client: &'a mut Client,
  name: &'b str,
  version: &'c str
}

impl<'a, 'b, 'c> KrateVersion<'a, 'b, 'c> {
  pub fn new(client:&'a mut Client, name: &'b str, version: &'c str) -> KrateVersion<'a, 'b, 'c> {
    KrateVersion { client: client, name: name, version: version }
  }

  pub fn get(self) -> Result<Version> {
    let body = try!(self.client.get(format!("/crates/{}/{}", self.name, self.version)));
    Ok(json::decode::<VersionReq>(&body).unwrap().version)
  }

  pub fn dependencies(self) -> Result<Vec<Dependency>> {
    let body = try!(self.client.get(format!("/crates/{}/{}/dependencies", self.name, self.version)));
    Ok(json::decode::<Dependencies>(&body).unwrap().dependencies)
  }

  pub fn downloads(self) -> Result<Vec<Download>> {
    let body = try!(self.client.get(format!("/crates/{}/{}/downloads", self.name, self.version)));
    Ok(json::decode::<VersionDownloads>(&body).unwrap().version_downloads)
  }

  pub fn authors(self) -> Result<Vec<String>> {
    let body = try!(self.client.get(format!("/crates/{}/{}/authors", self.name, self.version)));
    Ok(json::decode::<Authors>(&body).unwrap().meta.names)
  }

  pub fn yank(self) -> Result<()> {
    let body = try!(self.client.delete(format!("/crates/{}/{}/yank", self.name, self.version), None));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn unyank(self) -> Result<()> {
    let body = try!(self.client.put(format!("/crates/{}/{}/unyank", self.name, self.version), None));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }
}

/// Client interface for a given crate
pub struct Krate<'a, 'b> {
  client: &'a mut Client,
  name: &'b str
}

impl<'a, 'b> Krate<'a, 'b> {
  pub fn new(client:&'a mut Client, name: &'b str) -> Krate<'a,'b> {
    Krate { client: client, name: name }
  }

  pub fn downloads(self) -> Result<Vec<Download>> {
    let body = try!(self.client.get(format!("/crates/{}/downloads", self.name)));
    Ok(json::decode::<MetaDownloads>(&body).unwrap().meta.extra_downloads)
  }

  pub fn follow(self) -> Result<()> {
    let body = try!(self.client.put(format!("/crates/{}/follow", self.name), None));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn unfollow(self) -> Result<()> {
    let body = try!(self.client.delete(format!("/crates/{}/follow", self.name), None));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn following(self) -> Result<bool> {
    let body = try!(self.client.get(format!("/crates/{}/following", self.name)));
    Ok(json::decode::<Following>(&body).unwrap().following)
  }

  pub fn get(self) -> Result<Crate> {
    let body = try!(self.client.get(format!("/crates/{}", self.name)));
    Ok(json::decode::<CrateReq>(&body).unwrap().krate)
  }

  pub fn owners(self) -> Result<Vec<User>> {
    let body = try!(self.client.get(format!("/crates/{}/owners", self.name)));
    Ok(json::decode::<Users>(&body).unwrap().users)
  }

  pub fn add_owners(self, owners: &[&str]) -> Result<()> {
    let data = json::encode(&OwnersReq { users: owners }).unwrap();
    let mut bytes = data.as_bytes();
    let body = try!(self.client.put(format!("/crates/{}/owners", self.name),
                             Some(Body::new(&mut Box::new(&mut bytes), bytes.len() as u64))));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn remove_owners(self, owners: &[&str]) -> Result<()> {
    let data = json::encode(&OwnersReq { users: owners }).unwrap();
    let mut bytes = data.as_bytes();
    let body = try!(self.client.delete(format!("/crates/{}/owners", self.name),
                                Some(Body::new(&mut Box::new(&mut bytes), bytes.len() as u64))));
    assert!(json::decode::<Status>(&body).unwrap().ok);
    Ok(())
  }

  pub fn reverse_dependencies(&mut self) -> Result<Vec<Dependency>> {
    let body = try!(self.client.get(format!("/crates/{}/reverse_dependencies", self.name)));
    Ok(json::decode::<Dependencies>(&body).unwrap().dependencies)
  }

  pub fn version<'c>(&'c mut self, version: &'c str) -> KrateVersion {
    KrateVersion::new(self.client, self.name, version)
  }

  pub fn versions(self) -> Result<Vec<Version>> {
    let body = try!(self.client.get(format!("/crates/{}/versions", self.name)));
    let versions: Vec<Version> = json::decode::<Versions>(&body).unwrap().versions;
    Ok(versions)
  }
}

impl Client {
  pub fn new() -> Client {
    Client::host("https://crates.io")
  }

  pub fn host(addr: &str) -> Client {
    Client {
      host: addr.to_string(),
      token: None
    }
  }

  pub fn token(self, auth: &str) -> Client {
    Client {
      host: self.host,
      token: Some(auth.to_string())
    }
  }

  pub fn krate<'a>(&'a mut self, name: &'a str) -> Krate {
    Krate::new(self, name)
  }

  // todo: sort (downloads|name), by letter/keyword/user_id/following
  pub fn find(&mut self, query: &str) -> Result<Vec<Crate>> {
    let body = try!(self.get(format!("/crates?q={}&sort={}", query, "name")));
    Ok(json::decode::<Crates>(&body).unwrap().crates)
  }

  // todo: publish -- https://github.com/rust-lang/crates.io/blob/dabd8778c1a515ea7572c59096da76e562afe2e2/src/lib.rs#L76
  pub fn publish(&mut self, krate: &NewCrate, tarball: &Path) -> Result<()> {
    let json = json::encode(krate).unwrap();
    let stat = try!(fs::metadata(tarball));
    let header = {
      let mut w = Vec::new();
      w.extend([
        (json.len() >>  0) as u8,
        (json.len() >>  8) as u8,
        (json.len() >> 16) as u8,
        (json.len() >> 24) as u8,
      ].iter().cloned());
      w.extend(json.as_bytes().iter().cloned());
      w.extend([
        (stat.len() >>  0) as u8,
        (stat.len() >>  8) as u8,
        (stat.len() >> 16) as u8,
        (stat.len() >> 24) as u8,
      ].iter().cloned());
      w
    };
    let size = stat.len() as usize + header.len();
    let tarball = try!(File::open(tarball));
    let mut body = Cursor::new(header).chain(tarball);
    let _ = try!(self.put("/crates/new".to_string(), Some(Body::new(&mut Box::new(&mut body), size as u64))));
    Ok(())
  }

  // todo: version download -- https://github.com/rust-lang/crates.io/blob/dabd8778c1a515ea7572c59096da76e562afe2e2/src/lib.rs#L78

  fn get(&mut self, path: String) -> Result<String> {
    self.req(Method::Get, path, None)
  }

  fn delete(&mut self, path: String, body: Option<Body>) -> Result<String> {
    self.req(Method::Delete, path, body)
  }

  fn put(&mut self, path: String, body: Option<Body>) -> Result<String> {
    self.req(Method::Put, path, body)
  }

  fn req(&mut self, method: Method, path: String, body: Option<Body>) -> Result<String> {
    let uri = Url::parse(&format!("{}/api/v1{}", self.host, path)).ok().expect("invalid url");
    let mut client = hyper::Client::new();
    let content_type: Mime = Mime(Application, Json, vec![(Attr::Charset, Value::Utf8)]);
    let bound = client.request(method, uri)
      .header(UserAgent("cargopants/0.1.0".to_string()))
      .header(Accept(vec![qitem(content_type.clone())]))
      .header(ContentType(content_type));
    let authenticated = match self.token.clone() {
      Some(auth) => bound.header(Authorization(auth)),
               _ => bound
    };
    let embodied = match body {
      Some(Body { read: r, size: l }) => {
        let reader: &mut Read  = *r.deref_mut();
        authenticated.body(client::Body::SizedBody(reader, l))
      },
      _  => authenticated
    };
    let mut res = match embodied.send() {
      Ok(r)    => r,
      Err(err) => panic!("failed request: {:?}", err)
    };
    let mut body = String::new();
    res.read_to_string(&mut body).map(|_| body)
  }
}

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

  #[test]
  fn it_parses_crate_req() {

  }

  #[bench]
  fn it_benches(b: &mut Bencher) {

  }
}
<|endoftext|>