<commit_before>////////////////////////////////////////////////////////////////
// Several variations on a theme to test failing variants
////////////////////////////////////////////////////////////////

use crate as verifier;

use crate::assert;

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t0() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);

    #[cfg(not(any(feature = "verifier-crux", feature = "verifier-seahorn")))]
    if verifier::is_replay() { eprintln!("Test values: a = {}, b = {}", a, b) }

    let r = a*b;
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t1() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t2() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(Some("multiply with overflow"));

    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    let r = a*b;
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t3() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(Some("assertion failed"));

    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r < 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t4() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(None);

    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r < 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t5() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(a <= 1000000); // avoid overflow
    verifier::assume(b <= 1000000);
    verifier::assert_eq!(a + b, b + a);
    verifier::assert_ne!(a, a+1);
}

// KLEE-only test of get_concrete_value and is_symbolic
#[cfg(feature = "verifier-klee")]
#[test]
fn concrete1() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(a <= 100); // avoid overflow
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));

    let b = verifier::VerifierNonDet::get_concrete_value(a);
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
    verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
    verifier::assert!(b <= 100);

    // There is no expectation that each call to get_concrete_value
    // will produce a different result and, on KLEE, it can
    // produce the same result unless you add assumptions/branches
    // to avoid repetition.
    // This test is commented out because we don't want to insist
    // on one behavior or another.
    // let c = verifier::VerifierNonDet::get_concrete_value(a);
    // verifier::assert_eq!(b, c);
}

// KLEE-only test of concretize
#[cfg(feature = "verifier-klee")]
#[test]
fn concrete2() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(a <= 10); // limit number of distinct solutions
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));

    let b = verifier::concretize(a);
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
    verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
    verifier::assert!(b <= 10);
}

// KLEE-only test of sample
#[cfg(feature = "verifier-klee")]
#[test]
fn concrete3() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(a <= 1_000_000_000); // allow a huge number of solutions
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));

    let b = verifier::sample(10, a); // consider only 10 of the possible solutions for a
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
    verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
    verifier::assert!(b <= 1_000_000_000);
}

////////////////////////////////////////////////////////////////
// End
////////////////////////////////////////////////////////////////
<commit_msg>Annotations/KLEE: Tests for Vec<u8> and strings<commit_after>////////////////////////////////////////////////////////////////
// Several variations on a theme to test failing variants
////////////////////////////////////////////////////////////////

use crate as verifier;

use crate::assert;

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t0() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);

    #[cfg(not(any(feature = "verifier-crux", feature = "verifier-seahorn")))]
    if verifier::is_replay() { eprintln!("Test values: a = {}, b = {}", a, b) }

    let r = a*b;
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t1() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t2() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(Some("multiply with overflow"));

    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    let r = a*b;
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t3() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(Some("assertion failed"));

    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r < 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t4() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(None);

    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r < 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t5() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    let b : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(a <= 1000000); // avoid overflow
    verifier::assume(b <= 1000000);
    verifier::assert_eq!(a + b, b + a);
    verifier::assert_ne!(a, a+1);
}

// KLEE-only test of get_concrete_value and is_symbolic
#[cfg(feature = "verifier-klee")]
#[test]
fn concrete1() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(a <= 100); // avoid overflow
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));

    let b = verifier::VerifierNonDet::get_concrete_value(a);
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
    verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
    verifier::assert!(b <= 100);

    // There is no expectation that each call to get_concrete_value
    // will produce a different result and, on KLEE, it can
    // produce the same result unless you add assumptions/branches
    // to avoid repetition.
    // This test is commented out because we don't want to insist
    // on one behavior or another.
    // let c = verifier::VerifierNonDet::get_concrete_value(a);
    // verifier::assert_eq!(b, c);
}

// KLEE-only test of concretize
#[cfg(feature = "verifier-klee")]
#[test]
fn concrete2() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(a <= 10); // limit number of distinct solutions
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));

    let b = verifier::concretize(a);
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
    verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
    verifier::assert!(b <= 10);
}

// KLEE-only test of sample
#[cfg(feature = "verifier-klee")]
#[test]
fn concrete3() {
    let a : u32 = verifier::AbstractValue::abstract_value();
    verifier::assume(a <= 1_000_000_000); // allow a huge number of solutions
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));

    let b = verifier::sample(10, a); // consider only 10 of the possible solutions for a
    verifier::assert!(verifier::VerifierNonDet::is_symbolic(a));
    verifier::assert!(!verifier::VerifierNonDet::is_symbolic(b));
    verifier::assert!(b <= 1_000_000_000);
}

/// Test of verifier_nondet_bytes
#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn bytes() {
    let a = verifier::verifier_nondet_bytes(8);
    for i in &a {
        verifier::assume(*i == 42);
    }
    if verifier::is_replay() {
        println!("{:?}", a);
    }
    verifier::assert_eq!(a.len(), 8);
    verifier::assert_ne!(a[2], 0u8);
    verifier::assert_eq!(a[3], 42u8);
}

/// Test of verifier_nondet_cstring
#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn cstring() {
    let a = verifier::verifier_nondet_cstring(8);

    if verifier::is_replay() {
        println!("{:?}", a);
    }

    // force string to be plain ASCII - to keep things simple
    for i in a.as_bytes() {
        // note: this code suffers from a path explosion and
        // would benefit from using verifier::coherent!
        // We will not do that though because the goal is to
        // test this feature in isolation.
        verifier::assume(i.is_ascii_alphabetic());
    }

    for i in a.as_bytes() {
        verifier::assert!(i.is_ascii());
        // this assertion would fail
        // verifier::assert!(i.is_ascii_digit());
    }
}

/// Test of verifier_nondet_ascii_string
#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn string_ok() {
    let a = verifier::verifier_nondet_ascii_string(6);

    if verifier::is_replay() {
        println!("{:?}", a);
    }

    // force string to be a legal int
    for i in a.as_bytes() {
        verifier::assume(('0'..='3').contains(&(*i as char)))
    }

    let i: u32 = a.parse().unwrap();
    verifier::assert!(i <= 333_333);
}

/// Test of  verifier_nondet_ascii_stringg
#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn string_should_fail() {
    verifier::expect(Some("assertion failed"));
    let a = verifier::verifier_nondet_ascii_string(6);

    if verifier::is_replay() {
        println!("{:?}", a);
    }

    // force string to be a legal int
    for i in a.as_bytes() {
        verifier::assume(('0'..='3').contains(&(*i as char)))
    }

    let i: u32 = a.parse().unwrap();
    verifier::assert!(i <= 222_222);
}

////////////////////////////////////////////////////////////////
// End
////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////
// Several variations on a theme to test failing variants
////////////////////////////////////////////////////////////////

#[cfg(feature = "verifier-klee")]
use crate::klee as verifier;

#[cfg(feature = "verifier-crux")]
use crate::crux as verifier;
#[cfg(feature = "verifier-crux")]
use crate::assert;
#[cfg(feature = "verifier-crux")]
use crate::assert_eq;
#[cfg(feature = "verifier-crux")]
use crate::assert_ne;

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t0() {
    let a = crate::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);

    #[cfg(not(feature = "verifier-crux"))]
    if verifier::is_replay() { eprintln!("Test values: a = {}, b = {}", a, b) }

    let r = a*b;
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t1() {
    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t2() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(Some("multiply with overflow"));

    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    let r = a*b;
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t3() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(Some("assertion failed"));

    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r < 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t4() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(None);

    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r < 56);
}

////////////////////////////////////////////////////////////////
// End
////////////////////////////////////////////////////////////////
<commit_msg>Clean the use of mod and use in tests<commit_after>////////////////////////////////////////////////////////////////
// Several variations on a theme to test failing variants
////////////////////////////////////////////////////////////////

use crate as verifier;

use crate::assert;
use crate::assert_eq;
use crate::assert_ne;

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t0() {
    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);

    #[cfg(not(feature = "verifier-crux"))]
    if verifier::is_replay() { eprintln!("Test values: a = {}, b = {}", a, b) }

    let r = a*b;
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t1() {
    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t2() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(Some("multiply with overflow"));

    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    let r = a*b;
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    assert!(20 <= r && r <= 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t3() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(Some("assertion failed"));

    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r < 56);
}

#[cfg_attr(not(feature = "verifier-crux"), test)]
#[cfg_attr(feature = "verifier-crux", crux_test)]
fn t4() {
    #[cfg(not(feature = "verifier-crux"))]
    verifier::expect(None);

    let a = verifier::abstract_value::<u32>();
    let b = verifier::abstract_value::<u32>();
    verifier::assume(4 <= a && a <= 7);
    verifier::assume(5 <= b && b <= 8);
    let r = a*b;
    assert!(20 <= r && r < 56);
}

////////////////////////////////////////////////////////////////
// End
////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, LittleEndian};

pub struct Stream {
    chacha20: ChaCha20,
    counter: u32,
    block: [u8; 64],
    block_index: u8,
}

pub struct ChaCha20 {
    state: [u32; 16],
}

/// A ChaCha20 iterator that can be used for encryption and decryption.
///
/// Initialized with a 32-byte key and 12-byte nonce. If reusing a key for encryption, be sure to
/// generate a unique nonce so that a given (key, nonce) pair is never used twice.
///
/// # Overflow Behavior
///
/// Iterating past 256 GB of the bytestream will cause the block counter to overflow.
impl Stream {
    pub fn new(key: &[u8], nonce: &[u8]) -> Self {
        let chacha20 = ChaCha20::new(key, nonce);
        let block = chacha20.block(0);
        Self {
            chacha20: chacha20,
            counter: 0,
            block: block,
            block_index: 0,
        }
    }

    // not sure how legal it is to encrypt without starting with a fresh block
    pub fn encrypt(&mut self, message: &[u8], ciphertext: &mut [u8]) {
        self.xor(message, ciphertext)
    }

    pub fn decrypt(&mut self, ciphertext: &[u8], message: &mut [u8]) {
        self.xor(ciphertext, message)
    }

    fn xor(&mut self, input: &[u8], output: &mut [u8]) {
        for (x, (y, z)) in output.iter_mut().zip(self.take(input.len()).zip(input)) {
            *x = y ^ z;
        }
    }
}

// doing this is a bit strange but it seemed interesting
impl Iterator for Stream {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        if self.block_index == 64 {
            self.counter += 1; // could overflow
            self.block = self.chacha20.block(self.counter);
            self.block_index = 0;
        }
        let byte = self.block[self.block_index as usize];
        self.block_index += 1;
        Some(byte)
    }
}

