<commit_before>#![ feature(libc, collections) ]
#![ allow(non_snake_case) ]

extern crate libc;

use libusb::*;
use libc::c_int;
use std::mem;
use std::slice;
use std::iter::repeat;
use std::result::Result;
use std::mem::transmute;
use std::mem::size_of;
use std::vec::Vec;
use std::cell::UnsafeCell;

pub mod libusb;

pub struct Context(*mut libusb_context);
unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = mem::uninitialized();
			let r = libusb_init(&mut ctx);
			assert!(r == 0);
			Context(ctx)
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		self.0
	}

	pub fn set_debug(&self, level: u32) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn list_devices(&self) -> Vec<Device> {
		unsafe{
			let mut list: *mut *mut libusb_device = mem::uninitialized();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let l = slice::from_raw_parts_mut(list, num_devices as usize);
			let devices = l.iter().map(|i| Device { dev: *i, ctx: self }).collect();
			libusb_free_device_list(list, 0);
			devices
		}
	}

	pub fn find_by_vid_pid(&self, vid: u16, pid: u16) -> Option<Device> {
		self.list_devices().into_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor == vid && desc.idProduct == pid
		})
	}
}

impl Drop for Context {
	fn drop(&mut self) {
		unsafe { libusb_exit(self.0); }
	}
}

pub struct Device<'c> {
	dev: *mut libusb_device,
	ctx: &'c Context,
}

impl<'c> Device<'c> {
	pub fn descriptor(&self) -> libusb_device_descriptor {
		unsafe{
			let mut d: libusb_device_descriptor = mem::uninitialized();
			libusb_get_device_descriptor(self.dev, &mut d as *mut libusb_device_descriptor);
			d
		}
	}

	pub fn bus(&self) -> u8 {
		unsafe {
			libusb_get_bus_number(self.dev)
		}
	}

	pub fn address(&self) -> u8 {
		unsafe {
			libusb_get_device_address(self.dev)
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, c_int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = mem::uninitialized();
			let r = libusb_open(self.dev, &mut handle);
			if r == 0 {
				Ok(DeviceHandle {
					dev: handle,
					ctx: self.ctx
				})
			}else{
				Err(r)
			}
		}
	}
}

impl<'c> Drop for Device<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl<'c> Clone for Device<'c> {
	fn clone(&self) -> Device<'c> {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{ dev: self.dev, ctx: self.ctx }
	}
}

pub struct DeviceHandle<'c> {
	dev: *mut libusb_device_handle,
	ctx: &'c Context
}
unsafe impl<'c> Sync for DeviceHandle<'c> {}

impl<'c> DeviceHandle<'c> {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		self.dev
	}

	pub fn claim_interface(&self, iface_num: u16) {
		unsafe {
			libusb_claim_interface(self.ptr(), iface_num as c_int);
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: usize,
		buffer: *mut u8,
		timeout: u32) -> (libusb_transfer_status, usize) {

		let completed: UnsafeCell<c_int> = UnsafeCell::new(0);

		extern fn callback(transfer: *mut libusb_transfer) {
			unsafe {
				let completed: &UnsafeCell<c_int> = transmute((*transfer).user_data);
				*completed.get() = 1;
			}
		}

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = timeout;
		(*t).length = length as c_int;
		(*t).callback = callback;
		(*t).user_data = transmute(&completed);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);

		while *completed.get() == 0{
			libusb_handle_events_completed(self.ctx.ptr(), completed.get());
		}

		let r = ((*t).get_status(), (*t).actual_length as usize);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: usize,
			timeout: u32
			) -> Result<Vec<u8>, libusb_transfer_status> {
		let mut buf: Vec<u8> = repeat(0u8).take(size).collect();
		unsafe {
			let ptr = buf.as_mut_ptr();
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			buf: &[u8],
			timeout: u32
			) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = buf.as_ptr() as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: usize, timeout: u32) -> Result<Vec<u8>, libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length;
		let mut buf: Vec<u8> = repeat(0u8).take(total_length).collect();
		let ptr = fill_setup_buf(&mut buf, bmRequestType, bRequest, wValue, wIndex, length);

		unsafe{
			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf[setup_length..setup_length+actual_length].to_vec())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8], timeout: u32) -> Result<(), libusb_transfer_status> {
		let mut setup_buf: Vec<_> = repeat(0u8).take(size_of::<libusb_control_setup>()).collect();
		fill_setup_buf(&mut setup_buf, bmRequestType, bRequest, wValue, wIndex, buf.len());
		setup_buf.push_all(buf);
		self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, &setup_buf, timeout)
	}
}

impl<'c> Drop for DeviceHandle<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_close(self.dev);
		}
	}
}

fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: usize) -> *mut u8 {
	let ptr = buf.as_mut_ptr();
	let setup = ptr as *mut libusb_control_setup;

	assert!(buf.len() >= 8);
	assert!(length <= (std::u16::MAX as usize));

	unsafe {
		(*setup).bmRequestType = bmRequestType;
		(*setup).bRequest = bRequest;
		(*setup).wValue = wValue.to_le();
		(*setup).wIndex = wIndex.to_le();
		(*setup).wLength = (length as u16).to_le();
	}

	return ptr;
}
<commit_msg>rust: push_all -> extend<commit_after>#![ feature(libc) ]
#![ allow(non_snake_case) ]

extern crate libc;

use libusb::*;
use libc::c_int;
use std::mem;
use std::slice;
use std::iter::repeat;
use std::result::Result;
use std::mem::transmute;
use std::mem::size_of;
use std::vec::Vec;
use std::cell::UnsafeCell;

pub mod libusb;

pub struct Context(*mut libusb_context);
unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = mem::uninitialized();
			let r = libusb_init(&mut ctx);
			assert!(r == 0);
			Context(ctx)
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		self.0
	}

	pub fn set_debug(&self, level: u32) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn list_devices(&self) -> Vec<Device> {
		unsafe{
			let mut list: *mut *mut libusb_device = mem::uninitialized();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let l = slice::from_raw_parts_mut(list, num_devices as usize);
			let devices = l.iter().map(|i| Device { dev: *i, ctx: self }).collect();
			libusb_free_device_list(list, 0);
			devices
		}
	}

	pub fn find_by_vid_pid(&self, vid: u16, pid: u16) -> Option<Device> {
		self.list_devices().into_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor == vid && desc.idProduct == pid
		})
	}
}

impl Drop for Context {
	fn drop(&mut self) {
		unsafe { libusb_exit(self.0); }
	}
}

pub struct Device<'c> {
	dev: *mut libusb_device,
	ctx: &'c Context,
}

impl<'c> Device<'c> {
	pub fn descriptor(&self) -> libusb_device_descriptor {
		unsafe{
			let mut d: libusb_device_descriptor = mem::uninitialized();
			libusb_get_device_descriptor(self.dev, &mut d as *mut libusb_device_descriptor);
			d
		}
	}

	pub fn bus(&self) -> u8 {
		unsafe {
			libusb_get_bus_number(self.dev)
		}
	}

	pub fn address(&self) -> u8 {
		unsafe {
			libusb_get_device_address(self.dev)
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, c_int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = mem::uninitialized();
			let r = libusb_open(self.dev, &mut handle);
			if r == 0 {
				Ok(DeviceHandle {
					dev: handle,
					ctx: self.ctx
				})
			}else{
				Err(r)
			}
		}
	}
}

impl<'c> Drop for Device<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl<'c> Clone for Device<'c> {
	fn clone(&self) -> Device<'c> {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{ dev: self.dev, ctx: self.ctx }
	}
}

pub struct DeviceHandle<'c> {
	dev: *mut libusb_device_handle,
	ctx: &'c Context
}
unsafe impl<'c> Sync for DeviceHandle<'c> {}

impl<'c> DeviceHandle<'c> {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		self.dev
	}

	pub fn claim_interface(&self, iface_num: u16) {
		unsafe {
			libusb_claim_interface(self.ptr(), iface_num as c_int);
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: usize,
		buffer: *mut u8,
		timeout: u32) -> (libusb_transfer_status, usize) {

		let completed: UnsafeCell<c_int> = UnsafeCell::new(0);

		extern fn callback(transfer: *mut libusb_transfer) {
			unsafe {
				let completed: &UnsafeCell<c_int> = transmute((*transfer).user_data);
				*completed.get() = 1;
			}
		}

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = timeout;
		(*t).length = length as c_int;
		(*t).callback = callback;
		(*t).user_data = transmute(&completed);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);

		while *completed.get() == 0{
			libusb_handle_events_completed(self.ctx.ptr(), completed.get());
		}

		let r = ((*t).get_status(), (*t).actual_length as usize);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: usize,
			timeout: u32
			) -> Result<Vec<u8>, libusb_transfer_status> {
		let mut buf: Vec<u8> = repeat(0u8).take(size).collect();
		unsafe {
			let ptr = buf.as_mut_ptr();
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			buf: &[u8],
			timeout: u32
			) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = buf.as_ptr() as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: usize, timeout: u32) -> Result<Vec<u8>, libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length;
		let mut buf: Vec<u8> = repeat(0u8).take(total_length).collect();
		let ptr = fill_setup_buf(&mut buf, bmRequestType, bRequest, wValue, wIndex, length);

		unsafe{
			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf[setup_length..setup_length+actual_length].to_vec())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8], timeout: u32) -> Result<(), libusb_transfer_status> {
		let mut setup_buf: Vec<_> = repeat(0u8).take(size_of::<libusb_control_setup>()).collect();
		fill_setup_buf(&mut setup_buf, bmRequestType, bRequest, wValue, wIndex, buf.len());
		setup_buf.extend(buf.iter().cloned());
		self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, &setup_buf, timeout)
	}
}

impl<'c> Drop for DeviceHandle<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_close(self.dev);
		}
	}
}

fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: usize) -> *mut u8 {
	let ptr = buf.as_mut_ptr();
	let setup = ptr as *mut libusb_control_setup;

	assert!(buf.len() >= 8);
	assert!(length <= (std::u16::MAX as usize));

	unsafe {
		(*setup).bmRequestType = bmRequestType;
		(*setup).bRequest = bRequest;
		(*setup).wValue = wValue.to_le();
		(*setup).wIndex = wIndex.to_le();
		(*setup).wLength = (length as u16).to_le();
	}

	return ptr;
}
<|endoftext|>


