<commit_before>//! Implementations of things like `Eq` for fixed-length arrays
//! up to a certain length. Eventually we should able to generalize
//! to all lengths.
//!
//! *[See also the array primitive type](../../std/primitive.array.html).*

#![stable(feature = "core_array", since = "1.36.0")]

use crate::borrow::{Borrow, BorrowMut};
use crate::cmp::Ordering;
use crate::convert::{Infallible, TryFrom};
use crate::fmt;
use crate::hash::{Hash, self};
use crate::marker::Unsize;
use crate::slice::{Iter, IterMut};

/// Utility trait implemented only on arrays of fixed size
///
/// This trait can be used to implement other traits on fixed-size arrays
/// without causing much metadata bloat.
///
/// The trait is marked unsafe in order to restrict implementors to fixed-size
/// arrays. User of this trait can assume that implementors have the exact
/// layout in memory of a fixed size array (for example, for unsafe
/// initialization).
///
/// Note that the traits AsRef and AsMut provide similar methods for types that
/// may not be fixed-size arrays. Implementors should prefer those traits
/// instead.
#[unstable(feature = "fixed_size_array", issue = "27778")]
pub unsafe trait FixedSizeArray<T> {
    /// Converts the array to immutable slice
    #[unstable(feature = "fixed_size_array", issue = "27778")]
    fn as_slice(&self) -> &[T];
    /// Converts the array to mutable slice
    #[unstable(feature = "fixed_size_array", issue = "27778")]
    fn as_mut_slice(&mut self) -> &mut [T];
}

#[unstable(feature = "fixed_size_array", issue = "27778")]
unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A {
    #[inline]
    fn as_slice(&self) -> &[T] {
        self
    }
    #[inline]
    fn as_mut_slice(&mut self) -> &mut [T] {
        self
    }
}

/// The error type returned when a conversion from a slice to an array fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromSliceError(());

#[stable(feature = "core_array", since = "1.36.0")]
impl fmt::Display for TryFromSliceError {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.__description(), f)
    }
}

impl TryFromSliceError {
    #[unstable(feature = "array_error_internals",
           reason = "available through Error trait and this method should not \
                     be exposed publicly",
           issue = "0")]
    #[inline]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        "could not convert slice to array"
    }
}

#[stable(feature = "try_from_slice_error", since = "1.36.0")]
impl From<Infallible> for TryFromSliceError {
    fn from(x: Infallible) -> TryFromSliceError {
        match x {}
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, const N: usize> AsRef<[T]> for [T; N]
where
    [T; N]: LengthAtMost32,
{
    #[inline]
    fn as_ref(&self) -> &[T] {
        &self[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, const N: usize> AsMut<[T]> for [T; N]
where
    [T; N]: LengthAtMost32,
{
    #[inline]
    fn as_mut(&mut self) -> &mut [T] {
        &mut self[..]
    }
}

#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T, const N: usize> Borrow<[T]> for [T; N]
where
    [T; N]: LengthAtMost32,
{
    fn borrow(&self) -> &[T] {
        self
    }
}

#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T, const N: usize> BorrowMut<[T]> for [T; N]
where
    [T; N]: LengthAtMost32,
{
    fn borrow_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl<T, const N: usize> TryFrom<&[T]> for [T; N]
where
    T: Copy,
    [T; N]: LengthAtMost32,
{
    type Error = TryFromSliceError;

    fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> {
        <&Self>::try_from(slice).map(|r| *r)
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N]
where
    [T; N]: LengthAtMost32,
{
    type Error = TryFromSliceError;

    fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> {
        if slice.len() == N {
            let ptr = slice.as_ptr() as *const [T; N];
            unsafe { Ok(&*ptr) }
        } else {
            Err(TryFromSliceError(()))
        }
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N]
where
    [T; N]: LengthAtMost32,
{
    type Error = TryFromSliceError;

    fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> {
        if slice.len() == N {
            let ptr = slice.as_mut_ptr() as *mut [T; N];
            unsafe { Ok(&mut *ptr) }
        } else {
            Err(TryFromSliceError(()))
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash, const N: usize> Hash for [T; N]
where
    [T; N]: LengthAtMost32,
{
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        Hash::hash(&self[..], state)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N]
where
    [T; N]: LengthAtMost32,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&&self[..], f)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, const N: usize> IntoIterator for &'a [T; N]
where
    [T; N]: LengthAtMost32,
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N]
where
    [T; N]: LengthAtMost32,
{
    type Item = &'a mut T;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> IterMut<'a, T> {
        self.iter_mut()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
where
    A: PartialEq<B>,
    [A; N]: LengthAtMost32,
    [B; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[B; N]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[B; N]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[B]> for [A; N]
where
    A: PartialEq<B>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[B]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[B]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[A; N]> for [B]
where
    B: PartialEq<A>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[A; N]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[A; N]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N]
where
    A: PartialEq<B>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &&'b [B]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &&'b [B]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B]
where
    B: PartialEq<A>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[A; N]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[A; N]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N]
where
    A: PartialEq<B>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &&'b mut [B]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &&'b mut [B]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B]
where
    B: PartialEq<A>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[A; N]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[A; N]) -> bool {
        self[..] != other[..]
    }
}

// NOTE: some less important impls are omitted to reduce code bloat
// __impl_slice_eq2! { [A; $N], &'b [B; $N] }
// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq, const N: usize> Eq for [T; N] where [T; N]: LengthAtMost32 {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd, const N: usize> PartialOrd for [T; N]
where
    [T; N]: LengthAtMost32,
{
    #[inline]
    fn partial_cmp(&self, other: &[T; N]) -> Option<Ordering> {
        PartialOrd::partial_cmp(&&self[..], &&other[..])
    }
    #[inline]
    fn lt(&self, other: &[T; N]) -> bool {
        PartialOrd::lt(&&self[..], &&other[..])
    }
    #[inline]
    fn le(&self, other: &[T; N]) -> bool {
        PartialOrd::le(&&self[..], &&other[..])
    }
    #[inline]
    fn ge(&self, other: &[T; N]) -> bool {
        PartialOrd::ge(&&self[..], &&other[..])
    }
    #[inline]
    fn gt(&self, other: &[T; N]) -> bool {
        PartialOrd::gt(&&self[..], &&other[..])
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord, const N: usize> Ord for [T; N]
where
    [T; N]: LengthAtMost32,
{
    #[inline]
    fn cmp(&self, other: &[T; N]) -> Ordering {
        Ord::cmp(&&self[..], &&other[..])
    }
}

/// Implemented for lengths where trait impls are allowed on arrays in core/std
#[rustc_on_unimplemented(
    message="arrays only have std trait implementations for lengths 0..=32",
)]
#[unstable(feature = "const_generic_impls_guard", issue = "0",
    reason = "will never be stable, just a temporary step until const generics are stable")]
pub trait LengthAtMost32 {}

macro_rules! array_impls {
    ($($N:literal)+) => {
        $(
            #[unstable(feature = "const_generic_impls_guard", issue = "0")]
            impl<T> LengthAtMost32 for [T; $N] {}
        )+
    }
}

array_impls! {
     0  1  2  3  4  5  6  7  8  9
    10 11 12 13 14 15 16 17 18 19
    20 21 22 23 24 25 26 27 28 29
    30 31 32
}

// The Default impls cannot be generated using the array_impls! macro because
// they require array literals.

macro_rules! array_impl_default {
    {$n:expr, $t:ident $($ts:ident)*} => {
        #[stable(since = "1.4.0", feature = "array_default")]
        impl<T> Default for [T; $n] where T: Default {
            fn default() -> [T; $n] {
                [$t::default(), $($ts::default()),*]
            }
        }
        array_impl_default!{($n - 1), $($ts)*}
    };
    {$n:expr,} => {
        #[stable(since = "1.4.0", feature = "array_default")]
        impl<T> Default for [T; $n] {
            fn default() -> [T; $n] { [] }
        }
    };
}

array_impl_default!{32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T}
<commit_msg>FixedSizeArray: Add missing links in doc comments.<commit_after>//! Implementations of things like `Eq` for fixed-length arrays
//! up to a certain length. Eventually we should able to generalize
//! to all lengths.
//!
//! *[See also the array primitive type](../../std/primitive.array.html).*

#![stable(feature = "core_array", since = "1.36.0")]

use crate::borrow::{Borrow, BorrowMut};
use crate::cmp::Ordering;
use crate::convert::{Infallible, TryFrom};
use crate::fmt;
use crate::hash::{Hash, self};
use crate::marker::Unsize;
use crate::slice::{Iter, IterMut};

/// Utility trait implemented only on arrays of fixed size
///
/// This trait can be used to implement other traits on fixed-size arrays
/// without causing much metadata bloat.
///
/// The trait is marked unsafe in order to restrict implementors to fixed-size
/// arrays. User of this trait can assume that implementors have the exact
/// layout in memory of a fixed size array (for example, for unsafe
/// initialization).
///
/// Note that the traits [`AsRef`] and [`AsMut`] provide similar methods for types that
/// may not be fixed-size arrays. Implementors should prefer those traits
/// instead.
///
/// [`AsRef`]: ../convert/trait.AsRef.html
/// [`AsMut`]: ../convert/trait.AsMut.html
#[unstable(feature = "fixed_size_array", issue = "27778")]
pub unsafe trait FixedSizeArray<T> {
    /// Converts the array to immutable slice
    #[unstable(feature = "fixed_size_array", issue = "27778")]
    fn as_slice(&self) -> &[T];
    /// Converts the array to mutable slice
    #[unstable(feature = "fixed_size_array", issue = "27778")]
    fn as_mut_slice(&mut self) -> &mut [T];
}

#[unstable(feature = "fixed_size_array", issue = "27778")]
unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A {
    #[inline]
    fn as_slice(&self) -> &[T] {
        self
    }
    #[inline]
    fn as_mut_slice(&mut self) -> &mut [T] {
        self
    }
}

/// The error type returned when a conversion from a slice to an array fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromSliceError(());

#[stable(feature = "core_array", since = "1.36.0")]
impl fmt::Display for TryFromSliceError {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.__description(), f)
    }
}

impl TryFromSliceError {
    #[unstable(feature = "array_error_internals",
           reason = "available through Error trait and this method should not \
                     be exposed publicly",
           issue = "0")]
    #[inline]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        "could not convert slice to array"
    }
}

