<commit_before>use dispatcher::request::InternalRequest;

pub use self::linear::LinearContext;
pub use self::map::MapContext;

pub mod base;
pub mod event;
pub mod map;

pub enum Context {
    Linear(LinearContext),
    Map(MapContext)
}

impl From<Context> for Box<self::event::EventHandler<InternalRequest>> {
    fn from(context: Context) -> Box<self::event::EventHandler<InternalRequest>> {
        match context {
            Context::Linear(context) => Box::new(context),
            Context::Map(context) => Box::new(context),
        }
    }
}

pub mod linear {
    use uuid::Uuid;
    use std::rc::Rc;

    use conditions::Conditions;
    use context::event::{EventHandler};
    use message::{Message};
    use state::State;
    use timer::TimerEvent;
    use dispatcher::request::{InternalRequest, Request};
    use context::base::BaseContext;

    pub struct LinearContext {
        base: BaseContext,
        state: State
    }

    impl LinearContext {
        pub fn new(uuid: Uuid, conditions: Conditions) -> LinearContext {
            LinearContext {
                base: BaseContext::new(uuid, conditions),
                state: State::new()
            }
        }

        pub fn on_event(&mut self, event: InternalRequest) {
            if let Request::Timer(event) = event {
                self.on_timer(&event);
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) {
            self.base.on_timer(event, &mut self.state)
        }

        pub fn on_message(&mut self, event: Rc<Message>) {
            self.base.on_message(event, &mut self.state);
        }

        pub fn is_open(&self) -> bool {
            self.state.is_open()
        }

        pub fn patterns(&self) -> &[String] {
            &self.base.conditions().patterns
        }
    }

    impl From<BaseContext> for LinearContext {
        fn from(context: BaseContext) -> LinearContext {
            LinearContext {
                base: context,
                state: State::new()
            }
        }
    }

    impl EventHandler<InternalRequest> for LinearContext {
        fn handlers(&self) -> &[String] {
            self.patterns()
        }
        fn handle_event(&mut self, event: InternalRequest) {
            self.on_event(event);
        }
    }
}

#[cfg(test)]
mod test {
    use uuid::Uuid;
    use std::rc::Rc;

    use message;
    use timer::TimerEvent;
    use context::LinearContext;
    use conditions::Builder;

    #[test]
    fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
        let timeout = 100;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), Builder::new(timeout).patterns(patterns).build());
        let msg1 = message::Builder::new(&msg_id).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event);
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(50));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(49));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
        let timeout = 100;
        let max_size = 3;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), Builder::new(timeout).max_size(max_size).patterns(patterns).build());
        let msg1 = message::Builder::new(&msg_id).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), Builder::new(timeout).renew_timeout(renew_timeout).patterns(patterns).build());
        let msg1 = message::Builder::new(&msg_id).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), Builder::new(timeout).renew_timeout(renew_timeout).patterns(patterns).build());
        let msg1 = message::Builder::new(&msg_id).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
    }
}
<commit_msg>LinearContext: call on_message() when a Message event received<commit_after>use dispatcher::request::InternalRequest;

pub use self::linear::LinearContext;
pub use self::map::MapContext;

pub mod base;
pub mod event;
pub mod map;

pub enum Context {
    Linear(LinearContext),
    Map(MapContext)
}

impl From<Context> for Box<self::event::EventHandler<InternalRequest>> {
    fn from(context: Context) -> Box<self::event::EventHandler<InternalRequest>> {
        match context {
            Context::Linear(context) => Box::new(context),
            Context::Map(context) => Box::new(context),
        }
    }
}

pub mod linear {
    use uuid::Uuid;
    use std::rc::Rc;

    use conditions::Conditions;
    use context::event::{EventHandler};
    use message::{Message};
    use state::State;
    use timer::TimerEvent;
    use dispatcher::request::{InternalRequest, Request};
    use context::base::BaseContext;

    pub struct LinearContext {
        base: BaseContext,
        state: State
    }

    impl LinearContext {
        pub fn new(uuid: Uuid, conditions: Conditions) -> LinearContext {
            LinearContext {
                base: BaseContext::new(uuid, conditions),
                state: State::new()
            }
        }

        pub fn on_event(&mut self, event: InternalRequest) {
            match event {
                Request::Timer(event) => {
                    self.on_timer(&event)
                },
                Request::Message(message) => {
                    self.on_message(message)
                },
                _ => {}
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) {
            self.base.on_timer(event, &mut self.state)
        }

        pub fn on_message(&mut self, event: Rc<Message>) {
            self.base.on_message(event, &mut self.state);
        }

        pub fn is_open(&self) -> bool {
            self.state.is_open()
        }

        pub fn patterns(&self) -> &[String] {
            &self.base.conditions().patterns
        }
    }

    impl From<BaseContext> for LinearContext {
        fn from(context: BaseContext) -> LinearContext {
            LinearContext {
                base: context,
                state: State::new()
            }
        }
    }

    impl EventHandler<InternalRequest> for LinearContext {
        fn handlers(&self) -> &[String] {
            self.patterns()
        }
        fn handle_event(&mut self, event: InternalRequest) {
            self.on_event(event);
        }
    }
}

#[cfg(test)]
mod test {
    use uuid::Uuid;
    use std::rc::Rc;

    use message;
    use timer::TimerEvent;
    use context::LinearContext;
    use conditions::Builder;

    #[test]
    fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
        let timeout = 100;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), Builder::new(timeout).patterns(patterns).build());
        let msg1 = message::Builder::new(&msg_id).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event);
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(50));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(49));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
        let timeout = 100;
        let max_size = 3;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), Builder::new(timeout).max_size(max_size).patterns(patterns).build());
        let msg1 = message::Builder::new(&msg_id).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), Builder::new(timeout).renew_timeout(renew_timeout).patterns(patterns).build());
        let msg1 = message::Builder::new(&msg_id).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "11eaf6f8-0640-460f-aee2-a72d2f2ab258".to_string();
        let patterns = vec![
            msg_id.clone(),
        ];
        let mut context = LinearContext::new(Uuid::new_v4(), Builder::new(timeout).renew_timeout(renew_timeout).patterns(patterns).build());
        let msg1 = message::Builder::new(&msg_id).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
    }
}
<|endoftext|>


<commit_before>extern crate piston_window;

use piston_window::Transformed;

use piston_window as pw;

struct Game {
    rotation: f64,
	up: bool,
	down: bool,
	left: bool,
	right: bool,
}

