<commit_before>#![cfg(feature = "mturk")]

extern crate rusoto_core;
extern crate rusoto_mturk;

use rusoto_core::Region;
use rusoto_mturk::{MechanicalTurkClient, MechanicalTurk, ListHITsRequest};

#[test]
fn should_list_hits() {
    let client = MechanicalTurkClient::new(Region::UsEast1);
    let request = ListHITsRequest::default();

    // If your AWS account isn't linked to a Mechanical Turk account, AWS returns an error
    match client.list_hi_ts(request).sync() {
        Err(e) => assert!(format!("{}", e).contains("Your AWS account must be linked to your Amazon Mechanical Turk Account")),
        Ok(_) => (),
    }
}<commit_msg>Fix mturk integration test.<commit_after>#![cfg(feature = "mturk")]

extern crate rusoto_core;
extern crate rusoto_mturk;

use rusoto_core::Region;
use rusoto_mturk::{MechanicalTurkClient, MechanicalTurk, ListHITsRequest, ListHITsError};

use std::str;

#[test]
fn should_list_hits() {
    let client = MechanicalTurkClient::new(Region::UsEast1);
    let request = ListHITsRequest::default();

    // If your AWS account isn't linked to a Mechanical Turk account, AWS returns an error
    match client.list_hi_ts(request).sync() {
        Err(e) => {
            match e {
                ListHITsError::Unknown(ref e) => assert!(str::from_utf8(&e.body).unwrap().contains("Your AWS account must be linked to your Amazon Mechanical Turk Account"), "Missing error message"),
                ListHITsError::RequestError(_) => (), // request doesn't work without a linked mturk account, this is ok
                _ => panic!("Should have a typed error from MTurk, got {:?}", e),
            }
        },
        Ok(_) => (),
    }
}<|endoftext|>


<commit_before>//! Representations of C types and arrays thereof.
//!
//! These are used to describe the types of the arguments and results of
//! functions. When we construct a CIF (“Call InterFace”), we provide a
//! sequence of argument types and a result type, and libffi uses this
//! to figure out how to set up a call to a function with those types.

use std::fmt;
use std::mem;
use std::ptr::{Unique, self};
use libc;

use low;

// Internally we represent types and type arrays using raw pointers,
// since this is what libffi understands. Below we wrap them with
// types that implement Drop and Clone.

type Type_      = *mut low::ffi_type;
type TypeArray_ = *mut Type_;

// Informal indication that the object should be considered owned by
// the given reference.
type Owned<T>      = T;

/// Represents a single C type.
///
/// # Example
///
/// Suppose we have a C struct:
///
/// ```c
/// struct my_struct {
///     uint16_t f1;
///     uint64_t f2;
/// };
/// ```
///
/// To pass the struct by value via libffi, we need to construct a
/// `Type` object describing its layout:
///
/// ```
/// use libffi::middle::Type;
///
/// let my_struct = Type::structure(vec![
///     Type::u64(),
///     Type::u16(),
/// ].into_iter());
/// ```
pub struct Type(Unique<low::ffi_type>);

/// Represents a sequence of C types.
///
/// This can be used to construct a struct type or as the arguments
/// when creating a [`Cif`](../middle/struct.Cif.html).
pub struct TypeArray(Unique<*mut low::ffi_type>);

impl fmt::Debug for Type {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("Type({:?})", *self.0))
    }
}

impl fmt::Debug for TypeArray {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("TypeArray({:?})", *self.0))
    }
}

/// Computes the length of a raw `TypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: TypeArray_) -> usize {
    let mut count   = 0;
    while !(*array).is_null() {
        count += 1;
        array = array.offset(1);
    }
    count
}

/// Creates an empty `TypeArray_` with null terminator.
unsafe fn ffi_type_array_create_empty(len: usize) -> Owned<TypeArray_> {
    let array = libc::malloc((len + 1) * mem::size_of::<Type_>())
                    as TypeArray_;
    assert!(!array.is_null(),
            "ffi_type_array_create_empty: out of memory");
    *array.offset(len as isize) = ptr::null::<low::ffi_type>() as Type_;
    array
}

/// Creates a null-terminated array of Type_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create<I>(elements: I) -> Owned<TypeArray_>
    where I: ExactSizeIterator<Item=Type>
{
    let size = elements.len();
    let new  = ffi_type_array_create_empty(size);
    for (i, element) in elements.enumerate() {
        *new.offset(i as isize) = *element.0;
    }

    new
}

/// Creates a struct type from a raw array of element types.
unsafe fn ffi_type_struct_create_raw(elements: Owned<TypeArray_>)
    -> Owned<Type_>
{
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as Type_;
    assert!(!new.is_null(),
            "ffi_type_struct_create_raw: out of memory");

    (*new).size      = 0;
    (*new).alignment = 0;
    (*new).type_     = low::type_tag::STRUCT;
    (*new).elements  = elements;

    new
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create<I>(elements: I) -> Owned<Type_>
    where I: ExactSizeIterator<Item=Type>
{
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

/// Makes a copy of a type array.
unsafe fn ffi_type_array_clone(old: TypeArray_) -> Owned<TypeArray_> {
    let size = ffi_type_array_len(old);
    let new  = ffi_type_array_create_empty(size);

    for i in 0 .. size {
        *new.offset(i as isize) = ffi_type_clone(*old.offset(i as isize));
    }

    new
}

/// Makes a copy of a type.
unsafe fn ffi_type_clone(old: Type_) -> Owned<Type_> {
    if (*old).type_ == low::type_tag::STRUCT {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys a TypeArray_ and all of its elements.
unsafe fn ffi_type_array_destroy(victim: Owned<TypeArray_>) {
    let mut current = victim;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(victim as *mut libc::c_void);
}

/// Destroys a Type_ if it was dynamically allocated.
unsafe fn ffi_type_destroy(victim: Owned<Type_>) {
    if (*victim).type_ == low::type_tag::STRUCT {
        ffi_type_array_destroy((*victim).elements);
        libc::free(victim as *mut libc::c_void);
    }
}

impl Drop for Type {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(self.0.get_mut()) }
    }
}

impl Drop for TypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(self.0.get_mut()) }
    }
}

impl Clone for Type {
    fn clone(&self) -> Self {
        unsafe { Type(Unique::new(ffi_type_clone(*self.0))) }
    }
}

impl Clone for TypeArray {
    fn clone(&self) -> Self {
        unsafe {
            TypeArray(Unique::new(ffi_type_array_clone(*self.0)))
        }
    }
}

impl Type {
    /// Returns the representation of the C `void` type.
    ///
    /// This is used only for the return type of a CIF, not for an
    /// argument or struct member.
    pub fn void() -> Self {
        Type(unsafe { Unique::new(&mut low::types::void) })
    }

    /// Returns the unsigned 8-bit numeric type.
    pub fn u8() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint8) })
    }

    /// Returns the signed 8-bit numeric type.
    pub fn i8() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint8) })
    }

    /// Returns the unsigned 16-bit numeric type.
    pub fn u16() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint16) })
    }

    /// Returns the signed 16-bit numeric type.
    pub fn i16() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint16) })
    }

    /// Returns the unsigned 32-bit numeric type.
    pub fn u32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint32) })
    }

    /// Returns the signed 32-bit numeric type.
    pub fn i32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint32) })
    }

    /// Returns the unsigned 64-bit numeric type.
    pub fn u64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint64) })
    }

    /// Returns the signed 64-bit numeric type.
    pub fn i64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint64) })
    }

    /// Returns the C equivalent of Rust `usize` (`u16`).
    #[cfg(target_pointer_width = "16")]
    pub fn usize() -> Self {
        Self::u16()
    }

    /// Returns the C equivalent of Rust `isize` (`i16`).
    #[cfg(target_pointer_width = "16")]
    pub fn isize() -> Self {
        Self::i16()
    }

    /// Returns the C equivalent of Rust `usize` (`u32`).
    #[cfg(target_pointer_width = "32")]
    pub fn usize() -> Self {
        Self::u32()
    }

    /// Returns the C equivalent of Rust `isize` (`i32`).
    #[cfg(target_pointer_width = "32")]
    pub fn isize() -> Self {
        Self::i32()
    }

    /// Returns the C equivalent of Rust `usize` (`u64`).
    #[cfg(target_pointer_width = "64")]
    pub fn usize() -> Self {
        Self::u64()
    }

    /// Returns the C equivalent of Rust `isize` (`i64`).
    #[cfg(target_pointer_width = "64")]
    pub fn isize() -> Self {
        Self::i64()
    }

    /// Returns the C `float` (32-bit floating point) type.
    pub fn f32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::float) })
    }

    /// Returns the C `double` (64-bit floating point) type.
    pub fn f64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::double) })
    }

    /// Returns the C `void*` type, for passing any kind of pointer.
    pub fn pointer() -> Self {
        Type(unsafe { Unique::new(&mut low::types::pointer) })
    }

    /// Returns the C `long double` (extended-precision floating point) type.
    pub fn longdouble() -> Self {
        Type(unsafe { Unique::new(&mut low::types::longdouble) })
    }

    /// Returns the C `_Complex float` type.
    pub fn c32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_float) })
    }

    /// Returns the C `_Complex double` type.
    pub fn c64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_double) })
    }

    /// Returns the C `_Complex long double` type.
    pub fn complex_longdouble() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_longdouble) })
    }

    /// Constructs a structure type whose fields have the given types.
    pub fn structure<I>(fields: I) -> Self
        where I: ExactSizeIterator<Item=Type>
    {
        unsafe {
            Type(Unique::new(ffi_type_struct_create(fields)))
        }
    }

    /// Constructs a structure type whose fields have the given types.
    pub fn structure_from_array(fields: TypeArray) -> Self {
        unsafe {
            Type(Unique::new(ffi_type_struct_create_raw(*fields.0)))
        }
    }

    /// Gets a raw pointer to the underlying
    /// [`ffi_type`](../../low/struct.ffi_type.html).
    ///
    /// This method may be useful for interacting with the
    /// [`low`](../../low/index.html) and
    /// [`raw`](../../raw/index.html) layers.
    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        *self.0
    }
}