#[stable(feature = "try_from_slice_error", since = "1.36.0")]
impl From<Infallible> for TryFromSliceError {
    fn from(x: Infallible) -> TryFromSliceError {
        match x {}
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, const N: usize> AsRef<[T]> for [T; N]
where
    [T; N]: LengthAtMost32,
{
    #[inline]
    fn as_ref(&self) -> &[T] {
        &self[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, const N: usize> AsMut<[T]> for [T; N]
where
    [T; N]: LengthAtMost32,
{
    #[inline]
    fn as_mut(&mut self) -> &mut [T] {
        &mut self[..]
    }
}

#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T, const N: usize> Borrow<[T]> for [T; N]
where
    [T; N]: LengthAtMost32,
{
    fn borrow(&self) -> &[T] {
        self
    }
}

#[stable(feature = "array_borrow", since = "1.4.0")]
impl<T, const N: usize> BorrowMut<[T]> for [T; N]
where
    [T; N]: LengthAtMost32,
{
    fn borrow_mut(&mut self) -> &mut [T] {
        self
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl<T, const N: usize> TryFrom<&[T]> for [T; N]
where
    T: Copy,
    [T; N]: LengthAtMost32,
{
    type Error = TryFromSliceError;

    fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> {
        <&Self>::try_from(slice).map(|r| *r)
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N]
where
    [T; N]: LengthAtMost32,
{
    type Error = TryFromSliceError;

    fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> {
        if slice.len() == N {
            let ptr = slice.as_ptr() as *const [T; N];
            unsafe { Ok(&*ptr) }
        } else {
            Err(TryFromSliceError(()))
        }
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N]
where
    [T; N]: LengthAtMost32,
{
    type Error = TryFromSliceError;

    fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> {
        if slice.len() == N {
            let ptr = slice.as_mut_ptr() as *mut [T; N];
            unsafe { Ok(&mut *ptr) }
        } else {
            Err(TryFromSliceError(()))
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash, const N: usize> Hash for [T; N]
where
    [T; N]: LengthAtMost32,
{
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        Hash::hash(&self[..], state)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N]
where
    [T; N]: LengthAtMost32,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&&self[..], f)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, const N: usize> IntoIterator for &'a [T; N]
where
    [T; N]: LengthAtMost32,
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Iter<'a, T> {
        self.iter()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N]
where
    [T; N]: LengthAtMost32,
{
    type Item = &'a mut T;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> IterMut<'a, T> {
        self.iter_mut()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
where
    A: PartialEq<B>,
    [A; N]: LengthAtMost32,
    [B; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[B; N]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[B; N]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[B]> for [A; N]
where
    A: PartialEq<B>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[B]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[B]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[A; N]> for [B]
where
    B: PartialEq<A>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[A; N]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[A; N]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N]
where
    A: PartialEq<B>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &&'b [B]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &&'b [B]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B]
where
    B: PartialEq<A>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[A; N]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[A; N]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N]
where
    A: PartialEq<B>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &&'b mut [B]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &&'b mut [B]) -> bool {
        self[..] != other[..]
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B]
where
    B: PartialEq<A>,
    [A; N]: LengthAtMost32,
{
    #[inline]
    fn eq(&self, other: &[A; N]) -> bool {
        self[..] == other[..]
    }
    #[inline]
    fn ne(&self, other: &[A; N]) -> bool {
        self[..] != other[..]
    }
}

// NOTE: some less important impls are omitted to reduce code bloat
// __impl_slice_eq2! { [A; $N], &'b [B; $N] }
// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq, const N: usize> Eq for [T; N] where [T; N]: LengthAtMost32 {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd, const N: usize> PartialOrd for [T; N]
where
    [T; N]: LengthAtMost32,
{
    #[inline]
    fn partial_cmp(&self, other: &[T; N]) -> Option<Ordering> {
        PartialOrd::partial_cmp(&&self[..], &&other[..])
    }
    #[inline]
    fn lt(&self, other: &[T; N]) -> bool {
        PartialOrd::lt(&&self[..], &&other[..])
    }
    #[inline]
    fn le(&self, other: &[T; N]) -> bool {
        PartialOrd::le(&&self[..], &&other[..])
    }
    #[inline]
    fn ge(&self, other: &[T; N]) -> bool {
        PartialOrd::ge(&&self[..], &&other[..])
    }
    #[inline]
    fn gt(&self, other: &[T; N]) -> bool {
        PartialOrd::gt(&&self[..], &&other[..])
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord, const N: usize> Ord for [T; N]
where
    [T; N]: LengthAtMost32,
{
    #[inline]
    fn cmp(&self, other: &[T; N]) -> Ordering {
        Ord::cmp(&&self[..], &&other[..])
    }
}

/// Implemented for lengths where trait impls are allowed on arrays in core/std
#[rustc_on_unimplemented(
    message="arrays only have std trait implementations for lengths 0..=32",
)]
#[unstable(feature = "const_generic_impls_guard", issue = "0",
    reason = "will never be stable, just a temporary step until const generics are stable")]
pub trait LengthAtMost32 {}

macro_rules! array_impls {
    ($($N:literal)+) => {
        $(
            #[unstable(feature = "const_generic_impls_guard", issue = "0")]
            impl<T> LengthAtMost32 for [T; $N] {}
        )+
    }
}

array_impls! {
     0  1  2  3  4  5  6  7  8  9
    10 11 12 13 14 15 16 17 18 19
    20 21 22 23 24 25 26 27 28 29
    30 31 32
}

// The Default impls cannot be generated using the array_impls! macro because
// they require array literals.

macro_rules! array_impl_default {
    {$n:expr, $t:ident $($ts:ident)*} => {
        #[stable(since = "1.4.0", feature = "array_default")]
        impl<T> Default for [T; $n] where T: Default {
            fn default() -> [T; $n] {
                [$t::default(), $($ts::default()),*]
            }
        }
        array_impl_default!{($n - 1), $($ts)*}
    };
    {$n:expr,} => {
        #[stable(since = "1.4.0", feature = "array_default")]
        impl<T> Default for [T; $n] {
            fn default() -> [T; $n] { [] }
        }
    };
}

array_impl_default!{32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T}
<|endoftext|>


<commit_before>use library::*;
use super::general::IsWidget;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TypeKind {
    Simple,     //coded with from_glib
    Pointer,    //coded with from_glib_xxx
    Object,
    Interface,
    Widget,     //coded with Widget::from_glib_xxx
    Enumeration,//coded without conversion
    Unknown,
}

impl Default for TypeKind {
    fn default() -> Self { TypeKind::Unknown }
}

pub trait ToTypeKind {
    fn to_type_kind(&self, library: &Library) -> TypeKind;
}

impl ToTypeKind for Type {
    fn to_type_kind(&self, library: &Library) -> TypeKind {
        match self {
            &Type::Fundamental(_) => TypeKind::Simple,
            &Type::Enumeration(_) => TypeKind::Enumeration,
            &Type::Interface(_) => TypeKind::Interface,
            &Type::Class(ref klass) => {
                if klass.is_widget(&library) { TypeKind::Widget } else { TypeKind::Object }
            },
            _ => TypeKind::Unknown,
        }
    }
}
<commit_msg>Separate type kinds for library::Fundamental<commit_after>use library::*;
use super::general::IsWidget;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TypeKind {
    Simple,     //coded with from_glib
    Pointer,    //coded with from_glib_xxx
    Object,
    Interface,
    Widget,     //coded with Widget::from_glib_xxx
    Enumeration,//coded without conversion
    Unknown,
}

impl Default for TypeKind {
    fn default() -> Self { TypeKind::Unknown }
}

pub trait ToTypeKind {
    fn to_type_kind(&self, library: &Library) -> TypeKind;
}

impl ToTypeKind for Fundamental {
    fn to_type_kind(&self, _library: &Library) -> TypeKind {
        use library::Fundamental::*;
        match self {
            &Boolean => TypeKind::Simple,
            &Int8 => TypeKind::Simple,
            &UInt8 => TypeKind::Simple,
            &Int16 => TypeKind::Simple,
            &UInt16 => TypeKind::Simple,
            &Int32 => TypeKind::Simple,
            &UInt32 => TypeKind::Simple,
            &Int64 => TypeKind::Simple,
            &UInt64 => TypeKind::Simple,
            &Char => TypeKind::Simple,
            &UChar => TypeKind::Simple,
            &Int => TypeKind::Simple,
            &UInt => TypeKind::Simple,
            &Long => TypeKind::Simple,
            &ULong => TypeKind::Simple,
            &Size => TypeKind::Simple,
            &SSize => TypeKind::Simple,
            &Float => TypeKind::Simple,
            &Double => TypeKind::Simple,
            &UniChar => TypeKind::Unknown,
            &Pointer => TypeKind::Pointer,
            &VarArgs => TypeKind::Unknown,
            &Utf8 => TypeKind::Pointer,
            &Filename => TypeKind::Pointer,
            &Type => TypeKind::Enumeration,
            &None => TypeKind::Unknown,
            &Unsupported => TypeKind::Unknown,
        }
    }
}

impl ToTypeKind for Type {
    fn to_type_kind(&self, library: &Library) -> TypeKind {
        match self {
            &Type::Fundamental(fund) => fund.to_type_kind(library),
            &Type::Enumeration(_) => TypeKind::Enumeration,
            &Type::Interface(_) => TypeKind::Interface,
            &Type::Class(ref klass) => {
                if klass.is_widget(&library) { TypeKind::Widget } else { TypeKind::Object }
            },
            _ => TypeKind::Unknown,
        }
    }
}
<|endoftext|>


<commit_before>//! `Ports` are the IO channels for a `Node`
//!
//! They can be used as a `Source` and `Destination` for certain `Instruction`s.

/// A `Port` can be read from and write to
#[derive(Debug,PartialEq,Eq)]
pub struct Port {
    input: Vec<i32>,
    output: Vec<i32>,
}

/// The result of reading from a `Port`
#[derive(Debug)]
pub enum PortReadResult {
    /// Success
    Success(Port, i32),
    /// Failure
    Failure
}

impl Port {
    /// Create a port with a number of readable values
    pub fn new(input: Vec<i32>) -> Port {
        Port { input: input, output: vec![] }
    }

    fn with(input: Vec<i32>, output: Vec<i32>) -> Port {
        Port { input: input, output: output }
    }

    /// Read from this `Port`. Will return a `PortReadResult::Success` when a
    /// value is available, otherwise a `PortReadResult::Failure`
    pub fn read(&self) -> PortReadResult {
        if self.input.len() > 0 {
            let mut result_input = vec![];
            for index in 1..self.input.len() {
                result_input.push(self.input[index]);
            }
            PortReadResult::Success(Port::with(result_input, vec![]), self.input[0])
        } else {
            PortReadResult::Failure
        }
    }

    /// Write to this `Port`. Will always succeed and return the Port as it is
    /// changed by the write
    pub fn write(&self, value: i32) -> Port {
        let mut result_input = vec![];
        for index in 0..self.input.len() {
            result_input.push(self.input[index]);
        }
        let mut result_output = vec![];
        for index in 0..self.output.len() {
            result_output.push(self.output[index]);
        }
        result_output.push(value);
        Port::with(result_input, result_output)
    }
}

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

    #[test]
    fn read_from_a_port_should_work_correctly() {
        let port: Port = Port::new(vec![0, 1, 2]);

        match port.read() {
            PortReadResult::Success(next_port, value) => {
                assert_eq!(0, value);
                assert_eq!(Port::with(vec![1,2], vec![]), next_port);
            },
            PortReadResult::Failure => panic!(),

        }
    }

    #[test]
    fn write_to_a_port_should_work_correctly() {
        let port: Port = Port::with(vec![1, 2], vec![3]);

        let next_port = port.write(4);

        assert_eq!(Port::with(vec![1, 2], vec![3, 4]), next_port);
    }
}
<commit_msg>Clone a port<commit_after>//! `Ports` are the IO channels for a `Node`
//!
//! They can be used as a `Source` and `Destination` for certain `Instruction`s.

/// A `Port` can be read from and write to
#[derive(Debug,PartialEq,Eq,Clone)]
pub struct Port {
    input: Vec<i32>,
    output: Vec<i32>,
}

/// The result of reading from a `Port`
#[derive(Debug)]
pub enum PortReadResult {
    /// Success
    Success(Port, i32),
    /// Failure
    Failure
}

impl Port {
    /// Create a port with a number of readable values
    pub fn new(input: Vec<i32>) -> Port {
        Port { input: input, output: vec![] }
    }

    fn with(input: Vec<i32>, output: Vec<i32>) -> Port {
        Port { input: input, output: output }
    }

    /// Read from this `Port`. Will return a `PortReadResult::Success` when a
    /// value is available, otherwise a `PortReadResult::Failure`
    pub fn read(&self) -> PortReadResult {
        if self.input.len() > 0 {
            let mut result_input = vec![];
            for index in 1..self.input.len() {
                result_input.push(self.input[index]);
            }
            PortReadResult::Success(Port::with(result_input, vec![]), self.input[0])
        } else {
            PortReadResult::Failure
        }
    }

    /// Write to this `Port`. Will always succeed and return the Port as it is
    /// changed by the write
    pub fn write(&self, value: i32) -> Port {
        let mut result_input = vec![];
        for index in 0..self.input.len() {
            result_input.push(self.input[index]);
        }
        let mut result_output = vec![];
        for index in 0..self.output.len() {
            result_output.push(self.output[index]);
        }
        result_output.push(value);
        Port::with(result_input, result_output)
    }
}

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

    #[test]
    fn read_from_a_port_should_work_correctly() {
        let port: Port = Port::new(vec![0, 1, 2]);

        match port.read() {
            PortReadResult::Success(next_port, value) => {
                assert_eq!(0, value);
                assert_eq!(Port::with(vec![1,2], vec![]), next_port);
            },
            PortReadResult::Failure => panic!(),

        }
    }

    #[test]
    fn write_to_a_port_should_work_correctly() {
        let port: Port = Port::with(vec![1, 2], vec![3]);

        let next_port = port.write(4);

        assert_eq!(Port::with(vec![1, 2], vec![3, 4]), next_port);
    }

    #[test]
    fn ports_should_be_able_to_be_cloned() {
        let port: Port = Port::with(vec![1, 2], vec![3, 4]);

        let clone: Port = port.clone();

        assert_eq!(clone, port);
    }
}
<|endoftext|>


<commit_before>// This file is part of Twig (ported to Rust).
//
// For the copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Twig Error Handling
//!
//! # Examples
//!
//! ```rust,macro_test
//! #[macro_use] extern crate twig; // Macros must be imported *explicitly*
//!
//! use std::fmt;
//! use twig::api::error::Traced;
//! use std::error::Error;
//!
//! // Implement a custom error code.
//! type MyTracedSimpleError = Traced<MySimpleError>;
//!
//! #[derive(Debug)]
//! enum MySimpleError {
//!     Critical,
//!     Recoverable
//! }
//!
//! impl Error for MySimpleError {
//!     fn description(&self) -> &str {
//!         match *self {
//!             MySimpleError::Critical => "Critical error.",
//!             MySimpleError::Recoverable => "Recoverable error."
//!         }
//!     }
//! }
//!
//! impl fmt::Display for MySimpleError {
//!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//!         write!(f, "{} With human readable details", self.description())
//!     }
//! }
//!
//! fn main() {
//!     // Create a twig error, wrapping this error code + code location.
//!     let result: Result<(), Traced<MySimpleError>> = traced_err!(MySimpleError::Critical);
//!
//!     if let Err(error) = result {
//!         assert!(error.to_string().starts_with("Critical error. With human readable details at <anon>:"));
//!     }
//! }
//! ```

#[macro_use] mod macros;
use std::fmt::{self, Debug, Display};
use std::error::Error; // use std Error-trait to improve cross-crate compatibility
use std::ops::{Deref, DerefMut};

/// Extension trait for std::error::Error
///
/// adds conversion to `Traced` error
pub trait ErrorExt: Error {
    /// Returns generic twig error for this error code.
    /// You must provide the location, where the error occured.
    fn at(self, location: Location) -> Traced<Self>
        where Self: Sized
    {
        Traced::new(self, location)
    }
}

impl<T> ErrorExt for T where T: Error {}

/// Record current state of complex objects
///
/// The purpose of a dump is to be wrapped in error codes instead of complex objects.
/// This abstraction allows to
/// * keep error codes free of any lifetimes
/// * maintain the ability of receiver of error codes to decide about verbosity
///
/// The Dump::Data type may not contain lifetimes.
/// In practice this means cloning all referenced data into the dump.
///
/// For a type `X: Dump` you can reference the associated dump type via `<X as Dump>::Data`.
pub trait Dump {
    type Data: Debug + Display + 'static;

    fn dump(&self) -> Self::Data;
}

/// Generic error with backtrace.
///
/// Wrapper around some error type `T` implementing `std::error::Error`.
/// * Adds support for a backtrace.
/// * Automatically derefs to the inner error.
pub struct Traced<T>
    where T: Error
{
    // the error codes are going to be structured enums
    error: T,

    /// Backtrace
    trace: Trace,
}

impl<T> Traced<T> where
    T: Error
{
    /// Create a new twig error out of some generic error code.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use] extern crate twig;
    /// # fn main() {
    /// use twig::api::error;
    /// use std::env::VarError;
    ///
    /// error::Traced::new(VarError::NotPresent, loc!()); // shorthand: `trace!(VarError::NotPresent)`
    /// # }
    /// ```
    pub fn new(error: T, location: Location) -> Traced<T> {
        Traced {
            error: error,
            trace: Trace(vec![location]),
        }
    }

    /// Return the first location the error occured.
    pub fn location(&self) -> Option<&Location> {
        self.trace.first()
    }

    pub fn backtrace(&self) -> &[Location] {
        &self.trace
    }

    // should not name it `at`, because `Traced` derefs to `Error` which impl `ErrorExt::at()`
    pub fn trace<R>(self, loc: Location) -> Traced<R>
        where T: Into<R>,
              R: Error
    {
        let Traced { error, mut trace } = self;
        trace.push(loc);

        Traced {
            error: error.into(),
            trace: trace
        }
    }

    /// Creates an iterator to iterate along the error cause-chain.
    pub fn iter(&self) -> ErrorIter {
        ErrorIter {
            next: Some(&self.error),
        }
    }
}

impl<T> Deref for Traced<T> where
    T: Error
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.error
    }
}

/// Iterator to iterate along the error cause-chain.
pub struct ErrorIter<'a> {
    next: Option<&'a Error>
}

impl<'a> Iterator for ErrorIter<'a> {
    type Item = &'a Error;

    fn next(&mut self) -> Option<Self::Item> {
        return match self.next {
            Some(err) => {
                self.next = err.cause();
                Some(err)
            }
            None => None,
        }
    }
}

impl<T> Debug for Traced<T> where
    T: Error
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.debug_struct("Traced")
            .field("error", &self.error)
            .field("at", &self.trace)
            .finish()
    }
}

