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

#![allow(missing_docs)]
#![unstable(feature = "core")]

//! Contains struct definitions for the layout of compiler built-in types.
//!
//! They can be used as targets of transmutes in unsafe code for manipulating
//! the raw representations directly.
//!
//! Their definition should always match the ABI defined in `rustc::back::abi`.

use clone::Clone;
use marker::Copy;
use mem;

/// The representation of a slice like `&[T]`.
///
/// This struct is guaranteed to have the layout of types like `&[T]`,
/// `&str`, and `Box<[T]>`, but is not the type of such slices
/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
/// it control that layout (changing the definition will not change
/// the layout of a `&[T]`). It is only designed to be used by unsafe
/// code that needs to manipulate the low-level details.
///
/// However, it is not recommended to use this type for such code,
/// since there are alternatives which may be safer:
///
/// - Creating a slice from a data pointer and length can be done with
///   `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
///   instead of `std::mem::transmute`ing a value of type `Slice`.
/// - Extracting the data pointer and length from a slice can be
///   performed with the `as_ptr` (or `as_mut_ptr`) and `len`
///   methods.
///
/// If one does decide to convert a slice value to a `Slice`, the
/// `Repr` trait in this module provides a method for a safe
/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
/// than a call to `transmute`.
///
/// # Examples
///
/// ```
/// # #![feature(core)]
/// use std::raw::{self, Repr};
///
/// let slice: &[u16] = &[1, 2, 3, 4];
///
/// let repr: raw::Slice<u16> = slice.repr();
/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
/// ```
#[repr(C)]
pub struct Slice<T> {
    pub data: *const T,
    pub len: usize,
}

impl<T> Copy for Slice<T> {}
impl<T> Clone for Slice<T> {
    fn clone(&self) -> Slice<T> { *self }
}

/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
/// `Box<AnotherTrait>`. The [Trait Objects chapter of the
/// Book][moreinfo] contains more details about the precise nature of
/// these internals.
///
/// [moreinfo]: ../../book/trait-objects.html#representation
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g. the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&SometTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no `Repr` implementation for `TraitObject` because there
/// is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// `std::mem::transmute`. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behaviour.
///
/// # Examples
///
/// ```
/// # #![feature(core)]
/// use std::mem;
/// use std::raw;
///
/// // an example trait
/// trait Foo {
///     fn bar(&self) -> i32;
/// }
/// impl Foo for i32 {
///     fn bar(&self) -> i32 {
///          *self + 1
///     }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &Foo = unsafe {
///      mem::transmute(raw::TraitObject {
///          data: &other_value as *const _ as *mut (),
///          vtable: raw_object.vtable
///      })
/// };
///
/// // it should work just like we constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy, Clone)]
pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}

/// This trait is meant to map equivalences between raw structs and their
/// corresponding rust values.
pub unsafe trait Repr<T> {
    /// This function "unwraps" a rust value (without consuming it) into its raw
    /// struct representation. This can be used to read/write different values
    /// for the struct. This is a safe method because by default it does not
    /// enable write-access to the fields of the return value in safe code.
    #[inline]
    fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
}

unsafe impl<T> Repr<Slice<T>> for [T] {}
unsafe impl Repr<Slice<u8>> for str {}
<commit_msg>Fix a tiny typo in core::raw<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(missing_docs)]
#![unstable(feature = "core")]

//! Contains struct definitions for the layout of compiler built-in types.
//!
//! They can be used as targets of transmutes in unsafe code for manipulating
//! the raw representations directly.
//!
//! Their definition should always match the ABI defined in `rustc::back::abi`.

use clone::Clone;
use marker::Copy;
use mem;

/// The representation of a slice like `&[T]`.
///
/// This struct is guaranteed to have the layout of types like `&[T]`,
/// `&str`, and `Box<[T]>`, but is not the type of such slices
/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
/// it control that layout (changing the definition will not change
/// the layout of a `&[T]`). It is only designed to be used by unsafe
/// code that needs to manipulate the low-level details.
///
/// However, it is not recommended to use this type for such code,
/// since there are alternatives which may be safer:
///
/// - Creating a slice from a data pointer and length can be done with
///   `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
///   instead of `std::mem::transmute`ing a value of type `Slice`.
/// - Extracting the data pointer and length from a slice can be
///   performed with the `as_ptr` (or `as_mut_ptr`) and `len`
///   methods.
///
/// If one does decide to convert a slice value to a `Slice`, the
/// `Repr` trait in this module provides a method for a safe
/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
/// than a call to `transmute`.
///
/// # Examples
///
/// ```
/// # #![feature(core)]
/// use std::raw::{self, Repr};
///
/// let slice: &[u16] = &[1, 2, 3, 4];
///
/// let repr: raw::Slice<u16> = slice.repr();
/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
/// ```
#[repr(C)]
pub struct Slice<T> {
    pub data: *const T,
    pub len: usize,
}

impl<T> Copy for Slice<T> {}
impl<T> Clone for Slice<T> {
    fn clone(&self) -> Slice<T> { *self }
}

/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
/// `Box<AnotherTrait>`. The [Trait Objects chapter of the
/// Book][moreinfo] contains more details about the precise nature of
/// these internals.
///
/// [moreinfo]: ../../book/trait-objects.html#representation
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g. the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&SomeTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no `Repr` implementation for `TraitObject` because there
/// is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// `std::mem::transmute`. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behaviour.
///
/// # Examples
///
/// ```
/// # #![feature(core)]
/// use std::mem;
/// use std::raw;
///
/// // an example trait
/// trait Foo {
///     fn bar(&self) -> i32;
/// }
/// impl Foo for i32 {
///     fn bar(&self) -> i32 {
///          *self + 1
///     }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &Foo = unsafe {
///      mem::transmute(raw::TraitObject {
///          data: &other_value as *const _ as *mut (),
///          vtable: raw_object.vtable
///      })
/// };
///
/// // it should work just like we constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy, Clone)]
pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}

/// This trait is meant to map equivalences between raw structs and their
/// corresponding rust values.
pub unsafe trait Repr<T> {
    /// This function "unwraps" a rust value (without consuming it) into its raw
    /// struct representation. This can be used to read/write different values
    /// for the struct. This is a safe method because by default it does not
    /// enable write-access to the fields of the return value in safe code.
    #[inline]
    fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
}

unsafe impl<T> Repr<Slice<T>> for [T] {}
unsafe impl Repr<Slice<u8>> for str {}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder};
use aes;
use ghash;

pub struct GCM {
    cipher: aes::AES,
}

impl GCM {
    pub fn new(key: &[u8]) -> Self {
        Self { cipher: aes::AES::new(key) }
    }

    pub fn auth_encrypt(&self, message: &[u8], data: &[u8], nonce: &[u8]) -> (Vec<u8>, [u8; 16]) {
        assert!(1 << 39 >= message.len() + 256);
        let counter = self.get_counter(nonce);
        let ciphertext = self.counter_mode(&message, &counter);
        let tag = self.tag(&ciphertext, data, &counter);
        (ciphertext, tag)
    }

    pub fn auth_decrypt(
        &self,
        ciphertext: &[u8],
        tag: &[u8],
        data: &[u8],
        nonce: &[u8],
    ) -> Result<Vec<u8>, ()> {
        assert_eq!(16, tag.len());
        let counter = self.get_counter(nonce);
        let expected_tag = self.tag(ciphertext, data, &counter);
        self.check_tag(&expected_tag, tag)?;
        let message = self.counter_mode(&ciphertext, &counter);
        Ok(message)
    }