impl Game {
    fn new() -> Game {
        Game { rotation: 0.0, up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &pw::UpdateArgs) {
        self.rotation += 3.0 * args.dt;
    }

    fn on_draw(&mut self, args: &pw::RenderArgs, window: &pw::PistonWindow) {
        window.draw_2d(|context, graphics| {
            pw::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let red = [1.0, 0.0, 0.0, 1.0];
            let square = pw::rectangle::square(0.0, 0.0, 100.0);
            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            pw::rectangle(red, square, center.rot_rad(self.rotation).trans(-50.0, -50.0), graphics);
        });
    }

	fn on_input(&mut self, input: &pw::Input) {
		match input {
			&pw::Input::Press(button) => {
				match button {
					pw::Button::Keyboard(pw::Key::Up) => { self.up = true; }
					pw::Button::Keyboard(pw::Key::Down) => { self.down = true; }
					pw::Button::Keyboard(pw::Key::Left) => { self.left = true; }
					pw::Button::Keyboard(pw::Key::Right) => { self.right = true; }
					_ => {}
				}
			}
			&pw::Input::Release(button) => {
				match button {
					pw::Button::Keyboard(pw::Key::Up) => { self.up = false; }
					pw::Button::Keyboard(pw::Key::Down) => { self.down = false; }
					pw::Button::Keyboard(pw::Key::Left) => { self.left = false; }
					pw::Button::Keyboard(pw::Key::Right) => { self.right = false; }
					_ => {}
				}
			}
			_ => {}
		}
	}
}

fn main() {
    let window: pw::PistonWindow = pw::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

	let mut game = Game::new();

    for w in window {
		match w.event {
			Some(pw::Event::Update(args)) => { game.on_update(&args); }
			Some(pw::Event::Render(args)) => { game.on_draw(&args, &w); }
			Some(pw::Event::Input(input)) => { game.on_input(&input); }
			_ => {}
		}
    }
}
<commit_msg>on_update - x/y position<commit_after>extern crate piston_window;

use piston_window::Transformed;

use piston_window as pw;

struct Game {
    rotation: f64,
	x: f64,
	y: f64,
	up: bool,
	down: bool,
	left: bool,
	right: bool,
}

impl Game {
    fn new() -> Game {
        Game { rotation: 0.0, x: 0., y: 0., up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &pw::UpdateArgs) {
        self.rotation += 3.0 * args.dt;

		if self.up {
			self.y += -50.0 * args.dt;
		}
		if self.down {
			self.y += 50.0 * args.dt;
		}
		if self.left {
			self.x += -50.0 * args.dt;
		}
		if self.right {
			self.x += 50.0 * args.dt;
		}
    }

    fn on_draw(&mut self, args: &pw::RenderArgs, window: &pw::PistonWindow) {
        window.draw_2d(|context, graphics| {
            pw::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let red = [1.0, 0.0, 0.0, 1.0];
            let square = pw::rectangle::square(0.0, 0.0, 100.0);
            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            pw::rectangle(red, square, center.rot_rad(self.rotation).trans(-50.0, -50.0), graphics);
        });
    }

	fn on_input(&mut self, input: &pw::Input) {
		match input {
			&pw::Input::Press(button) => {
				match button {
					pw::Button::Keyboard(pw::Key::Up) => { self.up = true; }
					pw::Button::Keyboard(pw::Key::Down) => { self.down = true; }
					pw::Button::Keyboard(pw::Key::Left) => { self.left = true; }
					pw::Button::Keyboard(pw::Key::Right) => { self.right = true; }
					_ => {}
				}
			}
			&pw::Input::Release(button) => {
				match button {
					pw::Button::Keyboard(pw::Key::Up) => { self.up = false; }
					pw::Button::Keyboard(pw::Key::Down) => { self.down = false; }
					pw::Button::Keyboard(pw::Key::Left) => { self.left = false; }
					pw::Button::Keyboard(pw::Key::Right) => { self.right = false; }
					_ => {}
				}
			}
			_ => {}
		}
	}
}

fn main() {
    let window: pw::PistonWindow = pw::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

	let mut game = Game::new();

    for w in window {
		match w.event {
			Some(pw::Event::Update(args)) => { game.on_update(&args); }
			Some(pw::Event::Render(args)) => { game.on_draw(&args, &w); }
			Some(pw::Event::Input(input)) => { game.on_input(&input); }
			_ => {}
		}
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Create_a_file

extern crate libc;

use std::io::{mod, File, fs};

#[cfg(not(test))]
fn main () {
    // Create a new file.  We get a Result object from
    // File::create. We could check if there is an error by using
    // .is_error() or by using pattern matching. We choose here to
    // ignore the possibility of an error and just unwrap the value
    // contained in the Result object.  This means that an error will
    // cause the program to fail at runtime.
    let mut new_file = File::create(&Path::new("build/output.txt")).unwrap();

    // Write something trivial to the file.
    // Now we are handling a possible error by using pattern matching
    match writeln!(&mut new_file as &mut Writer, "Nothing here...") {
        Ok(()) => (),
        Err(e) => println!("Failed to write to file: {}", e),
    }

    // Create a directory. Here we handle a possible error by using
    // the functions provided by result.  The second argument sets the
    // file permissions
    let result = fs::mkdir(&Path::new("build/docs"), io::USER_RWX);
    if result.is_err() {
        println!("Failed to create a directory: {}", result.err().unwrap());
    }
}

#[test]
fn test_create_file() {
    use std::io::fs::PathExtensions;

    let build_dir = Path::new("build-tests");
    if !(build_dir.exists() && build_dir.is_dir()) {
        let r = fs::mkdir(&build_dir, io::UserRWX);
        assert!(r.is_ok());
    }

    let file_path = Path::new("build-tests/create_file_test.txt");
    if file_path.exists() && file_path.is_file() {
        let r = fs::unlink(&file_path);
        assert!(r.is_ok());
    }
    match File::create(&file_path) {
        Ok(_) => assert!(true),
        Err(e) => fail!("failed to create_file at {}, error: {}",
                        file_path.display(),
                        e.desc)
    }
}
<commit_msg>create file: fix static casing test<commit_after>// Implements http://rosettacode.org/wiki/Create_a_file

extern crate libc;

use std::io::{mod, File, fs};

#[cfg(not(test))]
fn main () {
    // Create a new file.  We get a Result object from
    // File::create. We could check if there is an error by using
    // .is_error() or by using pattern matching. We choose here to
    // ignore the possibility of an error and just unwrap the value
    // contained in the Result object.  This means that an error will
    // cause the program to fail at runtime.
    let mut new_file = File::create(&Path::new("build/output.txt")).unwrap();

    // Write something trivial to the file.
    // Now we are handling a possible error by using pattern matching
    match writeln!(&mut new_file as &mut Writer, "Nothing here...") {
        Ok(()) => (),
        Err(e) => println!("Failed to write to file: {}", e),
    }

    // Create a directory. Here we handle a possible error by using
    // the functions provided by result.  The second argument sets the
    // file permissions
    let result = fs::mkdir(&Path::new("build/docs"), io::USER_RWX);
    if result.is_err() {
        println!("Failed to create a directory: {}", result.err().unwrap());
    }
}

#[test]
fn test_create_file() {
    use std::io::fs::PathExtensions;

    let build_dir = Path::new("build-tests");
    if !(build_dir.exists() && build_dir.is_dir()) {
        let r = fs::mkdir(&build_dir, io::USER_RWX);
        assert!(r.is_ok());
    }

    let file_path = Path::new("build-tests/create_file_test.txt");
    if file_path.exists() && file_path.is_file() {
        let r = fs::unlink(&file_path);
        assert!(r.is_ok());
    }
    match File::create(&file_path) {
        Ok(_) => assert!(true),
        Err(e) => fail!("failed to create_file at {}, error: {}",
                        file_path.display(),
                        e.desc)
    }
}
<|endoftext|>


<commit_before>use std::env;
use dirs;
use ini::Ini;
use error::{S3Result, S3Error};
use std::collections::HashMap;

/// AWS access credentials: access key, secret key, and optional token.
///
/// # Example
///
/// Loads from the standard AWS credentials file with the given profile name,
/// defaults to "default".
///
/// ```no_run
/// # // Do not execute this as it would cause unit tests to attempt to access
/// # // real user credentials.
/// use s3::credentials::Credentials;
///
/// // Load credentials from `[default]` profile
/// let credentials = Credentials::default();
///
/// // Also loads credentials from `[default]` profile
/// let credentials = Credentials::new(None, None, None, None);
///
/// // Load credentials from `[my-profile]` profile
/// let credentials = Credentials::new(None, None, None, Some("my-profile".into()));
/// ```
///
/// Credentials may also be initialized directly or by the following environment variables:
///
///   - `AWS_ACCESS_KEY_ID`,
///   - `AWS_SECRET_ACCESS_KEY`
///   - `AWS_SESSION_TOKEN`
///
/// The order of preference is arguments, then environment, and finally AWS
/// credentials file.
///
/// ```
/// use s3::credentials::Credentials;
///
/// // Load credentials directly
/// let access_key = String::from("AKIAIOSFODNN7EXAMPLE");
/// let secret_key = String::from("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
/// let credentials = Credentials::new(Some(access_key), Some(secret_key), None, None);
///
/// // Load credentials from the environment
/// use std::env;
/// env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
/// env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
/// let credentials = Credentials::new(None, None, None, None);
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Credentials {
    /// AWS public access key.
    pub access_key: String,
    /// AWS secret key.
    pub secret_key: String,
    /// Temporary token issued by AWS service.
    pub token: Option<String>,
    _private: (),
}

impl Credentials {
    /// Initialize Credentials directly with key ID, secret key, and optional
    /// token.
    pub fn new(access_key: Option<String>, secret_key: Option<String>, token: Option<String>, profile: Option<String>) -> Credentials {
        let credentials = match access_key {
            Some(key) => match secret_key {
                Some(secret) => {
                    match token {
                        Some(t) => {
                            Some(Credentials {
                                access_key: key,
                                secret_key: secret,
                                token: Some(t),
                                _private: (),
                            })
                        }
                        None => {
                            Some(Credentials {
                                access_key: key,
                                secret_key: secret,
                                token: None,
                                _private: (),
                            })
                        }
                    }
                }
                None => None
            }
            None => None
        };
        match credentials {
            Some(c) => c,
            None => match Credentials::from_env() {
                Ok(c) => c,
                Err(_) => match Credentials::from_profile(profile) {
                    Ok(c) => c,
                    Err(_) => match Credentials::from_instance_metadata() {
                        Ok(c) => c,
                        Err(e) => panic!("No credentials provided as arguments, in the environment or in the profile file. \n {}", e)
                    }
                }
            }
        }
    }

    fn from_env() -> S3Result<Credentials> {
        let access_key = env::var("AWS_ACCESS_KEY_ID")?;
        let secret_key = env::var("AWS_SECRET_ACCESS_KEY")?;
        let token = match env::var("AWS_SESSION_TOKEN") {
            Ok(x) => Some(x),
            Err(_) => None
        };
        Ok(Credentials { access_key, secret_key, token, _private: () })
    }

    fn from_instance_metadata() -> S3Result<Credentials> {
        let resp: HashMap<String, String> = reqwest::get("http://169.254.169.254/latest/meta-data/iam/info")?
            .json()?;
        let credentials = if let Some(arn) = resp.get("InstanceProfileArn") {
            if let Some(role) = arn.split('/').last() {
                let resp: HashMap<String, String> = reqwest::get(&format!("http://169.254.169.254/latest/meta-data/iam/security-credentials/{}", role))?
                    .json()?;
                let access_key = resp.get("AccessKeyId").unwrap().clone();
                let secret_key = resp.get("SecretAccessKey").unwrap().clone();
                let token = Some(resp.get("Token").unwrap().clone());
                Some(Credentials { access_key, secret_key, token, _private: ()})
            } else {
                None
            }
        } else {
            None
        };

        Ok(credentials.unwrap())
    }

    pub fn from_profile(section: Option<String>) -> S3Result<Credentials> {
        let home_dir = match dirs::home_dir() {
            Some(path) => Ok(path),
            None => Err(S3Error::from("Invalid home dir")),
        };
        let profile = format!("{}/.aws/credentials", home_dir?.display());
        let conf = Ini::load_from_file(&profile)?;
        let section = match section {
            Some(s) => s,
            None => String::from("default")
        };
        let data1 = match conf.section(Some(section.clone())) {
            Some(d) => Ok(d),
            None => Err(S3Error::from("Missing aws section"))
        };
        let data2 = match conf.section(Some(section.clone())) {
            Some(d) => Ok(d),
            None => Err(S3Error::from("Missing aws section"))
        };
        let access_key = match data1?.get("aws_access_key_id") {
            Some(x) => Ok(x.to_owned()),
            None => Err(S3Error::from("Missing aws_access_key_id section"))
        };
        let secret_key = match data2?.get("aws_secret_access_key") {
            Some(x) => Ok(x.to_owned()),
            None => Err(S3Error::from("Missing aws_secret_access_key section"))
        };
        Ok(Credentials { access_key: access_key?.to_owned(), secret_key: secret_key?.to_owned(), token: None, _private: () })
    }
}

impl Default for Credentials {
    fn default() -> Self {
        Credentials::new(None, None, None, None)
    }
}
<commit_msg>Pull aws_security_token from credentials file<commit_after>use std::env;
use dirs;
use ini::Ini;
use error::{S3Result, S3Error};
use std::collections::HashMap;

/// AWS access credentials: access key, secret key, and optional token.
///
/// # Example
///
/// Loads from the standard AWS credentials file with the given profile name,
/// defaults to "default".
///
/// ```no_run
/// # // Do not execute this as it would cause unit tests to attempt to access
/// # // real user credentials.
/// use s3::credentials::Credentials;
///
/// // Load credentials from `[default]` profile
/// let credentials = Credentials::default();
///
/// // Also loads credentials from `[default]` profile
/// let credentials = Credentials::new(None, None, None, None);
///
/// // Load credentials from `[my-profile]` profile
/// let credentials = Credentials::new(None, None, None, Some("my-profile".into()));
/// ```
///
/// Credentials may also be initialized directly or by the following environment variables:
///
///   - `AWS_ACCESS_KEY_ID`,
///   - `AWS_SECRET_ACCESS_KEY`
///   - `AWS_SESSION_TOKEN`
///
/// The order of preference is arguments, then environment, and finally AWS
/// credentials file.
///
/// ```
/// use s3::credentials::Credentials;
///
/// // Load credentials directly
/// let access_key = String::from("AKIAIOSFODNN7EXAMPLE");
/// let secret_key = String::from("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
/// let credentials = Credentials::new(Some(access_key), Some(secret_key), None, None);
///
/// // Load credentials from the environment
/// use std::env;
/// env::set_var("AWS_ACCESS_KEY_ID", "AKIAIOSFODNN7EXAMPLE");
/// env::set_var("AWS_SECRET_ACCESS_KEY", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");
/// let credentials = Credentials::new(None, None, None, None);
/// ```
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Credentials {
    /// AWS public access key.
    pub access_key: String,
    /// AWS secret key.
    pub secret_key: String,
    /// Temporary token issued by AWS service.
    pub token: Option<String>,
    _private: (),
}

impl Credentials {
    /// Initialize Credentials directly with key ID, secret key, and optional
    /// token.
    pub fn new(access_key: Option<String>, secret_key: Option<String>, token: Option<String>, profile: Option<String>) -> Credentials {
        let credentials = match access_key {
            Some(key) => match secret_key {
                Some(secret) => {
                    match token {
                        Some(t) => {
                            Some(Credentials {
                                access_key: key,
                                secret_key: secret,
                                token: Some(t),
                                _private: (),
                            })
                        }
                        None => {
                            Some(Credentials {
                                access_key: key,
                                secret_key: secret,
                                token: None,
                                _private: (),
                            })
                        }
                    }
                }
                None => None
            }
            None => None
        };
        match credentials {
            Some(c) => c,
            None => match Credentials::from_env() {
                Ok(c) => c,
                Err(_) => match Credentials::from_profile(profile) {
                    Ok(c) => c,
                    Err(_) => match Credentials::from_instance_metadata() {
                        Ok(c) => c,
                        Err(e) => panic!("No credentials provided as arguments, in the environment or in the profile file. \n {}", e)
                    }
                }
            }
        }
    }

    fn from_env() -> S3Result<Credentials> {
        let access_key = env::var("AWS_ACCESS_KEY_ID")?;
        let secret_key = env::var("AWS_SECRET_ACCESS_KEY")?;
        let token = match env::var("AWS_SESSION_TOKEN") {
            Ok(x) => Some(x),
            Err(_) => None
        };
        Ok(Credentials { access_key, secret_key, token, _private: () })
    }

    fn from_instance_metadata() -> S3Result<Credentials> {
        let resp: HashMap<String, String> = reqwest::get("http://169.254.169.254/latest/meta-data/iam/info")?
            .json()?;
        let credentials = if let Some(arn) = resp.get("InstanceProfileArn") {
            if let Some(role) = arn.split('/').last() {
                let resp: HashMap<String, String> = reqwest::get(&format!("http://169.254.169.254/latest/meta-data/iam/security-credentials/{}", role))?
                    .json()?;
                let access_key = resp.get("AccessKeyId").unwrap().clone();
                let secret_key = resp.get("SecretAccessKey").unwrap().clone();
                let token = Some(resp.get("Token").unwrap().clone());
                Some(Credentials { access_key, secret_key, token, _private: ()})
            } else {
                None
            }
        } else {
            None
        };

        Ok(credentials.unwrap())
    }

    pub fn from_profile(section: Option<String>) -> S3Result<Credentials> {
        let home_dir = match dirs::home_dir() {
            Some(path) => Ok(path),
            None => Err(S3Error::from("Invalid home dir")),
        };
        let profile = format!("{}/.aws/credentials", home_dir?.display());
        let conf = Ini::load_from_file(&profile)?;
        let section = match section {
            Some(s) => s,
            None => String::from("default")
        };
        let mut access_key = Err(S3Error::from("Missing aws_access_key_id section"));
        let mut secret_key = Err(S3Error::from("Missing aws_secret_access_key section"));
        let mut token = None;
        if let Some(data) = conf.section(Some(section)) {
            access_key = match data.get("aws_access_key_id") {
                Some(x) => Ok(x.to_owned()),
                None => Err(S3Error::from("Missing aws_access_key_id section"))
            };
            secret_key = match data.get("aws_secret_access_key") {
                Some(x) => Ok(x.to_owned()),
                None => Err(S3Error::from("Missing aws_secret_access_key section"))
            };
            token = match data.get("aws_security_token") {
                Some(x) => Some(x.to_owned()),
                None => None
            }
        }

        Ok(Credentials { access_key: access_key?.to_owned(), secret_key: secret_key?.to_owned(), token, _private: () })
    }
}

impl Default for Credentials {
    fn default() -> Self {
        Credentials::new(None, None, None, None)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use crate::gpio::{
    interrupt::{AsyncInterrupt, EventLoop},
    mem::GpioMem,
    Level, Mode,
    PullUpDown::{self, *},
    Result, Trigger, PINS_TAKEN,
};

// Maximum GPIO pins on the BCM2835. The actual number of pins
// exposed through the Pi's GPIO header depends on the model.
pub const MAX: usize = 54;

/// Unconfigured GPIO pin.
#[derive(Debug)]
pub struct Pin {
    pub(crate) pin: u8,
    event_loop: Arc<Mutex<EventLoop>>,
    gpio_mem: Arc<GpioMem>,
    gpio_cdev: Arc<File>,
}

impl Pin {
    #[inline]
    pub(crate) fn new(
        pin: u8,
        event_loop: Arc<Mutex<EventLoop>>,
        gpio_mem: Arc<GpioMem>,
        gpio_cdev: Arc<File>,
    ) -> Pin {
        Pin {
            pin,
            event_loop,
            gpio_mem,
            gpio_cdev,
        }
    }

    /// Consumes the pin, returns an [`InputPin`] and sets its mode to [`Mode::Input`].
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    #[inline]
    pub fn into_input(self) -> InputPin {
        InputPin::new(self, Off)
    }

    /// Additionally to `into_input`, activates the pin's pull-up resistor.
    #[inline]
    pub fn into_input_pullup(self) -> InputPin {
        InputPin::new(self, PullUp)
    }

    /// Additionally to `into_input`, activates the pin's pull-down resistor.
    #[inline]
    pub fn into_input_pulldown(self) -> InputPin {
        InputPin::new(self, PullDown)
    }

    /// Consumes the pin, returns an [`OutputPin`] and sets its mode to [`Mode::Output`].
    ///
    /// [`OutputPin`]: struct.OutputPin.html
    /// [`Mode::Output`]: enum.Mode.html#variant.Output
    #[inline]
    pub fn into_output(self) -> OutputPin {
        OutputPin::new(self)
    }

    /// Consumes the pin, returns an [`AltPin`] and sets its mode to the given mode.
    ///
    /// [`AltPin`]: struct.AltPin.html
    /// [`Mode`]: enum.Mode.html
    #[inline]
    pub fn into_alt(self, mode: Mode) -> AltPin {
        AltPin::new(self, mode)
    }

    #[inline]
    pub(crate) fn set_mode(&mut self, mode: Mode) {
        (*self.gpio_mem).set_mode(self.pin, mode);
    }

    /// Returns the current GPIO pin mode.
    #[inline]
    pub fn mode(&self) -> Mode {
        (*self.gpio_mem).mode(self.pin)
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    #[inline]
    pub(crate) fn set_pullupdown(&self, pud: PullUpDown) {
        (*self.gpio_mem).set_pullupdown(self.pin, pud);
    }

    /// Reads the pin's current logic level.
    #[inline]
    pub fn read(&self) -> Level {
        (*self.gpio_mem).level(self.pin)
    }

    #[inline]
    pub(crate) fn set_low(&mut self) {
        (*self.gpio_mem).set_low(self.pin);
    }

    #[inline]
    pub(crate) fn set_high(&mut self) {
        (*self.gpio_mem).set_high(self.pin);
    }

    #[inline]
    pub(crate) fn write(&mut self, level: Level) {
        match level {
            Level::Low => self.set_low(),
            Level::High => self.set_high(),
        };
    }
}

impl Drop for Pin {
    fn drop(&mut self) {
        // Release taken pin
        PINS_TAKEN[self.pin as usize].store(false, Ordering::SeqCst);
    }
}

macro_rules! impl_input {
    () => {
        /// Reads the pin's current logic level.
        #[inline]
        pub fn read(&self) -> Level {
            self.pin.read()
        }
    }
}

macro_rules! impl_output {
    () => {
        /// Sets pin's logic level to low.
        #[inline]
        pub fn set_low(&mut self) {
            self.pin.set_low()
        }

        /// Sets pin's logic level to high.
        #[inline]
        pub fn set_high(&mut self) {
            self.pin.set_high()
        }

        /// Sets pin's logic level.
        #[inline]
        pub fn write(&mut self, level: Level) {
            self.pin.write(level)
        }
    }
}

macro_rules! impl_clear_on_drop {
    () => {
        /// Returns the value of `clear_on_drop`.
        pub fn clear_on_drop(&self) -> bool {
            self.clear_on_drop
        }

        /// When enabled, resets pin's mode to its original state when it goes out of scope.
        /// By default, this is set to `true`.
        ///
        /// # Note
        ///
        /// Drop methods aren't called when a program is abnormally terminated, for
        /// instance when a user presses Ctrl + C, and the `SIGINT` signal
        /// isn't caught. You catch those using crates such as [`simple_signal`].
        ///
        /// [`simple_signal`]: https://crates.io/crates/simple-signal
        /// [`cleanup`]: #method.cleanup
        pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
            self.clear_on_drop = clear_on_drop;
        }
    };
}

macro_rules! impl_drop {
    ($struct:ident) => {
        impl Drop for $struct {
            /// Resets the pin's mode if `clear_on_drop` is set to `true` (default).
            fn drop(&mut self) {
                if !self.clear_on_drop {
                    return;
                }

                if let Some(prev_mode) = self.prev_mode {
                    self.pin.set_mode(prev_mode)
                }
            }
        }
    };
}

/// GPIO pin configured as input.
#[derive(Debug)]
pub struct InputPin {
    pub(crate) pin: Pin,
    prev_mode: Option<Mode>,
    async_interrupt: Option<AsyncInterrupt>,
    clear_on_drop: bool,
}

impl InputPin {
    pub(crate) fn new(mut pin: Pin, pud_mode: PullUpDown) -> InputPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Input {
            None
        } else {
            pin.set_mode(Mode::Input);
            Some(prev_mode)
        };

        pin.set_pullupdown(pud_mode);

        InputPin {
            pin,
            prev_mode,
            async_interrupt: None,
            clear_on_drop: true,
        }
    }

    impl_input!();

    /// Configures a synchronous interrupt trigger.
    ///
    /// After configuring a synchronous interrupt trigger, you can use
    /// [`poll_interrupt`] to wait for a trigger event.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`poll_interrupt`]: #method.poll_interrupt
    pub fn set_interrupt(&mut self, trigger: Trigger) -> Result<()> {
        self.clear_async_interrupt()?;

        // Each pin can only be configured for a single trigger type
        (*self.pin.event_loop.lock().unwrap()).set_interrupt(self.pin.pin, trigger)
    }

    /// Removes a previously configured synchronous interrupt trigger.
    pub fn clear_interrupt(&mut self) -> Result<()> {
        (*self.pin.event_loop.lock().unwrap()).clear_interrupt(self.pin.pin)
    }

    /// Blocks until an interrupt is triggered on the pin, or until a timeout occurs.
    ///
    /// This only works after the pin has been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// If `reset` is set to `false`, returns immediately if an interrupt trigger event was cached in a
    /// previous call to `poll_interrupt`.
    /// If `reset` is set to `true`, clears any cached interrupt trigger events before polling.
    ///
    /// The `timeout` duration indicates how long the call will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    pub fn poll_interrupt(
        &mut self,
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<Level>> {
        let opt = (*self.pin.event_loop.lock().unwrap()).poll(&[self], reset, timeout)?;

        if let Some(trigger) = opt {
            Ok(Some(trigger.1))
        } else {
            Ok(None)
        }
    }

    /// Configures an asynchronous interrupt trigger, which will execute the callback on a
    /// separate thread when the interrupt is triggered.
    ///
    /// The callback closure or function pointer is called with a single [`Level`] argument.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`Level`]: enum.Level.html
    pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        self.clear_interrupt()?;
        self.clear_async_interrupt()?;

        self.async_interrupt = Some(AsyncInterrupt::new(
            (*self.pin.gpio_cdev).as_raw_fd(),
            self.pin.pin,
            trigger,
            callback,
        )?);

        Ok(())
    }

    /// Removes a previously configured asynchronous interrupt trigger.
    pub fn clear_async_interrupt(&mut self) -> Result<()> {
        if let Some(mut interrupt) = self.async_interrupt.take() {
            interrupt.stop()?;
        }

        Ok(())
    }

    impl_clear_on_drop!();
}

impl_drop!(InputPin);

/// GPIO pin configured as output.
#[derive(Debug)]
pub struct OutputPin {
    pin: Pin,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl OutputPin {
    pub(crate) fn new(mut pin: Pin) -> OutputPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Output {
            None
        } else {
            pin.set_mode(Mode::Output);
            Some(prev_mode)
        };

        OutputPin {
            pin,
            prev_mode,
            clear_on_drop: true,
        }
    }

    impl_input!();
    impl_output!();
    impl_clear_on_drop!();
}

impl_drop!(OutputPin);

/// GPIO pin configured with an alternate function.
#[derive(Debug)]
pub struct AltPin {
    pin: Pin,
    mode: Mode,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl AltPin {
    pub(crate) fn new(mut pin: Pin, mode: Mode) -> AltPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == mode {
            None
        } else {
            pin.set_mode(mode);
            Some(prev_mode)
        };

        AltPin {
            pin,
            mode,
            prev_mode,
            clear_on_drop: true,
        }
    }

    impl_input!();
    impl_output!();
    impl_clear_on_drop!();
}

impl_drop!(AltPin);
<commit_msg>Add is_low() and is_high() convenience methods<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use crate::gpio::{
    interrupt::{AsyncInterrupt, EventLoop},
    mem::GpioMem,
    Level, Mode,
    PullUpDown::{self, *},
    Result, Trigger, PINS_TAKEN,
};

// Maximum GPIO pins on the BCM2835. The actual number of pins
// exposed through the Pi's GPIO header depends on the model.
pub const MAX: usize = 54;

/// Unconfigured GPIO pin.
#[derive(Debug)]
pub struct Pin {
    pub(crate) pin: u8,
    event_loop: Arc<Mutex<EventLoop>>,
    gpio_mem: Arc<GpioMem>,
    gpio_cdev: Arc<File>,
}

impl Pin {
    #[inline]
    pub(crate) fn new(
        pin: u8,
        event_loop: Arc<Mutex<EventLoop>>,
        gpio_mem: Arc<GpioMem>,
        gpio_cdev: Arc<File>,
    ) -> Pin {
        Pin {
            pin,
            event_loop,
            gpio_mem,
            gpio_cdev,
        }
    }

    /// Consumes the pin, returns an [`InputPin`] and sets its mode to [`Mode::Input`].
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    #[inline]
    pub fn into_input(self) -> InputPin {
        InputPin::new(self, Off)
    }

    /// Additionally to `into_input`, activates the pin's pull-up resistor.
    #[inline]
    pub fn into_input_pullup(self) -> InputPin {
        InputPin::new(self, PullUp)
    }

    /// Additionally to `into_input`, activates the pin's pull-down resistor.
    #[inline]
    pub fn into_input_pulldown(self) -> InputPin {
        InputPin::new(self, PullDown)
    }

    /// Consumes the pin, returns an [`OutputPin`] and sets its mode to [`Mode::Output`].
    ///
    /// [`OutputPin`]: struct.OutputPin.html
    /// [`Mode::Output`]: enum.Mode.html#variant.Output
    #[inline]
    pub fn into_output(self) -> OutputPin {
        OutputPin::new(self)
    }

    /// Consumes the pin, returns an [`AltPin`] and sets its mode to the given mode.
    ///
    /// [`AltPin`]: struct.AltPin.html
    /// [`Mode`]: enum.Mode.html
    #[inline]
    pub fn into_alt(self, mode: Mode) -> AltPin {
        AltPin::new(self, mode)
    }

    #[inline]
    pub(crate) fn set_mode(&mut self, mode: Mode) {
        (*self.gpio_mem).set_mode(self.pin, mode);
    }

    /// Returns the current GPIO pin mode.
    #[inline]
    pub fn mode(&self) -> Mode {
        (*self.gpio_mem).mode(self.pin)
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    #[inline]
    pub(crate) fn set_pullupdown(&self, pud: PullUpDown) {
        (*self.gpio_mem).set_pullupdown(self.pin, pud);
    }

    /// Reads the pin's current logic level.
    #[inline]
    pub fn read(&self) -> Level {
        (*self.gpio_mem).level(self.pin)
    }

    #[inline]
    pub(crate) fn set_low(&mut self) {
        (*self.gpio_mem).set_low(self.pin);
    }

    #[inline]
    pub(crate) fn set_high(&mut self) {
        (*self.gpio_mem).set_high(self.pin);
    }

    #[inline]
    pub(crate) fn write(&mut self, level: Level) {
        match level {
            Level::Low => self.set_low(),
            Level::High => self.set_high(),
        };
    }
}

impl Drop for Pin {
    fn drop(&mut self) {
        // Release taken pin
        PINS_TAKEN[self.pin as usize].store(false, Ordering::SeqCst);
    }
}

macro_rules! impl_input {
    () => {
        /// Reads the pin's current logic level.
        #[inline]
        pub fn read(&self) -> Level {
            self.pin.read()
        }

        /// Returns `true` if the pin's logic level is [`Level::Low`].
        ///
        /// [`Level::Low`]: enum.Level.html
        #[inline]
        pub fn is_low(&self) -> bool {
            self.pin.read() == Level::Low
        }

        /// Returns `true` if the pin's logic level is [`Level::High`].
        ///
        /// [`Level::High`]: enum.Level.html
        #[inline]
        pub fn is_high(&self) -> bool {
            self.pin.read() == Level::High
        }
    }
}

macro_rules! impl_output {
    () => {
        /// Sets pin's logic level to low.
        #[inline]
        pub fn set_low(&mut self) {
            self.pin.set_low()
        }

        /// Sets pin's logic level to high.
        #[inline]
        pub fn set_high(&mut self) {
            self.pin.set_high()
        }

        /// Sets pin's logic level.
        #[inline]
        pub fn write(&mut self, level: Level) {
            self.pin.write(level)
        }
    }
}

macro_rules! impl_clear_on_drop {
    () => {
        /// Returns the value of `clear_on_drop`.
        pub fn clear_on_drop(&self) -> bool {
            self.clear_on_drop
        }

        /// When enabled, resets pin's mode to its original state when it goes out of scope.
        /// By default, this is set to `true`.
        ///
        /// # Note
        ///
        /// Drop methods aren't called when a program is abnormally terminated, for
        /// instance when a user presses Ctrl + C, and the `SIGINT` signal
        /// isn't caught. You catch those using crates such as [`simple_signal`].
        ///
        /// [`simple_signal`]: https://crates.io/crates/simple-signal
        /// [`cleanup`]: #method.cleanup
        pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
            self.clear_on_drop = clear_on_drop;
        }
    };
}

macro_rules! impl_drop {
    ($struct:ident) => {
        impl Drop for $struct {
            /// Resets the pin's mode if `clear_on_drop` is set to `true` (default).
            fn drop(&mut self) {
                if !self.clear_on_drop {
                    return;
                }

                if let Some(prev_mode) = self.prev_mode {
                    self.pin.set_mode(prev_mode)
                }
            }
        }
    };
}

/// GPIO pin configured as input.
#[derive(Debug)]
pub struct InputPin {
    pub(crate) pin: Pin,
    prev_mode: Option<Mode>,
    async_interrupt: Option<AsyncInterrupt>,
    clear_on_drop: bool,
}

impl InputPin {
    pub(crate) fn new(mut pin: Pin, pud_mode: PullUpDown) -> InputPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Input {
            None
        } else {
            pin.set_mode(Mode::Input);
            Some(prev_mode)
        };

        pin.set_pullupdown(pud_mode);

        InputPin {
            pin,
            prev_mode,
            async_interrupt: None,
            clear_on_drop: true,
        }
    }

    impl_input!();

    /// Configures a synchronous interrupt trigger.
    ///
    /// After configuring a synchronous interrupt trigger, you can use
    /// [`poll_interrupt`] to wait for a trigger event.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`poll_interrupt`]: #method.poll_interrupt
    pub fn set_interrupt(&mut self, trigger: Trigger) -> Result<()> {
        self.clear_async_interrupt()?;

        // Each pin can only be configured for a single trigger type
        (*self.pin.event_loop.lock().unwrap()).set_interrupt(self.pin.pin, trigger)
    }

    /// Removes a previously configured synchronous interrupt trigger.
    pub fn clear_interrupt(&mut self) -> Result<()> {
        (*self.pin.event_loop.lock().unwrap()).clear_interrupt(self.pin.pin)
    }

    /// Blocks until an interrupt is triggered on the pin, or until a timeout occurs.
    ///
    /// This only works after the pin has been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// If `reset` is set to `false`, returns immediately if an interrupt trigger event was cached in a
    /// previous call to `poll_interrupt`.
    /// If `reset` is set to `true`, clears any cached interrupt trigger events before polling.
    ///
    /// The `timeout` duration indicates how long the call will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    pub fn poll_interrupt(
        &mut self,
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<Level>> {
        let opt = (*self.pin.event_loop.lock().unwrap()).poll(&[self], reset, timeout)?;

        if let Some(trigger) = opt {
            Ok(Some(trigger.1))
        } else {
            Ok(None)
        }
    }

    /// Configures an asynchronous interrupt trigger, which will execute the callback on a
    /// separate thread when the interrupt is triggered.
    ///
    /// The callback closure or function pointer is called with a single [`Level`] argument.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`Level`]: enum.Level.html
    pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        self.clear_interrupt()?;
        self.clear_async_interrupt()?;

        self.async_interrupt = Some(AsyncInterrupt::new(
            (*self.pin.gpio_cdev).as_raw_fd(),
            self.pin.pin,
            trigger,
            callback,
        )?);

        Ok(())
    }

    /// Removes a previously configured asynchronous interrupt trigger.
    pub fn clear_async_interrupt(&mut self) -> Result<()> {
        if let Some(mut interrupt) = self.async_interrupt.take() {
            interrupt.stop()?;
        }

        Ok(())
    }

    impl_clear_on_drop!();
}

impl_drop!(InputPin);

/// GPIO pin configured as output.
#[derive(Debug)]
pub struct OutputPin {
    pin: Pin,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl OutputPin {
    pub(crate) fn new(mut pin: Pin) -> OutputPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Output {
            None
        } else {
            pin.set_mode(Mode::Output);
            Some(prev_mode)
        };

        OutputPin {
            pin,
            prev_mode,
            clear_on_drop: true,
        }
    }

