<commit_before>mod node;
mod node_children;
mod node_text;
mod text_info;

#[cfg(not(test))]
use std::mem::size_of;

pub(crate) use self::node::Node;
pub(crate) use self::node_children::NodeChildren;
pub(crate) use self::node_text::NodeText;
pub(crate) use self::text_info::TextInfo;

#[cfg(not(test))]
const PTR_SIZE: usize = size_of::<&u8>();

// Aim for nodes to be 768 bytes - Arc counters.  Keeping the nodes
// multiples of large powers of two makes it easier for the memory allocator
// to avoid fragmentation.
#[cfg(not(test))]
const TARGET_NODE_SIZE: usize = 768 - (PTR_SIZE * 2);

// Node min/max values.
// For testing, they're set small to trigger deeper trees.  For
// non-testing, they're determined by TARGET_NODE_SIZE, above.
#[cfg(test)]
pub(crate) const MAX_CHILDREN: usize = 5;
#[cfg(not(test))]
pub(crate) const MAX_CHILDREN: usize = (TARGET_NODE_SIZE - 1) / 32;
pub(crate) const MIN_CHILDREN: usize = MAX_CHILDREN - (MAX_CHILDREN / 2);

#[cfg(test)]
pub(crate) const MAX_BYTES: usize = 8;
#[cfg(not(test))]
pub(crate) const MAX_BYTES: usize = TARGET_NODE_SIZE - 1 - (PTR_SIZE * 2);
pub(crate) const MIN_BYTES: usize = MAX_BYTES - (MAX_BYTES / 2);

// Type used for storing tree metadata, such as byte and char length.
pub(crate) type Count = u64;
<commit_msg>Use size_of() for compile-time child count calculations.<commit_after>mod node;
mod node_children;
mod node_text;
mod text_info;

#[cfg(not(test))]
use std::{mem::size_of, sync::Arc};

pub(crate) use self::node::Node;
pub(crate) use self::node_children::NodeChildren;
pub(crate) use self::node_text::NodeText;
pub(crate) use self::text_info::TextInfo;

#[cfg(not(test))]
const PTR_SIZE: usize = size_of::<&u8>();
#[cfg(not(test))]
const CHILD_INFO_SIZE: usize = size_of::<Arc<Node>>() + size_of::<TextInfo>();

// Aim for nodes to be 768 bytes - Arc counters.  Keeping the nodes
// multiples of large powers of two makes it easier for the memory allocator
// to avoid fragmentation.
#[cfg(not(test))]
const TARGET_NODE_SIZE: usize = 768 - (PTR_SIZE * 2);

// Node min/max values.
// For testing, they're set small to trigger deeper trees.  For
// non-testing, they're determined by TARGET_NODE_SIZE, above.
#[cfg(test)]
pub(crate) const MAX_CHILDREN: usize = 5;
#[cfg(not(test))]
pub(crate) const MAX_CHILDREN: usize = (TARGET_NODE_SIZE - 1) / CHILD_INFO_SIZE;
pub(crate) const MIN_CHILDREN: usize = MAX_CHILDREN - (MAX_CHILDREN / 2);

#[cfg(test)]
pub(crate) const MAX_BYTES: usize = 8;
#[cfg(not(test))]
pub(crate) const MAX_BYTES: usize = TARGET_NODE_SIZE - 1 - (PTR_SIZE * 2);
pub(crate) const MIN_BYTES: usize = MAX_BYTES - (MAX_BYTES / 2);

// Type used for storing tree metadata, such as byte and char length.
pub(crate) type Count = u64;
<|endoftext|>


<commit_before>#[macro_escape];

macro_rules! new_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N> $t<N>
    {
      #[inline]
      pub fn new($comp0: N $( , $compN: N )*) -> $t<N>
      {
        $t {
          $comp0: $comp0
          $(, $compN: $compN )*
        }
      }
    }
  )
)

macro_rules! indexable_impl(
  ($t: ident, $dim: expr) => (
    impl<N: Clone> Indexable<uint, N> for $t<N>
    {
      #[inline]
      pub fn at(&self, i: uint) -> N
      { unsafe { cast::transmute::<&$t<N>, &[N, ..$dim]>(self)[i].clone() } }

      #[inline]
      pub fn set(&mut self, i: uint, val: N)
      { unsafe { cast::transmute::<&mut $t<N>, &mut [N, ..$dim]>(self)[i] = val } }

      #[inline]
      pub fn swap(&mut self, i1: uint, i2: uint)
      { unsafe { cast::transmute::<&mut $t<N>, &mut [N, ..$dim]>(self).swap(i1, i2) } }
    }
  )
)

macro_rules! new_repeat_impl(
  ($t: ident, $param: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone> $t<N>
    {
      #[inline]
      pub fn new_repeat($param: N) -> $t<N>
      {
        $t{
          $comp0: $param.clone()
          $(, $compN: $param.clone() )*
        }
      }
    }
  )
)

macro_rules! iterable_impl(
  ($t: ident, $dim: expr) => (
    impl<N> Iterable<N> for $t<N>
    {
      fn iter<'l>(&'l self) -> VecIterator<'l, N>
      { unsafe { cast::transmute::<&'l $t<N>, &'l [N, ..$dim]>(self).iter() } }
    }
  )
)

macro_rules! iterable_mut_impl(
  ($t: ident, $dim: expr) => (
    impl<N> IterableMut<N> for $t<N>
    {
      fn mut_iter<'l>(&'l mut self) -> VecMutIterator<'l, N>
      { unsafe { cast::transmute::<&'l mut $t<N>, &'l mut [N, ..$dim]>(self).mut_iter() } }
    }
  )
)

macro_rules! dim_impl(
  ($t: ident, $dim: expr) => (
    impl<N> Dim for $t<N>
    {
      #[inline]
      fn dim() -> uint
      { $dim }
    }
  )
)

// FIXME: add the possibility to specialize that
macro_rules! basis_impl(
  ($t: ident, $dim: expr) => (
    impl<N: Clone + DivisionRing + Algebraic + ApproxEq<N>> Basis for $t<N>
    {
      pub fn canonical_basis(f: &fn($t<N>))
      {
        for iterate(0u, $dim) |i|
        {
          let mut basis_element : $t<N> = Zero::zero();

          basis_element.set(i, One::one());

          f(basis_element);
        }
      }

      pub fn orthonormal_subspace_basis(&self, f: &fn($t<N>))
      {
        // compute the basis of the orthogonal subspace using Gram-Schmidt
        // orthogonalization algorithm
        let mut basis: ~[$t<N>] = ~[];

        for iterate(0u, $dim) |i|
        {
          let mut basis_element : $t<N> = Zero::zero();

          basis_element.set(i, One::one());

          if basis.len() == $dim - 1
          { break; }

          let mut elt = basis_element.clone();

          elt = elt - self.scalar_mul(&basis_element.dot(self));

          for basis.iter().advance |v|
          { elt = elt - v.scalar_mul(&elt.dot(v)) };

          if !elt.sqnorm().approx_eq(&Zero::zero())
          {
            let new_element = elt.normalized();

            f(new_element.clone());

            basis.push(new_element);
          }
        }
      }
    }
  )
)

macro_rules! add_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone + Add<N,N>> Add<$t<N>, $t<N>> for $t<N>
    {
      #[inline]
      fn add(&self, other: &$t<N>) -> $t<N>
      { $t::new(self.$comp0 + other.$comp0 $(, self.$compN + other.$compN)*) }
    }
  )
)

macro_rules! sub_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone + Sub<N,N>> Sub<$t<N>, $t<N>> for $t<N>
    {
      #[inline]
      fn sub(&self, other: &$t<N>) -> $t<N>
      { $t::new(self.$comp0 - other.$comp0 $(, self.$compN - other.$compN)*) }
    }
  )
)

macro_rules! neg_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Neg<N>> Neg<$t<N>> for $t<N>
    {
      #[inline]
      fn neg(&self) -> $t<N>
      { $t::new(-self.$comp0 $(, -self.$compN )*) }
    }
  )
)

macro_rules! dot_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Ring> Dot<N> for $t<N>
    {
      #[inline]
      fn dot(&self, other: &$t<N>) -> N
      { self.$comp0 * other.$comp0 $(+ self.$compN * other.$compN )* }
    }
  )
)

macro_rules! sub_dot_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Ring> SubDot<N> for $t<N>
    {
      #[inline]
      fn sub_dot(&self, a: &$t<N>, b: &$t<N>) -> N
      { (self.$comp0 - a.$comp0) * b.$comp0 $(+ (self.$compN - a.$comp0) * b.$compN )* }
    }
  )
)

macro_rules! scalar_mul_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Mul<N, N>> ScalarMul<N> for $t<N>
    {
      #[inline]
      fn scalar_mul(&self, s: &N) -> $t<N>
      { $t::new(self.$comp0 * *s $(, self.$compN * *s)*) }

      #[inline]
      fn scalar_mul_inplace(&mut self, s: &N)
      {
        self.$comp0   = self.$comp0 * *s;
        $(self.$compN = self.$compN * *s;)*
      }
    }
  )
)

macro_rules! scalar_div_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Div<N, N>> ScalarDiv<N> for $t<N>
    {
      #[inline]
      fn scalar_div(&self, s: &N) -> $t<N>
      { $t::new(self.$comp0 / *s $(, self.$compN / *s)*) }

      #[inline]
      fn scalar_div_inplace(&mut self, s: &N)
      {
        self.$comp0   = self.$comp0 / *s;
        $(self.$compN = self.$compN / *s;)*
      }
    }
  )
)

macro_rules! scalar_add_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Add<N, N>> ScalarAdd<N> for $t<N>
    {
      #[inline]
      fn scalar_add(&self, s: &N) -> $t<N>
      { $t::new(self.$comp0 + *s $(, self.$compN + *s)*) }

      #[inline]
      fn scalar_add_inplace(&mut self, s: &N)
      {
        self.$comp0   = self.$comp0 + *s;
        $(self.$compN = self.$compN + *s;)*
      }
    }
  )
)