impl<T> Display for Traced<T> where
    T: Error
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{error} at {trace}\n",
            error = self.error,
            trace = &self.trace)
    }
}

/// Trace wraps `Vec<Location>`  with specialized `Display` and `Debug` impls.
///
/// For everything else it just derefs to `Vec<Location>`.
pub struct Trace(Vec<Location>);

impl Deref for Trace {
    type Target = Vec<Location>;

    fn deref(&self) -> &Self::Target {
        let Trace(ref trace) = *self;

        trace
    }
}

impl DerefMut for Trace {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let Trace(ref mut trace) = *self;

        trace
    }
}

impl Debug for Trace {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.iter().enumerate().fold(
            &mut f.debug_struct("Trace"),
            |s, i| s.field(&format!("#{}", i.0), i.1)
        ).finish()
    }
}

impl Display for Trace {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.first() {
            Some(location) => write!(f, "{:?}", location),
            None =>  write!(f, "unknown (no backtrace)")
        }
    }
}

/// Location in rust source code
///
/// Debug::fmt() output is formatted in a compact way: `"{filename}:{line}:{column}"`.
#[derive(PartialEq)]
pub struct Location {
    pub filename : &'static str,    // e.g. /src/lexer/job/state/shared_traits.rs
    pub line : u32,
    pub column : u32,
}

impl Debug for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{filename}:{line}:{column}",
            filename = self.filename,
            line     = self.line,
            column   = self.column)
    }
}
<commit_msg>cleanup II<commit_after>// This file is part of Twig (ported to Rust).
//
// For the copyright and license information, please view the LICENSE
// file that was distributed with this source code.

//! Twig Error Handling
//!
//! # Examples
//!
//! ```rust,macro_test
//! #[macro_use] extern crate twig; // Macros must be imported *explicitly*
//!
//! use std::fmt;
//! use twig::api::error::Traced;
//! use std::error::Error;
//!
//! // Implement a custom error code.
//! type MyTracedSimpleError = Traced<MySimpleError>;
//!
//! #[derive(Debug)]
//! enum MySimpleError {
//!     Critical,
//!     Recoverable
//! }
//!
//! impl Error for MySimpleError {
//!     fn description(&self) -> &str {
//!         match *self {
//!             MySimpleError::Critical => "Critical error.",
//!             MySimpleError::Recoverable => "Recoverable error."
//!         }
//!     }
//! }
//!
//! impl fmt::Display for MySimpleError {
//!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//!         write!(f, "{} With human readable details", self.description())
//!     }
//! }
//!
//! fn main() {
//!     // Create a twig error, wrapping this error code + code location.
//!     let result: Result<(), Traced<MySimpleError>> = traced_err!(MySimpleError::Critical);
//!
//!     if let Err(error) = result {
//!         assert!(error.to_string().starts_with("Critical error. With human readable details at <anon>:"));
//!     }
//! }
//! ```

#[macro_use] mod macros;
use std::fmt::{self, Debug, Display};
use std::error::Error; // use std Error-trait to improve cross-crate compatibility
use std::ops::{Deref, DerefMut};

/// Extension trait for std::error::Error
///
/// adds conversion to `Traced` error
pub trait ErrorExt: Error {
    /// Returns generic twig error for this error code.
    /// You must provide the location, where the error occured.
    fn at(self, location: Location) -> Traced<Self>
        where Self: Sized
    {
        Traced::new(self, location)
    }
}

impl<T> ErrorExt for T where T: Error {}