impl TypeArray {
    /// Constructs an array the given `Type`s.
    pub fn new<I>(elements: I) -> Self
        where I: ExactSizeIterator<Item=Type>
    {
        unsafe { TypeArray(Unique::new(ffi_type_array_create(elements))) }
    }

    /// The length of this array of `Type`s.
    pub fn len(&self) -> usize {
        unsafe { ffi_type_array_len(*self.0) }
    }

    /// Gets a raw pointer to the underlying C array of
    /// [`ffi_type`](../../low/struct.ffi_type.html)s.
    ///
    /// The C array is null-terminated.
    ///
    /// This method may be useful for interacting with the
    /// [`low`](../../low/index.html) and
    /// [`raw`](../../raw/index.html) layers.
    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        *self.0
    }
}

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

    #[test]
    fn create_u64() {
        Type::u64();
    }

    #[test]
    fn clone_u64() {
        Type::u64().clone().clone();
    }

    #[test]
    fn create_struct() {
        Type::structure(vec![Type::i64(),
                             Type::i64(),
                             Type::u64()].into_iter());
    }

    #[test]
    fn clone_struct() {
        Type::structure(vec![Type::i64(),
                             Type::i64(),
                             Type::u64()].into_iter()).clone().clone();
    }

}
<commit_msg>Added middle layer support of native C types int, unsigned, short, etc.<commit_after>//! Representations of C types and arrays thereof.
//!
//! These are used to describe the types of the arguments and results of
//! functions. When we construct a CIF (“Call InterFace”), we provide a
//! sequence of argument types and a result type, and libffi uses this
//! to figure out how to set up a call to a function with those types.

use std::fmt;
use std::mem;
use std::ptr::{Unique, self};
use libc;

use low;

// Internally we represent types and type arrays using raw pointers,
// since this is what libffi understands. Below we wrap them with
// types that implement Drop and Clone.

type Type_      = *mut low::ffi_type;
type TypeArray_ = *mut Type_;

// Informal indication that the object should be considered owned by
// the given reference.
type Owned<T>      = T;

/// Represents a single C type.
///
/// # Example
///
/// Suppose we have a C struct:
///
/// ```c
/// struct my_struct {
///     uint16_t f1;
///     uint64_t f2;
/// };
/// ```
///
/// To pass the struct by value via libffi, we need to construct a
/// `Type` object describing its layout:
///
/// ```
/// use libffi::middle::Type;
///
/// let my_struct = Type::structure(vec![
///     Type::u64(),
///     Type::u16(),
/// ].into_iter());
/// ```
pub struct Type(Unique<low::ffi_type>);

/// Represents a sequence of C types.
///
/// This can be used to construct a struct type or as the arguments
/// when creating a [`Cif`](../middle/struct.Cif.html).
pub struct TypeArray(Unique<*mut low::ffi_type>);

impl fmt::Debug for Type {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("Type({:?})", *self.0))
    }
}

impl fmt::Debug for TypeArray {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_fmt(format_args!("TypeArray({:?})", *self.0))
    }
}

/// Computes the length of a raw `TypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: TypeArray_) -> usize {
    let mut count   = 0;
    while !(*array).is_null() {
        count += 1;
        array = array.offset(1);
    }
    count
}

/// Creates an empty `TypeArray_` with null terminator.
unsafe fn ffi_type_array_create_empty(len: usize) -> Owned<TypeArray_> {
    let array = libc::malloc((len + 1) * mem::size_of::<Type_>())
                    as TypeArray_;
    assert!(!array.is_null(),
            "ffi_type_array_create_empty: out of memory");
    *array.offset(len as isize) = ptr::null::<low::ffi_type>() as Type_;
    array
}

/// Creates a null-terminated array of Type_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create<I>(elements: I) -> Owned<TypeArray_>
    where I: ExactSizeIterator<Item=Type>
{
    let size = elements.len();
    let new  = ffi_type_array_create_empty(size);
    for (i, element) in elements.enumerate() {
        *new.offset(i as isize) = *element.0;
    }

    new
}

/// Creates a struct type from a raw array of element types.
unsafe fn ffi_type_struct_create_raw(elements: Owned<TypeArray_>)
    -> Owned<Type_>
{
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as Type_;
    assert!(!new.is_null(),
            "ffi_type_struct_create_raw: out of memory");

    (*new).size      = 0;
    (*new).alignment = 0;
    (*new).type_     = low::type_tag::STRUCT;
    (*new).elements  = elements;

    new
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create<I>(elements: I) -> Owned<Type_>
    where I: ExactSizeIterator<Item=Type>
{
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

/// Makes a copy of a type array.
unsafe fn ffi_type_array_clone(old: TypeArray_) -> Owned<TypeArray_> {
    let size = ffi_type_array_len(old);
    let new  = ffi_type_array_create_empty(size);

    for i in 0 .. size {
        *new.offset(i as isize) = ffi_type_clone(*old.offset(i as isize));
    }

    new
}

/// Makes a copy of a type.
unsafe fn ffi_type_clone(old: Type_) -> Owned<Type_> {
    if (*old).type_ == low::type_tag::STRUCT {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys a TypeArray_ and all of its elements.
unsafe fn ffi_type_array_destroy(victim: Owned<TypeArray_>) {
    let mut current = victim;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(victim as *mut libc::c_void);
}

/// Destroys a Type_ if it was dynamically allocated.
unsafe fn ffi_type_destroy(victim: Owned<Type_>) {
    if (*victim).type_ == low::type_tag::STRUCT {
        ffi_type_array_destroy((*victim).elements);
        libc::free(victim as *mut libc::c_void);
    }
}

impl Drop for Type {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(self.0.get_mut()) }
    }
}

impl Drop for TypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(self.0.get_mut()) }
    }
}

impl Clone for Type {
    fn clone(&self) -> Self {
        unsafe { Type(Unique::new(ffi_type_clone(*self.0))) }
    }
}

impl Clone for TypeArray {
    fn clone(&self) -> Self {
        unsafe {
            TypeArray(Unique::new(ffi_type_array_clone(*self.0)))
        }
    }
}

macro_rules! match_size_signed {
    ( $name:ident ) => {
        match mem::size_of::<libc::$name>() {
            1 => Self::i8(),
            2 => Self::i16(),
            4 => Self::i32(),
            8 => Self::i64(),
            _  => panic!("Strange size for C type"),
        }
    }
}

macro_rules! match_size_unsigned {
    ( $name:ident ) => {
        match mem::size_of::<libc::$name>() {
            1 => Self::u8(),
            2 => Self::u16(),
            4 => Self::u32(),
            8 => Self::u64(),
            _  => panic!("Strange size for C type"),
        }
    }
}

impl Type {
    /// Returns the representation of the C `void` type.
    ///
    /// This is used only for the return type of a CIF, not for an
    /// argument or struct member.
    pub fn void() -> Self {
        Type(unsafe { Unique::new(&mut low::types::void) })
    }