<commit_before>use std::cmp;
use self::EitherOrBoth::{Right, Left, Both};

// ZipLongest originally written by SimonSapin,
// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283

/// An iterator which iterates two other iterators simultaneously
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct ZipLongest<T, U> {
    a: T,
    b: U
}

impl<T, U> ZipLongest<T, U>
{
    /// Create a new ZipLongest iterator.
    pub fn new(a: T, b: U) -> ZipLongest<T, U>
    {
        ZipLongest{a: a, b: b}
    }
}

impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<EitherOrBoth<A, B>> for ZipLongest<T, U> {
    #[inline]
    fn next(&mut self) -> Option<EitherOrBoth<A, B>> {
        match (self.a.next(), self.b.next()) {
            (None, None) => None,
            (Some(a), None) => Some(Left(a)),
            (None, Some(b)) => Some(Right(b)),
            (Some(a), Some(b)) => Some(Both(a, b)),
        }
    }

    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        let (a_lower, a_upper) = self.a.size_hint();
        let (b_lower, b_upper) = self.b.size_hint();

        let lower = cmp::max(a_lower, b_lower);

        let upper = match (a_upper, b_upper) {
            (Some(x), Some(y)) => Some(cmp::max(x,y)),
            _ => None
        };

        (lower, upper)
    }
}

impl<A, B, T: ExactSizeIterator<A>, U: ExactSizeIterator<B>> DoubleEndedIterator<EitherOrBoth<A, B>>
for ZipLongest<T, U> {
    #[inline]
    fn next_back(&mut self) -> Option<EitherOrBoth<A, B>> {
        use std::cmp::{Equal, Greater, Less};
        match self.a.len().cmp(&self.b.len()) {
            Equal => match (self.a.next_back(), self.b.next_back()) {
                (None, None) => None,
                (Some(a), Some(b)) => Some(Both(a, b)),
                // These can only happen if .len() is inconsistent with .next_back()
                (Some(a), None) => Some(Left(a)),
                (None, Some(b)) => Some(Right(b)),
            },
            Greater => self.a.next_back().map(Left),
            Less => self.b.next_back().map(Right),
        }
    }
}

impl<A, B, T: RandomAccessIterator<A>, U: RandomAccessIterator<B>>
RandomAccessIterator<EitherOrBoth<A, B>> for ZipLongest<T, U> {
    #[inline]
    fn indexable(&self) -> uint {
        cmp::max(self.a.indexable(), self.b.indexable())
    }

    #[inline]
    fn idx(&mut self, index: uint) -> Option<EitherOrBoth<A, B>> {
        match (self.a.idx(index), self.b.idx(index)) {
            (None, None) => None,
            (Some(a), None) => Some(Left(a)),
            (None, Some(b)) => Some(Right(b)),
            (Some(a), Some(b)) => Some(Both(a, b)),
        }
    }
}

#[unstable = "trait is unstable"]
impl<A, B, T, U> ExactSizeIterator<EitherOrBoth<A, B>> for ZipLongest<T, U>
    where T: ExactSizeIterator<A>, U: ExactSizeIterator<B> {}

/// A value yielded by `ZipLongest`.
/// Contains one or two values,
/// depending on which of the input iterators are exhausted.
#[deriving(Clone, PartialEq, Eq, Show)]
pub enum EitherOrBoth<A, B> {
    /// Neither input iterator is exhausted yet, yielding two values.
    Both(A, B),
    /// The parameter iterator of `.zip_longest()` is exhausted,
    /// only yielding a value from the `self` iterator.
    Left(A),
    /// The `self` iterator of `.zip_longest()` is exhausted,
    /// only yielding a value from the parameter iterator.
    Right(B),
}
<commit_msg>Fix Ordering import for latest rustc<commit_after>use std::cmp;
use self::EitherOrBoth::{Right, Left, Both};

// ZipLongest originally written by SimonSapin,
// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283

/// An iterator which iterates two other iterators simultaneously
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct ZipLongest<T, U> {
    a: T,
    b: U
}

impl<T, U> ZipLongest<T, U>
{
    /// Create a new ZipLongest iterator.
    pub fn new(a: T, b: U) -> ZipLongest<T, U>
    {
        ZipLongest{a: a, b: b}
    }
}

impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<EitherOrBoth<A, B>> for ZipLongest<T, U> {
    #[inline]
    fn next(&mut self) -> Option<EitherOrBoth<A, B>> {
        match (self.a.next(), self.b.next()) {
            (None, None) => None,
            (Some(a), None) => Some(Left(a)),
            (None, Some(b)) => Some(Right(b)),
            (Some(a), Some(b)) => Some(Both(a, b)),
        }
    }

    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        let (a_lower, a_upper) = self.a.size_hint();
        let (b_lower, b_upper) = self.b.size_hint();

        let lower = cmp::max(a_lower, b_lower);

        let upper = match (a_upper, b_upper) {
            (Some(x), Some(y)) => Some(cmp::max(x,y)),
            _ => None
        };

        (lower, upper)
    }
}

impl<A, B, T: ExactSizeIterator<A>, U: ExactSizeIterator<B>> DoubleEndedIterator<EitherOrBoth<A, B>>
for ZipLongest<T, U> {
    #[inline]
    fn next_back(&mut self) -> Option<EitherOrBoth<A, B>> {
        use std::cmp::Ordering::{Equal, Greater, Less};
        match self.a.len().cmp(&self.b.len()) {
            Equal => match (self.a.next_back(), self.b.next_back()) {
                (None, None) => None,
                (Some(a), Some(b)) => Some(Both(a, b)),
                // These can only happen if .len() is inconsistent with .next_back()
                (Some(a), None) => Some(Left(a)),
                (None, Some(b)) => Some(Right(b)),
            },
            Greater => self.a.next_back().map(Left),
            Less => self.b.next_back().map(Right),
        }
    }
}

impl<A, B, T: RandomAccessIterator<A>, U: RandomAccessIterator<B>>
RandomAccessIterator<EitherOrBoth<A, B>> for ZipLongest<T, U> {
    #[inline]
    fn indexable(&self) -> uint {
        cmp::max(self.a.indexable(), self.b.indexable())
    }

    #[inline]
    fn idx(&mut self, index: uint) -> Option<EitherOrBoth<A, B>> {
        match (self.a.idx(index), self.b.idx(index)) {
            (None, None) => None,
            (Some(a), None) => Some(Left(a)),
            (None, Some(b)) => Some(Right(b)),
            (Some(a), Some(b)) => Some(Both(a, b)),
        }
    }
}

#[unstable = "trait is unstable"]
impl<A, B, T, U> ExactSizeIterator<EitherOrBoth<A, B>> for ZipLongest<T, U>
    where T: ExactSizeIterator<A>, U: ExactSizeIterator<B> {}

/// A value yielded by `ZipLongest`.
/// Contains one or two values,
/// depending on which of the input iterators are exhausted.
#[deriving(Clone, PartialEq, Eq, Show)]
pub enum EitherOrBoth<A, B> {
    /// Neither input iterator is exhausted yet, yielding two values.
    Both(A, B),
    /// The parameter iterator of `.zip_longest()` is exhausted,
    /// only yielding a value from the `self` iterator.
    Left(A),
    /// The `self` iterator of `.zip_longest()` is exhausted,
    /// only yielding a value from the parameter iterator.
    Right(B),
}
<|endoftext|>


<commit_before>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// ----- string -----

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>group nstring<commit_after>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// ----- string -----

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// ----- nstring ----- nil or string

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>use std::any::TypeId;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;

use crate::descriptor::EnumDescriptorProto;
use crate::descriptor::EnumValueDescriptorProto;
use crate::enums::ProtobufEnum;
use crate::enums::ProtobufEnumOrUnknown;
use crate::reflect::enums::dynamic::DynamicEnumDescriptor;
use crate::reflect::enums::generated::GeneratedEnumDescriptor;
#[cfg(not(rustc_nightly))]
use crate::reflect::enums::generated::GetEnumDescriptor;
use crate::reflect::file::FileDescriptorImpl;
use crate::reflect::FileDescriptor;
use crate::reflect::ProtobufValue;

pub(crate) mod dynamic;
pub(crate) mod generated;
pub(crate) mod index;

/// Description for enum variant.
///
/// Used in reflection.
#[derive(Clone, Eq, PartialEq)]
pub struct EnumValueDescriptor {
    pub(crate) enum_descriptor: EnumDescriptor,
    pub(crate) index: usize,
}

impl Hash for EnumValueDescriptor {
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&self.value(), state)
    }
}

fn _assert_send_sync() {
    fn _assert_send_sync<T: Send + Sync>() {}
    _assert_send_sync::<EnumValueDescriptor>();
}

impl fmt::Debug for EnumValueDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumValueDescriptor")
            // TODO: add something
            .field("value", &"...")
            .finish()
    }
}

impl EnumValueDescriptor {
    pub(crate) fn new(enum_descriptor: EnumDescriptor, index: usize) -> EnumValueDescriptor {
        EnumValueDescriptor {
            enum_descriptor,
            index,
        }
    }

    /// `.proto` object which declared this value.
    pub fn get_proto(&self) -> &EnumValueDescriptorProto {
        &self.enum_descriptor.get_proto().value[self.index as usize]
    }

    /// Name of enum variant as specified in proto file
    pub fn get_name(&self) -> &str {
        self.get_proto().get_name()
    }

    /// `i32` value of the enum variant
    pub fn value(&self) -> i32 {
        self.get_proto().get_number()
    }

    /// Get descriptor of enum holding this value.
    pub fn enum_descriptor(&self) -> &EnumDescriptor {
        &self.enum_descriptor
    }