macro_rules! scalar_sub_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Sub<N, N>> ScalarSub<N> for $t<N>
    {
      #[inline]
      fn scalar_sub(&self, s: &N) -> $t<N>
      { $t::new(self.$comp0 - *s $(, self.$compN - *s)*) }

      #[inline]
      fn scalar_sub_inplace(&mut self, s: &N)
      {
        self.$comp0   = self.$comp0 - *s;
        $(self.$compN = self.$compN - *s;)*
      }
    }
  )
)

macro_rules! translation_impl(
  ($t: ident) => (
    impl<N: Clone + Add<N, N> + Neg<N>> Translation<$t<N>> for $t<N>
    {
      #[inline]
      fn translation(&self) -> $t<N>
      { self.clone() }

      #[inline]
      fn inv_translation(&self) -> $t<N>
      { -self }

      #[inline]
      fn translate_by(&mut self, t: &$t<N>)
      { *self = *self + *t; }
    }
  )
)

macro_rules! translatable_impl(
  ($t: ident) => (
    impl<N: Add<N, N> + Neg<N> + Clone> Translatable<$t<N>, $t<N>> for $t<N>
    {
      #[inline]
      fn translated(&self, t: &$t<N>) -> $t<N>
      { self + *t }
    }
  )
)

macro_rules! norm_impl(
  ($t: ident) => (
    impl<N: Clone + DivisionRing + Algebraic> Norm<N> for $t<N>
    {
      #[inline]
      fn sqnorm(&self) -> N
      { self.dot(self) }

      #[inline]
      fn norm(&self) -> N
      { self.sqnorm().sqrt() }

      #[inline]
      fn normalized(&self) -> $t<N>
      {
        let mut res : $t<N> = self.clone();

        res.normalize();

        res
      }

      #[inline]
      fn normalize(&mut self) -> N
      {
        let l = self.norm();

        self.scalar_div_inplace(&l);

        l
      }
    }
  )
)

macro_rules! approx_eq_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: ApproxEq<N>> ApproxEq<N> for $t<N>
    {
      #[inline]
      fn approx_epsilon() -> N
      { ApproxEq::approx_epsilon::<N, N>() }

      #[inline]
      fn approx_eq(&self, other: &$t<N>) -> bool
      { self.$comp0.approx_eq(&other.$comp0) $(&& self.$compN.approx_eq(&other.$compN))* }

      #[inline]
      fn approx_eq_eps(&self, other: &$t<N>, eps: &N) -> bool
      { self.$comp0.approx_eq_eps(&other.$comp0, eps) $(&& self.$compN.approx_eq_eps(&other.$compN, eps))* }
    }
  )
)

macro_rules! one_impl(
  ($t: ident) => (
    impl<N: Clone + One> One for $t<N>
    {
      #[inline]
      fn one() -> $t<N>
      { $t::new_repeat(One::one()) }
    }
  )
)

macro_rules! from_iterator_impl(
  ($t: ident, $param0: ident $(, $paramN: ident)*) => (
    impl<N, Iter: Iterator<N>> FromIterator<N, Iter> for $t<N>
    {
      fn from_iterator($param0: &mut Iter) -> $t<N>
      { $t::new($param0.next().unwrap() $(, $paramN.next().unwrap())*) }
    }
  )
)

macro_rules! bounded_impl(
  ($t: ident) => (
    impl<N: Bounded + Clone> Bounded for $t<N>
    {
      #[inline]
      fn max_value() -> $t<N>
      { $t::new_repeat(Bounded::max_value()) }

      #[inline]
      fn min_value() -> $t<N>
      { $t::new_repeat(Bounded::min_value()) }
    }
  )
)

macro_rules! to_homogeneous_impl(
  ($t: ident, $t2: ident, $extra: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone + One + Zero> ToHomogeneous<$t2<N>> for $t<N>
    {
      fn to_homogeneous(&self) -> $t2<N>
      {
        let mut res: $t2<N> = One::one();

        res.$comp0    = self.$comp0.clone();
        $( res.$compN = self.$compN.clone(); )*

        res
      }
    }
  )
)

macro_rules! from_homogeneous_impl(
  ($t: ident, $t2: ident, $extra: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone + Div<N, N> + One + Zero> FromHomogeneous<$t2<N>> for $t<N>
    {
      fn from_homogeneous(v: &$t2<N>) -> $t<N>
      {
        let mut res: $t<N> = Zero::zero();

        res.$comp0    = v.$comp0.clone();
        $( res.$compN = v.$compN.clone(); )*

        res.scalar_div(&v.$extra);

        res
      }
    }
  )
)
<commit_msg>Fix sub_dot implementations.<commit_after>#[macro_escape];

macro_rules! new_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N> $t<N>
    {
      #[inline]
      pub fn new($comp0: N $( , $compN: N )*) -> $t<N>
      {
        $t {
          $comp0: $comp0
          $(, $compN: $compN )*
        }
      }
    }
  )
)

macro_rules! indexable_impl(
  ($t: ident, $dim: expr) => (
    impl<N: Clone> Indexable<uint, N> for $t<N>
    {
      #[inline]
      pub fn at(&self, i: uint) -> N
      { unsafe { cast::transmute::<&$t<N>, &[N, ..$dim]>(self)[i].clone() } }

      #[inline]
      pub fn set(&mut self, i: uint, val: N)
      { unsafe { cast::transmute::<&mut $t<N>, &mut [N, ..$dim]>(self)[i] = val } }

      #[inline]
      pub fn swap(&mut self, i1: uint, i2: uint)
      { unsafe { cast::transmute::<&mut $t<N>, &mut [N, ..$dim]>(self).swap(i1, i2) } }
    }
  )
)

macro_rules! new_repeat_impl(
  ($t: ident, $param: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone> $t<N>
    {
      #[inline]
      pub fn new_repeat($param: N) -> $t<N>
      {
        $t{
          $comp0: $param.clone()
          $(, $compN: $param.clone() )*
        }
      }
    }
  )
)

macro_rules! iterable_impl(
  ($t: ident, $dim: expr) => (
    impl<N> Iterable<N> for $t<N>
    {
      fn iter<'l>(&'l self) -> VecIterator<'l, N>
      { unsafe { cast::transmute::<&'l $t<N>, &'l [N, ..$dim]>(self).iter() } }
    }
  )
)

macro_rules! iterable_mut_impl(
  ($t: ident, $dim: expr) => (
    impl<N> IterableMut<N> for $t<N>
    {
      fn mut_iter<'l>(&'l mut self) -> VecMutIterator<'l, N>
      { unsafe { cast::transmute::<&'l mut $t<N>, &'l mut [N, ..$dim]>(self).mut_iter() } }
    }
  )
)

macro_rules! dim_impl(
  ($t: ident, $dim: expr) => (
    impl<N> Dim for $t<N>
    {
      #[inline]
      fn dim() -> uint
      { $dim }
    }
  )
)

// FIXME: add the possibility to specialize that
macro_rules! basis_impl(
  ($t: ident, $dim: expr) => (
    impl<N: Clone + DivisionRing + Algebraic + ApproxEq<N>> Basis for $t<N>
    {
      pub fn canonical_basis(f: &fn($t<N>))
      {
        for iterate(0u, $dim) |i|
        {
          let mut basis_element : $t<N> = Zero::zero();

          basis_element.set(i, One::one());

          f(basis_element);
        }
      }

      pub fn orthonormal_subspace_basis(&self, f: &fn($t<N>))
      {
        // compute the basis of the orthogonal subspace using Gram-Schmidt
        // orthogonalization algorithm
        let mut basis: ~[$t<N>] = ~[];

        for iterate(0u, $dim) |i|
        {
          let mut basis_element : $t<N> = Zero::zero();

          basis_element.set(i, One::one());

          if basis.len() == $dim - 1
          { break; }

          let mut elt = basis_element.clone();

          elt = elt - self.scalar_mul(&basis_element.dot(self));

          for basis.iter().advance |v|
          { elt = elt - v.scalar_mul(&elt.dot(v)) };

          if !elt.sqnorm().approx_eq(&Zero::zero())
          {
            let new_element = elt.normalized();

            f(new_element.clone());

            basis.push(new_element);
          }
        }
      }
    }
  )
)

macro_rules! add_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone + Add<N,N>> Add<$t<N>, $t<N>> for $t<N>
    {
      #[inline]
      fn add(&self, other: &$t<N>) -> $t<N>
      { $t::new(self.$comp0 + other.$comp0 $(, self.$compN + other.$compN)*) }
    }
  )
)

macro_rules! sub_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone + Sub<N,N>> Sub<$t<N>, $t<N>> for $t<N>
    {
      #[inline]
      fn sub(&self, other: &$t<N>) -> $t<N>
      { $t::new(self.$comp0 - other.$comp0 $(, self.$compN - other.$compN)*) }
    }
  )
)

macro_rules! neg_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Neg<N>> Neg<$t<N>> for $t<N>
    {
      #[inline]
      fn neg(&self) -> $t<N>
      { $t::new(-self.$comp0 $(, -self.$compN )*) }
    }
  )
)

macro_rules! dot_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Ring> Dot<N> for $t<N>
    {
      #[inline]
      fn dot(&self, other: &$t<N>) -> N
      { self.$comp0 * other.$comp0 $(+ self.$compN * other.$compN )* }
    }
  )
)

macro_rules! sub_dot_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Ring> SubDot<N> for $t<N>
    {
      #[inline]
      fn sub_dot(&self, a: &$t<N>, b: &$t<N>) -> N
      { (self.$comp0 - a.$comp0) * b.$comp0 $(+ (self.$compN - a.$compN) * b.$compN )* }
    }
  )
)

macro_rules! scalar_mul_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Mul<N, N>> ScalarMul<N> for $t<N>
    {
      #[inline]
      fn scalar_mul(&self, s: &N) -> $t<N>
      { $t::new(self.$comp0 * *s $(, self.$compN * *s)*) }

      #[inline]
      fn scalar_mul_inplace(&mut self, s: &N)
      {
        self.$comp0   = self.$comp0 * *s;
        $(self.$compN = self.$compN * *s;)*
      }
    }
  )
)

macro_rules! scalar_div_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Div<N, N>> ScalarDiv<N> for $t<N>
    {
      #[inline]
      fn scalar_div(&self, s: &N) -> $t<N>
      { $t::new(self.$comp0 / *s $(, self.$compN / *s)*) }

      #[inline]
      fn scalar_div_inplace(&mut self, s: &N)
      {
        self.$comp0   = self.$comp0 / *s;
        $(self.$compN = self.$compN / *s;)*
      }
    }
  )
)