    /// Returns the unsigned 8-bit numeric type.
    pub fn u8() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint8) })
    }

    /// Returns the signed 8-bit numeric type.
    pub fn i8() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint8) })
    }

    /// Returns the unsigned 16-bit numeric type.
    pub fn u16() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint16) })
    }

    /// Returns the signed 16-bit numeric type.
    pub fn i16() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint16) })
    }

    /// Returns the unsigned 32-bit numeric type.
    pub fn u32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint32) })
    }

    /// Returns the signed 32-bit numeric type.
    pub fn i32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint32) })
    }

    /// Returns the unsigned 64-bit numeric type.
    pub fn u64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::uint64) })
    }

    /// Returns the signed 64-bit numeric type.
    pub fn i64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::sint64) })
    }

    /// Returns the C equivalent of Rust `usize` (`u16`).
    #[cfg(target_pointer_width = "16")]
    pub fn usize() -> Self {
        Self::u16()
    }

    /// Returns the C equivalent of Rust `isize` (`i16`).
    #[cfg(target_pointer_width = "16")]
    pub fn isize() -> Self {
        Self::i16()
    }

    /// Returns the C equivalent of Rust `usize` (`u32`).
    #[cfg(target_pointer_width = "32")]
    pub fn usize() -> Self {
        Self::u32()
    }

    /// Returns the C equivalent of Rust `isize` (`i32`).
    #[cfg(target_pointer_width = "32")]
    pub fn isize() -> Self {
        Self::i32()
    }

    /// Returns the C equivalent of Rust `usize` (`u64`).
    #[cfg(target_pointer_width = "64")]
    pub fn usize() -> Self {
        Self::u64()
    }

    /// Returns the C equivalent of Rust `isize` (`i64`).
    #[cfg(target_pointer_width = "64")]
    pub fn isize() -> Self {
        Self::i64()
    }

    /// Returns the C `signed char` type.
    pub fn c_schar() -> Self {
        match_size_signed!(c_schar)
    }

    /// Returns the C `unsigned char` type.
    pub fn c_uchar() -> Self {
        match_size_unsigned!(c_uchar)
    }

    /// Returns the C `short` type.
    pub fn c_short() -> Self {
        match_size_signed!(c_short)
    }

    /// Returns the C `unsigned short` type.
    pub fn c_ushort() -> Self {
        match_size_unsigned!(c_ushort)
    }

    /// Returns the C `int` type.
    pub fn c_int() -> Self {
        match_size_signed!(c_int)
    }

    /// Returns the C `unsigned int` type.
    pub fn c_uint() -> Self {
        match_size_unsigned!(c_uint)
    }

    /// Returns the C `long` type.
    pub fn c_long() -> Self {
        match_size_signed!(c_long)
    }

    /// Returns the C `unsigned long` type.
    pub fn c_ulong() -> Self {
        match_size_unsigned!(c_ulong)
    }

    /// Returns the C `longlong` type.
    pub fn c_longlong() -> Self {
        match_size_signed!(c_longlong)
    }

    /// Returns the C `unsigned longlong` type.
    pub fn c_ulonglong() -> Self {
        match_size_unsigned!(c_ulonglong)
    }

    /// Returns the C `float` (32-bit floating point) type.
    pub fn f32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::float) })
    }

    /// Returns the C `double` (64-bit floating point) type.
    pub fn f64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::double) })
    }

    /// Returns the C `void*` type, for passing any kind of pointer.
    pub fn pointer() -> Self {
        Type(unsafe { Unique::new(&mut low::types::pointer) })
    }

    /// Returns the C `long double` (extended-precision floating point) type.
    pub fn longdouble() -> Self {
        Type(unsafe { Unique::new(&mut low::types::longdouble) })
    }

    /// Returns the C `_Complex float` type.
    pub fn c32() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_float) })
    }

    /// Returns the C `_Complex double` type.
    pub fn c64() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_double) })
    }

    /// Returns the C `_Complex long double` type.
    pub fn complex_longdouble() -> Self {
        Type(unsafe { Unique::new(&mut low::types::complex_longdouble) })
    }

    /// Constructs a structure type whose fields have the given types.
    pub fn structure<I>(fields: I) -> Self
        where I: ExactSizeIterator<Item=Type>
    {
        unsafe {
            Type(Unique::new(ffi_type_struct_create(fields)))
        }
    }

    /// Constructs a structure type whose fields have the given types.
    pub fn structure_from_array(fields: TypeArray) -> Self {
        unsafe {
            Type(Unique::new(ffi_type_struct_create_raw(*fields.0)))
        }
    }

    /// Gets a raw pointer to the underlying
    /// [`ffi_type`](../../low/struct.ffi_type.html).
    ///
    /// This method may be useful for interacting with the
    /// [`low`](../../low/index.html) and
    /// [`raw`](../../raw/index.html) layers.
    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        *self.0
    }
}

impl TypeArray {
    /// Constructs an array the given `Type`s.
    pub fn new<I>(elements: I) -> Self
        where I: ExactSizeIterator<Item=Type>
    {
        unsafe { TypeArray(Unique::new(ffi_type_array_create(elements))) }
    }

    /// The length of this array of `Type`s.
    pub fn len(&self) -> usize {
        unsafe { ffi_type_array_len(*self.0) }
    }

    /// Gets a raw pointer to the underlying C array of
    /// [`ffi_type`](../../low/struct.ffi_type.html)s.
    ///
    /// The C array is null-terminated.
    ///
    /// This method may be useful for interacting with the
    /// [`low`](../../low/index.html) and
    /// [`raw`](../../raw/index.html) layers.
    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        *self.0
    }
}

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

    #[test]
    fn create_u64() {
        Type::u64();
    }

    #[test]
    fn clone_u64() {
        Type::u64().clone().clone();
    }

    #[test]
    fn create_struct() {
        Type::structure(vec![Type::i64(),
                             Type::i64(),
                             Type::u64()].into_iter());
    }

    #[test]
    fn clone_struct() {
        Type::structure(vec![Type::i64(),
                             Type::i64(),
                             Type::u64()].into_iter()).clone().clone();
    }

}
<|endoftext|>


<commit_before>use crate::{transform::MirPass, util::patch::MirPatch};
use rustc_middle::mir::*;
use rustc_middle::ty::{Ty, TyCtxt};
use std::{borrow::Cow, fmt::Debug};

use super::simplify::simplify_cfg;

/// This pass optimizes something like
/// ```text
/// let x: Option<()>;
/// let y: Option<()>;
/// match (x,y) {
///     (Some(_), Some(_)) => {0},
///     _ => {1}
/// }
/// ```
/// into something like
/// ```text
/// let x: Option<()>;
/// let y: Option<()>;
/// let discriminant_x = // get discriminant of x
/// let discriminant_y = // get discriminant of y
/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0}
/// ```
pub struct EarlyOtherwiseBranch;

impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        if tcx.sess.opts.debugging_opts.mir_opt_level < 1 {
            return;
        }
        trace!("running EarlyOtherwiseBranch on {:?}", body.source);
        // we are only interested in this bb if the terminator is a switchInt
        let bbs_with_switch =
            body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));

        let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch
            .flat_map(|(bb_idx, bb)| {
                let switch = bb.terminator();
                let helper = Helper { body, tcx };
                let infos = helper.go(bb, switch)?;
                Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx })
            })
            .collect();

        let should_cleanup = !opts_to_apply.is_empty();

        for opt_to_apply in opts_to_apply {
            trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply);

            let statements_before =
                body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len();
            let end_of_block_location = Location {
                block: opt_to_apply.basic_block_first_switch,
                statement_index: statements_before,
            };

            let mut patch = MirPatch::new(body);

            // create temp to store second discriminant in
            let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty;
            let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span;
            let second_discriminant_temp = patch.new_temp(discr_type, discr_span);

            patch.add_statement(
                end_of_block_location,
                StatementKind::StorageLive(second_discriminant_temp),
            );

            // create assignment of discriminant
            let place_of_adt_to_get_discriminant_of =
                opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read;
            patch.add_assign(
                end_of_block_location,
                Place::from(second_discriminant_temp),
                Rvalue::Discriminant(place_of_adt_to_get_discriminant_of),
            );

            // create temp to store NotEqual comparison between the two discriminants
            let not_equal = BinOp::Ne;
            let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type);
            let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span);
            patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp));

            // create NotEqual comparison between the two discriminants
            let first_descriminant_place =
                opt_to_apply.infos[0].first_switch_info.discr_used_in_switch;
            let not_equal_rvalue = Rvalue::BinaryOp(
                not_equal,
                Operand::Copy(Place::from(second_discriminant_temp)),
                Operand::Copy(first_descriminant_place),
            );
            patch.add_statement(
                end_of_block_location,
                StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)),
            );

            let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply
                .infos
                .iter()
                .flat_map(|x| x.second_switch_info.targets_with_values.iter())
                .cloned()
                .unzip();

            // add otherwise case in the end
            targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb);
            // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
            let new_switch_data = BasicBlockData::new(Some(Terminator {
                source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
                kind: TerminatorKind::SwitchInt {
                    // the first and second discriminants are equal, so just pick one
                    discr: Operand::Copy(first_descriminant_place),
                    switch_ty: discr_type,
                    values: Cow::from(values_to_jump_to),
                    targets: targets_to_jump_to,
                },
            }));

            let new_switch_bb = patch.new_block(new_switch_data);

            // switch on the NotEqual. If true, then jump to the `otherwise` case.
            // If false, then jump to a basic block that then jumps to the correct disciminant case
            let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb;
            let false_case = new_switch_bb;
            patch.patch_terminator(
                opt_to_apply.basic_block_first_switch,
                TerminatorKind::if_(
                    tcx,
                    Operand::Move(Place::from(not_equal_temp)),
                    true_case,
                    false_case,
                ),
            );

            // generate StorageDead for the second_discriminant_temp not in use anymore
            patch.add_statement(
                end_of_block_location,
                StatementKind::StorageDead(second_discriminant_temp),
            );

            // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch
            for bb in [false_case, true_case].iter() {
                patch.add_statement(
                    Location { block: *bb, statement_index: 0 },
                    StatementKind::StorageDead(not_equal_temp),
                );
            }

            patch.apply(body);
        }

        // Since this optimization adds new basic blocks and invalidates others,
        // clean up the cfg to make it nicer for other passes
        if should_cleanup {
            simplify_cfg(body);
        }
    }
}

fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool {
    match terminator.kind {
        TerminatorKind::SwitchInt { .. } => true,
        _ => false,
    }
}

struct Helper<'a, 'tcx> {
    body: &'a Body<'tcx>,
    tcx: TyCtxt<'tcx>,
}

