<commit_before>#[feature(globs)];
#[feature(struct_variant)];

extern mod allegro5;
extern mod allegro_image;
extern mod extra;

use extra::getopts::groups::*;
use std::os;
use std::default::Default;
use std::c_str::*;
use allegro5::*;
use allegro_image::*;

#[start]
fn start(argc: int, argv: **u8) -> int
{
	allegro5::run(argc, argv, main)
}

fn main()
{
	let args = os::args();

	let opts = ~[
		optflag("i", "init-only", "only initialize Allegro, don't do anything else")
	];

	let matches = match getopts(args.tail(), opts)
	{
		Ok(m) => { m }
		Err(f) => { fail!(f.to_err_msg()) }
	};

	let init_only = matches.opt_present("i");

	let mut core = Core::init().expect("Your Allegro version does not match this Rust binding");
	ImageAddon::init(&core).expect("Failed to initialize the image addon");

	if init_only
	{
		return;
	}

	let disp = core.create_display(800, 600).unwrap();
	disp.set_window_title(&"Rust example".to_c_str());

	core.install_keyboard();
	core.install_mouse();

	let timer = core.create_timer(1.0 / 60.0).unwrap();

	let q = core.create_event_queue().unwrap();
	q.register_event_source(disp.get_event_source());
	q.register_event_source(core.get_keyboard_event_source().unwrap());
	q.register_event_source(core.get_mouse_event_source().unwrap());
	q.register_event_source(timer.get_event_source());

	let bmp = core.create_bitmap(256, 256).unwrap();

	let (mon_x1, mon_y1, mon_x2, mon_y2) = core.get_monitor_info(0).unwrap();
	println!("{} {} {} {}", mon_x1, mon_y1, mon_x2, mon_y2);

	bmp.clear_to_color(core.map_rgb_f(0.0, 0.0, 1.0));

	let sub_bmp = bmp.create_sub_bitmap(64, 64, 64, 64).unwrap();
	sub_bmp.clear_to_color(core.map_rgb_f(0.0, 1.0, 1.0));

	let bkg = core.load_bitmap("data/mysha.pcx").unwrap();

	let mut theta = 0.0f32;
	let mut redraw = true;
	timer.start();
	'exit: loop
	{
		if redraw && q.is_empty()
		{
			disp.clear_to_color(core.map_rgb_f(0.0, 0.0, 0.0));
			disp.draw_bitmap(&bkg, 0.0, 0.0, Default::default());
			disp.draw_rotated_bitmap(&bmp, 0.0, 0.0, (disp.get_width() / 2) as f32, (disp.get_height() / 2) as f32, theta, Default::default());
			disp.flip();
			redraw = false;
		}

		match q.wait_for_event()
		{
			DisplayClose{source: src, ..} =>
			{
				assert!(disp.get_event_source().get_event_source() == src)
				println!("Display close event...")
				break 'exit;
			},
			KeyDown{keycode: k, ..} if k == key::Escape =>
			{
				println!("Pressed Escape!");
				break 'exit;
			},
			KeyChar{unichar: c, ..} =>
			{
				println!("Entered a character: {}", c);
			},
			TimerTick{..} =>
			{
				redraw = true;
				theta = theta + 0.01;
			},
			MouseButtonDown{button: b, ..} =>
			{
				println!("Mouse button {} pressed", b);
			},
			_ => println!("Some other event...")
		}
	}
}
<commit_msg>getopts changes<commit_after>#[feature(globs)];
#[feature(struct_variant)];

extern mod allegro5;
extern mod allegro_image;
extern mod getopts;

use getopts::*;
use std::os;
use std::default::Default;
use std::c_str::*;
use allegro5::*;
use allegro_image::*;

#[start]
fn start(argc: int, argv: **u8) -> int
{
	allegro5::run(argc, argv, main)
}

fn main()
{
	let args = os::args();

	let opts = ~[
		optflag("i", "init-only", "only initialize Allegro, don't do anything else")
	];

	let matches = match getopts(args.tail(), opts)
	{
		Ok(m) => { m }
		Err(f) => { fail!(f.to_err_msg()) }
	};

	let init_only = matches.opt_present("i");

	let mut core = Core::init().expect("Your Allegro version does not match this Rust binding");
	ImageAddon::init(&core).expect("Failed to initialize the image addon");

	if init_only
	{
		return;
	}

	let disp = core.create_display(800, 600).unwrap();
	disp.set_window_title(&"Rust example".to_c_str());

	core.install_keyboard();
	core.install_mouse();

	let timer = core.create_timer(1.0 / 60.0).unwrap();

	let q = core.create_event_queue().unwrap();
	q.register_event_source(disp.get_event_source());
	q.register_event_source(core.get_keyboard_event_source().unwrap());
	q.register_event_source(core.get_mouse_event_source().unwrap());
	q.register_event_source(timer.get_event_source());

	let bmp = core.create_bitmap(256, 256).unwrap();

	let (mon_x1, mon_y1, mon_x2, mon_y2) = core.get_monitor_info(0).unwrap();
	println!("{} {} {} {}", mon_x1, mon_y1, mon_x2, mon_y2);

	bmp.clear_to_color(core.map_rgb_f(0.0, 0.0, 1.0));

	let sub_bmp = bmp.create_sub_bitmap(64, 64, 64, 64).unwrap();
	sub_bmp.clear_to_color(core.map_rgb_f(0.0, 1.0, 1.0));

	let bkg = core.load_bitmap("data/mysha.pcx").unwrap();

	let mut theta = 0.0f32;
	let mut redraw = true;
	timer.start();
	'exit: loop
	{
		if redraw && q.is_empty()
		{
			disp.clear_to_color(core.map_rgb_f(0.0, 0.0, 0.0));
			disp.draw_bitmap(&bkg, 0.0, 0.0, Default::default());
			disp.draw_rotated_bitmap(&bmp, 0.0, 0.0, (disp.get_width() / 2) as f32, (disp.get_height() / 2) as f32, theta, Default::default());
			disp.flip();
			redraw = false;
		}

		match q.wait_for_event()
		{
			DisplayClose{source: src, ..} =>
			{
				assert!(disp.get_event_source().get_event_source() == src)
				println!("Display close event...")
				break 'exit;
			},
			KeyDown{keycode: k, ..} if k == key::Escape =>
			{
				println!("Pressed Escape!");
				break 'exit;
			},
			KeyChar{unichar: c, ..} =>
			{
				println!("Entered a character: {}", c);
			},
			TimerTick{..} =>
			{
				redraw = true;
				theta = theta + 0.01;
			},
			MouseButtonDown{button: b, ..} =>
			{
				println!("Mouse button {} pressed", b);
			},
			_ => println!("Some other event...")
		}
	}
}
<|endoftext|>


