]> git.lizzy.rs Git - rust.git/blob - src/libstd/util.rs
auto merge of #9354 : thestinger/rust/cleanup, r=alexcrichton
[rust.git] / src / libstd / util.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Miscellaneous helpers for common patterns.
12
13 use cast;
14 use ptr;
15 use prelude::*;
16 use unstable::intrinsics;
17
18 /// The identity function.
19 #[inline]
20 pub fn id<T>(x: T) -> T { x }
21
22 /// Ignores a value.
23 #[inline]
24 pub fn ignore<T>(_x: T) { }
25
26 /**
27  * Swap the values at two mutable locations of the same type, without
28  * deinitialising or copying either one.
29  */
30 #[inline]
31 pub fn swap<T>(x: &mut T, y: &mut T) {
32     unsafe {
33         // Give ourselves some scratch space to work with
34         let mut tmp: T = intrinsics::uninit();
35         let t: *mut T = &mut tmp;
36
37         // Perform the swap, `&mut` pointers never alias
38         let x_raw: *mut T = x;
39         let y_raw: *mut T = y;
40         ptr::copy_nonoverlapping_memory(t, x_raw, 1);
41         ptr::copy_nonoverlapping_memory(x, y_raw, 1);
42         ptr::copy_nonoverlapping_memory(y, t, 1);
43
44         // y and t now point to the same thing, but we need to completely forget `tmp`
45         // because it's no longer relevant.
46         cast::forget(tmp);
47     }
48 }
49
50 /**
51  * Replace the value at a mutable location with a new one, returning the old
52  * value, without deinitialising or copying either one.
53  */
54 #[inline]
55 pub fn replace<T>(dest: &mut T, mut src: T) -> T {
56     swap(dest, &mut src);
57     src
58 }
59
60 /// A non-copyable dummy type.
61 #[deriving(Eq, TotalEq, Ord, TotalOrd)]
62 #[unsafe_no_drop_flag]
63 pub struct NonCopyable;
64
65 impl NonCopyable {
66     // FIXME(#8233) should not be necessary
67     /// Create a new noncopyable token.
68     pub fn new() -> NonCopyable { NonCopyable }
69 }
70
71 impl Drop for NonCopyable {
72     fn drop(&mut self) { }
73 }
74
75 /// A type with no inhabitants
76 pub enum Void { }
77
78 impl Void {
79     /// A utility function for ignoring this uninhabited type
80     pub fn uninhabited(self) -> ! {
81         match self {
82             // Nothing to match on
83         }
84     }
85 }
86
87
88 #[cfg(test)]
89 mod tests {
90     use super::*;
91
92     use clone::Clone;
93     use option::{None, Some};
94     use either::{Either, Left, Right};
95     use sys::size_of;
96     use kinds::Drop;
97
98     #[test]
99     fn identity_crisis() {
100         // Writing a test for the identity function. How did it come to this?
101         let x = ~[(5, false)];
102         //FIXME #3387 assert!(x.eq(id(x.clone())));
103         let y = x.clone();
104         assert!(x.eq(&id(y)));
105     }
106
107     #[test]
108     fn test_swap() {
109         let mut x = 31337;
110         let mut y = 42;
111         swap(&mut x, &mut y);
112         assert_eq!(x, 42);
113         assert_eq!(y, 31337);
114     }
115
116     #[test]
117     fn test_replace() {
118         let mut x = Some(NonCopyable);
119         let y = replace(&mut x, None);
120         assert!(x.is_none());
121         assert!(y.is_some());
122     }
123
124     #[test]
125     fn test_uninhabited() {
126         let could_only_be_coin : Either <Void, ()> = Right (());
127         match could_only_be_coin {
128             Right (coin) => coin,
129             Left (is_void) => is_void.uninhabited ()
130         }
131     }
132
133     #[test]
134     fn test_noncopyable() {
135         assert_eq!(size_of::<NonCopyable>(), 0);
136
137         // verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct
138
139         static mut did_run: bool = false;
140
141         struct Foo { five: int }
142
143         impl Drop for Foo {
144             fn drop(&mut self) {
145                 assert_eq!(self.five, 5);
146                 unsafe {
147                     did_run = true;
148                 }
149             }
150         }
151
152         {
153             let _a = (NonCopyable, Foo { five: 5 }, NonCopyable);
154         }
155
156         unsafe { assert_eq!(did_run, true); }
157     }
158 }
159
160 /// Completely miscellaneous language-construct benchmarks.
161 #[cfg(test)]
162 mod bench {
163
164     use extra::test::BenchHarness;
165     use option::{Some,None};
166
167     // Static/dynamic method dispatch
168
169     struct Struct {
170         field: int
171     }
172
173     trait Trait {
174         fn method(&self) -> int;
175     }
176
177     impl Trait for Struct {
178         fn method(&self) -> int {
179             self.field
180         }
181     }
182
183     #[bench]
184     fn trait_vtable_method_call(bh: &mut BenchHarness) {
185         let s = Struct { field: 10 };
186         let t = &s as &Trait;
187         do bh.iter {
188             t.method();
189         }
190     }
191
192     #[bench]
193     fn trait_static_method_call(bh: &mut BenchHarness) {
194         let s = Struct { field: 10 };
195         do bh.iter {
196             s.method();
197         }
198     }
199
200     // Overhead of various match forms
201
202     #[bench]
203     fn match_option_some(bh: &mut BenchHarness) {
204         let x = Some(10);
205         do bh.iter {
206             let _q = match x {
207                 Some(y) => y,
208                 None => 11
209             };
210         }
211     }
212
213     #[bench]
214     fn match_vec_pattern(bh: &mut BenchHarness) {
215         let x = [1,2,3,4,5,6];
216         do bh.iter {
217             let _q = match x {
218                 [1,2,3,.._] => 10,
219                 _ => 11
220             };
221         }
222     }
223 }