    /// Convert this value descriptor into proper enum object.
    ///
    /// ```
    /// # use protobuf::well_known_types::NullValue;
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::reflect::EnumValueDescriptor;
    ///
    /// let value: EnumValueDescriptor = NullValue::NULL_VALUE.descriptor();
    /// let null: Option<NullValue> = value.cast();
    /// assert_eq!(Some(NullValue::NULL_VALUE), null);
    /// ```
    pub fn cast<E: ProtobufEnum>(&self) -> Option<E> {
        self.enum_descriptor()
            .cast_to_protobuf_enum::<E>(self.value())
    }
}

/// Dynamic representation of enum type.
///
/// Can be used in reflective operations.
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct EnumDescriptor {
    file_descriptor: FileDescriptor,
    index: usize,
}

impl fmt::Debug for EnumDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumDescriptor")
            // TODO
            //.field("full_name", &self.full_name)
            .field("..", &"..")
            .finish()
    }
}

impl EnumDescriptor {
    pub(crate) fn new(file_descriptor: FileDescriptor, index: usize) -> EnumDescriptor {
        EnumDescriptor {
            file_descriptor,
            index,
        }
    }

    fn get_impl(&self) -> EnumDescriptorImplRef {
        match &self.file_descriptor.imp {
            FileDescriptorImpl::Generated(g) => {
                EnumDescriptorImplRef::Generated(&g.enums[self.index])
            }
            FileDescriptorImpl::Dynamic(d) => EnumDescriptorImplRef::Dynamic(&d.enums[self.index]),
        }
    }

    /// Descriptor objects which defined this enum.
    pub fn get_proto(&self) -> &EnumDescriptorProto {
        match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => &g.proto,
            EnumDescriptorImplRef::Dynamic(d) => d.get_proto(),
        }
    }

    /// Enum name as given in `.proto` file
    pub fn get_name(&self) -> &str {
        // TODO: get_proto is inefficient
        self.get_proto().get_name()
    }

    /// Fully qualified protobuf name of enum
    pub fn full_name(&self) -> &str {
        match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => &g.full_name,
            EnumDescriptorImplRef::Dynamic(d) => &d.full_name,
        }
    }

    /// Get `EnumDescriptor` object for given enum type
    pub fn for_type<E: ProtobufEnum>() -> EnumDescriptor {
        E::enum_descriptor_static()
    }

    #[doc(hidden)]
    pub fn new_generated_2(file_descriptor: FileDescriptor, index: usize) -> EnumDescriptor {
        EnumDescriptor {
            file_descriptor,
            index,
        }
    }

    /// This enum values
    pub fn values<'a>(&'a self) -> impl Iterator<Item = EnumValueDescriptor> + 'a {
        let value_len = self.get_proto().value.len();
        (0..value_len).map(move |index| EnumValueDescriptor {
            enum_descriptor: self.clone(),
            index,
        })
    }

    /// First variant (also default in proto3).
    pub fn first_value(&self) -> EnumValueDescriptor {
        self.values().next().unwrap()
    }

    /// Find enum variant by name
    pub fn get_value_by_name<'a>(&'a self, name: &str) -> Option<EnumValueDescriptor> {
        let index = match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => *g.indices.index_by_name.get(name)?,
            EnumDescriptorImplRef::Dynamic(d) => *d.indices.index_by_name.get(name)?,
        };
        Some(EnumValueDescriptor {
            enum_descriptor: self.clone(),
            index,
        })
    }

    /// Find enum variant by number
    pub fn get_value_by_number(&self, number: i32) -> Option<EnumValueDescriptor> {
        let index = match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => *g.indices.index_by_number.get(&number)?,
            EnumDescriptorImplRef::Dynamic(d) => *d.indices.index_by_number.get(&number)?,
        };
        Some(EnumValueDescriptor {
            enum_descriptor: self.clone(),
            index,
        })
    }

    /// Default enum value (first variant)
    pub fn get_default_value(&self) -> EnumValueDescriptor {
        EnumValueDescriptor {
            enum_descriptor: self.clone(),
            index: 0,
        }
    }

    /// Find enum variant by number or return default (first) enum value
    pub fn get_value_by_number_or_default(&self, number: i32) -> EnumValueDescriptor {
        match self.get_value_by_number(number) {
            Some(v) => v,
            None => self.get_default_value(),
        }
    }

    /// Check if this enum descriptor corresponds given enum type
    ///
    /// ```
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::descriptor::field_descriptor_proto::Label;
    /// # use protobuf::reflect::EnumDescriptor;
    ///
    /// let descriptor: EnumDescriptor = Label::enum_descriptor_static();
    ///
    /// assert!(descriptor.is::<Label>())
    /// ```
    pub fn is<E: ProtobufEnum>(&self) -> bool {
        match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => g.type_id == TypeId::of::<E>(),
            EnumDescriptorImplRef::Dynamic(..) => false,
        }
    }

    /// Create enum object from given value.
    ///
    /// Type parameter `E` can be either [`ProtobufEnum`](crate::ProtobufEnum)
    /// or [`ProtobufEnumOrUnknown`](crate::ProtobufEnumOrUnknown).
    ///
    /// # Panics
    ///
    /// This operation panics of `E` is `ProtobufEnum` and `value` is unknown.
    pub(crate) fn _cast<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        if let Some(e) = self.cast_to_protobuf_enum(value) {
            return Some(e);
        }
        if let Some(e) = self.cast_to_protobuf_enum_or_unknown(value) {
            return Some(e);
        }
        None
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        let g = match self.get_impl() {
            EnumDescriptorImplRef::Dynamic(..) => return None,
            EnumDescriptorImplRef::Generated(g) => g,
        };
        if TypeId::of::<E>() != g.type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnum>::cast(value))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        let g = match self.get_impl() {
            EnumDescriptorImplRef::Dynamic(..) => return None,
            EnumDescriptorImplRef::Generated(g) => g,
        };
        if TypeId::of::<E>() != g.type_id {
            return None;
        }

        use std::mem;
        unsafe {
            let mut r = mem::MaybeUninit::<E>::uninit();
            g.get_descriptor.copy_to(value, r.as_mut_ptr() as *mut ());
            Some(r.assume_init())
        }
    }

    #[cfg(rustc_nightly)]
    fn cast_to_protobuf_enum_or_unknown<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        let g = match self.get_impl() {
            EnumDescriptorImplRef::Dynamic(..) => return None,
            EnumDescriptorImplRef::Generated(g) => g,
        };
        if TypeId::of::<E>() != g.enum_or_unknown_type_id {
            return None;
        }

        Some(<E as cast_impl::CastValueToProtobufEnumOrUnknown>::cast(
            value,
        ))
    }

    #[cfg(not(rustc_nightly))]
    fn cast_to_protobuf_enum_or_unknown<E: ProtobufValue>(&self, value: i32) -> Option<E> {
        let g = match self.get_impl() {
            EnumDescriptorImplRef::Dynamic(..) => return None,
            EnumDescriptorImplRef::Generated(g) => g,
        };
        if TypeId::of::<E>() != g.enum_or_unknown_type_id {
            return None;
        }

        use std::mem;
        use std::ptr;
        debug_assert_eq!(mem::size_of::<E>(), mem::size_of::<i32>());
        unsafe {
            // This works because `ProtobufEnumOrUnknown<E>` is `#[repr(transparent)]`
            let mut r = mem::MaybeUninit::<E>::uninit();
            ptr::copy(&value, r.as_mut_ptr() as *mut i32, 1);
            Some(r.assume_init())
        }
    }
}

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

    pub(crate) trait CastValueToProtobufEnumOrUnknown: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnumOrUnknown for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnumOrUnknown for ProtobufEnumOrUnknown<E> {
        fn cast(value: i32) -> ProtobufEnumOrUnknown<E> {
            ProtobufEnumOrUnknown::from_i32(value)
        }
    }

    pub(crate) trait CastValueToProtobufEnum: Sized {
        fn cast(value: i32) -> Self;
    }

    impl<T> CastValueToProtobufEnum for T {
        default fn cast(_value: i32) -> T {
            unreachable!();
        }
    }

    impl<E: ProtobufEnum> CastValueToProtobufEnum for E {
        fn cast(value: i32) -> E {
            E::from_i32(value).expect(&format!("unknown enum value: {}", value))
        }
    }
}

enum EnumDescriptorImplRef<'a> {
    Generated(&'static GeneratedEnumDescriptor),
    Dynamic(&'a DynamicEnumDescriptor),
}
<commit_msg>Remove more unused/unsafe code<commit_after>use std::any::TypeId;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;

use crate::descriptor::EnumDescriptorProto;
use crate::descriptor::EnumValueDescriptorProto;
use crate::enums::ProtobufEnum;
use crate::reflect::enums::dynamic::DynamicEnumDescriptor;
use crate::reflect::enums::generated::GeneratedEnumDescriptor;
#[cfg(not(rustc_nightly))]
use crate::reflect::enums::generated::GetEnumDescriptor;
use crate::reflect::file::FileDescriptorImpl;
use crate::reflect::FileDescriptor;

pub(crate) mod dynamic;
pub(crate) mod generated;
pub(crate) mod index;

/// Description for enum variant.
///
/// Used in reflection.
#[derive(Clone, Eq, PartialEq)]
pub struct EnumValueDescriptor {
    pub(crate) enum_descriptor: EnumDescriptor,
    pub(crate) index: usize,
}

impl Hash for EnumValueDescriptor {
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&self.value(), state)
    }
}

fn _assert_send_sync() {
    fn _assert_send_sync<T: Send + Sync>() {}
    _assert_send_sync::<EnumValueDescriptor>();
}

impl fmt::Debug for EnumValueDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumValueDescriptor")
            // TODO: add something
            .field("value", &"...")
            .finish()
    }
}

impl EnumValueDescriptor {
    pub(crate) fn new(enum_descriptor: EnumDescriptor, index: usize) -> EnumValueDescriptor {
        EnumValueDescriptor {
            enum_descriptor,
            index,
        }
    }

    /// `.proto` object which declared this value.
    pub fn get_proto(&self) -> &EnumValueDescriptorProto {
        &self.enum_descriptor.get_proto().value[self.index as usize]
    }

    /// Name of enum variant as specified in proto file
    pub fn get_name(&self) -> &str {
        self.get_proto().get_name()
    }

    /// `i32` value of the enum variant
    pub fn value(&self) -> i32 {
        self.get_proto().get_number()
    }

