<commit_before>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate vertex;

use vertex::{
    Quad,
    EmitTriangles,
    Triangle,
    MapToVertices,
    LruIndexer,
    Indexer,
    Vertices,
    Triangulate
};

use vertex::generators::{Cube, Plane};

#[test]
fn test_quad_vertex() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(false, true, false, true),
                   Quad::new(true, false, true, false)];

    let transformed = input.iter().map(|x| x.clone())
                                  .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_quad_vertex_two_stages() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(false, true, false, true),
                   Quad::new(true, false, true, false)];

    let transformed = input.iter().map(|x| x.clone())
                                  .vertex(|v| v as u8)
                                  .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_quad_poly_simple() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(0i, 1, 2, 0),
                   Quad::new(0i, 2, 3, 0)];

    let transformed = input.iter().map(|x| x.clone())
                                  .map(|v| Quad::new(0i, v.y as int, v.z as int, 0));

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_vertex() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(false, true, false),
                   Triangle::new(true, false, true)];

    let transformed = input.iter().map(|x| x.clone())
                           .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_vertex_two_stages() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(false, true, false),
                   Triangle::new(true, false, true)];

    let transformed = input.iter().map(|x| x.clone())
                           .vertex(|v| v as u8)
                           .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_poly_simple() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(0i, 1, 2),
                   Triangle::new(0i, 2, 3)];

    let transformed = input.iter().map(|x| x.clone())
                           .map(|v| Triangle::new(0i, v.y as int, v.z as int));

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_to_triangles() {
    let q = Quad::new(0u, 1, 2, 3);
    let mut result = Vec::new();
    q.emit_triangles(|v| result.push(v));

    assert_eq!(result, vec![Triangle::new(0u, 1, 2),
                            Triangle::new(2u, 3, 0)]);

    let t = Triangle::new(0u, 1, 2);
    let mut result = Vec::new();
    t.emit_triangles(|v| result.push(v));

    assert_eq!(result, vec![Triangle::new(0u, 1, 2)]);
}

#[test]
fn test_plane() {
    let mut plane = Plane::new();

    let a = plane.next().unwrap();

    let Quad {
        x: (ax, ay),
        y: (bx, by),
        z: (cx, cy),
        w: (dx, dy)
    } = a;

    assert_eq!(ax, -1.); assert_eq!(ay, -1.);
    assert_eq!(bx, -1.); assert_eq!(by,  1.);
    assert_eq!(cx,  1.); assert_eq!(cy,  1.);
    assert_eq!(dx,  1.); assert_eq!(dy, -1.);
}

#[test]
fn test_lru_indexer() {
    let mut vectices = Vec::new();
    let indexes: Vec<uint> = {
        let mut indexer = LruIndexer::new(8, |_, v| vectices.push(v));

        Cube::new().vertex(|v| indexer.index(v))
                   .vertices()
                   .collect()
    };

    assert_eq!(8, vectices.len());
    assert_eq!(6*4, indexes.len());

    let mut vectices = Vec::new();
    let indexes: Vec<uint> = {
        let mut indexer = LruIndexer::new(4, |_, v| vectices.push(v));

        Cube::new().triangulate()
                   .vertex(|v| indexer.index(v))
                   .vertices()
                   .collect()
    };

    assert_eq!(20, vectices.len());
    assert_eq!(3*6*2, indexes.len());
}<commit_msg>fixed tests<commit_after>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate genmesh;

use genmesh::{
    Quad,
    EmitTriangles,
    Triangle,
    MapToVertices,
    LruIndexer,
    Indexer,
    Vertices,
    Triangulate
};

use genmesh::generators::{Cube, Plane};

#[test]
fn test_quad_vertex() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(false, true, false, true),
                   Quad::new(true, false, true, false)];

    let transformed = input.iter().map(|x| x.clone())
                                  .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_quad_vertex_two_stages() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(false, true, false, true),
                   Quad::new(true, false, true, false)];

    let transformed = input.iter().map(|x| x.clone())
                                  .vertex(|v| v as u8)
                                  .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_quad_poly_simple() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(0i, 1, 2, 0),
                   Quad::new(0i, 2, 3, 0)];

    let transformed = input.iter().map(|x| x.clone())
                                  .map(|v| Quad::new(0i, v.y as int, v.z as int, 0));

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_vertex() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(false, true, false),
                   Triangle::new(true, false, true)];

    let transformed = input.iter().map(|x| x.clone())
                           .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_vertex_two_stages() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(false, true, false),
                   Triangle::new(true, false, true)];

    let transformed = input.iter().map(|x| x.clone())
                           .vertex(|v| v as u8)
                           .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_poly_simple() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(0i, 1, 2),
                   Triangle::new(0i, 2, 3)];

    let transformed = input.iter().map(|x| x.clone())
                           .map(|v| Triangle::new(0i, v.y as int, v.z as int));

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_to_triangles() {
    let q = Quad::new(0u, 1, 2, 3);
    let mut result = Vec::new();
    q.emit_triangles(|v| result.push(v));

    assert_eq!(result, vec![Triangle::new(0u, 1, 2),
                            Triangle::new(2u, 3, 0)]);

    let t = Triangle::new(0u, 1, 2);
    let mut result = Vec::new();
    t.emit_triangles(|v| result.push(v));

    assert_eq!(result, vec![Triangle::new(0u, 1, 2)]);
}

#[test]
fn test_plane() {
    let mut plane = Plane::new();

    let a = plane.next().unwrap();

    let Quad {
        x: (ax, ay),
        y: (bx, by),
        z: (cx, cy),
        w: (dx, dy)
    } = a;

    assert_eq!(ax, -1.); assert_eq!(ay, -1.);
    assert_eq!(bx, -1.); assert_eq!(by,  1.);
    assert_eq!(cx,  1.); assert_eq!(cy,  1.);
    assert_eq!(dx,  1.); assert_eq!(dy, -1.);
}

#[test]
fn test_lru_indexer() {
    let mut vectices = Vec::new();
    let indexes: Vec<uint> = {
        let mut indexer = LruIndexer::new(8, |_, v| vectices.push(v));

        Cube::new().vertex(|v| indexer.index(v))
                   .vertices()
                   .collect()
    };

    assert_eq!(8, vectices.len());
    assert_eq!(6*4, indexes.len());

    let mut vectices = Vec::new();
    let indexes: Vec<uint> = {
        let mut indexer = LruIndexer::new(4, |_, v| vectices.push(v));

        Cube::new().triangulate()
                   .vertex(|v| indexer.index(v))
                   .vertices()
                   .collect()
    };

    assert_eq!(20, vectices.len());
    assert_eq!(3*6*2, indexes.len());
}<|endoftext|>


<commit_before>extern crate rustboy_core;
extern crate image;

use std::fs::{read_dir, create_dir, File};
use std::io::{Read, Error, Write};
use std::path::Path;

use std::vec::Vec;

const TEST_FRAMES: usize = 60 * 15;

pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>, Error> {
	let mut file = try!(File::open(path));
	let mut buffer = Vec::new();
	let result = file.read_to_end(&mut buffer);
	match result {
		Ok(_) => Ok(buffer.into_boxed_slice()),
		Err(err) => Err(err),
	}
}

///Runs a test rom and saves a sceenshot in tests/results after a specified ammount of cycles
///If there are no errors, it returns a vec of u32's that represent an rgba screenshot
fn run_test_rom(path: String) -> Result<Vec<u32>,String> {
	let rom = read_file(path.clone());
	if let Err(_) = rom {
		return Err(format!("Failed to open file {}.", path));
	}

	let gameboy = rustboy_core::init(rom.unwrap(), None);
	if let Err(ref msg) = gameboy {
		return Err(format!("Test rom {} failed with error {}.", path.clone(), msg));
	}
	let mut gameboy = gameboy.unwrap();

	for frame in 0..TEST_FRAMES {
		gameboy.step_frame();
	}

	let framebuffer = gameboy.get_framebuffer();
	let mut buffer = std::vec::Vec::with_capacity(framebuffer.len() * 4);
	buffer.extend_from_slice(framebuffer);

	//return screenshot
	Ok((buffer))
}

fn save_screenshot(path: String, raw: Vec<u32>) -> Result<(), std::io::Error> {
	let file = try!(File::create(path));

	//Convert the u32 pixels into rgba structs for the image library
	let mut buffer: Vec<u8> = Vec::with_capacity(raw.len() * 4);
	for val in raw {
		buffer.push((val >> 24) as u8);
		buffer.push((val >> 16) as u8);
		buffer.push((val >> 8) as u8);
		buffer.push((val & 0xFF) as u8);
	}
	let encoder = image::png::PNGEncoder::new(file);
	encoder.encode(buffer.as_slice(), rustboy_core::WIDTH as u32, rustboy_core::HEIGHT as u32, image::ColorType::RGBA(8))
}