macro_rules! scalar_add_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Add<N, N>> ScalarAdd<N> for $t<N>
    {
      #[inline]
      fn scalar_add(&self, s: &N) -> $t<N>
      { $t::new(self.$comp0 + *s $(, self.$compN + *s)*) }

      #[inline]
      fn scalar_add_inplace(&mut self, s: &N)
      {
        self.$comp0   = self.$comp0 + *s;
        $(self.$compN = self.$compN + *s;)*
      }
    }
  )
)

macro_rules! scalar_sub_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Sub<N, N>> ScalarSub<N> for $t<N>
    {
      #[inline]
      fn scalar_sub(&self, s: &N) -> $t<N>
      { $t::new(self.$comp0 - *s $(, self.$compN - *s)*) }

      #[inline]
      fn scalar_sub_inplace(&mut self, s: &N)
      {
        self.$comp0   = self.$comp0 - *s;
        $(self.$compN = self.$compN - *s;)*
      }
    }
  )
)

macro_rules! translation_impl(
  ($t: ident) => (
    impl<N: Clone + Add<N, N> + Neg<N>> Translation<$t<N>> for $t<N>
    {
      #[inline]
      fn translation(&self) -> $t<N>
      { self.clone() }

      #[inline]
      fn inv_translation(&self) -> $t<N>
      { -self }

      #[inline]
      fn translate_by(&mut self, t: &$t<N>)
      { *self = *self + *t; }
    }
  )
)

macro_rules! translatable_impl(
  ($t: ident) => (
    impl<N: Add<N, N> + Neg<N> + Clone> Translatable<$t<N>, $t<N>> for $t<N>
    {
      #[inline]
      fn translated(&self, t: &$t<N>) -> $t<N>
      { self + *t }
    }
  )
)

macro_rules! norm_impl(
  ($t: ident) => (
    impl<N: Clone + DivisionRing + Algebraic> Norm<N> for $t<N>
    {
      #[inline]
      fn sqnorm(&self) -> N
      { self.dot(self) }

      #[inline]
      fn norm(&self) -> N
      { self.sqnorm().sqrt() }

      #[inline]
      fn normalized(&self) -> $t<N>
      {
        let mut res : $t<N> = self.clone();

        res.normalize();

        res
      }

      #[inline]
      fn normalize(&mut self) -> N
      {
        let l = self.norm();

        self.scalar_div_inplace(&l);

        l
      }
    }
  )
)

macro_rules! approx_eq_impl(
  ($t: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: ApproxEq<N>> ApproxEq<N> for $t<N>
    {
      #[inline]
      fn approx_epsilon() -> N
      { ApproxEq::approx_epsilon::<N, N>() }

      #[inline]
      fn approx_eq(&self, other: &$t<N>) -> bool
      { self.$comp0.approx_eq(&other.$comp0) $(&& self.$compN.approx_eq(&other.$compN))* }

      #[inline]
      fn approx_eq_eps(&self, other: &$t<N>, eps: &N) -> bool
      { self.$comp0.approx_eq_eps(&other.$comp0, eps) $(&& self.$compN.approx_eq_eps(&other.$compN, eps))* }
    }
  )
)

macro_rules! one_impl(
  ($t: ident) => (
    impl<N: Clone + One> One for $t<N>
    {
      #[inline]
      fn one() -> $t<N>
      { $t::new_repeat(One::one()) }
    }
  )
)

macro_rules! from_iterator_impl(
  ($t: ident, $param0: ident $(, $paramN: ident)*) => (
    impl<N, Iter: Iterator<N>> FromIterator<N, Iter> for $t<N>
    {
      fn from_iterator($param0: &mut Iter) -> $t<N>
      { $t::new($param0.next().unwrap() $(, $paramN.next().unwrap())*) }
    }
  )
)

macro_rules! bounded_impl(
  ($t: ident) => (
    impl<N: Bounded + Clone> Bounded for $t<N>
    {
      #[inline]
      fn max_value() -> $t<N>
      { $t::new_repeat(Bounded::max_value()) }

      #[inline]
      fn min_value() -> $t<N>
      { $t::new_repeat(Bounded::min_value()) }
    }
  )
)

macro_rules! to_homogeneous_impl(
  ($t: ident, $t2: ident, $extra: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone + One + Zero> ToHomogeneous<$t2<N>> for $t<N>
    {
      fn to_homogeneous(&self) -> $t2<N>
      {
        let mut res: $t2<N> = One::one();

        res.$comp0    = self.$comp0.clone();
        $( res.$compN = self.$compN.clone(); )*

        res
      }
    }
  )
)

macro_rules! from_homogeneous_impl(
  ($t: ident, $t2: ident, $extra: ident, $comp0: ident $(,$compN: ident)*) => (
    impl<N: Clone + Div<N, N> + One + Zero> FromHomogeneous<$t2<N>> for $t<N>
    {
      fn from_homogeneous(v: &$t2<N>) -> $t<N>
      {
        let mut res: $t<N> = Zero::zero();

        res.$comp0    = v.$comp0.clone();
        $( res.$compN = v.$compN.clone(); )*

        res.scalar_div(&v.$extra);

        res
      }
    }
  )
)
<|endoftext|>


<commit_before>//! # System MenuBar Sample
//!
//! This sample demonstrates how to create a "system" menu bar. It should always be preferred
//! over the `gtk::MenuBar` since it adapts to the targetted system.

extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;
use gtk::{AboutDialog, ToVariant};

use std::env::args;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

fn build_system_menu(application: &gtk::Application) {
    let menu = gio::Menu::new();
    let menu_bar = gio::Menu::new();
    let more_menu = gio::Menu::new();
    let switch_menu = gio::Menu::new();
    let settings_menu = gio::Menu::new();
    let submenu = gio::Menu::new();

    // The first argument is the label of the menu item whereas the second is the action name. It'll
    // makes more sense when you'll be reading the "add_actions" function.
    menu.append(Some("Quit"), Some("app.quit"));

    switch_menu.append(Some("Switch"), Some("app.switch"));
    menu_bar.append_submenu(Some("_Switch"), &switch_menu);

    settings_menu.append(Some("Sub another"), Some("app.sub_another"));
    submenu.append(Some("Sub sub another"), Some("app.sub_sub_another"));
    submenu.append(Some("Sub sub another2"), Some("app.sub_sub_another2"));
    settings_menu.append_submenu(Some("Sub menu"), &submenu);
    menu_bar.append_submenu(Some("_Another"), &settings_menu);

    more_menu.append(Some("About"), Some("app.about"));
    menu_bar.append_submenu(Some("?"), &more_menu);

    application.set_app_menu(Some(&menu));
    application.set_menubar(Some(&menu_bar));
}

// This function creates "actions" which connect on the declared actions from the menu items.
fn add_actions(
    application: &gtk::Application,
    switch: &gtk::Switch,
    label: &gtk::Label,
    window: &gtk::ApplicationWindow,
) {
    // Thanks to this method, we can say that this item is actually a checkbox.
    let switch_action = gio::SimpleAction::new_stateful("switch", None, &false.to_variant());
    switch_action.connect_activate(clone!(switch => move |g, _| {
        let mut is_active = false;
        if let Some(g) = g.get_state() {
            is_active = g.get().expect("couldn't get bool");
            // We update the state of the toggle.
            switch.set_active(!is_active);
        }
        // We need to change the toggle state ourselves. `gio` dark magic.
        g.change_state(&(!is_active).to_variant());
    }));

    // The same goes the around way: if we update the switch state, we need to update the menu
    // item's state.
    switch.connect_property_active_notify(clone!(switch_action => move |s| {
        switch_action.change_state(&s.get_active().to_variant());
    }));

    let sub_another = gio::SimpleAction::new("sub_another", None);
    sub_another.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub another menu item clicked");
    }));
    let sub_sub_another = gio::SimpleAction::new("sub_sub_another", None);
    sub_sub_another.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub sub another menu item clicked");
    }));
    let sub_sub_another2 = gio::SimpleAction::new("sub_sub_another2", None);
    sub_sub_another2.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub sub another2 menu item clicked");
    }));

    let quit = gio::SimpleAction::new("quit", None);
    quit.connect_activate(clone!(window => move |_, _| {
        window.destroy();
    }));

    let about = gio::SimpleAction::new("about", None);
    about.connect_activate(clone!(window => move |_, _| {
        let p = AboutDialog::new();
        p.set_authors(&["gtk-rs developers"]);
        p.set_website_label(Some("gtk-rs"));
        p.set_website(Some("http://gtk-rs.org"));
        p.set_authors(&["Gtk-rs developers"]);
        p.set_title("About!");
        p.set_transient_for(Some(&window));
        p.run();
        p.destroy();
    }));

    // We need to add all the actions to the application so they can be taken into account.
    application.add_action(&about);
    application.add_action(&quit);
    application.add_action(&sub_another);
    application.add_action(&sub_sub_another);
    application.add_action(&sub_sub_another2);
    application.add_action(&switch_action);
}

fn add_accelerators(application: &gtk::Application) {
    application.set_accels_for_action("app.about", &["F1"]);
    // `Primary` is a platform-agnostic accelerator modifier.
    // On Windows and Linux, `Primary` maps to the `Ctrl` key,
    // and on macOS it maps to the `command` key.
    application.set_accels_for_action("app.quit", &["<Primary>Q"]);
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    window.set_title("System menu bar");
    window.set_border_width(10);
    window.set_position(gtk::WindowPosition::Center);
    window.set_default_size(350, 70);

    let v_box = gtk::Box::new(gtk::Orientation::Vertical, 10);
    let label = gtk::Label::new(Some("Nothing happened yet"));
    let switch = gtk::Switch::new();

    v_box.pack_start(&label, false, false, 0);
    v_box.pack_start(&switch, true, true, 0);
    window.add(&v_box);

    build_system_menu(application);

    add_actions(application, &switch, &label, &window);

    window.show_all();
}

fn main() {
    let application = gtk::Application::new(
        Some("com.github.gtk-rs.examples.menu_bar_system"),
        Default::default(),
    )
    .expect("Initialization failed...");

    application.connect_startup(|app| {
        add_accelerators(app);
    });
    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}