    /// Get descriptor of enum holding this value.
    pub fn enum_descriptor(&self) -> &EnumDescriptor {
        &self.enum_descriptor
    }

    /// Convert this value descriptor into proper enum object.
    ///
    /// ```
    /// # use protobuf::well_known_types::NullValue;
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::reflect::EnumValueDescriptor;
    ///
    /// let value: EnumValueDescriptor = NullValue::NULL_VALUE.descriptor();
    /// let null: Option<NullValue> = value.cast();
    /// assert_eq!(Some(NullValue::NULL_VALUE), null);
    /// ```
    pub fn cast<E: ProtobufEnum>(&self) -> Option<E> {
        if self.enum_descriptor != E::enum_descriptor_static() {
            return None;
        }
        E::from_i32(self.value())
    }
}

/// Dynamic representation of enum type.
///
/// Can be used in reflective operations.
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct EnumDescriptor {
    file_descriptor: FileDescriptor,
    index: usize,
}

impl fmt::Debug for EnumDescriptor {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("EnumDescriptor")
            // TODO
            //.field("full_name", &self.full_name)
            .field("..", &"..")
            .finish()
    }
}

impl EnumDescriptor {
    pub(crate) fn new(file_descriptor: FileDescriptor, index: usize) -> EnumDescriptor {
        EnumDescriptor {
            file_descriptor,
            index,
        }
    }

    fn get_impl(&self) -> EnumDescriptorImplRef {
        match &self.file_descriptor.imp {
            FileDescriptorImpl::Generated(g) => {
                EnumDescriptorImplRef::Generated(&g.enums[self.index])
            }
            FileDescriptorImpl::Dynamic(d) => EnumDescriptorImplRef::Dynamic(&d.enums[self.index]),
        }
    }

    /// Descriptor objects which defined this enum.
    pub fn get_proto(&self) -> &EnumDescriptorProto {
        match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => &g.proto,
            EnumDescriptorImplRef::Dynamic(d) => d.get_proto(),
        }
    }

    /// Enum name as given in `.proto` file
    pub fn get_name(&self) -> &str {
        // TODO: get_proto is inefficient
        self.get_proto().get_name()
    }

    /// Fully qualified protobuf name of enum
    pub fn full_name(&self) -> &str {
        match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => &g.full_name,
            EnumDescriptorImplRef::Dynamic(d) => &d.full_name,
        }
    }

    /// Get `EnumDescriptor` object for given enum type
    pub fn for_type<E: ProtobufEnum>() -> EnumDescriptor {
        E::enum_descriptor_static()
    }

    #[doc(hidden)]
    pub fn new_generated_2(file_descriptor: FileDescriptor, index: usize) -> EnumDescriptor {
        EnumDescriptor {
            file_descriptor,
            index,
        }
    }

    /// This enum values
    pub fn values<'a>(&'a self) -> impl Iterator<Item = EnumValueDescriptor> + 'a {
        let value_len = self.get_proto().value.len();
        (0..value_len).map(move |index| EnumValueDescriptor {
            enum_descriptor: self.clone(),
            index,
        })
    }

    /// First variant (also default in proto3).
    pub fn first_value(&self) -> EnumValueDescriptor {
        self.values().next().unwrap()
    }

    /// Find enum variant by name
    pub fn get_value_by_name<'a>(&'a self, name: &str) -> Option<EnumValueDescriptor> {
        let index = match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => *g.indices.index_by_name.get(name)?,
            EnumDescriptorImplRef::Dynamic(d) => *d.indices.index_by_name.get(name)?,
        };
        Some(EnumValueDescriptor {
            enum_descriptor: self.clone(),
            index,
        })
    }

    /// Find enum variant by number
    pub fn get_value_by_number(&self, number: i32) -> Option<EnumValueDescriptor> {
        let index = match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => *g.indices.index_by_number.get(&number)?,
            EnumDescriptorImplRef::Dynamic(d) => *d.indices.index_by_number.get(&number)?,
        };
        Some(EnumValueDescriptor {
            enum_descriptor: self.clone(),
            index,
        })
    }

    /// Default enum value (first variant)
    pub fn get_default_value(&self) -> EnumValueDescriptor {
        EnumValueDescriptor {
            enum_descriptor: self.clone(),
            index: 0,
        }
    }

    /// Find enum variant by number or return default (first) enum value
    pub fn get_value_by_number_or_default(&self, number: i32) -> EnumValueDescriptor {
        match self.get_value_by_number(number) {
            Some(v) => v,
            None => self.get_default_value(),
        }
    }

    /// Check if this enum descriptor corresponds given enum type
    ///
    /// ```
    /// # use protobuf::ProtobufEnum;
    /// # use protobuf::descriptor::field_descriptor_proto::Label;
    /// # use protobuf::reflect::EnumDescriptor;
    ///
    /// let descriptor: EnumDescriptor = Label::enum_descriptor_static();
    ///
    /// assert!(descriptor.is::<Label>())
    /// ```
    pub fn is<E: ProtobufEnum>(&self) -> bool {
        match self.get_impl() {
            EnumDescriptorImplRef::Generated(g) => g.type_id == TypeId::of::<E>(),
            EnumDescriptorImplRef::Dynamic(..) => false,
        }
    }
}

enum EnumDescriptorImplRef<'a> {
    Generated(&'static GeneratedEnumDescriptor),
    Dynamic(&'a DynamicEnumDescriptor),
}
<|endoftext|>


<commit_before>#![cfg(feature = "s3")]
extern crate rusoto_core;
extern crate rusoto_s3;
extern crate time;
extern crate hyper;
extern crate env_logger;
extern crate log;

use hyper::Client;
use std::fs::File;
use std::io::{Read, BufReader};
use time::get_time;

use rusoto_core::{DefaultCredentialsProvider, Region};
use rusoto_s3::{S3, S3Client, HeadObjectRequest, CopyObjectRequest, GetObjectRequest,
                 PutObjectRequest, DeleteObjectRequest, PutBucketCorsRequest, CORSConfiguration,
                 CORSRule, CreateBucketRequest, DeleteBucketRequest, CreateMultipartUploadRequest,
                 UploadPartRequest, CompleteMultipartUploadRequest, CompletedMultipartUpload,
                 CompletedPart, ListObjectsV2Request};
use rusoto_core::default_tls_client;

type TestClient = S3Client<DefaultCredentialsProvider, Client>;

// Rust is in bad need of an integration test harness
// This creates the S3 resources needed for a suite of tests,
// executes those tests, and then destroys the resources
#[test]
fn test_all_the_things() {
    let _ = env_logger::init();

    let client = S3Client::new(default_tls_client().unwrap(),
                               DefaultCredentialsProvider::new().unwrap(),
                               Region::UsEast1);

    let test_bucket = format!("rusoto_test_bucket_{}", get_time().sec);
    let filename = format!("test_file_{}", get_time().sec);
    let utf8_filename = format!("test[über]file@{}", get_time().sec);
    let binary_filename = format!("test_file_b{}", get_time().sec);
    let multipart_filename = format!("test_multipart_file_{}", get_time().sec);

    // get a list of list_buckets
    test_list_buckets(&client);

    // create a bucket for these tests
    test_create_bucket(&client, &test_bucket);

    // list items v2
    list_items_in_bucket(&client, &test_bucket);

    // do a multipart upload
    test_multipart_upload(&client, &test_bucket, &multipart_filename);

    // modify the bucket's CORS properties
    test_put_bucket_cors(&client, &test_bucket);

    // PUT an object (no_credentials is an arbitrary choice)
    test_put_object_with_filename(&client,
                                  &test_bucket,
                                  &filename,
                                  &"tests/sample-data/no_credentials");

    // HEAD the object that was PUT
    test_head_object(&client, &test_bucket, &filename);

    // GET the object
    test_get_object(&client, &test_bucket, &filename);
    test_get_object_bufreader(&client, &test_bucket, &filename);
    test_get_object_range(&client, &test_bucket, &filename);
    // copy the object to change its settings
    test_copy_object(&client, &test_bucket, &filename);

    // UTF8 filenames
    test_put_object_with_filename(&client,
                                  &test_bucket,
                                  &utf8_filename,
                                  &"tests/sample-data/no_credentials");

    test_copy_object_utf8(&client, &test_bucket, &utf8_filename);

    test_delete_object(&client, &test_bucket, &utf8_filename);

    // Binary objects:
    test_put_object_with_filename(&client,
                                  &test_bucket,
                                  &binary_filename,
                                  &"tests/sample-data/binary-file");
    test_get_object(&client, &test_bucket, &binary_filename);
    test_get_object_bufreader(&client, &test_bucket, &binary_filename);

    // paging test requires three items in the bucket, put another item there:
    // PUT an object (no_credentials is an arbitrary choice)
    let another_filename = format!("foo{}", filename);
    test_put_object_with_filename(&client,
                                  &test_bucket,
                                  &another_filename,
                                  &"tests/sample-data/no_credentials");

    // list items with paging
    list_items_in_bucket_paged(&client, &test_bucket);

    test_delete_object(&client, &test_bucket, &binary_filename);
    test_delete_object(&client, &test_bucket, &another_filename);

    // DELETE the object
    test_delete_object(&client, &test_bucket, &filename);

    // delete the test bucket
    test_delete_bucket(&client, &test_bucket);
}

fn test_multipart_upload(client: &TestClient, bucket: &str, filename: &str) {
    let create_multipart_req = CreateMultipartUploadRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    // start the multipart upload and note the upload_id generated
    let response = client.create_multipart_upload(&create_multipart_req).expect("Couldn't create multipart upload");
    println!("{:#?}", response);
    let upload_id = response.upload_id.unwrap();

    // create 2 upload parts
    let create_upload_part = |body: Vec<u8>, part_number: i64| -> UploadPartRequest {
        UploadPartRequest {
            body: Some(body),
            bucket: bucket.to_owned(),
            key: filename.to_owned(),
            upload_id: upload_id.to_owned(),
            part_number: part_number,
            ..Default::default()
        }
    };

    // minimum size for a non-final multipart upload part is 5MB
    let part_req1 = create_upload_part(vec!['a' as u8; 1024 * 1024 * 5], 1);
    let part_req2 = create_upload_part("foo".as_bytes().to_vec(), 2);

    // upload 2 parts and note the etags generated for them
    let mut completed_parts = Vec::new();
    for req in [part_req1, part_req2].into_iter() {
        let response = client.upload_part(&req).expect("Couldn't upload a file part");
        println!("{:#?}", response);
        completed_parts.push(CompletedPart {
            e_tag: response.e_tag.clone(),
            part_number: Some(req.part_number),
        });
    }

    // complete the multipart upload with the etags of the parts
    let completed_upload = CompletedMultipartUpload { parts: Some(completed_parts) };

    let complete_req = CompleteMultipartUploadRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        upload_id: upload_id.to_owned(),
        multipart_upload: Some(completed_upload),
        ..Default::default()
    };

    let response = client.complete_multipart_upload(&complete_req).expect("Couldn't complete multipart upload");
    println!("{:#?}", response);

    // delete the completed file
    test_delete_object(client, bucket, filename);
}