    fn get_counter(&self, nonce: &[u8]) -> [u8; 16] {
        if nonce.len() == 12 {
            let mut counter = [0; 16];
            counter[..12].copy_from_slice(nonce);
            counter[15] = 1;
            counter
        } else {
            self.ghash(&[], nonce)
        }
    }

    fn counter_mode(&self, input: &[u8], counter: &[u8; 16]) -> Vec<u8> {
        let mut output = vec![];
        let x0 = (&counter[..12], BigEndian::read_u32(&counter[12..]));
        for (i, mi) in (1..).zip(input.chunks(16)) {
            let xi = Self::incr(x0, i);
            output.extend(mi.iter().zip(&self.cipher.cipher(&xi)).map(|(x, y)| x ^ y));
        }
        output.truncate(input.len());
        output
    }

    fn tag(&self, ciphertext: &[u8], data: &[u8], counter: &[u8; 16]) -> [u8; 16] {
        let mut tag = self.ghash(data, ciphertext);
        for (t, &x) in tag.iter_mut().zip(&self.cipher.cipher(counter)) {
            *t ^= x;
        }
        tag
    }

    /// Meant to check tag without early returns
    fn check_tag(&self, expected: &[u8], tag: &[u8]) -> Result<(), ()> {
        let valid = expected.iter().zip(tag).fold(
            true,
            |acc, (x, y)| acc && x == y,
        );
        if valid { Ok(()) } else { Err(()) }
    }

    fn incr((f, w): (&[u8], u32), i: u32) -> [u8; 16] {
        let mut y = [0; 16];
        y[..12].copy_from_slice(f);
        BigEndian::write_u32(&mut y[12..], w.wrapping_add(i));
        y
    }

    fn ghash(&self, a: &[u8], c: &[u8]) -> [u8; 16] {
        ghash::ghash(&self.cipher.cipher(&[0; 16]), a, c)
    }
}

#[cfg(test)]
mod tests {
    use gcm::*;

    fn check(k: &[u8], m: &Vec<u8>, a: &[u8], n: &[u8], c: &Vec<u8>, t: &[u8]) {
        let gcm = GCM::new(&k);
        let actual = gcm.auth_encrypt(&m, &a, &n);
        assert_eq!(c, &actual.0);
        assert_eq!(t, actual.1);
        assert_eq!(m, &gcm.auth_decrypt(&c, &t, &a, &n).unwrap());
    }

    #[test]
    fn test_case_13_14() {
        let key = [0; 32];
        let nonce = [0; 12];
        let tag = [
            0x53,
            0x0f,
            0x8a,
            0xfb,
            0xc7,
            0x45,
            0x36,
            0xb9,
            0xa9,
            0x63,
            0xb4,
            0xf1,
            0xc4,
            0xcb,
            0x73,
            0x8b,
        ];
        check(&key, &vec![], &[], &nonce, &vec![], &tag);

        let message = vec![0; 16];
        let ciphertext = vec![
            0xce,
            0xa7,
            0x40,
            0x3d,
            0x4d,
            0x60,
            0x6b,
            0x6e,
            0x07,
            0x4e,
            0xc5,
            0xd3,
            0xba,
            0xf3,
            0x9d,
            0x18,
        ];
        let tag = [
            0xd0,
            0xd1,
            0xc8,
            0xa7,
            0x99,
            0x99,
            0x6b,
            0xf0,
            0x26,
            0x5b,
            0x98,
            0xb5,
            0xd4,
            0x8a,
            0xb9,
            0x19,
        ];
        check(&key, &message, &[], &nonce, &ciphertext, &tag);
    }

    #[test]
    fn test_case_15_16_17_18() {
        let key = [
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
        ];
        let mut message = vec![
            0xd9,
            0x31,
            0x32,
            0x25,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0xa5,
            0x59,
            0x09,
            0xc5,
            0xaf,
            0xf5,
            0x26,
            0x9a,
            0x86,
            0xa7,
            0xa9,
            0x53,
            0x15,
            0x34,
            0xf7,
            0xda,
            0x2e,
            0x4c,
            0x30,
            0x3d,
            0x8a,
            0x31,
            0x8a,
            0x72,
            0x1c,
            0x3c,
            0x0c,
            0x95,
            0x95,
            0x68,
            0x09,
            0x53,
            0x2f,
            0xcf,
            0x0e,
            0x24,
            0x49,
            0xa6,
            0xb5,
            0x25,
            0xb1,
            0x6a,
            0xed,
            0xf5,
            0xaa,
            0x0d,
            0xe6,
            0x57,
            0xba,
            0x63,
            0x7b,
            0x39,
            0x1a,
            0xaf,
            0xd2,
            0x55,
        ];
        let nonce = [
            0xca,
            0xfe,
            0xba,
            0xbe,
            0xfa,
            0xce,
            0xdb,
            0xad,
            0xde,
            0xca,
            0xf8,
            0x88,
        ];
        let mut ciphertext = vec![
            0x52,
            0x2d,
            0xc1,
            0xf0,
            0x99,
            0x56,
            0x7d,
            0x07,
            0xf4,
            0x7f,
            0x37,
            0xa3,
            0x2a,
            0x84,
            0x42,
            0x7d,
            0x64,
            0x3a,
            0x8c,
            0xdc,
            0xbf,
            0xe5,
            0xc0,
            0xc9,
            0x75,
            0x98,
            0xa2,
            0xbd,
            0x25,
            0x55,
            0xd1,
            0xaa,
            0x8c,
            0xb0,
            0x8e,
            0x48,
            0x59,
            0x0d,
            0xbb,
            0x3d,
            0xa7,
            0xb0,
            0x8b,
            0x10,
            0x56,
            0x82,
            0x88,
            0x38,
            0xc5,
            0xf6,
            0x1e,
            0x63,
            0x93,
            0xba,
            0x7a,
            0x0a,
            0xbc,
            0xc9,
            0xf6,
            0x62,
            0x89,
            0x80,
            0x15,
            0xad,
        ];
        let tag = [
            0xb0,
            0x94,
            0xda,
            0xc5,
            0xd9,
            0x34,
            0x71,
            0xbd,
            0xec,
            0x1a,
            0x50,
            0x22,
            0x70,
            0xe3,
            0xcc,
            0x6c,
        ];
        check(&key, &message, &[], &nonce, &ciphertext, &tag);

        message.truncate(60);
        ciphertext.truncate(60);
        let data = [
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xab,
            0xad,
            0xda,
            0xd2,
        ];
        let tag = [
            0x76,
            0xfc,
            0x6e,
            0xce,
            0x0f,
            0x4e,
            0x17,
            0x68,
            0xcd,
            0xdf,
            0x88,
            0x53,
            0xbb,
            0x2d,
            0x55,
            0x1b,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);

        let nonce = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
        let ciphertext = vec![
            0xc3,
            0x76,
            0x2d,
            0xf1,
            0xca,
            0x78,
            0x7d,
            0x32,
            0xae,
            0x47,
            0xc1,
            0x3b,
            0xf1,
            0x98,
            0x44,
            0xcb,
            0xaf,
            0x1a,
            0xe1,
            0x4d,
            0x0b,
            0x97,
            0x6a,
            0xfa,
            0xc5,
            0x2f,
            0xf7,
            0xd7,
            0x9b,
            0xba,
            0x9d,
            0xe0,
            0xfe,
            0xb5,
            0x82,
            0xd3,
            0x39,
            0x34,
            0xa4,
            0xf0,
            0x95,
            0x4c,
            0xc2,
            0x36,
            0x3b,
            0xc7,
            0x3f,
            0x78,
            0x62,
            0xac,
            0x43,
            0x0e,
            0x64,
            0xab,
            0xe4,
            0x99,
            0xf4,
            0x7c,
            0x9b,
            0x1f,
        ];
        let tag = [
            0x3a,
            0x33,
            0x7d,
            0xbf,
            0x46,
            0xa7,
            0x92,
            0xc4,
            0x5e,
            0x45,
            0x49,
            0x13,
            0xfe,
            0x2e,
            0xa8,
            0xf2,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);

        let nonce = [
            0x93,
            0x13,
            0x22,
            0x5d,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0x55,
            0x90,
            0x9c,
            0x5a,
            0xff,
            0x52,
            0x69,
            0xaa,
            0x6a,
            0x7a,
            0x95,
            0x38,
            0x53,
            0x4f,
            0x7d,
            0xa1,
            0xe4,
            0xc3,
            0x03,
            0xd2,
            0xa3,
            0x18,
            0xa7,
            0x28,
            0xc3,
            0xc0,
            0xc9,
            0x51,
            0x56,
            0x80,
            0x95,
            0x39,
            0xfc,
            0xf0,
            0xe2,
            0x42,
            0x9a,
            0x6b,
            0x52,
            0x54,
            0x16,
            0xae,
            0xdb,
            0xf5,
            0xa0,
            0xde,
            0x6a,
            0x57,
            0xa6,
            0x37,
            0xb3,
            0x9b,
        ];
        let ciphertext = vec![
            0x5a,
            0x8d,
            0xef,
            0x2f,
            0x0c,
            0x9e,
            0x53,
            0xf1,
            0xf7,
            0x5d,
            0x78,
            0x53,
            0x65,
            0x9e,
            0x2a,
            0x20,
            0xee,
            0xb2,
            0xb2,
            0x2a,
            0xaf,
            0xde,
            0x64,
            0x19,
            0xa0,
            0x58,
            0xab,
            0x4f,
            0x6f,
            0x74,
            0x6b,
            0xf4,
            0x0f,
            0xc0,
            0xc3,
            0xb7,
            0x80,
            0xf2,
            0x44,
            0x45,
            0x2d,
            0xa3,
            0xeb,
            0xf1,
            0xc5,
            0xd8,
            0x2c,
            0xde,
            0xa2,
            0x41,
            0x89,
            0x97,
            0x20,
            0x0e,
            0xf8,
            0x2e,
            0x44,
            0xae,
            0x7e,
            0x3f,
        ];
        let tag = [
            0xa4,
            0x4a,
            0x82,
            0x66,
            0xee,
            0x1c,
            0x8e,
            0xb0,
            0xc8,
            0xb5,
            0xd4,
            0xcf,
            0x5a,
            0xe9,
            0xf1,
            0x9a,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);
    }
}
<commit_msg>gcm: note on early return fail<commit_after>use byteorder::{BigEndian, ByteOrder};
use aes;
use ghash;