<commit_msg>Update menu_bar_system.rs<commit_after>//! # System MenuBar Sample
//!
//! This sample demonstrates how to create a "system" menu bar. It should always be preferred
//! over the `gtk::MenuBar` since it adapts to the targetted system.

extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;
use gtk::{AboutDialog, ToVariant};

use std::env::args;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

fn build_system_menu(application: &gtk::Application) {
    let menu = gio::Menu::new();
    let menu_bar = gio::Menu::new();
    let more_menu = gio::Menu::new();
    let switch_menu = gio::Menu::new();
    let settings_menu = gio::Menu::new();
    let submenu = gio::Menu::new();

    // The first argument is the label of the menu item whereas the second is the action name. It'll
    // makes more sense when you'll be reading the "add_actions" function.
    menu.append(Some("Quit"), Some("app.quit"));

    switch_menu.append(Some("Switch"), Some("app.switch"));
    menu_bar.append_submenu(Some("_Switch"), &switch_menu);

    settings_menu.append(Some("Sub another"), Some("app.sub_another"));
    submenu.append(Some("Sub sub another"), Some("app.sub_sub_another"));
    submenu.append(Some("Sub sub another2"), Some("app.sub_sub_another2"));
    settings_menu.append_submenu(Some("Sub menu"), &submenu);
    menu_bar.append_submenu(Some("_Another"), &settings_menu);

    more_menu.append(Some("About"), Some("app.about"));
    menu_bar.append_submenu(Some("?"), &more_menu);

    application.set_app_menu(Some(&menu));
    application.set_menubar(Some(&menu_bar));
}

/// This function creates "actions" which connect on the declared actions from the menu items.
fn add_actions(
    application: &gtk::Application,
    switch: &gtk::Switch,
    label: &gtk::Label,
    window: &gtk::ApplicationWindow,
) {
    // Thanks to this method, we can say that this item is actually a checkbox.
    let switch_action = gio::SimpleAction::new_stateful("switch", None, &false.to_variant());
    switch_action.connect_activate(clone!(switch => move |g, _| {
        let mut is_active = false;
        if let Some(g) = g.get_state() {
            is_active = g.get().expect("couldn't get bool");
            // We update the state of the toggle.
            switch.set_active(!is_active);
        }
        // We need to change the toggle state ourselves. `gio` dark magic.
        g.change_state(&(!is_active).to_variant());
    }));

    // The same goes the around way: if we update the switch state, we need to update the menu
    // item's state.
    switch.connect_property_active_notify(clone!(switch_action => move |s| {
        switch_action.change_state(&s.get_active().to_variant());
    }));

    let sub_another = gio::SimpleAction::new("sub_another", None);
    sub_another.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub another menu item clicked");
    }));
    let sub_sub_another = gio::SimpleAction::new("sub_sub_another", None);
    sub_sub_another.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub sub another menu item clicked");
    }));
    let sub_sub_another2 = gio::SimpleAction::new("sub_sub_another2", None);
    sub_sub_another2.connect_activate(clone!(label => move |_, _| {
        label.set_text("sub sub another2 menu item clicked");
    }));

    let quit = gio::SimpleAction::new("quit", None);
    quit.connect_activate(clone!(window => move |_, _| {
        window.destroy();
    }));

    let about = gio::SimpleAction::new("about", None);
    about.connect_activate(clone!(window => move |_, _| {
        let p = AboutDialog::new();
        p.set_website_label(Some("gtk-rs"));
        p.set_website(Some("http://gtk-rs.org"));
        p.set_authors(&["Gtk-rs developers"]);
        p.set_title("About!");
        p.set_transient_for(Some(&window));
        p.run();
        p.destroy();
    }));

    // We need to add all the actions to the application so they can be taken into account.
    application.add_action(&about);
    application.add_action(&quit);
    application.add_action(&sub_another);
    application.add_action(&sub_sub_another);
    application.add_action(&sub_sub_another2);
    application.add_action(&switch_action);
}

fn add_accelerators(application: &gtk::Application) {
    application.set_accels_for_action("app.about", &["F1"]);
    // `Primary` is a platform-agnostic accelerator modifier.
    // On Windows and Linux, `Primary` maps to the `Ctrl` key,
    // and on macOS it maps to the `command` key.
    application.set_accels_for_action("app.quit", &["<Primary>Q"]);
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    window.set_title("System menu bar");
    window.set_border_width(10);
    window.set_position(gtk::WindowPosition::Center);
    window.set_default_size(350, 70);

    let v_box = gtk::Box::new(gtk::Orientation::Vertical, 10);
    let label = gtk::Label::new(Some("Nothing happened yet"));
    let switch = gtk::Switch::new();

    v_box.pack_start(&label, false, false, 0);
    v_box.pack_start(&switch, true, true, 0);
    window.add(&v_box);

    build_system_menu(application);

    add_actions(application, &switch, &label, &window);

    window.show_all();
}

fn main() {
    let application = gtk::Application::new(
        Some("com.github.gtk-rs.examples.menu_bar_system"),
        Default::default(),
    )
    .expect("Initialization failed...");

    application.connect_startup(|app| {
        add_accelerators(app);
    });
    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}
<|endoftext|>


<commit_before>use std::f32;
use glfw;
use glfw::{Key, MouseButton, Action, WindowEvent};
use num::Zero;
use na::{Point3, Vector2, Vector3, Matrix4, Isometry3, Perspective3, Translation3};
use na;
use camera::Camera;

/// First-person camera mode.
///
///   * Left button press + drag - look around
///   * Right button press + drag - translates the camera position on the plane orthogonal to the
///   view direction
///   * Scroll in/out - zoom in/out
#[derive(Debug, Clone)]
pub struct FirstPerson {
    eye:             Point3<f32>,
    yaw:             f32,
    pitch:           f32,

    yaw_step:        f32,
    pitch_step:      f32,
    move_step:       f32,
    rotate_button:   Option<MouseButton>,
    drag_button:     Option<MouseButton>,
    up_key:          Option<Key>,
    down_key:        Option<Key>,
    left_key:        Option<Key>,
    right_key:       Option<Key>,

    projection:      Perspective3<f32>,
    proj_view:       Matrix4<f32>,
    inverse_proj_view:   Matrix4<f32>,
    last_cursor_pos: Vector2<f32>
}

impl FirstPerson {
    /// Creates a first person camera with default sensitivity values.
    pub fn new(eye: Point3<f32>, at: Point3<f32>) -> FirstPerson {
        FirstPerson::new_with_frustrum(f32::consts::PI / 4.0, 0.1, 1024.0, eye, at)
    }

    /// Creates a new first person camera with default sensitivity values.
    pub fn new_with_frustrum(fov:    f32,
                             znear:  f32,
                             zfar:   f32,
                             eye:    Point3<f32>,
                             at:     Point3<f32>) -> FirstPerson {
        let mut res = FirstPerson {
            eye:             Point3::new(0.0, 0.0, 0.0),
            yaw:             0.0,
            pitch:           0.0,
            yaw_step:        0.005,
            pitch_step:      0.005,
            move_step:       0.5,
            rotate_button:   Some(glfw::MouseButtonLeft),
            drag_button:     Some(glfw::MouseButtonRight),
            up_key:          Some(Key::Up),
            down_key:        Some(Key::Down),
            left_key:        Some(Key::Left),
            right_key:       Some(Key::Right),
            projection:      Perspective3::new(800.0 / 600.0, fov, znear, zfar),
            proj_view:       na::zero(),
            inverse_proj_view:   na::zero(),
            last_cursor_pos: na::zero(),
        };

        res.look_at(eye, at);

        res
    }

    /// Sets the translational increment per arrow press.
    ///
    /// The default value is 0.5.
    #[inline]
    pub fn set_move_step(&mut self, step: f32) {
        self.move_step = step;
    }

    /// Sets the pitch increment per mouse movement.
    ///
    /// The default value is 0.005.
    #[inline]
    pub fn set_pitch_step(&mut self, step: f32) {
        self.pitch_step = step;
    }

    /// Sets the yaw increment per mouse movement.
    ///
    /// The default value is 0.005.
    #[inline]
    pub fn set_yaw_step(&mut self, step: f32) {
        self.yaw_step = step;
    }

    /// Gets the translational increment per arrow press.
    #[inline]
    pub fn move_step(&self) -> f32 {
        self.move_step
    }

    /// Gets the pitch increment per mouse movement.
    #[inline]
    pub fn pitch_step(&self) -> f32 {
        self.pitch_step
    }

    /// Gets the yaw  increment per mouse movement.
    #[inline]
    pub fn yaw_step(&self) -> f32 {
        self.yaw_step
    }

    /// Changes the orientation and position of the camera to look at the specified point.
    pub fn look_at(&mut self, eye: Point3<f32>, at: Point3<f32>) {
        let dist  = na::norm(&(eye - at));

        let pitch = ((at.y - eye.y) / dist).acos();
        let yaw   = (at.z - eye.z).atan2(at.x - eye.x);

        self.eye   = eye;
        self.yaw   = yaw;
        self.pitch = pitch;
        self.update_projviews();
    }

    /// The point the camera is looking at.
    pub fn at(&self) -> Point3<f32> {
        let ax = self.eye.x + self.yaw.cos() * self.pitch.sin();
        let ay = self.eye.y + self.pitch.cos();
        let az = self.eye.z + self.yaw.sin() * self.pitch.sin();

        Point3::new(ax, ay, az)
    }

    fn update_restrictions(&mut self) {
        if self.pitch <= 0.01 {
            self.pitch = 0.01
        }

        let _pi: f32 = f32::consts::PI;
        if self.pitch > _pi - 0.01 {
            self.pitch = _pi - 0.01
        }
    }

    /// The button used to rotate the FirstPerson camera.
    pub fn rotate_button(&self) -> Option<MouseButton> {
        self.rotate_button
    }

    /// Set the button used to rotate the FirstPerson camera.
    /// Use None to disable rotation.
    pub fn rebind_rotate_button(&mut self, new_button: Option<MouseButton>) {
        self.rotate_button = new_button;
    }