    impl_input!();
    impl_output!();
    impl_clear_on_drop!();
}

impl_drop!(OutputPin);

/// GPIO pin configured with an alternate function.
#[derive(Debug)]
pub struct AltPin {
    pin: Pin,
    mode: Mode,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl AltPin {
    pub(crate) fn new(mut pin: Pin, mode: Mode) -> AltPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == mode {
            None
        } else {
            pin.set_mode(mode);
            Some(prev_mode)
        };

        AltPin {
            pin,
            mode,
            prev_mode,
            clear_on_drop: true,
        }
    }

    impl_input!();
    impl_output!();
    impl_clear_on_drop!();
}

impl_drop!(AltPin);
<|endoftext|>


<commit_before>use std::fmt;
use std::sync::Arc;
use std::time::Duration;

use bytes::Bytes;
use futures::{Async, Future, Poll};
use hyper::client::FutureResponse;
use hyper::header::{Headers, Location, Referer, UserAgent, Accept, Encoding,
                    AcceptEncoding, Range, qitem};
use native_tls::{TlsConnector, TlsConnectorBuilder};
use tokio_core::reactor::Handle;

use super::body;
use super::request::{self, Request, RequestBuilder};
use super::response::{self, Response};
use connect::Connector;
use into_url::to_uri;
use redirect::{self, RedirectPolicy, check_redirect, remove_sensitive_headers};
use {Certificate, IntoUrl, Method, proxy, Proxy, StatusCode, Url};

static DEFAULT_USER_AGENT: &'static str =
    concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));