fn test_create_bucket(client: &TestClient, bucket: &str) {
    let create_bucket_req = CreateBucketRequest { bucket: bucket.to_owned(), ..Default::default() };

    let result = client.create_bucket(&create_bucket_req).expect("Couldn't create bucket");
    println!("{:#?}", result);
}

fn test_delete_bucket(client: &TestClient, bucket: &str) {
    let delete_bucket_req = DeleteBucketRequest { bucket: bucket.to_owned(), ..Default::default() };

    let result = client.delete_bucket(&delete_bucket_req).expect("Couldn't delete bucket");
    println!("{:#?}", result);
}

fn test_put_object_with_filename(client: &TestClient,
                                 bucket: &str,
                                 dest_filename: &str,
                                 local_filename: &str) {
    let mut f = File::open(local_filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
    match f.read_to_end(&mut contents) {
        Err(why) => panic!("Error opening file to send to S3: {}", why),
        Ok(_) => {
            let req = PutObjectRequest {
                bucket: bucket.to_owned(),
                key: dest_filename.to_owned(),
                body: Some(contents),
                ..Default::default()
            };
            let result = client.put_object(&req);
            println!("{:#?}", result);
        }
    }
}

fn test_head_object(client: &TestClient, bucket: &str, filename: &str) {
    let head_req = HeadObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.head_object(&head_req).expect("Couldn't HEAD object");
    println!("{:#?}", result);
}

fn test_get_object(client: &TestClient, bucket: &str, filename: &str) {
    let get_req = GetObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.get_object(&get_req).expect("Couldn't GET object");
    println!("get object result: {:#?}", result);

    let mut body: Vec<u8> = Vec::new();
    let mut buf: [u8; 5] = [0; 5];
    let mut stream = result.body.unwrap();

    while let Ok(len) = stream.read(&mut buf) {
        if len == 0 {
            break;
        }

        println!("read {} bytes", len);
        body.extend_from_slice(&buf[0..len]);
    }

    assert!(body.len() > 0);
}

fn test_get_object_bufreader(client: &TestClient, bucket: &str, filename: &str) {
    let get_req = GetObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.get_object(&get_req).expect("Couldn't GET object");
    println!("get object result: {:#?}", result);

    let stream = BufReader::new(result.body.unwrap());
    let body = stream.bytes().collect::<Result<Vec<u8>, _>>().unwrap();

    assert!(body.len() > 0);
}

fn test_get_object_range(client: &TestClient, bucket: &str, filename: &str) {
    let get_req = GetObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        range: Some("bytes=0-1".to_owned()),
        ..Default::default()
    };

    let result = client.get_object(&get_req).expect("Couldn't GET object (range)");
    println!("\nget object range result: {:#?}", result);
    assert_eq!(result.content_length.unwrap(), 2);
}

fn test_copy_object(client: &TestClient, bucket: &str, filename: &str) {
    let req = CopyObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        copy_source: format!("{}/{}", bucket, filename),
        cache_control: Some("max-age=123".to_owned()),
        content_type: Some("application/json".to_owned()),
        metadata_directive: Some("REPLACE".to_owned()),
        ..Default::default()
    };

    let result = client.copy_object(&req).expect("Couldn't copy object");
    println!("{:#?}", result);
}

fn test_copy_object_utf8(client: &TestClient, bucket: &str, filename: &str) {
    let req = CopyObjectRequest {
        bucket: bucket.to_owned(),
        key: format!("{}", filename.to_owned()),
        copy_source: rusoto_s3::util::encode_key(format!("{}/{}", bucket, filename)),
        cache_control: Some("max-age=123".to_owned()),
        content_type: Some("application/json".to_owned()),
        metadata_directive: Some("REPLACE".to_owned()),
        ..Default::default()
    };

    let result = client.copy_object(&req).expect("Couldn't copy object (utf8)");
    println!("{:#?}", result);
}

fn test_delete_object(client: &TestClient, bucket: &str, filename: &str) {
    let del_req = DeleteObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.delete_object(&del_req).expect("Couldn't delete object");
    println!("{:#?}", result);
}

fn test_list_buckets(client: &TestClient) {
    let result = client.list_buckets().expect("Couldn't list buckets");
    println!("\nbuckets available: {:#?}", result);
}

fn list_items_in_bucket(client: &TestClient, bucket: &str) {
    let list_obj_req = ListObjectsV2Request {
        bucket: bucket.to_owned(),
        start_after: Some("foo".to_owned()),
        ..Default::default()
    };
    let result = client.list_objects_v2(&list_obj_req).expect("Couldn't list items in bucket (v2)");
    println!("Items in bucket: {:#?}", result);
}

// Assuming there's already more than three item in our test bucket:
fn list_items_in_bucket_paged(client: &TestClient, bucket: &str) {
    let mut list_obj_req = ListObjectsV2Request {
        bucket: bucket.to_owned(),
        max_keys: Some(1),
        ..Default::default()
    };
    let result = client.list_objects_v2(&list_obj_req).expect("list objects v2 failed");
    println!("Items in bucket, page 1: {:#?}", result);
    assert!(result.next_continuation_token.is_some());

    list_obj_req.continuation_token = result.next_continuation_token;
    let result = client.list_objects_v2(&list_obj_req).expect("list objects v2 paging failed");
    println!("Items in bucket, page 2: {:#?}", result);
    // For the second call it the token is in `continuation_token` not `next_continuation_token`
    assert!(result.continuation_token.is_some());
}

fn test_put_bucket_cors(client: &TestClient, bucket: &str) {
    let cors_rules =
        vec![CORSRule {
                 allowed_methods: vec!["PUT".to_owned(), "POST".to_owned(), "DELETE".to_owned()],
                 allowed_origins: vec!["http://www.example.com".to_owned()],
                 allowed_headers: Some(vec!["*".to_owned()]),
                 max_age_seconds: Some(3000),
                 expose_headers: Some(vec!["x-amz-server-side-encryption".to_owned()]),
                 ..Default::default()
             }];

    let cors_configuration = CORSConfiguration { cors_rules: cors_rules };

    let req = PutBucketCorsRequest {
        bucket: bucket.to_owned(),
        cors_configuration: cors_configuration,
        ..Default::default()
    };

    let result = client.put_bucket_cors(&req).expect("Couldn't apply bucket CORS");
    println!("{:#?}", result);
}
<commit_msg>add metadata integration tests<commit_after>#![cfg(feature = "s3")]
extern crate rusoto_core;
extern crate rusoto_s3;
extern crate time;
extern crate hyper;
extern crate env_logger;
extern crate log;

use hyper::Client;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, BufReader};
use time::get_time;

use rusoto_core::{DefaultCredentialsProvider, Region};
use rusoto_s3::{S3, S3Client, HeadObjectRequest, CopyObjectRequest, GetObjectRequest,
                 PutObjectRequest, DeleteObjectRequest, PutBucketCorsRequest, CORSConfiguration,
                 CORSRule, CreateBucketRequest, DeleteBucketRequest, CreateMultipartUploadRequest,
                 UploadPartRequest, CompleteMultipartUploadRequest, CompletedMultipartUpload,
                 CompletedPart, ListObjectsV2Request};
use rusoto_core::default_tls_client;

type TestClient = S3Client<DefaultCredentialsProvider, Client>;