impl ChaCha20 {
    pub fn new(key: &[u8], nonce: &[u8]) -> Self {
        assert_eq!(32, key.len());
        assert_eq!(12, nonce.len());
        let mut chacha20 = Self { state: [0; 16] };
        Self::setup_state(&mut chacha20.state, key, nonce);
        chacha20
    }

    pub fn block(&self, counter: u32) -> [u8; 64] {
        let mut state = [0; 16];
        self.transform_state(&mut state, counter);
        Self::serialize_block(state)
    }

    fn setup_state(state: &mut [u32; 16], key: &[u8], nonce: &[u8]) {
        state[0] = 0x6170_7865;
        state[1] = 0x3320_646e;
        state[2] = 0x7962_2d32;
        state[3] = 0x6b20_6574;
        LittleEndian::read_u32_into(key, &mut state[4..12]);
        LittleEndian::read_u32_into(nonce, &mut state[13..]);
    }

    fn transform_state(&self, state: &mut [u32; 16], counter: u32) {
        state.copy_from_slice(&self.state);
        state[12] = counter;
        for _ in 0..10 {
            Self::inner_block(state);
        }
        for (x, &y) in state.iter_mut().zip(&self.state) {
            *x = x.wrapping_add(y);
        }
        state[12] = state[12].wrapping_add(counter);
    }

    fn inner_block(state: &mut [u32; 16]) {
        Self::quarter_round(state, 0, 4, 8, 12);
        Self::quarter_round(state, 1, 5, 9, 13);
        Self::quarter_round(state, 2, 6, 10, 14);
        Self::quarter_round(state, 3, 7, 11, 15);
        Self::quarter_round(state, 0, 5, 10, 15);
        Self::quarter_round(state, 1, 6, 11, 12);
        Self::quarter_round(state, 2, 7, 8, 13);
        Self::quarter_round(state, 3, 4, 9, 14);
    }

    fn quarter_round(state: &mut [u32; 16], i: usize, j: usize, k: usize, l: usize) {
        let mut a = state[i];
        let mut b = state[j];
        let mut c = state[k];
        let mut d = state[l];
        a = a.wrapping_add(b);
        d ^= a;
        d = d.rotate_left(16);
        c = c.wrapping_add(d);
        b ^= c;
        b = b.rotate_left(12);
        a = a.wrapping_add(b);
        d ^= a;
        d = d.rotate_left(8);
        c = c.wrapping_add(d);
        b ^= c;
        b = b.rotate_left(7);
        state[i] = a;
        state[j] = b;
        state[k] = c;
        state[l] = d;
    }

    fn serialize_block(block: [u32; 16]) -> [u8; 64] {
        let mut bytes = [0; 64];
        LittleEndian::write_u32_into(&block, &mut bytes);
        bytes
    }
}

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

    const KEY: &str = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
    const NONCE: &[u8] = &[0, 0, 0, 0x09, 0, 0, 0, 0x4a, 0, 0, 0, 0];
    const SETUP_STATE: [u32; 16] = [
        0x61707865,
        0x3320646e,
        0x79622d32,
        0x6b206574,
        0x03020100,
        0x07060504,
        0x0b0a0908,
        0x0f0e0d0c,
        0x13121110,
        0x17161514,
        0x1b1a1918,
        0x1f1e1d1c,
        0x00000000,
        0x09000000,
        0x4a000000,
        0x00000000,
    ];
    const FINAL_STATE: [u32; 16] = [
        0xe4e7f110,
        0x15593bd1,
        0x1fdd0f50,
        0xc47120a3,
        0xc7f4d1c7,
        0x0368c033,
        0x9aaa2204,
        0x4e6cd4c3,
        0x466482d2,
        0x09aa9f07,
        0x05d7c214,
        0xa2028bd9,
        0xd19c12b5,
        0xb94e16de,
        0xe883d0cb,
        0x4e3c50a2,
    ];

    #[test]
    fn test_encrypt() {
        let key = &h2b(KEY);
        let nonce = &[0, 0, 0, 0, 0, 0, 0, 0x4a, 0, 0, 0, 0];
        let message = "Ladies and Gentlemen of the class of '99: If I could offer you only one \
            tip for the future, sunscreen would be it.";
        let ciphertext = h2b(
            "6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0b\
             f91b65c5524733ab8f593dabcd62b3571639d624e65152ab8f530c359f0861d8\
             07ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab7793736\
             5af90bbf74a35be6b40b8eedf2785e42874d",
        );
        let encrypted_message = &mut vec![0; message.len()];
        let decrypted_ciphertext = &mut vec![0; ciphertext.len()];

        let mut stream = Stream::new(key, nonce);
        stream.nth(64 - 1);
        stream.encrypt(message.as_bytes(), encrypted_message);
        assert_eq!(&ciphertext, encrypted_message);

        stream = Stream::new(key, nonce);
        stream.nth(64 - 1);
        stream.decrypt(&ciphertext, decrypted_ciphertext);
        assert_eq!(message.as_bytes(), decrypted_ciphertext.as_slice());
    }

    #[test]
    fn test_new() {
        let chacha20 = ChaCha20::new(&h2b(KEY), NONCE);
        let mut state = [0; 16];
        ChaCha20::setup_state(&mut state, &h2b(KEY), NONCE);
        assert_eq!(state, chacha20.state);
    }

    fn check_serialized_block(block: &[u8]) {
        let block_one = h2b(
            "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4e\
             d2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e",
        );
        assert_eq!(block_one, block.to_vec());
    }

    #[test]
    fn test_get_block() {
        let mut chacha20 = ChaCha20 { state: [0; 16] };
        ChaCha20::setup_state(&mut chacha20.state, &h2b(KEY), NONCE);
        check_serialized_block(&chacha20.block(1));
    }

    #[test]
    fn test_setup_state() {
        let mut state = [0; 16];
        ChaCha20::setup_state(&mut state, &h2b(KEY), NONCE);
        assert_eq!(SETUP_STATE, state);
    }

    #[test]
    fn test_transform_state() {
        let chacha20 = ChaCha20 { state: SETUP_STATE };
        let mut state = [0; 16];
        chacha20.transform_state(&mut state, 1);
        assert_eq!(FINAL_STATE, state);
    }

    #[test]
    fn test_inner_block() {
        let mut state = SETUP_STATE;
        state[12] = 1;
        for _ in 0..10 {
            ChaCha20::inner_block(&mut state);
        }
        assert_eq!(
            [
                0x837778ab,
                0xe238d763,
                0xa67ae21e,
                0x5950bb2f,
                0xc4f2d0c7,
                0xfc62bb2f,
                0x8fa018fc,
                0x3f5ec7b7,
                0x335271c2,
                0xf29489f3,
                0xeabda8fc,
                0x82e46ebd,
                0xd19c12b4,
                0xb04e16de,
                0x9e83d0cb,
                0x4e3c50a2,
            ],
            state
        );
    }

    #[test]
    fn test_quarter_round() {
        let mut state = [0; 16];
        state[0] = 0x11111111;
        state[1] = 0x01020304;
        state[2] = 0x9b8d6f43;
        state[3] = 0x01234567;
        ChaCha20::quarter_round(&mut state, 0, 1, 2, 3);
        assert_eq!([0xea2a92f4, 0xcb1cf8ce, 0x4581472e, 0x5881c4bb], state[..4]);

        state = [
            0x879531e0,
            0xc5ecf37d,
            0x516461b1,
            0xc9a62f8a,
            0x44c20ef3,
            0x3390af7f,
            0xd9fc690b,
            0x2a5f714c,
            0x53372767,
            0xb00a5631,
            0x974c541a,
            0x359e9963,
            0x5c971061,
            0x3d631689,
            0x2098d9d6,
            0x91dbd320,
        ];
        ChaCha20::quarter_round(&mut state, 2, 7, 8, 13);
        assert_eq!(
            [
                0x879531e0,
                0xc5ecf37d,
                0xbdb886dc,
                0xc9a62f8a,
                0x44c20ef3,
                0x3390af7f,
                0xd9fc690b,
                0xcfacafd2,
                0xe46bea80,
                0xb00a5631,
                0x974c541a,
                0x359e9963,
                0x5c971061,
                0xccc07c79,
                0x2098d9d6,
                0x91dbd320,
            ],
            state
        );
    }

    #[test]
    fn test_serialize_block() {
        check_serialized_block(&ChaCha20::serialize_block(FINAL_STATE));
    }
}
<commit_msg>chacha20: use Copy<commit_after>use byteorder::{ByteOrder, LittleEndian};

pub struct Stream {
    chacha20: ChaCha20,
    counter: u32,
    block: [u8; 64],
    block_index: u8,
}

pub struct ChaCha20 {
    state: [u32; 16],
}

/// A ChaCha20 iterator that can be used for encryption and decryption.
///
/// Initialized with a 32-byte key and 12-byte nonce. If reusing a key for encryption, be sure to
/// generate a unique nonce so that a given (key, nonce) pair is never used twice.
///
/// # Overflow Behavior
///
/// Iterating past 256 GB of the bytestream will cause the block counter to overflow.
impl Stream {
    pub fn new(key: &[u8], nonce: &[u8]) -> Self {
        let chacha20 = ChaCha20::new(key, nonce);
        let block = chacha20.block(0);
        Self {
            chacha20: chacha20,
            counter: 0,
            block: block,
            block_index: 0,
        }
    }

    // not sure how legal it is to encrypt without starting with a fresh block
    pub fn encrypt(&mut self, message: &[u8], ciphertext: &mut [u8]) {
        self.xor(message, ciphertext)
    }

    pub fn decrypt(&mut self, ciphertext: &[u8], message: &mut [u8]) {
        self.xor(ciphertext, message)
    }

    fn xor(&mut self, input: &[u8], output: &mut [u8]) {
        for (x, (y, z)) in output.iter_mut().zip(self.take(input.len()).zip(input)) {
            *x = y ^ z;
        }
    }
}

// doing this is a bit strange but it seemed interesting
impl Iterator for Stream {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        if self.block_index == 64 {
            self.counter += 1; // could overflow
            self.block = self.chacha20.block(self.counter);
            self.block_index = 0;
        }
        let byte = self.block[self.block_index as usize];
        self.block_index += 1;
        Some(byte)
    }
}

impl ChaCha20 {
    pub fn new(key: &[u8], nonce: &[u8]) -> Self {
        assert_eq!(32, key.len());
        assert_eq!(12, nonce.len());
        let mut chacha20 = Self { state: [0; 16] };
        Self::setup_state(&mut chacha20.state, key, nonce);
        chacha20
    }

    pub fn block(&self, counter: u32) -> [u8; 64] {
        let mut state = [0; 16];
        self.transform_state(&mut state, counter);
        Self::serialize_block(state)
    }