/// An asynchornous `Client` to make Requests with.
#[derive(Clone)]
pub struct Client {
    inner: Arc<ClientRef>,
}

/// A `ClientBuilder` can be used to create a `Client` with  custom configuration:
pub struct ClientBuilder {
    config: Option<Config>,
}

struct Config {
    gzip: bool,
    hostname_verification: bool,
    proxies: Vec<Proxy>,
    redirect_policy: RedirectPolicy,
    referer: bool,
    timeout: Option<Duration>,
    tls: TlsConnectorBuilder,
}

impl ClientBuilder {
    /// Constructs a new `ClientBuilder`
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created.
    pub fn new() -> ::Result<ClientBuilder> {
        let tls_connector_builder = try_!(TlsConnector::builder());
        Ok(ClientBuilder {
            config: Some(Config {
                gzip: true,
                hostname_verification: true,
                proxies: Vec::new(),
                redirect_policy: RedirectPolicy::default(),
                referer: true,
                timeout: None,
                tls: tls_connector_builder,
            })
        })
    }

    /// Returns a `Client` that uses this `ClientBuilder` configuration.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be initialized.
    ///
    /// # Panics
    ///
    /// This method consumes the internal state of the builder.
    /// Trying to use this builder again after calling `build` will panic.
    pub fn build(&mut self, handle: &Handle) -> ::Result<Client> {
        let config = self.take_config();

        let tls = try_!(config.tls.build());

        let proxies = Arc::new(config.proxies);

        let mut connector = Connector::new(tls, proxies.clone(), handle);
        if !config.hostname_verification {
            connector.danger_disable_hostname_verification();
        }

        let hyper_client = ::hyper::Client::configure()
            .connector(connector)
            .build(handle);

        Ok(Client {
            inner: Arc::new(ClientRef {
                gzip: config.gzip,
                hyper: hyper_client,
                proxies: proxies,
                redirect_policy: config.redirect_policy,
                referer: config.referer,
            }),
        })
    }