// Rust is in bad need of an integration test harness
// This creates the S3 resources needed for a suite of tests,
// executes those tests, and then destroys the resources
#[test]
fn test_all_the_things() {
    let _ = env_logger::init();

    let client = S3Client::new(default_tls_client().unwrap(),
                               DefaultCredentialsProvider::new().unwrap(),
                               Region::UsEast1);

    let test_bucket = format!("rusoto_test_bucket_{}", get_time().sec);
    let filename = format!("test_file_{}", get_time().sec);
    let utf8_filename = format!("test[über]file@{}", get_time().sec);
    let binary_filename = format!("test_file_b{}", get_time().sec);
    let multipart_filename = format!("test_multipart_file_{}", get_time().sec);
    let metadata_filename = format!("test_metadata_file_{}", get_time().sec);

    // get a list of list_buckets
    test_list_buckets(&client);

    // create a bucket for these tests
    test_create_bucket(&client, &test_bucket);

    // list items v2
    list_items_in_bucket(&client, &test_bucket);

    // do a multipart upload
    test_multipart_upload(&client, &test_bucket, &multipart_filename);

    // modify the bucket's CORS properties
    test_put_bucket_cors(&client, &test_bucket);

    // PUT an object (no_credentials is an arbitrary choice)
    test_put_object_with_filename(&client,
                                  &test_bucket,
                                  &filename,
                                  &"tests/sample-data/no_credentials");

    // HEAD the object that was PUT
    test_head_object(&client, &test_bucket, &filename);

    // GET the object
    test_get_object(&client, &test_bucket, &filename);
    test_get_object_bufreader(&client, &test_bucket, &filename);
    test_get_object_range(&client, &test_bucket, &filename);
    // copy the object to change its settings
    test_copy_object(&client, &test_bucket, &filename);

    // UTF8 filenames
    test_put_object_with_filename(&client,
                                  &test_bucket,
                                  &utf8_filename,
                                  &"tests/sample-data/no_credentials");

    test_copy_object_utf8(&client, &test_bucket, &utf8_filename);

    test_delete_object(&client, &test_bucket, &utf8_filename);

    // Binary objects:
    test_put_object_with_filename(&client,
                                  &test_bucket,
                                  &binary_filename,
                                  &"tests/sample-data/binary-file");
    test_get_object(&client, &test_bucket, &binary_filename);
    test_get_object_bufreader(&client, &test_bucket, &binary_filename);

    // paging test requires three items in the bucket, put another item there:
    // PUT an object (no_credentials is an arbitrary choice)
    let another_filename = format!("foo{}", filename);
    test_put_object_with_filename(&client,
                                  &test_bucket,
                                  &another_filename,
                                  &"tests/sample-data/no_credentials");

    // metadata tests
    let mut metadata = HashMap::<String, String>::new();
    metadata.insert("rusoto-metadata-some".to_string(), "some-test-value".to_string());
    metadata.insert("rusoto-metadata-none".to_string(), "".to_string());

    test_put_object_with_metadata(&client,
                                  &test_bucket,
                                  &metadata_filename,
                                  &"tests/sample-data/no_credentials",
                                  &metadata);

    test_head_object_with_metadata(&client, &test_bucket, &metadata_filename, &metadata);
    test_get_object_with_metadata(&client, &test_bucket, &metadata_filename, &metadata);

    // list items with paging
    list_items_in_bucket_paged(&client, &test_bucket);

    test_delete_object(&client, &test_bucket, &metadata_filename);
    test_delete_object(&client, &test_bucket, &binary_filename);
    test_delete_object(&client, &test_bucket, &another_filename);

    // DELETE the object
    test_delete_object(&client, &test_bucket, &filename);

    // delete the test bucket
    test_delete_bucket(&client, &test_bucket);
}

fn test_multipart_upload(client: &TestClient, bucket: &str, filename: &str) {
    let create_multipart_req = CreateMultipartUploadRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    // start the multipart upload and note the upload_id generated
    let response = client.create_multipart_upload(&create_multipart_req).expect("Couldn't create multipart upload");
    println!("{:#?}", response);
    let upload_id = response.upload_id.unwrap();

    // create 2 upload parts
    let create_upload_part = |body: Vec<u8>, part_number: i64| -> UploadPartRequest {
        UploadPartRequest {
            body: Some(body),
            bucket: bucket.to_owned(),
            key: filename.to_owned(),
            upload_id: upload_id.to_owned(),
            part_number: part_number,
            ..Default::default()
        }
    };

    // minimum size for a non-final multipart upload part is 5MB
    let part_req1 = create_upload_part(vec!['a' as u8; 1024 * 1024 * 5], 1);
    let part_req2 = create_upload_part("foo".as_bytes().to_vec(), 2);

    // upload 2 parts and note the etags generated for them
    let mut completed_parts = Vec::new();
    for req in [part_req1, part_req2].into_iter() {
        let response = client.upload_part(&req).expect("Couldn't upload a file part");
        println!("{:#?}", response);
        completed_parts.push(CompletedPart {
            e_tag: response.e_tag.clone(),
            part_number: Some(req.part_number),
        });
    }

    // complete the multipart upload with the etags of the parts
    let completed_upload = CompletedMultipartUpload { parts: Some(completed_parts) };

    let complete_req = CompleteMultipartUploadRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        upload_id: upload_id.to_owned(),
        multipart_upload: Some(completed_upload),
        ..Default::default()
    };

    let response = client.complete_multipart_upload(&complete_req).expect("Couldn't complete multipart upload");
    println!("{:#?}", response);

    // delete the completed file
    test_delete_object(client, bucket, filename);
}

fn test_create_bucket(client: &TestClient, bucket: &str) {
    let create_bucket_req = CreateBucketRequest { bucket: bucket.to_owned(), ..Default::default() };

    let result = client.create_bucket(&create_bucket_req).expect("Couldn't create bucket");
    println!("{:#?}", result);
}

fn test_delete_bucket(client: &TestClient, bucket: &str) {
    let delete_bucket_req = DeleteBucketRequest { bucket: bucket.to_owned(), ..Default::default() };

    let result = client.delete_bucket(&delete_bucket_req).expect("Couldn't delete bucket");
    println!("{:#?}", result);
}

fn test_put_object_with_filename(client: &TestClient,
                                 bucket: &str,
                                 dest_filename: &str,
                                 local_filename: &str) {
    let mut f = File::open(local_filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
    match f.read_to_end(&mut contents) {
        Err(why) => panic!("Error opening file to send to S3: {}", why),
        Ok(_) => {
            let req = PutObjectRequest {
                bucket: bucket.to_owned(),
                key: dest_filename.to_owned(),
                body: Some(contents),
                ..Default::default()
            };
            let result = client.put_object(&req);
            println!("{:#?}", result);
        }
    }
}

fn test_head_object(client: &TestClient, bucket: &str, filename: &str) {
    let head_req = HeadObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.head_object(&head_req).expect("Couldn't HEAD object");
    println!("{:#?}", result);
}

fn test_get_object(client: &TestClient, bucket: &str, filename: &str) {
    let get_req = GetObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.get_object(&get_req).expect("Couldn't GET object");
    println!("get object result: {:#?}", result);

    let mut body: Vec<u8> = Vec::new();
    let mut buf: [u8; 5] = [0; 5];
    let mut stream = result.body.unwrap();

    while let Ok(len) = stream.read(&mut buf) {
        if len == 0 {
            break;
        }

        println!("read {} bytes", len);
        body.extend_from_slice(&buf[0..len]);
    }

    assert!(body.len() > 0);
}

fn test_get_object_bufreader(client: &TestClient, bucket: &str, filename: &str) {
    let get_req = GetObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.get_object(&get_req).expect("Couldn't GET object");
    println!("get object result: {:#?}", result);

    let stream = BufReader::new(result.body.unwrap());
    let body = stream.bytes().collect::<Result<Vec<u8>, _>>().unwrap();

    assert!(body.len() > 0);
}

fn test_get_object_range(client: &TestClient, bucket: &str, filename: &str) {
    let get_req = GetObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        range: Some("bytes=0-1".to_owned()),
        ..Default::default()
    };

    let result = client.get_object(&get_req).expect("Couldn't GET object (range)");
    println!("\nget object range result: {:#?}", result);
    assert_eq!(result.content_length.unwrap(), 2);
}

fn test_copy_object(client: &TestClient, bucket: &str, filename: &str) {
    let req = CopyObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        copy_source: format!("{}/{}", bucket, filename),
        cache_control: Some("max-age=123".to_owned()),
        content_type: Some("application/json".to_owned()),
        metadata_directive: Some("REPLACE".to_owned()),
        ..Default::default()
    };

    let result = client.copy_object(&req).expect("Couldn't copy object");
    println!("{:#?}", result);
}

fn test_copy_object_utf8(client: &TestClient, bucket: &str, filename: &str) {
    let req = CopyObjectRequest {
        bucket: bucket.to_owned(),
        key: format!("{}", filename.to_owned()),
        copy_source: rusoto_s3::util::encode_key(format!("{}/{}", bucket, filename)),
        cache_control: Some("max-age=123".to_owned()),
        content_type: Some("application/json".to_owned()),
        metadata_directive: Some("REPLACE".to_owned()),
        ..Default::default()
    };

    let result = client.copy_object(&req).expect("Couldn't copy object (utf8)");
    println!("{:#?}", result);
}

fn test_delete_object(client: &TestClient, bucket: &str, filename: &str) {
    let del_req = DeleteObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.delete_object(&del_req).expect("Couldn't delete object");
    println!("{:#?}", result);
}

fn test_list_buckets(client: &TestClient) {
    let result = client.list_buckets().expect("Couldn't list buckets");
    println!("\nbuckets available: {:#?}", result);
}

fn list_items_in_bucket(client: &TestClient, bucket: &str) {
    let list_obj_req = ListObjectsV2Request {
        bucket: bucket.to_owned(),
        start_after: Some("foo".to_owned()),
        ..Default::default()
    };
    let result = client.list_objects_v2(&list_obj_req).expect("Couldn't list items in bucket (v2)");
    println!("Items in bucket: {:#?}", result);
}

// Assuming there's already more than three item in our test bucket:
fn list_items_in_bucket_paged(client: &TestClient, bucket: &str) {
    let mut list_obj_req = ListObjectsV2Request {
        bucket: bucket.to_owned(),
        max_keys: Some(1),
        ..Default::default()
    };
    let result = client.list_objects_v2(&list_obj_req).expect("list objects v2 failed");
    println!("Items in bucket, page 1: {:#?}", result);
    assert!(result.next_continuation_token.is_some());

    list_obj_req.continuation_token = result.next_continuation_token;
    let result = client.list_objects_v2(&list_obj_req).expect("list objects v2 paging failed");
    println!("Items in bucket, page 2: {:#?}", result);
    // For the second call it the token is in `continuation_token` not `next_continuation_token`
    assert!(result.continuation_token.is_some());
}

fn test_put_bucket_cors(client: &TestClient, bucket: &str) {
    let cors_rules =
        vec![CORSRule {
                 allowed_methods: vec!["PUT".to_owned(), "POST".to_owned(), "DELETE".to_owned()],
                 allowed_origins: vec!["http://www.example.com".to_owned()],
                 allowed_headers: Some(vec!["*".to_owned()]),
                 max_age_seconds: Some(3000),
                 expose_headers: Some(vec!["x-amz-server-side-encryption".to_owned()]),
                 ..Default::default()
             }];

    let cors_configuration = CORSConfiguration { cors_rules: cors_rules };

    let req = PutBucketCorsRequest {
        bucket: bucket.to_owned(),
        cors_configuration: cors_configuration,
        ..Default::default()
    };

    let result = client.put_bucket_cors(&req).expect("Couldn't apply bucket CORS");
    println!("{:#?}", result);
}