    /// The button used to drag the FirstPerson camera.
    pub fn drag_button(&self) -> Option<MouseButton> {
        self.drag_button
    }

    /// Set the button used to drag the FirstPerson camera.
    /// Use None to disable dragging.
    pub fn rebind_drag_button(&mut self, new_button: Option<MouseButton>) {
        self.drag_button = new_button;
    }

    /// The movement button for up.
    pub fn up_key(&self) -> Option<Key> {
        self.up_key
    }

    /// The movement button for down.
    pub fn down_key(&self) -> Option<Key> {
        self.down_key
    }

    /// The movement button for left.
    pub fn left_key(&self) -> Option<Key> {
        self.left_key
    }

    /// The movement button for right.
    pub fn right_key(&self) -> Option<Key> {
        self.right_key
    }

    /// Set the movement button for up.
    /// Use None to disable movement in this direction.
    pub fn rebind_up_key(&mut self, new_key: Option<Key>) {
        self.up_key = new_key;
    }

    /// Set the movement button for down.
    /// Use None to disable movement in this direction.
    pub fn rebind_down_key(&mut self, new_key: Option<Key>) {
        self.down_key = new_key;
    }

    /// Set the movement button for left.
    /// Use None to disable movement in this direction.
    pub fn rebind_left_key(&mut self, new_key: Option<Key>) {
        self.left_key = new_key;
    }

    /// Set the movement button for right.
    /// Use None to disable movement in this direction.
    pub fn rebind_right_key(&mut self, new_key: Option<Key>) {
        self.right_key = new_key;
    }

    /// Disable the movement buttons for up, down, left and right.
    pub fn unbind_movement_keys(&mut self) {
        self.up_key    = None;
        self.down_key  = None;
        self.left_key  = None;
        self.right_key = None;
    }

    #[doc(hidden)]
    pub fn handle_left_button_displacement(&mut self, dpos: &Vector2<f32>) {
        self.yaw   = self.yaw   + dpos.x * self.yaw_step;
        self.pitch = self.pitch + dpos.y * self.pitch_step;

        self.update_restrictions();
        self.update_projviews();
    }

    #[doc(hidden)]
    pub fn handle_right_button_displacement(&mut self, dpos: &Vector2<f32>) {
        let at        = self.at();
        let dir       = na::normalize(&(at - self.eye));
        let tangent   = na::normalize(&Vector3::y().cross(&dir));
        let bitangent = dir.cross(&tangent);

        self.eye = self.eye + tangent * (0.01 * dpos.x / 10.0) + bitangent * (0.01 * dpos.y / 10.0);
        self.update_restrictions();
        self.update_projviews();
    }

    #[doc(hidden)]
    pub fn handle_scroll(&mut self, yoff: f32) {
        let front = self.view_transform() * Vector3::z();

        self.eye = self.eye + front * (self.move_step * yoff);

        self.update_restrictions();
        self.update_projviews();
    }

    fn update_projviews(&mut self) {
        let _ = self.proj_view = *self.projection.as_matrix() * self.view_transform().to_homogeneous();
        let _ = self.proj_view.try_inverse().map(|inverse_proj| self.inverse_proj_view = inverse_proj);
    }

    /// The direction this camera is looking at.
    pub fn eye_dir(&self) -> Vector3<f32> {
        na::normalize(&(self.at() - self.eye))
    }

    /// The direction this camera is being moved by the keyboard keys for a given set of key states.
    pub fn move_dir(&self, up: bool, down: bool, right: bool, left: bool) -> Vector3<f32> {
        let t      = self.view_transform();
        let frontv = t * Vector3::z();
        let rightv = t * Vector3::x();

        let mut movement = na::zero::<Vector3<f32>>();

        if up {
            movement = movement + frontv
        }

        if down {
            movement = movement - frontv
        }

        if right {
            movement = movement - rightv
        }

        if left {
            movement =  movement + rightv
        }

        if movement.is_zero() {
            movement
        }
        else {
            na::normalize(&movement)
        }
    }

    /// Translates in-place this camera by `t`.
    #[inline]
    pub fn translate_mut(&mut self, t: &Translation3<f32>) {
        let new_eye = t * self.eye;

        self.set_eye(new_eye);
    }

    /// Translates this camera by `t`.
    #[inline]
    pub fn translate(&self, t: &Translation3<f32>) -> FirstPerson {
        let mut res = self.clone();
        res.translate_mut(t);
        res
    }

    /// Sets the eye of this camera to `eye`.
    #[inline]
    fn set_eye(&mut self, eye: Point3<f32>) {
        self.eye = eye;
        self.update_restrictions();
        self.update_projviews();
    }
}

impl Camera for FirstPerson {
    fn clip_planes(&self) -> (f32, f32) {
        (self.projection.znear(), self.projection.zfar())
    }

    /// The camera view transformation (i-e transformation without projection).
    fn view_transform(&self) -> Isometry3<f32> {
        Isometry3::look_at_rh(&self.eye, &self.at(), &Vector3::y())
    }

    fn handle_event(&mut self, window: &glfw::Window, event: &WindowEvent) {
        match *event {
            WindowEvent::CursorPos(x, y) => {
                let curr_pos = Vector2::new(x as f32, y as f32);

                if let Some(rotate_button) = self.rotate_button {
                    if window.get_mouse_button(rotate_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_left_button_displacement(&dpos)
                    }
                }

                if let Some(drag_button) = self.drag_button {
                    if window.get_mouse_button(drag_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_right_button_displacement(&dpos)
                    }
                }

                self.last_cursor_pos = curr_pos;
            },
            WindowEvent::Scroll(_, off) => self.handle_scroll(off as f32),
            WindowEvent::FramebufferSize(w, h) => {
                self.projection.set_aspect(w as f32 / h as f32);
                self.update_projviews();
            }
            _ => { }
        }
    }

    fn eye(&self) -> Point3<f32> {
        self.eye
    }

    fn transformation(&self) -> Matrix4<f32> {
        self.proj_view
    }

    fn inverse_transformation(&self) -> Matrix4<f32> {
        self.inverse_proj_view
    }

    fn update(&mut self, window: &glfw::Window) {
        let up    = check_optional_key_state(window, self.up_key,    Action::Press);
        let down  = check_optional_key_state(window, self.down_key,  Action::Press);
        let right = check_optional_key_state(window, self.right_key, Action::Press);
        let left  = check_optional_key_state(window, self.left_key,  Action::Press);
        let dir   = self.move_dir(up, down, right, left);

        let move_amount  = dir * self.move_step;
        self.translate_mut(&Translation3::from_vector(move_amount));
    }
}

fn check_optional_key_state(window: &glfw::Window, key: Option<Key>, key_state: Action) -> bool {
    if let Some(actual_key) = key {
        window.get_key(actual_key) == key_state
    } else {
        false
    }
}
<commit_msg>Fix first person camera translation directions.<commit_after>use std::f32;
use glfw;
use glfw::{Key, MouseButton, Action, WindowEvent};
use num::Zero;
use na::{Point3, Vector2, Vector3, Matrix4, Isometry3, Perspective3, Translation3};
use na;
use camera::Camera;

/// First-person camera mode.
///
///   * Left button press + drag - look around
///   * Right button press + drag - translates the camera position on the plane orthogonal to the
///   view direction
///   * Scroll in/out - zoom in/out
#[derive(Debug, Clone)]
pub struct FirstPerson {
    eye:             Point3<f32>,
    yaw:             f32,
    pitch:           f32,

    yaw_step:        f32,
    pitch_step:      f32,
    move_step:       f32,
    rotate_button:   Option<MouseButton>,
    drag_button:     Option<MouseButton>,
    up_key:          Option<Key>,
    down_key:        Option<Key>,
    left_key:        Option<Key>,
    right_key:       Option<Key>,

    projection:      Perspective3<f32>,
    proj_view:       Matrix4<f32>,
    inverse_proj_view:   Matrix4<f32>,
    last_cursor_pos: Vector2<f32>
}

impl FirstPerson {
    /// Creates a first person camera with default sensitivity values.
    pub fn new(eye: Point3<f32>, at: Point3<f32>) -> FirstPerson {
        FirstPerson::new_with_frustrum(f32::consts::PI / 4.0, 0.1, 1024.0, eye, at)
    }

    /// Creates a new first person camera with default sensitivity values.
    pub fn new_with_frustrum(fov:    f32,
                             znear:  f32,
                             zfar:   f32,
                             eye:    Point3<f32>,
                             at:     Point3<f32>) -> FirstPerson {
        let mut res = FirstPerson {
            eye:             Point3::new(0.0, 0.0, 0.0),
            yaw:             0.0,
            pitch:           0.0,
            yaw_step:        0.005,
            pitch_step:      0.005,
            move_step:       0.5,
            rotate_button:   Some(glfw::MouseButtonLeft),
            drag_button:     Some(glfw::MouseButtonRight),
            up_key:          Some(Key::Up),
            down_key:        Some(Key::Down),
            left_key:        Some(Key::Left),
            right_key:       Some(Key::Right),
            projection:      Perspective3::new(800.0 / 600.0, fov, znear, zfar),
            proj_view:       na::zero(),
            inverse_proj_view:   na::zero(),
            last_cursor_pos: na::zero(),
        };

        res.look_at(eye, at);

        res
    }

    /// Sets the translational increment per arrow press.
    ///
    /// The default value is 0.5.
    #[inline]
    pub fn set_move_step(&mut self, step: f32) {
        self.move_step = step;
    }

    /// Sets the pitch increment per mouse movement.
    ///
    /// The default value is 0.005.
    #[inline]
    pub fn set_pitch_step(&mut self, step: f32) {
        self.pitch_step = step;
    }

    /// Sets the yaw increment per mouse movement.
    ///
    /// The default value is 0.005.
    #[inline]
    pub fn set_yaw_step(&mut self, step: f32) {
        self.yaw_step = step;
    }

    /// Gets the translational increment per arrow press.
    #[inline]
    pub fn move_step(&self) -> f32 {
        self.move_step
    }

    /// Gets the pitch increment per mouse movement.
    #[inline]
    pub fn pitch_step(&self) -> f32 {
        self.pitch_step
    }

    /// Gets the yaw  increment per mouse movement.
    #[inline]
    pub fn yaw_step(&self) -> f32 {
        self.yaw_step
    }