/// Record current state of complex objects
///
/// The purpose of a dump is to be wrapped in error codes instead of complex objects.
/// This abstraction allows to
/// * keep error codes free of any lifetimes
/// * maintain the ability of receiver of error codes to decide about verbosity
///
/// The Dump::Data type may not contain lifetimes.
/// In practice this means cloning all referenced data into the dump.
///
/// For a type `X: Dump` you can reference the associated dump type via `<X as Dump>::Data`.
pub trait Dump {
    type Data: Debug + Display + 'static;

    fn dump(&self) -> Self::Data;
}

/// Generic error with backtrace.
///
/// Wrapper around some error type `T` implementing `std::error::Error`.
/// * Adds support for a backtrace.
/// * Automatically derefs to the inner error.
pub struct Traced<T>
    where T: Error
{
    error: T,
    trace: Trace,
}

impl<T> Traced<T> where
    T: Error
{
    /// Create a new twig error out of some generic error code.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use] extern crate twig;
    /// # fn main() {
    /// use twig::api::error;
    /// use std::env::VarError;
    ///
    /// error::Traced::new(VarError::NotPresent, loc!()); // shorthand: `trace!(VarError::NotPresent)`
    /// # }
    /// ```
    pub fn new(error: T, location: Location) -> Traced<T> {
        Traced {
            error: error,
            trace: Trace(vec![location]),
        }
    }

    /// Return the first location the error occured.
    pub fn location(&self) -> Option<&Location> {
        self.trace.first()
    }

    pub fn backtrace(&self) -> &[Location] {
        &self.trace
    }

    // should not name it `at`, because `Traced` derefs to `Error` which impl `ErrorExt::at()`
    pub fn trace<R>(self, loc: Location) -> Traced<R>
        where T: Into<R>,
              R: Error
    {
        let Traced { error, mut trace } = self;
        trace.push(loc);

        Traced {
            error: error.into(),
            trace: trace
        }
    }

    /// Creates an iterator to iterate along the error cause-chain.
    pub fn iter(&self) -> ErrorIter {
        ErrorIter {
            next: Some(&self.error),
        }
    }
}

impl<T> Deref for Traced<T> where
    T: Error
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.error
    }
}

/// Iterator to iterate along the error cause-chain.
pub struct ErrorIter<'a> {
    next: Option<&'a Error>
}

impl<'a> Iterator for ErrorIter<'a> {
    type Item = &'a Error;

    fn next(&mut self) -> Option<Self::Item> {
        return match self.next {
            Some(err) => {
                self.next = err.cause();
                Some(err)
            }
            None => None,
        }
    }
}

impl<T> Debug for Traced<T> where
    T: Error
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.debug_struct("Traced")
            .field("error", &self.error)
            .field("at", &self.trace)
            .finish()
    }
}

impl<T> Display for Traced<T> where
    T: Error
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{error} at {trace}\n",
            error = self.error,
            trace = &self.trace)
    }
}

/// Trace wraps `Vec<Location>`  with specialized `Display` and `Debug` impls.
///
/// For everything else it just derefs to `Vec<Location>`.
pub struct Trace(Vec<Location>);

impl Deref for Trace {
    type Target = Vec<Location>;

    fn deref(&self) -> &Self::Target {
        let Trace(ref trace) = *self;

        trace
    }
}

impl DerefMut for Trace {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let Trace(ref mut trace) = *self;

        trace
    }
}

impl Debug for Trace {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.iter().enumerate().fold(
            &mut f.debug_struct("Trace"),
            |s, i| s.field(&format!("#{}", i.0), i.1)
        ).finish()
    }
}

impl Display for Trace {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.first() {
            Some(location) => write!(f, "{:?}", location),
            None =>  write!(f, "unknown (no backtrace)")
        }
    }
}

/// Location in rust source code
///
/// Debug::fmt() output is formatted in a compact way: `"{filename}:{line}:{column}"`.
#[derive(PartialEq)]
pub struct Location {
    pub filename : &'static str,    // e.g. /src/lexer/job/state/shared_traits.rs
    pub line : u32,
    pub column : u32,
}

impl Debug for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{filename}:{line}:{column}",
            filename = self.filename,
            line     = self.line,
            column   = self.column)
    }
}
<|endoftext|>


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

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Sunrin SHIMURA
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;
extern crate tempfile;
extern crate rand;

#[macro_use]
extern crate uucore;

use std::env;
use std::io::Write;
use std::path::{PathBuf, is_separator};
use std::mem::forget;
use std::iter;

use rand::Rng;
use tempfile::NamedTempFileOptions;

static NAME: &'static str = "mktemp";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static DEFAULT_TEMPLATE: &'static str = "tmp.XXXXXXXXXX";

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("d", "directory", "Make a directory instead of a file");
    opts.optflag("u", "dry-run", "do not create anything; merely print a name (unsafe)");
    opts.optflag("q", "quiet", "Fail silently if an error occurs.");
    opts.optopt("", "suffix", "append SUFF to TEMPLATE; SUFF must not contain a path separator. This option is implied if TEMPLATE does not end with X.", "SUFF");
    opts.optopt("p", "tmpdir", "interpret TEMPLATE relative to DIR; if DIR is not specified, use $TMPDIR if set, else /tmp.  With this option, TEMPLATE  must  not  be  an  absolute name; unlike with -t, TEMPLATE may contain slashes, but mktemp creates only the final component", "DIR");
    // deprecated option of GNU coreutils
    //    opts.optflag("t", "", "Generate a template (using the supplied prefix and TMPDIR if set) to create a filename template");
    opts.optflag("", "help", "Print this help and exit");
    opts.optflag("", "version", "print the version and exit");

    // >> early return options
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };

    if matches.opt_present("quiet") {
        // TODO: close stderror. `crash!` macro always write output to stderror
        crash!(1, "quiet option is not supported yet.");
    };

    if args.len() == 1 || matches.opt_present("help") {
        print_help(&opts);
        return 0;
    }
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if 1 < matches.free.len() {
        crash!(1, "Too many templates");
    }
    // <<

    let make_dir = matches.opt_present("directory");
    let dry_run = matches.opt_present("dry-run");
    let suffix_opt = matches.opt_str("suffix");

    let template = if matches.free.is_empty() {
        DEFAULT_TEMPLATE
    } else {
        &matches.free[0][..]
    };

    let (prefix, rand, suffix) = match parse_template(template) {
        Some((p, r, s)) => match suffix_opt {
            Some(suf) => if s == "" {
                (p, r, suf)
            } else {
                crash!(1, "Template should end with 'X' when you specify suffix option.")
            },
            None => (p, r, s.to_string())
        },
        None => ("",0, "".to_string())
    };

    if rand < 3 {
        crash!(1, "Too few 'X's in template")
    }

    if suffix.chars().any(|c| is_separator(c)) {
        crash!(1, "suffix cannot contain any path separators");
    }

    let tmpdir = match matches.opt_str("tmpdir") {
        Some(s) => {
            if PathBuf::from(prefix).is_absolute() {
                crash!(1, "template must not be an absolute path when tempdir is specified.");
            }
            PathBuf::from(s)

        },
        None => env::temp_dir()
    };

    if dry_run {
        dry_exec(tmpdir, prefix, rand, &suffix)
    } else {
        exec(tmpdir, prefix, rand , &suffix, make_dir)
    }

}

fn print_help(opts: &getopts::Options) {
    let usage = format!(" Create a temporary file or directory, safely, and print its name.
TEMPLATE must contain at least 3 consecutive 'X's in last component.
If TEMPLATE is not specified, use {}, and --tmpdir is implied", DEFAULT_TEMPLATE);

    println!("{} {}", NAME, VERSION);
    println!("SYNOPSIS");
    println!("  {} [OPTION]... [FILE]", NAME);
    println!("Usage:");
    print!("{}", opts.usage(&usage[..]));
}

fn parse_template(temp :&str) -> Option<(&str, usize, &str)> {
    let right = match temp.rfind('X') {
        Some(r) => r+1,
        None => return None
    };
    let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1);
    let prefix = &temp[..left];
    let rand = right - left;
    let suffix = &temp[right..];
    Some((prefix, rand, suffix))
}

pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) -> i32 {
    let len = prefix.len() + suffix.len() + rand;
    let mut buf = String::with_capacity(len);
    buf.push_str(prefix);
    buf.extend(iter::repeat('X').take(rand));
    buf.push_str(suffix);

    // Randomize.
    unsafe {
        // We guarantee utf8.
        let bytes = &mut buf.as_mut_vec()[prefix.len()..prefix.len() + rand];
        rand::thread_rng().fill_bytes(bytes);
        for byte in bytes.iter_mut() {
            *byte = match *byte % 62 {
                v @ 0...9 => (v + '0' as u8),
                v @ 10...35 => (v - 10 + 'a' as u8),
                v @ 36...61 => (v - 36 + 'A' as u8),
                _ => unreachable!(),
            }
        }
    }
    tmpdir.push(String::from(buf));
    println!("{}", tmpdir.display());
    return 0;
}

fn exec(tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> i32 {
    // TODO: respect make_dir option
    if make_dir {
        crash!(1, "Directory option is not supported yet. Sorry.");
    }

    let tmpfile = NamedTempFileOptions::new()
        .prefix(prefix)
        .rand_bytes(rand)
        .suffix(suffix)
        .create_in(tmpdir);

    let tmpfile = match tmpfile {
        Ok(f) => f,
        Err(_) => crash!(1, "failed to create tempfile")
    };

    let tmpname = tmpfile
        .path()
        .to_string_lossy()
        .to_string();

    println!("{}", tmpname);

    // CAUTION: Not to call `drop` of tmpfile, which removes the tempfile,
    // I call a dengeros function `forget`.
    forget(tmpfile);

    return 0;
}
<commit_msg>[mktemp] allow empty argument<commit_after>#![crate_name = "uu_mktemp"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Sunrin SHIMURA
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;
extern crate tempfile;
extern crate rand;

#[macro_use]
extern crate uucore;

use std::env;
use std::io::Write;
use std::path::{PathBuf, is_separator};
use std::mem::forget;
use std::iter;

use rand::Rng;
use tempfile::NamedTempFileOptions;

static NAME: &'static str = "mktemp";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static DEFAULT_TEMPLATE: &'static str = "tmp.XXXXXXXXXX";

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("d", "directory", "Make a directory instead of a file");
    opts.optflag("u", "dry-run", "do not create anything; merely print a name (unsafe)");
    opts.optflag("q", "quiet", "Fail silently if an error occurs.");
    opts.optopt("", "suffix", "append SUFF to TEMPLATE; SUFF must not contain a path separator. This option is implied if TEMPLATE does not end with X.", "SUFF");
    opts.optopt("p", "tmpdir", "interpret TEMPLATE relative to DIR; if DIR is not specified, use $TMPDIR if set, else /tmp.  With this option, TEMPLATE  must  not  be  an  absolute name; unlike with -t, TEMPLATE may contain slashes, but mktemp creates only the final component", "DIR");
    // deprecated option of GNU coreutils
    //    opts.optflag("t", "", "Generate a template (using the supplied prefix and TMPDIR if set) to create a filename template");
    opts.optflag("", "help", "Print this help and exit");
    opts.optflag("", "version", "print the version and exit");

    // >> early return options
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };

    if matches.opt_present("quiet") {
        // TODO: close stderror. `crash!` macro always write output to stderror
        crash!(1, "quiet option is not supported yet.");
    };

    if  matches.opt_present("help") {
        print_help(&opts);
        return 0;
    }
    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if 1 < matches.free.len() {
        crash!(1, "Too many templates");
    }
    // <<

    let make_dir = matches.opt_present("directory");
    let dry_run = matches.opt_present("dry-run");
    let suffix_opt = matches.opt_str("suffix");

    let template = if matches.free.is_empty() {
        DEFAULT_TEMPLATE
    } else {
        &matches.free[0][..]
    };

    let (prefix, rand, suffix) = match parse_template(template) {
        Some((p, r, s)) => match suffix_opt {
            Some(suf) => if s == "" {
                (p, r, suf)
            } else {
                crash!(1, "Template should end with 'X' when you specify suffix option.")
            },
            None => (p, r, s.to_string())
        },
        None => ("",0, "".to_string())
    };

    if rand < 3 {
        crash!(1, "Too few 'X's in template")
    }

    if suffix.chars().any(|c| is_separator(c)) {
        crash!(1, "suffix cannot contain any path separators");
    }

    let tmpdir = match matches.opt_str("tmpdir") {
        Some(s) => {
            if PathBuf::from(prefix).is_absolute() {
                crash!(1, "template must not be an absolute path when tempdir is specified.");
            }
            PathBuf::from(s)

        },
        None => env::temp_dir()
    };

    if dry_run {
        dry_exec(tmpdir, prefix, rand, &suffix)
    } else {
        exec(tmpdir, prefix, rand , &suffix, make_dir)
    }

}