pub struct GCM {
    cipher: aes::AES,
}

impl GCM {
    pub fn new(key: &[u8]) -> Self {
        Self { cipher: aes::AES::new(key) }
    }

    pub fn auth_encrypt(&self, message: &[u8], data: &[u8], nonce: &[u8]) -> (Vec<u8>, [u8; 16]) {
        assert!(1 << 39 >= message.len() + 256);
        let counter = self.get_counter(nonce);
        let ciphertext = self.counter_mode(&message, &counter);
        let tag = self.tag(&ciphertext, data, &counter);
        (ciphertext, tag)
    }

    pub fn auth_decrypt(
        &self,
        ciphertext: &[u8],
        tag: &[u8],
        data: &[u8],
        nonce: &[u8],
    ) -> Result<Vec<u8>, ()> {
        assert_eq!(16, tag.len());
        let counter = self.get_counter(nonce);
        let expected_tag = self.tag(ciphertext, data, &counter);
        self.check_tag(&expected_tag, tag)?;
        let message = self.counter_mode(&ciphertext, &counter);
        Ok(message)
    }

    fn get_counter(&self, nonce: &[u8]) -> [u8; 16] {
        if nonce.len() == 12 {
            let mut counter = [0; 16];
            counter[..12].copy_from_slice(nonce);
            counter[15] = 1;
            counter
        } else {
            self.ghash(&[], nonce)
        }
    }

    fn counter_mode(&self, input: &[u8], counter: &[u8; 16]) -> Vec<u8> {
        let mut output = vec![];
        let x0 = (&counter[..12], BigEndian::read_u32(&counter[12..]));
        for (i, mi) in (1..).zip(input.chunks(16)) {
            let xi = Self::incr(x0, i);
            output.extend(mi.iter().zip(&self.cipher.cipher(&xi)).map(|(x, y)| x ^ y));
        }
        output.truncate(input.len());
        output
    }

    fn tag(&self, ciphertext: &[u8], data: &[u8], counter: &[u8; 16]) -> [u8; 16] {
        let mut tag = self.ghash(data, ciphertext);
        for (t, &x) in tag.iter_mut().zip(&self.cipher.cipher(counter)) {
            *t ^= x;
        }
        tag
    }

    /// This is meant to check the tag without early returns, but the compiler ruins it
    fn check_tag(&self, expected: &[u8], tag: &[u8]) -> Result<(), ()> {
        let valid = expected.iter().zip(tag).fold(
            true,
            |acc, (x, y)| acc && x == y,
        );
        if valid { Ok(()) } else { Err(()) }
    }

    fn incr((f, w): (&[u8], u32), i: u32) -> [u8; 16] {
        let mut y = [0; 16];
        y[..12].copy_from_slice(f);
        BigEndian::write_u32(&mut y[12..], w.wrapping_add(i));
        y
    }

    fn ghash(&self, a: &[u8], c: &[u8]) -> [u8; 16] {
        ghash::ghash(&self.cipher.cipher(&[0; 16]), a, c)
    }
}

#[cfg(test)]
mod tests {
    use gcm::*;

    fn check(k: &[u8], m: &Vec<u8>, a: &[u8], n: &[u8], c: &Vec<u8>, t: &[u8]) {
        let gcm = GCM::new(&k);
        let actual = gcm.auth_encrypt(&m, &a, &n);
        assert_eq!(c, &actual.0);
        assert_eq!(t, actual.1);
        assert_eq!(m, &gcm.auth_decrypt(&c, &t, &a, &n).unwrap());
    }

    #[test]
    fn test_case_13_14() {
        let key = [0; 32];
        let nonce = [0; 12];
        let tag = [
            0x53,
            0x0f,
            0x8a,
            0xfb,
            0xc7,
            0x45,
            0x36,
            0xb9,
            0xa9,
            0x63,
            0xb4,
            0xf1,
            0xc4,
            0xcb,
            0x73,
            0x8b,
        ];
        check(&key, &vec![], &[], &nonce, &vec![], &tag);

        let message = vec![0; 16];
        let ciphertext = vec![
            0xce,
            0xa7,
            0x40,
            0x3d,
            0x4d,
            0x60,
            0x6b,
            0x6e,
            0x07,
            0x4e,
            0xc5,
            0xd3,
            0xba,
            0xf3,
            0x9d,
            0x18,
        ];
        let tag = [
            0xd0,
            0xd1,
            0xc8,
            0xa7,
            0x99,
            0x99,
            0x6b,
            0xf0,
            0x26,
            0x5b,
            0x98,
            0xb5,
            0xd4,
            0x8a,
            0xb9,
            0x19,
        ];
        check(&key, &message, &[], &nonce, &ciphertext, &tag);
    }

