]> git.lizzy.rs Git - rust.git/blob - src/libstd/util.rs
5085f337d4bba216103ddf9f17c1505dca509123
[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 /// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the
27 /// original value of `*ptr`.
28 ///
29 /// NB: This function accepts `@mut T` and not `&mut T` to avoid
30 /// an obvious borrowck hazard. Typically passing in `&mut T` will
31 /// cause borrow check errors because it freezes whatever location
32 /// that `&mut T` is stored in (either statically or dynamically).
33 #[inline]
34 pub fn with<T,R>(
35     ptr: @mut T,
36     value: T,
37     op: &fn() -> R) -> R
38 {
39     let prev = replace(ptr, value);
40     let result = op();
41     *ptr = prev;
42     return result;
43 }
44
45 /**
46  * Swap the values at two mutable locations of the same type, without
47  * deinitialising or copying either one.
48  */
49 #[inline]
50 pub fn swap<T>(x: &mut T, y: &mut T) {
51     unsafe {
52         // Give ourselves some scratch space to work with
53         let mut tmp: T = intrinsics::uninit();
54         let t: *mut T = &mut tmp;
55
56         // Perform the swap, `&mut` pointers never alias
57         let x_raw: *mut T = x;
58         let y_raw: *mut T = y;
59         ptr::copy_nonoverlapping_memory(t, x_raw, 1);
60         ptr::copy_nonoverlapping_memory(x, y_raw, 1);
61         ptr::copy_nonoverlapping_memory(y, t, 1);
62
63         // y and t now point to the same thing, but we need to completely forget `tmp`
64         // because it's no longer relevant.
65         cast::forget(tmp);
66     }
67 }
68
69 /**
70  * Replace the value at a mutable location with a new one, returning the old
71  * value, without deinitialising or copying either one.
72  */
73 #[inline]
74 pub fn replace<T>(dest: &mut T, mut src: T) -> T {
75     swap(dest, &mut src);
76     src
77 }
78
79 /// A non-copyable dummy type.
80 #[deriving(Eq, TotalEq, Ord, TotalOrd)]
81 #[unsafe_no_drop_flag]
82 pub struct NonCopyable;
83
84 impl NonCopyable {
85     // FIXME(#8233) should not be necessary
86     /// Create a new noncopyable token.
87     pub fn new() -> NonCopyable { NonCopyable }
88 }
89
90 impl Drop for NonCopyable {
91     fn drop(&self) { }
92 }
93
94 /// A type with no inhabitants
95 pub enum Void { }
96
97 impl Void {
98     /// A utility function for ignoring this uninhabited type
99     pub fn uninhabited(self) -> ! {
100         match self {
101             // Nothing to match on
102         }
103     }
104 }
105
106
107 /**
108 A utility function for indicating unreachable code. It will fail if
109 executed. This is occasionally useful to put after loops that never
110 terminate normally, but instead directly return from a function.
111
112 # Example
113
114 ~~~ {.rust}
115 fn choose_weighted_item(v: &[Item]) -> Item {
116     assert!(!v.is_empty());
117     let mut so_far = 0u;
118     for v.each |item| {
119         so_far += item.weight;
120         if so_far > 100 {
121             return item;
122         }
123     }
124     // The above loop always returns, so we must hint to the
125     // type checker that it isn't possible to get down here
126     util::unreachable();
127 }
128 ~~~
129
130 */
131 pub fn unreachable() -> ! {
132     fail!("internal error: entered unreachable code");
133 }
134
135 #[cfg(test)]
136 mod tests {
137     use super::*;
138
139     use clone::Clone;
140     use option::{None, Some};
141     use either::{Either, Left, Right};
142     use sys::size_of;
143     use kinds::Drop;
144
145     #[test]
146     fn identity_crisis() {
147         // Writing a test for the identity function. How did it come to this?
148         let x = ~[(5, false)];
149         //FIXME #3387 assert!(x.eq(id(x.clone())));
150         let y = x.clone();
151         assert!(x.eq(&id(y)));
152     }
153
154     #[test]
155     fn test_swap() {
156         let mut x = 31337;
157         let mut y = 42;
158         swap(&mut x, &mut y);
159         assert_eq!(x, 42);
160         assert_eq!(y, 31337);
161     }
162
163     #[test]
164     fn test_replace() {
165         let mut x = Some(NonCopyable);
166         let y = replace(&mut x, None);
167         assert!(x.is_none());
168         assert!(y.is_some());
169     }
170
171     #[test]
172     fn test_uninhabited() {
173         let could_only_be_coin : Either <Void, ()> = Right (());
174         match could_only_be_coin {
175             Right (coin) => coin,
176             Left (is_void) => is_void.uninhabited ()
177         }
178     }
179
180     #[test]
181     fn test_noncopyable() {
182         assert_eq!(size_of::<NonCopyable>(), 0);
183
184         // verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct
185
186         static mut did_run: bool = false;
187
188         struct Foo { five: int }
189
190         impl Drop for Foo {
191             fn drop(&self) {
192                 assert_eq!(self.five, 5);
193                 unsafe {
194                     did_run = true;
195                 }
196             }
197         }
198
199         {
200             let _a = (NonCopyable, Foo { five: 5 }, NonCopyable);
201         }
202
203         unsafe { assert_eq!(did_run, true); }
204     }
205 }
206
207 /// Completely miscellaneous language-construct benchmarks.
208 #[cfg(test)]
209 mod bench {
210
211     use extra::test::BenchHarness;
212     use option::{Some,None};
213
214     // Static/dynamic method dispatch
215
216     struct Struct {
217         field: int
218     }
219
220     trait Trait {
221         fn method(&self) -> int;
222     }
223
224     impl Trait for Struct {
225         fn method(&self) -> int {
226             self.field
227         }
228     }
229
230     #[bench]
231     fn trait_vtable_method_call(bh: &mut BenchHarness) {
232         let s = Struct { field: 10 };
233         let t = &s as &Trait;
234         do bh.iter {
235             t.method();
236         }
237     }
238
239     #[bench]
240     fn trait_static_method_call(bh: &mut BenchHarness) {
241         let s = Struct { field: 10 };
242         do bh.iter {
243             s.method();
244         }
245     }
246
247     // Overhead of various match forms
248
249     #[bench]
250     fn match_option_some(bh: &mut BenchHarness) {
251         let x = Some(10);
252         do bh.iter {
253             let _q = match x {
254                 Some(y) => y,
255                 None => 11
256             };
257         }
258     }
259
260     #[bench]
261     fn match_vec_pattern(bh: &mut BenchHarness) {
262         let x = [1,2,3,4,5,6];
263         do bh.iter {
264             let _q = match x {
265                 [1,2,3,.._] => 10,
266                 _ => 11
267             };
268         }
269     }
270 }