<commit_before>/* AES ECB cut and paste
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate aes_lib;

use std::rand::random;

use aes_lib::{AES_BLOCK_SIZE, decrypt_aes_ecb, encrypt_aes_ecb};

struct Profile {
    key: Vec<u8>,
}

impl Profile {
    fn new() -> Profile {
        let key = random_bytes(AES_BLOCK_SIZE);
        Profile{key: key}
    }

    fn profile_for(&self, email: &str) -> Vec<u8> {
        if email.contains("&") || email.contains("=") {
            fail!("Invalid character in email: {}", email);
        }
        let map = [("email".into_string(), email.to_string()),
                   ("uid".into_string(), "10".into_string()),
                   ("role".into_string(), "user".into_string())];
        let encoded = encode_kv(map);
        encrypt_aes_ecb(encoded.as_slice(), self.key.as_slice())
    }

    fn decrypt(&self, encrypted: &[u8]) -> Vec<(String, String)> {
        let encoded = decrypt_aes_ecb(encrypted, self.key.as_slice());
        parse_kv(encoded.as_slice())
    }

    #[cfg(not(test))]
    fn make_admin_profile(&self) -> Vec<u8> {
        let encrypted = self.profile_for("foooo@bar.com".as_slice());
        let enc_admin = self.profile_for(concat!("f@bar.com.",
            "admin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b").as_slice());
        encrypted.slice_to(32).to_vec()
            + enc_admin.slice(16, 32).to_vec()
    }
}

fn random_bytes(len: uint) -> Vec<u8> {
    Vec::from_fn(len, |_| random::<u8>())
}

fn parse_kv(string: &[u8]) -> Vec<(String, String)> {
    let kv = string.split(|&c| c == b'&');
    kv.map(|kv| {
        let pair: Vec<&[u8]> = kv.split(|&c| c == b'=').collect();
        (String::from_utf8(pair[0].to_vec()).unwrap(),
         String::from_utf8(pair[1].to_vec()).unwrap())
        }).collect()
}

fn encode_kv(map: &[(String, String)]) -> Vec<u8> {
    let mut bytes = Vec::new();
    for item in map.iter() {
        bytes.push_all(item.ref0().clone().into_bytes().as_slice());
        bytes.push(b'=');
        bytes.push_all(item.ref1().clone().into_bytes().as_slice());
        bytes.push(b'&');
    }
    bytes.pop();
    bytes
}

#[cfg(not(test))]
fn main() {
    let profile = Profile::new();
    let encrypted = profile.make_admin_profile();
    println!("Decrypted: {}", profile.decrypt(encrypted.as_slice()));
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use super::{Profile, parse_kv, encode_kv};

    #[test]
    fn test_parse_encode_kv() {
        let map = [("foo".into_string(), "bar".into_string()),
                   ("baz".into_string(), "qux".into_string()),
                   ("zap".into_string(), "zazzle".into_string())];
        let encoded: Vec<u8> = b"foo=bar&baz=qux&zap=zazzle".to_vec();
        assert_eq!(map.to_vec(), parse_kv(encoded.as_slice()));
        assert_eq!(encode_kv(map), encoded);
    }

    #[test]
    fn test_profile() {
        let profile = Profile::new();
        let email = "foo@bar.com";
        let encrypted = profile.profile_for(email.as_slice());
        assert_eq!(profile.decrypt(encrypted.as_slice()),
                   [("email".into_string(), email.into_string()),
                    ("uid".into_string(), "10".into_string()),
                    ("role".into_string(), "user".into_string())].to_vec());
    }
}
<commit_msg>Fix the code<commit_after>/* AES ECB cut and paste
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate aes_lib;

use std::rand::random;

use aes_lib::{AES_BLOCK_SIZE, decrypt_aes_ecb, encrypt_aes_ecb};

struct Profile {
    key: Vec<u8>,
}

impl Profile {
    fn new() -> Profile {
        let key = random_bytes(AES_BLOCK_SIZE);
        Profile{key: key}
    }

    fn profile_for(&self, email: &str) -> Vec<u8> {
        if email.contains("&") || email.contains("=") {
            panic!("Invalid character in email: {}", email);
        }
        let map = [("email".into_string(), email.to_string()),
                   ("uid".into_string(), "10".into_string()),
                   ("role".into_string(), "user".into_string())];
        let encoded = encode_kv(&map);
        encrypt_aes_ecb(encoded.as_slice(), self.key.as_slice())
    }

    fn decrypt(&self, encrypted: &[u8]) -> Vec<(String, String)> {
        let encoded = decrypt_aes_ecb(encrypted, self.key.as_slice());
        parse_kv(encoded.as_slice())
    }

    #[cfg(not(test))]
    fn make_admin_profile(&self) -> Vec<u8> {
        let encrypted = self.profile_for("foooo@bar.com");
        let enc_admin = self.profile_for(concat!("f@bar.com.",
            "admin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"));
        encrypted.slice_to(32).to_vec()
            + enc_admin.slice(16, 32).to_vec()
    }
}

fn random_bytes(len: uint) -> Vec<u8> {
    Vec::from_fn(len, |_| random::<u8>())
}

fn parse_kv(string: &[u8]) -> Vec<(String, String)> {
    let kv = string.split(|&c| c == b'&');
    kv.map(|kv| {
        let pair: Vec<&[u8]> = kv.split(|&c| c == b'=').collect();
        (String::from_utf8(pair[0].to_vec()).unwrap(),
         String::from_utf8(pair[1].to_vec()).unwrap())
        }).collect()
}

fn encode_kv(map: &[(String, String)]) -> Vec<u8> {
    let mut bytes = Vec::new();
    for item in map.iter() {
        bytes.push_all(item.ref0().clone().into_bytes().as_slice());
        bytes.push(b'=');
        bytes.push_all(item.ref1().clone().into_bytes().as_slice());
        bytes.push(b'&');
    }
    // Remove last '&'
    bytes.pop();
    bytes
}

#[cfg(not(test))]
fn main() {
    let profile = Profile::new();
    let encrypted = profile.make_admin_profile();
    println!("Decrypted: {}", profile.decrypt(encrypted.as_slice()));
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use super::{Profile, parse_kv, encode_kv};

    #[test]
    fn test_parse_encode_kv() {
        let map = [("foo".into_string(), "bar".into_string()),
                   ("baz".into_string(), "qux".into_string()),
                   ("zap".into_string(), "zazzle".into_string())];
        let encoded: Vec<u8> = b"foo=bar&baz=qux&zap=zazzle".to_vec();
        assert_eq!(map.to_vec(), parse_kv(encoded.as_slice()));
        assert_eq!(encode_kv(&map), encoded);
    }

    #[test]
    fn test_profile() {
        let profile = Profile::new();
        let email = "foo@bar.com";
        let encrypted = profile.profile_for(email.as_slice());
        assert_eq!(profile.decrypt(encrypted.as_slice()),
                   [("email".into_string(), email.into_string()),
                    ("uid".into_string(), "10".into_string()),
                    ("role".into_string(), "user".into_string())].to_vec());
    }
}
<|endoftext|>


<commit_before>use std::slice;
use { ffi, FtResult, Error };

/// An enumeration type used to describe the format of pixels in a given bitmap. Note that
/// additional formats may be added in the future.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PixelMode {
    /// This value is reserved.
    None,

    /// A monochrome bitmap, using 1 bit per pixel. Note that pixels are
    /// stored in most-significant order (MSB), which means that the left-most
    /// pixel in a byte has value 128.
    Mono,

    /// An 8-bit bitmap, generally used to represent anti-aliased glyph images.
    /// Each pixel is stored in one byte. Note that the number of `gray`
    /// levels is stored in the `num_grays` field of the FT_Bitmap structure
    /// (it generally is 256).
    Gray,

    /// A 2-bit per pixel bitmap, used to represent embedded anti-aliased
    /// bitmaps in font files according to the OpenType specification. We
    /// haven't found a single font using this format, however.
    Gray2,

    /// A 4-bit per pixel bitmap, representing embedded anti-aliased bitmaps in
    /// font files according to the OpenType specification. We haven't found a
    /// single font using this format, however.
    Gray4,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used
    /// for display on LCD displays; the bitmap is three times wider than the
    /// original glyph image. See also FT_RENDER_MODE_LCD.
    Lcd,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used for
    /// display on rotated LCD displays; the bitmap is three times taller than
    /// the original glyph image. See also FT_RENDER_MODE_LCD_V.
    LcdV,

    /// An image with four 8-bit channels per pixel, representing a color image
    /// (such as emoticons) with alpha channel. For each pixel, the format is
    /// BGRA, which means, the blue channel comes first in memory. The color
    /// channels are pre-multiplied and in the sRGB colorspace. For example,
    /// full red at half-translucent opacity will be represented as
    /// `00,00,80,80`, not `00,00,FF,80`. See also FT_LOAD_COLOR.
    Bgra
}

#[allow(missing_copy_implementations)]
pub struct Bitmap {
    raw: *const ffi::FT_Bitmap
}

impl Bitmap {
    pub unsafe fn from_raw(raw: *const ffi::FT_Bitmap) -> Self {
        Bitmap {
            raw: raw
        }
    }

    /// A typeless pointer to the bitmap buffer. This value should be aligned
    /// on 32-bit boundaries in most cases.
    pub fn buffer(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                (*self.raw).buffer,
                (self.pitch().abs() * self.rows()) as usize
            )
        }
    }

    /// The number of pixels in bitmap row.
    pub fn width(&self) -> i32 {
        unsafe {
            (*self.raw).width
        }
    }

    /// The number of bitmap rows.
    pub fn rows(&self) -> i32 {
        unsafe {
            (*self.raw).rows
        }
    }

    pub fn raw(&self) -> &ffi::FT_Bitmap {
        unsafe {
            &*self.raw
        }
    }

    /// The pixel mode, i.e., how pixel bits are stored. See `PixelMode` for
    /// possible values.
    pub fn pixel_mode(&self) -> FtResult<PixelMode> {
        let pixel_mode = unsafe { (*self.raw).pixel_mode } as u32;

        Ok(match pixel_mode {
            ffi::FT_PIXEL_MODE_NONE  => PixelMode::None,
            ffi::FT_PIXEL_MODE_MONO  => PixelMode::Mono,
            ffi::FT_PIXEL_MODE_GRAY  => PixelMode::Gray,
            ffi::FT_PIXEL_MODE_GRAY2 => PixelMode::Gray2,
            ffi::FT_PIXEL_MODE_GRAY4 => PixelMode::Gray4,
            ffi::FT_PIXEL_MODE_LCD   => PixelMode::Lcd,
            ffi::FT_PIXEL_MODE_LCD_V => PixelMode::LcdV,
            ffi::FT_PIXEL_MODE_BGRA  => PixelMode::Bgra,
            _ => return Err(Error::UnexpectedPixelMode)
        })
    }

    /// The pitch's absolute value is the number of bytes taken by one bitmap row, including
    /// padding. However, the pitch is positive when the bitmap has a ‘down’ flow, and negative
    /// when it has an ‘up’ flow. In all cases, the pitch is an offset to add to a bitmap pointer
    /// in order to go down one row.
    ///
    /// Note that ‘padding’ means the alignment of a bitmap to a byte border, and FreeType
    /// functions normally align to the smallest possible integer value.
    /// For the B/W rasterizer, ‘pitch’ is always an even number.
    ///
    /// To change the pitch of a bitmap (say, to make it a multiple of 4), use FT_Bitmap_Convert.
    /// Alternatively, you might use callback functions to directly render to the application's
    /// surface; see the file ‘example2.cpp’ in the tutorial for a demonstration.
    pub fn pitch(&self) -> i32 {
        unsafe {
            (*self.raw).pitch
        }
    }
}
<commit_msg>Handle null bitmap pointer<commit_after>use std::slice;
use { ffi, FtResult, Error };

/// An enumeration type used to describe the format of pixels in a given bitmap. Note that
/// additional formats may be added in the future.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PixelMode {
    /// This value is reserved.
    None,

    /// A monochrome bitmap, using 1 bit per pixel. Note that pixels are
    /// stored in most-significant order (MSB), which means that the left-most
    /// pixel in a byte has value 128.
    Mono,

    /// An 8-bit bitmap, generally used to represent anti-aliased glyph images.
    /// Each pixel is stored in one byte. Note that the number of `gray`
    /// levels is stored in the `num_grays` field of the FT_Bitmap structure
    /// (it generally is 256).
    Gray,

    /// A 2-bit per pixel bitmap, used to represent embedded anti-aliased
    /// bitmaps in font files according to the OpenType specification. We
    /// haven't found a single font using this format, however.
    Gray2,

    /// A 4-bit per pixel bitmap, representing embedded anti-aliased bitmaps in
    /// font files according to the OpenType specification. We haven't found a
    /// single font using this format, however.
    Gray4,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used
    /// for display on LCD displays; the bitmap is three times wider than the
    /// original glyph image. See also FT_RENDER_MODE_LCD.
    Lcd,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used for
    /// display on rotated LCD displays; the bitmap is three times taller than
    /// the original glyph image. See also FT_RENDER_MODE_LCD_V.
    LcdV,

    /// An image with four 8-bit channels per pixel, representing a color image
    /// (such as emoticons) with alpha channel. For each pixel, the format is
    /// BGRA, which means, the blue channel comes first in memory. The color
    /// channels are pre-multiplied and in the sRGB colorspace. For example,
    /// full red at half-translucent opacity will be represented as
    /// `00,00,80,80`, not `00,00,FF,80`. See also FT_LOAD_COLOR.
    Bgra
}

#[allow(missing_copy_implementations)]
pub struct Bitmap {
    raw: *const ffi::FT_Bitmap
}

impl Bitmap {
    pub unsafe fn from_raw(raw: *const ffi::FT_Bitmap) -> Self {
        Bitmap {
            raw: raw
        }
    }

    /// A typeless pointer to the bitmap buffer. This value should be aligned
    /// on 32-bit boundaries in most cases.
    pub fn buffer(&self) -> &[u8] {
        let buffer_size = (self.pitch().abs() * self.rows()) as usize;
        if buffer_size > 0 {
            unsafe {
                slice::from_raw_parts((*self.raw).buffer, buffer_size)
            }
        } else {
            // When buffer_size is 0, the buffer pointer will be null.
            &[]
        }
    }

    /// The number of pixels in bitmap row.
    pub fn width(&self) -> i32 {
        unsafe {
            (*self.raw).width
        }
    }

    /// The number of bitmap rows.
    pub fn rows(&self) -> i32 {
        unsafe {
            (*self.raw).rows
        }
    }

    pub fn raw(&self) -> &ffi::FT_Bitmap {
        unsafe {
            &*self.raw
        }
    }

    /// The pixel mode, i.e., how pixel bits are stored. See `PixelMode` for
    /// possible values.
    pub fn pixel_mode(&self) -> FtResult<PixelMode> {
        let pixel_mode = unsafe { (*self.raw).pixel_mode } as u32;

        Ok(match pixel_mode {
            ffi::FT_PIXEL_MODE_NONE  => PixelMode::None,
            ffi::FT_PIXEL_MODE_MONO  => PixelMode::Mono,
            ffi::FT_PIXEL_MODE_GRAY  => PixelMode::Gray,
            ffi::FT_PIXEL_MODE_GRAY2 => PixelMode::Gray2,
            ffi::FT_PIXEL_MODE_GRAY4 => PixelMode::Gray4,
            ffi::FT_PIXEL_MODE_LCD   => PixelMode::Lcd,
            ffi::FT_PIXEL_MODE_LCD_V => PixelMode::LcdV,
            ffi::FT_PIXEL_MODE_BGRA  => PixelMode::Bgra,
            _ => return Err(Error::UnexpectedPixelMode)
        })
    }

    /// The pitch's absolute value is the number of bytes taken by one bitmap row, including
    /// padding. However, the pitch is positive when the bitmap has a ‘down’ flow, and negative
    /// when it has an ‘up’ flow. In all cases, the pitch is an offset to add to a bitmap pointer
    /// in order to go down one row.
    ///
    /// Note that ‘padding’ means the alignment of a bitmap to a byte border, and FreeType
    /// functions normally align to the smallest possible integer value.
    /// For the B/W rasterizer, ‘pitch’ is always an even number.
    ///
    /// To change the pitch of a bitmap (say, to make it a multiple of 4), use FT_Bitmap_Convert.
    /// Alternatively, you might use callback functions to directly render to the application's
    /// surface; see the file ‘example2.cpp’ in the tutorial for a demonstration.
    pub fn pitch(&self) -> i32 {
        unsafe {
            (*self.raw).pitch
        }
    }
}
<|endoftext|>


<commit_before>use std::env::*;
use std::env;
use std::fs;
use std::fs::File;
use std::path::Path;
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;
use std::ascii::AsciiExt;
use hyper::Client;
use hyper::header::Connection;

extern crate rustc_serialize;
use self::rustc_serialize::json::*;

extern crate chrono;
use self::chrono::*;

#[derive(Clone, Debug)]
pub struct AWSCredentials {
    key: String,
    secret: String,
    token: String,
    expires_at: DateTime<UTC>
}

impl AWSCredentials {
    pub fn new(key:&str, secret:&str, token:&str, expires_at:DateTime<UTC>) -> AWSCredentials {
        AWSCredentials {
            key: key.to_string(),
            secret: secret.to_string(),
            token: token.to_string(),
            expires_at: expires_at,
        }
    }

    pub fn get_aws_access_key_id(&self) -> &str {
    	&self.key
    }

    pub fn get_aws_secret_key(&self) -> &str {
    	&self.secret
    }

    pub fn get_expires_at(&self) -> &DateTime<UTC> {
        &self.expires_at
    }

    pub fn get_token(&self) -> &str {
        &self.token
    }

    fn credentials_are_expired(&self) -> bool {
        println!("Seeing if creds of {:?} are expired compared to {:?}", self.expires_at, UTC::now() + Duration::seconds(20));
        // This is a rough hack to hopefully avoid someone requesting creds then sitting on them
        // before issuing the request:
        if self.expires_at < UTC::now() + Duration::seconds(20) {
            return true;
        }
        return false;
    }
}

// TODO: refactor get_credentials to return std::result
pub trait AWSCredentialsProvider {
    fn new() -> Self;
	fn get_credentials(&mut self) -> &AWSCredentials;
	fn refresh(&mut self);
}

pub struct EnvironmentCredentialsProvider {
    credentials: AWSCredentials
}

impl AWSCredentialsProvider for EnvironmentCredentialsProvider {
    fn new() -> EnvironmentCredentialsProvider {
        return EnvironmentCredentialsProvider {credentials: AWSCredentials{ key: "".to_string(),
            secret: "".to_string(), token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) } };
    }

	fn refresh(&mut self) {
        let env_key = match var("AWS_ACCESS_KEY_ID") {
            Ok(val) => val,
            Err(_) => "".to_string()
        };
        let env_secret = match var("AWS_SECRET_ACCESS_KEY") {
            Ok(val) => val,
            Err(_) => "".to_string()
        };

        self.credentials = AWSCredentials{key: env_key, secret: env_secret,
             token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600)};
	}

	fn get_credentials(&mut self) -> &AWSCredentials {
		return &self.credentials;
	}
}

pub struct FileCredentialsProvider {
    credentials: AWSCredentials
}

impl AWSCredentialsProvider for FileCredentialsProvider {
    fn new() -> FileCredentialsProvider {
        return FileCredentialsProvider {credentials: AWSCredentials{ key: "".to_string(),
            secret: "".to_string(), token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) } };
    }

	fn refresh(&mut self) {
        // Default credentials file location:
        // ~/.aws/credentials (Linux/Mac)
        // %USERPROFILE%\.aws\credentials  (Windows)
        let mut profile_location = String::new();
        match env::home_dir() {
            Some(ref p) => profile_location = p.display().to_string() + "/.aws/credentials",
            None => {
                println!("Couldn't get your home dir.");
                self.credentials = AWSCredentials{ key: "".to_string(), secret: "".to_string(),
                     token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) };
                return;
            }
        }
        let credentials = get_credentials_from_file(profile_location);
        self.credentials = AWSCredentials{ key: credentials.get_aws_access_key_id().to_string(),
            secret: credentials.get_aws_secret_key().to_string(), token: "".to_string(),
            expires_at: UTC::now() + Duration::seconds(600) };
    }

    fn get_credentials(&mut self) -> &AWSCredentials {
		return &self.credentials;
	}
}

// Finds and uses the first "aws_access_key_id" and "aws_secret_access_key" in the file.
fn get_credentials_from_file(file_with_path: String) -> AWSCredentials {
    println!("Looking for credentials file at {}", file_with_path);
    let path = Path::new(&file_with_path);
    let display = path.display();

    let mut found_file = false;

    match fs::metadata(&path) {
        Err(why) => println!("Couldn't get metadata for file: {}", why),
        Ok(metadata) => found_file = metadata.is_file()
    };

    // bail early.  Should be converted to a return type.
    if !found_file {
        return AWSCredentials{ key: "".to_string(), secret: "".to_string(),
             token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) };
    }

    let file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(opened_file) => opened_file,
    };

    let mut access_key = String::new();
    let mut secret_key = String::new();
    let file_lines = BufReader::new(&file);
    for line in file_lines.lines() {
        let unwrapped_line : String = line.unwrap();
        if unwrapped_line.starts_with('#') {
            continue;
        }

        let lower_case_line = unwrapped_line.to_ascii_lowercase().to_string();

        if lower_case_line.contains("aws_access_key_id") {
            if access_key.is_empty() {
                let v: Vec<&str> = unwrapped_line.split("=").collect();
                if v.len() == 0 {
                    access_key = "".to_string();
                } else {
                    access_key = v[1].trim_matches(' ').to_string();
                }
            }
        } else if lower_case_line.contains("aws_secret_access_key") {
            if secret_key.is_empty() {
                let v: Vec<&str> = unwrapped_line.split("=").collect();
                if v.len() == 0 {
                    secret_key = "".to_string();
                } else {
                    secret_key = v[1].trim_matches(' ').to_string();
                }
            }
        }
    }

    return AWSCredentials{ key: access_key.to_string(), secret: secret_key.to_string(),
         token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) };
}

pub struct IAMRoleCredentialsProvider {
    credentials: AWSCredentials
}

impl AWSCredentialsProvider for IAMRoleCredentialsProvider {
    fn new() -> IAMRoleCredentialsProvider {
        return IAMRoleCredentialsProvider {credentials: AWSCredentials{ key: "".to_string(),
        secret: "".to_string(), token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) } };
    }

	fn refresh(&mut self) {
        // for "real" use: http://169.254.169.254/latest/meta-data/iam/security-credentials/
        let mut address : String = "http://169.254.169.254/latest/meta-data/iam/security-credentials".to_string();
        let client = Client::new();
        let mut response;
        match client.get(&address)
            .header(Connection::close()).send() {
                Err(why) => {
                    println!("boo, request failed: {}", why);
                    return;
                }
                Ok(received_response) => response = received_response
            };

        let mut body = String::new();
        match response.read_to_string(&mut body) {
            Err(why) => println!("Had issues with reading response: {}", why),
            Ok(_) => (),
        };

        address.push_str("/");
        address.push_str(&body);
        body = String::new();
        match client.get(&address)
            .header(Connection::close()).send() {
                Err(_) => return,
                Ok(received_response) => response = received_response
            };

        match response.read_to_string(&mut body) {
            Err(why) => println!("Had issues with reading iam role response: {}", why),
            Ok(_) => (),
        };

        let json_object : Json;
        match Json::from_str(&body) {
            Err(why) => {
                println!("Error: {}", why);
                return;
            }
            Ok(val) => json_object = val
        };

        let mut access_key = String::new();
        match json_object.find("AccessKeyId") {
            None => {
                println!("Error finding AccessKeyId");
                return;
            }
            Some(val) => access_key = val.to_string().replace("\"", "")
        };

        let mut secret_key = String::new();
        match json_object.find("SecretAccessKey") {
            None => {
                println!("Error finding SecretAccessKey");
                return;
            }
            Some(val) => secret_key = val.to_string().replace("\"", "")
        };

        let mut expiration = String::new();
        match json_object.find("Expiration") {
            None => {
                println!("Error finding Expiration");
                return;
            }
            Some(val) => expiration = val.to_string().replace("\"", "")
        };

        let mut expiration_time;
        match expiration.parse::<DateTime<UTC>>() {
            Err(why) => panic!("Kabloey on parse: {}", why),
            Ok(val) => expiration_time = val
        };

        let mut token_from_response = String::new();
        match json_object.find("Token") {
            None => {
                println!("Error finding Token");
                return;
            }
            Some(val) => token_from_response = val.to_string().replace("\"", "")
        };

        self.credentials = AWSCredentials{ key: access_key.to_string(),
            secret: secret_key.to_string(),  token: token_from_response.to_string(), expires_at: expiration_time };
    }

    // This seems a bit convoluted: try to reused expired instead of making a new var.
    fn get_credentials(&mut self) -> &AWSCredentials {
        let expired = &self.credentials.credentials_are_expired();
        if *expired {
            println!("Creds are expired, refreshing.");
            &self.refresh();
            let new_expired = &self.credentials.credentials_are_expired();
            if *new_expired {
                panic!("Credentials were expired and couldn't fetch fresh ones.");
            }
        }
		return &self.credentials;
	}
}

pub struct DefaultAWSCredentialsProviderChain {
    credentials: AWSCredentials
}

// Chain the providers:
impl DefaultAWSCredentialsProviderChain {
    pub fn new() -> DefaultAWSCredentialsProviderChain {
        return DefaultAWSCredentialsProviderChain {credentials: AWSCredentials{ key: "".to_string(),
            secret: "".to_string(), token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) } };
    }

    pub fn get_credentials(&mut self) -> &AWSCredentials {
        return &self.credentials;
    }

    // This is getting a bit out of control with nested if/else: should try doing something else for flow control.
    pub fn refresh(&mut self) {
        // fetch creds in order: env, file, IAM
        self.credentials = AWSCredentials{ key: "".to_string(), secret: "".to_string(),
            token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) };

        let mut env_provider = EnvironmentCredentialsProvider::new();
        env_provider.refresh();
        let credentials = env_provider.get_credentials();

        if creds_have_values(credentials) {
            println!("using creds from env: {}, {}", credentials.get_aws_access_key_id(), credentials.get_aws_secret_key());
            self.credentials = AWSCredentials{ key: credentials.get_aws_access_key_id().to_string(),
                secret: credentials.get_aws_secret_key().to_string(), token: "".to_string(),
                expires_at: UTC::now() + Duration::seconds(600) };
            return;
        } else {
            // try the file provider
            let mut file_provider = FileCredentialsProvider::new();
            file_provider.refresh();
            let credentials = file_provider.get_credentials();
            println!("using creds from file: {}, {}", credentials.get_aws_access_key_id(), credentials.get_aws_secret_key());

            if creds_have_values(credentials) {
                self.credentials = AWSCredentials{ key: credentials.get_aws_access_key_id().to_string(),
                    secret: credentials.get_aws_secret_key().to_string(), token: "".to_string(),
                    expires_at: UTC::now() + Duration::seconds(600) };
            } else {
                let mut iam_provider = IAMRoleCredentialsProvider::new();
                iam_provider.refresh();
                let credentials = iam_provider.get_credentials();
                if creds_have_values(credentials) {
                    println!("using creds from IAM: {}, {}, {}", credentials.get_aws_access_key_id(),
                        credentials.get_aws_secret_key(), credentials.get_token());
                    self.credentials = AWSCredentials{ key: credentials.get_aws_access_key_id().to_string(),
                        secret: credentials.get_aws_secret_key().to_string(), token: credentials.get_token().to_string(),
                        expires_at: UTC::now() + Duration::seconds(600) };
                    return;
                } else {
                    // We're out of options
                    panic!("Couldn't find AWS credentials in environment, default credential file location or IAM role.");
                }
            }
        }
    }
}

fn creds_have_values(creds: &AWSCredentials) -> bool {
    if creds.get_aws_access_key_id().len() > 0 && creds.get_aws_secret_key().len() > 0 {
        return true;
    }
    return false;
}
<commit_msg>Removes unneeded variable initialization.  Compiler's right.<commit_after>use std::env::*;
use std::env;
use std::fs;
use std::fs::File;
use std::path::Path;
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;
use std::ascii::AsciiExt;
use hyper::Client;
use hyper::header::Connection;

extern crate rustc_serialize;
use self::rustc_serialize::json::*;

extern crate chrono;
use self::chrono::*;

#[derive(Clone, Debug)]
pub struct AWSCredentials {
    key: String,
    secret: String,
    token: String,
    expires_at: DateTime<UTC>
}

impl AWSCredentials {
    pub fn new(key:&str, secret:&str, token:&str, expires_at:DateTime<UTC>) -> AWSCredentials {
        AWSCredentials {
            key: key.to_string(),
            secret: secret.to_string(),
            token: token.to_string(),
            expires_at: expires_at,
        }
    }

    pub fn get_aws_access_key_id(&self) -> &str {
    	&self.key
    }

    pub fn get_aws_secret_key(&self) -> &str {
    	&self.secret
    }

    pub fn get_expires_at(&self) -> &DateTime<UTC> {
        &self.expires_at
    }

    pub fn get_token(&self) -> &str {
        &self.token
    }

    fn credentials_are_expired(&self) -> bool {
        println!("Seeing if creds of {:?} are expired compared to {:?}", self.expires_at, UTC::now() + Duration::seconds(20));
        // This is a rough hack to hopefully avoid someone requesting creds then sitting on them
        // before issuing the request:
        if self.expires_at < UTC::now() + Duration::seconds(20) {
            return true;
        }
        return false;
    }
}

// TODO: refactor get_credentials to return std::result
pub trait AWSCredentialsProvider {
    fn new() -> Self;
	fn get_credentials(&mut self) -> &AWSCredentials;
	fn refresh(&mut self);
}

pub struct EnvironmentCredentialsProvider {
    credentials: AWSCredentials
}

impl AWSCredentialsProvider for EnvironmentCredentialsProvider {
    fn new() -> EnvironmentCredentialsProvider {
        return EnvironmentCredentialsProvider {credentials: AWSCredentials{ key: "".to_string(),
            secret: "".to_string(), token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) } };
    }

	fn refresh(&mut self) {
        let env_key = match var("AWS_ACCESS_KEY_ID") {
            Ok(val) => val,
            Err(_) => "".to_string()
        };
        let env_secret = match var("AWS_SECRET_ACCESS_KEY") {
            Ok(val) => val,
            Err(_) => "".to_string()
        };

        self.credentials = AWSCredentials{key: env_key, secret: env_secret,
             token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600)};
	}

	fn get_credentials(&mut self) -> &AWSCredentials {
		return &self.credentials;
	}
}

pub struct FileCredentialsProvider {
    credentials: AWSCredentials
}

impl AWSCredentialsProvider for FileCredentialsProvider {
    fn new() -> FileCredentialsProvider {
        return FileCredentialsProvider {credentials: AWSCredentials{ key: "".to_string(),
            secret: "".to_string(), token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) } };
    }

	fn refresh(&mut self) {
        // Default credentials file location:
        // ~/.aws/credentials (Linux/Mac)
        // %USERPROFILE%\.aws\credentials  (Windows)
        let mut profile_location;
        match env::home_dir() {
            Some(ref p) => profile_location = p.display().to_string() + "/.aws/credentials",
            None => {
                println!("Couldn't get your home dir.");
                self.credentials = AWSCredentials{ key: "".to_string(), secret: "".to_string(),
                     token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) };
                return;
            }
        }
        let credentials = get_credentials_from_file(profile_location);
        self.credentials = AWSCredentials{ key: credentials.get_aws_access_key_id().to_string(),
            secret: credentials.get_aws_secret_key().to_string(), token: "".to_string(),
            expires_at: UTC::now() + Duration::seconds(600) };
    }

    fn get_credentials(&mut self) -> &AWSCredentials {
		return &self.credentials;
	}
}

// Finds and uses the first "aws_access_key_id" and "aws_secret_access_key" in the file.
fn get_credentials_from_file(file_with_path: String) -> AWSCredentials {
    println!("Looking for credentials file at {}", file_with_path);
    let path = Path::new(&file_with_path);
    let display = path.display();

    let mut found_file = false;

    match fs::metadata(&path) {
        Err(why) => println!("Couldn't get metadata for file: {}", why),
        Ok(metadata) => found_file = metadata.is_file()
    };

    // bail early.  Should be converted to a return type.
    if !found_file {
        return AWSCredentials{ key: "".to_string(), secret: "".to_string(),
             token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) };
    }

    let file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(opened_file) => opened_file,
    };

    let mut access_key = String::new();
    let mut secret_key = String::new();
    let file_lines = BufReader::new(&file);
    for line in file_lines.lines() {
        let unwrapped_line : String = line.unwrap();
        if unwrapped_line.starts_with('#') {
            continue;
        }

        let lower_case_line = unwrapped_line.to_ascii_lowercase().to_string();

        if lower_case_line.contains("aws_access_key_id") {
            if access_key.is_empty() {
                let v: Vec<&str> = unwrapped_line.split("=").collect();
                if v.len() == 0 {
                    access_key = "".to_string();
                } else {
                    access_key = v[1].trim_matches(' ').to_string();
                }
            }
        } else if lower_case_line.contains("aws_secret_access_key") {
            if secret_key.is_empty() {
                let v: Vec<&str> = unwrapped_line.split("=").collect();
                if v.len() == 0 {
                    secret_key = "".to_string();
                } else {
                    secret_key = v[1].trim_matches(' ').to_string();
                }
            }
        }
    }

    return AWSCredentials{ key: access_key.to_string(), secret: secret_key.to_string(),
         token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) };
}

pub struct IAMRoleCredentialsProvider {
    credentials: AWSCredentials
}

impl AWSCredentialsProvider for IAMRoleCredentialsProvider {
    fn new() -> IAMRoleCredentialsProvider {
        return IAMRoleCredentialsProvider {credentials: AWSCredentials{ key: "".to_string(),
        secret: "".to_string(), token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) } };
    }

	fn refresh(&mut self) {
        // for "real" use: http://169.254.169.254/latest/meta-data/iam/security-credentials/
        let mut address : String = "http://169.254.169.254/latest/meta-data/iam/security-credentials".to_string();
        let client = Client::new();
        let mut response;
        match client.get(&address)
            .header(Connection::close()).send() {
                Err(why) => {
                    println!("boo, request failed: {}", why);
                    return;
                }
                Ok(received_response) => response = received_response
            };

        let mut body = String::new();
        match response.read_to_string(&mut body) {
            Err(why) => println!("Had issues with reading response: {}", why),
            Ok(_) => (),
        };

        address.push_str("/");
        address.push_str(&body);
        body = String::new();
        match client.get(&address)
            .header(Connection::close()).send() {
                Err(_) => return,
                Ok(received_response) => response = received_response
            };

        match response.read_to_string(&mut body) {
            Err(why) => println!("Had issues with reading iam role response: {}", why),
            Ok(_) => (),
        };

        let json_object : Json;
        match Json::from_str(&body) {
            Err(why) => {
                println!("Error: {}", why);
                return;
            }
            Ok(val) => json_object = val
        };

        let mut access_key;
        match json_object.find("AccessKeyId") {
            None => {
                println!("Error finding AccessKeyId");
                return;
            }
            Some(val) => access_key = val.to_string().replace("\"", "")
        };

        let mut secret_key;
        match json_object.find("SecretAccessKey") {
            None => {
                println!("Error finding SecretAccessKey");
                return;
            }
            Some(val) => secret_key = val.to_string().replace("\"", "")
        };

        let mut expiration;
        match json_object.find("Expiration") {
            None => {
                println!("Error finding Expiration");
                return;
            }
            Some(val) => expiration = val.to_string().replace("\"", "")
        };

        let mut expiration_time;
        match expiration.parse::<DateTime<UTC>>() {
            Err(why) => panic!("Kabloey on parse: {}", why),
            Ok(val) => expiration_time = val
        };

        let mut token_from_response;
        match json_object.find("Token") {
            None => {
                println!("Error finding Token");
                return;
            }
            Some(val) => token_from_response = val.to_string().replace("\"", "")
        };

        self.credentials = AWSCredentials{ key: access_key.to_string(),
            secret: secret_key.to_string(),  token: token_from_response.to_string(), expires_at: expiration_time };
    }

    // This seems a bit convoluted: try to reused expired instead of making a new var.
    fn get_credentials(&mut self) -> &AWSCredentials {
        let expired = &self.credentials.credentials_are_expired();
        if *expired {
            println!("Creds are expired, refreshing.");
            &self.refresh();
            let new_expired = &self.credentials.credentials_are_expired();
            if *new_expired {
                panic!("Credentials were expired and couldn't fetch fresh ones.");
            }
        }
		return &self.credentials;
	}
}

pub struct DefaultAWSCredentialsProviderChain {
    credentials: AWSCredentials
}

// Chain the providers:
impl DefaultAWSCredentialsProviderChain {
    pub fn new() -> DefaultAWSCredentialsProviderChain {
        return DefaultAWSCredentialsProviderChain {credentials: AWSCredentials{ key: "".to_string(),
            secret: "".to_string(), token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) } };
    }

    pub fn get_credentials(&mut self) -> &AWSCredentials {
        return &self.credentials;
    }

    // This is getting a bit out of control with nested if/else: should try doing something else for flow control.
    pub fn refresh(&mut self) {
        // fetch creds in order: env, file, IAM
        self.credentials = AWSCredentials{ key: "".to_string(), secret: "".to_string(),
            token: "".to_string(), expires_at: UTC::now() + Duration::seconds(600) };

        let mut env_provider = EnvironmentCredentialsProvider::new();
        env_provider.refresh();
        let credentials = env_provider.get_credentials();

        if creds_have_values(credentials) {
            println!("using creds from env: {}, {}", credentials.get_aws_access_key_id(), credentials.get_aws_secret_key());
            self.credentials = AWSCredentials{ key: credentials.get_aws_access_key_id().to_string(),
                secret: credentials.get_aws_secret_key().to_string(), token: "".to_string(),
                expires_at: UTC::now() + Duration::seconds(600) };
            return;
        } else {
            // try the file provider
            let mut file_provider = FileCredentialsProvider::new();
            file_provider.refresh();
            let credentials = file_provider.get_credentials();
            println!("using creds from file: {}, {}", credentials.get_aws_access_key_id(), credentials.get_aws_secret_key());

            if creds_have_values(credentials) {
                self.credentials = AWSCredentials{ key: credentials.get_aws_access_key_id().to_string(),
                    secret: credentials.get_aws_secret_key().to_string(), token: "".to_string(),
                    expires_at: UTC::now() + Duration::seconds(600) };
            } else {
                let mut iam_provider = IAMRoleCredentialsProvider::new();
                iam_provider.refresh();
                let credentials = iam_provider.get_credentials();
                if creds_have_values(credentials) {
                    println!("using creds from IAM: {}, {}, {}", credentials.get_aws_access_key_id(),
                        credentials.get_aws_secret_key(), credentials.get_token());
                    self.credentials = AWSCredentials{ key: credentials.get_aws_access_key_id().to_string(),
                        secret: credentials.get_aws_secret_key().to_string(), token: credentials.get_token().to_string(),
                        expires_at: UTC::now() + Duration::seconds(600) };
                    return;
                } else {
                    // We're out of options
                    panic!("Couldn't find AWS credentials in environment, default credential file location or IAM role.");
                }
            }
        }
    }
}

fn creds_have_values(creds: &AWSCredentials) -> bool {
    if creds.get_aws_access_key_id().len() > 0 && creds.get_aws_secret_key().len() > 0 {
        return true;
    }
    return false;
}
<|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.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0154: r##"
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.

Here is an example that demonstrates the error:

```
fn f() {
    // Variable declaration before import
    let x = 0;
    use std::io::Read;
    ...
}
```

The solution is to declare the imports at the top of the block, function, or
file.

Here is the previous example again, with the correct order:

```
fn f() {
    use std::io::Read;
    let x = 0;
    ...
}
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0251: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::*; // error, do `use foo::baz as quux` instead on the previous line

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0252: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::baz; // error, do `use bar::baz as quux` instead

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0253: r##"
Attempt was made to import an unimportable value. This can happen when
trying to import a method from a trait. An example of this error:

```
mod foo {
    pub trait MyTrait {
        fn do_something();
    }
}
use foo::MyTrait::do_something;
```

It's illegal to directly import methods belonging to a trait or concrete type.
"##,

E0255: r##"
You can't import a value whose name is the same as another value defined in the
module.

An example of this error:

```
use bar::foo; // error, do `use bar::foo as baz` instead

fn foo() {}

mod bar {
     pub fn foo() {}
}

fn main() {}
```
"##,

E0256: r##"
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.

An example of this error:

```
use foo::Bar; // error

type Bar = u32;

mod foo {
    pub mod Bar { }
}

fn main() {}
```
"##,

E0259: r##"
The name chosen for an external crate conflicts with another external crate that
has been imported into the current module.

Wrong example:

```
extern crate a;
extern crate crate_a as a;
```

The solution is to choose a different name that doesn't conflict with any
external crate imported into the current module.

Correct example:

```
extern crate a;
extern crate crate_a as other_name;
```
"##,

E0260: r##"
The name for an item declaration conflicts with an external crate's name.

For instance,

```
extern crate abc;

struct abc;
```

There are two possible solutions:

Solution #1: Rename the item.

```
extern crate abc;

struct xyz;
```

Solution #2: Import the crate with a different name.

```
extern crate abc as xyz;

struct abc;
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type.

See the Types section of the reference for more information about the primitive
types:

http://doc.rust-lang.org/reference.html#types
"##,

E0364: r##"
Private items cannot be publicly re-exported.  This error indicates that
you attempted to `pub use` a type or value that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    const X: u32 = 1;
}
pub use foo::X;
```

The solution to this problem is to ensure that the items that you are
re-exporting are themselves marked with `pub`:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo::X;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0365: r##"
Private modules cannot be publicly re-exported.  This error indicates
that you attempted to `pub use` a module that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;

```
The solution to this problem is to ensure that the module that you are
re-exporting is itself marked with `pub`:

```
pub mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0403: r##"
Some type parameters have the same name. Example of erroneous code:

```
fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
                            //        parameter in this type parameter list
```

Please verify that none of the type parameterss are misspelled, and rename any
clashing parameters. Example:

```
fn foo<T, Y>(s: T, u: Y) {} // ok!
```
"##,

E0404: r##"
You tried to implement something which was not a trait on an object. Example of
erroneous code:

```
struct Foo;
struct Bar;

impl Foo for Bar {} // error: `Foo` is not a trait
```

Please verify that you didn't misspell the trait's name or otherwise use the
wrong identifier. Example:

```
trait Foo {
    // some functions
}
struct Bar;

impl Foo for Bar { // ok!
    // functions implementation
}
```
"##,

E0405: r##"
An unknown trait was implemented. Example of erroneous code:

```
struct Foo;

impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
```

Please verify that the name of the trait wasn't misspelled and ensure that it
was imported. Example:

```
// solution 1:
use some_file::SomeTrait;

// solution 2:
trait SomeTrait {
    // some functions
}

struct Foo;

impl SomeTrait for Foo { // ok!
    // implements functions
}
```
"##,

E0407: r##"
A definition of a method not in the implemented trait was given in a trait
implementation. Example of erroneous code:

```
trait Foo {
    fn a();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // error: method `b` is not a member of trait `Foo`
}
```

Please verify you didn't misspell the method name and you used the correct
trait. First example:

```
trait Foo {
    fn a();
    fn b();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // ok!
}
```

Second example:

```
trait Foo {
    fn a();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
}

impl Bar {
    fn b() {}
}
```
"##,

E0417: r##"
A static variable was referenced in a pattern. Example of erroneous code:

```
static FOO : i32 = 0;

match 0 {
    FOO => {} // error: static variables cannot be referenced in a
              //        pattern, use a `const` instead
    _ => {}
}
```

The compiler needs to know the value of the pattern at compile time;
compile-time patterns can defined via const or enum items. Please verify
that the identifier is spelled correctly, and if so, use a const instead
of static to define it. Example:

```
const FOO : i32 = 0;

match 0 {
    FOO => {} // ok!
    _ => {}
}
```
"##,

E0424: r##"
The `self` keyword was used in a static method. Example of erroneous code:

```
struct Foo;

impl Foo {
    fn bar(self) {}

    fn foo() {
        self.bar(); // error: `self` is not available in a static method.
    }
}
```

Please check if the method's argument list should have contained self,
&self, or &mut self (in case you didn't want to create a static method),
and add it if so. Example:

```
struct Foo;

impl Foo {
    fn bar(self) {}

    fn foo(self) {
        self.bar(); // ok!
    }
}
```
"##,

E0428: r##"
A type or module has been defined more than once. Example of erroneous
code:

```
struct Bar;
struct Bar; // error: duplicate definition of value `Bar`
```

Please verify you didn't misspell the type/module's name or remove/rename the
duplicated one. Example:

```
struct Bar;
struct Bar2; // ok!
```
"##,

E0430: r##"
The `self` import appears more than once in the list.

```
use something::{self, self}; // error: `self` import can only appear once in
                             //        the list
```

Please verify you didn't misspell the import name or remove the duplicated
`self` import.
"##,

E0433: r##"
Invalid import. Example of erroneous code:

```
use something_which_doesnt_exist;
// error: unresolved import `something_which_doesnt_exist`
```

Please verify you didn't misspell the import's name.
"##,

}

register_diagnostics! {
    E0153, // called no where
    E0157, // called from no where
    E0254, // import conflicts with imported crate in this module
    E0257,
    E0258,
    E0401, // can't use type parameters from outer function
    E0402, // cannot use an outer type parameter in this context
    E0406, // undeclared associated type
    E0408, // variable from pattern #1 is not bound in pattern #
    E0409, // variable is bound with different mode in pattern # than in
           // pattern #1
    E0410, // variable from pattern is not bound in pattern 1
    E0411, // use of `Self` outside of an impl or trait
    E0412, // use of undeclared
    E0413, // declaration of shadows an enum variant or unit-like struct in
           // scope
    E0414, // only irrefutable patterns allowed here
    E0415, // identifier is bound more than once in this parameter list
    E0416, // identifier is bound more than once in the same pattern
    E0418, // is not an enum variant, struct or const
    E0419, // unresolved enum variant, struct or const
    E0420, // is not an associated const
    E0421, // unresolved associated const
    E0422, // does not name a structure
    E0423, // is a struct variant name, but this expression uses it like a
           // function name
    E0425, // unresolved name
    E0426, // use of undeclared label
    E0427, // cannot use `ref` binding mode with ...
    E0429, // `self` imports are only allowed within a { } list
    E0431, // `self` import can only appear in an import list with a non-empty
           // prefix
    E0432, // unresolved import
    E0434, // can't capture dynamic environment in a fn item
    E0435, // attempt to use a non-constant value in a constant
    E0437, // type is not a member of trait
    E0438, // const is not a member of trait
}
<commit_msg>Add E0431 error explanation<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.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0154: r##"
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.

Here is an example that demonstrates the error:

```
fn f() {
    // Variable declaration before import
    let x = 0;
    use std::io::Read;
    ...
}
```

The solution is to declare the imports at the top of the block, function, or
file.

Here is the previous example again, with the correct order:

```
fn f() {
    use std::io::Read;
    let x = 0;
    ...
}
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0251: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::*; // error, do `use foo::baz as quux` instead on the previous line

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0252: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::baz; // error, do `use bar::baz as quux` instead

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0253: r##"
Attempt was made to import an unimportable value. This can happen when
trying to import a method from a trait. An example of this error:

```
mod foo {
    pub trait MyTrait {
        fn do_something();
    }
}
use foo::MyTrait::do_something;
```

It's illegal to directly import methods belonging to a trait or concrete type.
"##,

E0255: r##"
You can't import a value whose name is the same as another value defined in the
module.

An example of this error:

```
use bar::foo; // error, do `use bar::foo as baz` instead

fn foo() {}

mod bar {
     pub fn foo() {}
}

fn main() {}
```
"##,

E0256: r##"
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.

An example of this error:

```
use foo::Bar; // error

type Bar = u32;

mod foo {
    pub mod Bar { }
}

fn main() {}
```
"##,

E0259: r##"
The name chosen for an external crate conflicts with another external crate that
has been imported into the current module.

Wrong example:

```
extern crate a;
extern crate crate_a as a;
```

The solution is to choose a different name that doesn't conflict with any
external crate imported into the current module.

Correct example:

```
extern crate a;
extern crate crate_a as other_name;
```
"##,

E0260: r##"
The name for an item declaration conflicts with an external crate's name.

For instance,

```
extern crate abc;

struct abc;
```

There are two possible solutions:

Solution #1: Rename the item.

```
extern crate abc;

struct xyz;
```

Solution #2: Import the crate with a different name.

```
extern crate abc as xyz;

struct abc;
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type.

See the Types section of the reference for more information about the primitive
types:

http://doc.rust-lang.org/reference.html#types
"##,

E0364: r##"
Private items cannot be publicly re-exported.  This error indicates that
you attempted to `pub use` a type or value that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    const X: u32 = 1;
}
pub use foo::X;
```

The solution to this problem is to ensure that the items that you are
re-exporting are themselves marked with `pub`:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo::X;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0365: r##"
Private modules cannot be publicly re-exported.  This error indicates
that you attempted to `pub use` a module that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;

```
The solution to this problem is to ensure that the module that you are
re-exporting is itself marked with `pub`:

```
pub mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0403: r##"
Some type parameters have the same name. Example of erroneous code:

```
fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
                            //        parameter in this type parameter list
```

Please verify that none of the type parameterss are misspelled, and rename any
clashing parameters. Example:

```
fn foo<T, Y>(s: T, u: Y) {} // ok!
```
"##,

E0404: r##"
You tried to implement something which was not a trait on an object. Example of
erroneous code:

```
struct Foo;
struct Bar;

impl Foo for Bar {} // error: `Foo` is not a trait
```

Please verify that you didn't misspell the trait's name or otherwise use the
wrong identifier. Example:

```
trait Foo {
    // some functions
}
struct Bar;

impl Foo for Bar { // ok!
    // functions implementation
}
```
"##,

E0405: r##"
An unknown trait was implemented. Example of erroneous code:

```
struct Foo;

impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
```

Please verify that the name of the trait wasn't misspelled and ensure that it
was imported. Example:

```
// solution 1:
use some_file::SomeTrait;

// solution 2:
trait SomeTrait {
    // some functions
}

struct Foo;

impl SomeTrait for Foo { // ok!
    // implements functions
}
```
"##,

E0407: r##"
A definition of a method not in the implemented trait was given in a trait
implementation. Example of erroneous code:

```
trait Foo {
    fn a();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // error: method `b` is not a member of trait `Foo`
}
```

Please verify you didn't misspell the method name and you used the correct
trait. First example:

```
trait Foo {
    fn a();
    fn b();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
    fn b() {} // ok!
}
```

Second example:

```
trait Foo {
    fn a();
}

struct Bar;

impl Foo for Bar {
    fn a() {}
}

impl Bar {
    fn b() {}
}
```
"##,

E0417: r##"
A static variable was referenced in a pattern. Example of erroneous code:

```
static FOO : i32 = 0;

match 0 {
    FOO => {} // error: static variables cannot be referenced in a
              //        pattern, use a `const` instead
    _ => {}
}
```

The compiler needs to know the value of the pattern at compile time;
compile-time patterns can defined via const or enum items. Please verify
that the identifier is spelled correctly, and if so, use a const instead
of static to define it. Example:

```
const FOO : i32 = 0;

match 0 {
    FOO => {} // ok!
    _ => {}
}
```
"##,

E0424: r##"
The `self` keyword was used in a static method. Example of erroneous code:

```
struct Foo;

impl Foo {
    fn bar(self) {}

    fn foo() {
        self.bar(); // error: `self` is not available in a static method.
    }
}
```

Please check if the method's argument list should have contained self,
&self, or &mut self (in case you didn't want to create a static method),
and add it if so. Example:

```
struct Foo;

impl Foo {
    fn bar(self) {}

    fn foo(self) {
        self.bar(); // ok!
    }
}
```
"##,

E0428: r##"
A type or module has been defined more than once. Example of erroneous
code:

```
struct Bar;
struct Bar; // error: duplicate definition of value `Bar`
```

Please verify you didn't misspell the type/module's name or remove/rename the
duplicated one. Example:

```
struct Bar;
struct Bar2; // ok!
```
"##,

E0430: r##"
The `self` import appears more than once in the list. Erroneous code example:

```
use something::{self, self}; // error: `self` import can only appear once in
                             //        the list
```

Please verify you didn't misspell the import name or remove the duplicated
`self` import.
"##,

E0431: r##"
`self` import was made. Erroneous code example:

```
use {self}; // error: `self` import can only appear in an import list with a
            //        non-empty prefix
```

You can't import the current module in itself, please remove this import or
verify you didn't misspell it.
"##,

E0433: r##"
Invalid import. Example of erroneous code:

```
use something_which_doesnt_exist;
// error: unresolved import `something_which_doesnt_exist`
```

Please verify you didn't misspell the import's name.
"##,

}

register_diagnostics! {
    E0153, // called no where
    E0157, // called from no where
    E0254, // import conflicts with imported crate in this module
    E0257,
    E0258,
    E0401, // can't use type parameters from outer function
    E0402, // cannot use an outer type parameter in this context
    E0406, // undeclared associated type
    E0408, // variable from pattern #1 is not bound in pattern #
    E0409, // variable is bound with different mode in pattern # than in
           // pattern #1
    E0410, // variable from pattern is not bound in pattern 1
    E0411, // use of `Self` outside of an impl or trait
    E0412, // use of undeclared
    E0413, // declaration of shadows an enum variant or unit-like struct in
           // scope
    E0414, // only irrefutable patterns allowed here
    E0415, // identifier is bound more than once in this parameter list
    E0416, // identifier is bound more than once in the same pattern
    E0418, // is not an enum variant, struct or const
    E0419, // unresolved enum variant, struct or const
    E0420, // is not an associated const
    E0421, // unresolved associated const
    E0422, // does not name a structure
    E0423, // is a struct variant name, but this expression uses it like a
           // function name
    E0425, // unresolved name
    E0426, // use of undeclared label
    E0427, // cannot use `ref` binding mode with ...
    E0429, // `self` imports are only allowed within a { } list
    E0432, // unresolved import
    E0434, // can't capture dynamic environment in a fn item
    E0435, // attempt to use a non-constant value in a constant
    E0437, // type is not a member of trait
    E0438, // const is not a member of trait
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! MSVC-specific logic for linkers and such.
//!
//! This module contains a cross-platform interface but has a blank unix
//! implementation. The Windows implementation builds on top of Windows native
//! libraries (reading registry keys), so it otherwise wouldn't link on unix.
//!
//! Note that we don't have much special logic for finding the system linker on
//! any other platforms, so it may seem a little odd to single out MSVC to have
//! a good deal of code just to find the linker. Unlike Unix systems, however,
//! the MSVC linker is not in the system PATH by default. It also additionally
//! needs a few environment variables or command line flags to be able to link
//! against system libraries.
//!
//! In order to have a nice smooth experience on Windows, the logic in this file
//! is here to find the MSVC linker and set it up in the default configuration
//! one would need to set up anyway. This means that the Rust compiler can be
//! run not only in the developer shells of MSVC but also the standard cmd.exe
//! shell or MSYS shells.
//!
//! As a high-level note, all logic in this module for looking up various
//! paths/files is copied over from Clang in its MSVCToolChain.cpp file, but
//! comments can also be found below leading through the various code paths.

use std::process::Command;
use session::Session;

#[cfg(windows)]
mod registry;

#[cfg(windows)]
pub fn link_exe_cmd(sess: &Session) -> Command {
    use std::env;
    use std::ffi::OsString;
    use std::fs;
    use std::io;
    use std::path::{Path, PathBuf};
    use self::registry::{RegistryKey, LOCAL_MACHINE};

    // When finding the link.exe binary the 32-bit version is at the top level
    // but the versions to cross to other architectures are stored in
    // sub-folders. Unknown architectures also just bail out early to return the
    // standard `link.exe` command.
    let extra = match &sess.target.target.arch[..] {
        "x86" => "",
        "x86_64" => "amd64",
        "arm" => "arm",
        _ => return Command::new("link.exe"),
    };

    let vs_install_dir = get_vs_install_dir();

    // First up, we need to find the `link.exe` binary itself, and there's a few
    // locations that we can look. First up is the standard VCINSTALLDIR
    // environment variable which is normally set by the vcvarsall.bat file. If
    // an environment is set up manually by whomever's driving the compiler then
    // we shouldn't muck with that decision and should instead respect that.
    //
    // Next up is looking in PATH itself. Here we look for `cl.exe` and then
    // assume that `link.exe` is next to it if we find it. Note that we look for
    // `cl.exe` because MinGW ships /usr/bin/link.exe which is normally found in
    // PATH but we're not interested in finding that.
    //
    // Finally we read the Windows registry to discover the VS install root.
    // From here we probe for `link.exe` just to make sure that it exists.
    let mut cmd = env::var_os("VCINSTALLDIR").and_then(|dir| {
        let mut p = PathBuf::from(dir);
        p.push("bin");
        p.push(extra);
        p.push("link.exe");
        if fs::metadata(&p).is_ok() {Some(p)} else {None}
    }).or_else(|| {
        env::var_os("PATH").and_then(|path| {
            env::split_paths(&path).find(|path| {
                fs::metadata(&path.join("cl.exe")).is_ok()
            }).map(|p| {
                p.join("link.exe")
            })
        })
    }).or_else(|| {
        vs_install_dir.as_ref().and_then(|p| {
            let mut p = p.join("VC/bin");
            p.push(extra);
            p.push("link.exe");
            if fs::metadata(&p).is_ok() {Some(p)} else {None}
        })
    }).map(|linker| {
        Command::new(linker)
    }).unwrap_or_else(|| {
        Command::new("link.exe")
    });

    // The MSVC linker uses the LIB environment variable as the default lookup
    // path for libraries. This environment variable is normally set up by the
    // VS shells, so we only want to start adding our own pieces if it's not
    // set.
    //
    // If we're adding our own pieces, then we need to add a few primary
    // directories to the default search path for the linker. The first is in
    // the VS install direcotry, the next is the Windows SDK directory, and the
    // last is the possible UCRT installation directory.
    //
    // The UCRT is a recent addition to Visual Studio installs (2015 at the time
    // of this writing), and it's in the normal windows SDK folder, but there
    // apparently aren't registry keys pointing to it. As a result we detect the
    // installation and then add it manually. This logic will probably need to
    // be tweaked over time...
    if env::var_os("LIB").is_none() {
        if let Some(mut vs_install_dir) = vs_install_dir {
            vs_install_dir.push("VC/lib");
            vs_install_dir.push(extra);
            let mut arg = OsString::from("/LIBPATH:");
            arg.push(&vs_install_dir);
            cmd.arg(arg);

            if let Some((ucrt_root, vers)) = ucrt_install_dir(&vs_install_dir) {
                if let Some(arch) = windows_sdk_v8_subdir(sess) {
                    let mut arg = OsString::from("/LIBPATH:");
                    arg.push(ucrt_root.join("Lib").join(vers)
                                      .join("ucrt").join(arch));
                    cmd.arg(arg);
                }
            }
        }
        if let Some(path) = get_windows_sdk_lib_path(sess) {
            let mut arg = OsString::from("/LIBPATH:");
            arg.push(&path);
            cmd.arg(arg);
        }
    }

    return cmd;

    // When looking for the Visual Studio installation directory we look in a
    // number of locations in varying degrees of precedence:
    //
    // 1. The Visual Studio registry keys
    // 2. The Visual Studio Express registry keys
    // 3. A number of somewhat standard environment variables
    //
    // If we find a hit from any of these keys then we strip off the IDE/Tools
    // folders which are typically found at the end.
    //
    // As a final note, when we take a look at the registry keys they're
    // typically found underneath the version of what's installed, but we don't
    // quite know what's installed. As a result we probe all sub-keys of the two
    // keys we're looking at to find out the maximum version of what's installed
    // and we use that root directory.
    fn get_vs_install_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VisualStudio".as_ref()).or_else(|_| {
            LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VCExpress".as_ref())
        }).ok().and_then(|key| {
            max_version(&key).and_then(|(_vers, key)| {
                key.query_str("InstallDir").ok()
            })
        }).or_else(|| {
            env::var_os("VS120COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS100COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS90COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS80COMNTOOLS")
        }).map(PathBuf::from).and_then(|mut dir| {
            if dir.ends_with("Common7/IDE") || dir.ends_with("Common7/Tools") {
                dir.pop();
                dir.pop();
                Some(dir)
            } else {
                None
            }
        })
    }

    // Given a registry key, look at all the sub keys and find the one which has
    // the maximal numeric value.
    //
    // Returns the name of the maximal key as well as the opened maximal key.
    fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
        let mut max_vers = 0;
        let mut max_key = None;
        for subkey in key.iter().filter_map(|k| k.ok()) {
            let val = subkey.to_str().and_then(|s| {
                s.trim_left_matches("v").replace(".", "").parse().ok()
            });
            let val = match val {
                Some(s) => s,
                None => continue,
            };
            if val > max_vers {
                if let Ok(k) = key.open(&subkey) {
                    max_vers = val;
                    max_key = Some((subkey, k));
                }
            }
        }
        return max_key
    }

    fn get_windows_sdk_path() -> Option<(PathBuf, usize)> {
        let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows";
        let key = LOCAL_MACHINE.open(key.as_ref());
        let (n, k) = match key.ok().as_ref().and_then(max_version) {
            Some(p) => p,
            None => return None,
        };
        let mut parts = n.to_str().unwrap().trim_left_matches("v").splitn(2, ".");
        let major = parts.next().unwrap().parse::<usize>().unwrap();
        let _minor = parts.next().unwrap().parse::<usize>().unwrap();
        k.query_str("InstallationFolder").ok().map(|folder| {
            (PathBuf::from(folder), major)
        })
    }

    fn get_windows_sdk_lib_path(sess: &Session) -> Option<PathBuf> {
        let (mut path, major) = match get_windows_sdk_path() {
            Some(p) => p,
            None => return None,
        };
        path.push("Lib");
        if major <= 7 {
            // In Windows SDK 7.x, x86 libraries are directly in the Lib folder,
            // x64 libraries are inside, and it's not necessary to link agains
            // the SDK 7.x when targeting ARM or other architectures.
            let x86 = match &sess.target.target.arch[..] {
                "x86" => true,
                "x86_64" => false,
                _ => return None,
            };
            Some(if x86 {path} else {path.join("x64")})
        } else {
            // Windows SDK 8.x installes libraries in a folder whose names
            // depend on the version of the OS you're targeting. By default
            // choose the newest, which usually corresponds to the version of
            // the OS you've installed the SDK on.
            let extra = match windows_sdk_v8_subdir(sess) {
                Some(e) => e,
                None => return None,
            };
            ["winv6.3", "win8", "win7"].iter().map(|p| path.join(p)).find(|part| {
                fs::metadata(part).is_ok()
            }).map(|path| {
                path.join("um").join(extra)
            })
        }
    }

    fn windows_sdk_v8_subdir(sess: &Session) -> Option<&'static str> {
        match &sess.target.target.arch[..] {
            "x86" => Some("x86"),
            "x86_64" => Some("x64"),
            "arm" => Some("arm"),
            _ => return None,
        }
    }

    fn ucrt_install_dir(vs_install_dir: &Path) -> Option<(PathBuf, String)> {
        let is_vs_14 = vs_install_dir.iter().filter_map(|p| p.to_str()).any(|s| {
            s == "Microsoft Visual Studio 14.0"
        });
        if !is_vs_14 {
            return None
        }
        let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
        let sdk_dir = LOCAL_MACHINE.open(key.as_ref()).and_then(|p| {
            p.query_str("KitsRoot10")
        }).map(PathBuf::from);
        let sdk_dir = match sdk_dir {
            Ok(p) => p,
            Err(..) => return None,
        };
        (move || -> io::Result<_> {
            let mut max = None;
            let mut max_s = None;
            for entry in try!(fs::read_dir(&sdk_dir.join("Lib"))) {
                let entry = try!(entry);
                if let Ok(s) = entry.file_name().into_string() {
                    if let Ok(u) = s.replace(".", "").parse::<usize>() {
                        if Some(u) > max {
                            max = Some(u);
                            max_s = Some(s);
                        }
                    }
                }
            }
            Ok(max_s.map(|m| (sdk_dir, m)))
        })().ok().and_then(|x| x)
    }
}

#[cfg(not(windows))]
pub fn link_exe_cmd(_sess: &Session) -> Command {
    Command::new("link.exe")
}
<commit_msg>Auto merge of #27437 - retep998:win10-sdk, r=alexcrichton<commit_after>// Copyright 2015 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.

//! MSVC-specific logic for linkers and such.
//!
//! This module contains a cross-platform interface but has a blank unix
//! implementation. The Windows implementation builds on top of Windows native
//! libraries (reading registry keys), so it otherwise wouldn't link on unix.
//!
//! Note that we don't have much special logic for finding the system linker on
//! any other platforms, so it may seem a little odd to single out MSVC to have
//! a good deal of code just to find the linker. Unlike Unix systems, however,
//! the MSVC linker is not in the system PATH by default. It also additionally
//! needs a few environment variables or command line flags to be able to link
//! against system libraries.
//!
//! In order to have a nice smooth experience on Windows, the logic in this file
//! is here to find the MSVC linker and set it up in the default configuration
//! one would need to set up anyway. This means that the Rust compiler can be
//! run not only in the developer shells of MSVC but also the standard cmd.exe
//! shell or MSYS shells.
//!
//! As a high-level note, all logic in this module for looking up various
//! paths/files is copied over from Clang in its MSVCToolChain.cpp file, but
//! comments can also be found below leading through the various code paths.

use std::process::Command;
use session::Session;

#[cfg(windows)]
mod registry;

#[cfg(windows)]
pub fn link_exe_cmd(sess: &Session) -> Command {
    use std::env;
    use std::ffi::OsString;
    use std::fs;
    use std::io;
    use std::path::{Path, PathBuf};
    use self::registry::{RegistryKey, LOCAL_MACHINE};

    // When finding the link.exe binary the 32-bit version is at the top level
    // but the versions to cross to other architectures are stored in
    // sub-folders. Unknown architectures also just bail out early to return the
    // standard `link.exe` command.
    let extra = match &sess.target.target.arch[..] {
        "x86" => "",
        "x86_64" => "amd64",
        "arm" => "arm",
        _ => return Command::new("link.exe"),
    };

    let vs_install_dir = get_vs_install_dir();

    // First up, we need to find the `link.exe` binary itself, and there's a few
    // locations that we can look. First up is the standard VCINSTALLDIR
    // environment variable which is normally set by the vcvarsall.bat file. If
    // an environment is set up manually by whomever's driving the compiler then
    // we shouldn't muck with that decision and should instead respect that.
    //
    // Next up is looking in PATH itself. Here we look for `cl.exe` and then
    // assume that `link.exe` is next to it if we find it. Note that we look for
    // `cl.exe` because MinGW ships /usr/bin/link.exe which is normally found in
    // PATH but we're not interested in finding that.
    //
    // Finally we read the Windows registry to discover the VS install root.
    // From here we probe for `link.exe` just to make sure that it exists.
    let mut cmd = env::var_os("VCINSTALLDIR").and_then(|dir| {
        let mut p = PathBuf::from(dir);
        p.push("bin");
        p.push(extra);
        p.push("link.exe");
        if fs::metadata(&p).is_ok() {Some(p)} else {None}
    }).or_else(|| {
        env::var_os("PATH").and_then(|path| {
            env::split_paths(&path).find(|path| {
                fs::metadata(&path.join("cl.exe")).is_ok()
            }).map(|p| {
                p.join("link.exe")
            })
        })
    }).or_else(|| {
        vs_install_dir.as_ref().and_then(|p| {
            let mut p = p.join("VC/bin");
            p.push(extra);
            p.push("link.exe");
            if fs::metadata(&p).is_ok() {Some(p)} else {None}
        })
    }).map(|linker| {
        Command::new(linker)
    }).unwrap_or_else(|| {
        Command::new("link.exe")
    });

    // The MSVC linker uses the LIB environment variable as the default lookup
    // path for libraries. This environment variable is normally set up by the
    // VS shells, so we only want to start adding our own pieces if it's not
    // set.
    //
    // If we're adding our own pieces, then we need to add a few primary
    // directories to the default search path for the linker. The first is in
    // the VS install direcotry, the next is the Windows SDK directory, and the
    // last is the possible UCRT installation directory.
    //
    // The UCRT is a recent addition to Visual Studio installs (2015 at the time
    // of this writing), and it's in the normal windows SDK folder, but there
    // apparently aren't registry keys pointing to it. As a result we detect the
    // installation and then add it manually. This logic will probably need to
    // be tweaked over time...
    if env::var_os("LIB").is_none() {
        if let Some(mut vs_install_dir) = vs_install_dir {
            vs_install_dir.push("VC/lib");
            vs_install_dir.push(extra);
            let mut arg = OsString::from("/LIBPATH:");
            arg.push(&vs_install_dir);
            cmd.arg(arg);

            if let Some((ucrt_root, vers)) = ucrt_install_dir(&vs_install_dir) {
                if let Some(arch) = windows_sdk_v8_subdir(sess) {
                    let mut arg = OsString::from("/LIBPATH:");
                    arg.push(ucrt_root.join("Lib").join(vers)
                                      .join("ucrt").join(arch));
                    cmd.arg(arg);
                }
            }
        }
        if let Some(path) = get_windows_sdk_lib_path(sess) {
            let mut arg = OsString::from("/LIBPATH:");
            arg.push(&path);
            cmd.arg(arg);
        }
    }

    return cmd;

    // When looking for the Visual Studio installation directory we look in a
    // number of locations in varying degrees of precedence:
    //
    // 1. The Visual Studio registry keys
    // 2. The Visual Studio Express registry keys
    // 3. A number of somewhat standard environment variables
    //
    // If we find a hit from any of these keys then we strip off the IDE/Tools
    // folders which are typically found at the end.
    //
    // As a final note, when we take a look at the registry keys they're
    // typically found underneath the version of what's installed, but we don't
    // quite know what's installed. As a result we probe all sub-keys of the two
    // keys we're looking at to find out the maximum version of what's installed
    // and we use that root directory.
    fn get_vs_install_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VisualStudio".as_ref()).or_else(|_| {
            LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VCExpress".as_ref())
        }).ok().and_then(|key| {
            max_version(&key).and_then(|(_vers, key)| {
                key.query_str("InstallDir").ok()
            })
        }).or_else(|| {
            env::var_os("VS120COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS100COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS90COMNTOOLS")
        }).or_else(|| {
            env::var_os("VS80COMNTOOLS")
        }).map(PathBuf::from).and_then(|mut dir| {
            if dir.ends_with("Common7/IDE") || dir.ends_with("Common7/Tools") {
                dir.pop();
                dir.pop();
                Some(dir)
            } else {
                None
            }
        })
    }

    // Given a registry key, look at all the sub keys and find the one which has
    // the maximal numeric value.
    //
    // Returns the name of the maximal key as well as the opened maximal key.
    fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> {
        let mut max_vers = 0;
        let mut max_key = None;
        for subkey in key.iter().filter_map(|k| k.ok()) {
            let val = subkey.to_str().and_then(|s| {
                s.trim_left_matches("v").replace(".", "").parse().ok()
            });
            let val = match val {
                Some(s) => s,
                None => continue,
            };
            if val > max_vers {
                if let Ok(k) = key.open(&subkey) {
                    max_vers = val;
                    max_key = Some((subkey, k));
                }
            }
        }
        return max_key
    }

    fn get_windows_sdk_path() -> Option<(PathBuf, usize, Option<OsString>)> {
        let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows";
        let key = LOCAL_MACHINE.open(key.as_ref());
        let (n, k) = match key.ok().as_ref().and_then(max_version) {
            Some(p) => p,
            None => return None,
        };
        let mut parts = n.to_str().unwrap().trim_left_matches("v").splitn(2, ".");
        let major = parts.next().unwrap().parse::<usize>().unwrap();
        let _minor = parts.next().unwrap().parse::<usize>().unwrap();
        k.query_str("InstallationFolder").ok().map(|folder| {
            let ver = k.query_str("ProductVersion");
            (PathBuf::from(folder), major, ver.ok())
        })
    }

    fn get_windows_sdk_lib_path(sess: &Session) -> Option<PathBuf> {
        let (mut path, major, ver) = match get_windows_sdk_path() {
            Some(p) => p,
            None => return None,
        };
        path.push("Lib");
        if major <= 7 {
            // In Windows SDK 7.x, x86 libraries are directly in the Lib folder,
            // x64 libraries are inside, and it's not necessary to link against
            // the SDK 7.x when targeting ARM or other architectures.
            let x86 = match &sess.target.target.arch[..] {
                "x86" => true,
                "x86_64" => false,
                _ => return None,
            };
            Some(if x86 {path} else {path.join("x64")})
        } else if major <= 8 {
            // Windows SDK 8.x installs libraries in a folder whose names
            // depend on the version of the OS you're targeting. By default
            // choose the newest, which usually corresponds to the version of
            // the OS you've installed the SDK on.
            let extra = match windows_sdk_v8_subdir(sess) {
                Some(e) => e,
                None => return None,
            };
            ["winv6.3", "win8", "win7"].iter().map(|p| path.join(p)).find(|part| {
                fs::metadata(part).is_ok()
            }).map(|path| {
                path.join("um").join(extra)
            })
        } else if let Some(mut ver) = ver {
            // Windows SDK 10 splits the libraries into architectures the same
            // as Windows SDK 8.x, except for the addition of arm64.
            // Additionally, the SDK 10 is split by Windows 10 build numbers
            // rather than the OS version like the SDK 8.x does.
            let extra = match windows_sdk_v10_subdir(sess) {
                Some(e) => e,
                None => return None,
            };
            // To get the correct directory we need to get the Windows SDK 10
            // version, and so far it looks like the "ProductVersion" of the SDK
            // corresponds to the folder name that the libraries are located in
            // except that the folder contains an extra ".0". For now just
            // append a ".0" to look for find the directory we're in. This logic
            // will likely want to be refactored one day.
            ver.push(".0");
            let p = path.join(ver).join("um").join(extra);
            fs::metadata(&p).ok().map(|_| p)
        } else { None }
    }

    fn windows_sdk_v8_subdir(sess: &Session) -> Option<&'static str> {
        match &sess.target.target.arch[..] {
            "x86" => Some("x86"),
            "x86_64" => Some("x64"),
            "arm" => Some("arm"),
            _ => return None,
        }
    }

    fn windows_sdk_v10_subdir(sess: &Session) -> Option<&'static str> {
        match &sess.target.target.arch[..] {
            "x86" => Some("x86"),
            "x86_64" => Some("x64"),
            "arm" => Some("arm"),
            "aarch64" => Some("arm64"), // FIXME - Check if aarch64 is correct
            _ => return None,
        }
    }

    fn ucrt_install_dir(vs_install_dir: &Path) -> Option<(PathBuf, String)> {
        let is_vs_14 = vs_install_dir.iter().filter_map(|p| p.to_str()).any(|s| {
            s == "Microsoft Visual Studio 14.0"
        });
        if !is_vs_14 {
            return None
        }
        let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots";
        let sdk_dir = LOCAL_MACHINE.open(key.as_ref()).and_then(|p| {
            p.query_str("KitsRoot10")
        }).map(PathBuf::from);
        let sdk_dir = match sdk_dir {
            Ok(p) => p,
            Err(..) => return None,
        };
        (move || -> io::Result<_> {
            let mut max = None;
            let mut max_s = None;
            for entry in try!(fs::read_dir(&sdk_dir.join("Lib"))) {
                let entry = try!(entry);
                if let Ok(s) = entry.file_name().into_string() {
                    if let Ok(u) = s.replace(".", "").parse::<usize>() {
                        if Some(u) > max {
                            max = Some(u);
                            max_s = Some(s);
                        }
                    }
                }
            }
            Ok(max_s.map(|m| (sdk_dir, m)))
        })().ok().and_then(|x| x)
    }
}

#[cfg(not(windows))]
pub fn link_exe_cmd(_sess: &Session) -> Command {
    Command::new("link.exe")
}
<|endoftext|>