#[test]
#[allow(unused_must_use)]
fn test_rom_runner() {
	create_dir("tests/results");	//Create a directory for screenshots
	let mut log = File::create("tests/results/test_log.txt").expect("Failed to create log file.");

	let dir = read_dir("tests/test_roms").expect("Test rom directory doesn't exist. Place test roms in tests/test_roms to run them.");

	for item in dir {
		if let Ok(ref entry) = item {
			writeln!(&mut log, "Running rom file {:?}", entry.file_name()).unwrap();

			let file_path = entry.path().into_os_string().into_string().unwrap();
			let gb_result = run_test_rom(file_path);
			if let Ok(screenshot) = gb_result {
				let screenshot_path = format!("tests/results/{}.png", entry.file_name().into_string().unwrap());
				let sc_result = save_screenshot(screenshot_path, screenshot);
				match sc_result {
					Ok(()) => {},
					Err(error) => writeln!(&mut log, "{}", error).unwrap(), /* Error saving screenshot */
				};
			}
			else if let Err(error) = gb_result {
				writeln!(&mut log, "Running rom {:?} failed with error: {}", entry.file_name(), error).unwrap();
			}
		}
	}
}
<commit_msg>changed the test rom runner to run in parallel.<commit_after>extern crate rustboy_core;
extern crate image;

use std::fs::{read_dir, create_dir, File};
use std::io::{Read, Error, Write};
use std::path::Path;
use std::thread;

use std::vec::Vec;

const TEST_FRAMES: usize = 60 * 15;

pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>, Error> {
	let mut file = try!(File::open(path));
	let mut buffer = Vec::new();
	let result = file.read_to_end(&mut buffer);
	match result {
		Ok(_) => Ok(buffer.into_boxed_slice()),
		Err(err) => Err(err),
	}
}

///Runs a test rom and saves a sceenshot in tests/results after a specified ammount of cycles
///If there are no errors, it returns a vec of u32's that represent an rgba screenshot
fn run_test_rom(path: String) -> Result<Vec<u32>,String> {
	let rom = read_file(path.clone());
	if let Err(_) = rom {
		return Err(format!("Failed to open file {}.", path));
	}

	let gameboy = rustboy_core::init(rom.unwrap(), None);
	if let Err(ref msg) = gameboy {
		return Err(format!("{}.", msg));
	}
	let mut gameboy = gameboy.unwrap();

	for _ in 0..TEST_FRAMES {
		gameboy.step_frame();
	}

	let framebuffer = gameboy.get_framebuffer();
	let mut buffer = std::vec::Vec::with_capacity(framebuffer.len() * 4);
	buffer.extend_from_slice(framebuffer);

	//return screenshot
	Ok((buffer))
}

fn save_screenshot(path: String, raw: Vec<u32>) -> Result<(), std::io::Error> {
	let file = try!(File::create(path));

	//Convert the u32 pixels into rgba structs for the image library
	let mut buffer: Vec<u8> = Vec::with_capacity(raw.len() * 4);
	for val in raw {
		buffer.push((val >> 24) as u8);
		buffer.push((val >> 16) as u8);
		buffer.push((val >> 8) as u8);
		buffer.push((val & 0xFF) as u8);
	}
	let encoder = image::png::PNGEncoder::new(file);
	encoder.encode(buffer.as_slice(), rustboy_core::WIDTH as u32, rustboy_core::HEIGHT as u32, image::ColorType::RGBA(8))
}

#[test]
#[allow(unused_must_use)]
fn test_rom_runner() {
	create_dir("tests/results");	//Create a directory for screenshots
	let mut log = File::create("tests/results/test_log.txt").expect("Failed to create log file.");
	let dir = read_dir("tests/test_roms").expect("Test rom directory doesn't exist. Place test roms in tests/test_roms to run them.");
	let mut runners = Vec::new();

	for item in dir {
		if let Ok(entry) = item {
			let path = entry.file_name().into_string().unwrap();
			let handle = thread::spawn(move || {
				let mut info = Vec::new();
				info.push(format!("Running rom file {:?}", entry.file_name()));
				let file_path = entry.path().into_os_string().into_string().unwrap();
				let gb_result = run_test_rom(file_path);
				if let Ok(screenshot) = gb_result {
					let screenshot_path = format!("tests/results/{}.png", entry.file_name().into_string().unwrap());
					let sc_result = save_screenshot(screenshot_path, screenshot);
					match sc_result {
						Ok(()) => info.push(format!("test complete")),
						Err(error) => info.push(format!("{}", error)), /* Error saving screenshot */
					};
				}
				else if let Err(error) = gb_result {
					info.push(format!("Running rom {:?} failed with error: {}", entry.file_name(), error))
				}
				return info;
			});
			runners.push((path, handle));
		}
	}

	for (path, handle) in runners {
		match handle.join() {
			Ok(test_info) => {
				for line in test_info {
					writeln!(&mut log, "{}", line);
				}
				writeln!(&mut log, "");
			},
			Err(panic_info) => {
				writeln!(&mut log, "{} panicked with argument {:?}", path, panic_info);
			}
		}
	}
}
<|endoftext|>


<commit_before>#![feature(proc_macro, custom_attribute)]

#[macro_use]
extern crate smelter;

#[derive(PartialEq, Debug, Builder, Default)]
struct Point {
    x: u32,
    #[smelter(field_name="y_axis")]
    y: u32,
}

#[derive(PartialEq, Debug, Builder, Default)]
struct Container<T>
    where T: PartialEq  + Default {
    item: T,
}

#[test]
fn can_generate_builder_methods() {
    let point = Point::default().x(1).y_axis(2);
    let expected = Point {x: 1, y: 2};
    assert_eq!(point, expected);
}

#[test]
fn can_generate_generic_builder_methods() {
    let container: Container<u32> = Container::default().item(1u32);
    let expected = Container { item: 1u32 };
    assert_eq!(container, expected);
}

#[test]
fn can_generate_mutable_methods() {
    let mut point = Point::default();
    point.x_mut(1).y_axis_mut(2);
    let expected = Point { x: 1, y: 2};
    assert_eq!(point, expected);
}

#[derive(PartialEq, Builder, Default, Debug)]
#[smelter(prefix="with_")]
struct ContainerWith<T>
    where T: PartialEq + Default {
        item: T,
        #[smelter(field_name = "id")]
        item_id: u64,
}

#[test]
fn can_generate_container_with_prefix() {
    let container: ContainerWith<u32> = ContainerWith::default()
                                            .with_item(1u32)
                                            .with_id(5u64);
    let expected = ContainerWith { item: 1u32 , item_id: 5u64 };
    assert_eq!(container, expected);
}
<commit_msg>Added test for lifetime elision<commit_after>#![feature(proc_macro, custom_attribute)]

#[macro_use]
extern crate smelter;

#[derive(PartialEq, Debug, Builder, Default)]
struct Point {
    x: u32,
    #[smelter(field_name="y_axis")]
    y: u32,
}

#[derive(PartialEq, Debug, Builder, Default)]
struct Container<T>
    where T: PartialEq  + Default {
    item: T,
}

#[test]
fn can_generate_builder_methods() {
    let point = Point::default().x(1).y_axis(2);
    let expected = Point {x: 1, y: 2};
    assert_eq!(point, expected);
}

#[test]
fn can_generate_generic_builder_methods() {
    let container: Container<u32> = Container::default().item(1u32);
    let expected = Container { item: 1u32 };
    assert_eq!(container, expected);
}

#[test]
fn can_generate_mutable_methods() {
    let mut point = Point::default();
    point.x_mut(1).y_axis_mut(2);
    let expected = Point { x: 1, y: 2};
    assert_eq!(point, expected);
}

#[derive(PartialEq, Builder, Default, Debug)]
#[smelter(prefix="with_")]
struct ContainerWith<T>
    where T: PartialEq + Default {
        item: T,
        #[smelter(field_name = "id")]
        item_id: u64,
}

#[test]
fn can_generate_container_with_prefix() {
    let container: ContainerWith<u32> = ContainerWith::default()
                                            .with_item(1u32)
                                            .with_id(5u64);
    let expected = ContainerWith { item: 1u32 , item_id: 5u64 };
    assert_eq!(container, expected);
}

#[derive(Builder, PartialEq, Debug, Default)]
struct LotsOfFields<T: PartialEq> {
    pub this: String,
    structure: u32,
    has: i32,
    pub a: String,
    lot: T,
    pub of: &'static str,
    fields: String,
}

#[test]
fn public_fields_work() {
    let this = "this".to_string();
    let structure = 1u32;
    let has = -10i32;
    let a = "a".to_string();
    let lot = 7u32;
    let of = &"of";
    let fields = "fields".to_string();
    let expected: LotsOfFields<u32> = LotsOfFields {
        this: this.clone(),
        structure: structure.clone(),
        has: has.clone(),
        a: a.clone(),
        lot: lot.clone(),
        of: of,
        fields: fields.clone(),
    };
    let lof: LotsOfFields<u32> = LotsOfFields::default()
        .this(this)
        .structure(structure)
        .has(has)
        .a(a)
        .lot(lot)
        .of(of)
        .fields(fields);

    assert_eq!(lof, expected);
}

#[derive(Builder, PartialEq, Debug)]
struct WithLifeTime<'a> {
    l: &'a String,
}

