From e639f2980eb5e54f09d5dc01b53d356c6b2df73c Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Sat, 19 Oct 2013 23:53:49 -0700 Subject: [PATCH 1/3] Add io to the hidden std re-exports By adding io to the hidden std re-exports, this allows the use of println!() inside of libstd. --- src/libstd/std.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/std.rs b/src/libstd/std.rs index c446fe3d94f97..e6669db5ba4ad 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -225,4 +225,5 @@ mod std { pub use fmt; pub use to_bytes; pub use logging; + pub use io; } From 26c90a2ae78bd45213acbc1bd7f612366fe07878 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Sun, 20 Oct 2013 00:06:37 -0700 Subject: [PATCH 2/3] Add functions cast::transmute_slice, cast::transmute_mut_slice --- src/libstd/cast.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index a4f2ee0d09c78..02e08b83ea0d7 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -13,6 +13,7 @@ use ptr::RawPtr; use mem; use unstable::intrinsics; +use unstable::raw::Slice; /// Casts the value at `src` to U. The two types must have the same length. #[cfg(target_word_size = "32")] @@ -111,6 +112,30 @@ pub unsafe fn transmute_mut_region<'a,'b,T>(ptr: &'a mut T) -> &'b mut T { transmute(ptr) } +/// Coerce a slice of one type into a slice of another. +/// This function modifies the length of the resulting slice appropriately. +/// +/// Note that if the coercion leaves some bytes from the original slice un-addressable +/// with the new slice, then this function will not be able to round-trip back to the +/// original slice. For example, if a &[u8] of length 16 is transmuted to a &[[u8,..3]], +/// which will have length 5, transmuting back to a &[u8] will produce a slice of length 15. +#[inline] +pub unsafe fn transmute_slice<'a,L,G>(thing: &'a [L]) -> &'a [G] { + let mut slice: Slice = transmute(thing); + let bytes = slice.len * mem::nonzero_size_of::(); + // NB: the previous operation cannot overflow. A slice cannot possibly hold more memory than + // is possible to allocate, and uint can represent all valid allocation sizes. + slice.len = bytes / mem::nonzero_size_of::(); + transmute(slice) +} + +/// Coerce a mutable slice of one type into a mutable slice of another. +/// This function modifies the length of the resulting slice appropriately. +#[inline] +pub unsafe fn transmute_mut_slice<'a,L,G>(thing: &'a mut [L]) -> &'a mut [G] { + transmute(transmute_slice::(thing)) +} + /// Transforms lifetime of the second pointer to match the first. #[inline] pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T { @@ -138,6 +163,7 @@ pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T { mod tests { use cast::{bump_box_refcount, transmute}; use unstable::raw; + use container::Container; #[test] fn test_transmute_copy() { @@ -175,4 +201,32 @@ mod tests { assert_eq!(~[76u8], transmute(~"L")); } } + + #[test] + fn test_transmute_slice() { + use cast::transmute_slice; + use unstable::raw::Vec; + + unsafe { + let u8ary = [0u8, ..16]; + let u32ary = [0u32, ..4]; + assert_eq!(4, transmute_slice::(u8ary).len()); + assert_eq!(16, transmute_slice::(u32ary).len()); + + let threeary = [[0u8, ..3], ..5]; + assert_eq!(5, transmute_slice::(u8ary).len()); + assert_eq!(15, transmute_slice::<[u8,..3],u8>(threeary).len()); + + // ensure the repr for a Vec uses nonzero sizes, since we rely on that + let vec: *Vec<()> = transmute(~[()]); + assert_eq!(1, (*vec).fill); + transmute::<*Vec<()>,~[()]>(vec); // don't leak it + + let unitary = [(), ..16]; + assert_eq!(16, transmute_slice::(u32ary).len()); + assert_eq!(16, transmute_slice::(u8ary).len()); + assert_eq!(4, transmute_slice::<(),u32>(unitary).len()); + assert_eq!(16, transmute_slice::<(),u8>(unitary).len()); + } + } } From 0338a59fc909fc31233254c5f9ea871ea02b372e Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Sun, 20 Oct 2013 00:18:53 -0700 Subject: [PATCH 3/3] Adopt cast::transmute_mut_slice in rand Also fix rand::isaac to transmute its slice properly. That didn't get updated when the slice repr changed, so it was not properly seeding itself. --- src/libstd/rand/isaac.rs | 4 ++-- src/libstd/rand/mod.rs | 16 ++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/libstd/rand/isaac.rs b/src/libstd/rand/isaac.rs index 0068b60cfa51b..8f9d6c59ef967 100644 --- a/src/libstd/rand/isaac.rs +++ b/src/libstd/rand/isaac.rs @@ -43,7 +43,7 @@ impl IsaacRng { let mut rng = EMPTY; { - let bytes = unsafe {cast::transmute::<&mut [u32], &mut [u8]>(rng.rsl)}; + let bytes = unsafe { cast::transmute_mut_slice::(rng.rsl) }; OSRng::new().fill_bytes(bytes); } @@ -239,7 +239,7 @@ impl Isaac64Rng { pub fn new() -> Isaac64Rng { let mut rng = EMPTY_64; { - let bytes = unsafe {cast::transmute::<&mut [u64], &mut [u8]>(rng.rsl)}; + let bytes = unsafe { cast::transmute_mut_slice::(rng.rsl) }; OSRng::new().fill_bytes(bytes); } rng.init(true); diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 954db42c89be1..cc6d6c4598456 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -52,8 +52,6 @@ fn main () { ``` */ -use mem::size_of; -use unstable::raw::Slice; use cast; use container::Container; use iter::{Iterator, range}; @@ -136,11 +134,11 @@ pub trait Rng { /// } /// ``` fn fill_bytes(&mut self, dest: &mut [u8]) { - let mut slice: Slice = unsafe { cast::transmute_copy(&dest) }; - slice.len /= size_of::(); - let as_u64: &mut [u64] = unsafe { cast::transmute(slice) }; - for dest in as_u64.mut_iter() { - *dest = self.next_u64(); + { + let as_u64: &mut [u64] = unsafe { cast::transmute_mut_slice(dest) }; + for dest in as_u64.mut_iter() { + *dest = self.next_u64(); + } } // the above will have filled up the vector as much as @@ -149,9 +147,7 @@ pub trait Rng { // space for a u32 if remaining >= 4 { - let mut slice: Slice = unsafe { cast::transmute_copy(&dest) }; - slice.len /= size_of::(); - let as_u32: &mut [u32] = unsafe { cast::transmute(slice) }; + let as_u32: &mut [u32] = unsafe { cast::transmute_mut_slice(dest) }; as_u32[as_u32.len() - 1] = self.next_u32(); remaining -= 4; }