#[derive(Debug, Clone)]
struct SwitchDiscriminantInfo<'tcx> {
    /// Type of the discriminant being switched on
    discr_ty: Ty<'tcx>,
    /// The basic block that the otherwise branch points to
    otherwise_bb: BasicBlock,
    /// Target along with the value being branched from. Otherwise is not included
    targets_with_values: Vec<(BasicBlock, u128)>,
    discr_source_info: SourceInfo,
    /// The place of the discriminant used in the switch
    discr_used_in_switch: Place<'tcx>,
    /// The place of the adt that has its discriminant read
    place_of_adt_discr_read: Place<'tcx>,
    /// The type of the adt that has its discriminant read
    type_adt_matched_on: Ty<'tcx>,
}

#[derive(Debug)]
struct OptimizationToApply<'tcx> {
    infos: Vec<OptimizationInfo<'tcx>>,
    /// Basic block of the original first switch
    basic_block_first_switch: BasicBlock,
}

#[derive(Debug)]
struct OptimizationInfo<'tcx> {
    /// Info about the first switch and discriminant
    first_switch_info: SwitchDiscriminantInfo<'tcx>,
    /// Info about the second switch and discriminant
    second_switch_info: SwitchDiscriminantInfo<'tcx>,
}

impl<'a, 'tcx> Helper<'a, 'tcx> {
    pub fn go(
        &self,
        bb: &BasicBlockData<'tcx>,
        switch: &Terminator<'tcx>,
    ) -> Option<Vec<OptimizationInfo<'tcx>>> {
        // try to find the statement that defines the discriminant that is used for the switch
        let discr = self.find_switch_discriminant_info(bb, switch)?;

        // go through each target, finding a discriminant read, and a switch
        let results = discr.targets_with_values.iter().map(|(target, value)| {
            self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone())
        });

        // if the optimization did not apply for one of the targets, then abort
        if results.clone().any(|x| x.is_none()) || results.len() == 0 {
            trace!("NO: not all of the targets matched the pattern for optimization");
            return None;
        }

        Some(results.flatten().collect())
    }

    fn find_discriminant_switch_pairing(
        &self,
        discr_info: &SwitchDiscriminantInfo<'tcx>,
        target: BasicBlock,
        value: u128,
    ) -> Option<OptimizationInfo<'tcx>> {
        let bb = &self.body.basic_blocks()[target];
        // find switch
        let terminator = bb.terminator();
        if is_switch(terminator) {
            let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?;

            // the types of the two adts matched on have to be equalfor this optimization to apply
            if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on {
                trace!(
                    "NO: types do not match. LHS: {:?}, RHS: {:?}",
                    discr_info.type_adt_matched_on,
                    this_bb_discr_info.type_adt_matched_on
                );
                return None;
            }

            // the otherwise branch of the two switches have to point to the same bb
            if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb {
                trace!("NO: otherwise target is not the same");
                return None;
            }

            // check that the value being matched on is the same. The
            if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() {
                trace!("NO: values being matched on are not the same");
                return None;
            }

            // only allow optimization if the left and right of the tuple being matched are the same variants.
            // so the following should not optimize
            //  ```rust
            // let x: Option<()>;
            // let y: Option<()>;
            // match (x,y) {
            //     (Some(_), None) => {},
            //     _ => {}
            // }
            //  ```
            // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
            if !(this_bb_discr_info.targets_with_values.len() == 1
                && this_bb_discr_info.targets_with_values[0].1 == value)
            {
                trace!(
                    "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
                );
                return None;
            }

            // if we reach this point, the optimization applies, and we should be able to optimize this case
            // store the info that is needed to apply the optimization

            Some(OptimizationInfo {
                first_switch_info: discr_info.clone(),
                second_switch_info: this_bb_discr_info,
            })
        } else {
            None
        }
    }

    fn find_switch_discriminant_info(
        &self,
        bb: &BasicBlockData<'tcx>,
        switch: &Terminator<'tcx>,
    ) -> Option<SwitchDiscriminantInfo<'tcx>> {
        match &switch.kind {
            TerminatorKind::SwitchInt { discr, targets, values, .. } => {
                let discr_local = discr.place()?.as_local()?;
                // the declaration of the discriminant read. Place of this read is being used in the switch
                let discr_decl = &self.body.local_decls()[discr_local];
                let discr_ty = discr_decl.ty;
                // the otherwise target lies as the last element
                let otherwise_bb = targets.get(values.len())?.clone();
                let targets_with_values = targets
                    .iter()
                    .zip(values.iter())
                    .map(|(t, v)| (t.clone(), v.clone()))
                    .collect();

                // find the place of the adt where the discriminant is being read from
                // assume this is the last statement of the block
                let place_of_adt_discr_read = match bb.statements.last()?.kind {
                    StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => {
                        Some(adt_place)
                    }
                    _ => None,
                }?;

                let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty;

                Some(SwitchDiscriminantInfo {
                    discr_used_in_switch: discr.place()?,
                    discr_ty,
                    otherwise_bb,
                    targets_with_values,
                    discr_source_info: discr_decl.source_info,
                    place_of_adt_discr_read,
                    type_adt_matched_on,
                })
            }
            _ => unreachable!("must only be passed terminator that is a switch"),
        }
    }
}
<commit_msg>Rollup merge of #77582 - ecstatic-morse:disable-early-otherwise-branch, r=wesleywiser<commit_after>use crate::{transform::MirPass, util::patch::MirPatch};
use rustc_middle::mir::*;
use rustc_middle::ty::{Ty, TyCtxt};
use std::{borrow::Cow, fmt::Debug};

use super::simplify::simplify_cfg;

/// This pass optimizes something like
/// ```text
/// let x: Option<()>;
/// let y: Option<()>;
/// match (x,y) {
///     (Some(_), Some(_)) => {0},
///     _ => {1}
/// }
/// ```
/// into something like
/// ```text
/// let x: Option<()>;
/// let y: Option<()>;
/// let discriminant_x = // get discriminant of x
/// let discriminant_y = // get discriminant of y
/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0}
/// ```
pub struct EarlyOtherwiseBranch;

impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
        if tcx.sess.opts.debugging_opts.mir_opt_level < 2 {
            return;
        }
        trace!("running EarlyOtherwiseBranch on {:?}", body.source);
        // we are only interested in this bb if the terminator is a switchInt
        let bbs_with_switch =
            body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));

        let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch
            .flat_map(|(bb_idx, bb)| {
                let switch = bb.terminator();
                let helper = Helper { body, tcx };
                let infos = helper.go(bb, switch)?;
                Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx })
            })
            .collect();

        let should_cleanup = !opts_to_apply.is_empty();

        for opt_to_apply in opts_to_apply {
            trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply);

            let statements_before =
                body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len();
            let end_of_block_location = Location {
                block: opt_to_apply.basic_block_first_switch,
                statement_index: statements_before,
            };

            let mut patch = MirPatch::new(body);

            // create temp to store second discriminant in
            let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty;
            let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span;
            let second_discriminant_temp = patch.new_temp(discr_type, discr_span);

            patch.add_statement(
                end_of_block_location,
                StatementKind::StorageLive(second_discriminant_temp),
            );

            // create assignment of discriminant
            let place_of_adt_to_get_discriminant_of =
                opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read;
            patch.add_assign(
                end_of_block_location,
                Place::from(second_discriminant_temp),
                Rvalue::Discriminant(place_of_adt_to_get_discriminant_of),
            );

            // create temp to store NotEqual comparison between the two discriminants
            let not_equal = BinOp::Ne;
            let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type);
            let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span);
            patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp));

            // create NotEqual comparison between the two discriminants
            let first_descriminant_place =
                opt_to_apply.infos[0].first_switch_info.discr_used_in_switch;
            let not_equal_rvalue = Rvalue::BinaryOp(
                not_equal,
                Operand::Copy(Place::from(second_discriminant_temp)),
                Operand::Copy(first_descriminant_place),
            );
            patch.add_statement(
                end_of_block_location,
                StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)),
            );

            let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply
                .infos
                .iter()
                .flat_map(|x| x.second_switch_info.targets_with_values.iter())
                .cloned()
                .unzip();

            // add otherwise case in the end
            targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb);
            // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
            let new_switch_data = BasicBlockData::new(Some(Terminator {
                source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
                kind: TerminatorKind::SwitchInt {
                    // the first and second discriminants are equal, so just pick one
                    discr: Operand::Copy(first_descriminant_place),
                    switch_ty: discr_type,
                    values: Cow::from(values_to_jump_to),
                    targets: targets_to_jump_to,
                },
            }));

            let new_switch_bb = patch.new_block(new_switch_data);

            // switch on the NotEqual. If true, then jump to the `otherwise` case.
            // If false, then jump to a basic block that then jumps to the correct disciminant case
            let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb;
            let false_case = new_switch_bb;
            patch.patch_terminator(
                opt_to_apply.basic_block_first_switch,
                TerminatorKind::if_(
                    tcx,
                    Operand::Move(Place::from(not_equal_temp)),
                    true_case,
                    false_case,
                ),
            );

            // generate StorageDead for the second_discriminant_temp not in use anymore
            patch.add_statement(
                end_of_block_location,
                StatementKind::StorageDead(second_discriminant_temp),
            );

            // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch
            for bb in [false_case, true_case].iter() {
                patch.add_statement(
                    Location { block: *bb, statement_index: 0 },
                    StatementKind::StorageDead(not_equal_temp),
                );
            }

            patch.apply(body);
        }

        // Since this optimization adds new basic blocks and invalidates others,
        // clean up the cfg to make it nicer for other passes
        if should_cleanup {
            simplify_cfg(body);
        }
    }
}

fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool {
    match terminator.kind {
        TerminatorKind::SwitchInt { .. } => true,
        _ => false,
    }
}

struct Helper<'a, 'tcx> {
    body: &'a Body<'tcx>,
    tcx: TyCtxt<'tcx>,
}

#[derive(Debug, Clone)]
struct SwitchDiscriminantInfo<'tcx> {
    /// Type of the discriminant being switched on
    discr_ty: Ty<'tcx>,
    /// The basic block that the otherwise branch points to
    otherwise_bb: BasicBlock,
    /// Target along with the value being branched from. Otherwise is not included
    targets_with_values: Vec<(BasicBlock, u128)>,
    discr_source_info: SourceInfo,
    /// The place of the discriminant used in the switch
    discr_used_in_switch: Place<'tcx>,
    /// The place of the adt that has its discriminant read
    place_of_adt_discr_read: Place<'tcx>,
    /// The type of the adt that has its discriminant read
    type_adt_matched_on: Ty<'tcx>,
}

#[derive(Debug)]
struct OptimizationToApply<'tcx> {
    infos: Vec<OptimizationInfo<'tcx>>,
    /// Basic block of the original first switch
    basic_block_first_switch: BasicBlock,
}

#[derive(Debug)]
struct OptimizationInfo<'tcx> {
    /// Info about the first switch and discriminant
    first_switch_info: SwitchDiscriminantInfo<'tcx>,
    /// Info about the second switch and discriminant
    second_switch_info: SwitchDiscriminantInfo<'tcx>,
}

impl<'a, 'tcx> Helper<'a, 'tcx> {
    pub fn go(
        &self,
        bb: &BasicBlockData<'tcx>,
        switch: &Terminator<'tcx>,
    ) -> Option<Vec<OptimizationInfo<'tcx>>> {
        // try to find the statement that defines the discriminant that is used for the switch
        let discr = self.find_switch_discriminant_info(bb, switch)?;

        // go through each target, finding a discriminant read, and a switch
        let results = discr.targets_with_values.iter().map(|(target, value)| {
            self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone())
        });

        // if the optimization did not apply for one of the targets, then abort
        if results.clone().any(|x| x.is_none()) || results.len() == 0 {
            trace!("NO: not all of the targets matched the pattern for optimization");
            return None;
        }

        Some(results.flatten().collect())
    }

    fn find_discriminant_switch_pairing(
        &self,
        discr_info: &SwitchDiscriminantInfo<'tcx>,
        target: BasicBlock,
        value: u128,
    ) -> Option<OptimizationInfo<'tcx>> {
        let bb = &self.body.basic_blocks()[target];
        // find switch
        let terminator = bb.terminator();
        if is_switch(terminator) {
            let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?;

            // the types of the two adts matched on have to be equalfor this optimization to apply
            if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on {
                trace!(
                    "NO: types do not match. LHS: {:?}, RHS: {:?}",
                    discr_info.type_adt_matched_on,
                    this_bb_discr_info.type_adt_matched_on
                );
                return None;
            }

            // the otherwise branch of the two switches have to point to the same bb
            if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb {
                trace!("NO: otherwise target is not the same");
                return None;
            }

            // check that the value being matched on is the same. The
            if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() {
                trace!("NO: values being matched on are not the same");
                return None;
            }

            // only allow optimization if the left and right of the tuple being matched are the same variants.
            // so the following should not optimize
            //  ```rust
            // let x: Option<()>;
            // let y: Option<()>;
            // match (x,y) {
            //     (Some(_), None) => {},
            //     _ => {}
            // }
            //  ```
            // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
            if !(this_bb_discr_info.targets_with_values.len() == 1
                && this_bb_discr_info.targets_with_values[0].1 == value)
            {
                trace!(
                    "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
                );
                return None;
            }

            // if we reach this point, the optimization applies, and we should be able to optimize this case
            // store the info that is needed to apply the optimization

            Some(OptimizationInfo {
                first_switch_info: discr_info.clone(),
                second_switch_info: this_bb_discr_info,
            })
        } else {
            None
        }
    }

    fn find_switch_discriminant_info(
        &self,
        bb: &BasicBlockData<'tcx>,
        switch: &Terminator<'tcx>,
    ) -> Option<SwitchDiscriminantInfo<'tcx>> {
        match &switch.kind {
            TerminatorKind::SwitchInt { discr, targets, values, .. } => {
                let discr_local = discr.place()?.as_local()?;
                // the declaration of the discriminant read. Place of this read is being used in the switch
                let discr_decl = &self.body.local_decls()[discr_local];
                let discr_ty = discr_decl.ty;
                // the otherwise target lies as the last element
                let otherwise_bb = targets.get(values.len())?.clone();
                let targets_with_values = targets
                    .iter()
                    .zip(values.iter())
                    .map(|(t, v)| (t.clone(), v.clone()))
                    .collect();

                // find the place of the adt where the discriminant is being read from
                // assume this is the last statement of the block
                let place_of_adt_discr_read = match bb.statements.last()?.kind {
                    StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => {
                        Some(adt_place)
                    }
                    _ => None,
                }?;

                let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty;

                Some(SwitchDiscriminantInfo {
                    discr_used_in_switch: discr.place()?,
                    discr_ty,
                    otherwise_bb,
                    targets_with_values,
                    discr_source_info: discr_decl.source_info,
                    place_of_adt_discr_read,
                    type_adt_matched_on,
                })
            }
            _ => unreachable!("must only be passed terminator that is a switch"),
        }
    }
}
<|endoftext|>


<commit_before>//! CSS font properties.

use cssparser::Parser;

use crate::drawing_ctx::ViewParams;
use crate::error::*;
use crate::length::*;
use crate::parsers::Parse;
use crate::properties::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(Length<Both>),
}

impl FontSizeSpec {
    pub fn value(&self) -> Length<Both> {
        match self {
            FontSizeSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let size = v.font_size.0.value();

        let new_size = match self {
            FontSizeSpec::Smaller => Length::<Both>::new(size.length / 1.2, size.unit),
            FontSizeSpec::Larger => Length::<Both>::new(size.length * 1.2, size.unit),
            FontSizeSpec::XXSmall => Length::<Both>::new(compute_points(-3.0), LengthUnit::In),
            FontSizeSpec::XSmall => Length::<Both>::new(compute_points(-2.0), LengthUnit::In),
            FontSizeSpec::Small => Length::<Both>::new(compute_points(-1.0), LengthUnit::In),
            FontSizeSpec::Medium => Length::<Both>::new(compute_points(0.0), LengthUnit::In),
            FontSizeSpec::Large => Length::<Both>::new(compute_points(1.0), LengthUnit::In),
            FontSizeSpec::XLarge => Length::<Both>::new(compute_points(2.0), LengthUnit::In),
            FontSizeSpec::XXLarge => Length::<Both>::new(compute_points(3.0), LengthUnit::In),
            FontSizeSpec::Value(s) if s.unit == LengthUnit::Percent => {
                Length::<Both>::new(size.length * s.length, size.unit)
            }
            FontSizeSpec::Value(s) => *s,
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for FontSizeSpec {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<FontSizeSpec, ParseError<'i>> {
        parser
            .try_parse(|p| Length::<Both>::parse(p))
            .and_then(|l| Ok(FontSizeSpec::Value(l)))
            .or_else(|_| {
                Ok(parse_identifiers!(
                    parser,
                    "smaller" => FontSizeSpec::Smaller,
                    "larger" => FontSizeSpec::Larger,
                    "xx-small" => FontSizeSpec::XXSmall,
                    "x-small" => FontSizeSpec::XSmall,
                    "small" => FontSizeSpec::Small,
                    "medium" => FontSizeSpec::Medium,
                    "large" => FontSizeSpec::Large,
                    "x-large" => FontSizeSpec::XLarge,
                    "xx-large" => FontSizeSpec::XXLarge,
                )?)
            })
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<FontWeightSpec, ParseError<'i>> {
        parser
            .try_parse(|p| {
                Ok(parse_identifiers!(
                    p,
                    "normal" => FontWeightSpec::Normal,
                    "bold" => FontWeightSpec::Bold,
                    "bolder" => FontWeightSpec::Bolder,
                    "lighter" => FontWeightSpec::Lighter,
                )?)
            })
            .or_else(|_: ParseError| {
                let loc = parser.current_source_location();
                let i = parser.expect_integer()?;
                match i {
                    100 => Ok(FontWeightSpec::W100),
                    200 => Ok(FontWeightSpec::W200),
                    300 => Ok(FontWeightSpec::W300),
                    400 => Ok(FontWeightSpec::W400),
                    500 => Ok(FontWeightSpec::W500),
                    600 => Ok(FontWeightSpec::W600),
                    700 => Ok(FontWeightSpec::W700),
                    800 => Ok(FontWeightSpec::W800),
                    900 => Ok(FontWeightSpec::W900),
                    _ => Err(loc.new_custom_error(ValueErrorKind::parse_error("parse error"))),
                }
            })
    }
}

// https://www.w3.org/TR/css-text-3/#letter-spacing-property
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LetterSpacingSpec {
    Normal,
    Value(Length<Horizontal>),
}

impl LetterSpacingSpec {
    pub fn value(&self) -> Length<Horizontal> {
        match self {
            LetterSpacingSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self) -> Self {
        let spacing = match self {
            LetterSpacingSpec::Normal => Length::<Horizontal>::new(0.0, LengthUnit::Px),
            LetterSpacingSpec::Value(s) => *s,
        };

        LetterSpacingSpec::Value(spacing)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for LetterSpacingSpec {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<LetterSpacingSpec, ParseError<'i>> {
        parser
            .try_parse(|p| Length::<Horizontal>::parse(p))
            .and_then(|l| Ok(LetterSpacingSpec::Value(l)))
            .or_else(|_| {
                Ok(parse_identifiers!(
                    parser,
                    "normal" => LetterSpacingSpec::Normal,
                )?)
            })
    }
}

/// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-family
#[derive(Debug, Clone, PartialEq)]
pub struct SingleFontFamily(pub String);

impl Parse for SingleFontFamily {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<SingleFontFamily, ParseError<'i>> {
        let loc = parser.current_source_location();

        if let Ok(cow) = parser.try_parse(|p| p.expect_string_cloned()) {
            if cow == "" {
                return Err(loc.new_custom_error(ValueErrorKind::value_error(
                    "empty string is not a valid font family name",
                )));
            }

            return Ok(SingleFontFamily((*cow).to_owned()));
        }

        let first_ident = parser.expect_ident()?.clone();

        let mut value = first_ident.as_ref().to_owned();

        while let Ok(cow) = parser.try_parse(|p| p.expect_ident_cloned()) {
            value.push(' ');
            value.push_str(&cow);
        }

        Ok(SingleFontFamily(value))
    }
}

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

    #[test]
    fn detects_invalid_invalid_font_size() {
        assert!(FontSizeSpec::parse_str("furlong").is_err());
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal"),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold"),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100"),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14").is_err());
    }

