<commit_before>use std::rand;
use std::rand::Rng;

fn main() {
	println("Secret Santa");

	let names = ~["Angus", "Greg", "Lewis", "Mike", "Isabel", "Rob", "Shannon", "Allan"];

	let pairings = secret_santa(&names);

	print_pairings(&pairings);
}

fn secret_santa<'r>(names: &~[&'r str]) -> ~[(&'r str,&'r str)] {
	let mut rng = rand::rng();
	let mut shuffled_names = rng.shuffle(names.clone());

	println!("Picking pairings from: {:?}", names);

	let mut pairs = ~[];

	let first = shuffled_names.last().clone();
	shuffled_names.unshift(first);

	while shuffled_names.len() > 1 {
		let chosen = shuffled_names.pop();
		let partner = shuffled_names.last().clone();

		pairs.push((chosen,partner));
	}

	return pairs.clone();
}

fn print_pairings(pairings: &~[(&str, &str)]) {
	for &pair in pairings.iter() {
			println!("{:?} --- is buying for ---> {:?}", pair.first(), pair.second());
	}
}<commit_msg>Revert "Changed implementation to be based on shuffled list"<commit_after>use std::rand;
use std::rand::Rng;

fn main() {
	println("Secret Santa");

	let names = ~["Angus", "Greg", "Lewis", "Mike", "Isabel", "Rob", "Shannon", "Allan"];

	let pairings = secret_santa(&names);

	print_pairings(&pairings);
}

fn secret_santa<'r>(names: &~[&'r str]) -> ~[(&'r str,&'r str)] {
	let mut rng = rand::rng();
	let mut unshuffled_names = names.clone();
	let mut shuffled_names = rng.shuffle(names.clone());

	println!("Picking pairings from: {:?}", unshuffled_names);

	let mut pairs = ~[];

	while shuffled_names.len() > 0 {
		let chosen = unshuffled_names.pop();
		let partner = shuffled_names.pop();

		if( chosen == partner ) {
			unshuffled_names.push(chosen);
			shuffled_names.push(partner);

			if(shuffled_names.len() == 1) {
				break;
			}
			rng.shuffle_mut(shuffled_names);
			loop;
		}

		pairs.push((chosen,partner));
	}

	if(shuffled_names.len() == 1) {
		println("Restarting - no good solution.");
		secret_santa(names);
	}

	return pairs.clone();
}

fn print_pairings(pairings: &~[(&str, &str)]) {
	for &pair in pairings.iter() {
			println!("{:?} --- is buying for ---> {:?}", pair.first(), pair.second());
	}
}<|endoftext|>


<commit_before><commit_msg>string was fun ...<commit_after>
fn takes_slice(slice: &str) {
    println!("got {}", slice);
}

fn main() {
    // two types of string
    // &str and String

    // &str is string slices
    // has fixed size and cannot be mutated
    // reference to the sequence of UTF8 bytes

    let greeting = "Hello there."; // greeting: &'static str
    println!("{}", greeting);

    let multi = "this is
    weird syntax with newline and spaces";
    println!("{}", multi);

    let multi2 = "this is too\
    weird syntax without newline and spaces";
    println!("{}", multi2);

    // String is heap allocated and growable
    let mut hello = "hello".to_string();
    hello.push_str(" world!");

    println!("{}", hello);

    takes_slice(&hello);

    // string indexing is not supported
    let hachiko = "忠犬ハチ公";

    for b in hachiko.as_bytes() {
        print!("{}, ", b);
    }

    print!("\n");

    for c in hachiko.chars() {
        print!("{}, ", c);
    }

    print!("\n");

    print!("2nd char {:?} \n", hachiko.chars().nth(1));

    let h = &greeting[0..2];
    println!("{}", h);

    // doesnot work wtf so much for everything UTF
    // let hh = &hachiko[0..2];
    // println!("{}", hh);

    let h1 = "hello".to_string();
    let h2 = "world";

    let h3 = h1 + h2;
    println!("concatenated {}", h3);

    let h1 = "hello".to_string();
    let h2 = "world".to_string();
    let h3 = h1 + &h2;
    println!("&String are coersed to &str {}", h3);
}
<|endoftext|>


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

//! Integer and floating-point number formatting

#![allow(deprecated)]

use fmt;
use ops::{Div, Rem, Sub};
use str;
use slice;
use ptr;
use mem;

#[doc(hidden)]
trait Int: PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
           Sub<Output=Self> + Copy {
    fn zero() -> Self;
    fn from_u8(u: u8) -> Self;
    fn to_u8(&self) -> u8;
    fn to_u16(&self) -> u16;
    fn to_u32(&self) -> u32;
    fn to_u64(&self) -> u64;
    fn to_u128(&self) -> u128;
}

macro_rules! doit {
    ($($t:ident)*) => ($(impl Int for $t {
        fn zero() -> $t { 0 }
        fn from_u8(u: u8) -> $t { u as $t }
        fn to_u8(&self) -> u8 { *self as u8 }
        fn to_u16(&self) -> u16 { *self as u16 }
        fn to_u32(&self) -> u32 { *self as u32 }
        fn to_u64(&self) -> u64 { *self as u64 }
        fn to_u128(&self) -> u128 { *self as u128 }
    })*)
}
doit! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }

/// A type that represents a specific radix
#[doc(hidden)]
trait GenericRadix {
    /// The number of digits.
    fn base(&self) -> u8;

    /// A radix-specific prefix string.
    fn prefix(&self) -> &'static str {
        ""
    }

    /// Converts an integer to corresponding radix digit.
    fn digit(&self, x: u8) -> u8;

    /// Format an integer using the radix using a formatter.
    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
        // The radix can be as low as 2, so we need a buffer of at least 128
        // characters for a base 2 number.
        let zero = T::zero();
        let is_nonnegative = x >= zero;
        let mut buf = [0; 128];
        let mut curr = buf.len();
        let base = T::from_u8(self.base());
        if is_nonnegative {
            // Accumulate each digit of the number from the least significant
            // to the most significant figure.
            for byte in buf.iter_mut().rev() {
                let n = x % base;              // Get the current place value.
                x = x / base;                  // Deaccumulate the number.
                *byte = self.digit(n.to_u8()); // Store the digit in the buffer.
                curr -= 1;
                if x == zero {
                    // No more digits left to accumulate.
                    break
                };
            }
        } else {
            // Do the same as above, but accounting for two's complement.
            for byte in buf.iter_mut().rev() {
                let n = zero - (x % base);     // Get the current place value.
                x = x / base;                  // Deaccumulate the number.
                *byte = self.digit(n.to_u8()); // Store the digit in the buffer.
                curr -= 1;
                if x == zero {
                    // No more digits left to accumulate.
                    break
                };
            }
        }
        let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
        f.pad_integral(is_nonnegative, self.prefix(), buf)
    }
}

/// A binary (base 2) radix
#[derive(Clone, PartialEq)]
struct Binary;

/// An octal (base 8) radix
#[derive(Clone, PartialEq)]
struct Octal;

/// A decimal (base 10) radix
#[derive(Clone, PartialEq)]
struct Decimal;

/// A hexadecimal (base 16) radix, formatted with lower-case characters
#[derive(Clone, PartialEq)]
struct LowerHex;

/// A hexadecimal (base 16) radix, formatted with upper-case characters
#[derive(Clone, PartialEq)]
struct UpperHex;

macro_rules! radix {
    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
        impl GenericRadix for $T {
            fn base(&self) -> u8 { $base }
            fn prefix(&self) -> &'static str { $prefix }
            fn digit(&self, x: u8) -> u8 {
                match x {
                    $($x => $conv,)+
                    x => panic!("number not in the range 0..{}: {}", self.base() - 1, x),
                }
            }
        }
    }
}

radix! { Binary,    2, "0b", x @  0 ...  2 => b'0' + x }
radix! { Octal,     8, "0o", x @  0 ...  7 => b'0' + x }
radix! { Decimal,  10, "",   x @  0 ...  9 => b'0' + x }
radix! { LowerHex, 16, "0x", x @  0 ...  9 => b'0' + x,
                             x @ 10 ... 15 => b'a' + (x - 10) }
radix! { UpperHex, 16, "0x", x @  0 ...  9 => b'0' + x,
                             x @ 10 ... 15 => b'A' + (x - 10) }

macro_rules! int_base {
    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::$Trait for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                $Radix.fmt_int(*self as $U, f)
            }
        }
    }
}

macro_rules! debug {
    ($T:ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::Debug for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                fmt::Display::fmt(self, f)
            }
        }
    }
}

macro_rules! integer {
    ($Int:ident, $Uint:ident) => {
        int_base! { Binary   for $Int as $Uint  -> Binary }
        int_base! { Octal    for $Int as $Uint  -> Octal }
        int_base! { LowerHex for $Int as $Uint  -> LowerHex }
        int_base! { UpperHex for $Int as $Uint  -> UpperHex }
        debug! { $Int }

        int_base! { Binary   for $Uint as $Uint -> Binary }
        int_base! { Octal    for $Uint as $Uint -> Octal }
        int_base! { LowerHex for $Uint as $Uint -> LowerHex }
        int_base! { UpperHex for $Uint as $Uint -> UpperHex }
        debug! { $Uint }
    }
}
integer! { isize, usize }
integer! { i8, u8 }
integer! { i16, u16 }
integer! { i32, u32 }
integer! { i64, u64 }
integer! { i128, u128 }

const DEC_DIGITS_LUT: &'static[u8] =
    b"0001020304050607080910111213141516171819\
      2021222324252627282930313233343536373839\
      4041424344454647484950515253545556575859\
      6061626364656667686970717273747576777879\
      8081828384858687888990919293949596979899";

macro_rules! impl_Display {
    ($($t:ident),*: $conv_fn:ident) => ($(
    #[stable(feature = "rust1", since = "1.0.0")]
    impl fmt::Display for $t {
        #[allow(unused_comparisons)]
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let is_nonnegative = *self >= 0;
            let mut n = if is_nonnegative {
                self.$conv_fn()
            } else {
                // convert the negative num to positive by summing 1 to it's 2 complement
                (!self.$conv_fn()).wrapping_add(1)
            };
            let mut buf: [u8; 39] = unsafe { mem::uninitialized() };
            let mut curr = buf.len() as isize;
            let buf_ptr = buf.as_mut_ptr();
            let lut_ptr = DEC_DIGITS_LUT.as_ptr();

            unsafe {
                // need at least 16 bits for the 4-characters-at-a-time to work.
                if ::mem::size_of::<$t>() >= 2 {
                    // eagerly decode 4 characters at a time
                    while n >= 10000 {
                        let rem = (n % 10000) as isize;
                        n /= 10000;

                        let d1 = (rem / 100) << 1;
                        let d2 = (rem % 100) << 1;
                        curr -= 4;
                        ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                        ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
                    }
                }

                // if we reach here numbers are <= 9999, so at most 4 chars long
                let mut n = n as isize; // possibly reduce 64bit math

                // decode 2 more chars, if > 2 chars
                if n >= 100 {
                    let d1 = (n % 100) << 1;
                    n /= 100;
                    curr -= 2;
                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                }

                // decode last 1 or 2 chars
                if n < 10 {
                    curr -= 1;
                    *buf_ptr.offset(curr) = (n as u8) + b'0';
                } else {
                    let d1 = n << 1;
                    curr -= 2;
                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                }
            }

            let buf_slice = unsafe {
                str::from_utf8_unchecked(
                    slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize))
            };
            f.pad_integral(is_nonnegative, "", buf_slice)
        }
    })*);
}