    fn setup_state(state: &mut [u32; 16], key: &[u8], nonce: &[u8]) {
        state[0] = 0x6170_7865;
        state[1] = 0x3320_646e;
        state[2] = 0x7962_2d32;
        state[3] = 0x6b20_6574;
        LittleEndian::read_u32_into(key, &mut state[4..12]);
        LittleEndian::read_u32_into(nonce, &mut state[13..]);
    }

    fn transform_state(&self, state: &mut [u32; 16], counter: u32) {
        *state = self.state;
        state[12] = counter;
        for _ in 0..10 {
            Self::inner_block(state);
        }
        for (x, &y) in state.iter_mut().zip(&self.state) {
            *x = x.wrapping_add(y);
        }
        state[12] = state[12].wrapping_add(counter);
    }

    fn inner_block(state: &mut [u32; 16]) {
        Self::quarter_round(state, 0, 4, 8, 12);
        Self::quarter_round(state, 1, 5, 9, 13);
        Self::quarter_round(state, 2, 6, 10, 14);
        Self::quarter_round(state, 3, 7, 11, 15);
        Self::quarter_round(state, 0, 5, 10, 15);
        Self::quarter_round(state, 1, 6, 11, 12);
        Self::quarter_round(state, 2, 7, 8, 13);
        Self::quarter_round(state, 3, 4, 9, 14);
    }

    fn quarter_round(state: &mut [u32; 16], i: usize, j: usize, k: usize, l: usize) {
        let mut a = state[i];
        let mut b = state[j];
        let mut c = state[k];
        let mut d = state[l];
        a = a.wrapping_add(b);
        d ^= a;
        d = d.rotate_left(16);
        c = c.wrapping_add(d);
        b ^= c;
        b = b.rotate_left(12);
        a = a.wrapping_add(b);
        d ^= a;
        d = d.rotate_left(8);
        c = c.wrapping_add(d);
        b ^= c;
        b = b.rotate_left(7);
        state[i] = a;
        state[j] = b;
        state[k] = c;
        state[l] = d;
    }

    fn serialize_block(block: [u32; 16]) -> [u8; 64] {
        let mut bytes = [0; 64];
        LittleEndian::write_u32_into(&block, &mut bytes);
        bytes
    }
}

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

    const KEY: &str = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
    const NONCE: &[u8] = &[0, 0, 0, 0x09, 0, 0, 0, 0x4a, 0, 0, 0, 0];
    const SETUP_STATE: [u32; 16] = [
        0x61707865,
        0x3320646e,
        0x79622d32,
        0x6b206574,
        0x03020100,
        0x07060504,
        0x0b0a0908,
        0x0f0e0d0c,
        0x13121110,
        0x17161514,
        0x1b1a1918,
        0x1f1e1d1c,
        0x00000000,
        0x09000000,
        0x4a000000,
        0x00000000,
    ];
    const FINAL_STATE: [u32; 16] = [
        0xe4e7f110,
        0x15593bd1,
        0x1fdd0f50,
        0xc47120a3,
        0xc7f4d1c7,
        0x0368c033,
        0x9aaa2204,
        0x4e6cd4c3,
        0x466482d2,
        0x09aa9f07,
        0x05d7c214,
        0xa2028bd9,
        0xd19c12b5,
        0xb94e16de,
        0xe883d0cb,
        0x4e3c50a2,
    ];

    #[test]
    fn test_encrypt() {
        let key = &h2b(KEY);
        let nonce = &[0, 0, 0, 0, 0, 0, 0, 0x4a, 0, 0, 0, 0];
        let message = "Ladies and Gentlemen of the class of '99: If I could offer you only one \
            tip for the future, sunscreen would be it.";
        let ciphertext = h2b(
            "6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0b\
             f91b65c5524733ab8f593dabcd62b3571639d624e65152ab8f530c359f0861d8\
             07ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab7793736\
             5af90bbf74a35be6b40b8eedf2785e42874d",
        );
        let encrypted_message = &mut vec![0; message.len()];
        let decrypted_ciphertext = &mut vec![0; ciphertext.len()];

        let mut stream = Stream::new(key, nonce);
        stream.nth(64 - 1);
        stream.encrypt(message.as_bytes(), encrypted_message);
        assert_eq!(&ciphertext, encrypted_message);

        stream = Stream::new(key, nonce);
        stream.nth(64 - 1);
        stream.decrypt(&ciphertext, decrypted_ciphertext);
        assert_eq!(message.as_bytes(), decrypted_ciphertext.as_slice());
    }

    #[test]
    fn test_new() {
        let chacha20 = ChaCha20::new(&h2b(KEY), NONCE);
        let mut state = [0; 16];
        ChaCha20::setup_state(&mut state, &h2b(KEY), NONCE);
        assert_eq!(state, chacha20.state);
    }

    fn check_serialized_block(block: &[u8]) {
        let block_one = h2b(
            "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4e\
             d2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e",
        );
        assert_eq!(block_one, block.to_vec());
    }

    #[test]
    fn test_get_block() {
        let mut chacha20 = ChaCha20 { state: [0; 16] };
        ChaCha20::setup_state(&mut chacha20.state, &h2b(KEY), NONCE);
        check_serialized_block(&chacha20.block(1));
    }

    #[test]
    fn test_setup_state() {
        let mut state = [0; 16];
        ChaCha20::setup_state(&mut state, &h2b(KEY), NONCE);
        assert_eq!(SETUP_STATE, state);
    }

    #[test]
    fn test_transform_state() {
        let chacha20 = ChaCha20 { state: SETUP_STATE };
        let mut state = [0; 16];
        chacha20.transform_state(&mut state, 1);
        assert_eq!(FINAL_STATE, state);
    }

    #[test]
    fn test_inner_block() {
        let mut state = SETUP_STATE;
        state[12] = 1;
        for _ in 0..10 {
            ChaCha20::inner_block(&mut state);
        }
        assert_eq!(
            [
                0x837778ab,
                0xe238d763,
                0xa67ae21e,
                0x5950bb2f,
                0xc4f2d0c7,
                0xfc62bb2f,
                0x8fa018fc,
                0x3f5ec7b7,
                0x335271c2,
                0xf29489f3,
                0xeabda8fc,
                0x82e46ebd,
                0xd19c12b4,
                0xb04e16de,
                0x9e83d0cb,
                0x4e3c50a2,
            ],
            state
        );
    }

    #[test]
    fn test_quarter_round() {
        let mut state = [0; 16];
        state[0] = 0x11111111;
        state[1] = 0x01020304;
        state[2] = 0x9b8d6f43;
        state[3] = 0x01234567;
        ChaCha20::quarter_round(&mut state, 0, 1, 2, 3);
        assert_eq!([0xea2a92f4, 0xcb1cf8ce, 0x4581472e, 0x5881c4bb], state[..4]);

        state = [
            0x879531e0,
            0xc5ecf37d,
            0x516461b1,
            0xc9a62f8a,
            0x44c20ef3,
            0x3390af7f,
            0xd9fc690b,
            0x2a5f714c,
            0x53372767,
            0xb00a5631,
            0x974c541a,
            0x359e9963,
            0x5c971061,
            0x3d631689,
            0x2098d9d6,
            0x91dbd320,
        ];
        ChaCha20::quarter_round(&mut state, 2, 7, 8, 13);
        assert_eq!(
            [
                0x879531e0,
                0xc5ecf37d,
                0xbdb886dc,
                0xc9a62f8a,
                0x44c20ef3,
                0x3390af7f,
                0xd9fc690b,
                0xcfacafd2,
                0xe46bea80,
                0xb00a5631,
                0x974c541a,
                0x359e9963,
                0x5c971061,
                0xccc07c79,
                0x2098d9d6,
                0x91dbd320,
            ],
            state
        );
    }

    #[test]
    fn test_serialize_block() {
        check_serialized_block(&ChaCha20::serialize_block(FINAL_STATE));
    }
}
<|endoftext|>


<commit_before>use redox::Box;
use redox::fs::file::File;
use redox::io::{Read, Write, SeekFrom};
use redox::mem;
use redox::net::*;
use redox::ptr;
use redox::rand;
use redox::slice;
use redox::{String, ToString};
use redox::to_num::*;
use redox::Vec;
use redox::URL;

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct UDPHeader {
    pub src: n16,
    pub dst: n16,
    pub len: n16,
    pub checksum: Checksum,
}

pub struct UDP {
    pub header: UDPHeader,
    pub data: Vec<u8>,
}

impl FromBytes for UDP {
    fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
        if bytes.len() >= mem::size_of::<UDPHeader>() {
            unsafe {
                return Option::Some(UDP {
                    header: ptr::read(bytes.as_ptr() as *const UDPHeader),
                    data: bytes[mem::size_of::<UDPHeader>().. bytes.len()].to_vec(),
                });
            }
        }
        Option::None
    }
}

impl ToBytes for UDP {
    fn to_bytes(&self) -> Vec<u8> {
        unsafe {
            let header_ptr: *const UDPHeader = &self.header;
            let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8, mem::size_of::<UDPHeader>()));
            ret.push_all(&self.data);
            ret
        }
    }
}

/// UDP resource
pub struct Resource {
    ip: File,
    data: Vec<u8>,
    peer_addr: IPv4Addr,
    peer_port: u16,
    host_port: u16,
}

impl Resource {
    pub fn dup(&self) -> Option<Box<Self>> {
        match self.ip.dup() {
            Some(ip) => Some(box Resource {
                ip: ip,
                data: self.data.clone(),
                peer_addr: self.peer_addr,
                peer_port: self.peer_port,
                host_port: self.host_port,
            }),
            None => None
        }
    }