    #[test]
    fn test_case_15_16_17_18() {
        let key = [
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
        ];
        let mut message = vec![
            0xd9,
            0x31,
            0x32,
            0x25,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0xa5,
            0x59,
            0x09,
            0xc5,
            0xaf,
            0xf5,
            0x26,
            0x9a,
            0x86,
            0xa7,
            0xa9,
            0x53,
            0x15,
            0x34,
            0xf7,
            0xda,
            0x2e,
            0x4c,
            0x30,
            0x3d,
            0x8a,
            0x31,
            0x8a,
            0x72,
            0x1c,
            0x3c,
            0x0c,
            0x95,
            0x95,
            0x68,
            0x09,
            0x53,
            0x2f,
            0xcf,
            0x0e,
            0x24,
            0x49,
            0xa6,
            0xb5,
            0x25,
            0xb1,
            0x6a,
            0xed,
            0xf5,
            0xaa,
            0x0d,
            0xe6,
            0x57,
            0xba,
            0x63,
            0x7b,
            0x39,
            0x1a,
            0xaf,
            0xd2,
            0x55,
        ];
        let nonce = [
            0xca,
            0xfe,
            0xba,
            0xbe,
            0xfa,
            0xce,
            0xdb,
            0xad,
            0xde,
            0xca,
            0xf8,
            0x88,
        ];
        let mut ciphertext = vec![
            0x52,
            0x2d,
            0xc1,
            0xf0,
            0x99,
            0x56,
            0x7d,
            0x07,
            0xf4,
            0x7f,
            0x37,
            0xa3,
            0x2a,
            0x84,
            0x42,
            0x7d,
            0x64,
            0x3a,
            0x8c,
            0xdc,
            0xbf,
            0xe5,
            0xc0,
            0xc9,
            0x75,
            0x98,
            0xa2,
            0xbd,
            0x25,
            0x55,
            0xd1,
            0xaa,
            0x8c,
            0xb0,
            0x8e,
            0x48,
            0x59,
            0x0d,
            0xbb,
            0x3d,
            0xa7,
            0xb0,
            0x8b,
            0x10,
            0x56,
            0x82,
            0x88,
            0x38,
            0xc5,
            0xf6,
            0x1e,
            0x63,
            0x93,
            0xba,
            0x7a,
            0x0a,
            0xbc,
            0xc9,
            0xf6,
            0x62,
            0x89,
            0x80,
            0x15,
            0xad,
        ];
        let tag = [
            0xb0,
            0x94,
            0xda,
            0xc5,
            0xd9,
            0x34,
            0x71,
            0xbd,
            0xec,
            0x1a,
            0x50,
            0x22,
            0x70,
            0xe3,
            0xcc,
            0x6c,
        ];
        check(&key, &message, &[], &nonce, &ciphertext, &tag);

        message.truncate(60);
        ciphertext.truncate(60);
        let data = [
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xab,
            0xad,
            0xda,
            0xd2,
        ];
        let tag = [
            0x76,
            0xfc,
            0x6e,
            0xce,
            0x0f,
            0x4e,
            0x17,
            0x68,
            0xcd,
            0xdf,
            0x88,
            0x53,
            0xbb,
            0x2d,
            0x55,
            0x1b,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);

        let nonce = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
        let ciphertext = vec![
            0xc3,
            0x76,
            0x2d,
            0xf1,
            0xca,
            0x78,
            0x7d,
            0x32,
            0xae,
            0x47,
            0xc1,
            0x3b,
            0xf1,
            0x98,
            0x44,
            0xcb,
            0xaf,
            0x1a,
            0xe1,
            0x4d,
            0x0b,
            0x97,
            0x6a,
            0xfa,
            0xc5,
            0x2f,
            0xf7,
            0xd7,
            0x9b,
            0xba,
            0x9d,
            0xe0,
            0xfe,
            0xb5,
            0x82,
            0xd3,
            0x39,
            0x34,
            0xa4,
            0xf0,
            0x95,
            0x4c,
            0xc2,
            0x36,
            0x3b,
            0xc7,
            0x3f,
            0x78,
            0x62,
            0xac,
            0x43,
            0x0e,
            0x64,
            0xab,
            0xe4,
            0x99,
            0xf4,
            0x7c,
            0x9b,
            0x1f,
        ];
        let tag = [
            0x3a,
            0x33,
            0x7d,
            0xbf,
            0x46,
            0xa7,
            0x92,
            0xc4,
            0x5e,
            0x45,
            0x49,
            0x13,
            0xfe,
            0x2e,
            0xa8,
            0xf2,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);

        let nonce = [
            0x93,
            0x13,
            0x22,
            0x5d,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0x55,
            0x90,
            0x9c,
            0x5a,
            0xff,
            0x52,
            0x69,
            0xaa,
            0x6a,
            0x7a,
            0x95,
            0x38,
            0x53,
            0x4f,
            0x7d,
            0xa1,
            0xe4,
            0xc3,
            0x03,
            0xd2,
            0xa3,
            0x18,
            0xa7,
            0x28,
            0xc3,
            0xc0,
            0xc9,
            0x51,
            0x56,
            0x80,
            0x95,
            0x39,
            0xfc,
            0xf0,
            0xe2,
            0x42,
            0x9a,
            0x6b,
            0x52,
            0x54,
            0x16,
            0xae,
            0xdb,
            0xf5,
            0xa0,
            0xde,
            0x6a,
            0x57,
            0xa6,
            0x37,
            0xb3,
            0x9b,
        ];
        let ciphertext = vec![
            0x5a,
            0x8d,
            0xef,
            0x2f,
            0x0c,
            0x9e,
            0x53,
            0xf1,
            0xf7,
            0x5d,
            0x78,
            0x53,
            0x65,
            0x9e,
            0x2a,
            0x20,
            0xee,
            0xb2,
            0xb2,
            0x2a,
            0xaf,
            0xde,
            0x64,
            0x19,
            0xa0,
            0x58,
            0xab,
            0x4f,
            0x6f,
            0x74,
            0x6b,
            0xf4,
            0x0f,
            0xc0,
            0xc3,
            0xb7,
            0x80,
            0xf2,
            0x44,
            0x45,
            0x2d,
            0xa3,
            0xeb,
            0xf1,
            0xc5,
            0xd8,
            0x2c,
            0xde,
            0xa2,
            0x41,
            0x89,
            0x97,
            0x20,
            0x0e,
            0xf8,
            0x2e,
            0x44,
            0xae,
            0x7e,
            0x3f,
        ];
        let tag = [
            0xa4,
            0x4a,
            0x82,
            0x66,
            0xee,
            0x1c,
            0x8e,
            0xb0,
            0xc8,
            0xb5,
            0xd4,
            0xcf,
            0x5a,
            0xe9,
            0xf1,
            0x9a,
        ];
        check(&key, &message, &data, &nonce, &ciphertext, &tag);
    }
}
<|endoftext|>


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

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the win32 console api

extern crate libc;

use std::io::IoResult;

use attr;
use color;
use Terminal;

pub struct WinConsole<T> {
    buf: T,
    foreground: color::Color,
    background: color::Color,
}

#[link(name = "kernel32")]
extern "system" {
    fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
    fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK   => 0,
        color::BLUE    => 0x1,
        color::GREEN   => 0x2,
        color::RED     => 0x4,
        color::YELLOW  => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN    => 0x1 | 0x2,
        color::WHITE   => 0x1 | 0x2 | 0x4,
        _ => unreachable!()
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

impl<T: Writer> WinConsole<T> {
    fn apply(&mut self) {
        let mut accum: libc::WORD = 0;
        accum |= color_to_bits(self.foreground);
        accum |= color_to_bits(self.background) << 4;

        unsafe {
            // Magic -11 means stdout, from
            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
            //
            // You may be wondering, "but what about stderr?", and the answer
            // to that is that setting terminal attributes on the stdout
            // handle also sets them for stderr, since they go to the same
            // terminal! Admittedly, this is fragile, since stderr could be
            // redirected to a different console. This is good enough for
            // rustc though. See #13400.
            let out = GetStdHandle(-11);
            SetConsoleTextAttribute(out, accum);
        }
    }
}

impl<T: Writer> Writer for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        self.buf.flush()
    }
}