impl_Display!(i8, u8, i16, u16, i32, u32: to_u32);
impl_Display!(i64, u64: to_u64);
impl_Display!(i128, u128: to_u128);
#[cfg(target_pointer_width = "16")]
impl_Display!(isize, usize: to_u16);
#[cfg(target_pointer_width = "32")]
impl_Display!(isize, usize: to_u32);
#[cfg(target_pointer_width = "64")]
impl_Display!(isize, usize: to_u64);
<commit_msg>Rollup merge of #46356 - daboross:patch-2, r=sfackler<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Integer and floating-point number formatting

#![allow(deprecated)]

use fmt;
use ops::{Div, Rem, Sub};
use str;
use slice;
use ptr;
use mem;

#[doc(hidden)]
trait Int: PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
           Sub<Output=Self> + Copy {
    fn zero() -> Self;
    fn from_u8(u: u8) -> Self;
    fn to_u8(&self) -> u8;
    fn to_u16(&self) -> u16;
    fn to_u32(&self) -> u32;
    fn to_u64(&self) -> u64;
    fn to_u128(&self) -> u128;
}

macro_rules! doit {
    ($($t:ident)*) => ($(impl Int for $t {
        fn zero() -> $t { 0 }
        fn from_u8(u: u8) -> $t { u as $t }
        fn to_u8(&self) -> u8 { *self as u8 }
        fn to_u16(&self) -> u16 { *self as u16 }
        fn to_u32(&self) -> u32 { *self as u32 }
        fn to_u64(&self) -> u64 { *self as u64 }
        fn to_u128(&self) -> u128 { *self as u128 }
    })*)
}
doit! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }

/// A type that represents a specific radix
#[doc(hidden)]
trait GenericRadix {
    /// The number of digits.
    fn base(&self) -> u8;

    /// A radix-specific prefix string.
    fn prefix(&self) -> &'static str {
        ""
    }

    /// Converts an integer to corresponding radix digit.
    fn digit(&self, x: u8) -> u8;

    /// Format an integer using the radix using a formatter.
    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
        // The radix can be as low as 2, so we need a buffer of at least 128
        // characters for a base 2 number.
        let zero = T::zero();
        let is_nonnegative = x >= zero;
        let mut buf = [0; 128];
        let mut curr = buf.len();
        let base = T::from_u8(self.base());
        if is_nonnegative {
            // Accumulate each digit of the number from the least significant
            // to the most significant figure.
            for byte in buf.iter_mut().rev() {
                let n = x % base;              // Get the current place value.
                x = x / base;                  // Deaccumulate the number.
                *byte = self.digit(n.to_u8()); // Store the digit in the buffer.
                curr -= 1;
                if x == zero {
                    // No more digits left to accumulate.
                    break
                };
            }
        } else {
            // Do the same as above, but accounting for two's complement.
            for byte in buf.iter_mut().rev() {
                let n = zero - (x % base);     // Get the current place value.
                x = x / base;                  // Deaccumulate the number.
                *byte = self.digit(n.to_u8()); // Store the digit in the buffer.
                curr -= 1;
                if x == zero {
                    // No more digits left to accumulate.
                    break
                };
            }
        }
        let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
        f.pad_integral(is_nonnegative, self.prefix(), buf)
    }
}

/// A binary (base 2) radix
#[derive(Clone, PartialEq)]
struct Binary;

/// An octal (base 8) radix
#[derive(Clone, PartialEq)]
struct Octal;

/// A decimal (base 10) radix
#[derive(Clone, PartialEq)]
struct Decimal;

/// A hexadecimal (base 16) radix, formatted with lower-case characters
#[derive(Clone, PartialEq)]
struct LowerHex;

/// A hexadecimal (base 16) radix, formatted with upper-case characters
#[derive(Clone, PartialEq)]
struct UpperHex;

macro_rules! radix {
    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
        impl GenericRadix for $T {
            fn base(&self) -> u8 { $base }
            fn prefix(&self) -> &'static str { $prefix }
            fn digit(&self, x: u8) -> u8 {
                match x {
                    $($x => $conv,)+
                    x => panic!("number not in the range 0..{}: {}", self.base() - 1, x),
                }
            }
        }
    }
}

radix! { Binary,    2, "0b", x @  0 ...  1 => b'0' + x }
radix! { Octal,     8, "0o", x @  0 ...  7 => b'0' + x }
radix! { Decimal,  10, "",   x @  0 ...  9 => b'0' + x }
radix! { LowerHex, 16, "0x", x @  0 ...  9 => b'0' + x,
                             x @ 10 ... 15 => b'a' + (x - 10) }
radix! { UpperHex, 16, "0x", x @  0 ...  9 => b'0' + x,
                             x @ 10 ... 15 => b'A' + (x - 10) }

macro_rules! int_base {
    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::$Trait for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                $Radix.fmt_int(*self as $U, f)
            }
        }
    }
}

macro_rules! debug {
    ($T:ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::Debug for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                fmt::Display::fmt(self, f)
            }
        }
    }
}

macro_rules! integer {
    ($Int:ident, $Uint:ident) => {
        int_base! { Binary   for $Int as $Uint  -> Binary }
        int_base! { Octal    for $Int as $Uint  -> Octal }
        int_base! { LowerHex for $Int as $Uint  -> LowerHex }
        int_base! { UpperHex for $Int as $Uint  -> UpperHex }
        debug! { $Int }

        int_base! { Binary   for $Uint as $Uint -> Binary }
        int_base! { Octal    for $Uint as $Uint -> Octal }
        int_base! { LowerHex for $Uint as $Uint -> LowerHex }
        int_base! { UpperHex for $Uint as $Uint -> UpperHex }
        debug! { $Uint }
    }
}
integer! { isize, usize }
integer! { i8, u8 }
integer! { i16, u16 }
integer! { i32, u32 }
integer! { i64, u64 }
integer! { i128, u128 }

const DEC_DIGITS_LUT: &'static[u8] =
    b"0001020304050607080910111213141516171819\
      2021222324252627282930313233343536373839\
      4041424344454647484950515253545556575859\
      6061626364656667686970717273747576777879\
      8081828384858687888990919293949596979899";

macro_rules! impl_Display {
    ($($t:ident),*: $conv_fn:ident) => ($(
    #[stable(feature = "rust1", since = "1.0.0")]
    impl fmt::Display for $t {
        #[allow(unused_comparisons)]
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let is_nonnegative = *self >= 0;
            let mut n = if is_nonnegative {
                self.$conv_fn()
            } else {
                // convert the negative num to positive by summing 1 to it's 2 complement
                (!self.$conv_fn()).wrapping_add(1)
            };
            let mut buf: [u8; 39] = unsafe { mem::uninitialized() };
            let mut curr = buf.len() as isize;
            let buf_ptr = buf.as_mut_ptr();
            let lut_ptr = DEC_DIGITS_LUT.as_ptr();

            unsafe {
                // need at least 16 bits for the 4-characters-at-a-time to work.
                if ::mem::size_of::<$t>() >= 2 {
                    // eagerly decode 4 characters at a time
                    while n >= 10000 {
                        let rem = (n % 10000) as isize;
                        n /= 10000;

                        let d1 = (rem / 100) << 1;
                        let d2 = (rem % 100) << 1;
                        curr -= 4;
                        ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                        ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
                    }
                }

                // if we reach here numbers are <= 9999, so at most 4 chars long
                let mut n = n as isize; // possibly reduce 64bit math

                // decode 2 more chars, if > 2 chars
                if n >= 100 {
                    let d1 = (n % 100) << 1;
                    n /= 100;
                    curr -= 2;
                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                }

                // decode last 1 or 2 chars
                if n < 10 {
                    curr -= 1;
                    *buf_ptr.offset(curr) = (n as u8) + b'0';
                } else {
                    let d1 = n << 1;
                    curr -= 2;
                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                }
            }

            let buf_slice = unsafe {
                str::from_utf8_unchecked(
                    slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize))
            };
            f.pad_integral(is_nonnegative, "", buf_slice)
        }
    })*);
}

impl_Display!(i8, u8, i16, u16, i32, u32: to_u32);
impl_Display!(i64, u64: to_u64);
impl_Display!(i128, u128: to_u128);
#[cfg(target_pointer_width = "16")]
impl_Display!(isize, usize: to_u16);
#[cfg(target_pointer_width = "32")]
impl_Display!(isize, usize: to_u32);
#[cfg(target_pointer_width = "64")]
impl_Display!(isize, usize: to_u64);
<|endoftext|>


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

//! Atomically reference counted data
//!
//! This modules contains the implementation of an atomically reference counted
//! pointer for the purpose of sharing data between tasks. This is obviously a
//! very unsafe primitive to use, but it has its use cases when implementing
//! concurrent data structures and similar tasks.
//!
//! Great care must be taken to ensure that data races do not arise through the
//! usage of `UnsafeArc`, and this often requires some form of external
//! synchronization. The only guarantee provided to you by this class is that
//! the underlying data will remain valid (not free'd) so long as the reference
//! count is greater than one.

use cast;
use clone::Clone;
use kinds::Send;
use ops::Drop;
use ptr::RawPtr;
use sync::atomics::{AtomicUint, SeqCst, Relaxed, Acquire};
use vec;

/// An atomically reference counted pointer.
///
/// Enforces no shared-memory safety.
#[unsafe_no_drop_flag]
pub struct UnsafeArc<T> {
    priv data: *mut ArcData<T>,
}

struct ArcData<T> {
    count: AtomicUint,
    data: T,
}

unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut ArcData<T> {
    let data = ~ArcData { count: AtomicUint::new(refcount), data: data };
    cast::transmute(data)
}

impl<T: Send> UnsafeArc<T> {
    /// Creates a new `UnsafeArc` which wraps the given data.
    pub fn new(data: T) -> UnsafeArc<T> {
        unsafe { UnsafeArc { data: new_inner(data, 1) } }
    }

    /// As new(), but returns an extra pre-cloned handle.
    pub fn new2(data: T) -> (UnsafeArc<T>, UnsafeArc<T>) {
        unsafe {
            let ptr = new_inner(data, 2);
            (UnsafeArc { data: ptr }, UnsafeArc { data: ptr })
        }
    }

    /// As new(), but returns a vector of as many pre-cloned handles as
    /// requested.
    pub fn newN(data: T, num_handles: uint) -> ~[UnsafeArc<T>] {
        unsafe {
            if num_handles == 0 {
                ~[] // need to free data here
            } else {
                let ptr = new_inner(data, num_handles);
                vec::from_fn(num_handles, |_| UnsafeArc { data: ptr })
            }
        }
    }

    /// Gets a pointer to the inner shared data. Note that care must be taken to
    /// ensure that the outer `UnsafeArc` does not fall out of scope while this
    /// pointer is in use, otherwise it could possibly contain a use-after-free.
    #[inline]
    pub fn get(&self) -> *mut T {
        unsafe {
            assert!((*self.data).count.load(Relaxed) > 0);
            return &mut (*self.data).data as *mut T;
        }
    }

    /// Gets an immutable pointer to the inner shared data. This has the same
    /// caveats as the `get` method.
    #[inline]
    pub fn get_immut(&self) -> *T {
        unsafe {
            assert!((*self.data).count.load(Relaxed) > 0);
            return &(*self.data).data as *T;
        }
    }

    /// checks if this is the only reference to the arc protected data
    #[inline]
    pub fn is_owned(&self) -> bool {
        unsafe {
            (*self.data).count.load(Relaxed) == 1
        }
    }
}