    pub fn path(&self) -> Option<String> {
        Some(format!("udp://{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port))
    }

    pub fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        if self.data.len() > 0 {
            let mut bytes: Vec<u8> = Vec::new();
            mem::swap(&mut self.data, &mut bytes);

            //TODO: Allow splitting
            let i = 0;
            while i < buf.len() && i < bytes.len() {
                 buf[i] = bytes[i];
            }
            return Some(i);
        }

        loop {
            let mut bytes: Vec<u8> = Vec::new();
            match self.ip.read_to_end(&mut bytes) {
                Some(_) => {
                    if let Some(datagram) = UDP::from_bytes(bytes) {
                        if datagram.header.dst.get() == self.host_port &&
                           datagram.header.src.get() == self.peer_port {
                            //TODO: Allow splitting
                            let i = 0;
                            while i < buf.len() && i < datagram.data.len() {
                                buf[i] = datagram.data[i];
                            }
                            return Some(i);
                        }
                    }
                }
                None => break,
            }
        }

        None
    }

    pub fn write(&mut self, buf: &[u8]) -> Option<usize> {
        let udp_data = Vec::from(buf);

        let mut udp = UDP {
            header: UDPHeader {
                src: n16::new(self.host_port),
                dst: n16::new(self.peer_port),
                len: n16::new((mem::size_of::<UDPHeader>() + udp_data.len()) as u16),
                checksum: Checksum { data: 0 },
            },
            data: udp_data,
        };

        unsafe {
            let proto = n16::new(0x11);
            let datagram_len = n16::new((mem::size_of::<UDPHeader>() + udp.data.len()) as u16);
            udp.header.checksum.data =
                Checksum::compile(Checksum::sum((&IP_ADDR as *const IPv4Addr) as usize,
                                                mem::size_of::<IPv4Addr>()) +
                                  Checksum::sum((&self.peer_addr as *const IPv4Addr) as usize,
                                                mem::size_of::<IPv4Addr>()) +
                                  Checksum::sum((&proto as *const n16) as usize,
                                                mem::size_of::<n16>()) +
                                  Checksum::sum((&datagram_len as *const n16) as usize,
                                                mem::size_of::<n16>()) +
                                  Checksum::sum((&udp.header as *const UDPHeader) as usize,
                                                mem::size_of::<UDPHeader>()) +
                                  Checksum::sum(udp.data.as_ptr() as usize, udp.data.len()));
        }

        match self.ip.write(udp.to_bytes().as_slice()) {
            Some(_) => return Some(buf.len()),
            None => return None,
        }
    }

    pub fn seek(&mut self, pos: SeekFrom) -> Option<usize> {
        None
    }

    pub fn sync(&mut self) -> bool {
        self.ip.sync()
    }
}

/// UDP scheme
pub struct Scheme;

impl Scheme {
    pub fn new() -> Box<Self> {
        box Scheme
    }

    pub fn open(&mut self, url_str: &str) -> Option<Box<Resource>> {
        let url = URL::from_str(&url_str);

        //Check host and port vs path
        if url.path().len() > 0 {
            let host_port = url.port().to_num();
            if host_port > 0 && host_port < 65536 {
                if let Some(mut ip) = File::open("ip:///11") {
                    let mut bytes: Vec<u8> = Vec::new();
                    if ip.read_to_end(&mut bytes).is_some() {
                        if let Some(datagram) = UDP::from_bytes(bytes) {
                            if datagram.header.dst.get() as usize == host_port {
                                let url_bytes = [0; 4096];
                                if let Some(path) = ip.path() {
                                    let url = URL::from_string(&path);

                                    return Some(box Resource {
                                        ip: ip,
                                        data: datagram.data,
                                        peer_addr: IPv4Addr::from_string(&url.host()),
                                        peer_port: datagram.header.src.get(),
                                        host_port: host_port as u16,
                                    });
                                }
                            }
                        }
                    }
                }
            }
        } else {
            let peer_port = url.port().to_num();
            if peer_port > 0 && peer_port < 65536 {
                let host_port = (rand() % 32768 + 32768) as u16;

                if let Some(ip) = File::open(&format!("ip://{}/11", url.host())) {
                    return Some(box Resource {
                        ip: ip,
                        data: Vec::new(),
                        peer_addr: IPv4Addr::from_string(&url.host()),
                        peer_port: peer_port as u16,
                        host_port: host_port,
                    });
                }
            }
        }

        None
    }
}
<commit_msg>Code cleanup: round 3<commit_after>use redox::Box;
use redox::fs::file::File;
use redox::io::{Read, Write, SeekFrom};
use redox::mem;
use redox::net::*;
use redox::ptr;
use redox::rand;
use redox::slice;
use redox::{String, ToString};
use redox::to_num::*;
use redox::Vec;
use redox::URL;

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct UDPHeader {
    pub src: n16,
    pub dst: n16,
    pub len: n16,
    pub checksum: Checksum,
}

pub struct UDP {
    pub header: UDPHeader,
    pub data: Vec<u8>,
}

impl FromBytes for UDP {
    fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
        if bytes.len() >= mem::size_of::<UDPHeader>() {
            unsafe {
                return Option::Some(UDP {
                    header: ptr::read(bytes.as_ptr() as *const UDPHeader),
                    data: bytes[mem::size_of::<UDPHeader>().. bytes.len()].to_vec(),
                });
            }
        }
        Option::None
    }
}

impl ToBytes for UDP {
    fn to_bytes(&self) -> Vec<u8> {
        unsafe {
            let header_ptr: *const UDPHeader = &self.header;
            let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8, mem::size_of::<UDPHeader>()));
            ret.push_all(&self.data);
            ret
        }
    }
}

/// UDP resource
pub struct Resource {
    ip: File,
    data: Vec<u8>,
    peer_addr: IPv4Addr,
    peer_port: u16,
    host_port: u16,
}

impl Resource {
    pub fn dup(&self) -> Option<Box<Self>> {
        match self.ip.dup() {
            Some(ip) => Some(box Resource {
                ip: ip,
                data: self.data.clone(),
                peer_addr: self.peer_addr,
                peer_port: self.peer_port,
                host_port: self.host_port,
            }),
            None => None
        }
    }

    pub fn path(&self) -> Option<String> {
        Some(format!("udp://{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port))
    }

    pub fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        if self.data.len() > 0 {
            let mut bytes: Vec<u8> = Vec::new();
            mem::swap(&mut self.data, &mut bytes);

            //TODO: Allow splitting
            let i = 0;
            while i < buf.len() && i < bytes.len() {
                 buf[i] = bytes[i];
            }
            return Some(i);
        }

        loop {
            let mut bytes: Vec<u8> = Vec::new();
            match self.ip.read_to_end(&mut bytes) {
                Some(_) => {
                    if let Some(datagram) = UDP::from_bytes(bytes) {
                        if datagram.header.dst.get() == self.host_port &&
                           datagram.header.src.get() == self.peer_port {
                            //TODO: Allow splitting
                            let i = 0;
                            while i < buf.len() && i < datagram.data.len() {
                                buf[i] = datagram.data[i];
                            }
                            return Some(i);
                        }
                    }
                }
                None => break,
            }
        }

        None
    }

    pub fn write(&mut self, buf: &[u8]) -> Option<usize> {
        let udp_data = Vec::from(buf);

        let mut udp = UDP {
            header: UDPHeader {
                src: n16::new(self.host_port),
                dst: n16::new(self.peer_port),
                len: n16::new((mem::size_of::<UDPHeader>() + udp_data.len()) as u16),
                checksum: Checksum { data: 0 },
            },
            data: udp_data,
        };

        unsafe {
            let proto = n16::new(0x11);
            let datagram_len = n16::new((mem::size_of::<UDPHeader>() + udp.data.len()) as u16);
            udp.header.checksum.data =
                Checksum::compile(Checksum::sum((&IP_ADDR as *const IPv4Addr) as usize,
                                                mem::size_of::<IPv4Addr>()) +
                                  Checksum::sum((&self.peer_addr as *const IPv4Addr) as usize,
                                                mem::size_of::<IPv4Addr>()) +
                                  Checksum::sum((&proto as *const n16) as usize,
                                                mem::size_of::<n16>()) +
                                  Checksum::sum((&datagram_len as *const n16) as usize,
                                                mem::size_of::<n16>()) +
                                  Checksum::sum((&udp.header as *const UDPHeader) as usize,
                                                mem::size_of::<UDPHeader>()) +
                                  Checksum::sum(udp.data.as_ptr() as usize, udp.data.len()));
        }

        match self.ip.write(udp.to_bytes().as_slice()) {
            Some(_) => return Some(buf.len()),
            None => return None,
        }
    }

    pub fn seek(&mut self, pos: SeekFrom) -> Option<usize> {
        None
    }

    pub fn sync(&mut self) -> bool {
        self.ip.sync()
    }
}

/// UDP scheme
pub struct Scheme;

impl Scheme {
    pub fn new() -> Box<Self> {
        box Scheme
    }

    pub fn open(&mut self, url_str: &str) -> Option<Box<Resource>> {
        let url = URL::from_str(&url_str);

        //Check host and port vs path
        if url.path().len() > 0 {
            let host_port = url.port().to_num();
            if host_port > 0 && host_port < 65536 {
                if let Some(mut ip) = File::open("ip:///11") {
                    let mut bytes: Vec<u8> = Vec::new();
                    if ip.read_to_end(&mut bytes).is_some() {
                        if let Some(datagram) = UDP::from_bytes(bytes) {
                            if datagram.header.dst.get() as usize == host_port {
                                if let Some(path) = ip.path() {
                                    let url = URL::from_string(&path);

                                    return Some(box Resource {
                                        ip: ip,
                                        data: datagram.data,
                                        peer_addr: IPv4Addr::from_string(&url.host()),
                                        peer_port: datagram.header.src.get(),
                                        host_port: host_port as u16,
                                    });
                                }
                            }
                        }
                    }
                }
            }
        } else {
            let peer_port = url.port().to_num();
            if peer_port > 0 && peer_port < 65536 {
                let host_port = (rand() % 32768 + 32768) as u16;

                if let Some(ip) = File::open(&format!("ip://{}/11", url.host())) {
                    return Some(box Resource {
                        ip: ip,
                        data: Vec::new(),
                        peer_addr: IPv4Addr::from_string(&url.host()),
                        peer_port: peer_port as u16,
                        host_port: host_port,
                    });
                }
            }
        }

        None
    }
}
<|endoftext|>


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

use client::{connect_to_server,connect_with_retry,ServerConnection};
use cmdline::Command;
use protocol::{
    CacheStats,
    ClientRequest,
    GetStats,
    Shutdown,
};
use server;
use std::env;
use std::io::{self,Error,ErrorKind};
use std::process;

/// The default sccache server port.
pub const DEFAULT_PORT : u16 = 4225;

fn maybe_redirect_stdio(cmd : &mut process::Command) {
    if !match env::var("SCCACHE_NO_DAEMON") {
            Ok(val) => val == "1",
            Err(_) => false,
    } {
        cmd.stdin(process::Stdio::null())
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null());
    }
}

/// Re-execute the current executable as a background server.
fn run_server_process() -> io::Result<()> {
    env::current_exe().and_then(|exe_path| {
        let mut cmd = process::Command::new(exe_path);
        maybe_redirect_stdio(&mut cmd);
        cmd.env("SCCACHE_START_SERVER", "1")
            .spawn()
    }).and(Ok(()))
}

fn result_exit_code<T : FnOnce(io::Error)>(res : io::Result<()>,
                                           else_func : T) -> i32 {
    res.and(Ok(0)).unwrap_or_else(|e| {
        else_func(e);
        1
    })
}