#[test]
fn with_lifetime() {
    let s1 = "hello".to_string();
    let s2 = "hello".to_string();
    let s3 = "world".to_string();
    let with_lifetime = WithLifeTime {
        l: &s1,
    };

    let expected = WithLifeTime {
        l: &s3,
    }.l(&s2);

    assert_eq!(with_lifetime, expected);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2018-2019 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

use std::sync::{Arc, Mutex, RwLock};

use futures::{
    future::{self, Either},
    Future,
};

use tokio_executor::{DefaultExecutor, Executor};

use crate::error::{self, ConnectionReason};

type WorkFn<T, A> = Fn(&T, A) -> Box<Future<Item = (), Error = error::Error> + Send> + Send + Sync;
type ConnFn<T> = Fn() -> Box<Future<Item = T, Error = error::Error> + Send> + Send + Sync;

pub(crate) struct Reconnect<A, T> {
    state: Arc<RwLock<ReconnectState<T>>>,

    work_fn: Arc<WorkFn<T, A>>,
    conn_fn: Arc<ConnFn<T>>,
}

pub(crate) fn reconnect<A, T, W, C>(
    w: W,
    c: C,
) -> impl Future<Item = Reconnect<A, T>, Error = error::Error>
where
    A: Send + 'static,
    W: Fn(&T, A) -> Box<Future<Item = (), Error = error::Error> + Send> + Send + Sync + 'static,
    C: Fn() -> Box<Future<Item = T, Error = error::Error> + Send> + Send + Sync + 'static,
    T: Clone + Send + Sync + 'static,
{
    let r = Reconnect {
        state: Arc::new(RwLock::new(ReconnectState::NotConnected)),

        work_fn: Arc::new(w),
        conn_fn: Arc::new(c),
    };
    r.reconnect().map(|()| r)
}

enum ReconnectState<T> {
    NotConnected,
    Connected(T),
    ConnectionFailed(Mutex<Option<error::Error>>),
    Connecting,
}

use self::ReconnectState::*;

impl<A, T> Reconnect<A, T>
where
    A: Send + 'static,
    T: Clone + Send + Sync + 'static,
{
    fn call_work(&self, t: &T, a: A) -> impl Future<Item = (), Error = error::Error> {
        let reconnect = self.clone();
        (self.work_fn)(t, a).map_err(move |e| {
            match e {
                error::Error::IO(_) | error::Error::Internal(_) | error::Error::Unexpected(_) => {
                    log::error!("Error in work_fn will force connection closed, next command will attempt to re-establish it: {}", e);
                    reconnect.disconnect();
                    reconnect.reconnect_spawn();
                }
                _ => ()
            }
            e
        })
    }

    // Called when a bad situation has been discovered, force the connections to re-connect.
    fn disconnect(&self) {
        let mut state = self.state.write().expect("Cannot obtain a write lock");
        *state = NotConnected;
    }

    pub(crate) fn do_work(&self, a: A) -> impl Future<Item = (), Error = error::Error> {
        let rv = {
            let state = self.state.read().expect("Cannot obtain read lock");
            match *state {
                NotConnected => Either::B(future::err(error::Error::Connection(
                    ConnectionReason::NotConnected,
                ))),
                Connected(ref t) => return Either::A(self.call_work(t, a)),
                ConnectionFailed(ref e) => {
                    let mut lock = e.lock().expect("Poisioned lock");
                    let e = match lock.take() {
                        Some(e) => e,
                        None => error::Error::Connection(ConnectionReason::NotConnected),
                    };
                    return Either::B(future::err(e));
                }
                Connecting => {
                    return Either::B(future::err(error::Error::Connection(
                        ConnectionReason::Connecting,
                    )));
                }
            }
        };
        self.reconnect_spawn();
        rv
    }

    /// Returns a future that completes when the connection is established or failed to establish
    /// used only for timing.
    fn reconnect(&self) -> impl Future<Item = (), Error = error::Error> {
        let mut state = self.state.write().expect("Cannot obtain write lock");
        match *state {
            Connected(_) => {
                return Either::B(future::err(error::Error::Connection(
                    ConnectionReason::Connected,
                )));
            }
            Connecting => {
                return Either::B(future::err(error::Error::Connection(
                    ConnectionReason::Connecting,
                )));
            }
            NotConnected | ConnectionFailed(_) => (),
        }
        *state = ReconnectState::Connecting;

        let reconnect = self.clone();
        let connect_f = (self.conn_fn)().then(move |t| {
            let mut state = reconnect.state.write().expect("Cannot obtain write lock");
            match *state {
                NotConnected | Connecting => match t {
                    Ok(t) => {
                        log::info!("Connection established");
                        *state = Connected(t);
                        Ok(())
                    }
                    Err(e) => {
                        log::error!("Connection cannot be established: {}", e);
                        *state = ConnectionFailed(Mutex::new(Some(e)));
                        Err(error::Error::Connection(ConnectionReason::ConnectionFailed))
                    }
                },
                ConnectionFailed(_) => {
                    panic!("The connection state wasn't reset before connecting")
                }
                Connected(_) => panic!("A connected state shouldn't be attempting to reconnect"),
            }
        });

        Either::A(connect_f)
    }

    fn reconnect_spawn(&self) {
        let reconnect_f = self
            .reconnect()
            .map_err(|e| log::error!("Error asynchronously reconnecting: {}", e)); // TODO - propagate this higher

        let mut executor = DefaultExecutor::current();
        executor
            .spawn(Box::new(reconnect_f))
            .expect("Cannot spawn asynchronous reconnection");
    }
}

impl<A, T> Clone for Reconnect<A, T> {
    fn clone(&self) -> Self {
        Reconnect {
            state: self.state.clone(),
            work_fn: self.work_fn.clone(),
            conn_fn: self.conn_fn.clone(),
        }
    }
}
<commit_msg>Only IO/Unexpected errors should trigger a reconnection<commit_after>/*
 * Copyright 2018-2019 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

use std::sync::{Arc, Mutex, RwLock};

use futures::{
    future::{self, Either},
    Future,
};

use tokio_executor::{DefaultExecutor, Executor};

use crate::error::{self, ConnectionReason};

type WorkFn<T, A> = Fn(&T, A) -> Box<Future<Item = (), Error = error::Error> + Send> + Send + Sync;
type ConnFn<T> = Fn() -> Box<Future<Item = T, Error = error::Error> + Send> + Send + Sync;

pub(crate) struct Reconnect<A, T> {
    state: Arc<RwLock<ReconnectState<T>>>,

    work_fn: Arc<WorkFn<T, A>>,
    conn_fn: Arc<ConnFn<T>>,
}

pub(crate) fn reconnect<A, T, W, C>(
    w: W,
    c: C,
) -> impl Future<Item = Reconnect<A, T>, Error = error::Error>
where
    A: Send + 'static,
    W: Fn(&T, A) -> Box<Future<Item = (), Error = error::Error> + Send> + Send + Sync + 'static,
    C: Fn() -> Box<Future<Item = T, Error = error::Error> + Send> + Send + Sync + 'static,
    T: Clone + Send + Sync + 'static,
{
    let r = Reconnect {
        state: Arc::new(RwLock::new(ReconnectState::NotConnected)),

        work_fn: Arc::new(w),
        conn_fn: Arc::new(c),
    };
    r.reconnect().map(|()| r)
}

enum ReconnectState<T> {
    NotConnected,
    Connected(T),
    ConnectionFailed(Mutex<Option<error::Error>>),
    Connecting,
}

use self::ReconnectState::*;

impl<A, T> Reconnect<A, T>
where
    A: Send + 'static,
    T: Clone + Send + Sync + 'static,
{
    fn call_work(&self, t: &T, a: A) -> impl Future<Item = (), Error = error::Error> {
        let reconnect = self.clone();
        (self.work_fn)(t, a).map_err(move |e| {
            match e {
                error::Error::IO(_) | error::Error::Unexpected(_) => {
                    log::error!("Error in work_fn will force connection closed, next command will attempt to re-establish it: {}", e);
                    reconnect.disconnect();
                    reconnect.reconnect_spawn();
                }
                _ => ()
            }
            e
        })
    }

    // Called when a bad situation has been discovered, force the connections to re-connect.
    fn disconnect(&self) {
        let mut state = self.state.write().expect("Cannot obtain a write lock");
        *state = NotConnected;
    }

    pub(crate) fn do_work(&self, a: A) -> impl Future<Item = (), Error = error::Error> {
        let rv = {
            let state = self.state.read().expect("Cannot obtain read lock");
            match *state {
                NotConnected => Either::B(future::err(error::Error::Connection(
                    ConnectionReason::NotConnected,
                ))),
                Connected(ref t) => return Either::A(self.call_work(t, a)),
                ConnectionFailed(ref e) => {
                    let mut lock = e.lock().expect("Poisioned lock");
                    let e = match lock.take() {
                        Some(e) => e,
                        None => error::Error::Connection(ConnectionReason::NotConnected),
                    };
                    return Either::B(future::err(e));
                }
                Connecting => {
                    return Either::B(future::err(error::Error::Connection(
                        ConnectionReason::Connecting,
                    )));
                }
            }
        };
        self.reconnect_spawn();
        rv
    }

    /// Returns a future that completes when the connection is established or failed to establish
    /// used only for timing.
    fn reconnect(&self) -> impl Future<Item = (), Error = error::Error> {
        let mut state = self.state.write().expect("Cannot obtain write lock");
        match *state {
            Connected(_) => {
                return Either::B(future::err(error::Error::Connection(
                    ConnectionReason::Connected,
                )));
            }
            Connecting => {
                return Either::B(future::err(error::Error::Connection(
                    ConnectionReason::Connecting,
                )));
            }
            NotConnected | ConnectionFailed(_) => (),
        }
        *state = ReconnectState::Connecting;

        let reconnect = self.clone();
        let connect_f = (self.conn_fn)().then(move |t| {
            let mut state = reconnect.state.write().expect("Cannot obtain write lock");
            match *state {
                NotConnected | Connecting => match t {
                    Ok(t) => {
                        log::info!("Connection established");
                        *state = Connected(t);
                        Ok(())
                    }
                    Err(e) => {
                        log::error!("Connection cannot be established: {}", e);
                        *state = ConnectionFailed(Mutex::new(Some(e)));
                        Err(error::Error::Connection(ConnectionReason::ConnectionFailed))
                    }
                },
                ConnectionFailed(_) => {
                    panic!("The connection state wasn't reset before connecting")
                }
                Connected(_) => panic!("A connected state shouldn't be attempting to reconnect"),
            }
        });

        Either::A(connect_f)
    }

    fn reconnect_spawn(&self) {
        let reconnect_f = self
            .reconnect()
            .map_err(|e| log::error!("Error asynchronously reconnecting: {}", e)); // TODO - propagate this higher

        let mut executor = DefaultExecutor::current();
        executor
            .spawn(Box::new(reconnect_f))
            .expect("Cannot spawn asynchronous reconnection");
    }
}

impl<A, T> Clone for Reconnect<A, T> {
    fn clone(&self) -> Self {
        Reconnect {
            state: self.state.clone(),
            work_fn: self.work_fn.clone(),
            conn_fn: self.conn_fn.clone(),
        }
    }
}
<|endoftext|>


<commit_before>use types::{ToRedisArgs, FromRedisValue, RedisResult};
use connection::Connection;

enum Arg {
    SimpleArg(Vec<u8>),
    CursorArg,
}

fn encode_command(args: &Vec<Arg>, cursor: u64) -> Vec<u8> {
    let mut cmd = vec![];
    cmd.push_all(format!("*{}\r\n", args.len()).as_bytes());

    {
        let encode = |item: &[u8]| {
            cmd.push_all(format!("${}\r\n", item.len()).as_bytes());
            cmd.push_all(item);
            cmd.push_all(b"\r\n");
        };

        for item in args.iter() {
            match *item {
                CursorArg => encode(cursor.to_string().as_bytes()),
                SimpleArg(ref val) => encode(val[]),
            }
        }
    }

    cmd
}

/// Represents redis commands.
pub struct Cmd {
    args: Vec<Arg>,
    cursor: Option<u64>,
}

/// Represents a redis iterator.
pub struct Iter<'a, T: FromRedisValue> {
    batch: Vec<T>,
    cursor: u64,
    con: &'a Connection,
    cmd: &'a Cmd,
}

impl<'a, T: FromRedisValue> Iterator<T> for Iter<'a, T> {

    #[inline]
    fn next(&mut self) -> Option<T> {
        match self.batch.pop() {
            Some(v) => { return Some(v); }
            None => {}
        };
        if self.cursor == 0 {
            return None;
        }

        let pcmd = unwrap_or!(self.cmd.get_packed_command_with_cursor(
            self.cursor), return None);
        let rv = unwrap_or!(self.con.send_packed_command(
            pcmd[]).ok(), return None);
        let (cur, mut batch) : (u64, Vec<T>) = unwrap_or!(
            FromRedisValue::from_redis_value(&rv).ok(), return None);
        batch.reverse();

        self.cursor = cur;
        self.batch = batch;
        self.batch.pop()
    }
}

/// A command acts as a builder interface to creating encoded redis
/// requests.  This allows you to easiy assemble a packed command
/// by chaining arguments together.
///
/// Basic example:
///
/// ```rust
/// redis::Cmd::new().arg("SET").arg("my_key").arg(42i);
/// ```
///
/// There is also a helper function called `cmd` which makes it a
/// tiny bit shorter:
///
/// ```rust
/// redis::cmd("SET").arg("my_key").arg(42i);
/// ```
///
/// Because currently rust's currently does not have an ideal system
/// for lifetimes of temporaries, sometimes you need to hold on to
/// the initially generated command:
///
/// ```rust
/// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// # let con = client.get_connection().unwrap();
/// let mut cmd = redis::cmd("SMEMBERS");
/// let mut iter : redis::Iter<i32> = cmd.arg("my_set").iter(&con).unwrap();
/// ```
impl Cmd {
    /// Creates a new empty command.
    pub fn new() -> Cmd {
        Cmd { args: vec![], cursor: None }
    }

    /// Appends an argument to the command.  The argument passed must
    /// be a type that implements `ToRedisArgs`.  Most primitive types as
    /// well as vectors of primitive types implement it.
    ///
    /// For instance all of the following are valid:
    ///
    /// ```rust,no_run
    /// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    /// # let con = client.get_connection().unwrap();
    /// redis::cmd("SET").arg(["my_key", "my_value"][]);
    /// redis::cmd("SET").arg("my_key").arg(42i);
    /// redis::cmd("SET").arg("my_key").arg(b"my_value");
    /// ```
    pub fn arg<T: ToRedisArgs>(&mut self, arg: T) -> &mut Cmd {
        for item in arg.to_redis_args().into_iter() {
            self.args.push(SimpleArg(item));
        }
        self
    }

    /// Works similar to `arg` but adds a cursor argument.  This is always
    /// an integer and also flips the command implementation to support a
    /// different mode for the iterators where the iterator will ask for
    /// another batch of items when the local data is exhausted.
    ///
    /// ```rust,no_run
    /// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    /// # let con = client.get_connection().unwrap();
    /// let mut cmd = redis::cmd("SSCAN");
    /// let mut iter : redis::Iter<int> = cmd.arg("my_set").cursor_arg(0).iter(&con).unwrap();
    /// for x in iter {
    ///     // do something with the item
    /// }
    /// ```
    pub fn cursor_arg(&mut self, cursor: u64) -> &mut Cmd {
        assert!(!self.in_scan_mode());
        self.cursor = Some(cursor);
        self.args.push(CursorArg);
        self
    }

    /// Returns the packed command as a byte vector.
    pub fn get_packed_command(&self) -> Vec<u8> {
        encode_command(&self.args, self.cursor.unwrap_or(0))
    }

    /// Like `get_packed_command` but replaces the cursor with the
    /// provided value.  If the command is not in scan mode, `None`
    /// is returned.
    fn get_packed_command_with_cursor(&self, cursor: u64) -> Option<Vec<u8>> {
        if !self.in_scan_mode() {
            None
        } else {
            Some(encode_command(&self.args, cursor))
        }
    }

    /// Returns true if the command is in scan mode.
    pub fn in_scan_mode(&self) -> bool {
        self.cursor.is_some()
    }

    /// Sends the command as query to the connection and converts the
    /// result to the target redis value.  This is the general way how
    /// you can retrieve data.
    pub fn query<T: FromRedisValue>(&self, con: &Connection) -> RedisResult<T> {
        let pcmd = self.get_packed_command();
        match con.send_packed_command(pcmd.as_slice()) {
            Ok(val) => FromRedisValue::from_redis_value(&val),
            Err(e) => Err(e),
        }
    }

    /// Similar to `query()` but returns an iterator over the items of the
    /// bulk result or iterator.  In normal mode this is not in any way more
    /// efficient than just querying into a `Vec<T>` as it's internally
    /// implemented as buffering into a vector.  This however is useful when
    /// `cursor_arg` was used in which case the iterator will query for more
    /// items until the server side cursor is exhausted.
    ///
    /// This is useful for commands such as `SSCAN`, `SCAN` and others.
    ///
    /// One speciality of this function is that it will check if the response
    /// looks like a cursor or not and always just looks at the payload.
    /// This way you can use the function the same for responses in the
    /// format of `KEYS` (just a list) as well as `SSCAN` (which returns a
    /// tuple of cursor and list).
    pub fn iter<'a, T: FromRedisValue>(&'a mut self, con: &'a Connection)
            -> RedisResult<Iter<'a, T>> {
        let pcmd = self.get_packed_command();
        let rv = try!(con.send_packed_command(pcmd.as_slice()));
        let mut batch : Vec<T>;
        let mut cursor = 0;

        if rv.looks_like_cursor() {
            let (next, b) : (u64, Vec<T>) = try!(FromRedisValue::from_redis_value(&rv));
            batch = b;
            cursor = next;
        } else {
            batch = try!(FromRedisValue::from_redis_value(&rv));
        }

        batch.reverse();
        Ok(Iter {
            batch: batch,
            cursor: cursor,
            con: con,
            cmd: self
        })
    }

    /// This is a shortcut to `query()` that does not return a value and
    /// will fail the task if the query fails because of an error.  This is
    /// mainly useful in examples and for simple commands like setting
    /// keys.
    ///
    /// This is equivalent to a call of query like this:
    ///
    /// ```rust,no_run
    /// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    /// # let con = client.get_connection().unwrap();
    /// let _ : () = redis::cmd("PING").query(&con).unwrap();
    /// ```
    pub fn execute(&self, con: &Connection) {
        let _ : () = self.query(con).unwrap();
    }
}

/// Shortcut function to creating a command with a single argument.
///
/// The first argument of a redis command is always the name of the command
/// which needs to be a string.  This is the recommended way to start a
/// command pipe.
///
/// ```rust
/// redis::cmd("PING");
/// ```
pub fn cmd(name: &'static str) -> Cmd {
    let mut rv = Cmd::new();
    rv.arg(name);
    rv
}
<commit_msg>Marked a test as no_run<commit_after>use types::{ToRedisArgs, FromRedisValue, RedisResult};
use connection::Connection;

enum Arg {
    SimpleArg(Vec<u8>),
    CursorArg,
}

fn encode_command(args: &Vec<Arg>, cursor: u64) -> Vec<u8> {
    let mut cmd = vec![];
    cmd.push_all(format!("*{}\r\n", args.len()).as_bytes());

    {
        let encode = |item: &[u8]| {
            cmd.push_all(format!("${}\r\n", item.len()).as_bytes());
            cmd.push_all(item);
            cmd.push_all(b"\r\n");
        };

        for item in args.iter() {
            match *item {
                CursorArg => encode(cursor.to_string().as_bytes()),
                SimpleArg(ref val) => encode(val[]),
            }
        }
    }

    cmd
}

/// Represents redis commands.
pub struct Cmd {
    args: Vec<Arg>,
    cursor: Option<u64>,
}

/// Represents a redis iterator.
pub struct Iter<'a, T: FromRedisValue> {
    batch: Vec<T>,
    cursor: u64,
    con: &'a Connection,
    cmd: &'a Cmd,
}

impl<'a, T: FromRedisValue> Iterator<T> for Iter<'a, T> {

    #[inline]
    fn next(&mut self) -> Option<T> {
        match self.batch.pop() {
            Some(v) => { return Some(v); }
            None => {}
        };
        if self.cursor == 0 {
            return None;
        }

        let pcmd = unwrap_or!(self.cmd.get_packed_command_with_cursor(
            self.cursor), return None);
        let rv = unwrap_or!(self.con.send_packed_command(
            pcmd[]).ok(), return None);
        let (cur, mut batch) : (u64, Vec<T>) = unwrap_or!(
            FromRedisValue::from_redis_value(&rv).ok(), return None);
        batch.reverse();

        self.cursor = cur;
        self.batch = batch;
        self.batch.pop()
    }
}

/// A command acts as a builder interface to creating encoded redis
/// requests.  This allows you to easiy assemble a packed command
/// by chaining arguments together.
///
/// Basic example:
///
/// ```rust
/// redis::Cmd::new().arg("SET").arg("my_key").arg(42i);
/// ```
///
/// There is also a helper function called `cmd` which makes it a
/// tiny bit shorter:
///
/// ```rust
/// redis::cmd("SET").arg("my_key").arg(42i);
/// ```
///
/// Because currently rust's currently does not have an ideal system
/// for lifetimes of temporaries, sometimes you need to hold on to
/// the initially generated command:
///
/// ```rust,no_run
/// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// # let con = client.get_connection().unwrap();
/// let mut cmd = redis::cmd("SMEMBERS");
/// let mut iter : redis::Iter<i32> = cmd.arg("my_set").iter(&con).unwrap();
/// ```
impl Cmd {
    /// Creates a new empty command.
    pub fn new() -> Cmd {
        Cmd { args: vec![], cursor: None }
    }

    /// Appends an argument to the command.  The argument passed must
    /// be a type that implements `ToRedisArgs`.  Most primitive types as
    /// well as vectors of primitive types implement it.
    ///
    /// For instance all of the following are valid:
    ///
    /// ```rust,no_run
    /// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    /// # let con = client.get_connection().unwrap();
    /// redis::cmd("SET").arg(["my_key", "my_value"][]);
    /// redis::cmd("SET").arg("my_key").arg(42i);
    /// redis::cmd("SET").arg("my_key").arg(b"my_value");
    /// ```
    pub fn arg<T: ToRedisArgs>(&mut self, arg: T) -> &mut Cmd {
        for item in arg.to_redis_args().into_iter() {
            self.args.push(SimpleArg(item));
        }
        self
    }

    /// Works similar to `arg` but adds a cursor argument.  This is always
    /// an integer and also flips the command implementation to support a
    /// different mode for the iterators where the iterator will ask for
    /// another batch of items when the local data is exhausted.
    ///
    /// ```rust,no_run
    /// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    /// # let con = client.get_connection().unwrap();
    /// let mut cmd = redis::cmd("SSCAN");
    /// let mut iter : redis::Iter<int> = cmd.arg("my_set").cursor_arg(0).iter(&con).unwrap();
    /// for x in iter {
    ///     // do something with the item
    /// }
    /// ```
    pub fn cursor_arg(&mut self, cursor: u64) -> &mut Cmd {
        assert!(!self.in_scan_mode());
        self.cursor = Some(cursor);
        self.args.push(CursorArg);
        self
    }

    /// Returns the packed command as a byte vector.
    pub fn get_packed_command(&self) -> Vec<u8> {
        encode_command(&self.args, self.cursor.unwrap_or(0))
    }

    /// Like `get_packed_command` but replaces the cursor with the
    /// provided value.  If the command is not in scan mode, `None`
    /// is returned.
    fn get_packed_command_with_cursor(&self, cursor: u64) -> Option<Vec<u8>> {
        if !self.in_scan_mode() {
            None
        } else {
            Some(encode_command(&self.args, cursor))
        }
    }

    /// Returns true if the command is in scan mode.
    pub fn in_scan_mode(&self) -> bool {
        self.cursor.is_some()
    }

    /// Sends the command as query to the connection and converts the
    /// result to the target redis value.  This is the general way how
    /// you can retrieve data.
    pub fn query<T: FromRedisValue>(&self, con: &Connection) -> RedisResult<T> {
        let pcmd = self.get_packed_command();
        match con.send_packed_command(pcmd.as_slice()) {
            Ok(val) => FromRedisValue::from_redis_value(&val),
            Err(e) => Err(e),
        }
    }

    /// Similar to `query()` but returns an iterator over the items of the
    /// bulk result or iterator.  In normal mode this is not in any way more
    /// efficient than just querying into a `Vec<T>` as it's internally
    /// implemented as buffering into a vector.  This however is useful when
    /// `cursor_arg` was used in which case the iterator will query for more
    /// items until the server side cursor is exhausted.
    ///
    /// This is useful for commands such as `SSCAN`, `SCAN` and others.
    ///
    /// One speciality of this function is that it will check if the response
    /// looks like a cursor or not and always just looks at the payload.
    /// This way you can use the function the same for responses in the
    /// format of `KEYS` (just a list) as well as `SSCAN` (which returns a
    /// tuple of cursor and list).
    pub fn iter<'a, T: FromRedisValue>(&'a mut self, con: &'a Connection)
            -> RedisResult<Iter<'a, T>> {
        let pcmd = self.get_packed_command();
        let rv = try!(con.send_packed_command(pcmd.as_slice()));
        let mut batch : Vec<T>;
        let mut cursor = 0;

        if rv.looks_like_cursor() {
            let (next, b) : (u64, Vec<T>) = try!(FromRedisValue::from_redis_value(&rv));
            batch = b;
            cursor = next;
        } else {
            batch = try!(FromRedisValue::from_redis_value(&rv));
        }

        batch.reverse();
        Ok(Iter {
            batch: batch,
            cursor: cursor,
            con: con,
            cmd: self
        })
    }

    /// This is a shortcut to `query()` that does not return a value and
    /// will fail the task if the query fails because of an error.  This is
    /// mainly useful in examples and for simple commands like setting
    /// keys.
    ///
    /// This is equivalent to a call of query like this:
    ///
    /// ```rust,no_run
    /// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    /// # let con = client.get_connection().unwrap();
    /// let _ : () = redis::cmd("PING").query(&con).unwrap();
    /// ```
    pub fn execute(&self, con: &Connection) {
        let _ : () = self.query(con).unwrap();
    }
}

/// Shortcut function to creating a command with a single argument.
///
/// The first argument of a redis command is always the name of the command
/// which needs to be a string.  This is the recommended way to start a
/// command pipe.
///
/// ```rust
/// redis::cmd("PING");
/// ```
pub fn cmd(name: &'static str) -> Cmd {
    let mut rv = Cmd::new();
    rv.arg(name);
    rv
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod sip;

use std::hash::{Hash, Hasher};
use std::default::Default;

struct MyHasher {
    hash: u64,
}

impl Default for MyHasher {
    fn default() -> MyHasher {
        MyHasher { hash: 0 }
    }
}

impl Hasher for MyHasher {
    fn write(&mut self, buf: &[u8]) {
        for byte in buf {
            self.hash += *byte as u64;
        }
    }
    fn finish(&self) -> u64 { self.hash }
}

#[test]
fn test_writer_hasher() {
    fn hash<T: Hash>(t: &T) -> u64 {
        let mut s = MyHasher { hash: 0 };
        t.hash(&mut s);
        s.finish()
    }

    assert_eq!(hash(&()), 0);

    assert_eq!(hash(&5_u8), 5);
    assert_eq!(hash(&5_u16), 5);
    assert_eq!(hash(&5_u32), 5);
    assert_eq!(hash(&5_u64), 5);
    assert_eq!(hash(&5_usize), 5);

    assert_eq!(hash(&5_i8), 5);
    assert_eq!(hash(&5_i16), 5);
    assert_eq!(hash(&5_i32), 5);
    assert_eq!(hash(&5_i64), 5);
    assert_eq!(hash(&5_isize), 5);

    assert_eq!(hash(&false), 0);
    assert_eq!(hash(&true), 1);

    assert_eq!(hash(&'a'), 97);

    let s: &str = "a";
    assert_eq!(hash(& s), 97 + 0xFF);
    // FIXME (#18283) Enable test
    //let s: Box<str> = box "a";
    //assert_eq!(hasher.hash(& s), 97 + 0xFF);
    let cs: &[u8] = &[1, 2, 3];
    assert_eq!(hash(& cs), 9);
    // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
    let cs: Box<[u8]> = Box::new([1, 2, 3]);
    assert_eq!(hash(& cs), 9);

    // FIXME (#18248) Add tests for hashing Rc<str> and Rc<[T]>

    let ptr = 5_usize as *const i32;
    assert_eq!(hash(&ptr), 5);

    let ptr = 5_usize as *mut i32;
    assert_eq!(hash(&ptr), 5);
}

struct Custom { hash: u64 }
struct CustomHasher { output: u64 }

impl Hasher for CustomHasher {
    fn finish(&self) -> u64 { self.output }
    fn write(&mut self, _: &[u8]) { panic!() }
    fn write_u64(&mut self, data: u64) { self.output = data; }
}

impl Default for CustomHasher {
    fn default() -> CustomHasher {
        CustomHasher { output: 0 }
    }
}

impl Hash for Custom {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u64(self.hash);
    }
}

#[test]
fn test_custom_state() {
    fn hash<T: Hash>(t: &T) -> u64 {
        let mut c = CustomHasher { output: 0 };
        t.hash(&mut c);
        c.finish()
    }

    assert_eq!(hash(&Custom { hash: 5 }), 5);
}
<commit_msg>Rollup merge of #39251 - wesleywiser:fixme_1, r=BurntSushi<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

mod sip;

use std::hash::{Hash, Hasher};
use std::default::Default;

struct MyHasher {
    hash: u64,
}

impl Default for MyHasher {
    fn default() -> MyHasher {
        MyHasher { hash: 0 }
    }
}

impl Hasher for MyHasher {
    fn write(&mut self, buf: &[u8]) {
        for byte in buf {
            self.hash += *byte as u64;
        }
    }
    fn finish(&self) -> u64 { self.hash }
}

#[test]
fn test_writer_hasher() {
    fn hash<T: Hash>(t: &T) -> u64 {
        let mut s = MyHasher { hash: 0 };
        t.hash(&mut s);
        s.finish()
    }

    assert_eq!(hash(&()), 0);

    assert_eq!(hash(&5_u8), 5);
    assert_eq!(hash(&5_u16), 5);
    assert_eq!(hash(&5_u32), 5);
    assert_eq!(hash(&5_u64), 5);
    assert_eq!(hash(&5_usize), 5);

    assert_eq!(hash(&5_i8), 5);
    assert_eq!(hash(&5_i16), 5);
    assert_eq!(hash(&5_i32), 5);
    assert_eq!(hash(&5_i64), 5);
    assert_eq!(hash(&5_isize), 5);

    assert_eq!(hash(&false), 0);
    assert_eq!(hash(&true), 1);

    assert_eq!(hash(&'a'), 97);

    let s: &str = "a";
    assert_eq!(hash(& s), 97 + 0xFF);
    let s: Box<str> = String::from("a").into_boxed_str();
    assert_eq!(hash(& s), 97 + 0xFF);
    let cs: &[u8] = &[1, 2, 3];
    assert_eq!(hash(& cs), 9);
    // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
    let cs: Box<[u8]> = Box::new([1, 2, 3]);
    assert_eq!(hash(& cs), 9);

    // FIXME (#18248) Add tests for hashing Rc<str> and Rc<[T]>

    let ptr = 5_usize as *const i32;
    assert_eq!(hash(&ptr), 5);

    let ptr = 5_usize as *mut i32;
    assert_eq!(hash(&ptr), 5);
}

struct Custom { hash: u64 }
struct CustomHasher { output: u64 }

impl Hasher for CustomHasher {
    fn finish(&self) -> u64 { self.output }
    fn write(&mut self, _: &[u8]) { panic!() }
    fn write_u64(&mut self, data: u64) { self.output = data; }
}

impl Default for CustomHasher {
    fn default() -> CustomHasher {
        CustomHasher { output: 0 }
    }
}

impl Hash for Custom {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u64(self.hash);
    }
}

#[test]
fn test_custom_state() {
    fn hash<T: Hash>(t: &T) -> u64 {
        let mut c = CustomHasher { output: 0 };
        t.hash(&mut c);
        c.finish()
    }

    assert_eq!(hash(&Custom { hash: 5 }), 5);
}
<|endoftext|>


<commit_before>use super::{BaseNum, PartialOrd};
use std::ops::{Div, Mul};

/// A two-dimensional dimension.
pub struct Dimension2<T> {
    pub width: T,
    pub height: T,
}

pub type Dimension2f = Dimension2<super::DefaultFloat>;
pub type Dimension2i = Dimension2<super::DefaultInt>;
pub type Dimension2u = Dimension2<super::DefaultUnsigned>;

impl<T: BaseNum> Dimension2<T> {
    pub fn new(width: T, height: T) -> Self {
        Dimension2 {
            width: width,
            height: height,
        }
    }

    pub fn area(&self) -> <T as Mul>::Output {
        self.width * self.height
    }
    pub fn scale(&self, scale: T) -> Dimension2<T> {
        Dimension2 {
            width: self.width * scale,
            height: self.height * scale,
        }
    }
    pub fn aspect_ratio(&self) -> <T as Div>::Output {
        //     assert!(self.height != 0);
        self.width / self.height
    }
    pub fn fitting(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_min(other.width / self.width, other.height / self.height);
        self.scale(scale)

    }
    pub fn filling(&self, other: Dimension2<T>) -> Dimension<T>
}
<commit_msg>added a few tests<commit_after>

use super::{BaseNum, PartialOrd};
use std::ops::{Div, Mul};
use num_traits::Zero;

/// A two-dimensional dimension.
pub struct Dimension2<T> {
    pub width: T,
    pub height: T,
}

pub type Dimension2f = Dimension2<super::DefaultFloat>;
pub type Dimension2i = Dimension2<super::DefaultInt>;
pub type Dimension2u = Dimension2<super::DefaultUnsigned>;

impl<T: BaseNum> Dimension2<T> {
    pub fn new(width: T, height: T) -> Self {
        Dimension2 {
            width: width,
            height: height,
        }
    }
    ///
    pub fn area(&self) -> <T as Mul>::Output {
        self.width * self.height
    }
    pub fn scale(&self, scale: T) -> Dimension2<T> {
        Dimension2 {
            width: self.width * scale,
            height: self.height * scale,
        }
    }
    pub fn aspect_ratio(&self) -> <T as Div>::Output {
      //  assert!(!self.height.Zero::is_zero());
        self.width / self.height
    }
    pub fn fitting(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_min(other.width / self.width, other.height / self.height);
        self.scale(scale)

    }
    pub fn filling(&self, other: Dimension2<T>) -> Dimension2<T> {
        let scale = PartialOrd::partial_max(other.width / self.width, other.height / self.height);
        self.scale(scale)
    }
}

#[test]
fn test_area() {
    let test1 = Dimension2(width: 3, height: 5);
    let test2 = Dimension2(width: 0, height: 0);

    assert_eq!(test2.area(), 0);
    assert_eq!(test1.area(), 15);
}
fn test_scale(){
    let test1 = Dimension2(width: 3, height: 5);
    let test2 = Dimension2(width: 0, height: 0);
    let scale = 4;

    test1.scale(scale);

}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use hir::def_id::DefId;
use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
use traits;
use rustc_target::spec::abi::Abi;
use util::ppaux;

use std::fmt;

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct Instance<'tcx> {
    pub def: InstanceDef<'tcx>,
    pub substs: &'tcx Substs<'tcx>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum InstanceDef<'tcx> {
    Item(DefId),
    Intrinsic(DefId),

    /// \<fn() as FnTrait>::call_*
    /// def-id is FnTrait::call_*
    FnPtrShim(DefId, Ty<'tcx>),

    /// <Trait as Trait>::fn
    Virtual(DefId, usize),

    /// <[mut closure] as FnOnce>::call_once
    ClosureOnceShim { call_once: DefId },

    /// drop_in_place::<T>; None for empty drop glue.
    DropGlue(DefId, Option<Ty<'tcx>>),

    ///`<T as Clone>::clone` shim.
    CloneShim(DefId, Ty<'tcx>),
}

impl<'a, 'tcx> Instance<'tcx> {
    pub fn ty(&self,
              tcx: TyCtxt<'a, 'tcx, 'tcx>)
              -> Ty<'tcx>
    {
        let ty = tcx.type_of(self.def.def_id());
        tcx.subst_and_normalize_erasing_regions(
            self.substs,
            ty::ParamEnv::reveal_all(),
            &ty,
        )
    }
}

impl<'tcx> InstanceDef<'tcx> {
    #[inline]
    pub fn def_id(&self) -> DefId {
        match *self {
            InstanceDef::Item(def_id) |
            InstanceDef::FnPtrShim(def_id, _) |
            InstanceDef::Virtual(def_id, _) |
            InstanceDef::Intrinsic(def_id, ) |
            InstanceDef::ClosureOnceShim { call_once: def_id } |
            InstanceDef::DropGlue(def_id, _) |
            InstanceDef::CloneShim(def_id, _) => def_id
        }
    }

    #[inline]
    pub fn attrs<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
        tcx.get_attrs(self.def_id())
    }

    pub fn is_inline<'a>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>
    ) -> bool {
        use hir::map::DefPathData;
        let def_id = match *self {
            ty::InstanceDef::Item(def_id) => def_id,
            ty::InstanceDef::DropGlue(_, Some(_)) => return false,
            _ => return true
        };
        match tcx.def_key(def_id).disambiguated_data.data {
            DefPathData::StructCtor |
            DefPathData::EnumVariant(..) |
            DefPathData::ClosureExpr => true,
            _ => false
        }
    }

    pub fn requires_local<'a>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>
    ) -> bool {
        if self.is_inline(tcx) {
            return true
        }
        if let ty::InstanceDef::DropGlue(..) = *self {
            // Drop glue wants to be instantiated at every codegen
            // unit, but without an #[inline] hint. We should make this
            // available to normal end-users.
            return true
        }
        let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id());
        codegen_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id())
    }
}

impl<'tcx> fmt::Display for Instance<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        ppaux::parameterized(f, self.substs, self.def_id(), &[])?;
        match self.def {
            InstanceDef::Item(_) => Ok(()),
            InstanceDef::Intrinsic(_) => {
                write!(f, " - intrinsic")
            }
            InstanceDef::Virtual(_, num) => {
                write!(f, " - shim(#{})", num)
            }
            InstanceDef::FnPtrShim(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
            InstanceDef::ClosureOnceShim { .. } => {
                write!(f, " - shim")
            }
            InstanceDef::DropGlue(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
            InstanceDef::CloneShim(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
        }
    }
}

impl<'a, 'b, 'tcx> Instance<'tcx> {
    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
               -> Instance<'tcx> {
        assert!(!substs.has_escaping_regions(),
                "substs of instance {:?} not normalized for codegen: {:?}",
                def_id, substs);
        Instance { def: InstanceDef::Item(def_id), substs: substs }
    }

    pub fn mono(tcx: TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> {
        Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id))
    }

    #[inline]
    pub fn def_id(&self) -> DefId {
        self.def.def_id()
    }

    /// Resolve a (def_id, substs) pair to an (optional) instance -- most commonly,
    /// this is used to find the precise code that will run for a trait method invocation,
    /// if known.
    ///
    /// Returns `None` if we cannot resolve `Instance` to a specific instance.
    /// For example, in a context like this,
    ///
    /// ```
    /// fn foo<T: Debug>(t: T) { ... }
    /// ```
    ///
    /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not
    /// know what code ought to run. (Note that this setting is also affected by the
    /// `RevealMode` in the parameter environment.)
    ///
    /// Presuming that coherence and type-check have succeeded, if this method is invoked
    /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
    /// `Some`.
    pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   param_env: ty::ParamEnv<'tcx>,
                   def_id: DefId,
                   substs: &'tcx Substs<'tcx>) -> Option<Instance<'tcx>> {
        debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
        let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
            debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
            let item = tcx.associated_item(def_id);
            resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
        } else {
            let ty = tcx.type_of(def_id);
            let item_type = tcx.subst_and_normalize_erasing_regions(
                substs,
                param_env,
                &ty,
            );

            let def = match item_type.sty {
                ty::FnDef(..) if {
                    let f = item_type.fn_sig(tcx);
                    f.abi() == Abi::RustIntrinsic ||
                        f.abi() == Abi::PlatformIntrinsic
                } =>
                {
                    debug!(" => intrinsic");
                    ty::InstanceDef::Intrinsic(def_id)
                }
                _ => {
                    if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
                        let ty = substs.type_at(0);
                        if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
                            debug!(" => nontrivial drop glue");
                            ty::InstanceDef::DropGlue(def_id, Some(ty))
                        } else {
                            debug!(" => trivial drop glue");
                            ty::InstanceDef::DropGlue(def_id, None)
                        }
                    } else {
                        debug!(" => free item");
                        ty::InstanceDef::Item(def_id)
                    }
                }
            };
            Some(Instance {
                def: def,
                substs: substs
            })
        };
        debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result);
        result
    }

    pub fn resolve_closure(
                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
                    def_id: DefId,
                    substs: ty::ClosureSubsts<'tcx>,
                    requested_kind: ty::ClosureKind)
    -> Instance<'tcx>
    {
        let actual_kind = substs.closure_kind(def_id, tcx);

        match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
            Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
            _ => Instance::new(def_id, substs.substs)
        }
    }
}

fn resolve_associated_item<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    trait_item: &ty::AssociatedItem,
    param_env: ty::ParamEnv<'tcx>,
    trait_id: DefId,
    rcvr_substs: &'tcx Substs<'tcx>,
) -> Option<Instance<'tcx>> {
    let def_id = trait_item.def_id;
    debug!("resolve_associated_item(trait_item={:?}, \
                                    trait_id={:?}, \
           rcvr_substs={:?})",
           def_id, trait_id, rcvr_substs);

    let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
    let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)));

    // Now that we know which impl is being used, we can dispatch to
    // the actual function:
    match vtbl {
        traits::VtableImpl(impl_data) => {
            let (def_id, substs) = traits::find_associated_item(
                tcx, trait_item, rcvr_substs, &impl_data);
            let substs = tcx.erase_regions(&substs);
            Some(ty::Instance::new(def_id, substs))
        }
        traits::VtableGenerator(generator_data) => {
            Some(Instance {
                def: ty::InstanceDef::Item(generator_data.generator_def_id),
                substs: generator_data.substs.substs
            })
        }
        traits::VtableClosure(closure_data) => {
            let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap();
            Some(Instance::resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs,
                                 trait_closure_kind))
        }
        traits::VtableFnPointer(ref data) => {
            Some(Instance {
                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
                substs: rcvr_substs
            })
        }
        traits::VtableObject(ref data) => {
            let index = tcx.get_vtable_index_of_object_method(data, def_id);
            Some(Instance {
                def: ty::InstanceDef::Virtual(def_id, index),
                substs: rcvr_substs
            })
        }
        traits::VtableBuiltin(..) => {
            if tcx.lang_items().clone_trait().is_some() {
                Some(Instance {
                    def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
                    substs: rcvr_substs
                })
            } else {
                None
            }
        }
        traits::VtableAutoImpl(..) | traits::VtableParam(..) => None
    }
}

fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind,
                              trait_closure_kind: ty::ClosureKind)
    -> Result<bool, ()>
{
    match (actual_closure_kind, trait_closure_kind) {
        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
            (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
            (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
                // No adapter needed.
                Ok(false)
            }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
            // `fn(&mut self, ...)`. In fact, at codegen time, these are
            // basically the same thing, so we can just return llfn.
            Ok(false)
        }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
            (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
                // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
                // self, ...)`.  We want a `fn(self, ...)`. We can produce
                // this by doing something like:
                //
                //     fn call_once(self, ...) { call_mut(&self, ...) }
                //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
                //
                // These are both the same at codegen time.
                Ok(true)
        }
        (ty::ClosureKind::FnMut, _) |
        (ty::ClosureKind::FnOnce, _) => Err(())
    }
}

fn fn_once_adapter_instance<'a, 'tcx>(
                            tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            closure_did: DefId,
                            substs: ty::ClosureSubsts<'tcx>,
                            ) -> Instance<'tcx> {
    debug!("fn_once_adapter_shim({:?}, {:?})",
    closure_did,
    substs);
    let fn_once = tcx.lang_items().fn_once_trait().unwrap();
    let call_once = tcx.associated_items(fn_once)
        .find(|it| it.kind == ty::AssociatedKind::Method)
        .unwrap().def_id;
    let def = ty::InstanceDef::ClosureOnceShim { call_once };

    let self_ty = tcx.mk_closure(closure_did, substs);

    let sig = substs.closure_sig(closure_did, tcx);
    let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
    assert_eq!(sig.inputs().len(), 1);
    let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);

    debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
    Instance { def, substs }
}
<commit_msg>Poke in the dark and see if bors+windows stops screaming<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use hir::def_id::DefId;
use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
use traits;
use rustc_target::spec::abi::Abi;
use util::ppaux;

use std::fmt;

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct Instance<'tcx> {
    pub def: InstanceDef<'tcx>,
    pub substs: &'tcx Substs<'tcx>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum InstanceDef<'tcx> {
    Item(DefId),
    Intrinsic(DefId),

    /// \<fn() as FnTrait>::call_*
    /// def-id is FnTrait::call_*
    FnPtrShim(DefId, Ty<'tcx>),

    /// <Trait as Trait>::fn
    Virtual(DefId, usize),

    /// <[mut closure] as FnOnce>::call_once
    ClosureOnceShim { call_once: DefId },

    /// drop_in_place::<T>; None for empty drop glue.
    DropGlue(DefId, Option<Ty<'tcx>>),

    ///`<T as Clone>::clone` shim.
    CloneShim(DefId, Ty<'tcx>),
}

impl<'a, 'tcx> Instance<'tcx> {
    pub fn ty(&self,
              tcx: TyCtxt<'a, 'tcx, 'tcx>)
              -> Ty<'tcx>
    {
        let ty = tcx.type_of(self.def.def_id());
        tcx.subst_and_normalize_erasing_regions(
            self.substs,
            ty::ParamEnv::reveal_all(),
            &ty,
        )
    }
}

impl<'tcx> InstanceDef<'tcx> {
    #[inline]
    pub fn def_id(&self) -> DefId {
        match *self {
            InstanceDef::Item(def_id) |
            InstanceDef::FnPtrShim(def_id, _) |
            InstanceDef::Virtual(def_id, _) |
            InstanceDef::Intrinsic(def_id, ) |
            InstanceDef::ClosureOnceShim { call_once: def_id } |
            InstanceDef::DropGlue(def_id, _) |
            InstanceDef::CloneShim(def_id, _) => def_id
        }
    }

    #[inline]
    pub fn attrs<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
        tcx.get_attrs(self.def_id())
    }

    pub fn is_inline<'a>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>
    ) -> bool {
        use hir::map::DefPathData;
        let def_id = match *self {
            ty::InstanceDef::Item(def_id) => def_id,
            ty::InstanceDef::DropGlue(_, Some(_)) => return false,
            _ => return true
        };
        match tcx.def_key(def_id).disambiguated_data.data {
            DefPathData::StructCtor |
            DefPathData::EnumVariant(..) |
            DefPathData::ClosureExpr => true,
            _ => false
        }
    }

    pub fn requires_local<'a>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>
    ) -> bool {
        if self.is_inline(tcx) {
            return true
        }
        if let ty::InstanceDef::DropGlue(..) = *self {
            // Drop glue wants to be instantiated at every codegen
            // unit, but without an #[inline] hint. We should make this
            // available to normal end-users.
            return true
        }
        let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id());
        // need to use `is_const_fn_raw` since we don't really care if the user can use it as a
        // const fn, just whether the function should be inlined
        codegen_fn_attrs.requests_inline() || tcx.is_const_fn_raw(self.def_id())
    }
}

impl<'tcx> fmt::Display for Instance<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        ppaux::parameterized(f, self.substs, self.def_id(), &[])?;
        match self.def {
            InstanceDef::Item(_) => Ok(()),
            InstanceDef::Intrinsic(_) => {
                write!(f, " - intrinsic")
            }
            InstanceDef::Virtual(_, num) => {
                write!(f, " - shim(#{})", num)
            }
            InstanceDef::FnPtrShim(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
            InstanceDef::ClosureOnceShim { .. } => {
                write!(f, " - shim")
            }
            InstanceDef::DropGlue(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
            InstanceDef::CloneShim(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
        }
    }
}

impl<'a, 'b, 'tcx> Instance<'tcx> {
    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
               -> Instance<'tcx> {
        assert!(!substs.has_escaping_regions(),
                "substs of instance {:?} not normalized for codegen: {:?}",
                def_id, substs);
        Instance { def: InstanceDef::Item(def_id), substs: substs }
    }

    pub fn mono(tcx: TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> {
        Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id))
    }

    #[inline]
    pub fn def_id(&self) -> DefId {
        self.def.def_id()
    }

    /// Resolve a (def_id, substs) pair to an (optional) instance -- most commonly,
    /// this is used to find the precise code that will run for a trait method invocation,
    /// if known.
    ///
    /// Returns `None` if we cannot resolve `Instance` to a specific instance.
    /// For example, in a context like this,
    ///
    /// ```
    /// fn foo<T: Debug>(t: T) { ... }
    /// ```
    ///
    /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not
    /// know what code ought to run. (Note that this setting is also affected by the
    /// `RevealMode` in the parameter environment.)
    ///
    /// Presuming that coherence and type-check have succeeded, if this method is invoked
    /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
    /// `Some`.
    pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   param_env: ty::ParamEnv<'tcx>,
                   def_id: DefId,
                   substs: &'tcx Substs<'tcx>) -> Option<Instance<'tcx>> {
        debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
        let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
            debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
            let item = tcx.associated_item(def_id);
            resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
        } else {
            let ty = tcx.type_of(def_id);
            let item_type = tcx.subst_and_normalize_erasing_regions(
                substs,
                param_env,
                &ty,
            );

            let def = match item_type.sty {
                ty::FnDef(..) if {
                    let f = item_type.fn_sig(tcx);
                    f.abi() == Abi::RustIntrinsic ||
                        f.abi() == Abi::PlatformIntrinsic
                } =>
                {
                    debug!(" => intrinsic");
                    ty::InstanceDef::Intrinsic(def_id)
                }
                _ => {
                    if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
                        let ty = substs.type_at(0);
                        if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
                            debug!(" => nontrivial drop glue");
                            ty::InstanceDef::DropGlue(def_id, Some(ty))
                        } else {
                            debug!(" => trivial drop glue");
                            ty::InstanceDef::DropGlue(def_id, None)
                        }
                    } else {
                        debug!(" => free item");
                        ty::InstanceDef::Item(def_id)
                    }
                }
            };
            Some(Instance {
                def: def,
                substs: substs
            })
        };
        debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result);
        result
    }

    pub fn resolve_closure(
                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
                    def_id: DefId,
                    substs: ty::ClosureSubsts<'tcx>,
                    requested_kind: ty::ClosureKind)
    -> Instance<'tcx>
    {
        let actual_kind = substs.closure_kind(def_id, tcx);

        match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
            Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
            _ => Instance::new(def_id, substs.substs)
        }
    }
}

fn resolve_associated_item<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    trait_item: &ty::AssociatedItem,
    param_env: ty::ParamEnv<'tcx>,
    trait_id: DefId,
    rcvr_substs: &'tcx Substs<'tcx>,
) -> Option<Instance<'tcx>> {
    let def_id = trait_item.def_id;
    debug!("resolve_associated_item(trait_item={:?}, \
                                    trait_id={:?}, \
           rcvr_substs={:?})",
           def_id, trait_id, rcvr_substs);

    let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
    let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)));

    // Now that we know which impl is being used, we can dispatch to
    // the actual function:
    match vtbl {
        traits::VtableImpl(impl_data) => {
            let (def_id, substs) = traits::find_associated_item(
                tcx, trait_item, rcvr_substs, &impl_data);
            let substs = tcx.erase_regions(&substs);
            Some(ty::Instance::new(def_id, substs))
        }
        traits::VtableGenerator(generator_data) => {
            Some(Instance {
                def: ty::InstanceDef::Item(generator_data.generator_def_id),
                substs: generator_data.substs.substs
            })
        }
        traits::VtableClosure(closure_data) => {
            let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap();
            Some(Instance::resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs,
                                 trait_closure_kind))
        }
        traits::VtableFnPointer(ref data) => {
            Some(Instance {
                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
                substs: rcvr_substs
            })
        }
        traits::VtableObject(ref data) => {
            let index = tcx.get_vtable_index_of_object_method(data, def_id);
            Some(Instance {
                def: ty::InstanceDef::Virtual(def_id, index),
                substs: rcvr_substs
            })
        }
        traits::VtableBuiltin(..) => {
            if tcx.lang_items().clone_trait().is_some() {
                Some(Instance {
                    def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
                    substs: rcvr_substs
                })
            } else {
                None
            }
        }
        traits::VtableAutoImpl(..) | traits::VtableParam(..) => None
    }
}

fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind,
                              trait_closure_kind: ty::ClosureKind)
    -> Result<bool, ()>
{
    match (actual_closure_kind, trait_closure_kind) {
        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
            (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
            (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
                // No adapter needed.
                Ok(false)
            }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
            // `fn(&mut self, ...)`. In fact, at codegen time, these are
            // basically the same thing, so we can just return llfn.
            Ok(false)
        }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
            (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
                // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
                // self, ...)`.  We want a `fn(self, ...)`. We can produce
                // this by doing something like:
                //
                //     fn call_once(self, ...) { call_mut(&self, ...) }
                //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
                //
                // These are both the same at codegen time.
                Ok(true)
        }
        (ty::ClosureKind::FnMut, _) |
        (ty::ClosureKind::FnOnce, _) => Err(())
    }
}

fn fn_once_adapter_instance<'a, 'tcx>(
                            tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            closure_did: DefId,
                            substs: ty::ClosureSubsts<'tcx>,
                            ) -> Instance<'tcx> {
    debug!("fn_once_adapter_shim({:?}, {:?})",
    closure_did,
    substs);
    let fn_once = tcx.lang_items().fn_once_trait().unwrap();
    let call_once = tcx.associated_items(fn_once)
        .find(|it| it.kind == ty::AssociatedKind::Method)
        .unwrap().def_id;
    let def = ty::InstanceDef::ClosureOnceShim { call_once };

    let self_ty = tcx.mk_closure(closure_did, substs);

    let sig = substs.closure_sig(closure_did, tcx);
    let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
    assert_eq!(sig.inputs().len(), 1);
    let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);

    debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
    Instance { def, substs }
}
<|endoftext|>