]> git.lizzy.rs Git - rust.git/blobdiff - src/libcore/ops.rs
rollup merge of #21457: alexcrichton/issue-21436
[rust.git] / src / libcore / ops.rs
index 853e4adb892955c8f34ee931f0f1fc4bf031e46d..e15c1001f0e64ec0bec3ea8ec7a97303b7bb5424 100644 (file)
 //! Implementing these traits allows you to get an effect similar to
 //! overloading operators.
 //!
-//! The values for the right hand side of an operator are automatically
-//! borrowed, so `a + b` is sugar for `a.add(&b)`.
-//!
-//! All of these traits are imported by the prelude, so they are available in
+//! Some of these traits are imported by the prelude, so they are available in
 //! every Rust program.
 //!
+//! Many of the operators take their operands by value. In non-generic
+//! contexts involving built-in types, this is usually not a problem.
+//! However, using these operators in generic code, requires some
+//! attention if values have to be reused as opposed to letting the operators
+//! consume them. One option is to occasionally use `clone()`.
+//! Another option is to rely on the types involved providing additional
+//! operator implementations for references. For example, for a user-defined
+//! type `T` which is supposed to support addition, it is probably a good
+//! idea to have both `T` and `&T` implement the traits `Add<T>` and `Add<&T>`
+//! so that generic code can be written without unnecessary cloning.
+//!
 //! # Example
 //!
 //! This example creates a `Point` struct that implements `Add` and `Sub`, and then
 //! demonstrates adding and subtracting two `Point`s.
 //!
 //! ```rust
-//! #![feature(associated_types)]
-//!
 //! use std::ops::{Add, Sub};
 //!
 //! #[derive(Show)]
@@ -96,6 +102,58 @@ pub trait Drop {
     fn drop(&mut self);
 }
 
+// implements the unary operator "op &T"
+// based on "op T" where T is expected to be `Copy`able
+macro_rules! forward_ref_unop {
+    (impl $imp:ident, $method:ident for $t:ty) => {
+        #[unstable = "recently added, waiting for dust to settle"]
+        impl<'a> $imp for &'a $t {
+            type Output = <$t as $imp>::Output;
+
+            #[inline]
+            fn $method(self) -> <$t as $imp>::Output {
+                $imp::$method(*self)
+            }
+        }
+    }
+}
+
+// implements binary operators "&T op U", "T op &U", "&T op &U"
+// based on "T op U" where T and U are expected to be `Copy`able
+macro_rules! forward_ref_binop {
+    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
+        #[unstable = "recently added, waiting for dust to settle"]
+        impl<'a> $imp<$u> for &'a $t {
+            type Output = <$t as $imp<$u>>::Output;
+
+            #[inline]
+            fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
+                $imp::$method(*self, other)
+            }
+        }
+
+        #[unstable = "recently added, waiting for dust to settle"]
+        impl<'a> $imp<&'a $u> for $t {
+            type Output = <$t as $imp<$u>>::Output;
+
+            #[inline]
+            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
+                $imp::$method(self, *other)
+            }
+        }
+
+        #[unstable = "recently added, waiting for dust to settle"]
+        impl<'a, 'b> $imp<&'a $u> for &'b $t {
+            type Output = <$t as $imp<$u>>::Output;
+
+            #[inline]
+            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
+                $imp::$method(*self, *other)
+            }
+        }
+    }
+}
+
 /// The `Add` trait is used to specify the functionality of `+`.
 ///
 /// # Example
@@ -104,8 +162,6 @@ pub trait Drop {
 /// calling `add`, and therefore, `main` prints `Adding!`.
 ///
 /// ```rust
-/// #![feature(associated_types)]
-///
 /// use std::ops::Add;
 ///
 /// #[derive(Copy)]
@@ -144,6 +200,8 @@ impl Add for $t {
             #[inline]
             fn add(self, other: $t) -> $t { self + other }
         }
+
+        forward_ref_binop! { impl Add, add for $t, $t }
     )*)
 }
 
@@ -157,8 +215,6 @@ fn add(self, other: $t) -> $t { self + other }
 /// calling `sub`, and therefore, `main` prints `Subtracting!`.
 ///
 /// ```rust
-/// #![feature(associated_types)]
-///
 /// use std::ops::Sub;
 ///
 /// #[derive(Copy)]
@@ -197,6 +253,8 @@ impl Sub for $t {
             #[inline]
             fn sub(self, other: $t) -> $t { self - other }
         }
+
+        forward_ref_binop! { impl Sub, sub for $t, $t }
     )*)
 }
 
@@ -210,8 +268,6 @@ fn sub(self, other: $t) -> $t { self - other }
 /// calling `mul`, and therefore, `main` prints `Multiplying!`.
 ///
 /// ```rust
-/// #![feature(associated_types)]
-///
 /// use std::ops::Mul;
 ///
 /// #[derive(Copy)]
@@ -250,6 +306,8 @@ impl Mul for $t {
             #[inline]
             fn mul(self, other: $t) -> $t { self * other }
         }
+
+        forward_ref_binop! { impl Mul, mul for $t, $t }
     )*)
 }
 