fn connect_or_start_server(port : u16) -> io::Result<ServerConnection> {
    connect_to_server(port).or_else(|e| {
        if e.kind() == io::ErrorKind::ConnectionRefused {
            // If the connection was refused we probably need to start
            // the server.
            run_server_process().and_then(|()| connect_with_retry(port))
        } else {
            debug!("Error: {}", e);
            Err(e)
        }
    })
}

fn request_stats(mut conn : ServerConnection) -> io::Result<CacheStats> {
    debug!("request_stats");
    let mut req = ClientRequest::new();
    req.set_get_stats(GetStats::new());
    //TODO: better error mapping
    let mut response = try!(conn.request(req).or(Err(Error::new(ErrorKind::Other, "Failed to send data to or receive data from server"))));
    if response.has_stats() {
        Ok(response.take_stats())
    } else {
        Err(Error::new(ErrorKind::Other, "Unexpected server response!"))
    }
}

fn request_shutdown(mut conn : ServerConnection) -> io::Result<CacheStats> {
    debug!("request_shutdown");
    let mut req = ClientRequest::new();
    req.set_shutdown(Shutdown::new());
    //TODO: better error mapping
    let mut response = try!(conn.request(req).or(Err(Error::new(ErrorKind::Other, "Failed to send data to or receive data from server"))));
    if response.has_shuttingdown() {
        Ok(response.take_shuttingdown().take_stats())
    } else {
        Err(Error::new(ErrorKind::Other, "Unexpected server response!"))
    }
}

fn format_size(size : u64) -> String {
    //TODO: actual nice formatting
    format!("{} {}", size, "bytes")
}

fn print_stats(stats : CacheStats) -> io::Result<()> {
    for stat in stats.get_stats().iter() {
        //TODO: properly align output
        print!("{}\t\t", stat.get_name());
        if stat.has_count() {
            print!("{}", stat.get_count());
        } else if stat.has_str() {
            print!("{}", stat.get_str());
        } else if stat.has_size() {
            print!("{}", format_size(stat.get_size()));
        }
        print!("\n");
    }
    Ok(())
}

pub fn run_command(cmd : Command) -> i32 {
    match cmd {
        // Actual usage gets printed in `cmdline::parse`.
        Command::Usage => 1,
        Command::ShowStats => {
            result_exit_code(connect_or_start_server(DEFAULT_PORT).and_then(request_stats).and_then(print_stats),
                             |e| {
                                 println!("Couldn't get stats from server: {}", e);
                             })
        },
        Command::InternalStartServer => {
            // Can't report failure here, we're already daemonized.
            result_exit_code(server::start_server(DEFAULT_PORT), |_| {})
        },
        Command::StartServer => {
            println!("Starting sccache server...");
            result_exit_code(run_server_process(), |e| {
                println!("failed to spawn server: {}", e);
            })
        },
        Command::StopServer => {
            println!("Stopping sccache server...");
            result_exit_code(connect_to_server(DEFAULT_PORT).and_then(request_shutdown).and_then(print_stats),
                             |_e| {
                                 //TODO: check if this was connection refused,
                                 // print error if not.
                                 println!("Couldn't connect to server");
                             })

        },
        Command::Compile(compile_cmdline) => {
            result_exit_code(connect_or_start_server(DEFAULT_PORT).and_then(|_conn| {
                //TODO: send Compile request
                let cmd_str = compile_cmdline.join(" ");
                println!("Command: '{}'", cmd_str);
                Ok(())
            }),
                             |e| {
                                 println!("compile failed: {}", e);
                             })
        },
    }
}
<commit_msg>implement format_size<commit_after>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use client::{connect_to_server,connect_with_retry,ServerConnection};
use cmdline::Command;
use protocol::{
    CacheStats,
    ClientRequest,
    GetStats,
    Shutdown,
};
use server;
use std::env;
use std::io::{self,Error,ErrorKind};
use std::process;

/// The default sccache server port.
pub const DEFAULT_PORT : u16 = 4225;

fn maybe_redirect_stdio(cmd : &mut process::Command) {
    if !match env::var("SCCACHE_NO_DAEMON") {
            Ok(val) => val == "1",
            Err(_) => false,
    } {
        cmd.stdin(process::Stdio::null())
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null());
    }
}

/// Re-execute the current executable as a background server.
fn run_server_process() -> io::Result<()> {
    env::current_exe().and_then(|exe_path| {
        let mut cmd = process::Command::new(exe_path);
        maybe_redirect_stdio(&mut cmd);
        cmd.env("SCCACHE_START_SERVER", "1")
            .spawn()
    }).and(Ok(()))
}

fn result_exit_code<T : FnOnce(io::Error)>(res : io::Result<()>,
                                           else_func : T) -> i32 {
    res.and(Ok(0)).unwrap_or_else(|e| {
        else_func(e);
        1
    })
}

fn connect_or_start_server(port : u16) -> io::Result<ServerConnection> {
    connect_to_server(port).or_else(|e| {
        if e.kind() == io::ErrorKind::ConnectionRefused {
            // If the connection was refused we probably need to start
            // the server.
            run_server_process().and_then(|()| connect_with_retry(port))
        } else {
            debug!("Error: {}", e);
            Err(e)
        }
    })
}

fn request_stats(mut conn : ServerConnection) -> io::Result<CacheStats> {
    debug!("request_stats");
    let mut req = ClientRequest::new();
    req.set_get_stats(GetStats::new());
    //TODO: better error mapping
    let mut response = try!(conn.request(req).or(Err(Error::new(ErrorKind::Other, "Failed to send data to or receive data from server"))));
    if response.has_stats() {
        Ok(response.take_stats())
    } else {
        Err(Error::new(ErrorKind::Other, "Unexpected server response!"))
    }
}

fn request_shutdown(mut conn : ServerConnection) -> io::Result<CacheStats> {
    debug!("request_shutdown");
    let mut req = ClientRequest::new();
    req.set_shutdown(Shutdown::new());
    //TODO: better error mapping
    let mut response = try!(conn.request(req).or(Err(Error::new(ErrorKind::Other, "Failed to send data to or receive data from server"))));
    if response.has_shuttingdown() {
        Ok(response.take_shuttingdown().take_stats())
    } else {
        Err(Error::new(ErrorKind::Other, "Unexpected server response!"))
    }
}

/// Format `size_in_bytes` as a size in sensible units.
///
/// e.g. format_size(3 * 1024 * 1024 * 1024) == "3 GB"
fn format_size(size_in_bytes : u64) -> String {
    let mut size = size_in_bytes;
    let mut remainder = 0;
    for suffix in ["bytes", "kB", "MB", "GB", "TB"].iter() {
        if size < 1024 {
            let frac = if remainder > 0 {
                let rem = (100.0 * remainder as f32 / 1024.0).trunc() as i32;
                format!(".{}", if rem % 10 == 0 { rem / 10 } else { rem })
            } else {
                "".to_owned()
            };
            return format!("{}{} {}", size, frac, suffix);
        }
        remainder = size % 1024;
        size = size / 1024;
    }
    //TODO: handle this more gracefully
    return format!("{} {}", size, "PB");
}

fn print_stats(stats : CacheStats) -> io::Result<()> {
    for stat in stats.get_stats().iter() {
        //TODO: properly align output
        print!("{}\t\t", stat.get_name());
        if stat.has_count() {
            print!("{}", stat.get_count());
        } else if stat.has_str() {
            print!("{}", stat.get_str());
        } else if stat.has_size() {
            print!("{}", format_size(stat.get_size()));
        }
        print!("\n");
    }
    Ok(())
}

pub fn run_command(cmd : Command) -> i32 {
    match cmd {
        // Actual usage gets printed in `cmdline::parse`.
        Command::Usage => 1,
        Command::ShowStats => {
            result_exit_code(connect_or_start_server(DEFAULT_PORT).and_then(request_stats).and_then(print_stats),
                             |e| {
                                 println!("Couldn't get stats from server: {}", e);
                             })
        },
        Command::InternalStartServer => {
            // Can't report failure here, we're already daemonized.
            result_exit_code(server::start_server(DEFAULT_PORT), |_| {})
        },
        Command::StartServer => {
            println!("Starting sccache server...");
            result_exit_code(run_server_process(), |e| {
                println!("failed to spawn server: {}", e);
            })
        },
        Command::StopServer => {
            println!("Stopping sccache server...");
            result_exit_code(connect_to_server(DEFAULT_PORT).and_then(request_shutdown).and_then(print_stats),
                             |_e| {
                                 //TODO: check if this was connection refused,
                                 // print error if not.
                                 println!("Couldn't connect to server");
                             })

        },
        Command::Compile(compile_cmdline) => {
            result_exit_code(connect_or_start_server(DEFAULT_PORT).and_then(|_conn| {
                //TODO: send Compile request
                let cmd_str = compile_cmdline.join(" ");
                println!("Command: '{}'", cmd_str);
                Ok(())
            }),
                             |e| {
                                 println!("compile failed: {}", e);
                             })
        },
    }
}

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

    #[test]
    fn test_format_size() {
        assert_eq!("10 bytes", format_size(10));
        assert_eq!("1023 bytes", format_size(1023));
        assert_eq!("1 kB", format_size(1024));
        assert_eq!("1.5 kB", format_size(1024 + 512));
        assert_eq!("1023.99 kB", format_size(1024 * 1024 - 1));
        assert_eq!("1 MB", format_size(1024 * 1024));
        assert_eq!("1 GB", format_size(1024 * 1024 * 1024));
        assert_eq!("1.25 GB", format_size(1024 * 1024 * (1024 + 256)));
        assert_eq!("3 GB", format_size(1024 * 1024 * 1024 * 3));
        assert_eq!("1 TB", format_size(1024 * 1024 * 1024 * 1024));
        assert_eq!("1 PB", format_size(1024 * 1024 * 1024 * 1024 * 1024));
    }
}
<|endoftext|>


<commit_before>mod utils;

use clap::{App, Arg, ArgGroup, ErrorKind};

static REQ_GROUP_USAGE: &str = "error: The following required arguments were not provided:
    <base|--delete>

USAGE:
    clap-test <base|--delete>

For more information try --help";

static REQ_GROUP_CONFLICT_USAGE: &str =
    "error: The argument '<base>' cannot be used with '--delete'

USAGE:
    clap-test <base|--delete>

For more information try --help";

// FIXME: This message has regressed after https://github.com/clap-rs/clap/pull/1856
//        Need to roll back somehow.
static REQ_GROUP_CONFLICT_REV: &str =
    "error: Found argument 'base' which wasn't expected, or isn't valid in this context