    #[test]
    fn parses_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal"),
            Ok(LetterSpacingSpec::Normal)
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em"),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn computes_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                0.0,
                LengthUnit::Px,
            )))
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn detects_invalid_invalid_letter_spacing() {
        assert!(LetterSpacingSpec::parse_str("furlong").is_err());
    }

    #[test]
    fn parses_font_family() {
        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("'Hello world'"),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("\"Hello world\""),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("  Hello  world  "),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("Plonk"),
            Ok(SingleFontFamily("Plonk".to_owned()))
        );
    }

    #[test]
    fn detects_invalid_font_family() {
        assert!(<SingleFontFamily as Parse>::parse_str("").is_err());
        assert!(<SingleFontFamily as Parse>::parse_str("''").is_err());
        assert!(<SingleFontFamily as Parse>::parse_str("42").is_err());
    }
}
<commit_msg>(#558): Compute cascaded font-size values correctly for relative units<commit_after>//! CSS font properties.

use cssparser::Parser;

use crate::drawing_ctx::ViewParams;
use crate::error::*;
use crate::length::*;
use crate::parsers::Parse;
use crate::properties::ComputedValues;

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontSizeSpec {
    Smaller,
    Larger,
    XXSmall,
    XSmall,
    Small,
    Medium,
    Large,
    XLarge,
    XXLarge,
    Value(Length<Both>),
}

impl FontSizeSpec {
    pub fn value(&self) -> Length<Both> {
        match self {
            FontSizeSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self, v: &ComputedValues) -> Self {
        let compute_points = |p| 12.0 * 1.2f64.powf(p) / POINTS_PER_INCH;

        let parent = v.font_size.0.value();

        // The parent must already have resolved to an absolute unit
        assert!(
            parent.unit != LengthUnit::Percent
                && parent.unit != LengthUnit::Em
                && parent.unit != LengthUnit::Ex
        );

        use FontSizeSpec::*;

        #[rustfmt::skip]
        let new_size = match self {
            Smaller => Length::<Both>::new(parent.length / 1.2,  parent.unit),
            Larger  => Length::<Both>::new(parent.length * 1.2,  parent.unit),
            XXSmall => Length::<Both>::new(compute_points(-3.0), LengthUnit::In),
            XSmall  => Length::<Both>::new(compute_points(-2.0), LengthUnit::In),
            Small   => Length::<Both>::new(compute_points(-1.0), LengthUnit::In),
            Medium  => Length::<Both>::new(compute_points(0.0),  LengthUnit::In),
            Large   => Length::<Both>::new(compute_points(1.0),  LengthUnit::In),
            XLarge  => Length::<Both>::new(compute_points(2.0),  LengthUnit::In),
            XXLarge => Length::<Both>::new(compute_points(3.0),  LengthUnit::In),

            Value(s) if s.unit == LengthUnit::Percent => {
                Length::<Both>::new(parent.length * s.length, parent.unit)
            }

            Value(s) if s.unit == LengthUnit::Em => {
                Length::<Both>::new(parent.length * s.length, parent.unit)
            }

            Value(s) if s.unit == LengthUnit::Ex => {
                // FIXME: it would be nice to know the actual Ex-height
                // of the font.
                Length::<Both>::new(parent.length * s.length / 2.0, parent.unit)
            }

            Value(s) => *s,
        };

        FontSizeSpec::Value(new_size)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for FontSizeSpec {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<FontSizeSpec, ParseError<'i>> {
        parser
            .try_parse(|p| Length::<Both>::parse(p))
            .and_then(|l| Ok(FontSizeSpec::Value(l)))
            .or_else(|_| {
                Ok(parse_identifiers!(
                    parser,
                    "smaller" => FontSizeSpec::Smaller,
                    "larger" => FontSizeSpec::Larger,
                    "xx-small" => FontSizeSpec::XXSmall,
                    "x-small" => FontSizeSpec::XSmall,
                    "small" => FontSizeSpec::Small,
                    "medium" => FontSizeSpec::Medium,
                    "large" => FontSizeSpec::Large,
                    "x-large" => FontSizeSpec::XLarge,
                    "xx-large" => FontSizeSpec::XXLarge,
                )?)
            })
    }
}

// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-weight
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FontWeightSpec {
    Normal,
    Bold,
    Bolder,
    Lighter,
    W100,
    W200,
    W300,
    W400,
    W500,
    W600,
    W700,
    W800,
    W900,
}

impl Parse for FontWeightSpec {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<FontWeightSpec, ParseError<'i>> {
        parser
            .try_parse(|p| {
                Ok(parse_identifiers!(
                    p,
                    "normal" => FontWeightSpec::Normal,
                    "bold" => FontWeightSpec::Bold,
                    "bolder" => FontWeightSpec::Bolder,
                    "lighter" => FontWeightSpec::Lighter,
                )?)
            })
            .or_else(|_: ParseError| {
                let loc = parser.current_source_location();
                let i = parser.expect_integer()?;
                match i {
                    100 => Ok(FontWeightSpec::W100),
                    200 => Ok(FontWeightSpec::W200),
                    300 => Ok(FontWeightSpec::W300),
                    400 => Ok(FontWeightSpec::W400),
                    500 => Ok(FontWeightSpec::W500),
                    600 => Ok(FontWeightSpec::W600),
                    700 => Ok(FontWeightSpec::W700),
                    800 => Ok(FontWeightSpec::W800),
                    900 => Ok(FontWeightSpec::W900),
                    _ => Err(loc.new_custom_error(ValueErrorKind::parse_error("parse error"))),
                }
            })
    }
}

// https://www.w3.org/TR/css-text-3/#letter-spacing-property
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LetterSpacingSpec {
    Normal,
    Value(Length<Horizontal>),
}

impl LetterSpacingSpec {
    pub fn value(&self) -> Length<Horizontal> {
        match self {
            LetterSpacingSpec::Value(s) => *s,
            _ => unreachable!(),
        }
    }

    pub fn compute(&self) -> Self {
        let spacing = match self {
            LetterSpacingSpec::Normal => Length::<Horizontal>::new(0.0, LengthUnit::Px),
            LetterSpacingSpec::Value(s) => *s,
        };

        LetterSpacingSpec::Value(spacing)
    }

    pub fn normalize(&self, values: &ComputedValues, params: &ViewParams) -> f64 {
        self.value().normalize(values, params)
    }
}

impl Parse for LetterSpacingSpec {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<LetterSpacingSpec, ParseError<'i>> {
        parser
            .try_parse(|p| Length::<Horizontal>::parse(p))
            .and_then(|l| Ok(LetterSpacingSpec::Value(l)))
            .or_else(|_| {
                Ok(parse_identifiers!(
                    parser,
                    "normal" => LetterSpacingSpec::Normal,
                )?)
            })
    }
}

/// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-family
#[derive(Debug, Clone, PartialEq)]
pub struct SingleFontFamily(pub String);

impl Parse for SingleFontFamily {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<SingleFontFamily, ParseError<'i>> {
        let loc = parser.current_source_location();

        if let Ok(cow) = parser.try_parse(|p| p.expect_string_cloned()) {
            if cow == "" {
                return Err(loc.new_custom_error(ValueErrorKind::value_error(
                    "empty string is not a valid font family name",
                )));
            }

            return Ok(SingleFontFamily((*cow).to_owned()));
        }

        let first_ident = parser.expect_ident()?.clone();

        let mut value = first_ident.as_ref().to_owned();

        while let Ok(cow) = parser.try_parse(|p| p.expect_ident_cloned()) {
            value.push(' ');
            value.push_str(&cow);
        }

        Ok(SingleFontFamily(value))
    }
}

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

    use crate::property_defs::FontSize;
    use crate::property_macros::Property;

    #[test]
    fn detects_invalid_invalid_font_size() {
        assert!(FontSizeSpec::parse_str("furlong").is_err());
    }

    #[test]
    fn computes_parent_relative_font_size() {
        let mut values = ComputedValues::default();
        values.font_size = FontSize::parse_str("10px").unwrap();

        assert_eq!(
            FontSize::parse_str("150%").unwrap().compute(&values),
            FontSize::parse_str("15px").unwrap()
        );

        assert_eq!(
            FontSize::parse_str("1.5em").unwrap().compute(&values),
            FontSize::parse_str("15px").unwrap()
        );

        assert_eq!(
            FontSize::parse_str("1ex").unwrap().compute(&values),
            FontSize::parse_str("5px").unwrap()
        );

        let smaller = FontSize::parse_str("smaller").unwrap().compute(&values).0;
        if let FontSizeSpec::Value(v) = smaller {
            assert!(v.length < 10.0);
            assert_eq!(v.unit, LengthUnit::Px);
        } else {
            unreachable!();
        }

        let larger = FontSize::parse_str("larger").unwrap().compute(&values).0;
        if let FontSizeSpec::Value(v) = larger {
            assert!(v.length > 10.0);
            assert_eq!(v.unit, LengthUnit::Px);
        } else {
            unreachable!();
        }
    }

    #[test]
    fn parses_font_weight() {
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("normal"),
            Ok(FontWeightSpec::Normal)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("bold"),
            Ok(FontWeightSpec::Bold)
        );
        assert_eq!(
            <FontWeightSpec as Parse>::parse_str("100"),
            Ok(FontWeightSpec::W100)
        );
    }

    #[test]
    fn detects_invalid_font_weight() {
        assert!(<FontWeightSpec as Parse>::parse_str("").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("strange").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("314").is_err());
        assert!(<FontWeightSpec as Parse>::parse_str("3.14").is_err());
    }

    #[test]
    fn parses_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal"),
            Ok(LetterSpacingSpec::Normal)
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em"),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn computes_letter_spacing() {
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("normal").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                0.0,
                LengthUnit::Px,
            )))
        );
        assert_eq!(
            <LetterSpacingSpec as Parse>::parse_str("10em").map(|s| s.compute()),
            Ok(LetterSpacingSpec::Value(Length::<Horizontal>::new(
                10.0,
                LengthUnit::Em,
            )))
        );
    }

    #[test]
    fn detects_invalid_invalid_letter_spacing() {
        assert!(LetterSpacingSpec::parse_str("furlong").is_err());
    }

    #[test]
    fn parses_font_family() {
        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("'Hello world'"),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("\"Hello world\""),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("  Hello  world  "),
            Ok(SingleFontFamily("Hello world".to_owned()))
        );

        assert_eq!(
            <SingleFontFamily as Parse>::parse_str("Plonk"),
            Ok(SingleFontFamily("Plonk".to_owned()))
        );
    }

    #[test]
    fn detects_invalid_font_family() {
        assert!(<SingleFontFamily as Parse>::parse_str("").is_err());
        assert!(<SingleFontFamily as Parse>::parse_str("''").is_err());
        assert!(<SingleFontFamily as Parse>::parse_str("42").is_err());
    }
}
<|endoftext|>