impl<T: Writer> Terminal<T> for WinConsole<T> {
    fn new(out: T) -> Option<WinConsole<T>> {
        Some(WinConsole { buf: out, foreground: color::WHITE, background: color::BLACK })
    }

    fn fg(&mut self, color: color::Color) -> IoResult<bool> {
        self.foreground = color;
        self.apply();

        Ok(true)
    }

    fn bg(&mut self, color: color::Color) -> IoResult<bool> {
        self.background = color;
        self.apply();

        Ok(true)
    }

    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
        match attr {
            attr::ForegroundColor(f) => {
                self.foreground = f;
                self.apply();
                Ok(true)
            },
            attr::BackgroundColor(b) => {
                self.background = b;
                self.apply();
                Ok(true)
            },
            _ => Ok(false)
        }
    }

    fn supports_attr(&self, attr: attr::Attr) -> bool {
        // it claims support for underscore and reverse video, but I can't get
        // it to do anything -cmr
        match attr {
            attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
            _ => false
        }
    }

    fn reset(&mut self) -> IoResult<()> {
        self.foreground = color::WHITE;
        self.background = color::BLACK;
        self.apply();

        Ok(())
    }

    fn unwrap(self) -> T { self.buf }

    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
}
<commit_msg>Add WinConsole docs<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the win32 console api

extern crate libc;

use std::io::IoResult;

use attr;
use color;
use Terminal;

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    foreground: color::Color,
    background: color::Color,
}

#[link(name = "kernel32")]
extern "system" {
    fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
    fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK   => 0,
        color::BLUE    => 0x1,
        color::GREEN   => 0x2,
        color::RED     => 0x4,
        color::YELLOW  => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN    => 0x1 | 0x2,
        color::WHITE   => 0x1 | 0x2 | 0x4,
        _ => unreachable!()
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

impl<T: Writer> WinConsole<T> {
    fn apply(&mut self) {
        let mut accum: libc::WORD = 0;
        accum |= color_to_bits(self.foreground);
        accum |= color_to_bits(self.background) << 4;

        unsafe {
            // Magic -11 means stdout, from
            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
            //
            // You may be wondering, "but what about stderr?", and the answer
            // to that is that setting terminal attributes on the stdout
            // handle also sets them for stderr, since they go to the same
            // terminal! Admittedly, this is fragile, since stderr could be
            // redirected to a different console. This is good enough for
            // rustc though. See #13400.
            let out = GetStdHandle(-11);
            SetConsoleTextAttribute(out, accum);
        }
    }
}

impl<T: Writer> Writer for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        self.buf.flush()
    }
}

impl<T: Writer> Terminal<T> for WinConsole<T> {
    fn new(out: T) -> Option<WinConsole<T>> {
        Some(WinConsole { buf: out, foreground: color::WHITE, background: color::BLACK })
    }

    fn fg(&mut self, color: color::Color) -> IoResult<bool> {
        self.foreground = color;
        self.apply();

        Ok(true)
    }

    fn bg(&mut self, color: color::Color) -> IoResult<bool> {
        self.background = color;
        self.apply();

        Ok(true)
    }

    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
        match attr {
            attr::ForegroundColor(f) => {
                self.foreground = f;
                self.apply();
                Ok(true)
            },
            attr::BackgroundColor(b) => {
                self.background = b;
                self.apply();
                Ok(true)
            },
            _ => Ok(false)
        }
    }

    fn supports_attr(&self, attr: attr::Attr) -> bool {
        // it claims support for underscore and reverse video, but I can't get
        // it to do anything -cmr
        match attr {
            attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
            _ => false
        }
    }

    fn reset(&mut self) -> IoResult<()> {
        self.foreground = color::WHITE;
        self.background = color::BLACK;
        self.apply();

        Ok(())
    }

    fn unwrap(self) -> T { self.buf }

    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }

    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
}
<|endoftext|>


<commit_before>extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate gip;
#[macro_use]
extern crate structopt;

use gip::{Provider, ProviderAny, ProviderType};
use std::env::home_dir;
use std::fs::File;
use std::io::Read;
use structopt::StructOpt;

// -------------------------------------------------------------------------------------------------
// Usage
// -------------------------------------------------------------------------------------------------

#[derive(Debug, StructOpt)]
#[structopt(name = "gip")]
#[structopt(raw(long_version = "option_env!(\"LONG_VERSION\").unwrap_or(env!(\"CARGO_PKG_VERSION\"))"))]
#[structopt(raw(setting = "clap::AppSettings::ColoredHelp"))]
#[structopt(raw(setting = "clap::AppSettings::DeriveDisplayOrder"))]
pub struct Opt {
    /// IPv4 address ( default )
    #[structopt(short = "4", long = "v4", conflicts_with = "v6")]
    pub v4: bool,

    /// IPv6 address
    #[structopt(short = "6", long = "v6", conflicts_with = "v4")]
    pub v6: bool,

    /// Show by plane text ( default )
    #[structopt(short = "p", long = "plane", conflicts_with = "string", conflicts_with = "json")]
    pub show_plane: bool,

    /// Show by plane text without line break
    #[structopt(short = "s", long = "string", conflicts_with = "plane", conflicts_with = "json")]
    pub show_string: bool,

    /// Show by JSON
    #[structopt(short = "j", long = "json", conflicts_with = "plane", conflicts_with = "string")]
    pub show_json: bool,

    /// Timeout per each provider by milliseconds
    #[structopt(long = "timeout", default_value = "1000")]
    pub timeout: usize,

    /// Key string of JSON format
    #[structopt(long = "json-key", default_value = "ip")]
    pub json_key: String,

    /// Proxy for HTTP access ( "host:port" )
    #[structopt(long = "proxy")]
    pub proxy: Option<String>,

    /// Show provider list
    #[structopt(short = "l", long = "list")]
    pub show_list: bool,

    /// Show verbose message
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,
}

// -------------------------------------------------------------------------------------------------
// Error
// -------------------------------------------------------------------------------------------------

error_chain! {
    links {
        Gip(::gip::Error, ::gip::ErrorKind);
    }
    foreign_links {
        Io(::std::io::Error);
        ParseInt(::std::num::ParseIntError);
    }
}

// -------------------------------------------------------------------------------------------------
// Main
// -------------------------------------------------------------------------------------------------

quick_main!(run);

pub fn run() -> Result<()> {
    let opt = Opt::from_args();
    run_opt(&opt)
}

