diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 34514fde9dbd1..1360b412c2370 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -15,8 +15,6 @@ use core::prelude::*; -use core::num::Bitwise; - #[deriving(Clone, PartialEq, Eq, Hash, Show)] /// A specialized Set implementation to use enum types. pub struct EnumSet { diff --git a/src/libcollections/hash/mod.rs b/src/libcollections/hash/mod.rs index bd7bab456ba01..a0c0c9f973578 100644 --- a/src/libcollections/hash/mod.rs +++ b/src/libcollections/hash/mod.rs @@ -98,46 +98,30 @@ pub trait Writer { ////////////////////////////////////////////////////////////////////////////// -fn id(t: T) -> T { t } - -macro_rules! impl_hash( - ( $($ty:ident, $uty:ident, $f:path;)* ) => ( - $( - impl Hash for $ty { - #[inline] - fn hash(&self, state: &mut S) { - let a: [u8, ..::core::$ty::BYTES] = unsafe { - mem::transmute($f(*self as $uty) as $ty) - }; - state.write(a.as_slice()) - } +macro_rules! impl_hash { + ($ty:ident, $uty:ident) => { + impl Hash for $ty { + #[inline] + fn hash(&self, state: &mut S) { + let a: [u8, ..::core::$ty::BYTES] = unsafe { + mem::transmute((*self as $uty).to_le() as $ty) + }; + state.write(a.as_slice()) } - )* - ) -) - -impl_hash!( - u8, u8, id; - u16, u16, mem::to_le16; - u32, u32, mem::to_le32; - u64, u64, mem::to_le64; - i8, u8, id; - i16, u16, mem::to_le16; - i32, u32, mem::to_le32; - i64, u64, mem::to_le64; -) - -#[cfg(target_word_size = "32")] -impl_hash!( - uint, u32, mem::to_le32; - int, u32, mem::to_le32; -) + } + } +} -#[cfg(target_word_size = "64")] -impl_hash!( - uint, u64, mem::to_le64; - int, u64, mem::to_le64; -) +impl_hash!(u8, u8) +impl_hash!(u16, u16) +impl_hash!(u32, u32) +impl_hash!(u64, u64) +impl_hash!(uint, uint) +impl_hash!(i8, u8) +impl_hash!(i16, u16) +impl_hash!(i32, u32) +impl_hash!(i64, u64) +impl_hash!(int, uint) impl Hash for bool { #[inline] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 237efcd0096d0..5280ac0d64fb2 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -13,9 +13,9 @@ //! This module contains functions for querying the size and alignment of //! types, initializing and manipulating memory. -use ptr; use intrinsics; -use intrinsics::{bswap16, bswap32, bswap64}; +use num::Int; +use ptr; pub use intrinsics::transmute; @@ -172,153 +172,89 @@ pub unsafe fn move_val_init(dst: &mut T, src: T) { /// Convert an u16 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn to_le16(x: u16) -> u16 { x } - -/// Convert an u16 to little endian from the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_le16(x: u16) -> u16 { unsafe { bswap16(x) } } - -/// Convert an u32 to little endian from the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_le32(x: u32) -> u32 { x } +#[inline] +#[deprecated = "use `Int::to_le` instead"] +pub fn to_le16(x: u16) -> u16 { x.to_le() } /// Convert an u32 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_le32(x: u32) -> u32 { unsafe { bswap32(x) } } - -/// Convert an u64 to little endian from the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_le64(x: u64) -> u64 { x } +#[inline] +#[deprecated = "use `Int::to_le` instead"] +pub fn to_le32(x: u32) -> u32 { x.to_le() } /// Convert an u64 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_le64(x: u64) -> u64 { unsafe { bswap64(x) } } - - -/// Convert an u16 to big endian from the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_be16(x: u16) -> u16 { unsafe { bswap16(x) } } +#[inline] +#[deprecated = "use `Int::to_le` instead"] +pub fn to_le64(x: u64) -> u64 { x.to_le() } /// Convert an u16 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_be16(x: u16) -> u16 { x } - -/// Convert an u32 to big endian from the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_be32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[inline] +#[deprecated = "use `Int::to_be` instead"] +pub fn to_be16(x: u16) -> u16 { x.to_be() } /// Convert an u32 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_be32(x: u32) -> u32 { x } - -/// Convert an u64 to big endian from the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn to_be64(x: u64) -> u64 { unsafe { bswap64(x) } } +#[inline] +#[deprecated = "use `Int::to_be` instead"] +pub fn to_be32(x: u32) -> u32 { x.to_be() } /// Convert an u64 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn to_be64(x: u64) -> u64 { x } - - -/// Convert an u16 from little endian to the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_le16(x: u16) -> u16 { x } +#[inline] +#[deprecated = "use `Int::to_be` instead"] +pub fn to_be64(x: u64) -> u64 { x.to_be() } /// Convert an u16 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_le16(x: u16) -> u16 { unsafe { bswap16(x) } } - -/// Convert an u32 from little endian to the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_le32(x: u32) -> u32 { x } +#[inline] +#[deprecated = "use `Int::from_le` instead"] +pub fn from_le16(x: u16) -> u16 { Int::from_le(x) } /// Convert an u32 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_le32(x: u32) -> u32 { unsafe { bswap32(x) } } - -/// Convert an u64 from little endian to the target's endianness. -/// -/// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_le64(x: u64) -> u64 { x } +#[inline] +#[deprecated = "use `Int::from_le` instead"] +pub fn from_le32(x: u32) -> u32 { Int::from_le(x) } /// Convert an u64 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_le64(x: u64) -> u64 { unsafe { bswap64(x) } } - - -/// Convert an u16 from big endian to the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_be16(x: u16) -> u16 { unsafe { bswap16(x) } } +#[inline] +#[deprecated = "use `Int::from_le` instead"] +pub fn from_le64(x: u64) -> u64 { Int::from_le(x) } /// Convert an u16 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_be16(x: u16) -> u16 { x } - -/// Convert an u32 from big endian to the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_be32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[inline] +#[deprecated = "use `Int::from_be` instead"] +pub fn from_be16(x: u16) -> u16 { Int::from_be(x) } /// Convert an u32 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_be32(x: u32) -> u32 { x } - -/// Convert an u64 from big endian to the target's endianness. -/// -/// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] #[stable] -pub fn from_be64(x: u64) -> u64 { unsafe { bswap64(x) } } +#[inline] +#[deprecated = "use `Int::from_be` instead"] +pub fn from_be32(x: u32) -> u32 { Int::from_be(x) } /// Convert an u64 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] #[stable] -pub fn from_be64(x: u64) -> u64 { x } +#[inline] +#[deprecated = "use `Int::from_be` instead"] +pub fn from_be64(x: u64) -> u64 { Int::from_be(x) } -/** - * Swap the values at two mutable locations of the same type, without - * deinitialising or copying either one. - */ +/// Swap the values at two mutable locations of the same type, without +/// deinitialising or copying either one. #[inline] #[stable] pub fn swap(x: &mut T, y: &mut T) { @@ -337,42 +273,40 @@ pub fn swap(x: &mut T, y: &mut T) { } } -/** - * Replace the value at a mutable location with a new one, returning the old - * value, without deinitialising or copying either one. - * - * This is primarily used for transferring and swapping ownership of a value - * in a mutable location. For example, this function allows consumption of - * one field of a struct by replacing it with another value. The normal approach - * doesn't always work: - * - * ```rust,ignore - * struct Buffer { buf: Vec } - * - * impl Buffer { - * fn get_and_reset(&mut self) -> Vec { - * // error: cannot move out of dereference of `&mut`-pointer - * let buf = self.buf; - * self.buf = Vec::new(); - * buf - * } - * } - * ``` - * - * Note that `T` does not necessarily implement `Clone`, so it can't even - * clone and reset `self.buf`. But `replace` can be used to disassociate - * the original value of `self.buf` from `self`, allowing it to be returned: - * - * ```rust - * # struct Buffer { buf: Vec } - * impl Buffer { - * fn get_and_reset(&mut self) -> Vec { - * use std::mem::replace; - * replace(&mut self.buf, Vec::new()) - * } - * } - * ``` - */ +/// Replace the value at a mutable location with a new one, returning the old +/// value, without deinitialising or copying either one. +/// +/// This is primarily used for transferring and swapping ownership of a value +/// in a mutable location. For example, this function allows consumption of +/// one field of a struct by replacing it with another value. The normal approach +/// doesn't always work: +/// +/// ```rust,ignore +/// struct Buffer { buf: Vec } +/// +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// // error: cannot move out of dereference of `&mut`-pointer +/// let buf = self.buf; +/// self.buf = Vec::new(); +/// buf +/// } +/// } +/// ``` +/// +/// Note that `T` does not necessarily implement `Clone`, so it can't even +/// clone and reset `self.buf`. But `replace` can be used to disassociate +/// the original value of `self.buf` from `self`, allowing it to be returned: +/// +/// ```rust +/// # struct Buffer { buf: Vec } +/// impl Buffer { +/// fn get_and_reset(&mut self) -> Vec { +/// use std::mem::replace; +/// replace(&mut self.buf, Vec::new()) +/// } +/// } +/// ``` #[inline] #[stable] pub fn replace(dest: &mut T, mut src: T) -> T { diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 20bb12db694c0..79734324706b2 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -35,7 +35,6 @@ mod tests { use int; use num; - use num::Bitwise; use num::CheckedDiv; #[test] @@ -90,7 +89,7 @@ mod tests { } #[test] - fn test_bitwise() { + fn test_bitwise_operators() { assert!(0b1110 as $T == (0b1100 as $T).bitor(&(0b1010 as $T))); assert!(0b1000 as $T == (0b1100 as $T).bitand(&(0b1010 as $T))); assert!(0b0110 as $T == (0b1100 as $T).bitxor(&(0b1010 as $T))); @@ -99,45 +98,74 @@ mod tests { assert!(-(0b11 as $T) - (1 as $T) == (0b11 as $T).not()); } + static A: $T = 0b0101100; + static B: $T = 0b0100001; + static C: $T = 0b1111001; + + static _0: $T = 0; + static _1: $T = !0; + #[test] fn test_count_ones() { - assert!((0b0101100 as $T).count_ones() == 3); - assert!((0b0100001 as $T).count_ones() == 2); - assert!((0b1111001 as $T).count_ones() == 5); + assert!(A.count_ones() == 3); + assert!(B.count_ones() == 2); + assert!(C.count_ones() == 5); } #[test] fn test_count_zeros() { - assert!((0b0101100 as $T).count_zeros() == BITS as $T - 3); - assert!((0b0100001 as $T).count_zeros() == BITS as $T - 2); - assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5); + assert!(A.count_zeros() == BITS as $T - 3); + assert!(B.count_zeros() == BITS as $T - 2); + assert!(C.count_zeros() == BITS as $T - 5); + } + + #[test] + fn test_rotate() { + assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + + // Rotating these should make no difference + // + // We test using 124 bits because to ensure that overlong bit shifts do + // not cause undefined behaviour. See #10183. + assert_eq!(_0.rotate_left(124), _0); + assert_eq!(_1.rotate_left(124), _1); + assert_eq!(_0.rotate_right(124), _0); + assert_eq!(_1.rotate_right(124), _1); } #[test] fn test_swap_bytes() { - let n: $T = 0b0101100; assert_eq!(n.swap_bytes().swap_bytes(), n); - let n: $T = 0b0100001; assert_eq!(n.swap_bytes().swap_bytes(), n); - let n: $T = 0b1111001; assert_eq!(n.swap_bytes().swap_bytes(), n); + assert_eq!(A.swap_bytes().swap_bytes(), A); + assert_eq!(B.swap_bytes().swap_bytes(), B); + assert_eq!(C.swap_bytes().swap_bytes(), C); // Swapping these should make no difference - let n: $T = 0; assert_eq!(n.swap_bytes(), n); - let n: $T = -1; assert_eq!(n.swap_bytes(), n); + assert_eq!(_0.swap_bytes(), _0); + assert_eq!(_1.swap_bytes(), _1); } #[test] - fn test_rotate() { - let n: $T = 0b0101100; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); - let n: $T = 0b0100001; assert_eq!(n.rotate_left(3).rotate_left(2).rotate_right(5), n); - let n: $T = 0b1111001; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); + fn test_le() { + assert_eq!(Int::from_le(A.to_le()), A); + assert_eq!(Int::from_le(B.to_le()), B); + assert_eq!(Int::from_le(C.to_le()), C); + assert_eq!(Int::from_le(_0), _0); + assert_eq!(Int::from_le(_1), _1); + assert_eq!(_0.to_le(), _0); + assert_eq!(_1.to_le(), _1); + } - // Rotating these should make no difference - // - // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behaviour. See #10183. - let n: $T = 0; assert_eq!(n.rotate_left(124), n); - let n: $T = -1; assert_eq!(n.rotate_left(124), n); - let n: $T = 0; assert_eq!(n.rotate_right(124), n); - let n: $T = -1; assert_eq!(n.rotate_right(124), n); + #[test] + fn test_be() { + assert_eq!(Int::from_be(A.to_be()), A); + assert_eq!(Int::from_be(B.to_be()), B); + assert_eq!(Int::from_be(C.to_be()), C); + assert_eq!(Int::from_be(_0), _0); + assert_eq!(Int::from_be(_1), _1); + assert_eq!(_0.to_be(), _0); + assert_eq!(_1.to_be(), _1); } #[test] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index eaa632be6d04c..573470c29bcf4 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -376,217 +376,293 @@ bounded_impl!(i64, i64::MIN, i64::MAX) bounded_impl!(f32, f32::MIN_VALUE, f32::MAX_VALUE) bounded_impl!(f64, f64::MIN_VALUE, f64::MAX_VALUE) -/// Numbers with a fixed binary representation. -pub trait Bitwise: Bounded - + Not - + BitAnd - + BitOr - + BitXor - + Shl - + Shr { - /// Returns the number of ones in the binary representation of the number. +/// Specifies the available operations common to all of Rust's core numeric primitives. +/// These may not always make sense from a purely mathematical point of view, but +/// may be useful for systems programming. +pub trait Primitive: Copy + + Clone + + Num + + NumCast + + PartialOrd + + Bounded {} + +trait_impl!(Primitive for uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) + +/// A primitive signed or unsigned integer equipped with various bitwise +/// operators, bit counting methods, and endian conversion functions. +pub trait Int: Primitive + + CheckedAdd + + CheckedSub + + CheckedMul + + CheckedDiv + + Bounded + + Not + + BitAnd + + BitOr + + BitXor + + Shl + + Shr { + /// Returns the number of ones in the binary representation of the integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0b01001100u8; + /// /// assert_eq!(n.count_ones(), 3); /// ``` - fn count_ones(&self) -> Self; + fn count_ones(self) -> Self; - /// Returns the number of zeros in the binary representation of the number. + /// Returns the number of zeros in the binary representation of the integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0b01001100u8; + /// /// assert_eq!(n.count_zeros(), 5); /// ``` #[inline] - fn count_zeros(&self) -> Self { - (!*self).count_ones() + fn count_zeros(self) -> Self { + (!self).count_ones() } /// Returns the number of leading zeros in the in the binary representation - /// of the number. + /// of the integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0b0101000u16; + /// /// assert_eq!(n.leading_zeros(), 10); /// ``` - fn leading_zeros(&self) -> Self; + fn leading_zeros(self) -> Self; /// Returns the number of trailing zeros in the in the binary representation - /// of the number. + /// of the integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; - /// /// let n = 0b0101000u16; + /// /// assert_eq!(n.trailing_zeros(), 3); /// ``` - fn trailing_zeros(&self) -> Self; + fn trailing_zeros(self) -> Self; - /// Reverses the byte order of a binary number. + /// Shifts the bits to the left by a specified amount amount, `n`, wrapping + /// the truncated bits to the end of the resulting integer. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; + /// let n = 0x0123456789ABCDEFu64; + /// let m = 0x3456789ABCDEF012u64; + /// + /// assert_eq!(n.rotate_left(12), m); + /// ``` + fn rotate_left(self, n: uint) -> Self; + + /// Shifts the bits to the right by a specified amount amount, `n`, wrapping + /// the truncated bits to the beginning of the resulting integer. /// + /// # Example + /// + /// ```rust + /// let n = 0x0123456789ABCDEFu64; + /// let m = 0xDEF0123456789ABCu64; + /// + /// assert_eq!(n.rotate_right(12), m); + /// ``` + fn rotate_right(self, n: uint) -> Self; + + /// Reverses the byte order of the integer. + /// + /// # Example + /// + /// ```rust /// let n = 0x0123456789ABCDEFu64; /// let m = 0xEFCDAB8967452301u64; + /// /// assert_eq!(n.swap_bytes(), m); /// ``` - fn swap_bytes(&self) -> Self; + fn swap_bytes(self) -> Self; - /// Shifts the bits to the left by a specified amount amount, `r`, wrapping - /// the truncated bits to the end of the resulting value. + /// Convert a integer from big endian to the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(Int::from_be(n), n) + /// } else { + /// assert_eq!(Int::from_be(n), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn from_be(x: Self) -> Self { + if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + } + + /// Convert a integer from little endian to the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. /// + /// # Example + /// + /// ```rust /// let n = 0x0123456789ABCDEFu64; - /// let m = 0x3456789ABCDEF012u64; - /// assert_eq!(n.rotate_left(12), m); + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(Int::from_le(n), n) + /// } else { + /// assert_eq!(Int::from_le(n), n.swap_bytes()) + /// } /// ``` - fn rotate_left(&self, r: uint) -> Self; + #[inline] + fn from_le(x: Self) -> Self { + if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + } - /// Shifts the bits to the right by a specified amount amount, `r`, wrapping - /// the truncated bits to the beginning of the resulting value. + /// Convert the integer to big endian from the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. /// /// # Example /// /// ```rust - /// use std::num::Bitwise; + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(n.to_be(), n) + /// } else { + /// assert_eq!(n.to_be(), n.swap_bytes()) + /// } + /// ``` + #[inline] + fn to_be(self) -> Self { // or not to be? + if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + } + + /// Convert the integer to little endian from the target's endianness. /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Example + /// + /// ```rust /// let n = 0x0123456789ABCDEFu64; - /// let m = 0xDEF0123456789ABCu64; - /// assert_eq!(n.rotate_right(12), m); + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(n.to_le(), n) + /// } else { + /// assert_eq!(n.to_le(), n.swap_bytes()) + /// } /// ``` - fn rotate_right(&self, r: uint) -> Self; + #[inline] + fn to_le(self) -> Self { + if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + } } -/// Swapping a single byte does nothing. This is unsafe to be consistent with -/// the other `bswap` intrinsics. -#[inline] -unsafe fn bswap8(x: u8) -> u8 { x } - -macro_rules! bitwise_impl( - ($t:ty, $bits:expr, $co:ident, $lz:ident, $tz:ident, $bs:path) => { - impl Bitwise for $t { +macro_rules! int_impl { + ($T:ty, $BITS:expr, $ctpop:path, $ctlz:path, $cttz:path, $bswap:path) => { + impl Int for $T { #[inline] - fn count_ones(&self) -> $t { unsafe { intrinsics::$co(*self) } } + fn count_ones(self) -> $T { unsafe { $ctpop(self) } } #[inline] - fn leading_zeros(&self) -> $t { unsafe { intrinsics::$lz(*self) } } + fn leading_zeros(self) -> $T { unsafe { $ctlz(self) } } #[inline] - fn trailing_zeros(&self) -> $t { unsafe { intrinsics::$tz(*self) } } + fn trailing_zeros(self) -> $T { unsafe { $cttz(self) } } #[inline] - fn swap_bytes(&self) -> $t { unsafe { $bs(*self) } } + fn rotate_left(self, n: uint) -> $T { + // Protect against undefined behaviour for over-long bit shifts + let n = n % $BITS; + (self << n) | (self >> ($BITS - n)) + } #[inline] - fn rotate_left(&self, r: uint) -> $t { - // Protect against undefined behaviour for overlong bit shifts - let r = r % $bits; - (*self << r) | (*self >> ($bits - r)) + fn rotate_right(self, n: uint) -> $T { + // Protect against undefined behaviour for over-long bit shifts + let n = n % $BITS; + (self >> n) | (self << ($BITS - n)) } #[inline] - fn rotate_right(&self, r: uint) -> $t { - // Protect against undefined behaviour for overlong bit shifts - let r = r % $bits; - (*self >> r) | (*self << ($bits - r)) - } + fn swap_bytes(self) -> $T { unsafe { $bswap(self) } } } } -) +} + +/// Swapping a single byte is a no-op. This is marked as `unsafe` for +/// consistency with the other `bswap` intrinsics. +unsafe fn bswap8(x: u8) -> u8 { x } + +int_impl!(u8, 8, + intrinsics::ctpop8, + intrinsics::ctlz8, + intrinsics::cttz8, + bswap8) + +int_impl!(u16, 16, + intrinsics::ctpop16, + intrinsics::ctlz16, + intrinsics::cttz16, + intrinsics::bswap16) + +int_impl!(u32, 32, + intrinsics::ctpop32, + intrinsics::ctlz32, + intrinsics::cttz32, + intrinsics::bswap32) -macro_rules! bitwise_cast_impl( - ($t:ty, $t_cast:ty, $bits:expr, $co:ident, $lz:ident, $tz:ident, $bs:path) => { - impl Bitwise for $t { +int_impl!(u64, 64, + intrinsics::ctpop64, + intrinsics::ctlz64, + intrinsics::cttz64, + intrinsics::bswap64) + +macro_rules! int_cast_impl { + ($T:ty, $U:ty) => { + impl Int for $T { #[inline] - fn count_ones(&self) -> $t { unsafe { intrinsics::$co(*self as $t_cast) as $t } } + fn count_ones(self) -> $T { (self as $U).count_ones() as $T } #[inline] - fn leading_zeros(&self) -> $t { unsafe { intrinsics::$lz(*self as $t_cast) as $t } } + fn leading_zeros(self) -> $T { (self as $U).leading_zeros() as $T } #[inline] - fn trailing_zeros(&self) -> $t { unsafe { intrinsics::$tz(*self as $t_cast) as $t } } + fn trailing_zeros(self) -> $T { (self as $U).trailing_zeros() as $T } #[inline] - fn swap_bytes(&self) -> $t { unsafe { $bs(*self as $t_cast) as $t } } + fn rotate_left(self, n: uint) -> $T { (self as $U).rotate_left(n) as $T } #[inline] - fn rotate_left(&self, r: uint) -> $t { - // cast to prevent the sign bit from being corrupted - (*self as $t_cast).rotate_left(r) as $t - } + fn rotate_right(self, n: uint) -> $T { (self as $U).rotate_right(n) as $T } #[inline] - fn rotate_right(&self, r: uint) -> $t { - // cast to prevent the sign bit from being corrupted - (*self as $t_cast).rotate_right(r) as $t - } + fn swap_bytes(self) -> $T { (self as $U).swap_bytes() as $T } } } -) - -#[cfg(target_word_size = "32")] -bitwise_cast_impl!(uint, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32) -#[cfg(target_word_size = "64")] -bitwise_cast_impl!(uint, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64) - -bitwise_impl!(u8, 8, ctpop8, ctlz8, cttz8, bswap8) -bitwise_impl!(u16, 16, ctpop16, ctlz16, cttz16, intrinsics::bswap16) -bitwise_impl!(u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32) -bitwise_impl!(u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64) - -#[cfg(target_word_size = "32")] -bitwise_cast_impl!(int, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32) -#[cfg(target_word_size = "64")] -bitwise_cast_impl!(int, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64) - -bitwise_cast_impl!(i8, u8, 8, ctpop8, ctlz8, cttz8, bswap8) -bitwise_cast_impl!(i16, u16, 16, ctpop16, ctlz16, cttz16, intrinsics::bswap16) -bitwise_cast_impl!(i32, u32, 32, ctpop32, ctlz32, cttz32, intrinsics::bswap32) -bitwise_cast_impl!(i64, u64, 64, ctpop64, ctlz64, cttz64, intrinsics::bswap64) - -/// Specifies the available operations common to all of Rust's core numeric primitives. -/// These may not always make sense from a purely mathematical point of view, but -/// may be useful for systems programming. -pub trait Primitive: Copy - + Clone - + Num - + NumCast - + PartialOrd - + Bounded {} - -trait_impl!(Primitive for uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64) +} -/// A collection of traits relevant to primitive signed and unsigned integers -pub trait Int: Primitive - + Bitwise - + CheckedAdd - + CheckedSub - + CheckedMul - + CheckedDiv {} +int_cast_impl!(i8, u8) +int_cast_impl!(i16, u16) +int_cast_impl!(i32, u32) +int_cast_impl!(i64, u64) -trait_impl!(Int for uint u8 u16 u32 u64 int i8 i16 i32 i64) +#[cfg(target_word_size = "32")] int_cast_impl!(uint, u32) +#[cfg(target_word_size = "64")] int_cast_impl!(uint, u64) +#[cfg(target_word_size = "32")] int_cast_impl!(int, u32) +#[cfg(target_word_size = "64")] int_cast_impl!(int, u64) /// Returns the smallest power of 2 greater than or equal to `n`. #[inline] diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 8e4ba10154244..be1f960bcc3df 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -26,7 +26,6 @@ mod tests { use num; use num::CheckedDiv; - use num::Bitwise; #[test] fn test_overflows() { @@ -41,7 +40,7 @@ mod tests { } #[test] - fn test_bitwise() { + fn test_bitwise_operators() { assert!(0b1110 as $T == (0b1100 as $T).bitor(&(0b1010 as $T))); assert!(0b1000 as $T == (0b1100 as $T).bitand(&(0b1010 as $T))); assert!(0b0110 as $T == (0b1100 as $T).bitxor(&(0b1010 as $T))); @@ -50,45 +49,74 @@ mod tests { assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not()); } + static A: $T = 0b0101100; + static B: $T = 0b0100001; + static C: $T = 0b1111001; + + static _0: $T = 0; + static _1: $T = !0; + #[test] fn test_count_ones() { - assert!((0b0101100 as $T).count_ones() == 3); - assert!((0b0100001 as $T).count_ones() == 2); - assert!((0b1111001 as $T).count_ones() == 5); + assert!(A.count_ones() == 3); + assert!(B.count_ones() == 2); + assert!(C.count_ones() == 5); } #[test] fn test_count_zeros() { - assert!((0b0101100 as $T).count_zeros() == BITS as $T - 3); - assert!((0b0100001 as $T).count_zeros() == BITS as $T - 2); - assert!((0b1111001 as $T).count_zeros() == BITS as $T - 5); + assert!(A.count_zeros() == BITS as $T - 3); + assert!(B.count_zeros() == BITS as $T - 2); + assert!(C.count_zeros() == BITS as $T - 5); + } + + #[test] + fn test_rotate() { + assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + + // Rotating these should make no difference + // + // We test using 124 bits because to ensure that overlong bit shifts do + // not cause undefined behaviour. See #10183. + assert_eq!(_0.rotate_left(124), _0); + assert_eq!(_1.rotate_left(124), _1); + assert_eq!(_0.rotate_right(124), _0); + assert_eq!(_1.rotate_right(124), _1); } #[test] fn test_swap_bytes() { - let n: $T = 0b0101100; assert_eq!(n.swap_bytes().swap_bytes(), n); - let n: $T = 0b0100001; assert_eq!(n.swap_bytes().swap_bytes(), n); - let n: $T = 0b1111001; assert_eq!(n.swap_bytes().swap_bytes(), n); + assert_eq!(A.swap_bytes().swap_bytes(), A); + assert_eq!(B.swap_bytes().swap_bytes(), B); + assert_eq!(C.swap_bytes().swap_bytes(), C); // Swapping these should make no difference - let n: $T = 0; assert_eq!(n.swap_bytes(), n); - let n: $T = MAX; assert_eq!(n.swap_bytes(), n); + assert_eq!(_0.swap_bytes(), _0); + assert_eq!(_1.swap_bytes(), _1); } #[test] - fn test_rotate() { - let n: $T = 0b0101100; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); - let n: $T = 0b0100001; assert_eq!(n.rotate_left(3).rotate_left(2).rotate_right(5), n); - let n: $T = 0b1111001; assert_eq!(n.rotate_left(6).rotate_right(2).rotate_right(4), n); + fn test_le() { + assert_eq!(Int::from_le(A.to_le()), A); + assert_eq!(Int::from_le(B.to_le()), B); + assert_eq!(Int::from_le(C.to_le()), C); + assert_eq!(Int::from_le(_0), _0); + assert_eq!(Int::from_le(_1), _1); + assert_eq!(_0.to_le(), _0); + assert_eq!(_1.to_le(), _1); + } - // Rotating these should make no difference - // - // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behaviour. See #10183. - let n: $T = 0; assert_eq!(n.rotate_left(124), n); - let n: $T = MAX; assert_eq!(n.rotate_left(124), n); - let n: $T = 0; assert_eq!(n.rotate_right(124), n); - let n: $T = MAX; assert_eq!(n.rotate_right(124), n); + #[test] + fn test_be() { + assert_eq!(Int::from_be(A.to_be()), A); + assert_eq!(Int::from_be(B.to_be()), B); + assert_eq!(Int::from_be(C.to_be()), C); + assert_eq!(Int::from_be(_0), _0); + assert_eq!(Int::from_be(_1), _1); + assert_eq!(_0.to_be(), _0); + assert_eq!(_1.to_be(), _1); } #[test] diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 1c33114dc7173..36acfd5cf8a6b 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -27,10 +27,10 @@ use super::util; #[cfg(unix)] pub type sock_t = super::file::fd_t; pub fn htons(u: u16) -> u16 { - mem::to_be16(u) + u.to_be() } pub fn ntohs(u: u16) -> u16 { - mem::from_be16(u) + Int::from_be(u) } enum InAddr { @@ -46,7 +46,7 @@ fn ip_to_inaddr(ip: rtio::IpAddr) -> InAddr { (c as u32 << 8) | (d as u32 << 0); InAddr(libc::in_addr { - s_addr: mem::from_be32(ip) + s_addr: Int::from_be(ip) }) } rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => { @@ -180,7 +180,7 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let storage: &libc::sockaddr_in = unsafe { mem::transmute(storage) }; - let ip = mem::to_be32(storage.sin_addr.s_addr as u32); + let ip = (storage.sin_addr.s_addr as u32).to_be(); let a = (ip >> 24) as u8; let b = (ip >> 16) as u8; let c = (ip >> 8) as u8; diff --git a/src/libnum/bigint.rs b/src/libnum/bigint.rs index 0933301970d19..e9153f89e04ee 100644 --- a/src/libnum/bigint.rs +++ b/src/libnum/bigint.rs @@ -23,7 +23,7 @@ use std::{cmp, fmt}; use std::default::Default; use std::from_str::FromStr; use std::num::CheckedDiv; -use std::num::{Bitwise, ToPrimitive, FromPrimitive}; +use std::num::{ToPrimitive, FromPrimitive}; use std::num::{Zero, One, ToStrRadix, FromStrRadix}; use std::string::String; use std::{uint, i64, u64}; diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 1b530ea342491..082dce4ea473d 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -46,7 +46,6 @@ #![allow(unsigned_negate)] use libc::c_ulonglong; -use std::num::{Bitwise}; use std::rc::Rc; use lib::llvm::{ValueRef, True, IntEQ, IntNE}; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 47b321b068b36..271e292033265 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -30,8 +30,8 @@ use uvll; /// Generic functions related to dealing with sockaddr things //////////////////////////////////////////////////////////////////////////////// -pub fn htons(u: u16) -> u16 { mem::to_be16(u) } -pub fn ntohs(u: u16) -> u16 { mem::from_be16(u) } +pub fn htons(u: u16) -> u16 { u.to_be() } +pub fn ntohs(u: u16) -> u16 { Int::from_be(u) } pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, len: uint) -> rtio::SocketAddr { @@ -41,7 +41,7 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let storage: &libc::sockaddr_in = unsafe { mem::transmute(storage) }; - let ip = mem::to_be32(storage.sin_addr.s_addr as u32); + let ip = (storage.sin_addr.s_addr as u32).to_be(); let a = (ip >> 24) as u8; let b = (ip >> 16) as u8; let c = (ip >> 8) as u8; @@ -89,7 +89,8 @@ fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) { (*storage).sin_family = libc::AF_INET as libc::sa_family_t; (*storage).sin_port = htons(addr.port); (*storage).sin_addr = libc::in_addr { - s_addr: mem::from_be32(ip) + s_addr: Int::from_be(ip), + }; mem::size_of::() } diff --git a/src/libserialize/ebml.rs b/src/libserialize/ebml.rs index 9ba2c2cd258ed..12c5a3493c17b 100644 --- a/src/libserialize/ebml.rs +++ b/src/libserialize/ebml.rs @@ -154,8 +154,6 @@ pub mod reader { } pub fn vuint_at(data: &[u8], start: uint) -> DecodeResult { - use std::mem::from_be32; - if data.len() - start < 4 { return vuint_at_slow(data, start); } @@ -185,7 +183,7 @@ pub mod reader { unsafe { let ptr = data.as_ptr().offset(start as int) as *u32; - let val = from_be32(*ptr); + let val = Int::from_be(*ptr); let i = (val >> 28u) as uint; let (shift, mask) = SHIFT_MASK_TABLE[i]; diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 602a2240f3908..7301f9b08e9dc 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -22,7 +22,7 @@ use string::String; pub use core::num::{Num, div_rem, Zero, zero, One, one}; pub use core::num::{Signed, abs, abs_sub, signum}; -pub use core::num::{Unsigned, pow, Bounded, Bitwise}; +pub use core::num::{Unsigned, pow, Bounded}; pub use core::num::{Primitive, Int, Saturating}; pub use core::num::{CheckedAdd, CheckedSub, CheckedMul, CheckedDiv}; pub use core::num::{cast, FromPrimitive, NumCast, ToPrimitive}; diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index bace30e3f6ffd..b68b435da4bb0 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -209,8 +209,6 @@ impl Uuid { /// * `d3` A 16-bit word /// * `d4` Array of 8 octets pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid { - use std::mem::{to_be16, to_be32}; - // First construct a temporary field-based struct let mut fields = UuidFields { data1: 0, @@ -219,9 +217,9 @@ impl Uuid { data4: [0, ..8] }; - fields.data1 = to_be32(d1); - fields.data2 = to_be16(d2); - fields.data3 = to_be16(d3); + fields.data1 = d1.to_be(); + fields.data2 = d2.to_be(); + fields.data3 = d3.to_be(); slice::bytes::copy_memory(fields.data4, d4); unsafe { @@ -335,16 +333,15 @@ impl Uuid { /// /// Example: `550e8400-e29b-41d4-a716-446655440000` pub fn to_hyphenated_str(&self) -> String { - use std::mem::{to_be16, to_be32}; // Convert to field-based struct as it matches groups in output. // Ensure fields are in network byte order, as per RFC. let mut uf: UuidFields; unsafe { uf = transmute_copy(&self.bytes); } - uf.data1 = to_be32(uf.data1); - uf.data2 = to_be16(uf.data2); - uf.data3 = to_be16(uf.data3); + uf.data1 = uf.data1.to_be(); + uf.data2 = uf.data2.to_be(); + uf.data3 = uf.data3.to_be(); let s = format!("{:08x}-{:04x}-{:04x}-{:02x}{:02x}-\ {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}", uf.data1, diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index c0ea6f8617d87..af51157bba564 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -16,7 +16,6 @@ use std::io; use std::io::stdio::StdReader; use std::io::BufferedReader; -use std::num::Bitwise; use std::os; // Computes a single solution to a given 9x9 sudoku