Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| #![allow(dead_code, unused_variables, unused_assignments, deprecated)] | |
| #![feature(box_syntax, slice_patterns)] | |
| extern crate rustc_serialize; | |
| extern crate chrono; | |
| use std::fmt; | |
| use std::iter; | |
| static LONG_LIVED: &'static str = "foo"; | |
| #[test] | |
| fn looping() { | |
| // FOR | |
| let mut c = 0; | |
| for _ in 0..10 { | |
| c += 1; | |
| } | |
| assert!(c == 10); | |
| // endless LOOP | |
| let mut c = 1; | |
| loop { | |
| if c % 10 == 0 { | |
| break | |
| } | |
| c += 1; | |
| } | |
| assert!(c == 10); | |
| let mut c = 1; | |
| // WHILE | |
| while c % 10 != 0 { | |
| c += 1; | |
| } | |
| } | |
| #[test] | |
| fn compound_data() { | |
| struct Point { | |
| x: i32, | |
| y: i32, | |
| } | |
| let mut p = Point { x: 0, y: 0 }; | |
| let mut o = Point { x: p.x, y: p.y }; | |
| p.x = 5; | |
| o.x = 10; | |
| assert!(o.x != p.x); | |
| struct PointT(i32, i32); | |
| let p = PointT(5, 10); | |
| assert!(p.0 == 5 && p.1 == 10); | |
| struct Inches(f32); | |
| let i = Inches(25.0); | |
| assert_eq!(i.0, 25.0); | |
| } | |
| #[test] | |
| fn enumerations() { | |
| #[derive(PartialEq)] | |
| enum Order { | |
| Less, | |
| Equal, | |
| Greater | |
| } | |
| impl Order { | |
| fn instance_method(&self) -> &'static str { | |
| match *self { | |
| Order::Less => "Less", | |
| Order::Equal => "Equal", | |
| Order::Greater => "Greater", | |
| } | |
| } | |
| } | |
| fn cmp(x: i32, y: i32) -> Order { | |
| if x < y { Order::Less } | |
| else if x > y { Order::Greater } | |
| else { Order::Equal } | |
| } | |
| let o = cmp(1, 10); | |
| assert!(o == Order::Less); | |
| let res = match o { | |
| Order::Greater => "g", | |
| Order::Less => "l", | |
| Order::Equal => "e", | |
| }; | |
| assert!(res == "l"); | |
| #[derive(PartialEq)] | |
| enum OptionalInt { | |
| Value(i32), | |
| Nothing | |
| } | |
| let m = OptionalInt::Value(30); | |
| let n = match m { | |
| OptionalInt::Value(r) => r, | |
| OptionalInt::Nothing => 0, | |
| }; | |
| assert!(n == 30); | |
| assert!(!(m == OptionalInt::Nothing)); | |
| } | |
| #[test] | |
| fn strings() { | |
| let s = "Hi"; // This is a string slice | |
| // warning: use of deprecated item: use std::convert::AsRef<str> instead, #[warn(deprecated)] on by default | |
| assert!(&s.replace("Hi", "Ho") == "Ho"); | |
| // tests/lang.rs:120:35: 120:43 error: type annotations required: cannot resolve `collections::string::String : core::convert::AsRef<_>` [E0283] | |
| assert!(s.replace("Hi", "Ho") == "Ho"); | |
| } | |
| #[test] | |
| #[should_panic] | |
| fn no_static_inference() { | |
| // Compiler cannot see at compile time that this wouldn't work | |
| // First I put in a signed integer, which gets converted to a unsigned | |
| // Second, it doesn't realize that the index is out of bounds in any case | |
| let b = ["a", "b", "c"]; | |
| assert!(b[-1] == "c"); | |
| } | |
| #[test] | |
| fn arrays() { | |
| let a = [1,2,3]; | |
| assert!(a[0] == 1); | |
| let mut b = ["a", "b"]; | |
| b[1] = LONG_LIVED; | |
| assert!(b[1] == LONG_LIVED); | |
| for item in b.iter() { | |
| println!("{}", item); | |
| } | |
| // compile time constant ! | |
| const S: usize = 20; | |
| let mut a = [5; S]; | |
| assert!(a.len() == S); | |
| // This scope is needed as we have an immutable borrow | |
| // but want to borrow a mutable later | |
| { | |
| let sl = &a[1 .. 2]; // type given just to show it ... useful for fn () | |
| assert!(sl.len() == 1); | |
| assert!(sl[0] == a[1]); | |
| } | |
| let sl2 = &mut a[0..5]; | |
| assert!(sl2.len() == 5); | |
| sl2[0] = 0; | |
| assert!(sl2[0] == 0); | |
| } | |
| #[test] | |
| fn vectors() { | |
| // it's convention to use vec![] instead of vec!() | |
| let b = vec![1,2,3]; | |
| assert!(b.len() == 3); | |
| for item in b.into_iter() { | |
| println!("{:?}", item); | |
| } | |
| // Can't use b anymore ! into_iter() takes ownership out of vector | |
| // assert!(b.len() == 0); | |
| // vec!() is also possible - it's just how macros can be called in general | |
| let mut b = vec!(1, 4); | |
| assert_eq!(b.len(), 2); | |
| assert_eq!(b[0], 1); | |
| b.push(3); | |
| assert!(b.len() == 3); | |
| // you can't access a moved v ... is that supposed to be like that ? | |
| // The cool thing is that members make their parent structs non-copyable automatically. | |
| // v.stream.write(b"hello"); | |
| struct SingleInt { | |
| x: i32 | |
| } | |
| let mut b = Vec::new(); | |
| let mut v = SingleInt{x: 3}; | |
| b.push(v); | |
| v.x = 4; | |
| assert!(b[0].x == 3); | |
| // preallocate | |
| let c: Vec<u8> = (0u8 .. 255u8).collect(); | |
| assert_eq!(c.len(), 255); | |
| let c: Vec<usize> = iter::repeat(0).take(500).collect(); | |
| assert_eq!(c.len(), 500); | |
| } | |
| #[test] | |
| #[allow(dead_code)] | |
| #[allow(unused_variables)] | |
| fn ownership() { | |
| use std::cell::RefCell; | |
| use std::rc::Rc; | |
| struct Car { | |
| name: String, | |
| } | |
| #[derive(Copy, Clone)] | |
| struct Wheel<'a> { | |
| owner: &'a Car, | |
| } | |
| static NUM_WHEELS: u8 = 4; | |
| let car = Car { name: "DeLorean".to_string() }; | |
| for _ in 0 .. NUM_WHEELS { | |
| Wheel { owner: &car }; | |
| } | |
| // Borrows are always fine - they are read-only ! | |
| let wheels = [Wheel { owner: &car }; 4]; | |
| let mut dyn_wheels = Vec::with_capacity(NUM_WHEELS as usize); | |
| for _ in 0 .. NUM_WHEELS { | |
| dyn_wheels.push(box Wheel { owner: &car }); | |
| } | |
| let ocar = Rc::new(RefCell::new(Car { name: "Trabant".to_string() })); | |
| // Mutable reference only really work with RefCell and refcounts in this case | |
| // also means the car needs heap allocation, even though stack allocation should | |
| // be fine ... is there a better way to this ? | |
| struct OWheel { | |
| owner: Rc<RefCell<Car>>, | |
| } | |
| let mut wheels = Vec::new(); | |
| for _ in 0 .. NUM_WHEELS { | |
| wheels.push(OWheel { owner: ocar.clone() }); | |
| } | |
| // Car with replaceable wheels and backpointer of wheel to car | |
| struct OCar<'a> { | |
| wheels: [Wheel<'a>; 4] | |
| } | |
| // // // TODO: WITH Generics on Wheel !! Car should be OCar here | |
| // impl<'a> OCar<'a> { | |
| // fn replace_wheel(&'a mut self, wheel_id: usize) -> Wheel { | |
| // let mut previous = self.wheels[wheel_id]; | |
| // self.wheels[wheel_id] = Wheel { owner: self }; | |
| // previous | |
| // } | |
| // } | |
| } | |
| #[test] | |
| #[allow(unused_variables)] | |
| fn advanced_patterns() { | |
| let x = 3; | |
| match x { | |
| 1 | 2 => assert!(false, "Shouldn't be here"), | |
| _ => (), | |
| } | |
| match x { | |
| e @ 0 ... 3 => { format!("x is between 0 and incl. 3: {}", e); () }, | |
| _ => unreachable!(), | |
| } | |
| let x = Some(5); | |
| match x { | |
| Some(..) => (), | |
| None => unreachable!(), | |
| } | |
| // pattern guards use if | |
| match x { | |
| Some(v) if v == 5 => (), | |
| _ => unreachable!() | |
| } | |
| // destructuring pattern (implicit derefenece ... kind of) | |
| let y: &i32 = &x.unwrap(); | |
| match y { | |
| &y => (), // note that here x, is dereferenced, so we get a value // i32 | |
| } | |
| // You can ask for a ref explicitly though | |
| match x { | |
| ref z => (), // &i32 | |
| } | |
| let mut x = 5; | |
| match x { | |
| ref mut z => (), //&mut i32 | |
| } | |
| struct Point { | |
| x: i32, | |
| y: i32, | |
| } | |
| // Destructure members of struct | |
| let mut p = Point {x: 1, y: 2}; | |
| match p { | |
| Point { x: u, y: v } => p.x += p.y, | |
| } | |
| assert!(p.x == 3); | |
| // Destruction only some members | |
| match p{ | |
| // without ref mut, we would get a copy of the POD | |
| Point { y: ref mut u, .. } => {*u += 5; ()}, | |
| } | |
| assert!(p.y == 7); | |
| match p { | |
| ref mut m if m.x == 3 => m.x += 3, | |
| // m => (), this would move p, so it can't be used anymore | |
| _ => assert!(false), | |
| } | |
| assert!(p.x == 6); | |
| // you can also define you want a borrow right away | |
| match &mut p { | |
| m => m.x += 3, | |
| } | |
| // decomposition cannot be nested, so Some(Point(x: x, y: y)) won't work | |
| let mut p = Some(Point { x: 5, y: 10 } ); | |
| match p { | |
| Some(ref mut p) => { p.x += p.y; () }, // p is &Point, *p.x is a way to access it | |
| None => assert!(false), | |
| } | |
| assert!(p.unwrap().x == 15); | |
| // Tuple destucturing ! | |
| let mut t = (5, "foo", 24.0); | |
| match t { | |
| (ref mut x, _, _) if *x == 5 => *x += 5, | |
| (_, x, _) if x == "bar" => (), | |
| (_, _, _) => (), | |
| } | |
| assert!(t.0 == 10); | |
| // Array destructuring | |
| // NOTE: For arrays with any unkonwn size, .. works ! | |
| // Tuples require you to do | |
| let mut a = [1, 2, 3]; | |
| match &mut a { | |
| &mut [ref mut u, ref mut v, _] if *u == 1 && *v == 2 => { | |
| *u += 3; | |
| *v += 2 }, | |
| &mut [..] => (), | |
| // _ => (), would be equivalent | |
| } | |
| assert!(a[0] == a[1]); | |
| } | |
| #[test] | |
| fn methods() { | |
| const FROM_BASE: f32 = 2.54; | |
| #[derive(PartialEq)] | |
| struct Centimeters(f32); | |
| struct Inches(f32); | |
| impl Centimeters { | |
| fn from_inches(inch: &Inches) -> Centimeters { | |
| inch.to_cm() | |
| } | |
| } | |
| impl Inches { | |
| fn from_cm(cm: &Centimeters) -> Inches { | |
| Inches(cm.0 * FROM_BASE) | |
| } | |
| fn to_cm(&self) -> Centimeters { | |
| Centimeters(self.0 / FROM_BASE) | |
| } | |
| } | |
| let cm = Centimeters(20.0); | |
| let inch = Inches::from_cm(&cm); | |
| assert!(cm.0 == 20.0); | |
| assert!(cm == inch.to_cm()); | |
| let cm = Centimeters::from_inches(&inch); | |
| assert!(cm == inch.to_cm()); | |
| // deconstruction/matching of a NewType | |
| let Centimeters(myone) = cm; | |
| assert!(myone == cm.0); | |
| } | |
| #[test] | |
| fn closures() { | |
| // note that THIS doesnt work: x + 1 - type inference fails I guess | |
| // borrow closure for read-only access: |&:| | |
| let add_one_ref = |x| { 1 + x }; | |
| let explicit_add_one_ref = |x: i32| { x + 1 }; | |
| let x = 1; | |
| assert!(add_one_ref(x) == 2); | |
| assert!(x == 1); | |
| assert!(explicit_add_one_ref(x) == 2); | |
| assert!(x == 1); | |
| // mutable borrow closure returns ownership after so: |&mut| | |
| let mut x = 1; | |
| { | |
| let mut add_one_to_x = || -> i32 { x += 1; x }; | |
| assert!(add_one_to_x() == 2); | |
| // assert!(add_one_to_x() == x); // doesn't work because x is still borrowed mutably | |
| // assert!(2 == x); // same here ... :) | |
| // x = 2; // no writing ! | |
| } | |
| assert!(x == 2); | |
| x = 3; // can adjust it again | |
| let x = x; // drop mutability | |
| assert!(x == 3); | |
| // x = 5; // this fails now ! | |
| // TODO: MOVING CLOSURE | |
| // let mut x = 1; | |
| { | |
| // let add_one_to_x = || { x += 1 }; | |
| // add_one_to_x(); | |
| // assert!(x == 2); | |
| } | |
| // assert!(x == 2); | |
| let x = 3; | |
| fn thrice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { | |
| f(x) * 3 | |
| } | |
| fn subtract_one(x: i32) -> i32 { | |
| x - 1 | |
| } | |
| assert_eq!(thrice(x, |x| { x - 1 }), 6); | |
| assert!(x == 3); | |
| assert_eq!(thrice(x, subtract_one), 6); | |
| } | |
| #[test] | |
| fn iterators() { | |
| let mut range_10 = 0 .. 10; | |
| let mut c = 0usize; | |
| loop { | |
| match range_10.next() { | |
| Some(_) => (), | |
| None => break, | |
| } | |
| assert!(c < 10); | |
| c += 1; | |
| } | |
| let one_to_hundred = (1 .. 101).collect::<Vec<i32>>(); | |
| assert_eq!(one_to_hundred.len(), 100); | |
| let one_to_fifty = (1 .. std::usize::MAX).take(50).collect::<Vec<usize>>(); | |
| assert!(one_to_fifty.len() == 50); | |
| } | |
| #[test] | |
| fn sizes() { | |
| assert_eq!(std::mem::size_of::<i32>(), 4); | |
| assert_eq!(std::mem::size_of::<Option<i64>>(), 16); | |
| assert_eq!(std::mem::size_of::<Option<i32>>(), 8); | |
| assert_eq!(std::mem::size_of::<Result<u8, bool>>(), 2); | |
| #[allow(dead_code)] | |
| enum Multiple { | |
| One(bool), | |
| Two(i32), | |
| Three(i64) | |
| } | |
| assert!(std::mem::size_of::<Multiple>() == 16); | |
| } | |
| #[test] | |
| #[allow(unused_variables)] | |
| fn generics_and_traits() { | |
| let v: Option<i32> = Some(5); | |
| trait Outspoken : fmt::Debug {}; | |
| // This defines a default implementation to anything with the Outspoke trait. | |
| trait OutspokenImpl : Outspoken { | |
| fn speak(&self) -> String { | |
| format!("{:?}", self) | |
| } | |
| } | |
| // This line tells the generics system to provide the implementation to all types | |
| // which are outspoken | |
| impl<T> OutspokenImpl for T where T: Outspoken {} | |
| #[derive(Debug)] | |
| struct MyType(i32); | |
| // Add Outspoken marker to my type | |
| // impl Outspoken for MyType {}; | |
| // Add Outspoken to all types that have the Debug trait | |
| impl<T> Outspoken for T where T: fmt::Debug {} | |
| assert_eq!(format!("{:?}", MyType(15)), "MyType(15)"); | |
| let mti = MyType(20); | |
| assert_eq!(mti.speak(), "MyType(20)"); | |
| // You can bark even though the implementation follows later. | |
| // Makes sense as we handle generics at compile time | |
| assert_eq!(mti.bark(), "wuff"); | |
| // Add your own methods to any existing type who is Outspoken | |
| trait AmendDoggyness : Outspoken { | |
| fn bark(&self) -> &str { | |
| "wuff" | |
| } | |
| } | |
| impl<T> AmendDoggyness for T where T: Outspoken {} | |
| } | |
| #[test] | |
| fn outspoken_from_stackoverflow() { | |
| trait Outspoken { | |
| fn speak(&self) -> String; | |
| } | |
| impl<T> Outspoken for T where T: fmt::Debug { | |
| fn speak(&self) -> String { | |
| format!("{:?}", self) | |
| } | |
| } | |
| #[derive(Debug)] | |
| struct MyType(i32); | |
| fn main() { | |
| assert_eq!(format!("{:?}", MyType(15)), "MyType(15)"); | |
| assert_eq!(MyType(20).speak(), "MyType(20)"); | |
| } | |
| } | |
| #[test] | |
| fn type_aliases() { | |
| // type actually declares something like a new type with given memory layout | |
| struct Foo { | |
| a: u32, | |
| }; | |
| impl Foo { | |
| fn bark(&self) { | |
| println!("Wuff {}", self.a); | |
| } | |
| fn id() -> &'static str { | |
| "FOO" | |
| } | |
| } | |
| assert_eq!(Foo::id(), "FOO"); | |
| let f = Foo { a: 1 }; | |
| f.bark(); | |
| type Bar = Foo; | |
| // assert_eq!(!Bar::id(), "FOO"); | |
| // error: unresolved name `Bar::id` | |
| // tests/lang.rs:628 assert_eq!(!Bar::id(), "FOO"); | |
| let b = Bar { a: 2 }; | |
| b.bark(); // this works though | |
| // impl Bar { | |
| // // This would add a similarly named implementation, that is difficult to call | |
| // // due to ambiguity. | |
| // // Interestingly, it also affects Foo, as well as Bar !! | |
| // // fn bark(&self) { | |
| // // println!("Grrrr {}", self.a); | |
| // // } | |
| // fn id() -> &'static str { | |
| // "BAR" | |
| // } | |
| // } | |
| // b.bark(); // or f.bark(); | |
| // error: multiple applicable methods in scope [E0034] | |
| // tests/lang.rs:625 f.bark(); | |
| // ^~~~~~ | |
| // tests/lang.rs:615:9: 617:10 note: candidate #1 is defined in an impl for the type `type_aliases::Foo` | |
| // tests/lang.rs:615 fn bark(&self) { | |
| // tests/lang.rs:616 println!("Wuff {}", self.a); | |
| // tests/lang.rs:617 } | |
| // tests/lang.rs:637:9: 639:10 note: candidate #2 is defined in an impl for the type `type_aliases::Foo` | |
| // tests/lang.rs:637 fn bark(&self) { | |
| // tests/lang.rs:638 println!("Grrrr {}", self.a); | |
| // assert_eq!(Bar::id(), "BAR"); | |
| } | |
| #[test] | |
| fn eq_on_float() { | |
| #[derive(PartialEq,Debug)] | |
| // #[derive(PartialEq,Eq,Debug)] // doesn't work, as there is no Eq for Floats | |
| struct PartialEqF32 { | |
| a: f32, | |
| } | |
| assert_eq!(PartialEqF32{a:1.0}, PartialEqF32{a:1.0}); | |
| type MyFloat = f32; | |
| // This has nothing to do with the Eq problem encountered in rust-tracer. | |
| #[derive(PartialEq,Debug)] | |
| struct PartialEqMyFloat { | |
| a: MyFloat, | |
| } | |
| assert_eq!(PartialEqMyFloat{a:1.0}, PartialEqMyFloat{a:1.0}); | |
| } | |
| #[test] | |
| fn traversing_tuples() { | |
| // one day, I might understand the destructuring syntax ... ! | |
| // The ampersand is required, and I'd like to be able to explain why. | |
| // see http://stackoverflow.com/questions/28405400/why-is-needed-to-destructure-a-list-of-tuples-during-iteration for an answer.git | |
| for &(a, b, c) in [("hello", 1.0, 5), ("world", 2.0, 2)].iter() { | |
| println!("{} {} {}", a, b, c); | |
| } | |
| for a in &[1, 2, 3] { | |
| println!("{}", a); | |
| } | |
| for &a in [1, 2, 3].iter() { | |
| println!("{}", a); | |
| } | |
| } | |
| #[test] | |
| fn into_iter() { | |
| use std::iter::IntoIterator; | |
| fn iterate<I: IntoIterator<Item=String>>(v: I) { | |
| } | |
| // iterate(&["foo".to_string()]) | |
| // error: type mismatch resolving `<&[collections::string::String; 1] as core::iter::IntoIterator>::Item == collections::string::String`: | |
| // expected &-ptr, | |
| // found struct `collections::string::String` [E0271] | |
| // iterate(["foo".to_string()].iter()) | |
| // type mismatch resolving `<core::slice::Iter<'_, collections::string::String> as core::iter::IntoIterator>::Item == collections::string::String`: | |
| // expected &-ptr, | |
| // found struct `collections::string::String` [E0271] | |
| // This works ! | |
| iterate(vec!["foo".to_string()]); | |
| } | |
| // Doesn't compile anymore: | |
| // tests/lang.rs:763:47: 763:60 error: type `[S]` does not implement any method in scope named `connect` | |
| // tests/lang.rs:763 s.into_iter().collect::<Vec<S>>()[..].connect(", ") | |
| // use std::slice::SliceConcatExt; | |
| // fn generic_collect() { | |
| // use std::iter::IntoIterator; | |
| // fn connected<S, I>(s: I) -> String | |
| // where S: Str+Clone, | |
| // I: IntoIterator<Item=S> { | |
| // // have | |
| // s.into_iter().collect::<Vec<S>>()[..].connect(", ") | |
| // // want | |
| // // s.into_iter().connect(", ") | |
| // // error: type `<I as core::iter::IntoIterator>::IntoIter` does not implement any method in scope named `connect` | |
| // // tests/lang.rs:790 s.into_iter().connect(", ") | |
| // } | |
| // connected(&["foo", "bar"]); | |
| // } | |
| #[test] | |
| fn pair_iterator_pattern() { | |
| fn pair_transformer<'a, I>(pairs: I) -> String | |
| where I: Iterator<Item=&'a (&'a str, &'a str)> { | |
| for pair in pairs { | |
| let &(a, b) = pair; | |
| // do something | |
| } | |
| String::new() | |
| } | |
| fn consuming_pair_transformer<'a, I>(pairs: I) -> String | |
| where I: Iterator<Item=(&'a str, &'a str)> { | |
| for pair in pairs { | |
| let (a, b) = pair; | |
| // do something | |
| } | |
| String::new() | |
| } | |
| // This works, natively | |
| pair_transformer([("a", "b")].iter()); | |
| // This one too | |
| pair_transformer(vec![("a", "b")].iter()); | |
| struct Pair<A: Copy, B: Copy> { | |
| first: A, | |
| second: B | |
| } | |
| impl<A: Copy, B: Copy> Pair<A, B> { | |
| fn from_tuple(t: (A, B)) -> Pair<A, B> { | |
| Pair { | |
| first: t.0, | |
| second: t.1 | |
| } | |
| } | |
| fn as_tuple(&self) -> (A, B) { | |
| (self.first, self.second) | |
| } | |
| } | |
| // Consuming custom type instances | |
| let pairs = [Pair::from_tuple(("a", "b"))]; | |
| // pair_transformer(pairs.iter().map(|p| &p.as_tuple())); | |
| // tests/lang.rs:845:44: 845:56 error: borrowed value does not live long enough | |
| // tests/lang.rs:845 pair_transformer(pairs.iter().map(|p| &p.as_tuple())); | |
| // ^~~~~~~~~~~~ | |
| // tests/lang.rs:845:22: 845:57 note: reference must be valid for the method call at 845:21... | |
| // tests/lang.rs:845 pair_transformer(pairs.iter().map(|p| &p.as_tuple())); | |
| // ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| // tests/lang.rs:845:43: 845:56 note: ...but borrowed value is only valid for the block at 845:42 | |
| // tests/lang.rs:845 pair_transformer(pairs.iter().map(|p| &p.as_tuple())); | |
| // ^~~~~~~~~~~~~ | |
| // This works now ... | |
| consuming_pair_transformer(pairs.iter().map(|p| p.as_tuple())); | |
| } | |
| #[test] | |
| fn pair_iterator_pattern_borrowed() { | |
| use std::borrow::Borrow; | |
| fn pair_transformer<'a, I, T>(pairs: I) -> String | |
| where T: Borrow<(&'a str, &'a str)>, | |
| I: Iterator<Item=T> { | |
| let mut s = String::new(); | |
| for pair in pairs { | |
| let &(a, b) = pair.borrow(); | |
| // do something | |
| s = s + a + b; | |
| } | |
| s | |
| } | |
| let pairs = [("a", "b")]; | |
| assert_eq!(pair_transformer(pairs.iter()), "ab"); | |
| assert_eq!(pair_transformer(pairs.iter().map(|p|(p.0, p.1))), "ab"); | |
| } | |
| #[test] | |
| fn pair_trait_for_iteration() { | |
| use std::borrow::Borrow; | |
| trait Pair<'a, A: ?Sized, B: ?Sized> { | |
| fn first_ref(&'a self) -> &'a A; | |
| fn second_ref(&'a self) -> &'a B; | |
| } | |
| struct PairOwned<A, B> { | |
| first: A, | |
| second: B, | |
| } | |
| // Only implemented for the cases we are interested in ... | |
| impl<'a, ARef: ?Sized, BRef: ?Sized, A, B> Pair<'a, ARef, BRef> for PairOwned<A,B> | |
| where A: Borrow<ARef>, | |
| B: Borrow<BRef> { | |
| fn first_ref(&'a self) -> &'a ARef { | |
| self.first.borrow() | |
| } | |
| fn second_ref(&'a self) -> &'a BRef { | |
| self.second.borrow() | |
| } | |
| } | |
| // It should also be possible to be more generic here with Borrow | |
| // But I wanted to leave your original implementation | |
| impl<'a, A: ?Sized, B: ?Sized> Pair<'a, A, B> for (&'a A, &'a B) { | |
| fn first_ref(&'a self) -> &'a A { | |
| self.0 | |
| } | |
| fn second_ref(&'a self) -> &'a B { | |
| self.1 | |
| } | |
| } | |
| fn pair_transformer<'a, I, T>(pairs: I) -> String | |
| where T: Pair<'a, str, str> + 'a, | |
| I: Iterator<Item=&'a T> { | |
| let mut s = String::new(); | |
| for pair in pairs { | |
| s = s | |
| + pair.first_ref().as_ref() | |
| + pair.second_ref().as_ref(); | |
| } | |
| s | |
| } | |
| pair_transformer([PairOwned { first: "a".to_string(), second: "b".to_string() }].iter()); | |
| pair_transformer([PairOwned { first: "a".to_string(), second: "b" }].iter()); // It is even possible to mix String and &str | |
| pair_transformer([PairOwned { first: "a", second: "b" }].iter()); | |
| pair_transformer([("a", "b")].iter()); | |
| pair_transformer(vec![("a", "b")].iter()); | |
| pair_transformer(vec![("a", "b")][..].iter()); | |
| } | |
| #[test] | |
| fn serialize_json() { | |
| use rustc_serialize::json; | |
| // Automatically generate `Decodable` and `Encodable` trait implementations | |
| #[derive(RustcDecodable, RustcEncodable)] | |
| struct TestStruct { | |
| data_int: u8, | |
| data_str: String, | |
| data_vector: Vec<u8>, | |
| } | |
| let object = TestStruct { | |
| data_int: 1, | |
| data_str: "homura".to_string(), | |
| data_vector: vec![2,3,4,5], | |
| }; | |
| // Serialize using `json::encode` | |
| let encoded = json::encode(&object).unwrap(); | |
| // Deserialize using `json::decode` | |
| let decoded: TestStruct = json::decode(encoded.as_ref()).unwrap(); | |
| } | |
| #[test] | |
| fn lifetime_never_used_bug() { | |
| // https://github.com/rust-lang/rust/issues/22798 | |
| // CLOSED | |
| struct Foo<'a> { | |
| a: &'a str, | |
| } | |
| // struct Bar<'a, T = Foo<'a>> { | |
| // b: T, | |
| // } | |
| use std::marker::PhantomData; | |
| struct BarWorking <'a, T = Foo<'a>> | |
| where T: 'a { | |
| b: T, | |
| _m: &'a PhantomData<T>, | |
| } | |
| } | |
| #[test] | |
| fn traits_and_generics() { | |
| // https://github.com/rust-lang/rust/issues/22834 | |
| // CLOSED (Invalid) | |
| use std::default::Default; | |
| trait Maker { | |
| type Item; | |
| fn make(&mut self) -> Self::Item; | |
| } | |
| struct Foo<T> { | |
| a: T, | |
| } | |
| // struct Bar; | |
| // | |
| // Fails | |
| // impl<T> Maker for Bar | |
| // where T: Default { | |
| // type Item = Foo<T>; | |
| // fn make(&mut self) -> Foo<T> { | |
| // Foo { | |
| // a: <T as Default>::default(), | |
| // } | |
| // } | |
| // } | |
| // Works | |
| use std::marker::PhantomData; | |
| struct Bar<T> { | |
| _m: PhantomData<T> | |
| } | |
| impl<T> Maker for Bar<T> | |
| where T: Default { | |
| type Item = Foo<T>; | |
| fn make(&mut self) -> Foo<T> { | |
| Foo { | |
| a: <T as Default>::default(), | |
| } | |
| } | |
| } | |
| } | |
| #[test] | |
| fn passing_static_refs() { | |
| trait Noop: Send { | |
| fn noop(&self){} | |
| } | |
| struct Foo { | |
| a: &'static str, | |
| b: &'static Noop, | |
| } | |
| impl Clone for Foo { | |
| fn clone(&self) -> Foo { | |
| Foo { | |
| a: self.a, | |
| b: self.b, | |
| } | |
| } | |
| } | |
| } | |
| #[test] | |
| fn chrono_time_conversion() { | |
| // http://stackoverflow.com/questions/28747694/how-do-i-convert-a-chrono-datetimeutc-instance-to-datetimelocal | |
| use chrono::{Local, TimeZone}; | |
| let utc = chrono::UTC::now(); | |
| let loc = chrono::Local::now(); | |
| println!("{:?}", utc); | |
| println!("{:?}", loc); | |
| println!("{:?}", utc.with_timezone(&Local)); | |
| println!("{:?}", Local.from_utc_datetime(&utc.naive_local())); | |
| } | |
| #[test] | |
| fn refcell_and_borrow_mut() { | |
| use std::cell::RefCell; | |
| use std::borrow::BorrowMut; | |
| struct Hub<C> { | |
| client: RefCell<C> | |
| } | |
| impl<C> Hub<C> | |
| where C: BorrowMut<Client> { | |
| fn new(client: C) -> Hub<C> { | |
| Hub { | |
| client: RefCell::new(client) | |
| } | |
| } | |
| fn builder<'a>(&'a self) -> Builder<'a, C> { | |
| Builder { | |
| hub: self | |
| } | |
| } | |
| } | |
| struct Builder<'a, C: 'a> { | |
| hub: &'a Hub<C> | |
| } | |
| impl<'a, C> Builder<'a, C> | |
| where C: BorrowMut<Client> { | |
| fn use_client(self) { | |
| // 1: borrow_mut() of RefCell | |
| // 2: borrow_mut() of BorrowMut() | |
| // but doesn't work, as RefMut returned by 1) always yields RefCell | |
| loop { | |
| (*self.hub.client.borrow_mut()).borrow_mut().doit(); | |
| break; | |
| } | |
| } | |
| } | |
| struct Client; | |
| impl Client { | |
| fn doit(&mut self) { | |
| println!("DID IT!!") | |
| } | |
| } | |
| // HUB USAGE | |
| { | |
| let h = Hub::new(Client); | |
| h.builder().use_client(); | |
| } | |
| { | |
| let mut c = Client; | |
| let h = Hub::new(&mut c); | |
| h.builder().use_client(); | |
| } | |
| } | |
| #[test] | |
| fn borrow_oddity() { | |
| /// A utility type to perform a resumable upload from start to end. | |
| struct Foo<'a> { | |
| a: &'a u64, | |
| } | |
| impl<'a> Foo<'a> { | |
| fn mutate_internal(&mut self) {} | |
| fn mutate(&mut self) { | |
| self.mutate_internal(); | |
| self.mutate_internal(); | |
| } | |
| } | |
| } | |
| // #[test] | |
| // http://stackoverflow.com/questions/28136739/variable-member-array-sizes-in-generic-types | |
| // fn test_generic_arrays() { | |
| // struct Vec<T: Sized, Count> { | |
| // a: [T; Count] | |
| // } | |
| // } | |
| #[test] | |
| fn boxed_write_and_mutability() { | |
| use std::io::{self, Write}; | |
| fn make_stream() -> Box<Write> { | |
| Box::new(io::stdout()) | |
| } | |
| fn use_stream(stream: &mut Write) { | |
| stream.write("Hello\n".as_bytes()).ok(); | |
| } | |
| use_stream(&mut make_stream()); | |
| } | |
| #[test] | |
| fn generic_iteration() { | |
| struct Foo<'a> { | |
| flag: Option<&'a str> | |
| } | |
| fn consumer<'a, T, I>(values: I) -> Option<&'a str> | |
| where T: AsRef<str> + 'a, | |
| I: IntoIterator<Item=&'a T> { | |
| for item in values { | |
| return Some(item.as_ref()); | |
| } | |
| None | |
| } | |
| let s = "string-val"; | |
| let values = vec![Foo { flag: Some(s) }]; | |
| let res = consumer(values.iter() | |
| .filter_map(|v| | |
| if let Some(ref f) = v.flag {Some(f)} else {None} | |
| )); | |
| assert_eq!(res, Some(s)); | |
| // self.opts.values() | |
| // .filter_map(|v| | |
| // if let Some(l) = v.long {Some(l)} else {None} | |
| // ) | |
| } | |
| #[test] | |
| fn enum_drill_down() { | |
| use std::collections::BTreeMap; | |
| enum Value { | |
| Null, | |
| Object(BTreeMap<String, Value>) | |
| } | |
| fn set_null_to_how_i_want_it(fields: &[&str], mut v: &mut Value) { | |
| debug_assert!(fields.len() > 0); | |
| for (fid, field) in fields.iter().enumerate() { | |
| let tmp = v; | |
| v = | |
| match *tmp { | |
| Value::Object(ref mut map) => { | |
| let val_to_insert = | |
| if fid == fields.len() - 1 { | |
| Value::Null | |
| } else { | |
| Value::Object(Default::default()) | |
| }; | |
| map.entry(field.to_string()).or_insert(val_to_insert) | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| } | |
| fn set_null_how_borrow_chk_allows_it(fields: &[&str], v: &mut Value) { | |
| let next = | |
| match *v { | |
| Value::Object(ref mut map) => { | |
| let val_to_insert = | |
| if fields.len() == 1 { | |
| Value::Null | |
| } else { | |
| Value::Object(Default::default()) | |
| }; | |
| map.entry(fields[0].to_string()).or_insert(val_to_insert) | |
| }, | |
| _ => unreachable!() | |
| }; | |
| if fields.len() > 1 { | |
| set_null_how_borrow_chk_allows_it(&fields[1..], next) | |
| } | |
| } | |
| let mut v = Value::Object(Default::default()); | |
| let fields = ["foo", "bar", "baz"]; | |
| set_null_to_how_i_want_it(&fields, &mut v); | |
| let mut map_count = 0; | |
| for (fid, field) in fields.iter().enumerate() { | |
| let next = | |
| match v { | |
| Value::Object(mut map) => { | |
| map_count += 1; | |
| map.remove(&field.to_string()).unwrap() | |
| }, | |
| _ => unreachable!() | |
| }; | |
| v = next; | |
| } | |
| assert_eq!(map_count, fields.len()); | |
| match v { | |
| Value::Null => (), | |
| Value::Object(_) => unreachable!(), | |
| } | |
| } |