pub fn run_opt(opt: &Opt) -> Result<()> {
    let giprc = match home_dir() {
        Some(mut p) => {
            p.push(".gip.toml");
            if p.exists() {
                Some(p)
            } else {
                None
            }
        }
        None => None,
    };

    let mut client = match giprc {
        Some(p) => {
            let mut f =
                File::open(&p).chain_err(|| format!("failed to open {}", p.to_string_lossy()))?;
            let mut s = String::new();
            let _ = f.read_to_string(&mut s);
            ProviderAny::from_toml(&s)?
        }
        None => ProviderAny::from_toml(&gip::DEFAULT_TOML)?,
    };

    if opt.v6 {
        client.ptype = ProviderType::IPv6;
    }

    if opt.show_list {
        for p in &client.providers {
            println!("{:?}: {}", p.get_type(), p.get_name());
        }
        return Ok(());
    }

    client.set_timeout(opt.timeout);

    if opt.proxy.is_some() {
        let proxy_str = opt.proxy.clone().unwrap();
        let (host, port) = proxy_str.split_at(proxy_str.find(':').unwrap_or(0));
        let port = port.trim_matches(':')
            .parse::<u16>()
            .chain_err(|| format!("failed to parse proxy: {}", proxy_str))?;
        client.set_proxy(host, port);
    }

    let addr = client.get_addr()?;
    let addr_str = if opt.v6 {
        format!("{:?}", addr.v6addr.unwrap())
    } else {
        format!("{:?}", addr.v4addr.unwrap())
    };

    if opt.verbose {
        println!("IP Address: {}", addr_str);
        println!("Provider  : {}", addr.provider);
        println!("Check Time: {}", addr.time.rfc822());
    } else {
        if opt.show_string {
            print!("{}", addr_str);
        } else if opt.show_json {
            println!("{{\"{}\": \"{}\"}}", opt.json_key, addr_str);
        } else {
            println!("{}", addr_str);
        }
    }

    return Ok(());
}