fn test_put_object_with_metadata(client: &TestClient,
                                 bucket: &str,
                                 dest_filename: &str,
                                 local_filename: &str,
                                 metadata: &HashMap<String,String>) {

    let mut f = File::open(local_filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
    match f.read_to_end(&mut contents) {
        Err(why) => panic!("Error opening file to send to S3: {}", why),
        Ok(_) => {
            let req = PutObjectRequest {
                bucket: bucket.to_owned(),
                key: dest_filename.to_owned(),
                body: Some(contents),
                metadata: Some(metadata.clone()),
                ..Default::default()
            };
            let result = client.put_object(&req);
            println!("{:#?}", result);
        }
    }
}

fn test_head_object_with_metadata(client: &TestClient, bucket: &str, filename: &str, metadata: &HashMap<String,String>) {
    let head_req = HeadObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.head_object(&head_req).expect("Couldn't HEAD object");
    println!("{:#?}", result);

    let head_metadata = result.metadata.as_ref().expect("No metadata available");
    assert_eq!(metadata, head_metadata);
}

fn test_get_object_with_metadata(client: &TestClient, bucket: &str, filename: &str, metadata: &HashMap<String,String>) {
    let get_req = GetObjectRequest {
        bucket: bucket.to_owned(),
        key: filename.to_owned(),
        ..Default::default()
    };

    let result = client.get_object(&get_req).expect("Couldn't GET object");
    println!("get object result: {:#?}", result);

    let head_metadata = result.metadata.as_ref().expect("No metadata available");
    assert_eq!(metadata, head_metadata);
}<|endoftext|>


<commit_before><commit_msg>Used rustfmt on main<commit_after><|endoftext|>


<commit_before>extern crate autocfg;

use std::env;

fn main() {
    let ac = autocfg::new();
    if ac.probe_type("i128") {
        println!("cargo:rustc-cfg=has_i128");
    } else if env::var_os("CARGO_FEATURE_I128").is_some() {
        panic!("i128 support was not detected!");
    }
    ac.emit_expression_cfg(
        "unsafe { 1f64.to_int_unchecked::<i32>() }",
        "has_to_int_unchecked",
    );

    autocfg::rerun_path("build.rs");
}
<commit_msg>Trust the "i128" feature<commit_after>extern crate autocfg;

use std::env;

fn main() {
    let ac = autocfg::new();

    // If the "i128" feature is explicity requested, don't bother probing for it.
    // It will still cause a build error if that was set improperly.
    if env::var_os("CARGO_FEATURE_I128").is_some() || ac.probe_type("i128") {
        autocfg::emit("has_i128");
    }

    ac.emit_expression_cfg(
        "unsafe { 1f64.to_int_unchecked::<i32>() }",
        "has_to_int_unchecked",
    );

    autocfg::rerun_path("build.rs");
}
<|endoftext|>


<commit_before>use std::process::Command;

fn git_hash() -> String {
    let output = Command::new("git")
        .args(&["rev-parse", "--short", "HEAD"])
        .output()
        .unwrap();
    String::from_utf8_lossy(&output.stdout).into()
}

fn main() {
    let git_hash = option_env!("TRAVIS_COMMIT")
        .map(|s| s.into())
        .unwrap_or_else(|| git_hash());

    println!("cargo:rustc-env=GIT_HASH={}", git_hash);
}
<commit_msg>Use cat to get get sha.<commit_after>use std::process::Command;

fn git_hash() -> String {
    let output = Command::new("cat")
        .args(&[".git/refs/heads/next"])
        .output()
        .unwrap();
    String::from_utf8_lossy(&output.stdout).into()
}

fn main() {
    let git_hash = option_env!("TRAVIS_COMMIT")
        .map(|s| s.into())
        .unwrap_or_else(|| git_hash());

    println!("cargo:rustc-env=GIT_HASH={}", git_hash);
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::fs;
use std::io;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::ffi::OsString;
use std::ffi::OsStr;

trait CommandExt {
    fn execute(&mut self) -> io::Result<()>;
}

impl CommandExt for Command {
    /// Execute the command and return an error if it exited with a failure status.
    fn execute(&mut self) -> io::Result<()> {
        let status = try!(self.status());
        if status.success() {
            Ok(())
        } else {
            Err(io::Error::new(io::ErrorKind::Other, format!("The command\n\
            \t{:?}\n\
            did not run successfully.", self)))
        }
    }
}

/// The command to build lua, with switches for different *nix targets.
fn build_lua(tooling: &gcc::Tool, source: &Path, build: &Path) -> io::Result<()> {
    // calculate the Lua platform name
    let platform = match env::var("TARGET").unwrap().split('-').nth(2).unwrap() {
        "windows" => "mingw",
        "macos" => "macosx",
        "linux" => "linux",
        "freebsd" => "freebsd",
        "dragonfly" => "bsd",
        // fall back to the "generic" system
        _ => "generic",
    };

    // extract CC and MYCFLAGS from the detected tooling
    let cc = tooling.path();
    let mut cflags = OsString::new();
    for arg in tooling.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    // VPATH is used to invoke "make" from the directory where we want Lua to
    // be built into, but read the sources from the provided source directory.
    // Setting MAKE to match the command we invoke means that the VPATH and
    // Makefile path will be carried over when the Makefile invokes itself.
    let makefile = source.join("Makefile");
    let make = OsString::from(format!("make -e -f {:?}", makefile.to_string_lossy().replace("\\", "/")));

    // call the makefile
    let mut command = Command::new("make");
    for &(ref key, ref val) in tooling.env() {
        command.env(key, val);
    }
    command.current_dir(build)
        .env("VPATH", source.to_string_lossy().replace("\\", "/"))
        .env("MAKE", make)
        .env("CC", cc)
        .env("MYCFLAGS", cflags)
        .arg("-e")
        .arg("-f").arg(makefile)
        .arg(platform)
        .execute()
}

/// Ensure we have cl.exe and lib.exe at our disposal.
fn verify_msvc_environment() {
    let found_cl_exe = Command::new("cl.exe").arg("/help").output().is_ok();
    let found_lib_exe = Command::new("lib.exe").arg("/help").output().is_ok();

    if !found_cl_exe || !found_lib_exe {
        panic!("cl.exe and lib.exe must be on your %PATH% to compile Lua for MSVC.\n\
        Please install this crate through the Visual Studio Native Tools Command Line.");
    }
}

/// Compile liblua.lib for use with MSVC flavored Rust.
fn build_lua_msvc(source: &Path, build: &Path) -> io::Result<()>{
    verify_msvc_environment();
    let build_str = build.as_os_str().to_str().unwrap();
    // Compile our .obj files
    let mut compile_cmd = Command::new("cl.exe");
    compile_cmd.current_dir(&source);
    // Give cl.exe our .c files.
    for file_res in fs::read_dir(source).unwrap() {
        let dir_entry = file_res.unwrap();
        let file_name = dir_entry.file_name().into_string().unwrap();
        if file_name.ends_with(".c") && file_name != "luac.c" {
            compile_cmd.arg(file_name);
        }
    }
    compile_cmd.arg("/c") // Don't link. Just generate .obj files.
        .arg("/MP") // Builds multiple source files concurrently.
        .arg(format!("/Fo{}\\", &build_str)) // Output to the build folder
        .arg("/nologo"); // Prevent stdout pollution
        //.arg("/LD") // Not sure if I need this or not.
    compile_cmd.execute().unwrap(); // Block until compilation is complete.
    // Link our .obj files into liblua.lib.
    let mut lib_cmd = Command::new("lib.exe");
    lib_cmd.current_dir(&build);
    for file_res in fs::read_dir(build).unwrap() {
        let dir_entry = file_res.unwrap();
        let file_name = dir_entry.file_name().into_string().unwrap();
        if file_name.ends_with(".obj") {
            lib_cmd.arg(file_name);
        }
    }
    lib_cmd.arg(format!("/out:{}\\lua.lib", &build_str)) // Output file
        .arg("/NOLOGO");
    lib_cmd.execute()
}

/// If a static Lua is not yet available from a prior run of this script, this
/// will download Lua and build it. The cargo configuration text to link
/// statically against liblua.a/liblua.lib is then printed to stdout.
fn prebuild() -> io::Result<()> {
    let lua_dir : PathBuf = match env::var_os("LUA_LOCAL_SOURCE") {
        // If LUA_LOCAL_SOURCE is set, use it
        Some(dir) => PathBuf::from(dir),
        // Otherwise, pull from lua-source/src in the crate root
        None => {
            let mut dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
            dir.push(OsStr::new("lua-source/src").to_str().unwrap());
            dir
        }
    };
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let mut config = gcc::Config::new();
    let msvc = env::var("TARGET").unwrap().split('-').last().unwrap() == "msvc";
    println!("cargo:rustc-link-lib=static=lua");
    if !msvc && lua_dir.join("liblua.a").exists() {
        // If liblua.a is already in lua_dir, use it
        println!("cargo:rustc-link-search=native={}", &lua_dir.display());
    } else if msvc {
        if !build_dir.join("lua.lib").exists() {
            try!(build_lua_msvc(&lua_dir, &build_dir));
        }
        println!("cargo:rustc-link-search=native={}", &build_dir.display());
    } else {
        // Check build_dir
        if !build_dir.join("liblua.a").exists() {
            // Build liblua.a
            let tooling = config.get_compiler();
            try!(fs::create_dir_all(&build_dir));
            try!(build_lua(&tooling, &lua_dir, &build_dir));
        }
        println!("cargo:rustc-link-search=native={}", lua_dir.display());
    }

    // Ensure the presence of glue.rs
    if !build_dir.join("glue.rs").exists() {
        // Compile and run glue.c
        let glue = build_dir.join("glue");
        try!(config.include(&lua_dir).get_compiler().to_command()
            .arg("-I").arg(&lua_dir)
            .arg("src/glue/glue.c")
            .arg("-o").arg(&glue)
            .execute());
        try!(Command::new(glue)
            .arg(build_dir.join("glue.rs"))
            .execute());
    }
    Ok(())
}

fn main() {
    match prebuild() {
        Err(e) => panic!("Error: {}", e),
        Ok(()) => (),
    }
}
<commit_msg>Fix output path on *nix<commit_after>extern crate gcc;

use std::fs;
use std::io;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::ffi::OsString;
use std::ffi::OsStr;

trait CommandExt {
    fn execute(&mut self) -> io::Result<()>;
}

impl CommandExt for Command {
    /// Execute the command and return an error if it exited with a failure status.
    fn execute(&mut self) -> io::Result<()> {
        let status = try!(self.status());
        if status.success() {
            Ok(())
        } else {
            Err(io::Error::new(io::ErrorKind::Other, format!("The command\n\
            \t{:?}\n\
            did not run successfully.", self)))
        }
    }
}

/// The command to build lua, with switches for different *nix targets.
fn build_lua(tooling: &gcc::Tool, source: &Path, build: &Path) -> io::Result<()> {
    // calculate the Lua platform name
    let platform = match env::var("TARGET").unwrap().split('-').nth(2).unwrap() {
        "windows" => "mingw",
        "macos" => "macosx",
        "linux" => "linux",
        "freebsd" => "freebsd",
        "dragonfly" => "bsd",
        // fall back to the "generic" system
        _ => "generic",
    };

    // extract CC and MYCFLAGS from the detected tooling
    let cc = tooling.path();
    let mut cflags = OsString::new();
    for arg in tooling.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    // VPATH is used to invoke "make" from the directory where we want Lua to
    // be built into, but read the sources from the provided source directory.
    // Setting MAKE to match the command we invoke means that the VPATH and
    // Makefile path will be carried over when the Makefile invokes itself.
    let makefile = source.join("Makefile");
    let make = OsString::from(format!("make -e -f {:?}", makefile.to_string_lossy().replace("\\", "/")));

    // call the makefile
    let mut command = Command::new("make");
    for &(ref key, ref val) in tooling.env() {
        command.env(key, val);
    }
    command.current_dir(build)
        .env("VPATH", source.to_string_lossy().replace("\\", "/"))
        .env("MAKE", make)
        .env("CC", cc)
        .env("MYCFLAGS", cflags)
        .arg("-e")
        .arg("-f").arg(makefile)
        .arg(platform)
        .execute()
}

/// Ensure we have cl.exe and lib.exe at our disposal.
fn verify_msvc_environment() {
    let found_cl_exe = Command::new("cl.exe").arg("/help").output().is_ok();
    let found_lib_exe = Command::new("lib.exe").arg("/help").output().is_ok();

    if !found_cl_exe || !found_lib_exe {
        panic!("cl.exe and lib.exe must be on your %PATH% to compile Lua for MSVC.\n\
        Please install this crate through the Visual Studio Native Tools Command Line.");
    }
}

/// Compile liblua.lib for use with MSVC flavored Rust.
fn build_lua_msvc(source: &Path, build: &Path) -> io::Result<()>{
    verify_msvc_environment();
    let build_str = build.as_os_str().to_str().unwrap();
    // Compile our .obj files
    let mut compile_cmd = Command::new("cl.exe");
    compile_cmd.current_dir(&source);
    // Give cl.exe our .c files.
    for file_res in fs::read_dir(source).unwrap() {
        let dir_entry = file_res.unwrap();
        let file_name = dir_entry.file_name().into_string().unwrap();
        if file_name.ends_with(".c") && file_name != "luac.c" {
            compile_cmd.arg(file_name);
        }
    }
    compile_cmd.arg("/c") // Don't link. Just generate .obj files.
        .arg("/MP") // Builds multiple source files concurrently.
        .arg(format!("/Fo{}\\", &build_str)) // Output to the build folder
        .arg("/nologo"); // Prevent stdout pollution
        //.arg("/LD") // Not sure if I need this or not.
    compile_cmd.execute().unwrap(); // Block until compilation is complete.
    // Link our .obj files into liblua.lib.
    let mut lib_cmd = Command::new("lib.exe");
    lib_cmd.current_dir(&build);
    for file_res in fs::read_dir(build).unwrap() {
        let dir_entry = file_res.unwrap();
        let file_name = dir_entry.file_name().into_string().unwrap();
        if file_name.ends_with(".obj") {
            lib_cmd.arg(file_name);
        }
    }
    lib_cmd.arg(format!("/out:{}\\lua.lib", &build_str)) // Output file
        .arg("/NOLOGO");
    lib_cmd.execute()
}

/// If a static Lua is not yet available from a prior run of this script, this
/// will download Lua and build it. The cargo configuration text to link
/// statically against liblua.a/liblua.lib is then printed to stdout.
fn prebuild() -> io::Result<()> {
    let lua_dir : PathBuf = match env::var_os("LUA_LOCAL_SOURCE") {
        // If LUA_LOCAL_SOURCE is set, use it
        Some(dir) => PathBuf::from(dir),
        // Otherwise, pull from lua-source/src in the crate root
        None => {
            let mut dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
            dir.push(OsStr::new("lua-source/src").to_str().unwrap());
            dir
        }
    };
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let mut config = gcc::Config::new();
    let msvc = env::var("TARGET").unwrap().split('-').last().unwrap() == "msvc";
    println!("cargo:rustc-link-lib=static=lua");
    if !msvc && lua_dir.join("liblua.a").exists() {
        // If liblua.a is already in lua_dir, use it
        println!("cargo:rustc-link-search=native={}", &lua_dir.display());
    } else if msvc {
        if !build_dir.join("lua.lib").exists() {
            try!(build_lua_msvc(&lua_dir, &build_dir));
        }
        println!("cargo:rustc-link-search=native={}", &build_dir.display());
    } else {
        // Check build_dir
        if !build_dir.join("liblua.a").exists() {
            // Build liblua.a
            let tooling = config.get_compiler();
            try!(fs::create_dir_all(&build_dir));
            try!(build_lua(&tooling, &lua_dir, &build_dir));
        }
        println!("cargo:rustc-link-search=native={}", &build_dir.display());
    }

    // Ensure the presence of glue.rs
    if !build_dir.join("glue.rs").exists() {
        // Compile and run glue.c
        let glue = build_dir.join("glue");
        try!(config.include(&lua_dir).get_compiler().to_command()
            .arg("-I").arg(&lua_dir)
            .arg("src/glue/glue.c")
            .arg("-o").arg(&glue)
            .execute());
        try!(Command::new(glue)
            .arg(build_dir.join("glue.rs"))
            .execute());
    }
    Ok(())
}

fn main() {
    match prebuild() {
        Err(e) => panic!("Error: {}", e),
        Ok(()) => (),
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus};

// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
    #![feature(backtrace)]
    #![allow(dead_code)]

    use std::backtrace::{Backtrace, BacktraceStatus};
    use std::error::Error;
    use std::fmt::{self, Display};

    #[derive(Debug)]
    struct E;

    impl Display for E {
        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }

    impl Error for E {
        fn backtrace(&self) -> Option<&Backtrace> {
            let backtrace = Backtrace::capture();
            match backtrace.status() {
                BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
            }
            unimplemented!()
        }
    }
"#;

fn main() {
    if !cfg!(feature = "std") {
        return;
    }
    match compile_probe() {
        Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
        _ => {}
    }
}

fn compile_probe() -> Option<ExitStatus> {
    let rustc = env::var_os("RUSTC")?;
    let out_dir = env::var_os("OUT_DIR")?;
    let probefile = Path::new(&out_dir).join("probe.rs");
    fs::write(&probefile, PROBE).ok()?;
    Command::new(rustc)
        .arg("--edition=2018")
        .arg("--crate-name=anyhow_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile)
        .status()
        .ok()
}
<commit_msg>Redirect probe compile errors to /dev/null<commit_after>use std::env;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus, Stdio};

// This code exercises the surface area that we expect of the std Backtrace
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
    #![feature(backtrace)]
    #![allow(dead_code)]

    use std::backtrace::{Backtrace, BacktraceStatus};
    use std::error::Error;
    use std::fmt::{self, Display};

    #[derive(Debug)]
    struct E;

    impl Display for E {
        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
            unimplemented!()
        }
    }

    impl Error for E {
        fn backtrace(&self) -> Option<&Backtrace> {
            let backtrace = Backtrace::capture();
            match backtrace.status() {
                BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
            }
            unimplemented!()
        }
    }
"#;

fn main() {
    if !cfg!(feature = "std") {
        return;
    }
    match compile_probe() {
        Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
        _ => {}
    }
}

fn compile_probe() -> Option<ExitStatus> {
    let rustc = env::var_os("RUSTC")?;
    let out_dir = env::var_os("OUT_DIR")?;
    let probefile = Path::new(&out_dir).join("probe.rs");
    fs::write(&probefile, PROBE).ok()?;
    Command::new(rustc)
        .stderr(Stdio::null())
        .arg("--edition=2018")
        .arg("--crate-name=anyhow_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile)
        .status()
        .ok()
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str;

fn main() {
    let compiler = match rustc_version() {
        Some(compiler) => compiler,
        None => return,
    };

    if compiler.nightly {
        println!("cargo:rustc-cfg=backtrace");
    }
}

struct Compiler {
    nightly: bool,
}

fn rustc_version() -> Option<Compiler> {
    let rustc = match env::var_os("RUSTC") {
        Some(rustc) => rustc,
        None => return None,
    };

    let output = match Command::new(rustc).arg("--version").output() {
        Ok(output) => output,
        Err(_) => return None,
    };

    let version = match str::from_utf8(&output.stdout) {
        Ok(version) => version,
        Err(_) => return None,
    };

    Some(Compiler {
        nightly: version.contains("nightly") || version.contains("dev"),
    })
}
<commit_msg>Detect compiler minor version in build script<commit_after>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

fn main() {
    let compiler = match rustc_version() {
        Some(compiler) => compiler,
        None => return,
    };

    if compiler.minor >= 40 && compiler.nightly {
        println!("cargo:rustc-cfg=backtrace");
    }
}

struct Compiler {
    minor: u32,
    nightly: bool,
}

fn rustc_version() -> Option<Compiler> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;

    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let next = pieces.next()?;
    let minor = u32::from_str(next).ok()?;
    let nightly = version.contains("nightly") || version.contains("dev");
    Some(Compiler { minor, nightly })
}
<|endoftext|>