fn print_help(opts: &getopts::Options) {
    let usage = format!(" Create a temporary file or directory, safely, and print its name.
TEMPLATE must contain at least 3 consecutive 'X's in last component.
If TEMPLATE is not specified, use {}, and --tmpdir is implied", DEFAULT_TEMPLATE);

    println!("{} {}", NAME, VERSION);
    println!("SYNOPSIS");
    println!("  {} [OPTION]... [FILE]", NAME);
    println!("Usage:");
    print!("{}", opts.usage(&usage[..]));
}

fn parse_template(temp :&str) -> Option<(&str, usize, &str)> {
    let right = match temp.rfind('X') {
        Some(r) => r+1,
        None => return None
    };
    let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1);
    let prefix = &temp[..left];
    let rand = right - left;
    let suffix = &temp[right..];
    Some((prefix, rand, suffix))
}

pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) -> i32 {
    let len = prefix.len() + suffix.len() + rand;
    let mut buf = String::with_capacity(len);
    buf.push_str(prefix);
    buf.extend(iter::repeat('X').take(rand));
    buf.push_str(suffix);

    // Randomize.
    unsafe {
        // We guarantee utf8.
        let bytes = &mut buf.as_mut_vec()[prefix.len()..prefix.len() + rand];
        rand::thread_rng().fill_bytes(bytes);
        for byte in bytes.iter_mut() {
            *byte = match *byte % 62 {
                v @ 0...9 => (v + '0' as u8),
                v @ 10...35 => (v - 10 + 'a' as u8),
                v @ 36...61 => (v - 36 + 'A' as u8),
                _ => unreachable!(),
            }
        }
    }
    tmpdir.push(String::from(buf));
    println!("{}", tmpdir.display());
    return 0;
}

fn exec(tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> i32 {
    // TODO: respect make_dir option
    if make_dir {
        crash!(1, "Directory option is not supported yet. Sorry.");
    }

    let tmpfile = NamedTempFileOptions::new()
        .prefix(prefix)
        .rand_bytes(rand)
        .suffix(suffix)
        .create_in(tmpdir);

    let tmpfile = match tmpfile {
        Ok(f) => f,
        Err(_) => crash!(1, "failed to create tempfile")
    };

    let tmpname = tmpfile
        .path()
        .to_string_lossy()
        .to_string();

    println!("{}", tmpname);

    // CAUTION: Not to call `drop` of tmpfile, which removes the tempfile,
    // I call a dengeros function `forget`.
    forget(tmpfile);

    return 0;
}
<|endoftext|>


<commit_before>
<commit_msg>tournament: Added template to the stub file<commit_after>pub fn tally(match_results: &str) -> String {
    unimplemented!(
        "Given the result of the played matches '{}' return a properly formatted tally table string.",
        match_results
    );
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{changed_since::changed_since_impl, context::XContext, Result};
use anyhow::anyhow;
use guppy::graph::DependencyDirection;
use std::collections::BTreeSet;
use structopt::StructOpt;

/// Arguments for the Cargo package selector.
#[derive(Debug, StructOpt)]
pub struct SelectedPackageArgs {
    #[structopt(long, short, number_of_values = 1)]
    /// Run on the provided packages
    pub(crate) package: Vec<String>,
    #[structopt(long, short)]
    /// Run on packages changed since the merge base of this commit
    changed_since: Option<String>,
    #[structopt(long)]
    /// Run on all packages in the workspace
    pub(crate) workspace: bool,
}

impl SelectedPackageArgs {
    pub fn to_selected_packages<'a>(&'a self, xctx: &'a XContext) -> Result<SelectedPackages<'a>> {
        // Mutually exclusive options -- only one of these can be provided.
        {
            let mut exclusive = vec![];
            if self.changed_since.is_some() {
                exclusive.push("--changed-since");
            }
            if !self.package.is_empty() {
                exclusive.push("--package");
            }
            if self.workspace {
                exclusive.push("--workspace");
            }

            if exclusive.len() > 1 {
                let err_msg = exclusive.join(", ");
                return Err(anyhow!("can only specify one of {}", err_msg));
            }
        }

        if self.workspace {
            Ok(SelectedPackages::workspace())
        } else if !self.package.is_empty() {
            Ok(SelectedPackages::includes(
                self.package.iter().map(|s| s.as_str()),
            ))
        } else if let Some(base) = &self.changed_since {
            let affected_set = changed_since_impl(&xctx, &base)?;

            Ok(SelectedPackages::includes(
                affected_set
                    .packages(DependencyDirection::Forward)
                    .map(|package| package.name()),
            ))
        } else {
            SelectedPackages::default_cwd(xctx)
        }
    }
}

/// Package selector for Cargo commands.
///
/// This may represent any of the following:
/// * the entire workspace
/// * a single package without arguments
/// * a list of packages
///
/// This may also exclude a set of packages. Note that currently, excludes only work in the "entire
/// workspace" and "list of packages" situations. They are ignored if a specific local package is
/// being built. (This is an extension on top of Cargo itself, which only supports --exclude
/// together with --workspace.)
///
/// Excludes are applied after includes. This allows changed-since to support excludes, even if only
/// a subset of the workspace changes.
#[derive(Clone, Debug)]
pub struct SelectedPackages<'a> {
    pub(super) includes: SelectedInclude<'a>,
    pub(super) excludes: BTreeSet<&'a str>,
}

impl<'a> SelectedPackages<'a> {
    /// Returns a new `CargoPackages` that selects all packages in this workspace.
    pub fn workspace() -> Self {
        Self {
            includes: SelectedInclude::Workspace,
            excludes: BTreeSet::new(),
        }
    }

    /// Returns a new `CargoPackages` that selects the default set of packages for the current
    /// working directory. This may either be the entire workspace or a set of packages inside the
    /// workspace.
    pub fn default_cwd(xctx: &'a XContext) -> Result<Self> {
        let includes = if xctx.core().current_dir_is_root() {
            SelectedInclude::Workspace
        } else {
            // Select all packages that begin with the current rel dir.
            let rel = xctx.core().current_rel_dir();
            let workspace = xctx.core().package_graph()?.workspace();
            let selected = workspace.iter_by_path().filter_map(|(path, package)| {
                // If we're in devtools, run tests for all packages inside devtools.
                // If we're in devtools/x/src, run tests for devtools/x.
                if path.starts_with(rel) || rel.starts_with(path) {
                    Some(package.name())
                } else {
                    None
                }
            });
            SelectedInclude::Includes(selected.collect())
        };
        Ok(Self {
            includes,
            excludes: BTreeSet::new(),
        })
    }

    /// Returns a new `CargoPackages` that selects the specified packages.
    pub fn includes(package_names: impl IntoIterator<Item = &'a str>) -> Self {
        Self {
            includes: SelectedInclude::Includes(package_names.into_iter().collect()),
            excludes: BTreeSet::new(),
        }
    }

    /// Adds excludes for this `CargoPackages`.
    ///
    /// The excludes are currently ignored if the local package is built.
    pub fn add_excludes(&mut self, exclude_names: impl IntoIterator<Item = &'a str>) -> &mut Self {
        self.excludes.extend(exclude_names);
        self
    }

    // ---
    // Helper methods
    // ---

    pub(super) fn should_invoke(&self) -> bool {
        match &self.includes {
            SelectedInclude::Workspace => true,
            SelectedInclude::Includes(includes) => {
                // If everything in the include set is excluded, a command invocation isn't needed.
                includes.iter().any(|p| !self.excludes.contains(p))
            }
        }
    }
}

#[derive(Clone, Debug)]
pub(super) enum SelectedInclude<'a> {
    Workspace,
    Includes(Vec<&'a str>),
}

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

    #[test]
    fn test_should_invoke() {
        let packages = SelectedPackages::workspace();
        assert!(packages.should_invoke(), "workspace => invoke");

        let mut packages = SelectedPackages::includes(vec!["foo", "bar"]);
        packages.add_excludes(vec!["foo"]);
        assert!(packages.should_invoke(), "non-empty packages => invoke");

        let packages = SelectedPackages::includes(vec![]);
        assert!(!packages.should_invoke(), "no packages => do not invoke");

        let mut packages = SelectedPackages::includes(vec!["foo", "bar"]);
        packages.add_excludes(vec!["foo", "bar"]);
        assert!(
            !packages.should_invoke(),
            "all packages excluded => do not invoke"
        );
    }
}
<commit_msg>[x] add a --production option to select production crates<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{changed_since::changed_since_impl, context::XContext, Result};
use anyhow::anyhow;
use guppy::graph::DependencyDirection;
use std::collections::BTreeSet;
use structopt::StructOpt;
use x_core::WorkspaceStatus;

/// Arguments for the Cargo package selector.
#[derive(Debug, StructOpt)]
pub struct SelectedPackageArgs {
    #[structopt(long, short, number_of_values = 1)]
    /// Run on the provided packages
    pub(crate) package: Vec<String>,
    #[structopt(long, short)]
    /// Run on packages changed since the merge base of this commit
    changed_since: Option<String>,
    #[structopt(long)]
    /// Run on all packages in the workspace
    pub(crate) workspace: bool,
    #[structopt(long)]
    /// Run on production code (non-test-only code, reachable from default members)
    pub(crate) production: bool,
}