// -------------------------------------------------------------------------------------------------
// Test
// -------------------------------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_run() {
        let args = vec!["gip"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_verbose() {
        let args = vec!["gip", "-v"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_string() {
        let args = vec!["gip", "-s"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_json() {
        let args = vec!["gip", "-j"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_list() {
        let args = vec!["gip", "-l"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_v6() {
        let args = vec!["gip", "-6"];
        let opt = Opt::from_iter(args.iter());
        let _ = run_opt(&opt);
    }

    #[test]
    fn test_proxy() {
        let args = vec!["gip", "--proxy", "example.com:8080"];
        let opt = Opt::from_iter(args.iter());
        let _ = run_opt(&opt);
    }

}
<commit_msg>Fix option conflict<commit_after>extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate gip;
#[macro_use]
extern crate structopt;

use gip::{Provider, ProviderAny, ProviderType};
use std::env::home_dir;
use std::fs::File;
use std::io::Read;
use structopt::StructOpt;

// -------------------------------------------------------------------------------------------------
// Usage
// -------------------------------------------------------------------------------------------------

#[derive(Debug, StructOpt)]
#[structopt(name = "gip")]
#[structopt(raw(long_version = "option_env!(\"LONG_VERSION\").unwrap_or(env!(\"CARGO_PKG_VERSION\"))"))]
#[structopt(raw(setting = "clap::AppSettings::ColoredHelp"))]
#[structopt(raw(setting = "clap::AppSettings::DeriveDisplayOrder"))]
pub struct Opt {
    /// IPv4 address ( default )
    #[structopt(short = "4", long = "v4", conflicts_with = "v6")]
    pub v4: bool,

    /// IPv6 address
    #[structopt(short = "6", long = "v6", conflicts_with = "v4")]
    pub v6: bool,

    /// Show by plane text ( default )
    #[structopt(short = "p", long = "plane", conflicts_with = "show_string", conflicts_with = "show_json")]
    pub show_plane: bool,

    /// Show by plane text without line break
    #[structopt(short = "s", long = "string", conflicts_with = "show_plane", conflicts_with = "show_json")]
    pub show_string: bool,

    /// Show by JSON
    #[structopt(short = "j", long = "json", conflicts_with = "show_plane", conflicts_with = "show_string")]
    pub show_json: bool,

    /// Timeout per each provider by milliseconds
    #[structopt(long = "timeout", default_value = "1000")]
    pub timeout: usize,

    /// Key string of JSON format
    #[structopt(long = "json-key", default_value = "ip")]
    pub json_key: String,

    /// Proxy for HTTP access ( "host:port" )
    #[structopt(long = "proxy")]
    pub proxy: Option<String>,

    /// Show provider list
    #[structopt(short = "l", long = "list")]
    pub show_list: bool,

    /// Show verbose message
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,
}

// -------------------------------------------------------------------------------------------------
// Error
// -------------------------------------------------------------------------------------------------

error_chain! {
    links {
        Gip(::gip::Error, ::gip::ErrorKind);
    }
    foreign_links {
        Io(::std::io::Error);
        ParseInt(::std::num::ParseIntError);
    }
}

// -------------------------------------------------------------------------------------------------
// Main
// -------------------------------------------------------------------------------------------------

quick_main!(run);

pub fn run() -> Result<()> {
    let opt = Opt::from_args();
    run_opt(&opt)
}

pub fn run_opt(opt: &Opt) -> Result<()> {
    let giprc = match home_dir() {
        Some(mut p) => {
            p.push(".gip.toml");
            if p.exists() {
                Some(p)
            } else {
                None
            }
        }
        None => None,
    };

    let mut client = match giprc {
        Some(p) => {
            let mut f =
                File::open(&p).chain_err(|| format!("failed to open {}", p.to_string_lossy()))?;
            let mut s = String::new();
            let _ = f.read_to_string(&mut s);
            ProviderAny::from_toml(&s)?
        }
        None => ProviderAny::from_toml(&gip::DEFAULT_TOML)?,
    };

    if opt.v6 {
        client.ptype = ProviderType::IPv6;
    }

    if opt.show_list {
        for p in &client.providers {
            println!("{:?}: {}", p.get_type(), p.get_name());
        }
        return Ok(());
    }

    client.set_timeout(opt.timeout);

    if opt.proxy.is_some() {
        let proxy_str = opt.proxy.clone().unwrap();
        let (host, port) = proxy_str.split_at(proxy_str.find(':').unwrap_or(0));
        let port = port.trim_matches(':')
            .parse::<u16>()
            .chain_err(|| format!("failed to parse proxy: {}", proxy_str))?;
        client.set_proxy(host, port);
    }

    let addr = client.get_addr()?;
    let addr_str = if opt.v6 {
        format!("{:?}", addr.v6addr.unwrap())
    } else {
        format!("{:?}", addr.v4addr.unwrap())
    };

    if opt.verbose {
        println!("IP Address: {}", addr_str);
        println!("Provider  : {}", addr.provider);
        println!("Check Time: {}", addr.time.rfc822());
    } else {
        if opt.show_string {
            print!("{}", addr_str);
        } else if opt.show_json {
            println!("{{\"{}\": \"{}\"}}", opt.json_key, addr_str);
        } else {
            println!("{}", addr_str);
        }
    }

    return Ok(());
}

// -------------------------------------------------------------------------------------------------
// Test
// -------------------------------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_run() {
        let args = vec!["gip"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_verbose() {
        let args = vec!["gip", "-v"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_string() {
        let args = vec!["gip", "-s"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_json() {
        let args = vec!["gip", "-j"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_list() {
        let args = vec!["gip", "-l"];
        let opt = Opt::from_iter(args.iter());
        let ret = run_opt(&opt);
        assert!(ret.is_ok());
    }

    #[test]
    fn test_v6() {
        let args = vec!["gip", "-6"];
        let opt = Opt::from_iter(args.iter());
        let _ = run_opt(&opt);
    }

    #[test]
    fn test_proxy() {
        let args = vec!["gip", "--proxy", "example.com:8080"];
        let opt = Opt::from_iter(args.iter());
        let _ = run_opt(&opt);
    }

}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::str;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::process::Command;
use util;

pub struct Git<'a> {
    command: String,
    git_dir: &'a str,
}

impl<'a> Git<'a> {
    pub fn command<S: AsRef<OsStr>>(&self, args: &[S]) -> util::Result<String> {
        let out = Command::new(&self.command)
                    .arg("--git-dir")
                    .arg(self.git_dir)
                    .args(args)
                    .output()
                    .map_err(|e| format!("Error on executing git command: {}", e))?;
        if !out.status.success() {
            return Err(format!("Git command exited with non-zero status: {}", str::from_utf8(&out.stderr).expect("Failed to convert git command output from UTF8")));
        }
        let s = str::from_utf8(&out.stdout).map_err(|e| format!("Invalid UTF-8 sequence in output of git command: {}", e))?;
        Ok(s.trim().to_string())
    }

    pub fn hash<S: AsRef<str>>(&self, commit: &S) -> util::Result<String> {
        self.command(&["rev-parse", commit.as_ref()])
    }

    pub fn remote_url<S: AsRef<str>>(&self, name: &S) -> util::Result<String> {
        // XXX:
        // `git remote get-url {name}` is not available because it's added recently (at 2.6.1).
        // Note that git installed in Ubuntu 14.04 is 1.9.1.
        let mut url = self.command(&["config", "--get", &format!("remote.{}.url", name.as_ref())])?;
        if url.starts_with("git@") {
            // Note: Convert SSH protocol URL
            //  git@service.com:user/repo.git -> ssh://git@service.com:22/user/repo.git
            if let Some(i) = url.find(':') {
                util::insert(&mut url, i + 1, "22/");
            }
            util::insert(&mut url, 0, "ssh://");
        }
        Ok(url)
    }

    pub fn tracking_remote(&self) -> util::Result<(String, String)> {
        let out = self.command(&["rev-parse", "--abbrev-ref", "--symbolic", "@{u}"])?;
        let mut split = out.splitn(2, "/");
        let url = match split.next() {
            None => return Err(format!("Invalid tracking remote name: {}", out)),
            Some(ref u) => self.remote_url(&u)?,
        };
        let branch = match split.next() {
            None => return Err(format!("Invalid tracking remote name: {}", out)),
            Some(ref u) => u.to_string(),
        };
        Ok((url, branch))
    }

    pub fn root_dir(&self) -> util::Result<PathBuf> {
        // XXX:
        // `git rev-parse` can't be used with --git-dir arguments.
        // `git --git-dir ../.git rev-parse --show-toplevel` always returns
        // current working directory.
        // So here root directory is calculated from git-dir.
        let p = Path::new(self.git_dir)
                    .parent()
                    .ok_or(format!("Cannot locate root directory from git-dir '{}'", self.git_dir))?;
        Ok(p.to_owned())
    }
}

pub fn get_git_command() -> String {
    env::var("GIT_BRWS_GIT_COMMAND").unwrap_or("git".to_string())
}

pub fn new(dir: &PathBuf) -> util::Result<Git> {
    let command = get_git_command();
    let path = dir.to_str().ok_or(format!("Failed to retrieve directory path as UTF8 string: {:?}", dir))?;
    Ok(Git { command: command, git_dir: path })
}

fn set_current_dir(p: &PathBuf) -> util::Result<()> {
    env::set_current_dir(p).map_err(|e| format!("Error on setting current direcotry to {:?}: {}", p, e))
}

fn git_revparse_git_dir(current: &PathBuf) -> util::Result<PathBuf> {
    // XXX:
    // We may be able to use exec or spawn to change current working directory
    // in child command.
    // It can avoid changing current working directory globally.
    let out = Command::new(get_git_command())
                .arg("rev-parse")
                .arg("--git-dir")
                .output()
                .map_err(|e| format!("{}", e))?;
    if !out.status.success() {
        return Err(format!("Git command exited with non-zero status: {}", str::from_utf8(&out.stderr).expect("Failed to convert git command output from UTF8")));
    }

    let s = str::from_utf8(&out.stdout).map_err(|e| format!("Invalid UTF-8 sequence in output of git command: {}", e))?.trim();

    let p = Path::new(s);
    if p.is_relative() {
        Ok(current.join(&p))
    } else {
        Ok(p.to_owned())
    }
}

pub fn git_dir(dir: Option<String>) -> util::Result<PathBuf> {
    let current_dir = env::current_dir().map_err(|e| format!("{}", e))?;
    match dir {
        Some(d) => {
            let d = fs::canonicalize(&d).map_err(|e| format!("Cannot locate canonical path for '{}': {}", d, e))?;
            set_current_dir(&d)?;
            let p = git_revparse_git_dir(&d).map_err(|e| format!("{}", e));
            set_current_dir(&current_dir)?;
            p
        },
        None => git_revparse_git_dir(&current_dir),
    }
}
<commit_msg>do not change current directory globally<commit_after>use std::env;
use std::fs;
use std::str;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::process::Command;
use util;

pub struct Git<'a> {
    command: String,
    git_dir: &'a str,
}

impl<'a> Git<'a> {
    pub fn command<S: AsRef<OsStr>>(&self, args: &[S]) -> util::Result<String> {
        let out = Command::new(&self.command)
                    .arg("--git-dir")
                    .arg(self.git_dir)
                    .args(args)
                    .output()
                    .map_err(|e| format!("Error on executing git command: {}", e))?;
        if !out.status.success() {
            return Err(format!("Git command exited with non-zero status: {}", str::from_utf8(&out.stderr).expect("Failed to convert git command output from UTF8")));
        }
        let s = str::from_utf8(&out.stdout).map_err(|e| format!("Invalid UTF-8 sequence in output of git command: {}", e))?;
        Ok(s.trim().to_string())
    }

    pub fn hash<S: AsRef<str>>(&self, commit: &S) -> util::Result<String> {
        self.command(&["rev-parse", commit.as_ref()])
    }

    pub fn remote_url<S: AsRef<str>>(&self, name: &S) -> util::Result<String> {
        // XXX:
        // `git remote get-url {name}` is not available because it's added recently (at 2.6.1).
        // Note that git installed in Ubuntu 14.04 is 1.9.1.
        let mut url = self.command(&["config", "--get", &format!("remote.{}.url", name.as_ref())])?;
        if url.starts_with("git@") {
            // Note: Convert SSH protocol URL
            //  git@service.com:user/repo.git -> ssh://git@service.com:22/user/repo.git
            if let Some(i) = url.find(':') {
                util::insert(&mut url, i + 1, "22/");
            }
            util::insert(&mut url, 0, "ssh://");
        }
        Ok(url)
    }

    pub fn tracking_remote(&self) -> util::Result<(String, String)> {
        let out = self.command(&["rev-parse", "--abbrev-ref", "--symbolic", "@{u}"])?;
        let mut split = out.splitn(2, "/");
        let url = match split.next() {
            None => return Err(format!("Invalid tracking remote name: {}", out)),
            Some(ref u) => self.remote_url(&u)?,
        };
        let branch = match split.next() {
            None => return Err(format!("Invalid tracking remote name: {}", out)),
            Some(ref u) => u.to_string(),
        };
        Ok((url, branch))
    }

    pub fn root_dir(&self) -> util::Result<PathBuf> {
        // XXX:
        // `git rev-parse` can't be used with --git-dir arguments.
        // `git --git-dir ../.git rev-parse --show-toplevel` always returns
        // current working directory.
        // So here root directory is calculated from git-dir.
        let p = Path::new(self.git_dir)
                    .parent()
                    .ok_or(format!("Cannot locate root directory from git-dir '{}'", self.git_dir))?;
        Ok(p.to_owned())
    }
}

pub fn get_git_command() -> String {
    env::var("GIT_BRWS_GIT_COMMAND").unwrap_or("git".to_string())
}

pub fn new(dir: &PathBuf) -> util::Result<Git> {
    let command = get_git_command();
    let path = dir.to_str().ok_or(format!("Failed to retrieve directory path as UTF8 string: {:?}", dir))?;
    Ok(Git { command: command, git_dir: path })
}

pub fn git_dir(dir: Option<String>) -> util::Result<PathBuf> {
    let mut cmd = Command::new(get_git_command());
    cmd.arg("rev-parse").arg("--git-dir");
    if let Some(d) = dir {
        let d = fs::canonicalize(&d).map_err(|e| format!("Cannot locate canonical path for '{}': {}", d, e))?;
        cmd.current_dir(d);
    }

    let out = cmd.output().map_err(|e| format!("{}", e))?;
    if !out.status.success() {
        let stderr = str::from_utf8(&out.stderr).map_err(|e| format!("Failed to convert git command output: {}", e))?;
        return Err(format!("Git command exited with non-zero status: {}", stderr));
    }

    let s = str::from_utf8(&out.stdout).map_err(|e| format!("Invalid UTF-8 sequence in output of git command: {}", e))?.trim();

    let p = Path::new(s);
    if p.is_relative() {
        let current = env::current_dir().map_err(|e| format!("Unable to get current working directory: {}", e))?;
        Ok(current.join(&p))
    } else {
        Ok(p.to_owned())
    }
}

<|endoftext|>


<commit_before>#![allow(unused_variables, unused_mut, dead_code)]

extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    for i in 0..361 {
        println!("1");
        canvas.apply(Command::Move {
            distance: 10.,
        });
        println!("2");
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
        println!("3");
        //canvas.apply(Command::Pen {
        //    enabled: i % 2 == 0,
        //});
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Mul};

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    trait LinearInterpolation {
        /// Interpolate between self and the given target
        ///
        /// t must be between 0.0 and 1.0
        fn interpolate(self, target: Self, t: f64) -> Self;
    }

    impl LinearInterpolation for f64 {
        fn interpolate(self, target: Self, t: f64) -> Self {
            (target - self) * t
        }
    }

    impl LinearInterpolation for (f64, f64) {
        fn interpolate(self, target: Self, t: f64) -> Self {
            let (x1, y1) = self;
            let (x2, y2) = target;

            let x = x1.interpolate(x2, t);
            let y = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
            (x, y)
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: (f64, f64),
        end: (f64, f64),
        pen: Pen,
    }

    impl Path {
        /// Returns the size of the line represented by this path
        fn len(&self) -> f64 {
            let (x1, y1) = self.start;
            let (x2, y2) = self.start;
            ((x2 - x1).powi(2) + (y2 - y1).powi(2)).sqrt()
        }

        /// Linearly interpolate between the points in this path
        fn interpolate(&self, t: f64) -> (f64, f64) {
            self.start.interpolate(self.end, t)
        }
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: (f64, f64),
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Default::default(),
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };
                let center = (200., 200.);

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            match command {
                                Command::Move {distance} => {
                                    if animation.is_some() {
                                        unreachable!("The main thread did not wait for the animation to complete before sending another command")
                                    }
                                    if distance != 0. {
                                        let current_x = center.0 + turtle.position.0;
                                        let current_y = center.1 + turtle.position.1;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        println!("move forward {:?}", (x, y));
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start: (current_x, current_y),
                                                    end: (current_x + x, current_y + y),
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    if animation.is_some() {
                                        unreachable!("The main thread did not wait for the animation to complete before sending another command")
                                    }
                                    animation = Some(Animation {
                                        kind: AnimationKind::Rotation {
                                            target_angle: turtle.heading + angle,
                                            clockwise,
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                },
                                Command::Pen {enabled} => unimplemented!(),
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed();

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    let speed = speed.to_absolute();
                                    let length = path.len();
                                    let total_time = Duration::from_millis((length * 1000. / speed) as u64);

                                    let progress = elapsed.as_secs() as f64 / total_time.as_secs() as f64;
                                    if progress > 1.0 {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                    }
                                    else {
                                        println!("progress = {}", progress);
                                        let current = path.interpolate(progress);
                                        turtle.position = current;
                                        println!("turtle.position = {:?}", turtle.position);

                                        let Pen {thickness, color, ..} = path.pen;
                                        let start = path.start;
                                        line(color.into(), thickness,
                                        [start.0, start.1, current.0, current.1],
                                        c.transform, g);
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = speed.to_rotation();
                                    animation_complete = true;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            line(pen.color.into(), pen.thickness,
                                [start.0, start.1, end.0, end.1],
                                c.transform, g);
                        }
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<commit_msg>Animations are fundamentally broken, but at least the turtle stays centered now<commit_after>#![allow(unused_variables, unused_mut, dead_code)]

extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    for i in 0..361 {
        println!("1");
        canvas.apply(Command::Move {
            distance: 10.,
        });
        println!("2");
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
        println!("3");
        //canvas.apply(Command::Pen {
        //    enabled: i % 2 == 0,
        //});
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Mul};

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    trait LinearInterpolation {
        /// Interpolate between self and the given target
        ///
        /// t must be between 0.0 and 1.0
        fn interpolate(self, target: Self, t: f64) -> Self;
    }

    impl LinearInterpolation for f64 {
        fn interpolate(self, target: Self, t: f64) -> Self {
            (target - self) * t
        }
    }

    impl LinearInterpolation for (f64, f64) {
        fn interpolate(self, target: Self, t: f64) -> Self {
            let (x1, y1) = self;
            let (x2, y2) = target;

            let x = x1.interpolate(x2, t);
            let y = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
            (x, y)
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: (f64, f64),
        end: (f64, f64),
        pen: Pen,
    }

    impl Path {
        /// Returns the size of the line represented by this path
        fn len(&self) -> f64 {
            let (x1, y1) = self.start;
            let (x2, y2) = self.end;
            ((x2 - x1).powi(2) + (y2 - y1).powi(2)).sqrt()
        }

        /// Linearly interpolate between the points in this path
        fn interpolate(&self, t: f64) -> (f64, f64) {
            self.start.interpolate(self.end, t)
        }
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: (f64, f64),
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Default::default(),
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            match command {
                                Command::Move {distance} => {
                                    if animation.is_some() {
                                        unreachable!("The main thread did not wait for the animation to complete before sending another command")
                                    }
                                    if distance != 0. {
                                        let current_x = turtle.position.0;
                                        let current_y = turtle.position.1;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        println!("move forward {:?}", (x, y));
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start: (current_x, current_y),
                                                    end: (current_x + x, current_y + y),
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    if animation.is_some() {
                                        unreachable!("The main thread did not wait for the animation to complete before sending another command")
                                    }
                                    animation = Some(Animation {
                                        kind: AnimationKind::Rotation {
                                            target_angle: turtle.heading + angle,
                                            clockwise,
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                },
                                Command::Pen {enabled} => unimplemented!(),
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = (width * 0.5, height * 0.5);

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis();
                            println!("elapsed = {}", elapsed);

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    let speed = speed.to_absolute();
                                    let length = path.len();
                                    println!("{:?}", (speed, length));
                                    let total_time = length / speed * 1000.; // ms
                                    println!("total_time = {}", total_time);

                                    let progress = elapsed as f64 / total_time;
                                    if progress > 1.0 {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                    }
                                    else {
                                        println!("progress = {}", progress);
                                        let current = path.interpolate(progress);
                                        turtle.position = current;
                                        println!("turtle.position = {:?}", turtle.position);

                                        let Pen {thickness, color, enabled} = path.pen;
                                        let start = path.start;

                                        if enabled {
                                            line(color.into(), thickness,
                                            [
                                            center.0 + start.0, center.1 + start.1,
                                            center.0 + current.0, center.1 + current.1
                                            ],
                                            c.transform, g);
                                        }
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = speed.to_rotation();
                                    animation_complete = true;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            line(pen.color.into(), pen.thickness,
                                [start.0, start.1, end.0, end.1],
                                c.transform, g);
                        }

                        // TODO: Draw the turtle
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<|endoftext|>