    /// Add a custom root certificate.
    ///
    /// This can be used to connect to a server that has a self-signed
    /// certificate for example.
    ///
    /// # Errors
    ///
    /// This method fails if adding root certificate was unsuccessful.
    pub fn add_root_certificate(&mut self, cert: Certificate) -> ::Result<&mut ClientBuilder> {
        let cert = ::tls::cert(cert);
        try_!(self.config_mut().tls.add_root_certificate(cert));
        Ok(self)
    }

    /// Disable hostname verification.
    ///
    /// # Warning
    ///
    /// You should think very carefully before you use this method. If
    /// hostname verification is not used, any valid certificate for any
    /// site will be trusted for use from any other. This introduces a
    /// significant vulnerability to man-in-the-middle attacks.
    #[inline]
    pub fn danger_disable_hostname_verification(&mut self) -> &mut ClientBuilder {
        self.config_mut().hostname_verification = false;
        self
    }

    /// Enable hostname verification.
    #[inline]
    pub fn enable_hostname_verification(&mut self) -> &mut ClientBuilder {
        self.config_mut().hostname_verification = true;
        self
    }

    /// Enable auto gzip decompression by checking the ContentEncoding response header.
    ///
    /// Default is enabled.
    #[inline]
    pub fn gzip(&mut self, enable: bool) -> &mut ClientBuilder {
        self.config_mut().gzip = enable;
        self
    }