impl SelectedPackageArgs {
    pub fn to_selected_packages<'a>(&'a self, xctx: &'a XContext) -> Result<SelectedPackages<'a>> {
        // Mutually exclusive options -- only one of these can be provided.
        {
            let mut exclusive = vec![];
            if self.changed_since.is_some() {
                exclusive.push("--changed-since");
            }
            if !self.package.is_empty() {
                exclusive.push("--package");
            }
            if self.workspace {
                exclusive.push("--workspace");
            }
            if self.production {
                exclusive.push("--production");
            }

            if exclusive.len() > 1 {
                let err_msg = exclusive.join(", ");
                return Err(anyhow!("can only specify one of {}", err_msg));
            }
        }

        if self.workspace {
            Ok(SelectedPackages::workspace())
        } else if !self.package.is_empty() {
            Ok(SelectedPackages::includes(
                self.package.iter().map(|s| s.as_str()),
            ))
        } else if let Some(base) = &self.changed_since {
            let affected_set = changed_since_impl(&xctx, &base)?;

            Ok(SelectedPackages::includes(
                affected_set
                    .packages(DependencyDirection::Forward)
                    .map(|package| package.name()),
            ))
        } else if self.production {
            SelectedPackages::production(xctx)
        } else {
            SelectedPackages::default_cwd(xctx)
        }
    }
}

/// Package selector for Cargo commands.
///
/// This may represent any of the following:
/// * the entire workspace
/// * a single package without arguments
/// * a list of packages
///
/// This may also exclude a set of packages. Note that currently, excludes only work in the "entire
/// workspace" and "list of packages" situations. They are ignored if a specific local package is
/// being built. (This is an extension on top of Cargo itself, which only supports --exclude
/// together with --workspace.)
///
/// Excludes are applied after includes. This allows changed-since to support excludes, even if only
/// a subset of the workspace changes.
#[derive(Clone, Debug)]
pub struct SelectedPackages<'a> {
    pub(super) includes: SelectedInclude<'a>,
    pub(super) excludes: BTreeSet<&'a str>,
}

impl<'a> SelectedPackages<'a> {
    /// Returns a new `CargoPackages` that selects all packages in this workspace.
    pub fn workspace() -> Self {
        Self {
            includes: SelectedInclude::Workspace,
            excludes: BTreeSet::new(),
        }
    }

    /// Returns a new `CargoPackages` that selects production crates (non-test-only code).
    pub fn production(xctx: &'a XContext) -> Result<Self> {
        let default_members = xctx.core().default_members()?;
        let workspace = xctx.core().package_graph()?.workspace();

        let selected = workspace.iter().filter_map(|package| {
            if default_members.status_of(package.id()) != WorkspaceStatus::Absent {
                Some(package.name())
            } else {
                None
            }
        });
        Ok(Self {
            includes: SelectedInclude::Includes(selected.collect()),
            excludes: BTreeSet::new(),
        })
    }

    /// Returns a new `CargoPackages` that selects the default set of packages for the current
    /// working directory. This may either be the entire workspace or a set of packages inside the
    /// workspace.
    pub fn default_cwd(xctx: &'a XContext) -> Result<Self> {
        let includes = if xctx.core().current_dir_is_root() {
            SelectedInclude::Workspace
        } else {
            // Select all packages that begin with the current rel dir.
            let rel = xctx.core().current_rel_dir();
            let workspace = xctx.core().package_graph()?.workspace();
            let selected = workspace.iter_by_path().filter_map(|(path, package)| {
                // If we're in devtools, run tests for all packages inside devtools.
                // If we're in devtools/x/src, run tests for devtools/x.
                if path.starts_with(rel) || rel.starts_with(path) {
                    Some(package.name())
                } else {
                    None
                }
            });
            SelectedInclude::Includes(selected.collect())
        };
        Ok(Self {
            includes,
            excludes: BTreeSet::new(),
        })
    }

    /// Returns a new `CargoPackages` that selects the specified packages.
    pub fn includes(package_names: impl IntoIterator<Item = &'a str>) -> Self {
        Self {
            includes: SelectedInclude::Includes(package_names.into_iter().collect()),
            excludes: BTreeSet::new(),
        }
    }

    /// Adds excludes for this `CargoPackages`.
    ///
    /// The excludes are currently ignored if the local package is built.
    pub fn add_excludes(&mut self, exclude_names: impl IntoIterator<Item = &'a str>) -> &mut Self {
        self.excludes.extend(exclude_names);
        self
    }

    // ---
    // Helper methods
    // ---

    pub(super) fn should_invoke(&self) -> bool {
        match &self.includes {
            SelectedInclude::Workspace => true,
            SelectedInclude::Includes(includes) => {
                // If everything in the include set is excluded, a command invocation isn't needed.
                includes.iter().any(|p| !self.excludes.contains(p))
            }
        }
    }
}