    /// Changes the orientation and position of the camera to look at the specified point.
    pub fn look_at(&mut self, eye: Point3<f32>, at: Point3<f32>) {
        let dist  = na::norm(&(eye - at));

        let pitch = ((at.y - eye.y) / dist).acos();
        let yaw   = (at.z - eye.z).atan2(at.x - eye.x);

        self.eye   = eye;
        self.yaw   = yaw;
        self.pitch = pitch;
        self.update_projviews();
    }

    /// The point the camera is looking at.
    pub fn at(&self) -> Point3<f32> {
        let ax = self.eye.x + self.yaw.cos() * self.pitch.sin();
        let ay = self.eye.y + self.pitch.cos();
        let az = self.eye.z + self.yaw.sin() * self.pitch.sin();

        Point3::new(ax, ay, az)
    }

    fn update_restrictions(&mut self) {
        if self.pitch <= 0.01 {
            self.pitch = 0.01
        }

        let _pi: f32 = f32::consts::PI;
        if self.pitch > _pi - 0.01 {
            self.pitch = _pi - 0.01
        }
    }

    /// The button used to rotate the FirstPerson camera.
    pub fn rotate_button(&self) -> Option<MouseButton> {
        self.rotate_button
    }

    /// Set the button used to rotate the FirstPerson camera.
    /// Use None to disable rotation.
    pub fn rebind_rotate_button(&mut self, new_button: Option<MouseButton>) {
        self.rotate_button = new_button;
    }

    /// The button used to drag the FirstPerson camera.
    pub fn drag_button(&self) -> Option<MouseButton> {
        self.drag_button
    }

    /// Set the button used to drag the FirstPerson camera.
    /// Use None to disable dragging.
    pub fn rebind_drag_button(&mut self, new_button: Option<MouseButton>) {
        self.drag_button = new_button;
    }

    /// The movement button for up.
    pub fn up_key(&self) -> Option<Key> {
        self.up_key
    }

    /// The movement button for down.
    pub fn down_key(&self) -> Option<Key> {
        self.down_key
    }

    /// The movement button for left.
    pub fn left_key(&self) -> Option<Key> {
        self.left_key
    }

    /// The movement button for right.
    pub fn right_key(&self) -> Option<Key> {
        self.right_key
    }

    /// Set the movement button for up.
    /// Use None to disable movement in this direction.
    pub fn rebind_up_key(&mut self, new_key: Option<Key>) {
        self.up_key = new_key;
    }

    /// Set the movement button for down.
    /// Use None to disable movement in this direction.
    pub fn rebind_down_key(&mut self, new_key: Option<Key>) {
        self.down_key = new_key;
    }

    /// Set the movement button for left.
    /// Use None to disable movement in this direction.
    pub fn rebind_left_key(&mut self, new_key: Option<Key>) {
        self.left_key = new_key;
    }

    /// Set the movement button for right.
    /// Use None to disable movement in this direction.
    pub fn rebind_right_key(&mut self, new_key: Option<Key>) {
        self.right_key = new_key;
    }

    /// Disable the movement buttons for up, down, left and right.
    pub fn unbind_movement_keys(&mut self) {
        self.up_key    = None;
        self.down_key  = None;
        self.left_key  = None;
        self.right_key = None;
    }

    #[doc(hidden)]
    pub fn handle_left_button_displacement(&mut self, dpos: &Vector2<f32>) {
        self.yaw   = self.yaw   + dpos.x * self.yaw_step;
        self.pitch = self.pitch + dpos.y * self.pitch_step;

        self.update_restrictions();
        self.update_projviews();
    }

    #[doc(hidden)]
    pub fn handle_right_button_displacement(&mut self, dpos: &Vector2<f32>) {
        let at        = self.at();
        let dir       = na::normalize(&(at - self.eye));
        let tangent   = na::normalize(&Vector3::y().cross(&dir));
        let bitangent = dir.cross(&tangent);

        self.eye = self.eye + tangent * (0.01 * dpos.x / 10.0) + bitangent * (0.01 * dpos.y / 10.0);
        self.update_restrictions();
        self.update_projviews();
    }

    #[doc(hidden)]
    pub fn handle_scroll(&mut self, yoff: f32) {
        let front = self.observer_frame() * Vector3::z();

        self.eye = self.eye + front * (self.move_step * yoff);

        self.update_restrictions();
        self.update_projviews();
    }

    fn update_projviews(&mut self) {
        let _ = self.proj_view = *self.projection.as_matrix() * self.view_transform().to_homogeneous();
        let _ = self.proj_view.try_inverse().map(|inverse_proj| self.inverse_proj_view = inverse_proj);
    }

    /// The direction this camera is looking at.
    pub fn eye_dir(&self) -> Vector3<f32> {
        na::normalize(&(self.at() - self.eye))
    }

    /// The direction this camera is being moved by the keyboard keys for a given set of key states.
    pub fn move_dir(&self, up: bool, down: bool, right: bool, left: bool) -> Vector3<f32> {
        let t      = self.observer_frame();
        let frontv = t * Vector3::z();
        let rightv = t * Vector3::x();

        let mut movement = na::zero::<Vector3<f32>>();

        if up {
            movement = movement + frontv
        }

        if down {
            movement = movement - frontv
        }

        if right {
            movement = movement - rightv
        }

        if left {
            movement =  movement + rightv
        }

        if movement.is_zero() {
            movement
        }
        else {
            na::normalize(&movement)
        }
    }

    /// Translates in-place this camera by `t`.
    #[inline]
    pub fn translate_mut(&mut self, t: &Translation3<f32>) {
        let new_eye = t * self.eye;

        self.set_eye(new_eye);
    }

    /// Translates this camera by `t`.
    #[inline]
    pub fn translate(&self, t: &Translation3<f32>) -> FirstPerson {
        let mut res = self.clone();
        res.translate_mut(t);
        res
    }

    /// Sets the eye of this camera to `eye`.
    #[inline]
    fn set_eye(&mut self, eye: Point3<f32>) {
        self.eye = eye;
        self.update_restrictions();
        self.update_projviews();
    }

    /// The camera observer local frame.
    fn observer_frame(&self) -> Isometry3<f32> {
        Isometry3::new_observer_frame(&self.eye, &self.at(), &Vector3::y())
    }
}

impl Camera for FirstPerson {
    fn clip_planes(&self) -> (f32, f32) {
        (self.projection.znear(), self.projection.zfar())
    }

    /// The camera view transformation (i-e transformation without projection).
    fn view_transform(&self) -> Isometry3<f32> {
        Isometry3::look_at_rh(&self.eye, &self.at(), &Vector3::y())
    }

    fn handle_event(&mut self, window: &glfw::Window, event: &WindowEvent) {
        match *event {
            WindowEvent::CursorPos(x, y) => {
                let curr_pos = Vector2::new(x as f32, y as f32);

                if let Some(rotate_button) = self.rotate_button {
                    if window.get_mouse_button(rotate_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_left_button_displacement(&dpos)
                    }
                }

                if let Some(drag_button) = self.drag_button {
                    if window.get_mouse_button(drag_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_right_button_displacement(&dpos)
                    }
                }

                self.last_cursor_pos = curr_pos;
            },
            WindowEvent::Scroll(_, off) => self.handle_scroll(off as f32),
            WindowEvent::FramebufferSize(w, h) => {
                self.projection.set_aspect(w as f32 / h as f32);
                self.update_projviews();
            }
            _ => { }
        }
    }

    fn eye(&self) -> Point3<f32> {
        self.eye
    }

    fn transformation(&self) -> Matrix4<f32> {
        self.proj_view
    }

    fn inverse_transformation(&self) -> Matrix4<f32> {
        self.inverse_proj_view
    }

    fn update(&mut self, window: &glfw::Window) {
        let up    = check_optional_key_state(window, self.up_key,    Action::Press);
        let down  = check_optional_key_state(window, self.down_key,  Action::Press);
        let right = check_optional_key_state(window, self.right_key, Action::Press);
        let left  = check_optional_key_state(window, self.left_key,  Action::Press);
        let dir   = self.move_dir(up, down, right, left);

        let move_amount  = dir * self.move_step;
        self.translate_mut(&Translation3::from_vector(move_amount));
    }
}

fn check_optional_key_state(window: &glfw::Window, key: Option<Key>, key_state: Action) -> bool {
    if let Some(actual_key) = key {
        window.get_key(actual_key) == key_state
    } else {
        false
    }
}
<|endoftext|>


<commit_before>use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;

use if_chain::if_chain;

use crate::utils::SpanlessEq;
use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg};

declare_clippy_lint! {
    /// **What it does:** Checks for string appends of the form `x = x + y` (without
    /// `let`!).
    ///
    /// **Why is this bad?** It's not really bad, but some people think that the
    /// `.push_str(_)` method is more readable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let mut x = "Hello".to_owned();
    /// x = x + ", World";
    ///
    /// // More readable
    /// x += ", World";
    /// x.push_str(", World");
    /// ```
    pub STRING_ADD_ASSIGN,
    pedantic,
    "using `x = x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for all instances of `x + _` where `x` is of type
    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
    /// match.
    ///
    /// **Why is this bad?** It's not bad in and of itself. However, this particular
    /// `Add` implementation is asymmetric (the other operand need not be `String`,
    /// but `x` does), while addition as mathematically defined is symmetric, also
    /// the `String::push_str(_)` function is a perfectly good replacement.
    /// Therefore, some dislike it and wish not to have it in their code.
    ///
    /// That said, other people think that string addition, having a long tradition
    /// in other languages is actually fine, which is why we decided to make this
    /// particular lint `allow` by default.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let x = "Hello".to_owned();
    /// x + ", World";
    /// ```
    pub STRING_ADD,
    restriction,
    "using `x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for the `as_bytes` method called on string literals
    /// that contain only ASCII characters.
    ///
    /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
    /// instead. They are shorter but less discoverable than `as_bytes()`.
    ///
    /// **Known Problems:**
    /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not
    /// equivalent because they have different types. The former is `&[u8]`
    /// while the latter is `&[u8; 3]`. That means in general they will have a
    /// different set of methods and different trait implementations.
    ///
    /// ```rust
    /// fn f(v: Vec<u8>) {}
    ///
    /// f("...".as_bytes().to_owned()); // works
    /// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
    ///
    /// fn g(r: impl std::io::Read) {}
    ///
    /// g("...".as_bytes()); // works
    /// g(b"..."); // does not work
    /// ```
    ///
    /// The actual equivalent of `"str".as_bytes()` with the same type is not
    /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
    /// more readable than a function call.
    ///
    /// **Example:**
    /// ```rust
    /// // Bad
    /// let bs = "a byte string".as_bytes();
    ///
    /// // Good
    /// let bs = b"a byte string";
    /// ```
    pub STRING_LIT_AS_BYTES,
    nursery,
    "calling `as_bytes` on a string literal instead of using a byte string literal"
}

declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);

impl<'tcx> LateLintPass<'tcx> for StringAdd {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if in_external_macro(cx.sess(), e.span) {
            return;
        }

        if let ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) = e.kind
        {
            if is_string(cx, left) {
                if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
                    let parent = get_parent_expr(cx, e);
                    if let Some(p) = parent {
                        if let ExprKind::Assign(ref target, _, _) = p.kind {
                            // avoid duplicate matches
                            if SpanlessEq::new(cx).eq_expr(target, left) {
                                return;
                            }
                        }
                    }
                }
                span_lint(
                    cx,
                    STRING_ADD,
                    e.span,
                    "you added something to a string. Consider using `String::push_str()` instead",
                );
            }
        } else if let ExprKind::Assign(ref target, ref src, _) = e.kind {
            if is_string(cx, target) && is_add(cx, src, target) {
                span_lint(
                    cx,
                    STRING_ADD_ASSIGN,
                    e.span,
                    "you assigned the result of adding something to this string. Consider using \
                     `String::push_str()` instead",
                );
            }
        }
    }
}

fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type))
}

fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
    match src.kind {
        ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) => SpanlessEq::new(cx).eq_expr(target, left),
        ExprKind::Block(ref block, _) => {
            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
        },
        _ => false,
    }
}

// Max length a b"foo" string can take
const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;

declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]);

impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        use crate::utils::{snippet, snippet_with_applicability};
        use rustc_ast::LitKind;

        if_chain! {
            if let ExprKind::MethodCall(path, _, args, _) = &e.kind;
            if path.ident.name == sym!(as_bytes);
            if let ExprKind::Lit(lit) = &args[0].kind;
            if let LitKind::Str(lit_content, _) = &lit.node;
            then {
                let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
                let mut applicability = Applicability::MachineApplicable;
                if callsite.starts_with("include_str!") {
                    span_lint_and_sugg(
                        cx,
                        STRING_LIT_AS_BYTES,
                        e.span,
                        "calling `as_bytes()` on `include_str!(..)`",
                        "consider using `include_bytes!(..)` instead",
                        snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
                            "include_str",
                            "include_bytes",
                            1,
                        ),
                        applicability,
                    );
                } else if lit_content.as_str().is_ascii()
                    && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
                    && !args[0].span.from_expansion()
                {
                    span_lint_and_sugg(
                        cx,
                        STRING_LIT_AS_BYTES,
                        e.span,
                        "calling `as_bytes()` on a string literal",
                        "consider using a byte string literal instead",
                        format!(
                            "b{}",
                            snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
                        ),
                        applicability,
                    );
                }
            }
        }
    }
}
<commit_msg>Make clippy_lints's doc tests succeed<commit_after>use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;

use if_chain::if_chain;

use crate::utils::SpanlessEq;
use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg};

declare_clippy_lint! {
    /// **What it does:** Checks for string appends of the form `x = x + y` (without
    /// `let`!).
    ///
    /// **Why is this bad?** It's not really bad, but some people think that the
    /// `.push_str(_)` method is more readable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let mut x = "Hello".to_owned();
    /// x = x + ", World";
    ///
    /// // More readable
    /// x += ", World";
    /// x.push_str(", World");
    /// ```
    pub STRING_ADD_ASSIGN,
    pedantic,
    "using `x = x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for all instances of `x + _` where `x` is of type
    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
    /// match.
    ///
    /// **Why is this bad?** It's not bad in and of itself. However, this particular
    /// `Add` implementation is asymmetric (the other operand need not be `String`,
    /// but `x` does), while addition as mathematically defined is symmetric, also
    /// the `String::push_str(_)` function is a perfectly good replacement.
    /// Therefore, some dislike it and wish not to have it in their code.
    ///
    /// That said, other people think that string addition, having a long tradition
    /// in other languages is actually fine, which is why we decided to make this
    /// particular lint `allow` by default.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let x = "Hello".to_owned();
    /// x + ", World";
    /// ```
    pub STRING_ADD,
    restriction,
    "using `x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for the `as_bytes` method called on string literals
    /// that contain only ASCII characters.
    ///
    /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
    /// instead. They are shorter but less discoverable than `as_bytes()`.
    ///
    /// **Known Problems:**
    /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not
    /// equivalent because they have different types. The former is `&[u8]`
    /// while the latter is `&[u8; 3]`. That means in general they will have a
    /// different set of methods and different trait implementations.
    ///
    /// ```compile_fail
    /// fn f(v: Vec<u8>) {}
    ///
    /// f("...".as_bytes().to_owned()); // works
    /// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
    ///
    /// fn g(r: impl std::io::Read) {}
    ///
    /// g("...".as_bytes()); // works
    /// g(b"..."); // does not work
    /// ```
    ///
    /// The actual equivalent of `"str".as_bytes()` with the same type is not
    /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
    /// more readable than a function call.
    ///
    /// **Example:**
    /// ```rust
    /// // Bad
    /// let bs = "a byte string".as_bytes();
    ///
    /// // Good
    /// let bs = b"a byte string";
    /// ```
    pub STRING_LIT_AS_BYTES,
    nursery,
    "calling `as_bytes` on a string literal instead of using a byte string literal"
}

declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);

impl<'tcx> LateLintPass<'tcx> for StringAdd {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        if in_external_macro(cx.sess(), e.span) {
            return;
        }

        if let ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) = e.kind
        {
            if is_string(cx, left) {
                if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
                    let parent = get_parent_expr(cx, e);
                    if let Some(p) = parent {
                        if let ExprKind::Assign(ref target, _, _) = p.kind {
                            // avoid duplicate matches
                            if SpanlessEq::new(cx).eq_expr(target, left) {
                                return;
                            }
                        }
                    }
                }
                span_lint(
                    cx,
                    STRING_ADD,
                    e.span,
                    "you added something to a string. Consider using `String::push_str()` instead",
                );
            }
        } else if let ExprKind::Assign(ref target, ref src, _) = e.kind {
            if is_string(cx, target) && is_add(cx, src, target) {
                span_lint(
                    cx,
                    STRING_ADD_ASSIGN,
                    e.span,
                    "you assigned the result of adding something to this string. Consider using \
                     `String::push_str()` instead",
                );
            }
        }
    }
}

fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type))
}

fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
    match src.kind {
        ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) => SpanlessEq::new(cx).eq_expr(target, left),
        ExprKind::Block(ref block, _) => {
            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
        },
        _ => false,
    }
}

// Max length a b"foo" string can take
const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;

declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]);

impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        use crate::utils::{snippet, snippet_with_applicability};
        use rustc_ast::LitKind;

        if_chain! {
            if let ExprKind::MethodCall(path, _, args, _) = &e.kind;
            if path.ident.name == sym!(as_bytes);
            if let ExprKind::Lit(lit) = &args[0].kind;
            if let LitKind::Str(lit_content, _) = &lit.node;
            then {
                let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
                let mut applicability = Applicability::MachineApplicable;
                if callsite.starts_with("include_str!") {
                    span_lint_and_sugg(
                        cx,
                        STRING_LIT_AS_BYTES,
                        e.span,
                        "calling `as_bytes()` on `include_str!(..)`",
                        "consider using `include_bytes!(..)` instead",
                        snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
                            "include_str",
                            "include_bytes",
                            1,
                        ),
                        applicability,
                    );
                } else if lit_content.as_str().is_ascii()
                    && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
                    && !args[0].span.from_expansion()
                {
                    span_lint_and_sugg(
                        cx,
                        STRING_LIT_AS_BYTES,
                        e.span,
                        "calling `as_bytes()` on a string literal",
                        "consider using a byte string literal instead",
                        format!(
                            "b{}",
                            snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
                        ),
                        applicability,
                    );
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::convert::TryInto;
use std::fmt;

use crate::mir::interpret::{AllocId, ConstValue, Scalar};
use crate::mir::Promoted;
use crate::ty::subst::{InternalSubsts, SubstsRef};
use crate::ty::ParamEnv;
use crate::ty::{self, TyCtxt, TypeFoldable};
use rustc_errors::ErrorReported;
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_target::abi::Size;

use super::ScalarInt;
/// An unevaluated, potentially generic, constant.
///
/// If `substs_` is `None` it means that this anon const
/// still has its default substs.
///
/// We check for all possible substs in `fn default_anon_const_substs`,
/// so refer to that check for more info.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Hash, HashStable)]
pub struct Unevaluated<'tcx, P = Option<Promoted>> {
    pub def: ty::WithOptConstParam<DefId>,
    pub substs_: Option<SubstsRef<'tcx>>,
    pub promoted: P,
}

impl<'tcx> Unevaluated<'tcx> {
    pub fn shrink(self) -> Unevaluated<'tcx, ()> {
        debug_assert_eq!(self.promoted, None);
        Unevaluated { def: self.def, substs_: self.substs_, promoted: () }
    }
}

impl<'tcx> Unevaluated<'tcx, ()> {
    pub fn expand(self) -> Unevaluated<'tcx> {
        Unevaluated { def: self.def, substs_: self.substs_, promoted: None }
    }
}

impl<'tcx, P: Default> Unevaluated<'tcx, P> {
    pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> {
        Unevaluated { def, substs_: Some(substs), promoted: Default::default() }
    }
}

impl<'tcx, P: Default + PartialEq + fmt::Debug> Unevaluated<'tcx, P> {
    pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> {
        self.substs_.unwrap_or_else(|| {
            // We must not use the parents default substs for promoted constants
            // as that can result in incorrect substs and calls the `default_anon_const_substs`
            // for something that might not actually be a constant.
            debug_assert_eq!(self.promoted, Default::default());
            tcx.default_anon_const_substs(self.def.did)
        })
    }
}

