<commit_before>//! Generic serialization framework.

#[cfg(feature = "std")]
use std::error;
#[cfg(not(feature = "std"))]
use error;

#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::String;

pub mod impls;

///////////////////////////////////////////////////////////////////////////////

/// `Error` is a trait that allows a `Serialize` to generically create a
/// `Serializer` error.
pub trait Error: Sized + error::Error {
    /// Raised when there is general error when deserializing a type.
    #[cfg(any(feature = "std", feature = "collections"))]
    fn custom<T: Into<String>>(msg: T) -> Self;

    /// Raised when there is general error when deserializing a type.
    #[cfg(all(not(feature = "std"), not(feature = "collections")))]
    fn custom<T: Into<&'static str>>(msg: T) -> Self;

    /// Raised when a `Serialize` was passed an incorrect value.
    fn invalid_value(msg: &str) -> Self {
        Error::custom(format!("invalid value: {}", msg))
    }
}

///////////////////////////////////////////////////////////////////////////////

/// A trait that describes a type that can be serialized by a `Serializer`.
pub trait Serialize {
    /// Serializes this value into this serializer.
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer;
}

///////////////////////////////////////////////////////////////////////////////

/// A trait that describes a type that can serialize a stream of values into the underlying format.
pub trait Serializer {
    /// The error type that can be returned if some error occurs during serialization.
    type Error: Error;

    /// A state object that is initialized by `serialize_seq`, passed to
    /// `serialize_seq_elt`, and consumed by `serialize_seq_end`. Use `()` if no
    /// state is required.
    type SeqState;
    /// A state object that is initialized by `serialize_tuple`, passed to
    /// `serialize_tuple_elt`, and consumed by `serialize_tuple_end`. Use `()`
    /// if no state is required.
    type TupleState;
    /// A state object that is initialized by `serialize_tuple_struct`, passed
    /// to `serialize_tuple_struct_elt`, and consumed by
    /// `serialize_tuple_struct_end`. Use `()` if no state is required.
    type TupleStructState;
    /// A state object that is initialized by `serialize_tuple_variant`, passed
    /// to `serialize_tuple_variant_elt`, and consumed by
    /// `serialize_tuple_variant_end`. Use `()` if no state is required.
    type TupleVariantState;
    /// A state object that is initialized by `serialize_map`, passed to
    /// `serialize_map_elt`, and consumed by `serialize_map_end`. Use `()` if no
    /// state is required.
    type MapState;
    /// A state object that is initialized by `serialize_struct`, passed to
    /// `serialize_struct_elt`, and consumed by `serialize_struct_end`. Use `()`
    /// if no state is required.
    type StructState;
    /// A state object that is initialized by `serialize_struct_variant`, passed
    /// to `serialize_struct_variant_elt`, and consumed by
    /// `serialize_struct_variant_end`. Use `()` if no state is required.
    type StructVariantState;

    /// Serializes a `bool` value.
    fn serialize_bool(&mut self, v: bool) -> Result<(), Self::Error>;

    /// Serializes an `isize` value. If the format does not differentiate
    /// between `isize` and `i64`, a reasonable implementation would be to cast
    /// the value to `i64` and forward to `serialize_i64`.
    fn serialize_isize(&mut self, v: isize) -> Result<(), Self::Error>;

    /// Serializes an `i8` value. If the format does not differentiate between
    /// `i8` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i8(&mut self, v: i8) -> Result<(), Self::Error>;

    /// Serializes an `i16` value. If the format does not differentiate between
    /// `i16` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i16(&mut self, v: i16) -> Result<(), Self::Error>;

    /// Serializes an `i32` value. If the format does not differentiate between
    /// `i32` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i32(&mut self, v: i32) -> Result<(), Self::Error>;

    /// Serializes an `i64` value.
    fn serialize_i64(&mut self, v: i64) -> Result<(), Self::Error>;

    /// Serializes a `usize` value. If the format does not differentiate between
    /// `usize` and `u64`, a reasonable implementation would be to cast the
    /// value to `u64` and forward to `serialize_u64`.
    fn serialize_usize(&mut self, v: usize) -> Result<(), Self::Error>;

    /// Serializes a `u8` value. If the format does not differentiate between
    /// `u8` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u8(&mut self, v: u8) -> Result<(), Self::Error>;

    /// Serializes a `u16` value. If the format does not differentiate between
    /// `u16` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u16(&mut self, v: u16) -> Result<(), Self::Error>;

    /// Serializes a `u32` value. If the format does not differentiate between
    /// `u32` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u32(&mut self, v: u32) -> Result<(), Self::Error>;

    /// `Serializes a `u64` value.
    fn serialize_u64(&mut self, v: u64) -> Result<(), Self::Error>;

    /// Serializes an `f32` value. If the format does not differentiate between
    /// `f32` and `f64`, a reasonable implementation would be to cast the value
    /// to `f64` and forward to `serialize_f64`.
    fn serialize_f32(&mut self, v: f32) -> Result<(), Self::Error>;

    /// Serializes an `f64` value.
    fn serialize_f64(&mut self, v: f64) -> Result<(), Self::Error>;

    /// Serializes a character.
    fn serialize_char(&mut self, v: char) -> Result<(), Self::Error>;

    /// Serializes a `&str`.
    fn serialize_str(&mut self, value: &str) -> Result<(), Self::Error>;

    /// Enables serializers to serialize byte slices more compactly or more
    /// efficiently than other types of slices. If no efficient implementation
    /// is available, a reasonable implementation would be to forward to
    /// `serialize_seq`.
    fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error>;

    /// Serializes a `()` value.
    fn serialize_unit(&mut self) -> Result<(), Self::Error>;

    /// Serializes a unit struct value. A reasonable implementation would be to
    /// forward to `serialize_unit`.
    fn serialize_unit_struct(
        &mut self,
        name: &str,
    ) -> Result<(), Self::Error>;

    /// Serializes a unit variant, otherwise known as a variant with no
    /// arguments. A reasonable implementation would be to forward to
    /// `serialize_unit`.
    fn serialize_unit_variant(
        &mut self,
        name: &str,
        variant_index: usize,
        variant: &str,
    ) -> Result<(), Self::Error>;