#[derive(Clone, Debug)]
pub(super) enum SelectedInclude<'a> {
    Workspace,
    Includes(Vec<&'a str>),
}

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

    #[test]
    fn test_should_invoke() {
        let packages = SelectedPackages::workspace();
        assert!(packages.should_invoke(), "workspace => invoke");

        let mut packages = SelectedPackages::includes(vec!["foo", "bar"]);
        packages.add_excludes(vec!["foo"]);
        assert!(packages.should_invoke(), "non-empty packages => invoke");

        let packages = SelectedPackages::includes(vec![]);
        assert!(!packages.should_invoke(), "no packages => do not invoke");

        let mut packages = SelectedPackages::includes(vec!["foo", "bar"]);
        packages.add_excludes(vec!["foo", "bar"]);
        assert!(
            !packages.should_invoke(),
            "all packages excluded => do not invoke"
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Data structures that represent video format information in virtio video devices.

use std::convert::From;
use std::convert::Into;
use std::convert::TryFrom;
use std::fmt;
use std::fmt::Display;
use std::io;

use base::error;
use data_model::Le32;
use enumn::N;

use crate::virtio::video::command::ReadCmdError;
use crate::virtio::video::protocol::*;
use crate::virtio::video::response::Response;
use crate::virtio::Writer;

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Profile {
    H264Baseline = VIRTIO_VIDEO_PROFILE_H264_BASELINE,
    H264Main = VIRTIO_VIDEO_PROFILE_H264_MAIN,
    H264Extended = VIRTIO_VIDEO_PROFILE_H264_EXTENDED,
    H264High = VIRTIO_VIDEO_PROFILE_H264_HIGH,
    H264High10 = VIRTIO_VIDEO_PROFILE_H264_HIGH10PROFILE,
    H264High422 = VIRTIO_VIDEO_PROFILE_H264_HIGH422PROFILE,
    H264High444PredictiveProfile = VIRTIO_VIDEO_PROFILE_H264_HIGH444PREDICTIVEPROFILE,
    H264ScalableBaseline = VIRTIO_VIDEO_PROFILE_H264_SCALABLEBASELINE,
    H264ScalableHigh = VIRTIO_VIDEO_PROFILE_H264_SCALABLEHIGH,
    H264StereoHigh = VIRTIO_VIDEO_PROFILE_H264_STEREOHIGH,
    H264MultiviewHigh = VIRTIO_VIDEO_PROFILE_H264_MULTIVIEWHIGH,
    HevcMain = VIRTIO_VIDEO_PROFILE_HEVC_MAIN,
    HevcMain10 = VIRTIO_VIDEO_PROFILE_HEVC_MAIN10,
    HevcMainStillPicture = VIRTIO_VIDEO_PROFILE_HEVC_MAIN_STILL_PICTURE,
    VP8Profile0 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE0,
    VP8Profile1 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE1,
    VP8Profile2 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE2,
    VP8Profile3 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE3,
    VP9Profile0 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE0,
    VP9Profile1 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE1,
    VP9Profile2 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE2,
    VP9Profile3 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE3,
}
impl_try_from_le32_for_enumn!(Profile, "profile");

impl Profile {
    #[cfg(any(feature = "video-encoder", feature = "libvda", feature = "vaapi"))]
    pub fn to_format(self) -> Format {
        use Profile::*;
        match self {
            H264Baseline
            | H264Main
            | H264Extended
            | H264High
            | H264High10
            | H264High422
            | H264High444PredictiveProfile
            | H264ScalableBaseline
            | H264ScalableHigh
            | H264StereoHigh
            | H264MultiviewHigh => Format::H264,
            HevcMain | HevcMain10 | HevcMainStillPicture => Format::Hevc,
            VP8Profile0 | VP8Profile1 | VP8Profile2 | VP8Profile3 => Format::VP8,
            VP9Profile0 | VP9Profile1 | VP9Profile2 | VP9Profile3 => Format::VP9,
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Level {
    H264_1_0 = VIRTIO_VIDEO_LEVEL_H264_1_0,
    H264_1_1 = VIRTIO_VIDEO_LEVEL_H264_1_1,
    H264_1_2 = VIRTIO_VIDEO_LEVEL_H264_1_2,
    H264_1_3 = VIRTIO_VIDEO_LEVEL_H264_1_3,
    H264_2_0 = VIRTIO_VIDEO_LEVEL_H264_2_0,
    H264_2_1 = VIRTIO_VIDEO_LEVEL_H264_2_1,
    H264_2_2 = VIRTIO_VIDEO_LEVEL_H264_2_2,
    H264_3_0 = VIRTIO_VIDEO_LEVEL_H264_3_0,
    H264_3_1 = VIRTIO_VIDEO_LEVEL_H264_3_1,
    H264_3_2 = VIRTIO_VIDEO_LEVEL_H264_3_2,
    H264_4_0 = VIRTIO_VIDEO_LEVEL_H264_4_0,
    H264_4_1 = VIRTIO_VIDEO_LEVEL_H264_4_1,
    H264_4_2 = VIRTIO_VIDEO_LEVEL_H264_4_2,
    H264_5_0 = VIRTIO_VIDEO_LEVEL_H264_5_0,
    H264_5_1 = VIRTIO_VIDEO_LEVEL_H264_5_1,
}
impl_try_from_le32_for_enumn!(Level, "level");

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Format {
    // Raw formats
    NV12 = VIRTIO_VIDEO_FORMAT_NV12,
    YUV420 = VIRTIO_VIDEO_FORMAT_YUV420,

    // Bitstream formats
    H264 = VIRTIO_VIDEO_FORMAT_H264,
    Hevc = VIRTIO_VIDEO_FORMAT_HEVC,
    VP8 = VIRTIO_VIDEO_FORMAT_VP8,
    VP9 = VIRTIO_VIDEO_FORMAT_VP9,
}
impl_try_from_le32_for_enumn!(Format, "format");

impl Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Format::*;
        match self {
            NV12 => write!(f, "NV12"),
            YUV420 => write!(f, "YUV420"),
            H264 => write!(f, "H264"),
            Hevc => write!(f, "HEVC"),
            VP8 => write!(f, "VP8"),
            VP9 => write!(f, "VP9"),
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum BitrateMode {
    Vbr = VIRTIO_VIDEO_BITRATE_MODE_VBR,
    Cbr = VIRTIO_VIDEO_BITRATE_MODE_CBR,
}
impl_try_from_le32_for_enumn!(BitrateMode, "bitrate_mode");

#[allow(dead_code)]
#[derive(Debug, Copy, Clone)]
pub enum Bitrate {
    /// Constant bitrate.
    Cbr { target: u32 },
    /// Variable bitrate.
    Vbr { target: u32, peak: u32 },
}

#[cfg(feature = "video-encoder")]
impl Bitrate {
    pub fn mode(&self) -> BitrateMode {
        match self {
            Bitrate::Cbr { .. } => BitrateMode::Cbr,
            Bitrate::Vbr { .. } => BitrateMode::Vbr,
        }
    }

    pub fn target(&self) -> u32 {
        match self {
            Bitrate::Cbr { target } => *target,
            Bitrate::Vbr { target, .. } => *target,
        }
    }
}

#[derive(Debug, Default, Copy, Clone)]
pub struct Crop {
    pub left: u32,
    pub top: u32,
    pub width: u32,
    pub height: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_crop, Crop, left, top, width, height);

#[derive(PartialEq, Eq, Debug, Default, Clone, Copy)]
pub struct PlaneFormat {
    pub plane_size: u32,
    pub stride: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_plane_format, PlaneFormat, plane_size, stride);

impl PlaneFormat {
    pub fn get_plane_layout(format: Format, width: u32, height: u32) -> Option<Vec<PlaneFormat>> {
        match format {
            Format::NV12 => Some(vec![
                // Y plane, 1 sample per pixel.
                PlaneFormat {
                    plane_size: width * height,
                    stride: width,
                },
                // UV plane, 1 sample per group of 4 pixels for U and V.
                PlaneFormat {
                    // Add one vertical line so odd resolutions result in an extra UV line to cover all the
                    // Y samples.
                    plane_size: width * ((height + 1) / 2),
                    stride: width,
                },
            ]),
            _ => None,
        }
    }
}

#[derive(Debug, Default, Clone, Copy)]
pub struct FormatRange {
    pub min: u32,
    pub max: u32,
    pub step: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_format_range, FormatRange, min, max, step);

#[derive(Debug, Default, Clone)]
pub struct FrameFormat {
    pub width: FormatRange,
    pub height: FormatRange,
    pub bitrates: Vec<FormatRange>,
}

impl Response for FrameFormat {
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        w.write_obj(virtio_video_format_frame {
            width: self.width.into(),
            height: self.height.into(),
            num_rates: Le32::from(self.bitrates.len() as u32),
            ..Default::default()
        })?;
        w.write_iter(
            self.bitrates
                .iter()
                .map(|r| Into::<virtio_video_format_range>::into(*r)),
        )
    }
}

#[derive(Debug, Clone)]
pub struct FormatDesc {
    pub mask: u64,
    pub format: Format,
    pub frame_formats: Vec<FrameFormat>,
    pub plane_align: u32,
}

impl Response for FormatDesc {
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        w.write_obj(virtio_video_format_desc {
            mask: self.mask.into(),
            format: Le32::from(self.format as u32),
            // ChromeOS only supports single-buffer mode.
            planes_layout: Le32::from(VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER),
            // No alignment is required on boards that we currently support.
            plane_align: Le32::from(self.plane_align),
            num_frames: Le32::from(self.frame_formats.len() as u32),
        })?;
        self.frame_formats.iter().try_for_each(|ff| ff.write(w))
    }
}

#[cfg(feature = "video-encoder")]
fn clamp_size(size: u32, min: u32, step: u32) -> u32 {
    match step {
        0 | 1 => size,
        _ => {
            let step_mod = (size - min) % step;
            if step_mod == 0 {
                size
            } else {
                size - step_mod + step
            }
        }
    }
}

/// Parses a slice of valid frame formats and the desired resolution
/// and returns the closest available resolution.
#[cfg(feature = "video-encoder")]
pub fn find_closest_resolution(
    frame_formats: &[FrameFormat],
    desired_width: u32,
    desired_height: u32,
) -> (u32, u32) {
    for FrameFormat { width, height, .. } in frame_formats.iter() {
        if desired_width < width.min || desired_width > width.max {
            continue;
        }
        if desired_height < height.min || desired_height > height.max {
            continue;
        }
        let allowed_width = clamp_size(desired_width, width.min, width.step);
        let allowed_height = clamp_size(desired_height, height.min, height.step);
        return (allowed_width, allowed_height);
    }

    // Return the resolution with maximum surface if nothing better is found.
    match frame_formats
        .iter()
        .max_by_key(|format| format.width.max * format.height.max)
    {
        None => (0, 0),
        Some(format) => (format.width.max, format.height.max),
    }
}

/// A rectangle used to describe portions of a frame.
#[derive(Debug, Eq, PartialEq)]
pub struct Rect {
    pub left: i32,
    pub top: i32,
    pub right: i32,
    pub bottom: i32,
}

/// Description of the layout for a single plane.
#[derive(Debug, Clone)]
pub struct FramePlane {
    pub offset: usize,
    pub stride: usize,
    pub size: usize,
}
<commit_msg>virtio: video: Implement plane layout calculation for YUV420<commit_after>// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Data structures that represent video format information in virtio video devices.

use std::convert::From;
use std::convert::Into;
use std::convert::TryFrom;
use std::fmt;
use std::fmt::Display;
use std::io;

use base::error;
use data_model::Le32;
use enumn::N;

use crate::virtio::video::command::ReadCmdError;
use crate::virtio::video::protocol::*;
use crate::virtio::video::response::Response;
use crate::virtio::Writer;

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Profile {
    H264Baseline = VIRTIO_VIDEO_PROFILE_H264_BASELINE,
    H264Main = VIRTIO_VIDEO_PROFILE_H264_MAIN,
    H264Extended = VIRTIO_VIDEO_PROFILE_H264_EXTENDED,
    H264High = VIRTIO_VIDEO_PROFILE_H264_HIGH,
    H264High10 = VIRTIO_VIDEO_PROFILE_H264_HIGH10PROFILE,
    H264High422 = VIRTIO_VIDEO_PROFILE_H264_HIGH422PROFILE,
    H264High444PredictiveProfile = VIRTIO_VIDEO_PROFILE_H264_HIGH444PREDICTIVEPROFILE,
    H264ScalableBaseline = VIRTIO_VIDEO_PROFILE_H264_SCALABLEBASELINE,
    H264ScalableHigh = VIRTIO_VIDEO_PROFILE_H264_SCALABLEHIGH,
    H264StereoHigh = VIRTIO_VIDEO_PROFILE_H264_STEREOHIGH,
    H264MultiviewHigh = VIRTIO_VIDEO_PROFILE_H264_MULTIVIEWHIGH,
    HevcMain = VIRTIO_VIDEO_PROFILE_HEVC_MAIN,
    HevcMain10 = VIRTIO_VIDEO_PROFILE_HEVC_MAIN10,
    HevcMainStillPicture = VIRTIO_VIDEO_PROFILE_HEVC_MAIN_STILL_PICTURE,
    VP8Profile0 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE0,
    VP8Profile1 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE1,
    VP8Profile2 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE2,
    VP8Profile3 = VIRTIO_VIDEO_PROFILE_VP8_PROFILE3,
    VP9Profile0 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE0,
    VP9Profile1 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE1,
    VP9Profile2 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE2,
    VP9Profile3 = VIRTIO_VIDEO_PROFILE_VP9_PROFILE3,
}
impl_try_from_le32_for_enumn!(Profile, "profile");

impl Profile {
    #[cfg(any(feature = "video-encoder", feature = "libvda", feature = "vaapi"))]
    pub fn to_format(self) -> Format {
        use Profile::*;
        match self {
            H264Baseline
            | H264Main
            | H264Extended
            | H264High
            | H264High10
            | H264High422
            | H264High444PredictiveProfile
            | H264ScalableBaseline
            | H264ScalableHigh
            | H264StereoHigh
            | H264MultiviewHigh => Format::H264,
            HevcMain | HevcMain10 | HevcMainStillPicture => Format::Hevc,
            VP8Profile0 | VP8Profile1 | VP8Profile2 | VP8Profile3 => Format::VP8,
            VP9Profile0 | VP9Profile1 | VP9Profile2 | VP9Profile3 => Format::VP9,
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Level {
    H264_1_0 = VIRTIO_VIDEO_LEVEL_H264_1_0,
    H264_1_1 = VIRTIO_VIDEO_LEVEL_H264_1_1,
    H264_1_2 = VIRTIO_VIDEO_LEVEL_H264_1_2,
    H264_1_3 = VIRTIO_VIDEO_LEVEL_H264_1_3,
    H264_2_0 = VIRTIO_VIDEO_LEVEL_H264_2_0,
    H264_2_1 = VIRTIO_VIDEO_LEVEL_H264_2_1,
    H264_2_2 = VIRTIO_VIDEO_LEVEL_H264_2_2,
    H264_3_0 = VIRTIO_VIDEO_LEVEL_H264_3_0,
    H264_3_1 = VIRTIO_VIDEO_LEVEL_H264_3_1,
    H264_3_2 = VIRTIO_VIDEO_LEVEL_H264_3_2,
    H264_4_0 = VIRTIO_VIDEO_LEVEL_H264_4_0,
    H264_4_1 = VIRTIO_VIDEO_LEVEL_H264_4_1,
    H264_4_2 = VIRTIO_VIDEO_LEVEL_H264_4_2,
    H264_5_0 = VIRTIO_VIDEO_LEVEL_H264_5_0,
    H264_5_1 = VIRTIO_VIDEO_LEVEL_H264_5_1,
}
impl_try_from_le32_for_enumn!(Level, "level");

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum Format {
    // Raw formats
    NV12 = VIRTIO_VIDEO_FORMAT_NV12,
    YUV420 = VIRTIO_VIDEO_FORMAT_YUV420,

    // Bitstream formats
    H264 = VIRTIO_VIDEO_FORMAT_H264,
    Hevc = VIRTIO_VIDEO_FORMAT_HEVC,
    VP8 = VIRTIO_VIDEO_FORMAT_VP8,
    VP9 = VIRTIO_VIDEO_FORMAT_VP9,
}
impl_try_from_le32_for_enumn!(Format, "format");

impl Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Format::*;
        match self {
            NV12 => write!(f, "NV12"),
            YUV420 => write!(f, "YUV420"),
            H264 => write!(f, "H264"),
            Hevc => write!(f, "HEVC"),
            VP8 => write!(f, "VP8"),
            VP9 => write!(f, "VP9"),
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
pub enum BitrateMode {
    Vbr = VIRTIO_VIDEO_BITRATE_MODE_VBR,
    Cbr = VIRTIO_VIDEO_BITRATE_MODE_CBR,
}
impl_try_from_le32_for_enumn!(BitrateMode, "bitrate_mode");

#[allow(dead_code)]
#[derive(Debug, Copy, Clone)]
pub enum Bitrate {
    /// Constant bitrate.
    Cbr { target: u32 },
    /// Variable bitrate.
    Vbr { target: u32, peak: u32 },
}

#[cfg(feature = "video-encoder")]
impl Bitrate {
    pub fn mode(&self) -> BitrateMode {
        match self {
            Bitrate::Cbr { .. } => BitrateMode::Cbr,
            Bitrate::Vbr { .. } => BitrateMode::Vbr,
        }
    }

    pub fn target(&self) -> u32 {
        match self {
            Bitrate::Cbr { target } => *target,
            Bitrate::Vbr { target, .. } => *target,
        }
    }
}

#[derive(Debug, Default, Copy, Clone)]
pub struct Crop {
    pub left: u32,
    pub top: u32,
    pub width: u32,
    pub height: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_crop, Crop, left, top, width, height);

#[derive(PartialEq, Eq, Debug, Default, Clone, Copy)]
pub struct PlaneFormat {
    pub plane_size: u32,
    pub stride: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_plane_format, PlaneFormat, plane_size, stride);

impl PlaneFormat {
    pub fn get_plane_layout(format: Format, width: u32, height: u32) -> Option<Vec<PlaneFormat>> {
        // Halved size for UV sampling, but rounded up to cover all samples in case of odd input
        // resolution.
        let half_width = (width + 1) / 2;
        let half_height = (height + 1) / 2;
        match format {
            Format::NV12 => Some(vec![
                // Y plane, 1 sample per pixel.
                PlaneFormat {
                    plane_size: width * height,
                    stride: width,
                },
                // UV plane, 1 sample per group of 4 pixels for U and V.
                PlaneFormat {
                    // Add one vertical line so odd resolutions result in an extra UV line to cover all the
                    // Y samples.
                    plane_size: width * half_height,
                    stride: width,
                },
            ]),
            Format::YUV420 => Some(vec![
                // Y plane, 1 sample per pixel.
                PlaneFormat {
                    plane_size: width * height,
                    stride: width,
                },
                // U plane, 1 sample per group of 4 pixels.
                PlaneFormat {
                    plane_size: half_width * half_height,
                    stride: half_width,
                },
                // V plane, same layout as U plane.
                PlaneFormat {
                    plane_size: half_width * half_height,
                    stride: half_width,
                },
            ]),
            _ => None,
        }
    }
}

#[derive(Debug, Default, Clone, Copy)]
pub struct FormatRange {
    pub min: u32,
    pub max: u32,
    pub step: u32,
}
impl_from_for_interconvertible_structs!(virtio_video_format_range, FormatRange, min, max, step);

#[derive(Debug, Default, Clone)]
pub struct FrameFormat {
    pub width: FormatRange,
    pub height: FormatRange,
    pub bitrates: Vec<FormatRange>,
}

impl Response for FrameFormat {
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        w.write_obj(virtio_video_format_frame {
            width: self.width.into(),
            height: self.height.into(),
            num_rates: Le32::from(self.bitrates.len() as u32),
            ..Default::default()
        })?;
        w.write_iter(
            self.bitrates
                .iter()
                .map(|r| Into::<virtio_video_format_range>::into(*r)),
        )
    }
}

#[derive(Debug, Clone)]
pub struct FormatDesc {
    pub mask: u64,
    pub format: Format,
    pub frame_formats: Vec<FrameFormat>,
    pub plane_align: u32,
}

impl Response for FormatDesc {
    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
        w.write_obj(virtio_video_format_desc {
            mask: self.mask.into(),
            format: Le32::from(self.format as u32),
            // ChromeOS only supports single-buffer mode.
            planes_layout: Le32::from(VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER),
            // No alignment is required on boards that we currently support.
            plane_align: Le32::from(self.plane_align),
            num_frames: Le32::from(self.frame_formats.len() as u32),
        })?;
        self.frame_formats.iter().try_for_each(|ff| ff.write(w))
    }
}

#[cfg(feature = "video-encoder")]
fn clamp_size(size: u32, min: u32, step: u32) -> u32 {
    match step {
        0 | 1 => size,
        _ => {
            let step_mod = (size - min) % step;
            if step_mod == 0 {
                size
            } else {
                size - step_mod + step
            }
        }
    }
}

/// Parses a slice of valid frame formats and the desired resolution
/// and returns the closest available resolution.
#[cfg(feature = "video-encoder")]
pub fn find_closest_resolution(
    frame_formats: &[FrameFormat],
    desired_width: u32,
    desired_height: u32,
) -> (u32, u32) {
    for FrameFormat { width, height, .. } in frame_formats.iter() {
        if desired_width < width.min || desired_width > width.max {
            continue;
        }
        if desired_height < height.min || desired_height > height.max {
            continue;
        }
        let allowed_width = clamp_size(desired_width, width.min, width.step);
        let allowed_height = clamp_size(desired_height, height.min, height.step);
        return (allowed_width, allowed_height);
    }

    // Return the resolution with maximum surface if nothing better is found.
    match frame_formats
        .iter()
        .max_by_key(|format| format.width.max * format.height.max)
    {
        None => (0, 0),
        Some(format) => (format.width.max, format.height.max),
    }
}

/// A rectangle used to describe portions of a frame.
#[derive(Debug, Eq, PartialEq)]
pub struct Rect {
    pub left: i32,
    pub top: i32,
    pub right: i32,
    pub bottom: i32,
}

/// Description of the layout for a single plane.
#[derive(Debug, Clone)]
pub struct FramePlane {
    pub offset: usize,
    pub stride: usize,
    pub size: usize,
}
<|endoftext|>


<commit_before>// Copyright 2015 Justin Noah, 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.

extern crate bincode;
extern crate "rustc-serialize" as rustc_serialize;

use self::bincode::SizeLimit;
use rustc_serialize::{Decodable, Decoder};

#[derive(RustcDecodable)]
pub struct PacketHeader {
    pub connection_id:  i64,
    pub action:         i32,
    pub transaction_id: i32,
}

#[derive(Debug, RustcEncodable)]
struct ConnectionResponse {
    action:         i32,
    transaction_id: i32,
    connection_id:  i64,
}

#[derive(Debug)]
struct ClientAnnounce {
    info_hash:  [u8; 20],
    peer_id:    [u8; 20],
    downloaded: i64,
    remaining:  i64,
    uploaded:   i64,
    event:      i32,
    ip:         u32,
    key:        u32,
    num_want:   i32,
    port:       u16,
}

impl Decodable for ClientAnnounce {
    fn decode<D: Decoder>(d: &mut D) -> Result<ClientAnnounce, D::Error> {
        let mut info_hash = [0u8; 20];
        for i in 0..20 {
            info_hash[i] = try!(d.read_u8());
        }
        let mut peer_id = [0u8; 20];
        for i in 0..20 {
            peer_id[i] = try!(d.read_u8());
        }
        Ok(ClientAnnounce {
            info_hash:  info_hash,
            peer_id:    peer_id,
            downloaded: try!(d.read_i64()),
            remaining:  try!(d.read_i64()),
            uploaded:   try!(d.read_i64()),
            event:      try!(d.read_i32()),
            ip:         try!(d.read_u32()),
            key:        try!(d.read_u32()),
            num_want:   try!(d.read_i32()),
            port:       try!(d.read_u16()),
        })
    }
}

#[derive(Debug, RustcEncodable)]
struct ServerAnnounce {
    action:         i32,
    transaction_id: i32,
    interval:       i32,
    leechers:       i32,
    seeders:        i32,
}

pub fn parse_header(packet: &[u8]) -> PacketHeader {
    // In case we send extra by mistake, make sure to only parse the first 16 bytes
    bincode::decode(&packet[..16]).unwrap()
}

pub fn encode_connect_response(uuid: i64, tran_id: i32) -> Vec<u8> {
    let packet = ConnectionResponse { action: 0, transaction_id: tran_id, connection_id: uuid};
    bincode::encode(&packet, SizeLimit::Infinite).unwrap()
}

pub fn decode_client_announce(packet: &[u8]) -> ClientAnnounce {
    bincode::decode(&packet).unwrap()
}
<commit_msg>begin work on encoding ServerAnnounce<commit_after>// Copyright 2015 Justin Noah, 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.

extern crate bincode;
extern crate "rustc-serialize" as rustc_serialize;

use self::bincode::SizeLimit;
use rustc_serialize::{Decodable, Decoder};

#[derive(RustcDecodable)]
pub struct PacketHeader {
    pub connection_id:  i64,
    pub action:         i32,
    pub transaction_id: i32,
}

#[derive(Debug, RustcEncodable)]
struct ConnectionResponse {
    action:         i32,
    transaction_id: i32,
    connection_id:  i64,
}

#[derive(Debug)]
pub struct ClientAnnounce {
    pub info_hash:  [u8; 20],
    pub peer_id:    [u8; 20],
    pub downloaded: i64,
    pub remaining:  i64,
    pub uploaded:   i64,
    pub event:      i32,
    pub ip:         u32,
    pub key:        u32,
    pub num_want:   i32,
    pub port:       u16,
}

impl Decodable for ClientAnnounce {
    fn decode<D: Decoder>(d: &mut D) -> Result<ClientAnnounce, D::Error> {
        let mut info_hash = [0u8; 20];
        for i in 0..20 {
            info_hash[i] = try!(d.read_u8());
        }
        let mut peer_id = [0u8; 20];
        for i in 0..20 {
            peer_id[i] = try!(d.read_u8());
        }
        Ok(ClientAnnounce {
            info_hash:  info_hash,
            peer_id:    peer_id,
            downloaded: try!(d.read_i64()),
            remaining:  try!(d.read_i64()),
            uploaded:   try!(d.read_i64()),
            event:      try!(d.read_i32()),
            ip:         try!(d.read_u32()),
            key:        try!(d.read_u32()),
            num_want:   try!(d.read_i32()),
            port:       try!(d.read_u16()),
        })
    }
}

#[derive(Debug, RustcEncodable)]
struct ServerAnnounce {
    action:         i32,
    transaction_id: i32,
    interval:       i32,
    leechers:       i32,
    seeders:        i32,
}

pub fn parse_header(packet: &[u8]) -> PacketHeader {
    // In case we send extra by mistake, make sure to only parse the first 16 bytes
    bincode::decode(&packet[..16]).unwrap()
}

pub fn encode_connect_response(uuid: i64, tran_id: i32) -> Vec<u8> {
    let packet = ConnectionResponse { action: 0, transaction_id: tran_id, connection_id: uuid};
    bincode::encode(&packet, SizeLimit::Infinite).unwrap()
}

pub fn decode_client_announce(packet: &[u8]) -> ClientAnnounce {
    bincode::decode(&packet).unwrap()
}

pub fn encode_server_announce(transaction_id: i32, leechers: i32, seeders: i32) -> Vec<u8> {
    let packet = ServerAnnounce {
        action:         1,              // Announce is always 1
        transaction_id: transaction_id,
        interval:       1800,           // 30min = 1800sec
        leechers:       leechers,
        seeders:        seeders,
    };

    bincode::encode(&packet, SizeLimit::Infinite).unwrap()
}
<|endoftext|>