/// Represents a constant in Rust.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable)]
pub enum ConstKind<'tcx> {
    /// A const generic parameter.
    Param(ty::ParamConst),

    /// Infer the value of the const.
    Infer(InferConst<'tcx>),

    /// Bound const variable, used only when preparing a trait query.
    Bound(ty::DebruijnIndex, ty::BoundVar),

    /// A placeholder const - universally quantified higher-ranked const.
    Placeholder(ty::PlaceholderConst<'tcx>),

    /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
    /// variants when the code is monomorphic enough for that.
    Unevaluated(Unevaluated<'tcx>),

    /// Used to hold computed value.
    Value(ConstValue<'tcx>),

    /// A placeholder for a const which could not be computed; this is
    /// propagated to avoid useless error messages.
    Error(ty::DelaySpanBugEmitted),
}

#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(ConstKind<'_>, 40);

impl<'tcx> ConstKind<'tcx> {
    #[inline]
    pub fn try_to_value(self) -> Option<ConstValue<'tcx>> {
        if let ConstKind::Value(val) = self { Some(val) } else { None }
    }

    #[inline]
    pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
        self.try_to_value()?.try_to_scalar()
    }

    #[inline]
    pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
        Some(self.try_to_value()?.try_to_scalar()?.assert_int())
    }

    #[inline]
    pub fn try_to_bits(self, size: Size) -> Option<u128> {
        self.try_to_scalar_int()?.to_bits(size).ok()
    }

    #[inline]
    pub fn try_to_bool(self) -> Option<bool> {
        self.try_to_scalar_int()?.try_into().ok()
    }

    #[inline]
    pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
        self.try_to_value()?.try_to_machine_usize(tcx)
    }
}

/// An inference variable for a const, for use in const generics.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
#[derive(HashStable)]
pub enum InferConst<'tcx> {
    /// Infer the value of the const.
    Var(ty::ConstVid<'tcx>),
    /// A fresh const variable. See `infer::freshen` for more details.
    Fresh(u32),
}

impl<'tcx> ConstKind<'tcx> {
    #[inline]
    /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
    /// unevaluated constant.
    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
        self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
    }

    #[inline]
    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
    /// return `None`.
    pub(super) fn try_eval(
        self,
        tcx: TyCtxt<'tcx>,
        param_env: ParamEnv<'tcx>,
    ) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
        if let ConstKind::Unevaluated(unevaluated) = self {
            use crate::mir::interpret::ErrorHandled;

            // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
            // also does later, but we want to do it before checking for
            // inference variables.
            // Note that we erase regions *before* calling `with_reveal_all_normalized`,
            // so that we don't try to invoke this query with
            // any region variables.
            let param_env_and = tcx
                .erase_regions(param_env)
                .with_reveal_all_normalized(tcx)
                .and(tcx.erase_regions(unevaluated));

            // HACK(eddyb) when the query key would contain inference variables,
            // attempt using identity substs and `ParamEnv` instead, that will succeed
            // when the expression doesn't depend on any parameters.
            // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
            // we can call `infcx.const_eval_resolve` which handles inference variables.
            let param_env_and = if param_env_and.needs_infer() {
                tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
                    def: unevaluated.def,
                    substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)),
                    promoted: unevaluated.promoted,
                })
            } else {
                param_env_and
            };

            // FIXME(eddyb) maybe the `const_eval_*` methods should take
            // `ty::ParamEnvAnd` instead of having them separate.
            let (param_env, unevaluated) = param_env_and.into_parts();
            // try to resolve e.g. associated constants to their definition on an impl, and then
            // evaluate the const.
            match tcx.const_eval_resolve(param_env, unevaluated, None) {
                // NOTE(eddyb) `val` contains no lifetimes/types/consts,
                // and we use the original type, so nothing from `substs`
                // (which may be identity substs, see above),
                // can leak through `val` into the const we return.
                Ok(val) => Some(Ok(val)),
                Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
                Err(ErrorHandled::Reported(e)) => Some(Err(e)),
            }
        } else {
            None
        }
    }
}
<commit_msg>inline stuff<commit_after>use std::convert::TryInto;
use std::fmt;

use crate::mir::interpret::{AllocId, ConstValue, Scalar};
use crate::mir::Promoted;
use crate::ty::subst::{InternalSubsts, SubstsRef};
use crate::ty::ParamEnv;
use crate::ty::{self, TyCtxt, TypeFoldable};
use rustc_errors::ErrorReported;
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_target::abi::Size;

use super::ScalarInt;
/// An unevaluated, potentially generic, constant.
///
/// If `substs_` is `None` it means that this anon const
/// still has its default substs.
///
/// We check for all possible substs in `fn default_anon_const_substs`,
/// so refer to that check for more info.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Hash, HashStable)]
pub struct Unevaluated<'tcx, P = Option<Promoted>> {
    pub def: ty::WithOptConstParam<DefId>,
    pub substs_: Option<SubstsRef<'tcx>>,
    pub promoted: P,
}

impl<'tcx> Unevaluated<'tcx> {
    #[inline]
    pub fn shrink(self) -> Unevaluated<'tcx, ()> {
        debug_assert_eq!(self.promoted, None);
        Unevaluated { def: self.def, substs_: self.substs_, promoted: () }
    }
}

impl<'tcx> Unevaluated<'tcx, ()> {
    #[inline]
    pub fn expand(self) -> Unevaluated<'tcx> {
        Unevaluated { def: self.def, substs_: self.substs_, promoted: None }
    }
}

impl<'tcx, P: Default> Unevaluated<'tcx, P> {
    #[inline]
    pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> {
        Unevaluated { def, substs_: Some(substs), promoted: Default::default() }
    }
}

impl<'tcx, P: Default + PartialEq + fmt::Debug> Unevaluated<'tcx, P> {
    #[inline]
    pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> {
        self.substs_.unwrap_or_else(|| {
            // We must not use the parents default substs for promoted constants
            // as that can result in incorrect substs and calls the `default_anon_const_substs`
            // for something that might not actually be a constant.
            debug_assert_eq!(self.promoted, Default::default());
            tcx.default_anon_const_substs(self.def.did)
        })
    }
}

/// Represents a constant in Rust.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable)]
pub enum ConstKind<'tcx> {
    /// A const generic parameter.
    Param(ty::ParamConst),

    /// Infer the value of the const.
    Infer(InferConst<'tcx>),

    /// Bound const variable, used only when preparing a trait query.
    Bound(ty::DebruijnIndex, ty::BoundVar),

    /// A placeholder const - universally quantified higher-ranked const.
    Placeholder(ty::PlaceholderConst<'tcx>),

    /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
    /// variants when the code is monomorphic enough for that.
    Unevaluated(Unevaluated<'tcx>),

    /// Used to hold computed value.
    Value(ConstValue<'tcx>),

    /// A placeholder for a const which could not be computed; this is
    /// propagated to avoid useless error messages.
    Error(ty::DelaySpanBugEmitted),
}

#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(ConstKind<'_>, 40);

impl<'tcx> ConstKind<'tcx> {
    #[inline]
    pub fn try_to_value(self) -> Option<ConstValue<'tcx>> {
        if let ConstKind::Value(val) = self { Some(val) } else { None }
    }

    #[inline]
    pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
        self.try_to_value()?.try_to_scalar()
    }

    #[inline]
    pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
        Some(self.try_to_value()?.try_to_scalar()?.assert_int())
    }

    #[inline]
    pub fn try_to_bits(self, size: Size) -> Option<u128> {
        self.try_to_scalar_int()?.to_bits(size).ok()
    }

    #[inline]
    pub fn try_to_bool(self) -> Option<bool> {
        self.try_to_scalar_int()?.try_into().ok()
    }

    #[inline]
    pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
        self.try_to_value()?.try_to_machine_usize(tcx)
    }
}

/// An inference variable for a const, for use in const generics.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
#[derive(HashStable)]
pub enum InferConst<'tcx> {
    /// Infer the value of the const.
    Var(ty::ConstVid<'tcx>),
    /// A fresh const variable. See `infer::freshen` for more details.
    Fresh(u32),
}

impl<'tcx> ConstKind<'tcx> {
    #[inline]
    /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
    /// unevaluated constant.
    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
        self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
    }

    #[inline]
    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
    /// return `None`.
    pub(super) fn try_eval(
        self,
        tcx: TyCtxt<'tcx>,
        param_env: ParamEnv<'tcx>,
    ) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
        if let ConstKind::Unevaluated(unevaluated) = self {
            use crate::mir::interpret::ErrorHandled;

            // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
            // also does later, but we want to do it before checking for
            // inference variables.
            // Note that we erase regions *before* calling `with_reveal_all_normalized`,
            // so that we don't try to invoke this query with
            // any region variables.
            let param_env_and = tcx
                .erase_regions(param_env)
                .with_reveal_all_normalized(tcx)
                .and(tcx.erase_regions(unevaluated));

            // HACK(eddyb) when the query key would contain inference variables,
            // attempt using identity substs and `ParamEnv` instead, that will succeed
            // when the expression doesn't depend on any parameters.
            // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
            // we can call `infcx.const_eval_resolve` which handles inference variables.
            let param_env_and = if param_env_and.needs_infer() {
                tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
                    def: unevaluated.def,
                    substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)),
                    promoted: unevaluated.promoted,
                })
            } else {
                param_env_and
            };

            // FIXME(eddyb) maybe the `const_eval_*` methods should take
            // `ty::ParamEnvAnd` instead of having them separate.
            let (param_env, unevaluated) = param_env_and.into_parts();
            // try to resolve e.g. associated constants to their definition on an impl, and then
            // evaluate the const.
            match tcx.const_eval_resolve(param_env, unevaluated, None) {
                // NOTE(eddyb) `val` contains no lifetimes/types/consts,
                // and we use the original type, so nothing from `substs`
                // (which may be identity substs, see above),
                // can leak through `val` into the const we return.
                Ok(val) => Some(Ok(val)),
                Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
                Err(ErrorHandled::Reported(e)) => Some(Err(e)),
            }
        } else {
            None
        }
    }
}
<|endoftext|>