If you tried to supply `base` as a PATTERN use `-- base`

USAGE:
    clap-test <base|--delete>

For more information try --help";

#[test]
fn required_group_missing_arg() {
    let result = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg(" -c, --color 'some other flag'")
        .group(
            ArgGroup::with_name("req")
                .args(&["flag", "color"])
                .required(true),
        )
        .try_get_matches_from(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group 'req' contains non-existent argument"]
fn non_existing_arg() {
    let _ = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some other flag'")
        .group(
            ArgGroup::with_name("req")
                .args(&["flg", "color"])
                .required(true),
        )
        .try_get_matches_from(vec![""]);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name must be unique\n\n\t'req' is already in use"]
fn unique_group_name() {
    let _ = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some other flag'")
        .group(ArgGroup::with_name("req").args(&["flag"]).required(true))
        .group(ArgGroup::with_name("req").args(&["color"]).required(true))
        .try_get_matches_from(vec![""]);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name '' must not conflict with argument name"]
fn groups_with_name_of_arg_name() {
    let _ = App::new("group")
        .arg(Arg::with_name("a").long("a").group("a"))
        .try_get_matches_from(vec!["", "--a"]);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name 'a' must not conflict with argument name"]
fn arg_group_with_name_of_arg_name() {
    let _ = App::new("group")
        .arg(Arg::with_name("a").long("a").group("a"))
        .group(ArgGroup::with_name("a"))
        .try_get_matches_from(vec!["", "--a"]);
}

#[test]
fn group_single_value() {
    let res = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp").args(&["flag", "color"]))
        .try_get_matches_from(vec!["", "-c", "blue"]);
    assert!(res.is_ok());

    let m = res.unwrap();
    assert!(m.is_present("grp"));
    assert_eq!(m.value_of("grp").unwrap(), "blue");
}

#[test]
fn group_single_flag() {
    let res = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp").args(&["flag", "color"]))
        .try_get_matches_from(vec!["", "-f"]);
    assert!(res.is_ok());

    let m = res.unwrap();
    assert!(m.is_present("grp"));
    assert!(m.value_of("grp").is_none());
}

#[test]
fn group_empty() {
    let res = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp").args(&["flag", "color"]))
        .try_get_matches_from(vec![""]);
    assert!(res.is_ok());

    let m = res.unwrap();
    assert!(!m.is_present("grp"));
    assert!(m.value_of("grp").is_none());
}

#[test]
fn group_reqired_flags_empty() {
    let result = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some option'")
        .group(
            ArgGroup::with_name("grp")
                .required(true)
                .args(&["flag", "color"]),
        )
        .try_get_matches_from(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn group_multi_value_single_arg() {
    let res = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color [color]... 'some option'")
        .group(ArgGroup::with_name("grp").args(&["flag", "color"]))
        .try_get_matches_from(vec!["", "-c", "blue", "red", "green"]);
    assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);

    let m = res.unwrap();
    assert!(m.is_present("grp"));
    assert_eq!(
        &*m.values_of("grp").unwrap().collect::<Vec<_>>(),
        &["blue", "red", "green"]
    );
}

#[test]
fn empty_group() {
    let r = App::new("empty_group")
        .arg(Arg::from("-f, --flag 'some flag'"))
        .group(ArgGroup::with_name("vers").required(true))
        .try_get_matches_from(vec!["empty_prog"]);
    assert!(r.is_err());
    let err = r.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn req_group_usage_string() {
    let app = App::new("req_group")
        .arg("[base] 'Base commit'")
        .arg("-d, --delete 'Remove the base commit information'")
        .group(
            ArgGroup::with_name("base_or_delete")
                .args(&["base", "delete"])
                .required(true),
        );

    assert!(utils::compare_output(
        app,
        "clap-test",
        REQ_GROUP_USAGE,
        true
    ));
}

#[test]
fn req_group_with_conflict_usage_string() {
    let app = App::new("req_group")
        .arg(Arg::from("[base] 'Base commit'").conflicts_with("delete"))
        .arg(Arg::from(
            "-d, --delete 'Remove the base commit information'",
        ))
        .group(
            ArgGroup::with_name("base_or_delete")
                .args(&["base", "delete"])
                .required(true),
        );

    assert!(utils::compare_output2(
        app,
        "clap-test --delete base",
        REQ_GROUP_CONFLICT_REV,
        REQ_GROUP_CONFLICT_USAGE,
        true
    ));
}

#[test]
fn required_group_multiple_args() {
    let result = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some other flag'")
        .group(
            ArgGroup::with_name("req")
                .args(&["flag", "color"])
                .required(true)
                .multiple(true),
        )
        .try_get_matches_from(vec!["group", "-f", "-c"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn group_multiple_args_error() {
    let result = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some other flag'")
        .group(ArgGroup::with_name("req").args(&["flag", "color"]))
        .try_get_matches_from(vec!["group", "-f", "-c"]);
    assert!(result.is_err());
    let err = result.unwrap_err();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_acts_like_arg() {
    let m = App::new("prog")
        .arg(Arg::with_name("debug").long("debug").group("mode"))
        .arg(Arg::with_name("verbose").long("verbose").group("mode"))
        .get_matches_from(vec!["prog", "--debug"]);
    assert!(m.is_present("mode"));
}

#[test]
fn issue_1794() {
    let app = clap::App::new("hello")
        .bin_name("deno")
        .arg(Arg::with_name("option1").long("option1").takes_value(false))
        .arg(Arg::with_name("pos1").takes_value(true))
        .arg(Arg::with_name("pos2").takes_value(true))
        .group(
            ArgGroup::with_name("arg1")
                .args(&["pos1", "option1"])
                .required(true),
        );

    let m = app.clone().get_matches_from(&["app", "pos1", "pos2"]);
    assert_eq!(m.value_of("pos1"), Some("pos1"));
    assert_eq!(m.value_of("pos2"), Some("pos2"));
    assert!(!m.is_present("option1"));

    let m = app
        .clone()
        .get_matches_from(&["app", "--option1", "positional"]);
    assert_eq!(m.value_of("pos1"), None);
    assert_eq!(m.value_of("pos2"), Some("positional"));
    assert!(m.is_present("option1"));
}
<commit_msg>Add a test<commit_after>mod utils;

use clap::{App, Arg, ArgGroup, ErrorKind};

static REQ_GROUP_USAGE: &str = "error: The following required arguments were not provided:
    <base|--delete>

USAGE:
    clap-test <base|--delete>

For more information try --help";

static REQ_GROUP_CONFLICT_USAGE: &str =
    "error: The argument '<base>' cannot be used with '--delete'

USAGE:
    clap-test <base|--delete>

For more information try --help";

#[allow(unused)]
static REQ_GROUP_CONFLICT_REV: &str = "error: The argument '--delete' cannot be used with '<base>'

USAGE:
    clap-test <base|--delete>

For more information try --help";

static REQ_GROUP_CONFLICT_ONLY_OPTIONS: &str =
    "error: Found argument '--all' which wasn't expected, or isn't valid in this context

If you tried to supply `--all` as a PATTERN use `-- --all`

USAGE:
    clap-test <-a|--delete>

For more information try --help";

// FIXME: This message has regressed after https://github.com/clap-rs/clap/pull/1856
//        Need to roll back somehow.
static REQ_GROUP_CONFLICT_REV_DEGRADED: &str =
    "error: Found argument 'base' which wasn't expected, or isn't valid in this context

If you tried to supply `base` as a PATTERN use `-- base`

USAGE:
    clap-test <base|--delete>

For more information try --help";

#[test]
fn required_group_missing_arg() {
    let result = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg(" -c, --color 'some other flag'")
        .group(
            ArgGroup::with_name("req")
                .args(&["flag", "color"])
                .required(true),
        )
        .try_get_matches_from(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group 'req' contains non-existent argument"]
fn non_existing_arg() {
    let _ = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some other flag'")
        .group(
            ArgGroup::with_name("req")
                .args(&["flg", "color"])
                .required(true),
        )
        .try_get_matches_from(vec![""]);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name must be unique\n\n\t'req' is already in use"]
fn unique_group_name() {
    let _ = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some other flag'")
        .group(ArgGroup::with_name("req").args(&["flag"]).required(true))
        .group(ArgGroup::with_name("req").args(&["color"]).required(true))
        .try_get_matches_from(vec![""]);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name '' must not conflict with argument name"]
fn groups_with_name_of_arg_name() {
    let _ = App::new("group")
        .arg(Arg::with_name("a").long("a").group("a"))
        .try_get_matches_from(vec!["", "--a"]);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic = "Argument group name 'a' must not conflict with argument name"]
fn arg_group_with_name_of_arg_name() {
    let _ = App::new("group")
        .arg(Arg::with_name("a").long("a").group("a"))
        .group(ArgGroup::with_name("a"))
        .try_get_matches_from(vec!["", "--a"]);
}

#[test]
fn group_single_value() {
    let res = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp").args(&["flag", "color"]))
        .try_get_matches_from(vec!["", "-c", "blue"]);
    assert!(res.is_ok());

    let m = res.unwrap();
    assert!(m.is_present("grp"));
    assert_eq!(m.value_of("grp").unwrap(), "blue");
}

#[test]
fn group_single_flag() {
    let res = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp").args(&["flag", "color"]))
        .try_get_matches_from(vec!["", "-f"]);
    assert!(res.is_ok());

    let m = res.unwrap();
    assert!(m.is_present("grp"));
    assert!(m.value_of("grp").is_none());
}

#[test]
fn group_empty() {
    let res = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp").args(&["flag", "color"]))
        .try_get_matches_from(vec![""]);
    assert!(res.is_ok());

    let m = res.unwrap();
    assert!(!m.is_present("grp"));
    assert!(m.value_of("grp").is_none());
}

#[test]
fn group_reqired_flags_empty() {
    let result = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some option'")
        .group(
            ArgGroup::with_name("grp")
                .required(true)
                .args(&["flag", "color"]),
        )
        .try_get_matches_from(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn group_multi_value_single_arg() {
    let res = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color [color]... 'some option'")
        .group(ArgGroup::with_name("grp").args(&["flag", "color"]))
        .try_get_matches_from(vec!["", "-c", "blue", "red", "green"]);
    assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);

    let m = res.unwrap();
    assert!(m.is_present("grp"));
    assert_eq!(
        &*m.values_of("grp").unwrap().collect::<Vec<_>>(),
        &["blue", "red", "green"]
    );
}

#[test]
fn empty_group() {
    let r = App::new("empty_group")
        .arg(Arg::from("-f, --flag 'some flag'"))
        .group(ArgGroup::with_name("vers").required(true))
        .try_get_matches_from(vec!["empty_prog"]);
    assert!(r.is_err());
    let err = r.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn req_group_usage_string() {
    let app = App::new("req_group")
        .arg("[base] 'Base commit'")
        .arg("-d, --delete 'Remove the base commit information'")
        .group(
            ArgGroup::with_name("base_or_delete")
                .args(&["base", "delete"])
                .required(true),
        );

    assert!(utils::compare_output(
        app,
        "clap-test",
        REQ_GROUP_USAGE,
        true
    ));
}

#[test]
fn req_group_with_conflict_usage_string() {
    let app = App::new("req_group")
        .arg(Arg::from("[base] 'Base commit'").conflicts_with("delete"))
        .arg(Arg::from(
            "-d, --delete 'Remove the base commit information'",
        ))
        .group(
            ArgGroup::with_name("base_or_delete")
                .args(&["base", "delete"])
                .required(true),
        );

    assert!(utils::compare_output2(
        app,
        "clap-test --delete base",
        REQ_GROUP_CONFLICT_REV_DEGRADED,
        REQ_GROUP_CONFLICT_USAGE,
        true
    ));
}

#[test]
fn req_group_with_conflict_usage_string_only_options() {
    let app = App::new("req_group")
        .arg(Arg::from("<all> -a, -all 'All'").conflicts_with("delete"))
        .arg(Arg::from(
            "<delete> -d, --delete 'Remove the base commit information'",
        ))
        .group(
            ArgGroup::with_name("all_or_delete")
                .args(&["all", "delete"])
                .required(true),
        );
    assert!(utils::compare_output2(
        app,
        "clap-test --delete --all",
        REQ_GROUP_CONFLICT_ONLY_OPTIONS,
        REQ_GROUP_CONFLICT_USAGE,
        true
    ));
}

#[test]
fn required_group_multiple_args() {
    let result = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some other flag'")
        .group(
            ArgGroup::with_name("req")
                .args(&["flag", "color"])
                .required(true)
                .multiple(true),
        )
        .try_get_matches_from(vec!["group", "-f", "-c"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn group_multiple_args_error() {
    let result = App::new("group")
        .arg("-f, --flag 'some flag'")
        .arg("-c, --color 'some other flag'")
        .group(ArgGroup::with_name("req").args(&["flag", "color"]))
        .try_get_matches_from(vec!["group", "-f", "-c"]);
    assert!(result.is_err());
    let err = result.unwrap_err();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}

#[test]
fn group_acts_like_arg() {
    let m = App::new("prog")
        .arg(Arg::with_name("debug").long("debug").group("mode"))
        .arg(Arg::with_name("verbose").long("verbose").group("mode"))
        .get_matches_from(vec!["prog", "--debug"]);
    assert!(m.is_present("mode"));
}

#[test]
fn issue_1794() {
    let app = clap::App::new("hello")
        .bin_name("deno")
        .arg(Arg::with_name("option1").long("option1").takes_value(false))
        .arg(Arg::with_name("pos1").takes_value(true))
        .arg(Arg::with_name("pos2").takes_value(true))
        .group(
            ArgGroup::with_name("arg1")
                .args(&["pos1", "option1"])
                .required(true),
        );

    let m = app.clone().get_matches_from(&["app", "pos1", "pos2"]);
    assert_eq!(m.value_of("pos1"), Some("pos1"));
    assert_eq!(m.value_of("pos2"), Some("pos2"));
    assert!(!m.is_present("option1"));

    let m = app
        .clone()
        .get_matches_from(&["app", "--option1", "positional"]);
    assert_eq!(m.value_of("pos1"), None);
    assert_eq!(m.value_of("pos2"), Some("positional"));
    assert!(m.is_present("option1"));
}
<|endoftext|>


<commit_before>//#![feature(trace_macros)]
#[macro_use]
extern crate nom;

use nom::{IResult,Needed,HexDisplay,space,digit,be_u16};
use std::str;

#[allow(dead_code)]
struct Range {
  start: char,
  end:   char
}

pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
  if input.len() > 0 {
    IResult::Done(&input[1..], input[0] as char)
  } else {
    IResult::Incomplete(Needed::Size(1))
  }
}

//trace_macros!(true);

#[allow(dead_code)]
named!(range<&[u8], Range>,
    alt!(
        chain!(
            start: take_char ~
            tag!("-") ~
            end: take_char,
            || {
                Range {
                    start: start,
                    end: end,
                }
            }
        ) |
        map!(
            take_char,
            |c| {
                Range {
                    start: c,
                    end: c,
                }
            }
        )
    )
);

#[allow(dead_code)]
named!(literal<&[u8], Vec<char> >,
    map!(
        many1!(take_char),
        |cs| {
          cs
        }
    )
);

#[test]
fn issue_58() {
  range(&b"abcd"[..]);
  literal(&b"abcd"[..]);
}

//trace_macros!(false);

named!(parse_ints< Vec<i32> >, many0!(spaces_or_int));

fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32>{
  println!("{}", input.to_hex(8));
  chain!(input,
    opt!(complete!(space)) ~
    x:   complete!(digit),
    || {
      println!("x: {:?}", x);
      let result = str::from_utf8(x).unwrap();
      println!("Result: {}", result);
      println!("int is empty?: {}", x.is_empty());
      match result.parse(){
        Ok(i) => i,
        Err(_) =>  panic!("UH OH! NOT A DIGIT!")
      }
    }
  )
}

#[test]
fn issue_142(){
   let subject = parse_ints(&b"12 34 5689"[..]);
   let expected = IResult::Done(&b""[..], vec![12, 34, 5689]);
   assert_eq!(subject, expected);

   let subject = parse_ints(&b"12 34 5689 "[..]);
   let expected = IResult::Done(&b" "[..], vec![12, 34, 5689]);
   assert_eq!(subject, expected)
}

#[test]
fn usize_length_bytes_issue(){
  length_bytes!(b"012346", be_u16);
}

/*
 DOES NOT COMPILE
#[test]
fn issue_152() {
  named!(take4, take!(4));
  named!(xyz, tag!("XYZ"));
  named!(abc, tag!("abc"));

  named!(sw,
    switch!(take4,
      b"abcd" => xyz |
      b"efgh" => abc
    )
  );
}
*/

#[test]
fn take_till_issue() {
    named!(nothing,
        take_till!(call!(|_| true))
    );

    assert_eq!(nothing(b""), IResult::Done(&b""[..], &b""[..]));
    assert_eq!(nothing(b"abc"), IResult::Done(&b"abc"[..], &b""[..]));
}
<commit_msg>tests/issues: don't use chain!<commit_after>//#![feature(trace_macros)]
#[macro_use]
extern crate nom;

use nom::{IResult,Needed,HexDisplay,space,digit,be_u16};
use std::str;

#[allow(dead_code)]
struct Range {
  start: char,
  end:   char
}

pub fn take_char(input: &[u8]) -> IResult<&[u8], char> {
  if input.len() > 0 {
    IResult::Done(&input[1..], input[0] as char)
  } else {
    IResult::Incomplete(Needed::Size(1))
  }
}

//trace_macros!(true);

#[allow(dead_code)]
named!(range<&[u8], Range>,
    alt!(
        do_parse!(
            start: take_char >>
            tag!("-")        >>
            end: take_char   >>
            (Range {
                start: start,
                end:   end,
            })
        ) |
        map!(
            take_char,
            |c| {
                Range {
                    start: c,
                    end:   c,
                }
            }
        )
    )
);

#[allow(dead_code)]
named!(literal<&[u8], Vec<char> >,
    map!(
        many1!(take_char),
        |cs| {
          cs
        }
    )
);

#[test]
fn issue_58() {
  range(&b"abcd"[..]);
  literal(&b"abcd"[..]);
}

//trace_macros!(false);

named!(parse_ints< Vec<i32> >, many0!(spaces_or_int));

fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32>{
  println!("{}", input.to_hex(8));
  do_parse!(input,
    opt!(complete!(space)) >>
    res: map!(complete!(digit),
    |x| {
      println!("x: {:?}", x);
      let result = str::from_utf8(x).unwrap();
      println!("Result: {}", result);
      println!("int is empty?: {}", x.is_empty());
      match result.parse(){
        Ok(i) => i,
        Err(_) =>  panic!("UH OH! NOT A DIGIT!")
      }
    }) >>
    (res)
  )
}

#[test]
fn issue_142(){
   let subject = parse_ints(&b"12 34 5689"[..]);
   let expected = IResult::Done(&b""[..], vec![12, 34, 5689]);
   assert_eq!(subject, expected);

   let subject = parse_ints(&b"12 34 5689 "[..]);
   let expected = IResult::Done(&b" "[..], vec![12, 34, 5689]);
   assert_eq!(subject, expected)
}

#[test]
fn usize_length_bytes_issue(){
  length_bytes!(b"012346", be_u16);
}

/*
 DOES NOT COMPILE
#[test]
fn issue_152() {
  named!(take4, take!(4));
  named!(xyz, tag!("XYZ"));
  named!(abc, tag!("abc"));

  named!(sw,
    switch!(take4,
      b"abcd" => xyz |
      b"efgh" => abc
    )
  );
}
*/

#[test]
fn take_till_issue() {
    named!(nothing,
        take_till!(call!(|_| true))
    );

    assert_eq!(nothing(b""), IResult::Done(&b""[..], &b""[..]));
    assert_eq!(nothing(b"abc"), IResult::Done(&b"abc"[..], &b""[..]));
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::error::Error;
use std::string::String;
use std::path::Path;
use json::{JsonValue, parse};

fn read_sprite_file(filename: &str) -> String {
  let path = Path::new(&filename);
  let mut file = match File::open(&path) {
    Ok(f) => f,
    Err(e) => panic!("File {} not found: {}", filename, e),
  };
  let mut buf = String::new();
  match file.read_to_string(&mut buf) {
    Ok(_) => buf,
    Err(_) => panic!("Couldn't read file {}", filename),
  }
}

pub fn load_character() -> JsonValue {
  let character_json = read_sprite_file("./assets/character.json");
  match parse(&character_json) {
    Ok(res) => res,
    Err(e) => panic!("Character JSON parse error {:?}", e),
  }
}
<commit_msg>Iterate sprite x,y value from JSON file<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::error::Error;
use std::string::String;
use std::path::Path;
use std::vec::Vec;
use json::{JsonValue, parse};

fn read_sprite_file(filename: &str) -> String {
  let path = Path::new(&filename);
  let mut file = match File::open(&path) {
    Ok(f) => f,
    Err(e) => panic!("File {} not found: {}", filename, e),
  };
  let mut buf = String::new();
  match file.read_to_string(&mut buf) {
    Ok(_) => buf,
    Err(_) => panic!("Couldn't read file {}", filename),
  }
}

pub fn load_character() {
  let character_json = read_sprite_file("./assets/character.json");
  let character = match parse(&character_json) {
    Ok(res) => res,
    Err(e) => panic!("Character JSON parse error {:?}", e),
  };
  let mut sprite_names = Vec::with_capacity(14);
  for x in 1..15 {
    let i = if x < 10 { format!("0{}", x) } else { format!("{}", x) };
    sprite_names.push(format!("Jog_45_{}", i));
    sprite_names.push(format!("Jog_135_{}", i));
    sprite_names.push(format!("Jog_225_{}", i));
    sprite_names.push(format!("Jog_315_{}", i));
  }
  for &ref sprite in &sprite_names {
    let x = character[sprite]["frame"]["x"].as_f64();
    let y = character[sprite]["frame"]["y"].as_f64();
    println!("{} x: {:?}, y: {:?}", sprite, x, y);
  }
}

<|endoftext|>


<commit_before>extern crate env_logger;
extern crate failure;
extern crate futures;
extern crate hubcaps;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
#[allow(unused_imports)]
#[macro_use]
extern crate structopt;
extern crate tokio;

extern crate gluon_master;

#[macro_use]
extern crate gluon_vm;
#[macro_use]
extern crate gluon_codegen;

use std::fs;
use std::ops::Deref;

use futures::{future, Future};

use hyper::client::HttpConnector;
use hyper_tls::HttpsConnector;

use gluon::{
    vm::{
        self,
        api::{OwnedFunction, RuntimeResult, IO},
        ExternModule,
    },
    Thread,
};

use structopt::StructOpt;

mod gluon;

pub fn load_master(thread: &Thread) -> vm::Result<ExternModule> {
    #[derive(Debug, Userdata)]
    pub struct TryThread(gluon_master::RootedThread);

    impl Deref for TryThread {
        type Target = gluon_master::Thread;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    thread.register_type::<TryThread>("MasterTryThread", &[])?;

    ExternModule::new(
        thread,
        record! {
            make_eval_vm => primitive!(1, "make_eval_vm", |()| {
                RuntimeResult::from(gluon_master::make_eval_vm().map(TryThread))
            }),
            eval => primitive!(2, "eval", |t: &TryThread, s: &str| gluon_master::eval(t, s)),
            format_expr => primitive!(2, |t: &TryThread, s: &str| gluon_master::format_expr(t, s))
        },
    )
}

#[derive(Debug, Default, Getable, VmType)]
pub struct Gist<'a> {
    pub code: &'a str,
}

#[derive(Debug, Default, Serialize, Pushable, VmType)]
pub struct PostGist {
    pub id: String,
    pub html_url: String,
}

#[derive(Debug, Userdata)]
struct Github(hubcaps::Github<HttpsConnector<HttpConnector>>);

fn new_github(gist_access_token: &str) -> Github {
    Github(hubcaps::Github::new(
        "try_gluon".to_string(),
        hubcaps::Credentials::Token(gist_access_token.into()),
    ))
}

fn share(
    github: &Github,
    gist: Gist,
) -> impl Future<Item = Result<PostGist, String>, Error = vm::Error> {
    info!("Share: `{}`", gist.code);

    github
        .0
        .gists()
        .create(&hubcaps::gists::GistOptions {
            description: Some("Gluon code shared from try_gluon".into()),
            public: Some(true),
            files: Some((
                "try_gluon.glu".into(),
                hubcaps::gists::Content {
                    filename: None,
                    content: gist.code.into(),
                },
            )).into_iter()
            .collect(),
        }).map_err(|err| err.to_string())
        .map(|response| PostGist {
            id: response.id,
            html_url: response.html_url,
        }).then(Ok)
}

#[derive(StructOpt, Pushable, VmType)]
struct Opts {
    #[structopt(
        long = "gist-access-token",
        env = "GIST_ACCESS_TOKEN",
        help = "The access tokens used to create gists"
    )]
    gist_access_token: Option<String>,
    #[structopt(
        short = "p",
        long = "port",
        help = "The port to start the server on"
    )]
    port: Option<u16>,
    #[structopt(
        long = "https",
        help = "Whether to run the server with https"
    )]
    https: bool,
    #[structopt(
        long = "host",
        default_value = "\"gluon-lang.org\"",
        help = "The hostname for the server"
    )]
    host: String,
    #[structopt(
        long = "staging",
        help = "Whether to use letsencrypt's staging environment"
    )]
    staging: bool,
}

fn main() {
    if let Err(err) = main_() {
        eprintln!("{}\n{}", err, err.backtrace());
    }
}

fn main_() -> Result<(), failure::Error> {
    env_logger::init();

    let opts = Opts::from_args();

    let mut runtime = tokio::runtime::Runtime::new()?;

    let vm = gluon::new_vm();
    gluon::add_extern_module(&vm, "gluon.try", gluon::load);
    gluon::add_extern_module(&vm, "gluon.try.master", load_master);
    gluon::add_extern_module(&vm, "gluon.http_server", |vm| {
        ExternModule::new(
            vm,
            record!{
                type Opts => Opts
            },
        )
    });
    gluon::add_extern_module(&vm, "github", |vm| {
        vm.register_type::<Github>("Github", &[])?;
        ExternModule::new(
            vm,
            record!{
                new_github => primitive!(1, new_github),
                share => primitive!(2, async fn share)
            },
        )
    });

    let server_source = fs::read_to_string("src/app/server.glu")?;

    runtime.block_on(future::lazy(move || {
        gluon::Compiler::new()
            .run_expr_async::<OwnedFunction<fn(Opts) -> IO<()>>>(
                &vm,
                "src.app.server",
                &server_source,
            ).and_then(|(mut f, _)| f.call_async(opts).from_err())
    }))?;

    Ok(())
}
<commit_msg>Remove extra quotes on host name<commit_after>extern crate env_logger;
extern crate failure;
extern crate futures;
extern crate hubcaps;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
#[allow(unused_imports)]
#[macro_use]
extern crate structopt;
extern crate tokio;

extern crate gluon_master;

#[macro_use]
extern crate gluon_vm;
#[macro_use]
extern crate gluon_codegen;

use std::fs;
use std::ops::Deref;

use futures::{future, Future};

use hyper::client::HttpConnector;
use hyper_tls::HttpsConnector;

use gluon::{
    vm::{
        self,
        api::{OwnedFunction, RuntimeResult, IO},
        ExternModule,
    },
    Thread,
};

use structopt::StructOpt;

mod gluon;

pub fn load_master(thread: &Thread) -> vm::Result<ExternModule> {
    #[derive(Debug, Userdata)]
    pub struct TryThread(gluon_master::RootedThread);

    impl Deref for TryThread {
        type Target = gluon_master::Thread;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    thread.register_type::<TryThread>("MasterTryThread", &[])?;

    ExternModule::new(
        thread,
        record! {
            make_eval_vm => primitive!(1, "make_eval_vm", |()| {
                RuntimeResult::from(gluon_master::make_eval_vm().map(TryThread))
            }),
            eval => primitive!(2, "eval", |t: &TryThread, s: &str| gluon_master::eval(t, s)),
            format_expr => primitive!(2, |t: &TryThread, s: &str| gluon_master::format_expr(t, s))
        },
    )
}

#[derive(Debug, Default, Getable, VmType)]
pub struct Gist<'a> {
    pub code: &'a str,
}

#[derive(Debug, Default, Serialize, Pushable, VmType)]
pub struct PostGist {
    pub id: String,
    pub html_url: String,
}

#[derive(Debug, Userdata)]
struct Github(hubcaps::Github<HttpsConnector<HttpConnector>>);

fn new_github(gist_access_token: &str) -> Github {
    Github(hubcaps::Github::new(
        "try_gluon".to_string(),
        hubcaps::Credentials::Token(gist_access_token.into()),
    ))
}

fn share(
    github: &Github,
    gist: Gist,
) -> impl Future<Item = Result<PostGist, String>, Error = vm::Error> {
    info!("Share: `{}`", gist.code);

    github
        .0
        .gists()
        .create(&hubcaps::gists::GistOptions {
            description: Some("Gluon code shared from try_gluon".into()),
            public: Some(true),
            files: Some((
                "try_gluon.glu".into(),
                hubcaps::gists::Content {
                    filename: None,
                    content: gist.code.into(),
                },
            )).into_iter()
            .collect(),
        }).map_err(|err| err.to_string())
        .map(|response| PostGist {
            id: response.id,
            html_url: response.html_url,
        }).then(Ok)
}

#[derive(StructOpt, Pushable, VmType)]
struct Opts {
    #[structopt(
        long = "gist-access-token",
        env = "GIST_ACCESS_TOKEN",
        help = "The access tokens used to create gists"
    )]
    gist_access_token: Option<String>,
    #[structopt(
        short = "p",
        long = "port",
        help = "The port to start the server on"
    )]
    port: Option<u16>,
    #[structopt(
        long = "https",
        help = "Whether to run the server with https"
    )]
    https: bool,
    #[structopt(
        long = "host",
        default_value = "gluon-lang.org",
        help = "The hostname for the server"
    )]
    host: String,
    #[structopt(
        long = "staging",
        help = "Whether to use letsencrypt's staging environment"
    )]
    staging: bool,
}