    /// Allows a tuple struct with a single element, also known as a newtype
    /// struct, to be more efficiently serialized than a tuple struct with
    /// multiple items. A reasonable implementation would be to forward to
    /// `serialize_tuple_struct`.
    fn serialize_newtype_struct<T: Serialize>(
        &mut self,
        name: &str,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Allows a variant with a single item to be more efficiently serialized
    /// than a variant with multiple items. A reasonable implementation would be
    /// to forward to `serialize_tuple_variant`.
    fn serialize_newtype_variant<T: Serialize>(
        &mut self,
        name: &str,
        variant_index: usize,
        variant: &str,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Serializes a `None` value.
    fn serialize_none(&mut self) -> Result<(), Self::Error>;

    /// Serializes a `Some(...)` value.
    fn serialize_some<T: Serialize>(
        &mut self,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a sequence. This call must be followed by zero or
    /// more calls to `serialize_seq_elt`, then a call to `serialize_seq_end`.
    fn serialize_seq(
        &mut self,
        len: Option<usize>,
    ) -> Result<Self::SeqState, Self::Error>;

    /// Serializes a sequence element. Must have previously called
    /// `serialize_seq`.
    fn serialize_seq_elt<T: Serialize>(
        &mut self,
        state: &mut Self::SeqState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a sequence.
    fn serialize_seq_end(
        &mut self,
        state: Self::SeqState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a sequence whose length will be known at
    /// deserialization time. This call must be followed by zero or more calls
    /// to `serialize_seq_elt`, then a call to `serialize_seq_end`. A reasonable
    /// implementation would be to forward to `serialize_seq`.
    fn serialize_seq_fixed_size(
        &mut self,
        size: usize,
    ) -> Result<Self::SeqState, Self::Error>;

    /// Begins to serialize a tuple. This call must be followed by zero or more
    /// calls to `serialize_tuple_elt`, then a call to `serialize_tuple_end`. A
    /// reasonable implementation would be to forward to `serialize_seq`.
    fn serialize_tuple(
        &mut self,
        len: usize,
    ) -> Result<Self::TupleState, Self::Error>;

    /// Serializes a tuple element. Must have previously called
    /// `serialize_tuple`.
    fn serialize_tuple_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple.
    fn serialize_tuple_end(
        &mut self,
        state: Self::TupleState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a tuple struct. This call must be followed by zero
    /// or more calls to `serialize_tuple_struct_elt`, then a call to
    /// `serialize_tuple_struct_end`. A reasonable implementation would be to
    /// forward to `serialize_tuple`.
    fn serialize_tuple_struct(
        &mut self,
        name: &str,
        len: usize,
    ) -> Result<Self::TupleStructState, Self::Error>;

    /// Serializes a tuple struct element. Must have previously called
    /// `serialize_tuple_struct`.
    fn serialize_tuple_struct_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleStructState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple struct.
    fn serialize_tuple_struct_end(
        &mut self,
        state: Self::TupleStructState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a tuple variant. This call must be followed by zero
    /// or more calls to `serialize_tuple_variant_elt`, then a call to
    /// `serialize_tuple_variant_end`. A reasonable implementation would be to
    /// forward to `serialize_tuple_struct`.
    fn serialize_tuple_variant(
        &mut self,
        name: &str,
        variant_index: usize,
        variant: &str,
        len: usize,
    ) -> Result<Self::TupleVariantState, Self::Error>;

    /// Serializes a tuple variant element. Must have previously called
    /// `serialize_tuple_variant`.
    fn serialize_tuple_variant_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleVariantState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple variant.
    fn serialize_tuple_variant_end(
        &mut self,
        state: Self::TupleVariantState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a map. This call must be followed by zero or more
    /// calls to `serialize_map_elt`, then a call to `serialize_map_end`.
    fn serialize_map(
        &mut self,
        len: Option<usize>,
    ) -> Result<Self::MapState, Self::Error>;

    /// Serialize a map element. Must have previously called `serialize_map`.
    fn serialize_map_elt<K: Serialize, V: Serialize>(
        &mut self,
        state: &mut Self::MapState,
        key: K,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a map.
    fn serialize_map_end(
        &mut self,
        state: Self::MapState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a struct. This call must be followed by zero or more
    /// calls to `serialize_struct_elt`, then a call to `serialize_struct_end`.
    fn serialize_struct(
        &mut self,
        name: &str,
        len: usize,
    ) -> Result<Self::StructState, Self::Error>;

    /// Serializes a struct field. Must have previously called
    /// `serialize_struct`.
    fn serialize_struct_elt<V: Serialize>(
        &mut self,
        state: &mut Self::StructState,
        key: &str,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a struct.
    fn serialize_struct_end(
        &mut self,
        state: Self::StructState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a struct variant. This call must be followed by zero
    /// or more calls to `serialize_struct_variant_elt`, then a call to
    /// `serialize_struct_variant_end`.
    fn serialize_struct_variant(
        &mut self,
        name: &str,
        variant_index: usize,
        variant: &str,
        len: usize,
    ) -> Result<Self::StructVariantState, Self::Error>;

    /// Serialize a struct variant element. Must have previously called
    /// `serialize_struct_variant`.
    fn serialize_struct_variant_elt<V: Serialize>(
        &mut self,
        state: &mut Self::StructVariantState,
        key: &str,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a struct variant.
    fn serialize_struct_variant_end(
        &mut self,
        state: Self::StructVariantState,
    ) -> Result<(), Self::Error>;
}
<commit_msg>Restore 'static requirement for names<commit_after>//! Generic serialization framework.

#[cfg(feature = "std")]
use std::error;
#[cfg(not(feature = "std"))]
use error;

#[cfg(all(feature = "collections", not(feature = "std")))]
use collections::String;

pub mod impls;

///////////////////////////////////////////////////////////////////////////////

/// `Error` is a trait that allows a `Serialize` to generically create a
/// `Serializer` error.
pub trait Error: Sized + error::Error {
    /// Raised when there is general error when deserializing a type.
    #[cfg(any(feature = "std", feature = "collections"))]
    fn custom<T: Into<String>>(msg: T) -> Self;

    /// Raised when there is general error when deserializing a type.
    #[cfg(all(not(feature = "std"), not(feature = "collections")))]
    fn custom<T: Into<&'static str>>(msg: T) -> Self;

    /// Raised when a `Serialize` was passed an incorrect value.
    fn invalid_value(msg: &str) -> Self {
        Error::custom(format!("invalid value: {}", msg))
    }
}

///////////////////////////////////////////////////////////////////////////////

/// A trait that describes a type that can be serialized by a `Serializer`.
pub trait Serialize {
    /// Serializes this value into this serializer.
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer;
}

///////////////////////////////////////////////////////////////////////////////

/// A trait that describes a type that can serialize a stream of values into the underlying format.
pub trait Serializer {
    /// The error type that can be returned if some error occurs during serialization.
    type Error: Error;

    /// A state object that is initialized by `serialize_seq`, passed to
    /// `serialize_seq_elt`, and consumed by `serialize_seq_end`. Use `()` if no
    /// state is required.
    type SeqState;
    /// A state object that is initialized by `serialize_tuple`, passed to
    /// `serialize_tuple_elt`, and consumed by `serialize_tuple_end`. Use `()`
    /// if no state is required.
    type TupleState;
    /// A state object that is initialized by `serialize_tuple_struct`, passed
    /// to `serialize_tuple_struct_elt`, and consumed by
    /// `serialize_tuple_struct_end`. Use `()` if no state is required.
    type TupleStructState;
    /// A state object that is initialized by `serialize_tuple_variant`, passed
    /// to `serialize_tuple_variant_elt`, and consumed by
    /// `serialize_tuple_variant_end`. Use `()` if no state is required.
    type TupleVariantState;
    /// A state object that is initialized by `serialize_map`, passed to
    /// `serialize_map_elt`, and consumed by `serialize_map_end`. Use `()` if no
    /// state is required.
    type MapState;
    /// A state object that is initialized by `serialize_struct`, passed to
    /// `serialize_struct_elt`, and consumed by `serialize_struct_end`. Use `()`
    /// if no state is required.
    type StructState;
    /// A state object that is initialized by `serialize_struct_variant`, passed
    /// to `serialize_struct_variant_elt`, and consumed by
    /// `serialize_struct_variant_end`. Use `()` if no state is required.
    type StructVariantState;

    /// Serializes a `bool` value.
    fn serialize_bool(&mut self, v: bool) -> Result<(), Self::Error>;

    /// Serializes an `isize` value. If the format does not differentiate
    /// between `isize` and `i64`, a reasonable implementation would be to cast
    /// the value to `i64` and forward to `serialize_i64`.
    fn serialize_isize(&mut self, v: isize) -> Result<(), Self::Error>;

    /// Serializes an `i8` value. If the format does not differentiate between
    /// `i8` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i8(&mut self, v: i8) -> Result<(), Self::Error>;

    /// Serializes an `i16` value. If the format does not differentiate between
    /// `i16` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i16(&mut self, v: i16) -> Result<(), Self::Error>;

    /// Serializes an `i32` value. If the format does not differentiate between
    /// `i32` and `i64`, a reasonable implementation would be to cast the value
    /// to `i64` and forward to `serialize_i64`.
    fn serialize_i32(&mut self, v: i32) -> Result<(), Self::Error>;

    /// Serializes an `i64` value.
    fn serialize_i64(&mut self, v: i64) -> Result<(), Self::Error>;

    /// Serializes a `usize` value. If the format does not differentiate between
    /// `usize` and `u64`, a reasonable implementation would be to cast the
    /// value to `u64` and forward to `serialize_u64`.
    fn serialize_usize(&mut self, v: usize) -> Result<(), Self::Error>;

    /// Serializes a `u8` value. If the format does not differentiate between
    /// `u8` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u8(&mut self, v: u8) -> Result<(), Self::Error>;

    /// Serializes a `u16` value. If the format does not differentiate between
    /// `u16` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u16(&mut self, v: u16) -> Result<(), Self::Error>;

    /// Serializes a `u32` value. If the format does not differentiate between
    /// `u32` and `u64`, a reasonable implementation would be to cast the value
    /// to `u64` and forward to `serialize_u64`.
    fn serialize_u32(&mut self, v: u32) -> Result<(), Self::Error>;

    /// `Serializes a `u64` value.
    fn serialize_u64(&mut self, v: u64) -> Result<(), Self::Error>;

    /// Serializes an `f32` value. If the format does not differentiate between
    /// `f32` and `f64`, a reasonable implementation would be to cast the value
    /// to `f64` and forward to `serialize_f64`.
    fn serialize_f32(&mut self, v: f32) -> Result<(), Self::Error>;

    /// Serializes an `f64` value.
    fn serialize_f64(&mut self, v: f64) -> Result<(), Self::Error>;

    /// Serializes a character.
    fn serialize_char(&mut self, v: char) -> Result<(), Self::Error>;

    /// Serializes a `&str`.
    fn serialize_str(&mut self, value: &str) -> Result<(), Self::Error>;

    /// Enables serializers to serialize byte slices more compactly or more
    /// efficiently than other types of slices. If no efficient implementation
    /// is available, a reasonable implementation would be to forward to
    /// `serialize_seq`.
    fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error>;

    /// Serializes a `()` value.
    fn serialize_unit(&mut self) -> Result<(), Self::Error>;

    /// Serializes a unit struct value. A reasonable implementation would be to
    /// forward to `serialize_unit`.
    fn serialize_unit_struct(
        &mut self,
        name: &'static str,
    ) -> Result<(), Self::Error>;

    /// Serializes a unit variant, otherwise known as a variant with no
    /// arguments. A reasonable implementation would be to forward to
    /// `serialize_unit`.
    fn serialize_unit_variant(
        &mut self,
        name: &'static str,
        variant_index: usize,
        variant: &'static str,
    ) -> Result<(), Self::Error>;

    /// Allows a tuple struct with a single element, also known as a newtype
    /// struct, to be more efficiently serialized than a tuple struct with
    /// multiple items. A reasonable implementation would be to forward to
    /// `serialize_tuple_struct`.
    fn serialize_newtype_struct<T: Serialize>(
        &mut self,
        name: &'static str,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Allows a variant with a single item to be more efficiently serialized
    /// than a variant with multiple items. A reasonable implementation would be
    /// to forward to `serialize_tuple_variant`.
    fn serialize_newtype_variant<T: Serialize>(
        &mut self,
        name: &'static str,
        variant_index: usize,
        variant: &'static str,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Serializes a `None` value.
    fn serialize_none(&mut self) -> Result<(), Self::Error>;

    /// Serializes a `Some(...)` value.
    fn serialize_some<T: Serialize>(
        &mut self,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a sequence. This call must be followed by zero or
    /// more calls to `serialize_seq_elt`, then a call to `serialize_seq_end`.
    fn serialize_seq(
        &mut self,
        len: Option<usize>,
    ) -> Result<Self::SeqState, Self::Error>;

    /// Serializes a sequence element. Must have previously called
    /// `serialize_seq`.
    fn serialize_seq_elt<T: Serialize>(
        &mut self,
        state: &mut Self::SeqState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a sequence.
    fn serialize_seq_end(
        &mut self,
        state: Self::SeqState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a sequence whose length will be known at
    /// deserialization time. This call must be followed by zero or more calls
    /// to `serialize_seq_elt`, then a call to `serialize_seq_end`. A reasonable
    /// implementation would be to forward to `serialize_seq`.
    fn serialize_seq_fixed_size(
        &mut self,
        size: usize,
    ) -> Result<Self::SeqState, Self::Error>;

    /// Begins to serialize a tuple. This call must be followed by zero or more
    /// calls to `serialize_tuple_elt`, then a call to `serialize_tuple_end`. A
    /// reasonable implementation would be to forward to `serialize_seq`.
    fn serialize_tuple(
        &mut self,
        len: usize,
    ) -> Result<Self::TupleState, Self::Error>;

    /// Serializes a tuple element. Must have previously called
    /// `serialize_tuple`.
    fn serialize_tuple_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple.
    fn serialize_tuple_end(
        &mut self,
        state: Self::TupleState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a tuple struct. This call must be followed by zero
    /// or more calls to `serialize_tuple_struct_elt`, then a call to
    /// `serialize_tuple_struct_end`. A reasonable implementation would be to
    /// forward to `serialize_tuple`.
    fn serialize_tuple_struct(
        &mut self,
        name: &'static str,
        len: usize,
    ) -> Result<Self::TupleStructState, Self::Error>;

    /// Serializes a tuple struct element. Must have previously called
    /// `serialize_tuple_struct`.
    fn serialize_tuple_struct_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleStructState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple struct.
    fn serialize_tuple_struct_end(
        &mut self,
        state: Self::TupleStructState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a tuple variant. This call must be followed by zero
    /// or more calls to `serialize_tuple_variant_elt`, then a call to
    /// `serialize_tuple_variant_end`. A reasonable implementation would be to
    /// forward to `serialize_tuple_struct`.
    fn serialize_tuple_variant(
        &mut self,
        name: &'static str,
        variant_index: usize,
        variant: &'static str,
        len: usize,
    ) -> Result<Self::TupleVariantState, Self::Error>;

    /// Serializes a tuple variant element. Must have previously called
    /// `serialize_tuple_variant`.
    fn serialize_tuple_variant_elt<T: Serialize>(
        &mut self,
        state: &mut Self::TupleVariantState,
        value: T,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a tuple variant.
    fn serialize_tuple_variant_end(
        &mut self,
        state: Self::TupleVariantState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a map. This call must be followed by zero or more
    /// calls to `serialize_map_elt`, then a call to `serialize_map_end`.
    fn serialize_map(
        &mut self,
        len: Option<usize>,
    ) -> Result<Self::MapState, Self::Error>;

    /// Serialize a map element. Must have previously called `serialize_map`.
    fn serialize_map_elt<K: Serialize, V: Serialize>(
        &mut self,
        state: &mut Self::MapState,
        key: K,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a map.
    fn serialize_map_end(
        &mut self,
        state: Self::MapState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a struct. This call must be followed by zero or more
    /// calls to `serialize_struct_elt`, then a call to `serialize_struct_end`.
    fn serialize_struct(
        &mut self,
        name: &'static str,
        len: usize,
    ) -> Result<Self::StructState, Self::Error>;

    /// Serializes a struct field. Must have previously called
    /// `serialize_struct`.
    fn serialize_struct_elt<V: Serialize>(
        &mut self,
        state: &mut Self::StructState,
        key: &'static str,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a struct.
    fn serialize_struct_end(
        &mut self,
        state: Self::StructState,
    ) -> Result<(), Self::Error>;

    /// Begins to serialize a struct variant. This call must be followed by zero
    /// or more calls to `serialize_struct_variant_elt`, then a call to
    /// `serialize_struct_variant_end`.
    fn serialize_struct_variant(
        &mut self,
        name: &'static str,
        variant_index: usize,
        variant: &'static str,
        len: usize,
    ) -> Result<Self::StructVariantState, Self::Error>;

    /// Serialize a struct variant element. Must have previously called
    /// `serialize_struct_variant`.
    fn serialize_struct_variant_elt<V: Serialize>(
        &mut self,
        state: &mut Self::StructVariantState,
        key: &'static str,
        value: V,
    ) -> Result<(), Self::Error>;

    /// Finishes serializing a struct variant.
    fn serialize_struct_variant_end(
        &mut self,
        state: Self::StructVariantState,
    ) -> Result<(), Self::Error>;
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! [*Unicode IDNA Compatibility Processing*
//! (Unicode Technical Standard #46)](http://www.unicode.org/reports/tr46/)

use self::Mapping::*;
use punycode;
use std::ascii::AsciiExt;
use std::cmp::Ordering::{Equal, Less, Greater};
use unicode_bidi::{BidiClass, bidi_class};
use unicode_normalization::UnicodeNormalization;
use unicode_normalization::char::is_combining_mark;

include!("uts46_mapping_table.rs");

pub static PUNYCODE_PREFIX: &'static str = "xn--";

#[derive(Debug)]
struct StringTableSlice {
    // Store these as separate fields so the structure will have an
    // alignment of 1 and thus pack better into the Mapping enum, below.
    byte_start_lo: u8,
    byte_start_hi: u8,
    byte_len: u8,
}

fn decode_slice(slice: &StringTableSlice) -> &'static str {
    let lo = slice.byte_start_lo as usize;
    let hi = slice.byte_start_hi as usize;
    let start = (hi << 8) | lo;
    let len = slice.byte_len as usize;
    &STRING_TABLE[start..(start + len)]
}

#[repr(u8)]
#[derive(Debug)]
enum Mapping {
    Valid,
    Ignored,
    Mapped(StringTableSlice),
    Deviation(StringTableSlice),
    Disallowed,
    DisallowedStd3Valid,
    DisallowedStd3Mapped(StringTableSlice),
}

struct Range {
    from: char,
    to: char,
    mapping: Mapping,
}

fn find_char(codepoint: char) -> &'static Mapping {
    let r = TABLE.binary_search_by(|ref range| {
        if codepoint > range.to {
            Less
        } else if codepoint < range.from {
            Greater
        } else {
            Equal
        }
    });
    r.ok().map(|i| &TABLE[i].mapping).unwrap()
}

fn map_char(codepoint: char, flags: Flags, output: &mut String, errors: &mut Vec<Error>) {
    match *find_char(codepoint) {
        Mapping::Valid => output.push(codepoint),
        Mapping::Ignored => {},
        Mapping::Mapped(ref slice) => output.push_str(decode_slice(slice)),
        Mapping::Deviation(ref slice) => {
            if flags.transitional_processing {
                output.push_str(decode_slice(slice))
            } else {
                output.push(codepoint)
            }
        }
        Mapping::Disallowed => {
            errors.push(Error::DissallowedCharacter);
            output.push(codepoint);
        }
        Mapping::DisallowedStd3Valid => {
            if flags.use_std3_ascii_rules {
                errors.push(Error::DissallowedByStd3AsciiRules);
            }
            output.push(codepoint)
        }
        Mapping::DisallowedStd3Mapped(ref slice) => {
            if flags.use_std3_ascii_rules {
                errors.push(Error::DissallowedMappedInStd3);
            }
            output.push_str(decode_slice(slice))
        }
    }
}

// http://tools.ietf.org/html/rfc5893#section-2
fn passes_bidi(label: &str, is_bidi_domain: bool) -> bool {
    // Rule 0: Bidi Rules apply to Bidi Domain Names: a name with at least one RTL label.  A label
    // is RTL if it contains at least one character of bidi class R, AL or AN.
    if !is_bidi_domain {
        return true;
    }

    let mut chars = label.chars();
    let first_char_class = match chars.next() {
        Some(c) => bidi_class(c),
        None => return true, // empty string
    };

    match first_char_class {
        // LTR label
        BidiClass::L => {
            // Rule 5
            loop {
                match chars.next() {
                    Some(c) => {
                        if !matches!(bidi_class(c),
                                     BidiClass::L | BidiClass::EN |
                                     BidiClass::ES | BidiClass::CS |
                                     BidiClass::ET | BidiClass::ON |
                                     BidiClass::BN | BidiClass::NSM
                                    ) {
                            return false;
                        }
                    },
                    None => { break; },
                }
            }

            // Rule 6
            // must end in L or EN followed by 0 or more NSM
            let mut rev_chars = label.chars().rev();
            let mut last_non_nsm = rev_chars.next();
            loop {
                match last_non_nsm {
                    Some(c) if bidi_class(c) == BidiClass::NSM => {
                        last_non_nsm = rev_chars.next();
                        continue;
                    }
                    _ => { break; },
                }
            }
            match last_non_nsm {
                Some(c) if bidi_class(c) == BidiClass::L
                    || bidi_class(c) == BidiClass::EN => {},
                Some(_) => { return false; },
                _ => {}
            }

        }

        // RTL label
        BidiClass::R | BidiClass::AL => {
            let mut found_en = false;
            let mut found_an = false;

            // Rule 2
            loop {
                match chars.next() {
                    Some(c) => {
                        let char_class = bidi_class(c);

                        if char_class == BidiClass::EN {
                            found_en = true;
                        }
                        if char_class == BidiClass::AN {
                            found_an = true;
                        }

                        if !matches!(char_class, BidiClass::R | BidiClass::AL |
                                     BidiClass::AN | BidiClass::EN |
                                     BidiClass::ES | BidiClass::CS |
                                     BidiClass::ET | BidiClass::ON |
                                     BidiClass::BN | BidiClass::NSM) {
                            return false;
                        }
                    },
                    None => { break; },
                }
            }
            // Rule 3
            let mut rev_chars = label.chars().rev();
            let mut last = rev_chars.next();
            loop { // must end in L or EN followed by 0 or more NSM
                match last {
                    Some(c) if bidi_class(c) == BidiClass::NSM => {
                        last = rev_chars.next();
                        continue;
                    }
                    _ => { break; },
                }
            }
            match last {
                Some(c) if matches!(bidi_class(c), BidiClass::R | BidiClass::AL |
                                    BidiClass::EN | BidiClass::AN) => {},
                _ => { return false; }
            }

            // Rule 4
            if found_an && found_en {
                return false;
            }
        }

        // Rule 1: Should start with L or R/AL
        _ => {
            return false;
        }
    }

    return true;
}

/// http://www.unicode.org/reports/tr46/#Validity_Criteria
fn validate(label: &str, is_bidi_domain: bool, flags: Flags, errors: &mut Vec<Error>) {
    let first_char = label.chars().next();
    if first_char == None {
        // Empty string, pass
    }

    // V1: Must be in NFC form.
    else if label.nfc().ne(label.chars()) {
        errors.push(Error::ValidityCriteria);
    }

    // V2: No U+002D HYPHEN-MINUS in both third and fourth positions.
    //
    // NOTE: Spec says that the label must not contain a HYPHEN-MINUS character in both the
    // third and fourth positions. But nobody follows this criteria. See the spec issue below:
    // https://github.com/whatwg/url/issues/53
    //
    // TODO: Add *CheckHyphens* flag.

    // V3: neither begin nor end with a U+002D HYPHEN-MINUS
    else if label.starts_with("-") || label.ends_with("-") {
        errors.push(Error::ValidityCriteria);
    }

    // V4: not contain a U+002E FULL STOP
    //
    // Here, label can't contain '.' since the input is from .split('.')

    // V5: not begin with a GC=Mark
    else if is_combining_mark(first_char.unwrap()) {
        errors.push(Error::ValidityCriteria);
    }

    // V6: Check against Mapping Table
    else if label.chars().any(|c| match *find_char(c) {
        Mapping::Valid => false,
        Mapping::Deviation(_) => flags.transitional_processing,
        Mapping::DisallowedStd3Valid => flags.use_std3_ascii_rules,
        _ => true,
    }) {
        errors.push(Error::ValidityCriteria);
    }

    // V7: ContextJ rules
    //
    // TODO: Implement rules and add *CheckJoiners* flag.

    // V8: Bidi rules
    //
    // TODO: Add *CheckBidi* flag
    else if !passes_bidi(label, is_bidi_domain)
    {
        errors.push(Error::ValidityCriteria);
    }
}

/// http://www.unicode.org/reports/tr46/#Processing
fn processing(domain: &str, flags: Flags, errors: &mut Vec<Error>) -> String {
    let mut mapped = String::new();
    for c in domain.chars() {
        map_char(c, flags, &mut mapped, errors)
    }
    let normalized: String = mapped.nfc().collect();

    // Find out if it's a Bidi Domain Name
    //
    // First, check for literal bidi chars
    let mut is_bidi_domain = domain.chars().any(|c|
        matches!(bidi_class(c), BidiClass::R | BidiClass::AL | BidiClass::AN)
    );
    if !is_bidi_domain {
        // Then check for punycode-encoded bidi chars
        for label in normalized.split('.') {
            if label.starts_with(PUNYCODE_PREFIX) {
                match punycode::decode_to_string(&label[PUNYCODE_PREFIX.len()..]) {
                    Some(decoded_label) => {
                        if decoded_label.chars().any(|c|
                            matches!(bidi_class(c), BidiClass::R | BidiClass::AL | BidiClass::AN)
                        ) {
                            is_bidi_domain = true;
                        }
                    }
                    None => {
                        is_bidi_domain = true;
                    }
                }
            }
        }
    }

    let mut validated = String::new();
    let mut first = true;
    for label in normalized.split('.') {
        if !first {
            validated.push('.');
        }
        first = false;
        if label.starts_with(PUNYCODE_PREFIX) {
            match punycode::decode_to_string(&label[PUNYCODE_PREFIX.len()..]) {
                Some(decoded_label) => {
                    let flags = Flags { transitional_processing: false, ..flags };
                    validate(&decoded_label, is_bidi_domain, flags, errors);
                    validated.push_str(&decoded_label)
                }
                None => errors.push(Error::PunycodeError)
            }
        } else {
            validate(label, is_bidi_domain, flags, errors);
            validated.push_str(label)
        }
    }
    validated
}

#[derive(Copy, Clone)]
pub struct Flags {
   pub use_std3_ascii_rules: bool,
   pub transitional_processing: bool,
   pub verify_dns_length: bool,
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
enum Error {
    PunycodeError,
    ValidityCriteria,
    DissallowedByStd3AsciiRules,
    DissallowedMappedInStd3,
    DissallowedCharacter,
    TooLongForDns,
    TooShortForDns,
}

/// Errors recorded during UTS #46 processing.
///
/// This is opaque for now, only indicating the presence of at least one error.
/// More details may be exposed in the future.
#[derive(Debug)]
pub struct Errors(Vec<Error>);

/// http://www.unicode.org/reports/tr46/#ToASCII
pub fn to_ascii(domain: &str, flags: Flags) -> Result<String, Errors> {
    let mut errors = Vec::new();
    let mut result = String::new();
    let mut first = true;
    for label in processing(domain, flags, &mut errors).split('.') {
        if !first {
            result.push('.');
        }
        first = false;
        if label.is_ascii() {
            result.push_str(label);
        } else {
            match punycode::encode_str(label) {
                Some(x) => {
                    result.push_str(PUNYCODE_PREFIX);
                    result.push_str(&x);
                },
                None => errors.push(Error::PunycodeError)
            }
        }
    }

    if flags.verify_dns_length {
        let domain = if result.ends_with(".") { &result[..result.len()-1]  } else { &*result };
        if domain.len() < 1 || domain.split('.').any(|label| label.len() < 1) {
            errors.push(Error::TooShortForDns)
        }
        if domain.len() > 253 || domain.split('.').any(|label| label.len() > 63) {
            errors.push(Error::TooLongForDns)
        }
    }
    if errors.is_empty() {
        Ok(result)
    } else {
        Err(Errors(errors))
    }
}

/// http://www.unicode.org/reports/tr46/#ToUnicode
///
/// Only `use_std3_ascii_rules` is used in `flags`.
pub fn to_unicode(domain: &str, mut flags: Flags) -> (String, Result<(), Errors>) {
    flags.transitional_processing = false;
    let mut errors = Vec::new();
    let domain = processing(domain, flags, &mut errors);
    let errors = if errors.is_empty() {
        Ok(())
    } else {
        Err(Errors(errors))
    };
    (domain, errors)
}
<commit_msg>Derive `Copy` for some structures.<commit_after>// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! [*Unicode IDNA Compatibility Processing*
//! (Unicode Technical Standard #46)](http://www.unicode.org/reports/tr46/)

use self::Mapping::*;
use punycode;
use std::ascii::AsciiExt;
use std::cmp::Ordering::{Equal, Less, Greater};
use unicode_bidi::{BidiClass, bidi_class};
use unicode_normalization::UnicodeNormalization;
use unicode_normalization::char::is_combining_mark;

include!("uts46_mapping_table.rs");

pub static PUNYCODE_PREFIX: &'static str = "xn--";

#[derive(Clone, Copy, Debug)]
struct StringTableSlice {
    // Store these as separate fields so the structure will have an
    // alignment of 1 and thus pack better into the Mapping enum, below.
    byte_start_lo: u8,
    byte_start_hi: u8,
    byte_len: u8,
}

fn decode_slice(slice: &StringTableSlice) -> &'static str {
    let lo = slice.byte_start_lo as usize;
    let hi = slice.byte_start_hi as usize;
    let start = (hi << 8) | lo;
    let len = slice.byte_len as usize;
    &STRING_TABLE[start..(start + len)]
}

#[repr(u8)]
#[derive(Clone, Copy, Debug)]
enum Mapping {
    Valid,
    Ignored,
    Mapped(StringTableSlice),
    Deviation(StringTableSlice),
    Disallowed,
    DisallowedStd3Valid,
    DisallowedStd3Mapped(StringTableSlice),
}

#[derive(Clone, Copy)]
struct Range {
    from: char,
    to: char,
    mapping: Mapping,
}

fn find_char(codepoint: char) -> &'static Mapping {
    let r = TABLE.binary_search_by(|ref range| {
        if codepoint > range.to {
            Less
        } else if codepoint < range.from {
            Greater
        } else {
            Equal
        }
    });
    r.ok().map(|i| &TABLE[i].mapping).unwrap()
}

fn map_char(codepoint: char, flags: Flags, output: &mut String, errors: &mut Vec<Error>) {
    match *find_char(codepoint) {
        Mapping::Valid => output.push(codepoint),
        Mapping::Ignored => {},
        Mapping::Mapped(ref slice) => output.push_str(decode_slice(slice)),
        Mapping::Deviation(ref slice) => {
            if flags.transitional_processing {
                output.push_str(decode_slice(slice))
            } else {
                output.push(codepoint)
            }
        }
        Mapping::Disallowed => {
            errors.push(Error::DissallowedCharacter);
            output.push(codepoint);
        }
        Mapping::DisallowedStd3Valid => {
            if flags.use_std3_ascii_rules {
                errors.push(Error::DissallowedByStd3AsciiRules);
            }
            output.push(codepoint)
        }
        Mapping::DisallowedStd3Mapped(ref slice) => {
            if flags.use_std3_ascii_rules {
                errors.push(Error::DissallowedMappedInStd3);
            }
            output.push_str(decode_slice(slice))
        }
    }
}

// http://tools.ietf.org/html/rfc5893#section-2
fn passes_bidi(label: &str, is_bidi_domain: bool) -> bool {
    // Rule 0: Bidi Rules apply to Bidi Domain Names: a name with at least one RTL label.  A label
    // is RTL if it contains at least one character of bidi class R, AL or AN.
    if !is_bidi_domain {
        return true;
    }

    let mut chars = label.chars();
    let first_char_class = match chars.next() {
        Some(c) => bidi_class(c),
        None => return true, // empty string
    };

    match first_char_class {
        // LTR label
        BidiClass::L => {
            // Rule 5
            loop {
                match chars.next() {
                    Some(c) => {
                        if !matches!(bidi_class(c),
                                     BidiClass::L | BidiClass::EN |
                                     BidiClass::ES | BidiClass::CS |
                                     BidiClass::ET | BidiClass::ON |
                                     BidiClass::BN | BidiClass::NSM
                                    ) {
                            return false;
                        }
                    },
                    None => { break; },
                }
            }

            // Rule 6
            // must end in L or EN followed by 0 or more NSM
            let mut rev_chars = label.chars().rev();
            let mut last_non_nsm = rev_chars.next();
            loop {
                match last_non_nsm {
                    Some(c) if bidi_class(c) == BidiClass::NSM => {
                        last_non_nsm = rev_chars.next();
                        continue;
                    }
                    _ => { break; },
                }
            }
            match last_non_nsm {
                Some(c) if bidi_class(c) == BidiClass::L
                    || bidi_class(c) == BidiClass::EN => {},
                Some(_) => { return false; },
                _ => {}
            }

        }

        // RTL label
        BidiClass::R | BidiClass::AL => {
            let mut found_en = false;
            let mut found_an = false;

            // Rule 2
            loop {
                match chars.next() {
                    Some(c) => {
                        let char_class = bidi_class(c);

                        if char_class == BidiClass::EN {
                            found_en = true;
                        }
                        if char_class == BidiClass::AN {
                            found_an = true;
                        }

                        if !matches!(char_class, BidiClass::R | BidiClass::AL |
                                     BidiClass::AN | BidiClass::EN |
                                     BidiClass::ES | BidiClass::CS |
                                     BidiClass::ET | BidiClass::ON |
                                     BidiClass::BN | BidiClass::NSM) {
                            return false;
                        }
                    },
                    None => { break; },
                }
            }
            // Rule 3
            let mut rev_chars = label.chars().rev();
            let mut last = rev_chars.next();
            loop { // must end in L or EN followed by 0 or more NSM
                match last {
                    Some(c) if bidi_class(c) == BidiClass::NSM => {
                        last = rev_chars.next();
                        continue;
                    }
                    _ => { break; },
                }
            }
            match last {
                Some(c) if matches!(bidi_class(c), BidiClass::R | BidiClass::AL |
                                    BidiClass::EN | BidiClass::AN) => {},
                _ => { return false; }
            }

            // Rule 4
            if found_an && found_en {
                return false;
            }
        }

        // Rule 1: Should start with L or R/AL
        _ => {
            return false;
        }
    }

    return true;
}

/// http://www.unicode.org/reports/tr46/#Validity_Criteria
fn validate(label: &str, is_bidi_domain: bool, flags: Flags, errors: &mut Vec<Error>) {
    let first_char = label.chars().next();
    if first_char == None {
        // Empty string, pass
    }

    // V1: Must be in NFC form.
    else if label.nfc().ne(label.chars()) {
        errors.push(Error::ValidityCriteria);
    }

    // V2: No U+002D HYPHEN-MINUS in both third and fourth positions.
    //
    // NOTE: Spec says that the label must not contain a HYPHEN-MINUS character in both the
    // third and fourth positions. But nobody follows this criteria. See the spec issue below:
    // https://github.com/whatwg/url/issues/53
    //
    // TODO: Add *CheckHyphens* flag.

    // V3: neither begin nor end with a U+002D HYPHEN-MINUS
    else if label.starts_with("-") || label.ends_with("-") {
        errors.push(Error::ValidityCriteria);
    }

    // V4: not contain a U+002E FULL STOP
    //
    // Here, label can't contain '.' since the input is from .split('.')

    // V5: not begin with a GC=Mark
    else if is_combining_mark(first_char.unwrap()) {
        errors.push(Error::ValidityCriteria);
    }

    // V6: Check against Mapping Table
    else if label.chars().any(|c| match *find_char(c) {
        Mapping::Valid => false,
        Mapping::Deviation(_) => flags.transitional_processing,
        Mapping::DisallowedStd3Valid => flags.use_std3_ascii_rules,
        _ => true,
    }) {
        errors.push(Error::ValidityCriteria);
    }

    // V7: ContextJ rules
    //
    // TODO: Implement rules and add *CheckJoiners* flag.

    // V8: Bidi rules
    //
    // TODO: Add *CheckBidi* flag
    else if !passes_bidi(label, is_bidi_domain)
    {
        errors.push(Error::ValidityCriteria);
    }
}

/// http://www.unicode.org/reports/tr46/#Processing
fn processing(domain: &str, flags: Flags, errors: &mut Vec<Error>) -> String {
    let mut mapped = String::new();
    for c in domain.chars() {
        map_char(c, flags, &mut mapped, errors)
    }
    let normalized: String = mapped.nfc().collect();

    // Find out if it's a Bidi Domain Name
    //
    // First, check for literal bidi chars
    let mut is_bidi_domain = domain.chars().any(|c|
        matches!(bidi_class(c), BidiClass::R | BidiClass::AL | BidiClass::AN)
    );
    if !is_bidi_domain {
        // Then check for punycode-encoded bidi chars
        for label in normalized.split('.') {
            if label.starts_with(PUNYCODE_PREFIX) {
                match punycode::decode_to_string(&label[PUNYCODE_PREFIX.len()..]) {
                    Some(decoded_label) => {
                        if decoded_label.chars().any(|c|
                            matches!(bidi_class(c), BidiClass::R | BidiClass::AL | BidiClass::AN)
                        ) {
                            is_bidi_domain = true;
                        }
                    }
                    None => {
                        is_bidi_domain = true;
                    }
                }
            }
        }
    }

    let mut validated = String::new();
    let mut first = true;
    for label in normalized.split('.') {
        if !first {
            validated.push('.');
        }
        first = false;
        if label.starts_with(PUNYCODE_PREFIX) {
            match punycode::decode_to_string(&label[PUNYCODE_PREFIX.len()..]) {
                Some(decoded_label) => {
                    let flags = Flags { transitional_processing: false, ..flags };
                    validate(&decoded_label, is_bidi_domain, flags, errors);
                    validated.push_str(&decoded_label)
                }
                None => errors.push(Error::PunycodeError)
            }
        } else {
            validate(label, is_bidi_domain, flags, errors);
            validated.push_str(label)
        }
    }
    validated
}

#[derive(Copy, Clone)]
pub struct Flags {
   pub use_std3_ascii_rules: bool,
   pub transitional_processing: bool,
   pub verify_dns_length: bool,
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
enum Error {
    PunycodeError,
    ValidityCriteria,
    DissallowedByStd3AsciiRules,
    DissallowedMappedInStd3,
    DissallowedCharacter,
    TooLongForDns,
    TooShortForDns,
}

/// Errors recorded during UTS #46 processing.
///
/// This is opaque for now, only indicating the presence of at least one error.
/// More details may be exposed in the future.
#[derive(Debug)]
pub struct Errors(Vec<Error>);

/// http://www.unicode.org/reports/tr46/#ToASCII
pub fn to_ascii(domain: &str, flags: Flags) -> Result<String, Errors> {
    let mut errors = Vec::new();
    let mut result = String::new();
    let mut first = true;
    for label in processing(domain, flags, &mut errors).split('.') {
        if !first {
            result.push('.');
        }
        first = false;
        if label.is_ascii() {
            result.push_str(label);
        } else {
            match punycode::encode_str(label) {
                Some(x) => {
                    result.push_str(PUNYCODE_PREFIX);
                    result.push_str(&x);
                },
                None => errors.push(Error::PunycodeError)
            }
        }
    }

    if flags.verify_dns_length {
        let domain = if result.ends_with(".") { &result[..result.len()-1]  } else { &*result };
        if domain.len() < 1 || domain.split('.').any(|label| label.len() < 1) {
            errors.push(Error::TooShortForDns)
        }
        if domain.len() > 253 || domain.split('.').any(|label| label.len() > 63) {
            errors.push(Error::TooLongForDns)
        }
    }
    if errors.is_empty() {
        Ok(result)
    } else {
        Err(Errors(errors))
    }
}

/// http://www.unicode.org/reports/tr46/#ToUnicode
///
/// Only `use_std3_ascii_rules` is used in `flags`.
pub fn to_unicode(domain: &str, mut flags: Flags) -> (String, Result<(), Errors>) {
    flags.transitional_processing = false;
    let mut errors = Vec::new();
    let domain = processing(domain, flags, &mut errors);
    let errors = if errors.is_empty() {
        Ok(())
    } else {
        Err(Errors(errors))
    };
    (domain, errors)
}
<|endoftext|>


<commit_before><commit_msg>Enable 4x multisampling<commit_after><|endoftext|>


<commit_before>#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Foo {
    A(&'static str),
    _B,
    _C,
}

pub fn main() {
    let mut b = std::collections::BTreeSet::new();
    b.insert(Foo::A("\'"));
    b.insert(Foo::A("/="));
    b.insert(Foo::A("#"));
    b.insert(Foo::A("0o"));
    assert!(b.remove(&Foo::A("/=")));
    assert!(!b.remove(&Foo::A("/=")));
}
<commit_msg>test BTree a bit more<commit_after>use std::collections::{BTreeMap, BTreeSet};

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Foo {
    A(&'static str),
    _B,
    _C,
}

pub fn main() {
    let mut b = BTreeSet::new();
    b.insert(Foo::A("\'"));
    b.insert(Foo::A("/="));
    b.insert(Foo::A("#"));
    b.insert(Foo::A("0o"));
    assert!(b.remove(&Foo::A("/=")));
    assert!(!b.remove(&Foo::A("/=")));

    // Also test a lower-alignment type, where the NodeHeader overlaps with
    // the keys.
    let mut b = BTreeSet::new();
    b.insert(1024);
    b.insert(7);

    let mut b = BTreeMap::new();
    b.insert("bar", 1024);
    b.insert("baz", 7);
    for _val in b.iter_mut() {}
}
<|endoftext|>


<commit_before>#![crate_name = "uu_arch"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Smigle00 <smigle00@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate libc;

#[macro_use]
extern crate uucore;

use std::ffi::CStr;
use std::mem::uninitialized;
use uucore::c_types::utsname;

struct Arch {
    arch_name: String
}

extern {
    fn uname(uts: *mut utsname);
}

unsafe fn string_from_c_str(ptr: *const i8) -> String {
    String::from_utf8_lossy(CStr::from_ptr(ptr as *const std::os::raw::c_char).to_bytes()).to_string()
}

unsafe fn get_machine_arch() -> Arch {
    let mut uts: utsname = uninitialized();
    uname(&mut uts);
    Arch {
        arch_name: string_from_c_str(uts.machine.as_ptr()  as *const i8)
    }
}

static NAME: &'static str = "arch";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = uucore::coreopts::CoreOptions::new(NAME);
    let usage = opts.usage("Determine architecture name for current machine.");
    opts.help(format!("
{0} {1}

{0}

{2}
", NAME, VERSION, usage)).parse(args);

    let machine_arch = unsafe { get_machine_arch() };
    let mut output = String::new();
    output.push_str(machine_arch.arch_name.as_ref());
    println!("{}", output.trim());

    0
}
<commit_msg>arch: switch to using new coreopts syntax<commit_after>#![crate_name = "uu_arch"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Smigle00 <smigle00@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate libc;

#[macro_use]
extern crate uucore;

use std::ffi::CStr;
use std::mem::uninitialized;
use uucore::c_types::utsname;

static SYNTAX: &'static str = "";
static SUMMARY: &'static str = "Determine architecture name for current machine.";
static LONG_HELP: &'static str = "";

struct Arch {
    arch_name: String
}

extern {
    fn uname(uts: *mut utsname);
}

unsafe fn string_from_c_str(ptr: *const i8) -> String {
    String::from_utf8_lossy(CStr::from_ptr(ptr as *const std::os::raw::c_char).to_bytes()).to_string()
}

unsafe fn get_machine_arch() -> Arch {
    let mut uts: utsname = uninitialized();
    uname(&mut uts);
    Arch {
        arch_name: string_from_c_str(uts.machine.as_ptr()  as *const i8)
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    let machine_arch = unsafe { get_machine_arch() };
    let mut output = String::new();
    output.push_str(machine_arch.arch_name.as_ref());
    println!("{}", output.trim());

    0
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crypto;
use crypto::{CipherText, CipherTextRef, PlainTextRef};
use hash::Hash;
use hash::tree::HashRef;

use super::BlobError;
use super::ChunkRef;

use std::mem;

pub struct Blob {
    master_key: crypto::FixedKey,
    chunks: CipherText,
    footer: Vec<u8>,
    overhead: usize,
    max_len: usize,
}

impl Blob {
    pub fn new(max_len: usize) -> Blob {
        // TODO(jos): Plug an actual crypto key through somehow.
        let pubkey = crypto::sealed::desc::PublicKey::from_slice(&[215, 136, 80, 128, 158, 109,
                                                                   227, 141, 219, 63, 118, 91,
                                                                   123, 97, 1, 97, 65, 237, 62,
                                                                   171, 83, 159, 200, 11, 68,
                                                                   138, 40, 82, 24, 47, 187, 29])
            .unwrap();
        let seckey = crypto::sealed::desc::SecretKey::from_slice(&[94, 13, 181, 81, 97, 87, 76,
                                                                   37, 53, 92, 120, 232, 17, 126,
                                                                   234, 78, 12, 23, 141, 61, 40,
                                                                   10, 136, 127, 103, 192, 255,
                                                                   193, 142, 154, 101, 35])
            .unwrap();

        let master_key = crypto::FixedKey::new(pubkey, Some(seckey));

        Blob {
            master_key: master_key,
            chunks: CipherText::empty(),
            footer: Vec::with_capacity(max_len / 2),
            overhead: crypto::sealed::desc::overhead(),
            max_len: max_len,
        }
    }

    pub fn read_chunk(blob: &[u8], hash: &Hash, cref: &ChunkRef) -> Result<Vec<u8>, BlobError> {
        let ct = crypto::CipherTextRef::new(blob);
        Ok(try!(crypto::RefKey::unseal(hash, cref, ct)).into_vec())
    }

    pub fn upperbound_len(&self) -> usize {
        if self.chunks.len() == 0 {
            0
        } else {
            self.chunks.len() + self.footer.len() + self.overhead
        }
    }

    pub fn try_append(&mut self, chunk: &[u8], mut href: &mut HashRef) -> Result<(), ()> {
        let ct = crypto::RefKey::seal(&mut href, PlainTextRef::new(&chunk));

        href.persistent_ref.offset = self.chunks.len();
        let mut href_bytes = href.as_bytes();
        assert!(href_bytes.len() < 255);

        if self.upperbound_len() + 1 + href_bytes.len() + ct.len() >= self.max_len {
            if self.chunks.len() == 0 {
                panic!("Can never fit chunk of size {} in blob of size {}",
                       chunk.len(),
                       self.max_len);
            }
            return Err(());
        }

        self.chunks.append(ct);

        // Generate footer entry.
        self.footer.push(href_bytes.len() as u8);
        self.footer.append(&mut href_bytes);

        Ok(())
    }

    pub fn to_ciphertext(&mut self) -> Option<CipherText> {
        if self.chunks.len() == 0 {
            return None;
        }

        let footer = self.master_key.seal(PlainTextRef::new(&self.footer[..]));
        self.footer.truncate(0);

        assert!(self.chunks.len() + footer.len() <= self.max_len);
        let mut out = mem::replace(&mut self.chunks, CipherText::empty());
        out.random_pad_upto(self.max_len - footer.len());
        out.append(footer);

        // Everything has been reset. We are ready to go again.
        assert_eq!(0, self.chunks.len());
        assert_eq!(0, self.footer.len());

        Some(out)
    }

    pub fn refs_from_bytes(&self, bytes: &[u8]) -> Result<Vec<HashRef>, BlobError> {
        if bytes.len() == 0 {
            return Ok(Vec::new());
        }

        let (_rest, footer_vec) = try!(self.master_key.unseal(CipherTextRef::new(bytes)));
        let mut footer_pos = footer_vec.as_bytes();

        let mut hrefs = Vec::new();
        while footer_pos.len() > 0 {
            let len = footer_pos[0] as usize;
            assert!(footer_pos.len() > len);

            hrefs.push(try!(HashRef::from_bytes(&mut &footer_pos[1..1 + len])));
            footer_pos = &footer_pos[len + 1..];
        }

        Ok(hrefs)
    }
}
<commit_msg>Do not accept unauthenticated empty blobs.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crypto;
use crypto::{CipherText, CipherTextRef, PlainTextRef};
use hash::Hash;
use hash::tree::HashRef;

use super::BlobError;
use super::ChunkRef;

use std::mem;

pub struct Blob {
    master_key: crypto::FixedKey,
    chunks: CipherText,
    footer: Vec<u8>,
    overhead: usize,
    max_len: usize,
}

impl Blob {
    pub fn new(max_len: usize) -> Blob {
        // TODO(jos): Plug an actual crypto key through somehow.
        let pubkey = crypto::sealed::desc::PublicKey::from_slice(&[215, 136, 80, 128, 158, 109,
                                                                   227, 141, 219, 63, 118, 91,
                                                                   123, 97, 1, 97, 65, 237, 62,
                                                                   171, 83, 159, 200, 11, 68,
                                                                   138, 40, 82, 24, 47, 187, 29])
            .unwrap();
        let seckey = crypto::sealed::desc::SecretKey::from_slice(&[94, 13, 181, 81, 97, 87, 76,
                                                                   37, 53, 92, 120, 232, 17, 126,
                                                                   234, 78, 12, 23, 141, 61, 40,
                                                                   10, 136, 127, 103, 192, 255,
                                                                   193, 142, 154, 101, 35])
            .unwrap();

        let master_key = crypto::FixedKey::new(pubkey, Some(seckey));

        Blob {
            master_key: master_key,
            chunks: CipherText::empty(),
            footer: Vec::with_capacity(max_len / 2),
            overhead: crypto::sealed::desc::overhead(),
            max_len: max_len,
        }
    }

    pub fn read_chunk(blob: &[u8], hash: &Hash, cref: &ChunkRef) -> Result<Vec<u8>, BlobError> {
        let ct = crypto::CipherTextRef::new(blob);
        Ok(try!(crypto::RefKey::unseal(hash, cref, ct)).into_vec())
    }

    pub fn upperbound_len(&self) -> usize {
        if self.chunks.len() == 0 {
            0
        } else {
            self.chunks.len() + self.footer.len() + self.overhead
        }
    }

    pub fn try_append(&mut self, chunk: &[u8], mut href: &mut HashRef) -> Result<(), ()> {
        let ct = crypto::RefKey::seal(&mut href, PlainTextRef::new(&chunk));

        href.persistent_ref.offset = self.chunks.len();
        let mut href_bytes = href.as_bytes();
        assert!(href_bytes.len() < 255);

        if self.upperbound_len() + 1 + href_bytes.len() + ct.len() >= self.max_len {
            if self.chunks.len() == 0 {
                panic!("Can never fit chunk of size {} in blob of size {}",
                       chunk.len(),
                       self.max_len);
            }
            return Err(());
        }

        self.chunks.append(ct);

        // Generate footer entry.
        self.footer.push(href_bytes.len() as u8);
        self.footer.append(&mut href_bytes);

        Ok(())
    }

    pub fn to_ciphertext(&mut self) -> Option<CipherText> {
        if self.chunks.len() == 0 {
            return None;
        }

        let footer = self.master_key.seal(PlainTextRef::new(&self.footer[..]));
        self.footer.truncate(0);

        assert!(self.chunks.len() + footer.len() <= self.max_len);
        let mut out = mem::replace(&mut self.chunks, CipherText::empty());
        out.random_pad_upto(self.max_len - footer.len());
        out.append(footer);

        // Everything has been reset. We are ready to go again.
        assert_eq!(0, self.chunks.len());
        assert_eq!(0, self.footer.len());

        Some(out)
    }

    pub fn refs_from_bytes(&self, bytes: &[u8]) -> Result<Vec<HashRef>, BlobError> {
        let (_rest, footer_vec) = try!(self.master_key.unseal(CipherTextRef::new(bytes)));
        let mut footer_pos = footer_vec.as_bytes();

        let mut hrefs = Vec::new();
        while footer_pos.len() > 0 {
            let len = footer_pos[0] as usize;
            assert!(footer_pos.len() > len);

            hrefs.push(try!(HashRef::from_bytes(&mut &footer_pos[1..1 + len])));
            footer_pos = &footer_pos[len + 1..];
        }

        Ok(hrefs)
    }
}
<|endoftext|>


<commit_before>//! Defines the BSDF which acts as a container for composing the various BRDFs
//! and BTDFs that describe the surface's properties

use std::vec::Vec;
use std::cmp;
use collect::enum_set::EnumSet;

use linalg;
use linalg::{Normal, Vector, Point};
use film::Colorf;
use geometry::DifferentialGeometry;
use bxdf::{BxDF, BxDFType};

/// The BSDF contains the various BRDFs and BTDFs that describe the surface's properties
/// at some point. It also transforms incident and outgoing light directions into
/// shading space to make the BxDFs easier to implement.
/// TODO: We really need the memory pool. Each time we get the bsdf from a
/// material we need to allocate a decent amount of stuff since they each need
/// their own tangent, bitangent and differential geometry reference.
pub struct BSDF<'a> {
    /// The hit point
    pub p: Point,
    /// Shading normal, may be perturbed by bump mapping
    pub n: Normal,
    /// The actual geometry normal
    pub ng: Normal,
    /// Tangent vector for the surface
    pub tan: Vector,
    /// Bitangent vector for the surface
    pub bitan: Vector,
    /// Refractive index of the geometry
    pub eta: f32,
    /// TODO: Currently a Vec is safe to use but once in the memory pool it
    /// will leak since it won't be dropped. This would also migrate our BxDFs
    /// from Box<BxDF> to &BxDF. When unboxed traits land we can move to unboxed
    /// BxDFs here though.
    bxdfs: &'a Vec<Box<BxDF + Send + Sync>>,
}

impl<'a> BSDF<'a> {
    /// Create a new BSDF using the BxDFs passed to shade the differential geometry with
    /// refractive index `eta`
    pub fn new(bxdfs: &'a Vec<Box<BxDF + Send + Sync>>, eta: f32,
               dg: &DifferentialGeometry<'a>)
               -> BSDF<'a> {
        let n = dg.n.normalized();
        let bitan = dg.dp_du.normalized();
        let tan = linalg::cross(&n, &bitan);
        BSDF { p: dg.p, n: n, ng: dg.ng, tan: tan, bitan: bitan, bxdfs: bxdfs, eta: eta }
    }
    /// Return the total number of BxDFs
    pub fn num_bxdfs(&self) -> usize { self.bxdfs.len() }
    /// Return the number of BxDFs matching the flags
    pub fn num_matching(&self, flags: EnumSet<BxDFType>) -> usize {
        self.bxdfs.iter().filter(|ref x| x.matches(flags)).count()
    }
    /// Transform the vector from world space to shading space
    pub fn to_shading(&self, v: &Vector) -> Vector {
        Vector::new(linalg::dot(v, &self.bitan), linalg::dot(v, &self.tan),
                    linalg::dot(v, &self.n))
    }
    /// Transform the vectro from shading space to world space
    pub fn from_shading(&self, v: &Vector) -> Vector {
        Vector::new(self.bitan.x * v.x + self.tan.x * v.y + self.n.x * v.z,
                    self.bitan.y * v.x + self.tan.y * v.y + self.n.y * v.z,
                    self.bitan.z * v.x + self.tan.z * v.y + self.n.z * v.z)
    }
    /// Evaluate the BSDF for the outgoing and incident light directions
    /// `w_o` and `w_i` in world space, sampling the desired subset of BxDFs
    /// selected by the flags passed. `wo_world` and `wi_world` should point from
    /// the hit point in the outgoing and incident light directions respectively.
    pub fn eval(&self, wo_world: &Vector, wi_world: &Vector, mut flags: EnumSet<BxDFType>) -> Colorf {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        // Determine if we should evaluate reflection or transmission based on the
        // geometry normal and the light directions
        if linalg::dot(wo_world, &self.ng) * linalg::dot(wi_world, &self.ng) > 0.0 {
            flags.remove(&BxDFType::Transmission);
        } else {
            flags.remove(&BxDFType::Reflection);
        }
        // Find all matching BxDFs and add their contribution to the material's color
        self.bxdfs.iter().filter_map(|ref x| if x.matches(flags) { Some(x.eval(&w_o, &w_i)) } else { None })
            .fold(Colorf::broadcast(0.0), |x, y| x + y)
    }
    /// Sample a component of the BSDF to get an incident light direction for light
    /// leaving the surface along `w_o`.
    /// `samples` are the 3 random values to use when sampling a component of the BSDF
    /// and a the chosen BSDF
    /// Returns the color, direction, pdf and the type of BxDF that was sampled.
    pub fn sample(&self, wo_world: &Vector, flags: EnumSet<BxDFType>, samples: &[f32])
        -> (Colorf, Vector, f32, EnumSet<BxDFType>) {
        // TODO: Is there a better way to accept slices but require they be of some length?
        assert!(samples.len() > 2);

        let n_matching = self.num_matching(flags);
        if n_matching == 0 {
            return (Colorf::broadcast(0.0), Vector::broadcast(0.0), 0.0, EnumSet::new());
        }
        let comp = cmp::min((samples[0] * n_matching as f32) as usize, n_matching - 1);
        let bxdf = self.matching_at(comp, flags);
        let w_o = self.to_shading(wo_world);
        let (f, w_i, pdf) = bxdf.sample(&w_o, &samples[1..]);
        // TODO sample other mats if non-specular
        (f, self.from_shading(&w_i), pdf, bxdf.bxdf_type())
    }
    /// Compute the pdf for sampling the pair of incident and outgoing light directions for
    /// the BxDFs matching the flags set
    pub fn pdf(&self, wo_world: &Vector, wi_world: &Vector, flags: EnumSet<BxDFType>) -> f32 {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        let (pdf_val, n_comps) = self.bxdfs.iter()
            .filter_map(|ref x| if x.matches(flags) { Some(x.pdf(&w_o, &w_i)) } else { None })
            .fold((0.0, 0), |(p, n), y| (p + y, n + 1));
        if n_comps == 0 {
            0.0
        } else {
            pdf_val / n_comps as f32
        }
    }
    /// Get the `i`th BxDF that matches the flags passed. There should not be fewer than i
    /// BxDFs that match the flags
    fn matching_at(&self, i: usize, flags: EnumSet<BxDFType>) -> &Box<BxDF + Send + Sync> {
        let mut it = self.bxdfs.iter().filter(|ref x| x.matches(flags)).skip(i);
        match it.next() {
            Some(b) => b,
            None => panic!("Out of bounds index for BxDF type {:?}", flags)
        }
    }
}

<commit_msg>Was forgetting to account for other components in sampling<commit_after>//! Defines the BSDF which acts as a container for composing the various BRDFs
//! and BTDFs that describe the surface's properties

use std::vec::Vec;
use std::cmp;
use collect::enum_set::EnumSet;

use linalg;
use linalg::{Normal, Vector, Point};
use film::Colorf;
use geometry::DifferentialGeometry;
use bxdf::{BxDF, BxDFType};

/// The BSDF contains the various BRDFs and BTDFs that describe the surface's properties
/// at some point. It also transforms incident and outgoing light directions into
/// shading space to make the BxDFs easier to implement.
/// TODO: We really need the memory pool. Each time we get the bsdf from a
/// material we need to allocate a decent amount of stuff since they each need
/// their own tangent, bitangent and differential geometry reference.
pub struct BSDF<'a> {
    /// The hit point
    pub p: Point,
    /// Shading normal, may be perturbed by bump mapping
    pub n: Normal,
    /// The actual geometry normal
    pub ng: Normal,
    /// Tangent vector for the surface
    pub tan: Vector,
    /// Bitangent vector for the surface
    pub bitan: Vector,
    /// Refractive index of the geometry
    pub eta: f32,
    /// TODO: Currently a Vec is safe to use but once in the memory pool it
    /// will leak since it won't be dropped. This would also migrate our BxDFs
    /// from Box<BxDF> to &BxDF. When unboxed traits land we can move to unboxed
    /// BxDFs here though.
    bxdfs: &'a Vec<Box<BxDF + Send + Sync>>,
}

impl<'a> BSDF<'a> {
    /// Create a new BSDF using the BxDFs passed to shade the differential geometry with
    /// refractive index `eta`
    pub fn new(bxdfs: &'a Vec<Box<BxDF + Send + Sync>>, eta: f32,
               dg: &DifferentialGeometry<'a>)
               -> BSDF<'a> {
        let n = dg.n.normalized();
        let bitan = dg.dp_du.normalized();
        let tan = linalg::cross(&n, &bitan);
        BSDF { p: dg.p, n: n, ng: dg.ng, tan: tan, bitan: bitan, bxdfs: bxdfs, eta: eta }
    }
    /// Return the total number of BxDFs
    pub fn num_bxdfs(&self) -> usize { self.bxdfs.len() }
    /// Return the number of BxDFs matching the flags
    pub fn num_matching(&self, flags: EnumSet<BxDFType>) -> usize {
        self.bxdfs.iter().filter(|ref x| x.matches(flags)).count()
    }
    /// Transform the vector from world space to shading space
    pub fn to_shading(&self, v: &Vector) -> Vector {
        Vector::new(linalg::dot(v, &self.bitan), linalg::dot(v, &self.tan),
                    linalg::dot(v, &self.n))
    }
    /// Transform the vectro from shading space to world space
    pub fn from_shading(&self, v: &Vector) -> Vector {
        Vector::new(self.bitan.x * v.x + self.tan.x * v.y + self.n.x * v.z,
                    self.bitan.y * v.x + self.tan.y * v.y + self.n.y * v.z,
                    self.bitan.z * v.x + self.tan.z * v.y + self.n.z * v.z)
    }
    /// Evaluate the BSDF for the outgoing and incident light directions
    /// `w_o` and `w_i` in world space, sampling the desired subset of BxDFs
    /// selected by the flags passed. `wo_world` and `wi_world` should point from
    /// the hit point in the outgoing and incident light directions respectively.
    pub fn eval(&self, wo_world: &Vector, wi_world: &Vector, mut flags: EnumSet<BxDFType>) -> Colorf {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        // Determine if we should evaluate reflection or transmission based on the
        // geometry normal and the light directions
        if linalg::dot(wo_world, &self.ng) * linalg::dot(wi_world, &self.ng) > 0.0 {
            flags.remove(&BxDFType::Transmission);
        } else {
            flags.remove(&BxDFType::Reflection);
        }
        // Find all matching BxDFs and add their contribution to the material's color
        self.bxdfs.iter().filter_map(|ref x| if x.matches(flags) { Some(x.eval(&w_o, &w_i)) } else { None })
            .fold(Colorf::broadcast(0.0), |x, y| x + y)
    }
    /// Sample a component of the BSDF to get an incident light direction for light
    /// leaving the surface along `w_o`.
    /// `samples` are the 3 random values to use when sampling a component of the BSDF
    /// and a the chosen BSDF
    /// Returns the color, direction, pdf and the type of BxDF that was sampled.
    pub fn sample(&self, wo_world: &Vector, flags: EnumSet<BxDFType>, samples: &[f32])
        -> (Colorf, Vector, f32, EnumSet<BxDFType>) {
        // TODO: Is there a better way to accept slices but require they be of some length?
        assert!(samples.len() > 2);

        let n_matching = self.num_matching(flags);
        if n_matching == 0 {
            return (Colorf::broadcast(0.0), Vector::broadcast(0.0), 0.0, EnumSet::new());
        }
        let comp = cmp::min((samples[0] * n_matching as f32) as usize, n_matching - 1);
        let bxdf = self.matching_at(comp, flags);
        let w_o = self.to_shading(wo_world);
        let (f, w_i, pdf) = bxdf.sample(&w_o, &samples[1..]);
        let wi_world = self.from_shading(&w_i);

        if n_matching > 1 {
            if !bxdf.bxdf_type().contains(&BxDFType::Specular) {
                (self.eval(wo_world, &wi_world, flags), wi_world,
                self.pdf(wo_world, &wi_world, flags), bxdf.bxdf_type())
            } else {
                (f, wi_world, pdf / n_matching as f32, bxdf.bxdf_type())
            }
        } else {
            (f, wi_world, pdf, bxdf.bxdf_type())
        }
    }
    /// Compute the pdf for sampling the pair of incident and outgoing light directions for
    /// the BxDFs matching the flags set
    pub fn pdf(&self, wo_world: &Vector, wi_world: &Vector, flags: EnumSet<BxDFType>) -> f32 {
        let w_o = self.to_shading(wo_world);
        let w_i = self.to_shading(wi_world);
        let (pdf_val, n_comps) = self.bxdfs.iter()
            .filter_map(|ref x| if x.matches(flags) { Some(x.pdf(&w_o, &w_i)) } else { None })
            .fold((0.0, 0), |(p, n), y| (p + y, n + 1));
        if n_comps == 0 {
            0.0
        } else {
            pdf_val / n_comps as f32
        }
    }
    /// Get the `i`th BxDF that matches the flags passed. There should not be fewer than i
    /// BxDFs that match the flags
    fn matching_at(&self, i: usize, flags: EnumSet<BxDFType>) -> &Box<BxDF + Send + Sync> {
        let mut it = self.bxdfs.iter().filter(|ref x| x.matches(flags)).skip(i);
        match it.next() {
            Some(b) => b,
            None => panic!("Out of bounds index for BxDF type {:?}", flags)
        }
    }
}

<|endoftext|>


<commit_before>#![cfg_attr(test, deny(warnings))]
// While we're getting used to 2018:
#![warn(rust_2018_idioms)]
// Due to some of the default clippy lints being somewhat subjective and not
// necessarily an improvement, we prefer to not use them at this time.
#![allow(clippy::all)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::redundant_clone)]

use crate::core::shell::Verbosity::Verbose;
use crate::core::Shell;
use anyhow::Error;
use log::debug;
use std::fmt;

pub use crate::util::errors::{InternalError, VerboseError};
pub use crate::util::{indented_lines, CargoResult, CliError, CliResult, Config};

pub const CARGO_ENV: &str = "CARGO";

#[macro_use]
mod macros;

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the Git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than Cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "cargo {}.{}.{}", self.major, self.minor, self.patch)?;
        if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            if channel != "stable" {
                write!(f, "-{}", channel)?;
                let empty = String::new();
                write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
            }
        };

        if let Some(ref cfg) = self.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
            }
        };
        Ok(())
    }
}

pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
    debug!("exit_with_error; err={:?}", err);
    if let Some(ref err) = err.error {
        if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
            clap_err.exit()
        }
    }

    let CliError { error, exit_code } = err;
    if let Some(error) = error {
        display_error(&error, shell);
    }

    std::process::exit(exit_code)
}

/// Displays an error, and all its causes, to stderr.
pub fn display_error(err: &Error, shell: &mut Shell) {
    debug!("display_error; err={:?}", err);
    let has_verbose = _display_error(err, shell, true);
    if has_verbose {
        drop(writeln!(
            shell.err(),
            "\nTo learn more, run the command again with --verbose."
        ));
    }
    if err
        .chain()
        .any(|e| e.downcast_ref::<InternalError>().is_some())
    {
        drop(shell.note("this is an unexpected cargo internal error"));
        drop(
            shell.note(
                "we would appreciate a bug report: https://github.com/rust-lang/cargo/issues/",
            ),
        );
        drop(shell.note(format!("{}", version())));
        // Once backtraces are stabilized, this should print out a backtrace
        // if it is available.
    }
}

/// Displays a warning, with an error object providing detailed information
/// and context.
pub fn display_warning_with_error(warning: &str, err: &Error, shell: &mut Shell) {
    drop(shell.warn(warning));
    drop(writeln!(shell.err()));
    _display_error(err, shell, false);
}

fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool {
    let verbosity = shell.verbosity();
    let is_verbose = |e: &(dyn std::error::Error + 'static)| -> bool {
        verbosity != Verbose && e.downcast_ref::<VerboseError>().is_some()
    };
    // Generally the top error shouldn't be verbose, but check it anyways.
    if is_verbose(err.as_ref()) {
        return true;
    }
    if as_err {
        drop(shell.error(&err));
    } else {
        drop(writeln!(shell.err(), "{}", err));
    }
    for cause in err.chain().skip(1) {
        // If we're not in verbose mode then print remaining errors until one
        // marked as `VerboseError` appears.
        if is_verbose(cause) {
            return true;
        }
        drop(writeln!(shell.err(), "\nCaused by:"));
        drop(write!(
            shell.err(),
            "{}",
            indented_lines(&cause.to_string())
        ));
    }
    false
}

pub fn version() -> VersionInfo {
    macro_rules! option_env_str {
        ($name:expr) => {
            option_env!($name).map(|s| s.to_string())
        };
    }

    // So this is pretty horrible...
    // There are two versions at play here:
    //   - version of cargo-the-binary, which you see when you type `cargo --version`
    //   - version of cargo-the-library, which you download from crates.io for use
    //     in your packages.
    //
    // We want to make the `binary` version the same as the corresponding Rust/rustc release.
    // At the same time, we want to keep the library version at `0.x`, because Cargo as
    // a library is (and probably will always be) unstable.
    //
    // Historically, Cargo used the same version number for both the binary and the library.
    // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w.
    // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes
    // of `cargo --version`.
    let major = 1;
    let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap() - 1;
    let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap();

    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info = option_env!("CFG_COMMIT_HASH").map(|s| CommitInfo {
                commit_hash: s.to_string(),
                short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
            });
            VersionInfo {
                major,
                minor,
                patch,
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: Some(CfgInfo {
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info,
                }),
            }
        }
        // We are being compiled by Cargo itself.
        None => VersionInfo {
            major,
            minor,
            patch,
            pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
            cfg_info: None,
        },
    }
}
<commit_msg>Update 2018 idioms comment.<commit_after>// For various reasons, some idioms are still allow'ed, but we would like to
// test and enforce them.
#![warn(rust_2018_idioms)]
#![cfg_attr(test, deny(warnings))]
// Due to some of the default clippy lints being somewhat subjective and not
// necessarily an improvement, we prefer to not use them at this time.
#![allow(clippy::all)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::redundant_clone)]

use crate::core::shell::Verbosity::Verbose;
use crate::core::Shell;
use anyhow::Error;
use log::debug;
use std::fmt;

pub use crate::util::errors::{InternalError, VerboseError};
pub use crate::util::{indented_lines, CargoResult, CliError, CliResult, Config};

pub const CARGO_ENV: &str = "CARGO";

#[macro_use]
mod macros;

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the Git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than Cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "cargo {}.{}.{}", self.major, self.minor, self.patch)?;
        if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            if channel != "stable" {
                write!(f, "-{}", channel)?;
                let empty = String::new();
                write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
            }
        };

        if let Some(ref cfg) = self.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
            }
        };
        Ok(())
    }
}

pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
    debug!("exit_with_error; err={:?}", err);
    if let Some(ref err) = err.error {
        if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
            clap_err.exit()
        }
    }

    let CliError { error, exit_code } = err;
    if let Some(error) = error {
        display_error(&error, shell);
    }

    std::process::exit(exit_code)
}

/// Displays an error, and all its causes, to stderr.
pub fn display_error(err: &Error, shell: &mut Shell) {
    debug!("display_error; err={:?}", err);
    let has_verbose = _display_error(err, shell, true);
    if has_verbose {
        drop(writeln!(
            shell.err(),
            "\nTo learn more, run the command again with --verbose."
        ));
    }
    if err
        .chain()
        .any(|e| e.downcast_ref::<InternalError>().is_some())
    {
        drop(shell.note("this is an unexpected cargo internal error"));
        drop(
            shell.note(
                "we would appreciate a bug report: https://github.com/rust-lang/cargo/issues/",
            ),
        );
        drop(shell.note(format!("{}", version())));
        // Once backtraces are stabilized, this should print out a backtrace
        // if it is available.
    }
}

/// Displays a warning, with an error object providing detailed information
/// and context.
pub fn display_warning_with_error(warning: &str, err: &Error, shell: &mut Shell) {
    drop(shell.warn(warning));
    drop(writeln!(shell.err()));
    _display_error(err, shell, false);
}

fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool {
    let verbosity = shell.verbosity();
    let is_verbose = |e: &(dyn std::error::Error + 'static)| -> bool {
        verbosity != Verbose && e.downcast_ref::<VerboseError>().is_some()
    };
    // Generally the top error shouldn't be verbose, but check it anyways.
    if is_verbose(err.as_ref()) {
        return true;
    }
    if as_err {
        drop(shell.error(&err));
    } else {
        drop(writeln!(shell.err(), "{}", err));
    }
    for cause in err.chain().skip(1) {
        // If we're not in verbose mode then print remaining errors until one
        // marked as `VerboseError` appears.
        if is_verbose(cause) {
            return true;
        }
        drop(writeln!(shell.err(), "\nCaused by:"));
        drop(write!(
            shell.err(),
            "{}",
            indented_lines(&cause.to_string())
        ));
    }
    false
}

pub fn version() -> VersionInfo {
    macro_rules! option_env_str {
        ($name:expr) => {
            option_env!($name).map(|s| s.to_string())
        };
    }

    // So this is pretty horrible...
    // There are two versions at play here:
    //   - version of cargo-the-binary, which you see when you type `cargo --version`
    //   - version of cargo-the-library, which you download from crates.io for use
    //     in your packages.
    //
    // We want to make the `binary` version the same as the corresponding Rust/rustc release.
    // At the same time, we want to keep the library version at `0.x`, because Cargo as
    // a library is (and probably will always be) unstable.
    //
    // Historically, Cargo used the same version number for both the binary and the library.
    // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w.
    // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes
    // of `cargo --version`.
    let major = 1;
    let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap() - 1;
    let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap();

    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info = option_env!("CFG_COMMIT_HASH").map(|s| CommitInfo {
                commit_hash: s.to_string(),
                short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
            });
            VersionInfo {
                major,
                minor,
                patch,
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: Some(CfgInfo {
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info,
                }),
            }
        }
        // We are being compiled by Cargo itself.
        None => VersionInfo {
            major,
            minor,
            patch,
            pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
            cfg_info: None,
        },
    }
}
<|endoftext|>