impl<T: Send> Clone for UnsafeArc<T> {
    fn clone(&self) -> UnsafeArc<T> {
        unsafe {
            // This barrier might be unnecessary, but I'm not sure...
            let old_count = (*self.data).count.fetch_add(1, Acquire);
            assert!(old_count >= 1);
            return UnsafeArc { data: self.data };
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for UnsafeArc<T>{
    fn drop(&mut self) {
        unsafe {
            // Happens when destructing an unwrapper's handle and from
            // `#[unsafe_no_drop_flag]`
            if self.data.is_null() {
                return
            }
            // Must be acquire+release, not just release, to make sure this
            // doesn't get reordered to after the unwrapper pointer load.
            let old_count = (*self.data).count.fetch_sub(1, SeqCst);
            assert!(old_count >= 1);
            if old_count == 1 {
                let _: ~ArcData<T> = cast::transmute(self.data);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use super::UnsafeArc;
    use mem::size_of;

    #[test]
    fn test_size() {
        assert_eq!(size_of::<UnsafeArc<[int, ..10]>>(), size_of::<*[int, ..10]>());
    }

    #[test]
    fn arclike_newN() {
        // Tests that the many-refcounts-at-once constructors don't leak.
        let _ = UnsafeArc::new2(~~"hello");
        let x = UnsafeArc::newN(~~"hello", 0);
        assert_eq!(x.len(), 0)
        let x = UnsafeArc::newN(~~"hello", 1);
        assert_eq!(x.len(), 1)
        let x = UnsafeArc::newN(~~"hello", 10);
        assert_eq!(x.len(), 10)
    }
}
<commit_msg>std: Add cfg(test) to UnsafeArc assertions<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Atomically reference counted data
//!
//! This modules contains the implementation of an atomically reference counted
//! pointer for the purpose of sharing data between tasks. This is obviously a
//! very unsafe primitive to use, but it has its use cases when implementing
//! concurrent data structures and similar tasks.
//!
//! Great care must be taken to ensure that data races do not arise through the
//! usage of `UnsafeArc`, and this often requires some form of external
//! synchronization. The only guarantee provided to you by this class is that
//! the underlying data will remain valid (not free'd) so long as the reference
//! count is greater than one.

use cast;
use clone::Clone;
use kinds::Send;
use ops::Drop;
use ptr::RawPtr;
use sync::atomics::{AtomicUint, SeqCst, Relaxed, Acquire};
use vec;

/// An atomically reference counted pointer.
///
/// Enforces no shared-memory safety.
#[unsafe_no_drop_flag]
pub struct UnsafeArc<T> {
    priv data: *mut ArcData<T>,
}

struct ArcData<T> {
    count: AtomicUint,
    data: T,
}

unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut ArcData<T> {
    let data = ~ArcData { count: AtomicUint::new(refcount), data: data };
    cast::transmute(data)
}

impl<T: Send> UnsafeArc<T> {
    /// Creates a new `UnsafeArc` which wraps the given data.
    pub fn new(data: T) -> UnsafeArc<T> {
        unsafe { UnsafeArc { data: new_inner(data, 1) } }
    }

    /// As new(), but returns an extra pre-cloned handle.
    pub fn new2(data: T) -> (UnsafeArc<T>, UnsafeArc<T>) {
        unsafe {
            let ptr = new_inner(data, 2);
            (UnsafeArc { data: ptr }, UnsafeArc { data: ptr })
        }
    }

    /// As new(), but returns a vector of as many pre-cloned handles as
    /// requested.
    pub fn newN(data: T, num_handles: uint) -> ~[UnsafeArc<T>] {
        unsafe {
            if num_handles == 0 {
                ~[] // need to free data here
            } else {
                let ptr = new_inner(data, num_handles);
                vec::from_fn(num_handles, |_| UnsafeArc { data: ptr })
            }
        }
    }

    /// Gets a pointer to the inner shared data. Note that care must be taken to
    /// ensure that the outer `UnsafeArc` does not fall out of scope while this
    /// pointer is in use, otherwise it could possibly contain a use-after-free.
    #[inline]
    pub fn get(&self) -> *mut T {
        unsafe {
            // FIXME(#12049): this needs some sort of debug assertion
            if cfg!(test) { assert!((*self.data).count.load(Relaxed) > 0); }
            return &mut (*self.data).data as *mut T;
        }
    }

    /// Gets an immutable pointer to the inner shared data. This has the same
    /// caveats as the `get` method.
    #[inline]
    pub fn get_immut(&self) -> *T {
        unsafe {
            // FIXME(#12049): this needs some sort of debug assertion
            if cfg!(test) { assert!((*self.data).count.load(Relaxed) > 0); }
            return &(*self.data).data as *T;
        }
    }

    /// checks if this is the only reference to the arc protected data
    #[inline]
    pub fn is_owned(&self) -> bool {
        unsafe {
            (*self.data).count.load(Relaxed) == 1
        }
    }
}

impl<T: Send> Clone for UnsafeArc<T> {
    fn clone(&self) -> UnsafeArc<T> {
        unsafe {
            // This barrier might be unnecessary, but I'm not sure...
            let old_count = (*self.data).count.fetch_add(1, Acquire);
            // FIXME(#12049): this needs some sort of debug assertion
            if cfg!(test) { assert!(old_count >= 1); }
            return UnsafeArc { data: self.data };
        }
    }
}

#[unsafe_destructor]
impl<T> Drop for UnsafeArc<T>{
    fn drop(&mut self) {
        unsafe {
            // Happens when destructing an unwrapper's handle and from
            // `#[unsafe_no_drop_flag]`
            if self.data.is_null() {
                return
            }
            // Must be acquire+release, not just release, to make sure this
            // doesn't get reordered to after the unwrapper pointer load.
            let old_count = (*self.data).count.fetch_sub(1, SeqCst);
            // FIXME(#12049): this needs some sort of debug assertion
            if cfg!(test) { assert!(old_count >= 1); }
            if old_count == 1 {
                let _: ~ArcData<T> = cast::transmute(self.data);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use super::UnsafeArc;
    use mem::size_of;

    #[test]
    fn test_size() {
        assert_eq!(size_of::<UnsafeArc<[int, ..10]>>(), size_of::<*[int, ..10]>());
    }

    #[test]
    fn arclike_newN() {
        // Tests that the many-refcounts-at-once constructors don't leak.
        let _ = UnsafeArc::new2(~~"hello");
        let x = UnsafeArc::newN(~~"hello", 0);
        assert_eq!(x.len(), 0)
        let x = UnsafeArc::newN(~~"hello", 1);
        assert_eq!(x.len(), 1)
        let x = UnsafeArc::newN(~~"hello", 10);
        assert_eq!(x.len(), 10)
    }
}
<|endoftext|>


<commit_before>//! Client handshake machine.

use std::{
    io::{Read, Write},
    marker::PhantomData,
};

use http::{
    header::HeaderName, HeaderMap, Request as HttpRequest, Response as HttpResponse, StatusCode,
};
use httparse::Status;
use log::*;

use super::{
    derive_accept_key,
    headers::{FromHttparse, MAX_HEADERS},
    machine::{HandshakeMachine, StageResult, TryParse},
    HandshakeRole, MidHandshake, ProcessingResult,
};
use crate::{
    error::{Error, ProtocolError, Result, UrlError},
    protocol::{Role, WebSocket, WebSocketConfig},
};

/// Client request type.
pub type Request = HttpRequest<()>;

/// Client response type.
pub type Response = HttpResponse<()>;

/// Client handshake role.
#[derive(Debug)]
pub struct ClientHandshake<S> {
    verify_data: VerifyData,
    config: Option<WebSocketConfig>,
    _marker: PhantomData<S>,
}

impl<S: Read + Write> ClientHandshake<S> {
    /// Initiate a client handshake.
    pub fn start(
        stream: S,
        request: Request,
        config: Option<WebSocketConfig>,
    ) -> Result<MidHandshake<Self>> {
        if request.method() != http::Method::GET {
            return Err(Error::Protocol(ProtocolError::WrongHttpMethod));
        }

        if request.version() < http::Version::HTTP_11 {
            return Err(Error::Protocol(ProtocolError::WrongHttpVersion));
        }

        // Check the URI scheme: only ws or wss are supported
        let _ = crate::client::uri_mode(request.uri())?;

        // Convert and verify the `http::Request` and turn it into the request as per RFC.
        // Also extract the key from it (it must be present in a correct request).
        let (request, key) = generate_request(request)?;

        let machine = HandshakeMachine::start_write(stream, request);

        let client = {
            let accept_key = derive_accept_key(key.as_ref());
            ClientHandshake { verify_data: VerifyData { accept_key }, config, _marker: PhantomData }
        };

        trace!("Client handshake initiated.");
        Ok(MidHandshake { role: client, machine })
    }
}

impl<S: Read + Write> HandshakeRole for ClientHandshake<S> {
    type IncomingData = Response;
    type InternalStream = S;
    type FinalResult = (WebSocket<S>, Response);
    fn stage_finished(
        &mut self,
        finish: StageResult<Self::IncomingData, Self::InternalStream>,
    ) -> Result<ProcessingResult<Self::InternalStream, Self::FinalResult>> {
        Ok(match finish {
            StageResult::DoneWriting(stream) => {
                ProcessingResult::Continue(HandshakeMachine::start_read(stream))
            }
            StageResult::DoneReading { stream, result, tail } => {
                let result = self.verify_data.verify_response(result)?;
                debug!("Client handshake done.");
                let websocket =
                    WebSocket::from_partially_read(stream, tail, Role::Client, self.config);
                ProcessingResult::Done((websocket, result))
            }
        })
    }
}

/// Verifies and generates a client WebSocket request from the original request and extracts a WebSocket key from it.
fn generate_request(mut request: Request) -> Result<(Vec<u8>, String)> {
    let mut req = Vec::new();
    write!(
        req,
        "GET {path} {version:?}\r\n",
        path = request.uri().path_and_query().ok_or(Error::Url(UrlError::NoPathOrQuery))?.as_str(),
        version = request.version()
    )
    .unwrap();

    // Headers that must be present in a correct request.
    const KEY_HEADERNAME: &str = "Sec-WebSocket-Key";
    const WEBSOCKET_HEADERS: [&str; 5] =
        ["Host", "Connection", "Upgrade", "Sec-WebSocket-Version", KEY_HEADERNAME];

    // We must extract a WebSocket key from a properly formed request or fail if it's not present.
    let key = request
        .headers()
        .get(KEY_HEADERNAME)
        .ok_or_else(|| {
            Error::Protocol(ProtocolError::InvalidHeader(
                HeaderName::from_bytes(KEY_HEADERNAME.as_bytes()).unwrap(),
            ))
        })?
        .to_str()?
        .to_owned();

    // We must check that all necessary headers for a valid request are present. Note that we have to
    // deal with the fact that some apps seem to have a case-sensitive check for headers which is not
    // correct and should not considered the correct behavior, but it seems like some apps ignore it.
    // `http` by default writes all headers in lower-case which is fine (and does not violate the RFC)
    // but some servers seem to be poorely written and ignore RFC.
    //
    // See similar problem in `hyper`: https://github.com/hyperium/hyper/issues/1492
    let headers = request.headers_mut();
    for &header in &WEBSOCKET_HEADERS {
        let value = headers.remove(header).ok_or_else(|| {
            Error::Protocol(ProtocolError::InvalidHeader(
                HeaderName::from_bytes(header.as_bytes()).unwrap(),
            ))
        })?;
        write!(req, "{header}: {value}\r\n", header = header, value = value.to_str()?).unwrap();
    }

    // Now we must ensure that the headers that we've written once are not anymore present in the map.
    // If they do, then the request is invalid (some headers are duplicated there for some reason).
    let insensitive: Vec<String> =
        WEBSOCKET_HEADERS.iter().map(|h| h.to_ascii_lowercase()).collect();
    for (k, v) in headers {
        let mut name = k.as_str();

        // We have already written the necessary headers once (above) and removed them from the map.
        // If we encounter them again, then the request is considered invalid and error is returned.
        // Note that we can't use `.contains()`, since `&str` does not coerce to `&String` in Rust.
        if insensitive.iter().any(|x| x == name) {
            return Err(Error::Protocol(ProtocolError::InvalidHeader(k.clone())));
        }

        // Relates to the issue of some servers treating headers in a case-sensitive way, please see:
        // https://github.com/snapview/tungstenite-rs/pull/119 (original fix of the problem)
        if name == "sec-websocket-protocol" {
            name = "Sec-WebSocket-Protocol";
        }

        writeln!(req, "{}: {}\r", name, v.to_str()?).unwrap();
    }

    writeln!(req, "\r").unwrap();
    trace!("Request: {:?}", String::from_utf8_lossy(&req));
    Ok((req, key))
}

/// Information for handshake verification.
#[derive(Debug)]
struct VerifyData {
    /// Accepted server key.
    accept_key: String,
}

impl VerifyData {
    pub fn verify_response(&self, response: Response) -> Result<Response> {
        // 1. If the status code received from the server is not 101, the
        // client handles the response per HTTP [RFC2616] procedures. (RFC 6455)
        if response.status() != StatusCode::SWITCHING_PROTOCOLS {
            return Err(Error::Http(response.map(|_| None)));
        }

        let headers = response.headers();

        // 2. If the response lacks an |Upgrade| header field or the |Upgrade|
        // header field contains a value that is not an ASCII case-
        // insensitive match for the value "websocket", the client MUST
        // _Fail the WebSocket Connection_. (RFC 6455)
        if !headers
            .get("Upgrade")
            .and_then(|h| h.to_str().ok())
            .map(|h| h.eq_ignore_ascii_case("websocket"))
            .unwrap_or(false)
        {
            return Err(Error::Protocol(ProtocolError::MissingUpgradeWebSocketHeader));
        }
        // 3.  If the response lacks a |Connection| header field or the
        // |Connection| header field doesn't contain a token that is an
        // ASCII case-insensitive match for the value "Upgrade", the client
        // MUST _Fail the WebSocket Connection_. (RFC 6455)
        if !headers
            .get("Connection")
            .and_then(|h| h.to_str().ok())
            .map(|h| h.eq_ignore_ascii_case("Upgrade"))
            .unwrap_or(false)
        {
            return Err(Error::Protocol(ProtocolError::MissingConnectionUpgradeHeader));
        }
        // 4.  If the response lacks a |Sec-WebSocket-Accept| header field or
        // the |Sec-WebSocket-Accept| contains a value other than the
        // base64-encoded SHA-1 of ... the client MUST _Fail the WebSocket
        // Connection_. (RFC 6455)
        if !headers.get("Sec-WebSocket-Accept").map(|h| h == &self.accept_key).unwrap_or(false) {
            return Err(Error::Protocol(ProtocolError::SecWebSocketAcceptKeyMismatch));
        }
        // 5.  If the response includes a |Sec-WebSocket-Extensions| header
        // field and this header field indicates the use of an extension
        // that was not present in the client's handshake (the server has
        // indicated an extension not requested by the client), the client
        // MUST _Fail the WebSocket Connection_. (RFC 6455)
        // TODO

        // 6.  If the response includes a |Sec-WebSocket-Protocol| header field
        // and this header field indicates the use of a subprotocol that was
        // not present in the client's handshake (the server has indicated a
        // subprotocol not requested by the client), the client MUST _Fail
        // the WebSocket Connection_. (RFC 6455)
        // TODO

        Ok(response)
    }
}

impl TryParse for Response {
    fn try_parse(buf: &[u8]) -> Result<Option<(usize, Self)>> {
        let mut hbuffer = [httparse::EMPTY_HEADER; MAX_HEADERS];
        let mut req = httparse::Response::new(&mut hbuffer);
        Ok(match req.parse(buf)? {
            Status::Partial => None,
            Status::Complete(size) => Some((size, Response::from_httparse(req)?)),
        })
    }
}

impl<'h, 'b: 'h> FromHttparse<httparse::Response<'h, 'b>> for Response {
    fn from_httparse(raw: httparse::Response<'h, 'b>) -> Result<Self> {
        if raw.version.expect("Bug: no HTTP version") < /*1.*/1 {
            return Err(Error::Protocol(ProtocolError::WrongHttpMethod));
        }

        let headers = HeaderMap::from_httparse(raw.headers)?;

        let mut response = Response::new(());
        *response.status_mut() = StatusCode::from_u16(raw.code.expect("Bug: no HTTP status code"))?;
        *response.headers_mut() = headers;
        // TODO: httparse only supports HTTP 0.9/1.0/1.1 but not HTTP 2.0
        // so the only valid value we could get in the response would be 1.1.
        *response.version_mut() = http::Version::HTTP_11;

        Ok(response)
    }
}

/// Generate a random key for the `Sec-WebSocket-Key` header.
pub fn generate_key() -> String {
    // a base64-encoded (see Section 4 of [RFC4648]) value that,
    // when decoded, is 16 bytes in length (RFC 6455)
    let r: [u8; 16] = rand::random();
    base64::encode(&r)
}

#[cfg(test)]
mod tests {
    use super::{super::machine::TryParse, generate_key, generate_request, Response};
    use crate::client::IntoClientRequest;

    #[test]
    fn random_keys() {
        let k1 = generate_key();
        println!("Generated random key 1: {}", k1);
        let k2 = generate_key();
        println!("Generated random key 2: {}", k2);
        assert_ne!(k1, k2);
        assert_eq!(k1.len(), k2.len());
        assert_eq!(k1.len(), 24);
        assert_eq!(k2.len(), 24);
        assert!(k1.ends_with("=="));
        assert!(k2.ends_with("=="));
        assert!(k1[..22].find('=').is_none());
        assert!(k2[..22].find('=').is_none());
    }

    fn construct_expected(host: &str, key: &str) -> Vec<u8> {
        format!(
            "\
            GET /getCaseCount HTTP/1.1\r\n\
            Host: {host}\r\n\
            Connection: Upgrade\r\n\
            Upgrade: websocket\r\n\
            Sec-WebSocket-Version: 13\r\n\
            Sec-WebSocket-Key: {key}\r\n\
            \r\n",
            host = host,
            key = key
        )
        .into_bytes()
    }

    #[test]
    fn request_formatting() {
        let request = "ws://localhost/getCaseCount".into_client_request().unwrap();
        let (request, key) = generate_request(request).unwrap();
        let correct = construct_expected("localhost", &key);
        assert_eq!(&request[..], &correct[..]);
    }

    #[test]
    fn request_formatting_with_host() {
        let request = "wss://localhost:9001/getCaseCount".into_client_request().unwrap();
        let (request, key) = generate_request(request).unwrap();
        let correct = construct_expected("localhost:9001", &key);
        assert_eq!(&request[..], &correct[..]);
    }

    #[test]
    fn request_formatting_with_at() {
        let request = "wss://user:pass@localhost:9001/getCaseCount".into_client_request().unwrap();
        let (request, key) = generate_request(request).unwrap();
        let correct = construct_expected("localhost:9001", &key);
        assert_eq!(&request[..], &correct[..]);
    }

    #[test]
    fn response_parsing() {
        const DATA: &[u8] = b"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
        let (_, resp) = Response::try_parse(DATA).unwrap().unwrap();
        assert_eq!(resp.status(), http::StatusCode::OK);
        assert_eq!(resp.headers().get("Content-Type").unwrap(), &b"text/html"[..],);
    }

    #[test]
    fn invalid_custom_request() {
        let request = http::Request::builder().method("GET").body(()).unwrap();
        assert!(generate_request(request).is_err());
    }
}
<commit_msg>fix: uppercase origin header<commit_after>//! Client handshake machine.

use std::{
    io::{Read, Write},
    marker::PhantomData,
};

use http::{
    header::HeaderName, HeaderMap, Request as HttpRequest, Response as HttpResponse, StatusCode,
};
use httparse::Status;
use log::*;

use super::{
    derive_accept_key,
    headers::{FromHttparse, MAX_HEADERS},
    machine::{HandshakeMachine, StageResult, TryParse},
    HandshakeRole, MidHandshake, ProcessingResult,
};
use crate::{
    error::{Error, ProtocolError, Result, UrlError},
    protocol::{Role, WebSocket, WebSocketConfig},
};

/// Client request type.
pub type Request = HttpRequest<()>;

/// Client response type.
pub type Response = HttpResponse<()>;

/// Client handshake role.
#[derive(Debug)]
pub struct ClientHandshake<S> {
    verify_data: VerifyData,
    config: Option<WebSocketConfig>,
    _marker: PhantomData<S>,
}

impl<S: Read + Write> ClientHandshake<S> {
    /// Initiate a client handshake.
    pub fn start(
        stream: S,
        request: Request,
        config: Option<WebSocketConfig>,
    ) -> Result<MidHandshake<Self>> {
        if request.method() != http::Method::GET {
            return Err(Error::Protocol(ProtocolError::WrongHttpMethod));
        }

        if request.version() < http::Version::HTTP_11 {
            return Err(Error::Protocol(ProtocolError::WrongHttpVersion));
        }

        // Check the URI scheme: only ws or wss are supported
        let _ = crate::client::uri_mode(request.uri())?;

        // Convert and verify the `http::Request` and turn it into the request as per RFC.
        // Also extract the key from it (it must be present in a correct request).
        let (request, key) = generate_request(request)?;

        let machine = HandshakeMachine::start_write(stream, request);

        let client = {
            let accept_key = derive_accept_key(key.as_ref());
            ClientHandshake { verify_data: VerifyData { accept_key }, config, _marker: PhantomData }
        };

        trace!("Client handshake initiated.");
        Ok(MidHandshake { role: client, machine })
    }
}

impl<S: Read + Write> HandshakeRole for ClientHandshake<S> {
    type IncomingData = Response;
    type InternalStream = S;
    type FinalResult = (WebSocket<S>, Response);
    fn stage_finished(
        &mut self,
        finish: StageResult<Self::IncomingData, Self::InternalStream>,
    ) -> Result<ProcessingResult<Self::InternalStream, Self::FinalResult>> {
        Ok(match finish {
            StageResult::DoneWriting(stream) => {
                ProcessingResult::Continue(HandshakeMachine::start_read(stream))
            }
            StageResult::DoneReading { stream, result, tail } => {
                let result = self.verify_data.verify_response(result)?;
                debug!("Client handshake done.");
                let websocket =
                    WebSocket::from_partially_read(stream, tail, Role::Client, self.config);
                ProcessingResult::Done((websocket, result))
            }
        })
    }
}

/// Verifies and generates a client WebSocket request from the original request and extracts a WebSocket key from it.
fn generate_request(mut request: Request) -> Result<(Vec<u8>, String)> {
    let mut req = Vec::new();
    write!(
        req,
        "GET {path} {version:?}\r\n",
        path = request.uri().path_and_query().ok_or(Error::Url(UrlError::NoPathOrQuery))?.as_str(),
        version = request.version()
    )
    .unwrap();

    // Headers that must be present in a correct request.
    const KEY_HEADERNAME: &str = "Sec-WebSocket-Key";
    const WEBSOCKET_HEADERS: [&str; 5] =
        ["Host", "Connection", "Upgrade", "Sec-WebSocket-Version", KEY_HEADERNAME];

    // We must extract a WebSocket key from a properly formed request or fail if it's not present.
    let key = request
        .headers()
        .get(KEY_HEADERNAME)
        .ok_or_else(|| {
            Error::Protocol(ProtocolError::InvalidHeader(
                HeaderName::from_bytes(KEY_HEADERNAME.as_bytes()).unwrap(),
            ))
        })?
        .to_str()?
        .to_owned();

    // We must check that all necessary headers for a valid request are present. Note that we have to
    // deal with the fact that some apps seem to have a case-sensitive check for headers which is not
    // correct and should not considered the correct behavior, but it seems like some apps ignore it.
    // `http` by default writes all headers in lower-case which is fine (and does not violate the RFC)
    // but some servers seem to be poorely written and ignore RFC.
    //
    // See similar problem in `hyper`: https://github.com/hyperium/hyper/issues/1492
    let headers = request.headers_mut();
    for &header in &WEBSOCKET_HEADERS {
        let value = headers.remove(header).ok_or_else(|| {
            Error::Protocol(ProtocolError::InvalidHeader(
                HeaderName::from_bytes(header.as_bytes()).unwrap(),
            ))
        })?;
        write!(req, "{header}: {value}\r\n", header = header, value = value.to_str()?).unwrap();
    }

    // Now we must ensure that the headers that we've written once are not anymore present in the map.
    // If they do, then the request is invalid (some headers are duplicated there for some reason).
    let insensitive: Vec<String> =
        WEBSOCKET_HEADERS.iter().map(|h| h.to_ascii_lowercase()).collect();
    for (k, v) in headers {
        let mut name = k.as_str();

        // We have already written the necessary headers once (above) and removed them from the map.
        // If we encounter them again, then the request is considered invalid and error is returned.
        // Note that we can't use `.contains()`, since `&str` does not coerce to `&String` in Rust.
        if insensitive.iter().any(|x| x == name) {
            return Err(Error::Protocol(ProtocolError::InvalidHeader(k.clone())));
        }

        // Relates to the issue of some servers treating headers in a case-sensitive way, please see:
        // https://github.com/snapview/tungstenite-rs/pull/119 (original fix of the problem)
        if name == "sec-websocket-protocol" {
            name = "Sec-WebSocket-Protocol";
        }

        if name == "origin" {
            name = "Origin";
        }

        writeln!(req, "{}: {}\r", name, v.to_str()?).unwrap();
    }

    writeln!(req, "\r").unwrap();
    trace!("Request: {:?}", String::from_utf8_lossy(&req));
    Ok((req, key))
}

/// Information for handshake verification.
#[derive(Debug)]
struct VerifyData {
    /// Accepted server key.
    accept_key: String,
}

impl VerifyData {
    pub fn verify_response(&self, response: Response) -> Result<Response> {
        // 1. If the status code received from the server is not 101, the
        // client handles the response per HTTP [RFC2616] procedures. (RFC 6455)
        if response.status() != StatusCode::SWITCHING_PROTOCOLS {
            return Err(Error::Http(response.map(|_| None)));
        }

        let headers = response.headers();

        // 2. If the response lacks an |Upgrade| header field or the |Upgrade|
        // header field contains a value that is not an ASCII case-
        // insensitive match for the value "websocket", the client MUST
        // _Fail the WebSocket Connection_. (RFC 6455)
        if !headers
            .get("Upgrade")
            .and_then(|h| h.to_str().ok())
            .map(|h| h.eq_ignore_ascii_case("websocket"))
            .unwrap_or(false)
        {
            return Err(Error::Protocol(ProtocolError::MissingUpgradeWebSocketHeader));
        }
        // 3.  If the response lacks a |Connection| header field or the
        // |Connection| header field doesn't contain a token that is an
        // ASCII case-insensitive match for the value "Upgrade", the client
        // MUST _Fail the WebSocket Connection_. (RFC 6455)
        if !headers
            .get("Connection")
            .and_then(|h| h.to_str().ok())
            .map(|h| h.eq_ignore_ascii_case("Upgrade"))
            .unwrap_or(false)
        {
            return Err(Error::Protocol(ProtocolError::MissingConnectionUpgradeHeader));
        }
        // 4.  If the response lacks a |Sec-WebSocket-Accept| header field or
        // the |Sec-WebSocket-Accept| contains a value other than the
        // base64-encoded SHA-1 of ... the client MUST _Fail the WebSocket
        // Connection_. (RFC 6455)
        if !headers.get("Sec-WebSocket-Accept").map(|h| h == &self.accept_key).unwrap_or(false) {
            return Err(Error::Protocol(ProtocolError::SecWebSocketAcceptKeyMismatch));
        }
        // 5.  If the response includes a |Sec-WebSocket-Extensions| header
        // field and this header field indicates the use of an extension
        // that was not present in the client's handshake (the server has
        // indicated an extension not requested by the client), the client
        // MUST _Fail the WebSocket Connection_. (RFC 6455)
        // TODO

        // 6.  If the response includes a |Sec-WebSocket-Protocol| header field
        // and this header field indicates the use of a subprotocol that was
        // not present in the client's handshake (the server has indicated a
        // subprotocol not requested by the client), the client MUST _Fail
        // the WebSocket Connection_. (RFC 6455)
        // TODO

        Ok(response)
    }
}

impl TryParse for Response {
    fn try_parse(buf: &[u8]) -> Result<Option<(usize, Self)>> {
        let mut hbuffer = [httparse::EMPTY_HEADER; MAX_HEADERS];
        let mut req = httparse::Response::new(&mut hbuffer);
        Ok(match req.parse(buf)? {
            Status::Partial => None,
            Status::Complete(size) => Some((size, Response::from_httparse(req)?)),
        })
    }
}

impl<'h, 'b: 'h> FromHttparse<httparse::Response<'h, 'b>> for Response {
    fn from_httparse(raw: httparse::Response<'h, 'b>) -> Result<Self> {
        if raw.version.expect("Bug: no HTTP version") < /*1.*/1 {
            return Err(Error::Protocol(ProtocolError::WrongHttpMethod));
        }

        let headers = HeaderMap::from_httparse(raw.headers)?;

        let mut response = Response::new(());
        *response.status_mut() = StatusCode::from_u16(raw.code.expect("Bug: no HTTP status code"))?;
        *response.headers_mut() = headers;
        // TODO: httparse only supports HTTP 0.9/1.0/1.1 but not HTTP 2.0
        // so the only valid value we could get in the response would be 1.1.
        *response.version_mut() = http::Version::HTTP_11;

        Ok(response)
    }
}

/// Generate a random key for the `Sec-WebSocket-Key` header.
pub fn generate_key() -> String {
    // a base64-encoded (see Section 4 of [RFC4648]) value that,
    // when decoded, is 16 bytes in length (RFC 6455)
    let r: [u8; 16] = rand::random();
    base64::encode(&r)
}

#[cfg(test)]
mod tests {
    use super::{super::machine::TryParse, generate_key, generate_request, Response};
    use crate::client::IntoClientRequest;

    #[test]
    fn random_keys() {
        let k1 = generate_key();
        println!("Generated random key 1: {}", k1);
        let k2 = generate_key();
        println!("Generated random key 2: {}", k2);
        assert_ne!(k1, k2);
        assert_eq!(k1.len(), k2.len());
        assert_eq!(k1.len(), 24);
        assert_eq!(k2.len(), 24);
        assert!(k1.ends_with("=="));
        assert!(k2.ends_with("=="));
        assert!(k1[..22].find('=').is_none());
        assert!(k2[..22].find('=').is_none());
    }

    fn construct_expected(host: &str, key: &str) -> Vec<u8> {
        format!(
            "\
            GET /getCaseCount HTTP/1.1\r\n\
            Host: {host}\r\n\
            Connection: Upgrade\r\n\
            Upgrade: websocket\r\n\
            Sec-WebSocket-Version: 13\r\n\
            Sec-WebSocket-Key: {key}\r\n\
            \r\n",
            host = host,
            key = key
        )
        .into_bytes()
    }

    #[test]
    fn request_formatting() {
        let request = "ws://localhost/getCaseCount".into_client_request().unwrap();
        let (request, key) = generate_request(request).unwrap();
        let correct = construct_expected("localhost", &key);
        assert_eq!(&request[..], &correct[..]);
    }

    #[test]
    fn request_formatting_with_host() {
        let request = "wss://localhost:9001/getCaseCount".into_client_request().unwrap();
        let (request, key) = generate_request(request).unwrap();
        let correct = construct_expected("localhost:9001", &key);
        assert_eq!(&request[..], &correct[..]);
    }

    #[test]
    fn request_formatting_with_at() {
        let request = "wss://user:pass@localhost:9001/getCaseCount".into_client_request().unwrap();
        let (request, key) = generate_request(request).unwrap();
        let correct = construct_expected("localhost:9001", &key);
        assert_eq!(&request[..], &correct[..]);
    }

    #[test]
    fn response_parsing() {
        const DATA: &[u8] = b"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
        let (_, resp) = Response::try_parse(DATA).unwrap().unwrap();
        assert_eq!(resp.status(), http::StatusCode::OK);
        assert_eq!(resp.headers().get("Content-Type").unwrap(), &b"text/html"[..],);
    }

    #[test]
    fn invalid_custom_request() {
        let request = http::Request::builder().method("GET").body(()).unwrap();
        assert!(generate_request(request).is_err());
    }
}
<|endoftext|>


<commit_before>#![crate_id = "jit_macro"]
#![comment = "LibJIT Macro"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![feature(quote, globs, macro_registrar, managed_boxes)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, non_camel_case_types, unused_must_use)]
//! This crate provides a macro `jit_type` which can compile a Rust type
//! into its LibJIT counterpart. It even supports functions *and* structs!
//!
//! For example:
//!
//! ```rust
//! #![feature(phase)]
//! extern crate jit;
//! #[phase(syntax)]
//! extern crate jit_macro;
//! fn main() {
//! 	let ty = jit_type!(i64);
//! 	assert_eq(ty.get_size(), 8);
//! 	let floor_sig = jit_type!((f64) -> i32);
//! 	let double_array_ty = jit_type!({
//! 		len: int,
//! 		ptr: **f64
//! 	});
//! }
//! ```
extern crate syntax;
use syntax::ext::quote::rt::ToSource;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::ext::base::*;
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::token::*;
use std::iter::Peekable;
use std::slice::Items;
#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
	let expander = box BasicMacroExpander { expander: jit_type, span: None };
	register(token::intern("jit_type"), NormalTT(expander, None))
}
fn error(e:Option<TokenTree>, tok:Token) -> Result<(), String> {
	match e {
		Some(TTTok(_, ref got)) => Err(format!("Bad syntax - got {} but expected {}", got, tok)),
		Some(TTNonterminal(_, ref got)) => Err(format!("Bad syntax - got {} but expected {}", got, tok)),
		Some(TTDelim(ref trees)) => error(Some(trees.deref().get(0).clone()), tok),
		Some(_) => Err("Bad syntax".into_string()),
		None => Err("Abrupt end".into_string())
	}
}
fn expect<'a>(_: &mut ExtCtxt, tts:&mut Peekable<&'a TokenTree, Items<'a, TokenTree>>, tok:Token) -> Result<(), String> {
	match tts.next().map(|v| v.clone()) {
		Some(TTTok(_, ref got)) if *got == tok => {
			Ok(())
		},
		Some(TTDelim(ref trees)) => {
			let curr = trees.deref().get(0).clone();
			match curr {
				TTTok(_, ref got) if *got == tok =>
					Ok(()),
				TTTok(_, ref tok) =>
					Err(format!("Bad result {}", tok)),
				_ =>
					Err("Bad result".into_string())
			}
		},
		v => error(v, tok)
	}
}
fn jit_parse_type<'a>(cx: &mut ExtCtxt, tts:&mut Peekable<&'a TokenTree, Items<'a, TokenTree>>) -> Result<P<Expr>, String> {
	let val:Option<&TokenTree> = tts.peek().map(|v|*v);
	match val {
		Some(ref val) => {
			match **val {
				TTDelim(ref toks) => {
					match *toks.get(0) {
						TTTok(span, LPAREN) => {
							let toks = toks.slice(1, toks.len() - 1);
							if toks.len() == 0 {
								Ok(quote_expr!(cx, ::jit::Types::get_void()))
							} else {
								let mut arg_types : Vec<P<Expr>> = Vec::new();
								{
									let mut tts = toks.iter().peekable();
									loop {
										let parsed = try!(jit_parse_type(cx, &mut tts));
										arg_types.push(cx.expr_addr_of(parsed.span, parsed));
										match tts.next() {
											Some(v) =>
												match *v {
													TTTok(_, COMMA) => {
														continue;
													},
													_ => return Err("Unexpected token in function decl".into_string())
												},
											None => break
										}
									}
								}
								tts.next();
								try!(expect(cx, tts, RARROW));
								let parsed_ret = try!(jit_parse_type(cx, tts));
								let ret = cx.expr_addr_of(parsed_ret.span, parsed_ret);
								let arg_types_ex = cx.expr(span, ExprVec(arg_types));
								let func = quote_expr!(&mut*cx, ::jit::Type::create_signature);
								let cdecl = quote_expr!(&mut*cx, ::jit::CDECL);
								let arg_types_ex = cx.expr_mut_addr_of(arg_types_ex.span, arg_types_ex);
								let arg_types_ex = cx.expr_method_call(span, arg_types_ex, cx.ident_of("as_mut_slice"), vec!());
								let call = cx.expr_call(span, func, vec!(cdecl, ret, arg_types_ex));
								Ok(call)

							}
						},
						TTTok(span, LBRACE) => {
							let toks = toks.slice(1, toks.len() - 1);
							let mut tts = toks.iter().peekable();
							let mut names:Vec<P<Expr>> = Vec::new();
							let mut types:Vec<P<Expr>> = Vec::new();
							loop {
								match tts.next() {
									Some(ref v) => {
										match **v {
											TTTok(_, COMMA) =>
												continue,
											TTTok(span, IDENT(field_name, _)) => {
												try!(expect(cx, &mut tts, COLON));
												let field_type = try!(jit_parse_type(cx, &mut tts));
												names.push(cx.expr_method_call(span, cx.expr_str(span, get_ident(field_name)), cx.ident_of("into_string"), vec!()));
												types.push(cx.expr_addr_of(field_type.span, field_type));
											},
											_ => return Err("Expected ident".into_string())
										}
									},
									None => break
								}
							}
							let func = quote_expr!(&mut*cx, ::jit::Type::create_struct);
							let types_vec = cx.expr(span, ExprVec(types));
							let types_vec_slices = cx.expr_method_call(span, types_vec, cx.ident_of("as_mut_slice"), vec!());
							let names_vec = cx.expr(span, ExprVec(names));
							let ident_type = cx.ident_of("ty");
							let final = cx.expr_block(cx.block(span, vec!(
								cx.stmt_let(span, false, ident_type, cx.expr_call(span, func, vec!(types_vec_slices))),
								cx.stmt_expr(cx.expr_method_call(span, cx.expr_ident(span, ident_type), cx.ident_of("set_names"), vec!(names_vec)))
							), Some(cx.expr_ident(span, ident_type))));
							println!("{}", final.to_source());
							Ok(final)
						},
						_ => Err("Expected bracket".into_string())
					}
				},
				TTTok(_, IDENT(ident, _)) => {
					let ident = ident.to_source();
					let res = match ident.as_slice() {
						"void" => Ok(quote_expr!(cx, ::jit::Types::get_void())),
						"int" | "i32" => Ok(quote_expr!(cx, ::jit::Types::get_int())),
						"uint" | "u32" => Ok(quote_expr!(cx, ::jit::Types::get_uint())),
						"i64" => Ok(quote_expr!(cx, ::jit::Types::get_long())),
						"u64" => Ok(quote_expr!(cx, ::jit::Types::get_ulong())),
						"char" => Ok(quote_expr!(cx, ::jit::Types::get_char())),
						"bool" => Ok(quote_expr!(cx, ::jit::Types::get_bool())),
						"f64" => Ok(quote_expr!(cx, ::jit::Types::get_float64())),
						"f32" => Ok(quote_expr!(cx, ::jit::Types::get_float32())),
						"String" => Ok(quote_expr!(cx, ::jit::Types::get_cstring())),
						"Vec" => Ok(quote_expr!(cx, ::jit::Types::get_vec())),
						id => Err(format!("Unexpected identifier {}", id))
					};
					if res.is_ok() {
						tts.next();
					}
					res
				},
				TTTok(span, BINOP(STAR)) => {
					tts.next();
					let func = quote_expr!(&mut*cx, ::jit::Type::create_pointer);
					let parsed_type = try!(jit_parse_type(&mut*cx, tts));
					let wv = cx.expr_addr_of(span, parsed_type);
					Ok(cx.expr_call(span, func, vec!(wv)))
				},
				TTTok(_, DOLLAR) => {
					tts.next();
					match tts.next() {
						Some(ref tks) => {
							match **tks {
								TTTok(span, IDENT(ident, _)) => {
									Ok(cx.expr_ident(span, ident))
								}
								_ => Err("Expected next".into_string())
							}
						},
						None => Err("Abrupt end".into_string())
					}
				},
				ref token => {
					try!(error(Some(token.clone()), DOLLAR));
					Err("...".into_string())
				}
			}
		},
		None =>
			Err("Not a type".into_string())
	}
}
fn jit_type(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
	let mut iter = tts.iter().peekable();
	MacExpr::new(match jit_parse_type(cx, &mut iter) {
		Ok(v) => v,
		Err(e) => {
			cx.span_err(sp, e.as_slice());
			quote_expr!(cx, fail!("Invalid"))
		}
	})
}<commit_msg>Simplify type resolution in macro<commit_after>#![crate_id = "jit_macro"]
#![comment = "LibJIT Macro"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![feature(quote, globs, macro_registrar, managed_boxes)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, non_camel_case_types, unused_must_use)]
//! This crate provides a macro `jit_type` which can compile a Rust type
//! into its LibJIT counterpart. It even supports functions *and* structs!
//!
//! For example:
//!
//! ```rust
//! #![feature(phase)]
//! extern crate jit;
//! #[phase(syntax)]
//! extern crate jit_macro;
//! fn main() {
//! 	let ty = jit_type!(i64);
//! 	assert_eq(ty.get_size(), 8);
//! 	let floor_sig = jit_type!((f64) -> i32);
//! 	let double_array_ty = jit_type!({
//! 		len: int,
//! 		ptr: **f64
//! 	});
//! }
//! ```
extern crate syntax;
use syntax::ext::quote::rt::ToSource;
use syntax::ast::*;
use syntax::codemap::Span;
use syntax::ext::base::*;
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::token::*;
use std::iter::Peekable;
use std::slice::Items;
#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
	let expander = box BasicMacroExpander { expander: jit_type, span: None };
	register(token::intern("jit_type"), NormalTT(expander, None))
}
fn error(e:Option<TokenTree>, tok:Token) -> Result<(), String> {
	match e {
		Some(TTTok(_, ref got)) => Err(format!("Bad syntax - got {} but expected {}", got, tok)),
		Some(TTNonterminal(_, ref got)) => Err(format!("Bad syntax - got {} but expected {}", got, tok)),
		Some(TTDelim(ref trees)) => error(Some(trees.deref().get(0).clone()), tok),
		Some(_) => Err("Bad syntax".into_string()),
		None => Err("Abrupt end".into_string())
	}
}
fn expect<'a>(_: &mut ExtCtxt, tts:&mut Peekable<&'a TokenTree, Items<'a, TokenTree>>, tok:Token) -> Result<(), String> {
	match tts.next().map(|v| v.clone()) {
		Some(TTTok(_, ref got)) if *got == tok => {
			Ok(())
		},
		Some(TTDelim(ref trees)) => {
			let curr = trees.deref().get(0).clone();
			match curr {
				TTTok(_, ref got) if *got == tok =>
					Ok(()),
				TTTok(_, ref tok) =>
					Err(format!("Bad result {}", tok)),
				_ =>
					Err("Bad result".into_string())
			}
		},
		v => error(v, tok)
	}
}
fn jit_parse_type<'a>(cx: &mut ExtCtxt, tts:&mut Peekable<&'a TokenTree, Items<'a, TokenTree>>) -> Result<P<Expr>, String> {
	let val:Option<&TokenTree> = tts.peek().map(|v|*v);
	match val {
		Some(ref val) => {
			match **val {
				TTDelim(ref toks) => {
					match *toks.get(0) {
						TTTok(span, LPAREN) => {
							let toks = toks.slice(1, toks.len() - 1);
							if toks.len() == 0 {
								Ok(quote_expr!(cx, ::jit::Types::get_void()))
							} else {
								let mut arg_types : Vec<P<Expr>> = Vec::new();
								{
									let mut tts = toks.iter().peekable();
									loop {
										let parsed = try!(jit_parse_type(cx, &mut tts));
										arg_types.push(cx.expr_addr_of(parsed.span, parsed));
										match tts.next() {
											Some(v) =>
												match *v {
													TTTok(_, COMMA) => {
														continue;
													},
													_ => return Err("Unexpected token in function decl".into_string())
												},
											None => break
										}
									}
								}
								tts.next();
								try!(expect(cx, tts, RARROW));
								let parsed_ret = try!(jit_parse_type(cx, tts));
								let ret = cx.expr_addr_of(parsed_ret.span, parsed_ret);
								let arg_types_ex = cx.expr(span, ExprVec(arg_types));
								let func = quote_expr!(&mut*cx, ::jit::Type::create_signature);
								let cdecl = quote_expr!(&mut*cx, ::jit::CDECL);
								let arg_types_ex = cx.expr_mut_addr_of(arg_types_ex.span, arg_types_ex);
								let arg_types_ex = cx.expr_method_call(span, arg_types_ex, cx.ident_of("as_mut_slice"), vec!());
								let call = cx.expr_call(span, func, vec!(cdecl, ret, arg_types_ex));
								Ok(call)

							}
						},
						TTTok(span, LBRACE) => {
							let toks = toks.slice(1, toks.len() - 1);
							let mut tts = toks.iter().peekable();
							let mut names:Vec<P<Expr>> = Vec::new();
							let mut types:Vec<P<Expr>> = Vec::new();
							loop {
								match tts.next() {
									Some(ref v) => {
										match **v {
											TTTok(_, COMMA) =>
												continue,
											TTTok(span, IDENT(field_name, _)) => {
												try!(expect(cx, &mut tts, COLON));
												let field_type = try!(jit_parse_type(cx, &mut tts));
												names.push(cx.expr_method_call(span, cx.expr_str(span, get_ident(field_name)), cx.ident_of("into_string"), vec!()));
												types.push(cx.expr_addr_of(field_type.span, field_type));
											},
											_ => return Err("Expected ident".into_string())
										}
									},
									None => break
								}
							}
							let func = quote_expr!(&mut*cx, ::jit::Type::create_struct);
							let types_vec = cx.expr(span, ExprVec(types));
							let types_vec_slices = cx.expr_method_call(span, types_vec, cx.ident_of("as_mut_slice"), vec!());
							let names_vec = cx.expr(span, ExprVec(names));
							let ident_type = cx.ident_of("ty");
							let final = cx.expr_block(cx.block(span, vec!(
								cx.stmt_let(span, false, ident_type, cx.expr_call(span, func, vec!(types_vec_slices))),
								cx.stmt_expr(cx.expr_method_call(span, cx.expr_ident(span, ident_type), cx.ident_of("set_names"), vec!(names_vec)))
							), Some(cx.expr_ident(span, ident_type))));
							println!("{}", final.to_source());
							Ok(final)
						},
						_ => Err("Expected bracket".into_string())
					}
				},
				TTTok(_, IDENT(ident, _)) => {
					let ident = ident.to_source();
					let type_id = match ident.as_slice() {
						"void" => "void",
						"int" | "i32" => "int",
						"uint" | "u32" => "uint",
						"i64" => "long",
						"u64" => "ulong",
						"char" => "char",
						"bool" => "bool",
						"f64" => "float64",
						"f32" => "float32",
						"String" => "cstring",
						"Vec" => "vec",
						id => return Err(format!("Unexpected identifier {}", id))
					};
					let full_type_id = cx.ident_of("get_".into_string().append(type_id).as_slice());
					tts.next();
					Ok(quote_expr!(cx, ::jit::Types::$full_type_id()))
				},
				TTTok(span, BINOP(STAR)) => {
					tts.next();
					let func = quote_expr!(&mut*cx, ::jit::Type::create_pointer);
					let parsed_type = try!(jit_parse_type(&mut*cx, tts));
					let wv = cx.expr_addr_of(span, parsed_type);
					Ok(cx.expr_call(span, func, vec!(wv)))
				},
				TTTok(_, DOLLAR) => {
					tts.next();
					match tts.next() {
						Some(ref tks) => {
							match **tks {
								TTTok(span, IDENT(ident, _)) => {
									Ok(cx.expr_ident(span, ident))
								}
								_ => Err("Expected next".into_string())
							}
						},
						None => Err("Abrupt end".into_string())
					}
				},
				ref token => {
					try!(error(Some(token.clone()), DOLLAR));
					Err("...".into_string())
				}
			}
		},
		None =>
			Err("Not a type".into_string())
	}
}
fn jit_type(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
	let mut iter = tts.iter().peekable();
	MacExpr::new(match jit_parse_type(cx, &mut iter) {
		Ok(v) => v,
		Err(e) => {
			cx.span_err(sp, e.as_slice());
			quote_expr!(cx, fail!("Invalid"))
		}
	})
}<|endoftext|>


<commit_before>extern crate cgmath;
#[macro_use]
extern crate clap;
extern crate collision;
extern crate futures;
extern crate grpcio;
extern crate point_viewer;
extern crate point_viewer_grpc;
extern crate protobuf;

use cgmath::Point3;
use collision::Aabb3;
use futures::{stream, Future, Sink};
use futures::sync::oneshot;
use grpcio::{Environment, RpcContext, ServerBuilder, ServerStreamingSink, UnarySink, WriteFlags};
use point_viewer::InternalIterator;
use point_viewer::octree::{read_meta_proto, NodeId, Octree, OnDiskOctree};
use point_viewer_grpc::proto;
use point_viewer_grpc::proto_grpc;
use protobuf::Message;
use std::{io, thread};
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;

#[derive(Clone)]
struct OctreeService {
    octree: Arc<OnDiskOctree>,
    meta: point_viewer::proto::Meta,
}

impl proto_grpc::Octree for OctreeService {
    fn get_meta(
        &self,
        ctx: RpcContext,
        req: proto::GetMetaRequest,
        sink: UnarySink<proto::GetMetaReply>,
    ) {
        let mut resp = proto::GetMetaReply::new();
        resp.set_meta(self.meta.clone());
        let f = sink.success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_node_data(
        &self,
        ctx: RpcContext,
        req: proto::GetNodeDataRequest,
        sink: UnarySink<proto::GetNodeDataReply>,
    ) {
        let data = self.octree
            .get_node_data(&NodeId::from_str(&req.id))
            .unwrap();
        let mut resp = proto::GetNodeDataReply::new();
        resp.mut_node()
            .set_position_encoding(data.meta.position_encoding.to_proto());
        resp.mut_node().set_num_points(data.meta.num_points);
        resp.set_position(data.position);
        resp.set_color(data.color);
        let f = sink.success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_points_in_box(
        &self,
        ctx: RpcContext,
        req: proto::GetPointsInBoxRequest,
        resp: ServerStreamingSink<proto::GetPointsInBoxReply>,
    ) {
        let bounding_box = {
            let bounding_box = req.bounding_box.clone().unwrap();
            let min = bounding_box.min.unwrap();
            let max = bounding_box.max.unwrap();
            Aabb3::new(
                Point3::new(min.x, min.y, min.z),
                Point3::new(max.x, max.y, max.z),
            )
        };
        let mut replies = Vec::new();
        replies.push((proto::GetPointsInBoxReply::new(), WriteFlags::default()));
        // Computing the protobuf size is very expensive.
        // We compute the byte size of a Vector3f in the reply proto once outside the loop.
        let bytes_per_point = {
            let mut reply = proto::GetPointsInBoxReply::new();
            let initial_proto_size = reply.compute_size();
            let mut v = point_viewer::proto::Vector3f::new();
            v.set_x(1.);
            v.set_y(1.);
            v.set_z(1.);
            reply.mut_points().push(v);
            let final_proto_size = reply.compute_size();
            final_proto_size - initial_proto_size
        };
        // Proto message must be below 4 MB.
        let max_message_size = 4 * 1024 * 1024;
        let mut reply_size = 0;
        self.octree.points_in_box(&bounding_box).for_each(|p| {
            let mut v = point_viewer::proto::Vector3f::new();
            v.set_x(p.position.x);
            v.set_y(p.position.y);
            v.set_z(p.position.z);
            replies.last_mut().unwrap().0.mut_points().push(v);
            reply_size += bytes_per_point;
            if reply_size > max_message_size - bytes_per_point {
                replies.push((proto::GetPointsInBoxReply::new(), WriteFlags::default()));
                reply_size = 0;
            }
        });
        let f = resp.send_all(stream::iter_ok::<_, grpcio::Error>(replies))
            .map(|_| {})
            .map_err(|e| println!("failed to rply: {:?}", e));
        ctx.spawn(f)
    }
}

fn main() {
    let matches = clap::App::new("octree_server")
        .args(&[
            clap::Arg::with_name("port")
                .help("Port to listen on for connections. [50051]")
                .long("port")
                .takes_value(true),
            clap::Arg::with_name("octree_directory")
                .help("Input directory of the octree directory to serve.")
                .index(1)
                .required(true),
        ])
        .get_matches();

    let port = value_t!(matches, "port", u16).unwrap_or(50051);
    let octree_directory = PathBuf::from(matches.value_of("octree_directory").unwrap());

    let env = Arc::new(Environment::new(1));
    let meta = read_meta_proto(&octree_directory).unwrap();
    let octree = Arc::new(OnDiskOctree::new(octree_directory).unwrap());

    let service = proto_grpc::create_octree(OctreeService { octree, meta });
    let mut server = ServerBuilder::new(env)
        .register_service(service)
        .bind("0.0.0.0" /* ip to bind to */, port)
        .build()
        .unwrap();
    server.start();
    for &(ref host, port) in server.bind_addrs() {
        println!("listening on {}:{}", host, port);
    }
    let (tx, rx) = oneshot::channel();
    thread::spawn(move || {
        println!("Press ENTER to exit...");
        let _ = io::stdin().read(&mut [0]).unwrap();
        tx.send(())
    });
    let _ = rx.wait();
    let _ = server.shutdown().wait();
}
<commit_msg>Actually stream points in the grpc server. (#146)<commit_after>extern crate cgmath;
#[macro_use]
extern crate clap;
extern crate collision;
extern crate futures;
extern crate grpcio;
extern crate point_viewer;
extern crate point_viewer_grpc;
extern crate protobuf;

use cgmath::Point3;
use collision::Aabb3;
use futures::{Stream, Future, Sink};
use futures::sync::oneshot;
use grpcio::{Environment, RpcContext, ServerBuilder, ServerStreamingSink, UnarySink, WriteFlags};
use point_viewer::InternalIterator;
use point_viewer::octree::{read_meta_proto, NodeId, Octree, OnDiskOctree};
use point_viewer_grpc::proto;
use point_viewer_grpc::proto_grpc;
use protobuf::Message;
use std::{io, thread};
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use futures::sync::mpsc;

#[derive(Clone)]
struct OctreeService {
    octree: Arc<OnDiskOctree>,
    meta: point_viewer::proto::Meta,
}

impl proto_grpc::Octree for OctreeService {
    fn get_meta(
        &self,
        ctx: RpcContext,
        req: proto::GetMetaRequest,
        sink: UnarySink<proto::GetMetaReply>,
    ) {
        let mut resp = proto::GetMetaReply::new();
        resp.set_meta(self.meta.clone());
        let f = sink.success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_node_data(
        &self,
        ctx: RpcContext,
        req: proto::GetNodeDataRequest,
        sink: UnarySink<proto::GetNodeDataReply>,
    ) {
        let data = self.octree
            .get_node_data(&NodeId::from_str(&req.id))
            .unwrap();
        let mut resp = proto::GetNodeDataReply::new();
        resp.mut_node()
            .set_position_encoding(data.meta.position_encoding.to_proto());
        resp.mut_node().set_num_points(data.meta.num_points);
        resp.set_position(data.position);
        resp.set_color(data.color);
        let f = sink.success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_points_in_box(
        &self,
        ctx: RpcContext,
        req: proto::GetPointsInBoxRequest,
        resp: ServerStreamingSink<proto::GetPointsInBoxReply>,
    ) {
        use std::thread;

        // This creates a async-aware (tx, rx) pair that can wake up the event loop when new data
        // is piped through it.
        let (tx, rx) = mpsc::channel(4);
        let octree = self.octree.clone();
        thread::spawn(move || {
            // This is the secret sauce connecting an OS thread to a event-based receiver. Calling
            // wait() on this turns the event aware, i.e. async 'tx' into a blocking 'tx' that will
            // make this thread block when the event loop is not quick enough with piping out data.
            let mut tx = tx.wait();

            let bounding_box = {
                let bounding_box = req.bounding_box.clone().unwrap();
                let min = bounding_box.min.unwrap();
                let max = bounding_box.max.unwrap();
                Aabb3::new(
                    Point3::new(min.x, min.y, min.z),
                    Point3::new(max.x, max.y, max.z),
                )
            };
            let mut reply = proto::GetPointsInBoxReply::new();

            // Computing the protobuf size is very expensive.
            // We compute the byte size of a Vector3f in the reply proto once outside the loop.
            let bytes_per_point = {
                let mut reply = proto::GetPointsInBoxReply::new();
                let initial_proto_size = reply.compute_size();
                let mut v = point_viewer::proto::Vector3f::new();
                v.set_x(1.);
                v.set_y(1.);
                v.set_z(1.);
                reply.mut_points().push(v);
                let final_proto_size = reply.compute_size();
                final_proto_size - initial_proto_size
            };
            // Proto message must be below 4 MB.
            let max_message_size = 4 * 1024 * 1024;
            let mut reply_size = 0;
            octree.points_in_box(&bounding_box).for_each(|p| {
                let mut v = point_viewer::proto::Vector3f::new();
                v.set_x(p.position.x);
                v.set_y(p.position.y);
                v.set_z(p.position.z);
                reply.mut_points().push(v);

                reply_size += bytes_per_point;
                if reply_size > max_message_size - bytes_per_point {
                    tx.send((reply.clone(), WriteFlags::default())).unwrap();
                    reply.mut_points().clear();
                    reply_size = 0;
                }
            });
        });

        // TODO(sirver): I did not figure out how to return meaningful errors. At least we return
        // any error.
        let rx = rx.map_err(|_| grpcio::Error::RemoteStopped);
        let f = resp
            .send_all(rx)
            .map(|_| {})
            .map_err(|e| println!("failed to reply: {:?}", e));
        ctx.spawn(f)
    }
}

fn main() {
    let matches = clap::App::new("octree_server")
        .args(&[
            clap::Arg::with_name("port")
                .help("Port to listen on for connections. [50051]")
                .long("port")
                .takes_value(true),
            clap::Arg::with_name("octree_directory")
                .help("Input directory of the octree directory to serve.")
                .index(1)
                .required(true),
        ])
        .get_matches();

    let port = value_t!(matches, "port", u16).unwrap_or(50051);
    let octree_directory = PathBuf::from(matches.value_of("octree_directory").unwrap());

    let env = Arc::new(Environment::new(1));
    let meta = read_meta_proto(&octree_directory).unwrap();
    let octree = Arc::new(OnDiskOctree::new(octree_directory).unwrap());

    let service = proto_grpc::create_octree(OctreeService { octree, meta });
    let mut server = ServerBuilder::new(env)
        .register_service(service)
        .bind("0.0.0.0" /* ip to bind to */, port)
        .build()
        .unwrap();
    server.start();
    for &(ref host, port) in server.bind_addrs() {
        println!("listening on {}:{}", host, port);
    }
    let (tx, rx) = oneshot::channel();
    thread::spawn(move || {
        println!("Press ENTER to exit...");
        let _ = io::stdin().read(&mut [0]).unwrap();
        tx.send(())
    });
    let _ = rx.wait();
    let _ = server.shutdown().wait();
}
<|endoftext|>


<commit_before>use provider::{Provider, ProviderTrait};

/// A provider for eLife
struct ElifeProvider {}

impl ProviderTrait for ElifeProvider {
    fn spec() -> Provider {
        Provider {}
    }
}
<commit_msg>chore(ELife provider): Update to meet `ProviderTrait` API<commit_after>use provider::{Provider, ProviderTrait};

pub struct ElifeProvider {}

impl ProviderTrait for ElifeProvider {
    fn spec() -> Provider {
        Provider::new("elife")
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 William (B.J.) Snow Orvis
//
// 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.

//! The burning ship fractal is an iterated function system similar to
//! Mandelbrot, but it is over the complex number function:
//! ```
//! f(z) = (abs(Re(z)) - i*abs(Im(z)))^2 + c
//! ```
//! It differs from the Mandelbrot equation in that the real and imaginary
//! components of z are always set to their absolute value before squaring
//! them. Also, the absolute value of the imaginary component of z is sometimes
//! added instead of subtracted, which makes the fractal flip upside down.
//!
//! This module also contains a few other variations of the burning ship
//! fractal that differ by only taking the absolute value of one of the
//! components of z (taking no absolute value would be the mandelbrot set)

use super::*;
use super::super::geometry;

pub struct BurningShip {
    max_iters: u64,
    power: u64,
}

impl BurningShip {
    /// Creates a new escape time specification for the burning ship family of fractals.
    ///
    /// `max_iterations` specifies the cutoff iteration for deciding whether a complex number
    /// escapes or has converged.
    ///
    /// `power` specifies the exponent used in the burning ship equation. The burning ship fractal
    /// has an exponent of 2, but this allows for an exponent of 3, 4, etc. to explore these
    /// related fractals. See <https://theory.org/fracdyn/burningship/symmetry.html> for examples
    /// of what these may look like.
    pub fn new(max_iterations: u64, power: u64) -> BurningShip {
        BurningShip {
            max_iters: max_iterations,
            power: power,
        }
    }
}

impl EscapeTime for BurningShip {
    fn max_iterations(&self) -> u64 {
        self.max_iters
    }

    fn default_view_area(&self) -> [Complex64; 2] {
        [Complex64::new(-2.5, 2.0), Complex64::new(1.5, -1.0)]
    }

    fn iterate(&self, c: Complex64, z: Complex64) -> Complex64 {
        let absz = Complex64::new(z.re.abs(), -z.im.abs());
        geometry::cpow(absz, self.power) + c
    }
}

/// Variation of the burning ship and mandelbrot fractals.
///
/// I made the name up, since I could not find a name online for this
/// variation. Where the BurningShip is defined as:
///
/// ```
/// f(z) = (abs(Re(z)) - i*abs(Im(z)))^2 + c
/// ```
///
/// This fractal is defined as:
///
/// ```
/// f(z) = (abs(Re(z)) - i*Im(z))^2 + c
/// ```
///
/// Where only the Real part of z is converted to its absolute value.
pub struct BurningMandel {
    max_iters: u64,
    power: u64,
}

impl BurningMandel {
    /// Creates a new escape time specification for the burning ship family of fractals.
    ///
    /// `max_iterations` specifies the cutoff iteration for deciding whether a complex number
    /// escapes or has converged.
    ///
    /// `power` specifies the exponent used in the burning ship equation. The burning ship fractal
    /// has an exponent of 2, but this allows for an exponent of 3, 4, etc. to explore these
    /// related fractals. See <https://theory.org/fracdyn/burningship/symmetry.html> for examples
    /// of what these may look like.
    pub fn new(max_iterations: u64, power: u64) -> BurningMandel {
        BurningMandel {
            max_iters: max_iterations,
            power: power,
        }
    }
}

impl EscapeTime for BurningMandel {
    fn max_iterations(&self) -> u64 {
        self.max_iters
    }

    fn default_view_area(&self) -> [Complex64; 2] {
        [Complex64::new(-2.5, 1.0), Complex64::new(1.5, -1.0)]
    }

    fn iterate(&self, c: Complex64, z: Complex64) -> Complex64 {
        let absz = Complex64::new(z.re.abs(), -z.im);
        geometry::cpow(absz, self.power) + c
    }
}

/// Variation of the burning ship and mandelbrot fractals.
///
/// I made the name up, since I could not find a name online for this
/// variation. Where the BurningShip is defined as:
///
/// ```
/// f(z) = (abs(Re(z)) - i*abs(Im(z)))^2 + c
/// ```
///
/// This fractal is defined as:
///
/// ```
/// f(z) = (Re(z) - i*abs(Im(z)))^2 + c
/// ```
///
/// Where only the Imaginary part of z is converted to its absolute value.
pub struct RoadRunner {
    max_iters: u64,
    power: u64,
}

impl RoadRunner {
    /// Creates a new escape time specification for the burning ship family of fractals.
    ///
    /// `max_iterations` specifies the cutoff iteration for deciding whether a complex number
    /// escapes or has converged.
    ///
    /// `power` specifies the exponent used in the burning ship equation. The burning ship fractal
    /// has an exponent of 2, but this allows for an exponent of 3, 4, etc. to explore these
    /// related fractals. See <https://theory.org/fracdyn/burningship/symmetry.html> for examples
    /// of what these may look like.
    pub fn new(max_iterations: u64, power: u64) -> RoadRunner {
        RoadRunner {
            max_iters: max_iterations,
            power: power,
        }
    }
}

impl EscapeTime for RoadRunner {
    fn max_iterations(&self) -> u64 {
        self.max_iters
    }

    fn default_view_area(&self) -> [Complex64; 2] {
        [Complex64::new(-2.5, 1.5), Complex64::new(1.5, -1.5)]
    }

    fn iterate(&self, c: Complex64, z: Complex64) -> Complex64 {
        let absz = Complex64::new(z.re, -z.im.abs());
        geometry::cpow(absz, self.power) + c
    }
}
<commit_msg>Fixing doctests accidentally added in new variation<commit_after>// Copyright (c) 2016 William (B.J.) Snow Orvis
//
// 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.

//! The burning ship fractal is an iterated function system similar to
//! Mandelbrot, but it is over the complex number function:
//! ```text
//! f(z) = (abs(Re(z)) - i*abs(Im(z)))^2 + c
//! ```
//! It differs from the Mandelbrot equation in that the real and imaginary
//! components of z are always set to their absolute value before squaring
//! them. Also, the absolute value of the imaginary component of z is sometimes
//! added instead of subtracted, which makes the fractal flip upside down.
//!
//! This module also contains a few other variations of the burning ship
//! fractal that differ by only taking the absolute value of one of the
//! components of z (taking no absolute value would be the mandelbrot set)

use super::*;
use super::super::geometry;

pub struct BurningShip {
    max_iters: u64,
    power: u64,
}

impl BurningShip {
    /// Creates a new escape time specification for the burning ship family of fractals.
    ///
    /// `max_iterations` specifies the cutoff iteration for deciding whether a complex number
    /// escapes or has converged.
    ///
    /// `power` specifies the exponent used in the burning ship equation. The burning ship fractal
    /// has an exponent of 2, but this allows for an exponent of 3, 4, etc. to explore these
    /// related fractals. See <https://theory.org/fracdyn/burningship/symmetry.html> for examples
    /// of what these may look like.
    pub fn new(max_iterations: u64, power: u64) -> BurningShip {
        BurningShip {
            max_iters: max_iterations,
            power: power,
        }
    }
}

impl EscapeTime for BurningShip {
    fn max_iterations(&self) -> u64 {
        self.max_iters
    }

    fn default_view_area(&self) -> [Complex64; 2] {
        [Complex64::new(-2.5, 2.0), Complex64::new(1.5, -1.0)]
    }

    fn iterate(&self, c: Complex64, z: Complex64) -> Complex64 {
        let absz = Complex64::new(z.re.abs(), -z.im.abs());
        geometry::cpow(absz, self.power) + c
    }
}

/// Variation of the burning ship and mandelbrot fractals.
///
/// I made the name up, since I could not find a name online for this
/// variation. Where the BurningShip is defined as:
///
/// ```text
/// f(z) = (abs(Re(z)) - i*abs(Im(z)))^2 + c
/// ```
///
/// This fractal is defined as:
///
/// ```text
/// f(z) = (abs(Re(z)) - i*Im(z))^2 + c
/// ```
///
/// Where only the Real part of z is converted to its absolute value.
pub struct BurningMandel {
    max_iters: u64,
    power: u64,
}

impl BurningMandel {
    /// Creates a new escape time specification for the burning ship family of fractals.
    ///
    /// `max_iterations` specifies the cutoff iteration for deciding whether a complex number
    /// escapes or has converged.
    ///
    /// `power` specifies the exponent used in the burning ship equation. The burning ship fractal
    /// has an exponent of 2, but this allows for an exponent of 3, 4, etc. to explore these
    /// related fractals. See <https://theory.org/fracdyn/burningship/symmetry.html> for examples
    /// of what these may look like.
    pub fn new(max_iterations: u64, power: u64) -> BurningMandel {
        BurningMandel {
            max_iters: max_iterations,
            power: power,
        }
    }
}

impl EscapeTime for BurningMandel {
    fn max_iterations(&self) -> u64 {
        self.max_iters
    }

    fn default_view_area(&self) -> [Complex64; 2] {
        [Complex64::new(-2.5, 1.0), Complex64::new(1.5, -1.0)]
    }

    fn iterate(&self, c: Complex64, z: Complex64) -> Complex64 {
        let absz = Complex64::new(z.re.abs(), -z.im);
        geometry::cpow(absz, self.power) + c
    }
}

/// Variation of the burning ship and mandelbrot fractals.
///
/// I made the name up, since I could not find a name online for this
/// variation. Where the BurningShip is defined as:
///
/// ```text
/// f(z) = (abs(Re(z)) - i*abs(Im(z)))^2 + c
/// ```
///
/// This fractal is defined as:
///
/// ```text
/// f(z) = (Re(z) - i*abs(Im(z)))^2 + c
/// ```
///
/// Where only the Imaginary part of z is converted to its absolute value.
pub struct RoadRunner {
    max_iters: u64,
    power: u64,
}

impl RoadRunner {
    /// Creates a new escape time specification for the burning ship family of fractals.
    ///
    /// `max_iterations` specifies the cutoff iteration for deciding whether a complex number
    /// escapes or has converged.
    ///
    /// `power` specifies the exponent used in the burning ship equation. The burning ship fractal
    /// has an exponent of 2, but this allows for an exponent of 3, 4, etc. to explore these
    /// related fractals. See <https://theory.org/fracdyn/burningship/symmetry.html> for examples
    /// of what these may look like.
    pub fn new(max_iterations: u64, power: u64) -> RoadRunner {
        RoadRunner {
            max_iters: max_iterations,
            power: power,
        }
    }
}

impl EscapeTime for RoadRunner {
    fn max_iterations(&self) -> u64 {
        self.max_iters
    }

    fn default_view_area(&self) -> [Complex64; 2] {
        [Complex64::new(-2.5, 1.5), Complex64::new(1.5, -1.5)]
    }

    fn iterate(&self, c: Complex64, z: Complex64) -> Complex64 {
        let absz = Complex64::new(z.re, -z.im.abs());
        geometry::cpow(absz, self.power) + c
    }
}
<|endoftext|>