@@ -263,8 +321,6 @@ fn mul(self, other: $t) -> $t { self * other }
 /// calling `div`, and therefore, `main` prints `Dividing!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::Div;
 ///
 /// #[derive(Copy)]
@@ -303,6 +359,8 @@ impl Div for $t {
             #[inline]
             fn div(self, other: $t) -> $t { self / other }
         }
+
+        forward_ref_binop! { impl Div, div for $t, $t }
     )*)
 }
 
@@ -316,8 +374,6 @@ fn div(self, other: $t) -> $t { self / other }
 /// calling `rem`, and therefore, `main` prints `Remainder-ing!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::Rem;
 ///
 /// #[derive(Copy)]
@@ -356,6 +412,8 @@ impl Rem for $t {
             #[inline]
             fn rem(self, other: $t) -> $t { self % other }
         }
+
+        forward_ref_binop! { impl Rem, rem for $t, $t }
     )*)
 }
 
@@ -371,6 +429,8 @@ fn rem(self, other: $t) -> $t {
                 unsafe { $fmod(self, other) }
             }
         }
+
+        forward_ref_binop! { impl Rem, rem for $t, $t }
     }
 }
 
@@ -386,8 +446,6 @@ fn rem(self, other: $t) -> $t {
 /// `neg`, and therefore, `main` prints `Negating!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::Neg;
 ///
 /// struct Foo;
@@ -429,6 +487,8 @@ impl Neg for $t {
             #[stable]
             fn neg(self) -> $t { -self }
         }
+
+        forward_ref_unop! { impl Neg, neg for $t }
     )*)
 }
 
@@ -441,6 +501,8 @@ impl Neg for $t {
             #[inline]
             fn neg(self) -> $t { -(self as $t_signed) as $t }
         }
+
+        forward_ref_unop! { impl Neg, neg for $t }
     }
 }
 
@@ -461,8 +523,6 @@ fn neg(self) -> $t { -(self as $t_signed) as $t }
 /// `not`, and therefore, `main` prints `Not-ing!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::Not;
 ///
 /// struct Foo;
@@ -502,6 +562,8 @@ impl Not for $t {
             #[inline]
             fn not(self) -> $t { !self }
         }
+
+        forward_ref_unop! { impl Not, not for $t }
     )*)
 }
 
@@ -515,8 +577,6 @@ fn not(self) -> $t { !self }
 /// calling `bitand`, and therefore, `main` prints `Bitwise And-ing!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::BitAnd;
 ///
 /// #[derive(Copy)]
@@ -555,6 +615,8 @@ impl BitAnd for $t {
             #[inline]
             fn bitand(self, rhs: $t) -> $t { self & rhs }
         }
+
+        forward_ref_binop! { impl BitAnd, bitand for $t, $t }
     )*)
 }
 
@@ -568,8 +630,6 @@ fn bitand(self, rhs: $t) -> $t { self & rhs }
 /// calling `bitor`, and therefore, `main` prints `Bitwise Or-ing!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::BitOr;
 ///
 /// #[derive(Copy)]
@@ -608,6 +668,8 @@ impl BitOr for $t {
             #[inline]
             fn bitor(self, rhs: $t) -> $t { self | rhs }
         }
+
+        forward_ref_binop! { impl BitOr, bitor for $t, $t }
     )*)
 }
 
@@ -621,8 +683,6 @@ fn bitor(self, rhs: $t) -> $t { self | rhs }
 /// calling `bitxor`, and therefore, `main` prints `Bitwise Xor-ing!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::BitXor;
 ///
 /// #[derive(Copy)]
@@ -661,6 +721,8 @@ impl BitXor for $t {
             #[inline]
             fn bitxor(self, other: $t) -> $t { self ^ other }
         }
+
+        forward_ref_binop! { impl BitXor, bitxor for $t, $t }
     )*)
 }
 
@@ -674,8 +736,6 @@ fn bitxor(self, other: $t) -> $t { self ^ other }
 /// calling `shl`, and therefore, `main` prints `Shifting left!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::Shl;
 ///
 /// #[derive(Copy)]
@@ -716,6 +776,8 @@ fn shl(self, other: $f) -> $t {
                 self << other
             }
         }
+
+        forward_ref_binop! { impl Shl, shl for $t, $f }
     )
 }
 
@@ -745,8 +807,6 @@ macro_rules! shl_impl_all {
 /// calling `shr`, and therefore, `main` prints `Shifting right!`.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::Shr;
 ///
 /// #[derive(Copy)]
@@ -786,6 +846,8 @@ fn shr(self, other: $f) -> $t {
                 self >> other
             }
         }
+
+        forward_ref_binop! { impl Shr, shr for $t, $f }
     )
 }
 
@@ -1006,8 +1068,6 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 /// struct.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::Deref;
 ///
 /// struct DerefExample<T> {
@@ -1061,8 +1121,6 @@ fn deref(&self) -> &T { *self }
 /// struct.
 ///
 /// ```
-/// #![feature(associated_types)]
-///
 /// use std::ops::{Deref, DerefMut};
 ///
 /// struct DerefMutExample<T> {