    /// Add a `Proxy` to the list of proxies the `Client` will use.
    #[inline]
    pub fn proxy(&mut self, proxy: Proxy) -> &mut ClientBuilder {
        self.config_mut().proxies.push(proxy);
        self
    }

    /// Set a `RedirectPolicy` for this client.
    ///
    /// Default will follow redirects up to a maximum of 10.
    #[inline]
    pub fn redirect(&mut self, policy: RedirectPolicy) -> &mut ClientBuilder {
        self.config_mut().redirect_policy = policy;
        self
    }

    /// Enable or disable automatic setting of the `Referer` header.
    ///
    /// Default is `true`.
    #[inline]
    pub fn referer(&mut self, enable: bool) -> &mut ClientBuilder {
        self.config_mut().referer = enable;
        self
    }

    /// Set a timeout for both the read and write operations of a client.
    #[inline]
    pub fn timeout(&mut self, timeout: Duration) -> &mut ClientBuilder {
        self.config_mut().timeout = Some(timeout);
        self
    }

    // private
    fn config_mut(&mut self) -> &mut Config {
        self.config
            .as_mut()
            .expect("ClientBuilder cannot be reused after building a Client")
    }

    fn take_config(&mut self) -> Config {
        self.config
            .take()
            .expect("ClientBuilder cannot be reused after building a Client")
    }
}

type HyperClient = ::hyper::Client<Connector>;

fn create_hyper_client(tls: TlsConnector, proxies: Arc<Vec<Proxy>>, handle: &Handle) -> HyperClient {
    ::hyper::Client::configure()
        .connector(Connector::new(tls, proxies, handle))
        .build(handle)
}

impl Client {
    /// Constructs a new `Client`.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created or initialized.
    #[inline]
    pub fn new(handle: &Handle) -> ::Result<Client> {
        ClientBuilder::new()?.build(handle)
    }

    /// Creates a `ClientBuilder` to configure a `Client`.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created.
    #[inline]
    pub fn builder() -> ::Result<ClientBuilder> {
        ClientBuilder::new()
    }

    /// Convenience method to make a `GET` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn get<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Get, url)
    }

    /// Convenience method to make a `POST` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn post<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Post, url)
    }

    /// Convenience method to make a `PUT` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn put<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Put, url)
    }

    /// Convenience method to make a `PATCH` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn patch<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Patch, url)
    }

    /// Convenience method to make a `DELETE` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn delete<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Delete, url)
    }

    /// Convenience method to make a `HEAD` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn head<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Head, url)
    }

    /// Start building a `Request` with the `Method` and `Url`.
    ///
    /// Returns a `RequestBuilder`, which will allow setting headers and
    /// request body before sending.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> ::Result<RequestBuilder> {
        let url = try_!(url.into_url());
        Ok(request::builder(self.clone(), Request::new(method, url)))
    }

    /// Executes a `Request`.
    ///
    /// A `Request` can be built manually with `Request::new()` or obtained
    /// from a RequestBuilder with `RequestBuilder::build()`.
    ///
    /// You should prefer to use the `RequestBuilder` and
    /// `RequestBuilder::send()`.
    ///
    /// # Errors
    ///
    /// This method fails if there was an error while sending request,
    /// redirect loop was detected or redirect limit was exhausted.
    pub fn execute(&self, request: Request) -> Pending {
        self.execute_request(request)
    }

    fn execute_request(&self, req: Request) -> Pending {
        let (
            method,
            url,
            mut headers,
            body
        ) = request::pieces(req);

        if !headers.has::<UserAgent>() {
            headers.set(UserAgent::new(DEFAULT_USER_AGENT));
        }

        if !headers.has::<Accept>() {
            headers.set(Accept::star());
        }
        if self.inner.gzip &&
            !headers.has::<AcceptEncoding>() &&
            !headers.has::<Range>() {
            headers.set(AcceptEncoding(vec![qitem(Encoding::Gzip)]));
        }

        let uri = to_uri(&url);
        let mut req = ::hyper::Request::new(method.clone(), uri.clone());
        *req.headers_mut() = headers.clone();
        let body = body.and_then(|body| {
            let (resuable, body) = body::into_hyper(body);
            req.set_body(body);
            resuable
        });

        if proxy::is_proxied(&self.inner.proxies, &uri) {
            req.set_proxy(true);
        }

        let in_flight = self.inner.hyper.request(req);

        Pending {
            method: method,
            url: url,
            headers: headers,
            body: body,

            urls: Vec::new(),

            client: self.inner.clone(),

            in_flight: in_flight,
        }
    }
}

impl fmt::Debug for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Client")
            .field("gzip", &self.inner.gzip)
            .field("redirect_policy", &self.inner.redirect_policy)
            .field("referer", &self.inner.referer)
            .finish()
    }
}

impl fmt::Debug for ClientBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ClientBuilder")
            .finish()
    }
}

struct ClientRef {
    gzip: bool,
    hyper: HyperClient,
    proxies: Arc<Vec<Proxy>>,
    redirect_policy: RedirectPolicy,
    referer: bool,
}

pub struct Pending {
    method: Method,
    url: Url,
    headers: Headers,
    body: Option<Bytes>,

    urls: Vec<Url>,

    client: Arc<ClientRef>,

    in_flight: FutureResponse,
}

impl Future for Pending {
    type Item = Response;
    type Error = ::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let res = match try_!(self.in_flight.poll(), &self.url) {
                Async::Ready(res) => res,
                Async::NotReady => return Ok(Async::NotReady),
            };
            let should_redirect = match res.status() {
                StatusCode::MovedPermanently |
                StatusCode::Found |
                StatusCode::SeeOther => {
                    self.body = None;
                    match self.method {
                        Method::Get | Method::Head => {},
                        _ => {
                            self.method = Method::Get;
                        }
                    }
                    true
                },
                StatusCode::TemporaryRedirect |
                StatusCode::PermanentRedirect => {
                    self.body.is_some()
                },
                _ => false,
            };
            if should_redirect {
                let loc = res.headers()
                    .get::<Location>()
                    .map(|loc| self.url.join(loc));
                if let Some(Ok(loc)) = loc {
                    if self.client.referer {
                        if let Some(referer) = make_referer(&loc, &self.url) {
                            self.headers.set(referer);
                        }
                    }
                    self.urls.push(self.url.clone());
                    let action = check_redirect(&self.client.redirect_policy, &loc, &self.urls);

                    match action {
                        redirect::Action::Follow => {
                            self.url = loc;

                            remove_sensitive_headers(&mut self.headers, &self.url, &self.urls);
                            debug!("redirecting to {:?} '{}'", self.method, self.url);
                            let uri = to_uri(&self.url);
                            let mut req = ::hyper::Request::new(
                                self.method.clone(),
                                uri.clone()
                            );
                            *req.headers_mut() = self.headers.clone();
                            if let Some(ref body) = self.body {
                                req.set_body(body.clone());
                            }
                            if proxy::is_proxied(&self.client.proxies, &uri) {
                                req.set_proxy(true);
                            }
                            self.in_flight = self.client.hyper.request(req);
                            continue;
                        },
                        redirect::Action::Stop => {
                            debug!("redirect_policy disallowed redirection to '{}'", loc);
                        },
                        redirect::Action::LoopDetected => {
                            return Err(::error::loop_detected(self.url.clone()));
                        },
                        redirect::Action::TooManyRedirects => {
                            return Err(::error::too_many_redirects(self.url.clone()));
                        }
                    }
                } else if let Some(Err(e)) = loc {
                    debug!("Location header had invalid URI: {:?}", e);
                }
            }
            let res = response::new(res, self.url.clone(), self.client.gzip);
            return Ok(Async::Ready(res));
        }
    }
}

impl fmt::Debug for Pending {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pending")
            .field("method", &self.method)
            .field("url", &self.url)
            .finish()
    }
}

fn make_referer(next: &Url, previous: &Url) -> Option<Referer> {
    if next.scheme() == "http" && previous.scheme() == "https" {
        return None;
    }

    let mut referer = previous.clone();
    let _ = referer.set_username("");
    let _ = referer.set_password(None);
    referer.set_fragment(None);
    Some(Referer::new(referer.into_string()))
}

// pub(crate)

pub fn take_builder(builder: &mut ClientBuilder) -> ClientBuilder {
    use std::mem;
    mem::replace(builder, ClientBuilder { config: None })
}
<commit_msg>do not set_proxy() for https requests<commit_after>use std::fmt;
use std::sync::Arc;
use std::time::Duration;

use bytes::Bytes;
use futures::{Async, Future, Poll};
use hyper::client::FutureResponse;
use hyper::header::{Headers, Location, Referer, UserAgent, Accept, Encoding,
                    AcceptEncoding, Range, qitem};
use native_tls::{TlsConnector, TlsConnectorBuilder};
use tokio_core::reactor::Handle;

use super::body;
use super::request::{self, Request, RequestBuilder};
use super::response::{self, Response};
use connect::Connector;
use into_url::to_uri;
use redirect::{self, RedirectPolicy, check_redirect, remove_sensitive_headers};
use {Certificate, IntoUrl, Method, proxy, Proxy, StatusCode, Url};