<commit_before>#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Error<T>
{
	error_summary: String,
	error: T,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum AlphaGetMetadataError
{
	#[serde(rename="path")]
	Path(LookupError),
	#[serde(rename="properties_error")]
	PropertiesError(LookUpPropertiesError),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum RelocationError
{
	#[serde(rename="from_lookup")]
	FromLookup(LookupError),
	#[serde(rename="from_write")]
	FromWrite(WriteError),
	#[serde(rename="to")]
	To(WriteError),
	#[serde(rename="cant_copy_shared_folder")]
	CantCopySharedFolder,
	#[serde(rename="cant_nest_shared_folder")]
	CantNestSharedFolder,
	#[serde(rename="cant_move_folder_into_itself")]
	CantMoveFolderInfoItself,
	#[serde(rename="too_many_files")]
	TooManyFiles,
	#[serde(rename="duplicated_or_nested_paths")]
	DuplicatedOrNestedPaths,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WriteError
{
	#[serde(rename="malformed_path")]
	MalformedPath(Option<String>),
	#[serde(rename="conflict")]
	Conflict(WriteConflictError),
	#[serde(rename="no_write_permission")]
	NoWritePermission,
	#[serde(rename="insufficient_space")]
	InsufficientSpace,
	#[serde(rename="disallowed_name")]
	DisallowedName,
	#[serde(rename="team_folder")]
	TeamFolder,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WriteConflictError
{
	#[serde(rename="file")]
	File,
	#[serde(rename="folder")]
	Folder,
	#[serde(rename="file_ancestor")]
	FileAncestor,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum RelocationBatchError
{
	#[serde(rename="from_lookup")]
	FromLookup(LookupError),
	#[serde(rename="from_write")]
	FromWrite(WriteError),
	#[serde(rename="to")]
	To(WriteError),
	#[serde(rename="cant_copy_shared_folder")]
	CantCopySharedFolder,
	#[serde(rename="cant_nest_shared_folder")]
	CantNestSharedFolder,
	#[serde(rename="too_many_files")]
	TooManyFiles,
	#[serde(rename="duplicated_or_nested_paths")]
	DuplicatedOrNestedPaths,
	#[serde(rename="too_many_write_operations")]
	TooManyWriteOperations,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum PollError
{
	#[serde(rename="invalid_async_job_id")]
	InvalidAsyncJobId,
	#[serde(rename="internal_error")]
	InternalError
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum GetCopyReferenceError
{
	#[serde(rename="path")]
	Path{ path: LookupError},
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum SaveCopyReferenceError
{
	#[serde(rename="path")]
	Path(WriteError),
	#[serde(rename="invalid_copy_reference")]
	InvalidCopyReference,
	#[serde(rename="no_permission")]
	NoPermission,
	#[serde(rename="not_found")]
	NotFound,
	#[serde(rename="too_many_files")]
	TooManyFiles,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum DownloadError
{
	#[serde(rename="path")]
	Path(LookupError)
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum GetMetadataError
{
	#[serde(rename="path")]
	Path(LookupError),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum PreviewError
{
	#[serde(rename="path")]
	Path(LookupError),
	#[serde(rename="in_prpgress")]
	InProgress,
	#[serde(rename="unsupported_extension")]
	UnsupportedExtension,
	#[serde(rename="unsupported_content")]
	UnsupportedContent,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum GetTemporaryLinkError
{
	#[serde(rename="path")]
	Path(LookupError),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ThumbnailError
{
	Path(LookupError),
	#[serde(rename="unsupported_extension")]
	UnsupportedExtension,
	#[serde(rename="unsupported_image")]
	UnsupportedImage,
	#[serde(rename="conversion_error")]
	ConversionError,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ListFolderContinueError
{
	#[serde(rename="path")]
	Path(LookupError),
	#[serde(rename="reset")]
	Reset,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ListFolderLongpollError
{
	#[serde(rename="reset")]
	Reset,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ListRevisionsError
{
	#[serde(rename="path")]
	Path(LookupError),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum CreateFolderError
{
	#[serde(rename="path")]
	Path(WriteError),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum DeleteError
{
	#[serde(rename="path_lookup")]
	PathLookup(LookupError),
	#[serde(rename="path_write")]
	PathWrite(WriteError),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum LookUpPropertiesError
{
	#[serde(rename="property_group_not_found")]
	PropertyGroupNotFound,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ListFolderError
{
	#[serde(rename="path")]
	Path{ path: LookupError},
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum LookupError
{
	#[serde(rename="malformed_path")]
	MalformedPath(Option<String>),
	#[serde(rename="not_found")]
	NotFound,
	#[serde(rename="not_file")]
	NotFile,
	#[serde(rename="not_folder")]
	NotFolder,
	#[serde(rename="restricted_content")]
	RestrictedContent,
	#[serde(rename="invalid_path_root")]
	InvalidPathRoot(PathRootError)
}

#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
pub struct PathRootError
{
	pub path_root: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum RestoreError
{
	#[serde(rename="path_lookup")]
	PathLookup(LookupError),
	#[serde(rename="path_write")]
	PathWrite(WriteError),
	#[serde(rename="invalid_revision")]
	InvalidRevision,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum SaveUrlError
{
	#[serde(rename="path")]
	Path(WriteError),
	#[serde(rename="download_failed")]
	DownloadFailed,
	#[serde(rename="invalid_url")]
	InvalidUrl,
	#[serde(rename="not_found")]
	NotFound,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum SearchError
{
	#[serde(rename="path")]
	Path(LookupError),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum UploadError
{
	#[serde(rename="path")]
	Path(UploadWriteFailed),
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct UploadWriteFailed
{
	pub reason: WriteError,
	pub upload_session_id: String,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum UploadSessionLookupError
{
	#[serde(rename="not_found")]
	NotFound,
	#[serde(rename="incorrect_offset")]
	IncorrectOffset(UploadSessionOffsetError),
	#[serde(rename="closed")]
	Closed,
	#[serde(rename="not_closed")]
	NotClosed,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct UploadSessionOffsetError
{
	pub correct_offset: u64,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum UploadSessionFinishError
{
	#[serde(rename="lookup_failed")]
	LookupFailed(UploadSessionLookupError),
	#[serde(rename="path")]
	Path(WriteError),
	#[serde(rename="too_many_shared_folder_targets")]
	TooManySharedFolderTargets,
	#[serde(rename="too_many_write_operations")]
	TooManyWriteOperations,
}
<commit_msg>removed serialize in errors<commit_after>#[derive(Deserialize, Debug, Clone, PartialEq)]
pub struct Error<T>
{
	error_summary: String,
	error: T,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum AlphaGetMetadataError
{
	#[serde(rename="path")]
	Path(LookupError),
	#[serde(rename="properties_error")]
	PropertiesError(LookUpPropertiesError),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum RelocationError
{
	#[serde(rename="from_lookup")]
	FromLookup(LookupError),
	#[serde(rename="from_write")]
	FromWrite(WriteError),
	#[serde(rename="to")]
	To(WriteError),
	#[serde(rename="cant_copy_shared_folder")]
	CantCopySharedFolder,
	#[serde(rename="cant_nest_shared_folder")]
	CantNestSharedFolder,
	#[serde(rename="cant_move_folder_into_itself")]
	CantMoveFolderInfoItself,
	#[serde(rename="too_many_files")]
	TooManyFiles,
	#[serde(rename="duplicated_or_nested_paths")]
	DuplicatedOrNestedPaths,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum WriteError
{
	#[serde(rename="malformed_path")]
	MalformedPath(Option<String>),
	#[serde(rename="conflict")]
	Conflict(WriteConflictError),
	#[serde(rename="no_write_permission")]
	NoWritePermission,
	#[serde(rename="insufficient_space")]
	InsufficientSpace,
	#[serde(rename="disallowed_name")]
	DisallowedName,
	#[serde(rename="team_folder")]
	TeamFolder,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum WriteConflictError
{
	#[serde(rename="file")]
	File,
	#[serde(rename="folder")]
	Folder,
	#[serde(rename="file_ancestor")]
	FileAncestor,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum RelocationBatchError
{
	#[serde(rename="from_lookup")]
	FromLookup(LookupError),
	#[serde(rename="from_write")]
	FromWrite(WriteError),
	#[serde(rename="to")]
	To(WriteError),
	#[serde(rename="cant_copy_shared_folder")]
	CantCopySharedFolder,
	#[serde(rename="cant_nest_shared_folder")]
	CantNestSharedFolder,
	#[serde(rename="too_many_files")]
	TooManyFiles,
	#[serde(rename="duplicated_or_nested_paths")]
	DuplicatedOrNestedPaths,
	#[serde(rename="too_many_write_operations")]
	TooManyWriteOperations,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum PollError
{
	#[serde(rename="invalid_async_job_id")]
	InvalidAsyncJobId,
	#[serde(rename="internal_error")]
	InternalError
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum GetCopyReferenceError
{
	#[serde(rename="path")]
	Path{ path: LookupError},
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum SaveCopyReferenceError
{
	#[serde(rename="path")]
	Path(WriteError),
	#[serde(rename="invalid_copy_reference")]
	InvalidCopyReference,
	#[serde(rename="no_permission")]
	NoPermission,
	#[serde(rename="not_found")]
	NotFound,
	#[serde(rename="too_many_files")]
	TooManyFiles,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum DownloadError
{
	#[serde(rename="path")]
	Path(LookupError)
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum GetMetadataError
{
	#[serde(rename="path")]
	Path(LookupError),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum PreviewError
{
	#[serde(rename="path")]
	Path(LookupError),
	#[serde(rename="in_prpgress")]
	InProgress,
	#[serde(rename="unsupported_extension")]
	UnsupportedExtension,
	#[serde(rename="unsupported_content")]
	UnsupportedContent,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum GetTemporaryLinkError
{
	#[serde(rename="path")]
	Path(LookupError),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ThumbnailError
{
	Path(LookupError),
	#[serde(rename="unsupported_extension")]
	UnsupportedExtension,
	#[serde(rename="unsupported_image")]
	UnsupportedImage,
	#[serde(rename="conversion_error")]
	ConversionError,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ListFolderContinueError
{
	#[serde(rename="path")]
	Path(LookupError),
	#[serde(rename="reset")]
	Reset,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ListFolderLongpollError
{
	#[serde(rename="reset")]
	Reset,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ListRevisionsError
{
	#[serde(rename="path")]
	Path(LookupError),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum CreateFolderError
{
	#[serde(rename="path")]
	Path(WriteError),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum DeleteError
{
	#[serde(rename="path_lookup")]
	PathLookup(LookupError),
	#[serde(rename="path_write")]
	PathWrite(WriteError),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum LookUpPropertiesError
{
	#[serde(rename="property_group_not_found")]
	PropertyGroupNotFound,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum ListFolderError
{
	#[serde(rename="path")]
	Path{ path: LookupError},
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum LookupError
{
	#[serde(rename="malformed_path")]
	MalformedPath(Option<String>),
	#[serde(rename="not_found")]
	NotFound,
	#[serde(rename="not_file")]
	NotFile,
	#[serde(rename="not_folder")]
	NotFolder,
	#[serde(rename="restricted_content")]
	RestrictedContent,
	#[serde(rename="invalid_path_root")]
	InvalidPathRoot(PathRootError)
}

#[derive(Deserialize, Debug, Clone, Default, PartialEq)]
pub struct PathRootError
{
	pub path_root: Option<String>,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum RestoreError
{
	#[serde(rename="path_lookup")]
	PathLookup(LookupError),
	#[serde(rename="path_write")]
	PathWrite(WriteError),
	#[serde(rename="invalid_revision")]
	InvalidRevision,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum SaveUrlError
{
	#[serde(rename="path")]
	Path(WriteError),
	#[serde(rename="download_failed")]
	DownloadFailed,
	#[serde(rename="invalid_url")]
	InvalidUrl,
	#[serde(rename="not_found")]
	NotFound,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum SearchError
{
	#[serde(rename="path")]
	Path(LookupError),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(tag=".tag")]
pub enum UploadError
{
	#[serde(rename="path")]
	Path(UploadWriteFailed),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub struct UploadWriteFailed
{
	pub reason: WriteError,
	pub upload_session_id: String,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum UploadSessionLookupError
{
	#[serde(rename="not_found")]
	NotFound,
	#[serde(rename="incorrect_offset")]
	IncorrectOffset(UploadSessionOffsetError),
	#[serde(rename="closed")]
	Closed,
	#[serde(rename="not_closed")]
	NotClosed,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub struct UploadSessionOffsetError
{
	pub correct_offset: u64,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum UploadSessionFinishError
{
	#[serde(rename="lookup_failed")]
	LookupFailed(UploadSessionLookupError),
	#[serde(rename="path")]
	Path(WriteError),
	#[serde(rename="too_many_shared_folder_targets")]
	TooManySharedFolderTargets,
	#[serde(rename="too_many_write_operations")]
	TooManyWriteOperations,
}
<|endoftext|>


<commit_before>#![ cfg_attr( not( feature = "use_std" ), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/meta_tools/latest/meta_tools/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

//!
//! Collection of general purpose meta tools.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

// xxx : expose one_cell
// xxx : rename dependencies -> dependency

/// Dependencies.
pub mod dependency
{
  #[ cfg( any( feature = "collection_make", feature = "literally" ) ) ]
  pub use ::literally;
  #[ cfg( feature = "for_each" ) ]
  pub use ::for_each;
  #[ cfg( feature = "impls_index" ) ]
  pub use ::impls_index;
  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use ::former;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use ::woptions;
}

//

mod_interface::mod_interface!
{
  prelude layer meta;
}
pub use protected::*;

//
// /// Collection of general purpose meta tools.
// pub mod meta;
//
// /// Protected namespace of the module.
// pub mod protected
// {
//   pub use super::orphan::*;
//   pub use super::meta::orphan::*;
// }
//
// pub use protected::*;
//
// /// Orphan namespace of the module.
// pub mod orphan
// {
//   pub use super::exposed::*;
// }
//
// /// Exposed namespace of the module.
// pub mod exposed
// {
//   pub use super::prelude::*;
//   pub use super::meta::exposed::*;
// }
//
// /// Prelude to use essentials: `use my_module::prelude::*`.
// pub mod prelude
// {
//   pub use super::meta::prelude::*;
// }
<commit_msg>Improve entry file of module `meta_tools`, add documentation for the declared module<commit_after>#![ cfg_attr( not( feature = "use_std" ), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/meta_tools/latest/meta_tools/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

//!
//! Collection of general purpose meta tools.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

// xxx : expose one_cell
// xxx : rename dependencies -> dependency

/// Dependencies.
pub mod dependency
{
  #[ cfg( any( feature = "collection_make", feature = "literally" ) ) ]
  pub use ::literally;
  #[ cfg( feature = "for_each" ) ]
  pub use ::for_each;
  #[ cfg( feature = "impls_index" ) ]
  pub use ::impls_index;
  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use ::former;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use ::woptions;
}

//

mod_interface::mod_interface!
{
  /// Collection of general purpose meta tools.
  prelude layer meta;
}
pub use protected::*;
<|endoftext|>