fn main() {
    if let Err(err) = main_() {
        eprintln!("{}\n{}", err, err.backtrace());
    }
}

fn main_() -> Result<(), failure::Error> {
    env_logger::init();

    let opts = Opts::from_args();

    let mut runtime = tokio::runtime::Runtime::new()?;

    let vm = gluon::new_vm();
    gluon::add_extern_module(&vm, "gluon.try", gluon::load);
    gluon::add_extern_module(&vm, "gluon.try.master", load_master);
    gluon::add_extern_module(&vm, "gluon.http_server", |vm| {
        ExternModule::new(
            vm,
            record!{
                type Opts => Opts
            },
        )
    });
    gluon::add_extern_module(&vm, "github", |vm| {
        vm.register_type::<Github>("Github", &[])?;
        ExternModule::new(
            vm,
            record!{
                new_github => primitive!(1, new_github),
                share => primitive!(2, async fn share)
            },
        )
    });

    let server_source = fs::read_to_string("src/app/server.glu")?;

    runtime.block_on(future::lazy(move || {
        gluon::Compiler::new()
            .run_expr_async::<OwnedFunction<fn(Opts) -> IO<()>>>(
                &vm,
                "src.app.server",
                &server_source,
            ).and_then(|(mut f, _)| f.call_async(opts).from_err())
    }))?;

    Ok(())
}
<|endoftext|>