static DEFAULT_USER_AGENT: &'static str =
    concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));

/// An asynchornous `Client` to make Requests with.
#[derive(Clone)]
pub struct Client {
    inner: Arc<ClientRef>,
}

/// A `ClientBuilder` can be used to create a `Client` with  custom configuration:
pub struct ClientBuilder {
    config: Option<Config>,
}

struct Config {
    gzip: bool,
    hostname_verification: bool,
    proxies: Vec<Proxy>,
    redirect_policy: RedirectPolicy,
    referer: bool,
    timeout: Option<Duration>,
    tls: TlsConnectorBuilder,
}

impl ClientBuilder {
    /// Constructs a new `ClientBuilder`
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created.
    pub fn new() -> ::Result<ClientBuilder> {
        let tls_connector_builder = try_!(TlsConnector::builder());
        Ok(ClientBuilder {
            config: Some(Config {
                gzip: true,
                hostname_verification: true,
                proxies: Vec::new(),
                redirect_policy: RedirectPolicy::default(),
                referer: true,
                timeout: None,
                tls: tls_connector_builder,
            })
        })
    }

    /// Returns a `Client` that uses this `ClientBuilder` configuration.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be initialized.
    ///
    /// # Panics
    ///
    /// This method consumes the internal state of the builder.
    /// Trying to use this builder again after calling `build` will panic.
    pub fn build(&mut self, handle: &Handle) -> ::Result<Client> {
        let config = self.take_config();

        let tls = try_!(config.tls.build());

        let proxies = Arc::new(config.proxies);

        let mut connector = Connector::new(tls, proxies.clone(), handle);
        if !config.hostname_verification {
            connector.danger_disable_hostname_verification();
        }

        let hyper_client = ::hyper::Client::configure()
            .connector(connector)
            .build(handle);

        Ok(Client {
            inner: Arc::new(ClientRef {
                gzip: config.gzip,
                hyper: hyper_client,
                proxies: proxies,
                redirect_policy: config.redirect_policy,
                referer: config.referer,
            }),
        })
    }

    /// Add a custom root certificate.
    ///
    /// This can be used to connect to a server that has a self-signed
    /// certificate for example.
    ///
    /// # Errors
    ///
    /// This method fails if adding root certificate was unsuccessful.
    pub fn add_root_certificate(&mut self, cert: Certificate) -> ::Result<&mut ClientBuilder> {
        let cert = ::tls::cert(cert);
        try_!(self.config_mut().tls.add_root_certificate(cert));
        Ok(self)
    }

    /// Disable hostname verification.
    ///
    /// # Warning
    ///
    /// You should think very carefully before you use this method. If
    /// hostname verification is not used, any valid certificate for any
    /// site will be trusted for use from any other. This introduces a
    /// significant vulnerability to man-in-the-middle attacks.
    #[inline]
    pub fn danger_disable_hostname_verification(&mut self) -> &mut ClientBuilder {
        self.config_mut().hostname_verification = false;
        self
    }

    /// Enable hostname verification.
    #[inline]
    pub fn enable_hostname_verification(&mut self) -> &mut ClientBuilder {
        self.config_mut().hostname_verification = true;
        self
    }

    /// Enable auto gzip decompression by checking the ContentEncoding response header.
    ///
    /// Default is enabled.
    #[inline]
    pub fn gzip(&mut self, enable: bool) -> &mut ClientBuilder {
        self.config_mut().gzip = enable;
        self
    }

    /// Add a `Proxy` to the list of proxies the `Client` will use.
    #[inline]
    pub fn proxy(&mut self, proxy: Proxy) -> &mut ClientBuilder {
        self.config_mut().proxies.push(proxy);
        self
    }

    /// Set a `RedirectPolicy` for this client.
    ///
    /// Default will follow redirects up to a maximum of 10.
    #[inline]
    pub fn redirect(&mut self, policy: RedirectPolicy) -> &mut ClientBuilder {
        self.config_mut().redirect_policy = policy;
        self
    }

    /// Enable or disable automatic setting of the `Referer` header.
    ///
    /// Default is `true`.
    #[inline]
    pub fn referer(&mut self, enable: bool) -> &mut ClientBuilder {
        self.config_mut().referer = enable;
        self
    }

    /// Set a timeout for both the read and write operations of a client.
    #[inline]
    pub fn timeout(&mut self, timeout: Duration) -> &mut ClientBuilder {
        self.config_mut().timeout = Some(timeout);
        self
    }

    // private
    fn config_mut(&mut self) -> &mut Config {
        self.config
            .as_mut()
            .expect("ClientBuilder cannot be reused after building a Client")
    }

    fn take_config(&mut self) -> Config {
        self.config
            .take()
            .expect("ClientBuilder cannot be reused after building a Client")
    }
}

type HyperClient = ::hyper::Client<Connector>;

fn create_hyper_client(tls: TlsConnector, proxies: Arc<Vec<Proxy>>, handle: &Handle) -> HyperClient {
    ::hyper::Client::configure()
        .connector(Connector::new(tls, proxies, handle))
        .build(handle)
}

impl Client {
    /// Constructs a new `Client`.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created or initialized.
    #[inline]
    pub fn new(handle: &Handle) -> ::Result<Client> {
        ClientBuilder::new()?.build(handle)
    }

    /// Creates a `ClientBuilder` to configure a `Client`.
    ///
    /// # Errors
    ///
    /// This method fails if native TLS backend cannot be created.
    #[inline]
    pub fn builder() -> ::Result<ClientBuilder> {
        ClientBuilder::new()
    }

    /// Convenience method to make a `GET` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn get<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Get, url)
    }

    /// Convenience method to make a `POST` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn post<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Post, url)
    }

    /// Convenience method to make a `PUT` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn put<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Put, url)
    }

    /// Convenience method to make a `PATCH` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn patch<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Patch, url)
    }

    /// Convenience method to make a `DELETE` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn delete<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Delete, url)
    }

    /// Convenience method to make a `HEAD` request to a URL.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn head<U: IntoUrl>(&self, url: U) -> ::Result<RequestBuilder> {
        self.request(Method::Head, url)
    }

    /// Start building a `Request` with the `Method` and `Url`.
    ///
    /// Returns a `RequestBuilder`, which will allow setting headers and
    /// request body before sending.
    ///
    /// # Errors
    ///
    /// This method fails whenever supplied `Url` cannot be parsed.
    pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> ::Result<RequestBuilder> {
        let url = try_!(url.into_url());
        Ok(request::builder(self.clone(), Request::new(method, url)))
    }

    /// Executes a `Request`.
    ///
    /// A `Request` can be built manually with `Request::new()` or obtained
    /// from a RequestBuilder with `RequestBuilder::build()`.
    ///
    /// You should prefer to use the `RequestBuilder` and
    /// `RequestBuilder::send()`.
    ///
    /// # Errors
    ///
    /// This method fails if there was an error while sending request,
    /// redirect loop was detected or redirect limit was exhausted.
    pub fn execute(&self, request: Request) -> Pending {
        self.execute_request(request)
    }

    fn execute_request(&self, req: Request) -> Pending {
        let (
            method,
            url,
            mut headers,
            body
        ) = request::pieces(req);

        if !headers.has::<UserAgent>() {
            headers.set(UserAgent::new(DEFAULT_USER_AGENT));
        }

        if !headers.has::<Accept>() {
            headers.set(Accept::star());
        }
        if self.inner.gzip &&
            !headers.has::<AcceptEncoding>() &&
            !headers.has::<Range>() {
            headers.set(AcceptEncoding(vec![qitem(Encoding::Gzip)]));
        }

        let uri = to_uri(&url);
        let mut req = ::hyper::Request::new(method.clone(), uri.clone());
        *req.headers_mut() = headers.clone();
        let body = body.and_then(|body| {
            let (resuable, body) = body::into_hyper(body);
            req.set_body(body);
            resuable
        });

        if proxy::is_proxied(&self.inner.proxies, &uri) {
            if uri.scheme() == Some("http") {
                req.set_proxy(true);
            }
        }

        let in_flight = self.inner.hyper.request(req);

        Pending {
            method: method,
            url: url,
            headers: headers,
            body: body,

            urls: Vec::new(),

            client: self.inner.clone(),

            in_flight: in_flight,
        }
    }
}

impl fmt::Debug for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Client")
            .field("gzip", &self.inner.gzip)
            .field("redirect_policy", &self.inner.redirect_policy)
            .field("referer", &self.inner.referer)
            .finish()
    }
}

impl fmt::Debug for ClientBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ClientBuilder")
            .finish()
    }
}

struct ClientRef {
    gzip: bool,
    hyper: HyperClient,
    proxies: Arc<Vec<Proxy>>,
    redirect_policy: RedirectPolicy,
    referer: bool,
}

pub struct Pending {
    method: Method,
    url: Url,
    headers: Headers,
    body: Option<Bytes>,

    urls: Vec<Url>,

    client: Arc<ClientRef>,

    in_flight: FutureResponse,
}

