Skip to content

Implement core ops for references + fix core module documentation #21227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 21, 2015
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 114 additions & 4 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@
//! 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
Expand Down Expand Up @@ -96,6 +104,80 @@ 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]
impl<'a> $imp for &'a $t {
type Output = <$t as $imp>::Output;

#[inline]
fn $method(self) -> <$t as $imp>::Output {
$imp::$method(*self)
}
}
}
}

// implements the binary operator "&T op U"
// based on "T + U" where T and U are expected `Copy`able
macro_rules! forward_ref_val_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
#[unstable]
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)
}
}
}
}

// implements the binary operator "T op &U"
// based on "T + U" where T and U are expected `Copy`able
macro_rules! forward_val_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
#[unstable]
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)
}
}
}
}

// implements the binary operator "&T op &U"
// based on "T + U" where T and U are expected `Copy`able
macro_rules! forward_ref_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
#[unstable]
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)
}
}
}
}

// implements binary operators "&T op U", "T op &U", "&T op &U"
// based on "T + U" where T and U are expected `Copy`able
macro_rules! forward_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
forward_ref_val_binop! { impl $imp, $method for $t, $u }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if these three macros could be inlined and just have 3 impl blocks in here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huonw Sure, that's doable. I've never used them anywhere except in the bottom macro. And I think it should save 12 non-empty lines of code. Do you want me to inline them? Personally, I don't have a preference.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think they should be inlined; thanks!

forward_val_ref_binop! { impl $imp, $method for $t, $u }
forward_ref_ref_binop! { impl $imp, $method for $t, $u }
}
}

/// The `Add` trait is used to specify the functionality of `+`.
///
/// # Example
Expand Down Expand Up @@ -144,6 +226,8 @@ macro_rules! add_impl {
#[inline]
fn add(self, other: $t) -> $t { self + other }
}

forward_ref_binop! { impl Add, add for $t, $t }
)*)
}

Expand Down Expand Up @@ -197,6 +281,8 @@ macro_rules! sub_impl {
#[inline]
fn sub(self, other: $t) -> $t { self - other }
}

forward_ref_binop! { impl Sub, sub for $t, $t }
)*)
}

Expand Down Expand Up @@ -250,6 +336,8 @@ macro_rules! mul_impl {
#[inline]
fn mul(self, other: $t) -> $t { self * other }
}

forward_ref_binop! { impl Mul, mul for $t, $t }
)*)
}

Expand Down Expand Up @@ -303,6 +391,8 @@ macro_rules! div_impl {
#[inline]
fn div(self, other: $t) -> $t { self / other }
}

forward_ref_binop! { impl Div, div for $t, $t }
)*)
}

Expand Down Expand Up @@ -356,6 +446,8 @@ macro_rules! rem_impl {
#[inline]
fn rem(self, other: $t) -> $t { self % other }
}

forward_ref_binop! { impl Rem, rem for $t, $t }
)*)
}

Expand All @@ -371,6 +463,8 @@ macro_rules! rem_float_impl {
unsafe { $fmod(self, other) }
}
}

forward_ref_binop! { impl Rem, rem for $t, $t }
}
}

Expand Down Expand Up @@ -429,6 +523,8 @@ macro_rules! neg_impl {
#[stable]
fn neg(self) -> $t { -self }
}

forward_ref_unop! { impl Neg, neg for $t }
)*)
}

Expand All @@ -441,6 +537,8 @@ macro_rules! neg_uint_impl {
#[inline]
fn neg(self) -> $t { -(self as $t_signed) as $t }
}

forward_ref_unop! { impl Neg, neg for $t }
}
}

Expand Down Expand Up @@ -502,6 +600,8 @@ macro_rules! not_impl {
#[inline]
fn not(self) -> $t { !self }
}

forward_ref_unop! { impl Not, not for $t }
)*)
}

Expand Down Expand Up @@ -555,6 +655,8 @@ macro_rules! bitand_impl {
#[inline]
fn bitand(self, rhs: $t) -> $t { self & rhs }
}

forward_ref_binop! { impl BitAnd, bitand for $t, $t }
)*)
}

Expand Down Expand Up @@ -608,6 +710,8 @@ macro_rules! bitor_impl {
#[inline]
fn bitor(self, rhs: $t) -> $t { self | rhs }
}

forward_ref_binop! { impl BitOr, bitor for $t, $t }
)*)
}

Expand Down Expand Up @@ -661,6 +765,8 @@ macro_rules! bitxor_impl {
#[inline]
fn bitxor(self, other: $t) -> $t { self ^ other }
}

forward_ref_binop! { impl BitXor, bitxor for $t, $t }
)*)
}

Expand Down Expand Up @@ -716,6 +822,8 @@ macro_rules! shl_impl {
self << other
}
}

forward_ref_binop! { impl Shl, shl for $t, $f }
)
}

Expand Down Expand Up @@ -795,6 +903,8 @@ macro_rules! shr_impl {
self >> other
}
}

forward_ref_binop! { impl Shr, shr for $t, $f }
)
}

Expand Down