about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcollections/macros.rs28
-rw-r--r--src/libcollections/vec.rs24
-rw-r--r--src/test/run-pass/vec-macro-repeat.rs5
3 files changed, 54 insertions, 3 deletions
diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs
index 79c86a846f1..ebcfb8d1cf8 100644
--- a/src/libcollections/macros.rs
+++ b/src/libcollections/macros.rs
@@ -9,12 +9,34 @@
 // except according to those terms.
 
 /// Creates a `Vec` containing the arguments.
+///
+/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
+/// There are two forms of this macro:
+///
+/// - Create a `Vec` containing a given list of elements:
+///
+/// ```
+/// let v = vec![1, 2, 3];
+/// assert_eq!(v[0], 1);
+/// assert_eq!(v[1], 2);
+/// assert_eq!(v[2], 3);
+/// ```
+///
+/// - Create a `Vec` from a given element and size:
+///
+/// ```
+/// let v = vec![1; 3];
+/// assert_eq!(v, vec![1, 1, 1]);
+/// ```
+///
+/// Note that unlike array expressions this syntax supports all elements
+/// which implement `Clone` and the number of elements doesn't have to be
+/// a constant.
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 macro_rules! vec {
-    ($x:expr; $y:expr) => (
-        <[_] as $crate::slice::SliceExt>::into_vec(
-            $crate::boxed::Box::new([$x; $y]))
+    ($elem:expr; $n:expr) => (
+        $crate::vec::from_elem($elem, $n)
     );
     ($($x:expr),*) => (
         <[_] as $crate::slice::SliceExt>::into_vec(
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index f294dd3c3e0..dcb63aa1939 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1252,6 +1252,30 @@ unsafe fn dealloc<T>(ptr: *mut T, len: usize) {
     }
 }
 
+#[doc(hidden)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
+    unsafe {
+        let mut v = Vec::with_capacity(n);
+        let mut ptr = v.as_mut_ptr();
+
+        // Write all elements except the last one
+        for i in 1..n {
+            ptr::write(ptr, Clone::clone(&elem));
+            ptr = ptr.offset(1);
+            v.set_len(i); // Increment the length in every step in case Clone::clone() panics
+        }
+
+        if n > 0 {
+            // We can write the last element directly without cloning needlessly
+            ptr::write(ptr, elem);
+            v.set_len(n);
+        }
+
+        v
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Common trait implementations for Vec
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/test/run-pass/vec-macro-repeat.rs b/src/test/run-pass/vec-macro-repeat.rs
index 9e69ecfce4f..76e7b92ea04 100644
--- a/src/test/run-pass/vec-macro-repeat.rs
+++ b/src/test/run-pass/vec-macro-repeat.rs
@@ -14,4 +14,9 @@ pub fn main() {
     assert_eq!(vec![1; 2], vec![1, 1]);
     assert_eq!(vec![1; 1], vec![1]);
     assert_eq!(vec![1; 0], vec![]);
+
+    // from_elem syntax (see RFC 832)
+    let el = Box::new(1);
+    let n = 3;
+    assert_eq!(vec![el; n], vec![Box::new(1), Box::new(1), Box::new(1)]);
 }