impl Future for Pending {
    type Item = Response;
    type Error = ::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let res = match try_!(self.in_flight.poll(), &self.url) {
                Async::Ready(res) => res,
                Async::NotReady => return Ok(Async::NotReady),
            };
            let should_redirect = match res.status() {
                StatusCode::MovedPermanently |
                StatusCode::Found |
                StatusCode::SeeOther => {
                    self.body = None;
                    match self.method {
                        Method::Get | Method::Head => {},
                        _ => {
                            self.method = Method::Get;
                        }
                    }
                    true
                },
                StatusCode::TemporaryRedirect |
                StatusCode::PermanentRedirect => {
                    self.body.is_some()
                },
                _ => false,
            };
            if should_redirect {
                let loc = res.headers()
                    .get::<Location>()
                    .map(|loc| self.url.join(loc));
                if let Some(Ok(loc)) = loc {
                    if self.client.referer {
                        if let Some(referer) = make_referer(&loc, &self.url) {
                            self.headers.set(referer);
                        }
                    }
                    self.urls.push(self.url.clone());
                    let action = check_redirect(&self.client.redirect_policy, &loc, &self.urls);

                    match action {
                        redirect::Action::Follow => {
                            self.url = loc;

                            remove_sensitive_headers(&mut self.headers, &self.url, &self.urls);
                            debug!("redirecting to {:?} '{}'", self.method, self.url);
                            let uri = to_uri(&self.url);
                            let mut req = ::hyper::Request::new(
                                self.method.clone(),
                                uri.clone()
                            );
                            *req.headers_mut() = self.headers.clone();
                            if let Some(ref body) = self.body {
                                req.set_body(body.clone());
                            }
                            if proxy::is_proxied(&self.client.proxies, &uri) {
                                if uri.scheme() == Some("http") {
                                    req.set_proxy(true);
                                }
                            }
                            self.in_flight = self.client.hyper.request(req);
                            continue;
                        },
                        redirect::Action::Stop => {
                            debug!("redirect_policy disallowed redirection to '{}'", loc);
                        },
                        redirect::Action::LoopDetected => {
                            return Err(::error::loop_detected(self.url.clone()));
                        },
                        redirect::Action::TooManyRedirects => {
                            return Err(::error::too_many_redirects(self.url.clone()));
                        }
                    }
                } else if let Some(Err(e)) = loc {
                    debug!("Location header had invalid URI: {:?}", e);
                }
            }
            let res = response::new(res, self.url.clone(), self.client.gzip);
            return Ok(Async::Ready(res));
        }
    }
}

impl fmt::Debug for Pending {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pending")
            .field("method", &self.method)
            .field("url", &self.url)
            .finish()
    }
}

fn make_referer(next: &Url, previous: &Url) -> Option<Referer> {
    if next.scheme() == "http" && previous.scheme() == "https" {
        return None;
    }

    let mut referer = previous.clone();
    let _ = referer.set_username("");
    let _ = referer.set_password(None);
    referer.set_fragment(None);
    Some(Referer::new(referer.into_string()))
}

// pub(crate)

pub fn take_builder(builder: &mut ClientBuilder) -> ClientBuilder {
    use std::mem;
    mem::replace(builder, ClientBuilder { config: None })
}
<|endoftext|>


<commit_before>use std::path::Path;

use sdl2;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::rect::{Point, Rect};
use sdl2::render::{Renderer, RenderTarget, Texture, TextureAccess};
use sdl2_ttf::{self, Font, Sdl2TtfContext};

pub struct Display {
    _text:   Sdl2TtfContext,
    font:   Font,
    screen: Renderer<'static>,
}

impl Display {

    pub fn new(context: &sdl2::Sdl) -> Display {
        // boot the renderer
        let (w,h) = (1280,720);

        let video            = context.video().unwrap();
        let mut window_proto = video.window("koko", w as u32, h as u32);

        let current_mode     = window_proto.position_centered()
                                           .input_grabbed()
                                           .build();

        let window_context = match current_mode {
            Ok(ctx)  => ctx,
            Err(msg) => panic!(msg),
        };

        let renderer = window_context.renderer().build()
            .ok().expect("could not initialize sdl2 rendering context");

        // NOTE: must hide cursor _after_ window is built otherwise it doesn't work.
        context.mouse().show_cursor(false);
        println!("is cursor showing? {}", context.mouse().is_cursor_showing());

        // set up the font stuff
        let textmode = sdl2_ttf::init()
            .ok().expect("could not open ttf font renderer");

        let opensans = textmode.load_font(Path::new("./OpenSans-Regular.ttf"), 18)
            .ok().expect("could not load OpenSans-Regular.ttf from workingdir");

        // strap it all to the graphics subsystem
        Display {
            _text: textmode,
            font: opensans,
            screen: renderer,
        }
    }

    pub fn switch_buffers(&mut self) {
        self.screen.present();
    }

    pub fn clear_buffer(&mut self) {
        let _ = self.screen.clear();
    }

    pub fn blit_text(&mut self, buf: &str, color: Color) {
        let surface = self.font.render(&buf[..])
            .solid(color)
            .ok().expect("could not render text");

        let bounds = surface.rect();
        let texture = self.screen.create_texture_from_surface(surface)
            .ok().expect("could blit font to texture");

        let cursor_block = Rect::new(10,10, bounds.width(),bounds.height());
        self.screen.copy(&texture, None, Some(cursor_block));

    }

    pub fn copy(&mut self, texture: &Texture) {
        self.screen.copy(texture, None, None);
    }

    pub fn copy_t(&mut self, texture: &Texture, src: Rect, dst: Rect) {
        self.screen.copy(texture, Some(src), Some(dst));
    }

    pub fn get_texture(&mut self, width: u32, height: u32) -> Texture {
        self.screen.create_texture(PixelFormatEnum::ARGB8888,
                                   TextureAccess::Target,
                                   width, height)
            .ok().expect("could not open texture")
    }

    pub fn retarget(&mut self) -> RenderTarget {
        self.screen.render_target()
            .expect("renderer does not support arbitrary targets")
    }

    pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: Color)  {
        let previous = self.screen.draw_color();
        self.screen.set_draw_color(color);

        self.screen.draw_line(Point::new(x1,y1), Point::new(x2,y2))
            .ok().expect("could not draw line");

        self.screen.set_draw_color(previous);
    }

    pub fn fill_rect(&mut self, dst: Rect, fill: Color) {
        let previous = self.screen.draw_color();
        let _ = self.screen.set_draw_color(fill);
        let _ = self.screen.fill_rect(dst);
        let _ = self.screen.set_draw_color(previous);

    }

    pub fn read_pixels(&mut self) -> Vec<u8> {
        self.screen.read_pixels(None, PixelFormatEnum::ARGB8888)
            .ok().expect("could not get pixels out of current buffer")
    }
}
<commit_msg>(fix) (hack) us sdl2 software rendeer for now<commit_after>use std::path::Path;

use sdl2;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::rect::{Point, Rect};
use sdl2::render::{Renderer, RenderTarget, Texture, TextureAccess};
use sdl2_ttf::{self, Font, Sdl2TtfContext};

pub struct Display {
    _text:   Sdl2TtfContext,
    font:   Font,
    screen: Renderer<'static>,
}

impl Display {

    pub fn new(context: &sdl2::Sdl) -> Display {
        // boot the renderer
        let (w,h) = (1280,720);

        let video            = context.video().unwrap();
        let mut window_proto = video.window("koko", w as u32, h as u32);

        let current_mode     = window_proto.position_centered()
                                           .input_grabbed()
                                           .build();

        let window_context = match current_mode {
            Ok(ctx)  => ctx,
            Err(msg) => panic!(msg),
        };

        let renderer = window_context.renderer()
            .software()
            .build()
            .ok().expect("could not initialize sdl2 rendering context");

        // NOTE: must hide cursor _after_ window is built otherwise it doesn't work.
        context.mouse().show_cursor(false);
        println!("is cursor showing? {}", context.mouse().is_cursor_showing());

        // set up the font stuff
        let textmode = sdl2_ttf::init()
            .ok().expect("could not open ttf font renderer");

        let opensans = textmode.load_font(Path::new("./OpenSans-Regular.ttf"), 18)
            .ok().expect("could not load OpenSans-Regular.ttf from workingdir");

        // strap it all to the graphics subsystem
        Display {
            _text: textmode,
            font: opensans,
            screen: renderer,
        }
    }

    pub fn switch_buffers(&mut self) {
        self.screen.present();
    }

    pub fn clear_buffer(&mut self) {
        let _ = self.screen.clear();
    }

    pub fn blit_text(&mut self, buf: &str, color: Color) {
        let surface = self.font.render(&buf[..])
            .solid(color)
            .ok().expect("could not render text");

        let bounds = surface.rect();
        let texture = self.screen.create_texture_from_surface(surface)
            .ok().expect("could blit font to texture");

        let cursor_block = Rect::new(10,10, bounds.width(),bounds.height());
        self.screen.copy(&texture, None, Some(cursor_block));

    }

    pub fn copy(&mut self, texture: &Texture) {
        self.screen.copy(texture, None, None);
    }

    pub fn copy_t(&mut self, texture: &Texture, src: Rect, dst: Rect) {
        self.screen.copy(texture, Some(src), Some(dst));
    }

    pub fn get_texture(&mut self, width: u32, height: u32) -> Texture {
        self.screen.create_texture(PixelFormatEnum::ARGB8888,
                                   TextureAccess::Target,
                                   width, height)
            .ok().expect("could not open texture")
    }

    pub fn retarget(&mut self) -> RenderTarget {
        self.screen.render_target()
            .expect("renderer does not support arbitrary targets")
    }

    pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: Color)  {
        let previous = self.screen.draw_color();
        self.screen.set_draw_color(color);

        self.screen.draw_line(Point::new(x1,y1), Point::new(x2,y2))
            .ok().expect("could not draw line");

        self.screen.set_draw_color(previous);
    }

    pub fn fill_rect(&mut self, dst: Rect, fill: Color) {
        let previous = self.screen.draw_color();
        let _ = self.screen.set_draw_color(fill);
        let _ = self.screen.fill_rect(dst);
        let _ = self.screen.set_draw_color(previous);

    }

    pub fn read_pixels(&mut self) -> Vec<u8> {
        self.screen.read_pixels(None, PixelFormatEnum::ARGB8888)
            .ok().expect("could not get pixels out of current buffer")
    }
}
<|endoftext|>