<commit_before>#![cfg(not(test))]

use core::fmt;
use core::fmt::Write;

use serial_logger;
use serial_logger::write_static;

#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn eh_personality() {
    write_static("PANIC: eh_personality\n");
}

#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {
    write_static("PANIC: rust_eh_unwind_resume\n");
}

#[no_mangle]
pub extern "C" fn __udivti3() {
    write_static("ERROR: Unimplemented intrinsic __udivti3\n");
}

#[no_mangle]
pub extern "C" fn __umodti3() {
    write_static("ERROR: Unimplemented intrinsic __umodti3\n");
}

#[no_mangle]
pub extern "C" fn __muloti4() {
    write_static("ERROR: Unimplemented intrinsic __muloti4\n");
}

#[no_mangle]
pub extern "C" fn __floatundisf() {
    write_static("ERROR: Unimplemented intrinsic __floatundisf\n");
}

#[no_mangle]
pub extern "C" fn __floatundidf() {
    write_static("ERROR: Unimplemented intrinsic __floatundidf\n");
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() {
    write_static("PANIC: _Unwind_Resume\n");
}

#[allow(empty_loop)]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(fmt: fmt::Arguments, file: &'static str, line: u32) -> ! {

    write_static("PANIC: \n");
    let mut logger: serial_logger::SerialLogger = Default::default();
    let _ = write!(logger, "{} {} {}\n", fmt, file, line);

    loop {
        unsafe {
            asm!("cli; hlt;");
        }
    }
}
<commit_msg>Use normal logging and formatting<commit_after>#![cfg(not(test))]

use core::fmt;

#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn eh_personality() {
    error!("PANIC: eh_personality\n");
}

#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {
    error!("PANIC: rust_eh_unwind_resume\n");
}

#[no_mangle]
pub extern "C" fn __udivti3() {
    error!("ERROR: Unimplemented intrinsic __udivti3\n");
}

#[no_mangle]
pub extern "C" fn __umodti3() {
    error!("ERROR: Unimplemented intrinsic __umodti3\n");
}

#[no_mangle]
pub extern "C" fn __muloti4() {
    error!("ERROR: Unimplemented intrinsic __muloti4\n");
}

#[no_mangle]
pub extern "C" fn __floatundisf() {
    error!("ERROR: Unimplemented intrinsic __floatundisf\n");
}

#[no_mangle]
pub extern "C" fn __floatundidf() {
    error!("ERROR: Unimplemented intrinsic __floatundidf\n");
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() {
    error!("PANIC: _Unwind_Resume\n");
}

#[allow(empty_loop)]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(fmt: fmt::Arguments, file: &'static str, line: u32) -> ! {

    error!("PANIC: {} {} {}\n", fmt, file, line);

    loop {
        unsafe {
            asm!("cli; hlt;");
        }
    }
}
<|endoftext|>


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

//! The implementations of `Rand` for the built-in types.

use core::prelude::*;
use core::char;
use core::int;
use core::uint;

use {Rand,Rng};

impl Rand for int {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> int {
        if int::BITS == 32 {
            rng.gen::<i32>() as int
        } else {
            rng.gen::<i64>() as int
        }
    }
}

impl Rand for i8 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> i8 {
        rng.next_u32() as i8
    }
}

impl Rand for i16 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> i16 {
        rng.next_u32() as i16
    }
}

impl Rand for i32 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> i32 {
        rng.next_u32() as i32
    }
}

impl Rand for i64 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> i64 {
        rng.next_u64() as i64
    }
}

impl Rand for uint {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> uint {
        if uint::BITS == 32 {
            rng.gen::<u32>() as uint
        } else {
            rng.gen::<u64>() as uint
        }
    }
}

impl Rand for u8 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> u8 {
        rng.next_u32() as u8
    }
}

impl Rand for u16 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> u16 {
        rng.next_u32() as u16
    }
}

impl Rand for u32 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> u32 {
        rng.next_u32()
    }
}

impl Rand for u64 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> u64 {
        rng.next_u64()
    }
}

macro_rules! float_impls {
    ($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident, $ignored_bits:expr) => {
        mod $mod_name {
            use {Rand, Rng, Open01, Closed01};

            static SCALE: $ty = (1u64 << $mantissa_bits) as $ty;

            impl Rand for $ty {
                /// Generate a floating point number in the half-open
                /// interval `[0,1)`.
                ///
                /// See `Closed01` for the closed interval `[0,1]`,
                /// and `Open01` for the open interval `(0,1)`.
                #[inline]
                fn rand<R: Rng>(rng: &mut R) -> $ty {
                    // using any more than `mantissa_bits` bits will
                    // cause (e.g.) 0xffff_ffff to correspond to 1
                    // exactly, so we need to drop some (8 for f32, 11
                    // for f64) to guarantee the open end.
                    (rng.$method_name() >> $ignored_bits) as $ty / SCALE
                }
            }
            impl Rand for Open01<$ty> {
                #[inline]
                fn rand<R: Rng>(rng: &mut R) -> Open01<$ty> {
                    // add a small amount (specifically 2 bits below
                    // the precision of f64/f32 at 1.0), so that small
                    // numbers are larger than 0, but large numbers
                    // aren't pushed to/above 1.
                    Open01(((rng.$method_name() >> $ignored_bits) as $ty + 0.25) / SCALE)
                }
            }
            impl Rand for Closed01<$ty> {
                #[inline]
                fn rand<R: Rng>(rng: &mut R) -> Closed01<$ty> {
                    // divide by the maximum value of the numerator to
                    // get a non-zero probability of getting exactly
                    // 1.0.
                    Closed01((rng.$method_name() >> $ignored_bits) as $ty / (SCALE - 1.0))
                }
            }
        }
    }
}
float_impls! { f64_rand_impls, f64, 53, next_u64, 11 }
float_impls! { f32_rand_impls, f32, 24, next_u32, 8 }

impl Rand for char {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> char {
        // a char is 21 bits
        static CHAR_MASK: u32 = 0x001f_ffff;
        loop {
            // Rejection sampling. About 0.2% of numbers with at most
            // 21-bits are invalid codepoints (surrogates), so this
            // will succeed first go almost every time.
            match char::from_u32(rng.next_u32() & CHAR_MASK) {
                Some(c) => return c,
                None => {}
            }
        }
    }
}

impl Rand for bool {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> bool {
        rng.gen::<u8>() & 1 == 1
    }
}

macro_rules! tuple_impl {
    // use variables to indicate the arity of the tuple
    ($($tyvar:ident),* ) => {
        // the trailing commas are for the 1 tuple
        impl<
            $( $tyvar : Rand ),*
            > Rand for ( $( $tyvar ),* , ) {

            #[inline]
            fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
                (
                    // use the $tyvar's to get the appropriate number of
                    // repeats (they're not actually needed)
                    $(
                        _rng.gen::<$tyvar>()
                    ),*
                    ,
                )
            }
        }
    }
}

impl Rand for () {
    #[inline]
    fn rand<R: Rng>(_: &mut R) -> () { () }
}
tuple_impl!{A}
tuple_impl!{A, B}
tuple_impl!{A, B, C}
tuple_impl!{A, B, C, D}
tuple_impl!{A, B, C, D, E}
tuple_impl!{A, B, C, D, E, F}
tuple_impl!{A, B, C, D, E, F, G}
tuple_impl!{A, B, C, D, E, F, G, H}
tuple_impl!{A, B, C, D, E, F, G, H, I}
tuple_impl!{A, B, C, D, E, F, G, H, I, J}

impl<T:Rand> Rand for Option<T> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Option<T> {
        if rng.gen() {
            Some(rng.gen())
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::*;
    use std::rand::{Rng, task_rng, Open01, Closed01};

    struct ConstantRng(u64);
    impl Rng for ConstantRng {
        fn next_u32(&mut self) -> u32 {
            let ConstantRng(v) = *self;
            v as u32
        }
        fn next_u64(&mut self) -> u64 {
            let ConstantRng(v) = *self;
            v
        }
    }

    #[test]
    fn floating_point_edge_cases() {
        // the test for exact equality is correct here.
        assert!(ConstantRng(0xffff_ffff).gen::<f32>() != 1.0)
        assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::<f64>() != 1.0)
    }

    #[test]
    fn rand_open() {
        // this is unlikely to catch an incorrect implementation that
        // generates exactly 0 or 1, but it keeps it sane.
        let mut rng = task_rng();
        for _ in range(0u, 1_000) {
            // strict inequalities
            let Open01(f) = rng.gen::<Open01<f64>>();
            assert!(0.0 < f && f < 1.0);

            let Open01(f) = rng.gen::<Open01<f32>>();
            assert!(0.0 < f && f < 1.0);
        }
    }

    #[test]
    fn rand_closed() {
        let mut rng = task_rng();
        for _ in range(0u, 1_000) {
            // strict inequalities
            let Closed01(f) = rng.gen::<Closed01<f64>>();
            assert!(0.0 <= f && f <= 1.0);

            let Closed01(f) = rng.gen::<Closed01<f32>>();
            assert!(0.0 <= f && f <= 1.0);
        }
    }
}
<commit_msg>Impl Rand for tuples of arity 11 and 12<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The implementations of `Rand` for the built-in types.

use core::prelude::*;
use core::char;
use core::int;
use core::uint;

use {Rand,Rng};

impl Rand for int {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> int {
        if int::BITS == 32 {
            rng.gen::<i32>() as int
        } else {
            rng.gen::<i64>() as int
        }
    }
}

impl Rand for i8 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> i8 {
        rng.next_u32() as i8
    }
}

impl Rand for i16 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> i16 {
        rng.next_u32() as i16
    }
}

impl Rand for i32 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> i32 {
        rng.next_u32() as i32
    }
}

impl Rand for i64 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> i64 {
        rng.next_u64() as i64
    }
}

impl Rand for uint {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> uint {
        if uint::BITS == 32 {
            rng.gen::<u32>() as uint
        } else {
            rng.gen::<u64>() as uint
        }
    }
}

impl Rand for u8 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> u8 {
        rng.next_u32() as u8
    }
}

impl Rand for u16 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> u16 {
        rng.next_u32() as u16
    }
}

impl Rand for u32 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> u32 {
        rng.next_u32()
    }
}

impl Rand for u64 {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> u64 {
        rng.next_u64()
    }
}

macro_rules! float_impls {
    ($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident, $ignored_bits:expr) => {
        mod $mod_name {
            use {Rand, Rng, Open01, Closed01};

            static SCALE: $ty = (1u64 << $mantissa_bits) as $ty;

            impl Rand for $ty {
                /// Generate a floating point number in the half-open
                /// interval `[0,1)`.
                ///
                /// See `Closed01` for the closed interval `[0,1]`,
                /// and `Open01` for the open interval `(0,1)`.
                #[inline]
                fn rand<R: Rng>(rng: &mut R) -> $ty {
                    // using any more than `mantissa_bits` bits will
                    // cause (e.g.) 0xffff_ffff to correspond to 1
                    // exactly, so we need to drop some (8 for f32, 11
                    // for f64) to guarantee the open end.
                    (rng.$method_name() >> $ignored_bits) as $ty / SCALE
                }
            }
            impl Rand for Open01<$ty> {
                #[inline]
                fn rand<R: Rng>(rng: &mut R) -> Open01<$ty> {
                    // add a small amount (specifically 2 bits below
                    // the precision of f64/f32 at 1.0), so that small
                    // numbers are larger than 0, but large numbers
                    // aren't pushed to/above 1.
                    Open01(((rng.$method_name() >> $ignored_bits) as $ty + 0.25) / SCALE)
                }
            }
            impl Rand for Closed01<$ty> {
                #[inline]
                fn rand<R: Rng>(rng: &mut R) -> Closed01<$ty> {
                    // divide by the maximum value of the numerator to
                    // get a non-zero probability of getting exactly
                    // 1.0.
                    Closed01((rng.$method_name() >> $ignored_bits) as $ty / (SCALE - 1.0))
                }
            }
        }
    }
}
float_impls! { f64_rand_impls, f64, 53, next_u64, 11 }
float_impls! { f32_rand_impls, f32, 24, next_u32, 8 }

impl Rand for char {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> char {
        // a char is 21 bits
        static CHAR_MASK: u32 = 0x001f_ffff;
        loop {
            // Rejection sampling. About 0.2% of numbers with at most
            // 21-bits are invalid codepoints (surrogates), so this
            // will succeed first go almost every time.
            match char::from_u32(rng.next_u32() & CHAR_MASK) {
                Some(c) => return c,
                None => {}
            }
        }
    }
}

impl Rand for bool {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> bool {
        rng.gen::<u8>() & 1 == 1
    }
}

macro_rules! tuple_impl {
    // use variables to indicate the arity of the tuple
    ($($tyvar:ident),* ) => {
        // the trailing commas are for the 1 tuple
        impl<
            $( $tyvar : Rand ),*
            > Rand for ( $( $tyvar ),* , ) {

            #[inline]
            fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) {
                (
                    // use the $tyvar's to get the appropriate number of
                    // repeats (they're not actually needed)
                    $(
                        _rng.gen::<$tyvar>()
                    ),*
                    ,
                )
            }
        }
    }
}

impl Rand for () {
    #[inline]
    fn rand<R: Rng>(_: &mut R) -> () { () }
}
tuple_impl!{A}
tuple_impl!{A, B}
tuple_impl!{A, B, C}
tuple_impl!{A, B, C, D}
tuple_impl!{A, B, C, D, E}
tuple_impl!{A, B, C, D, E, F}
tuple_impl!{A, B, C, D, E, F, G}
tuple_impl!{A, B, C, D, E, F, G, H}
tuple_impl!{A, B, C, D, E, F, G, H, I}
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}

impl<T:Rand> Rand for Option<T> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Option<T> {
        if rng.gen() {
            Some(rng.gen())
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::*;
    use std::rand::{Rng, task_rng, Open01, Closed01};

    struct ConstantRng(u64);
    impl Rng for ConstantRng {
        fn next_u32(&mut self) -> u32 {
            let ConstantRng(v) = *self;
            v as u32
        }
        fn next_u64(&mut self) -> u64 {
            let ConstantRng(v) = *self;
            v
        }
    }

    #[test]
    fn floating_point_edge_cases() {
        // the test for exact equality is correct here.
        assert!(ConstantRng(0xffff_ffff).gen::<f32>() != 1.0)
        assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::<f64>() != 1.0)
    }

    #[test]
    fn rand_open() {
        // this is unlikely to catch an incorrect implementation that
        // generates exactly 0 or 1, but it keeps it sane.
        let mut rng = task_rng();
        for _ in range(0u, 1_000) {
            // strict inequalities
            let Open01(f) = rng.gen::<Open01<f64>>();
            assert!(0.0 < f && f < 1.0);

            let Open01(f) = rng.gen::<Open01<f32>>();
            assert!(0.0 < f && f < 1.0);
        }
    }

    #[test]
    fn rand_closed() {
        let mut rng = task_rng();
        for _ in range(0u, 1_000) {
            // strict inequalities
            let Closed01(f) = rng.gen::<Closed01<f64>>();
            assert!(0.0 <= f && f <= 1.0);

            let Closed01(f) = rng.gen::<Closed01<f32>>();
            assert!(0.0 <= f && f <= 1.0);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Dmitry Tantsur <divius.inside@gmail.com>
//
// 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.

//! Generic API bits for implementing new services.

use std::cmp;
use std::fmt::Debug;
use std::vec;

use fallible_iterator::FallibleIterator;
use reqwest::Url;
use reqwest::header::Headers;
use serde::Serialize;

use super::{Error, Result, ApiVersion, ApiVersionRequest};
use super::auth::AuthMethod;
use super::session::Session;
use super::utils::Query;

/// Information about API endpoint.
#[derive(Clone, Debug)]
pub struct ServiceInfo {
    /// Root endpoint.
    pub root_url: Url,
    /// Current API version (if supported).
    pub current_version: Option<ApiVersion>,
    /// Minimum API version (if supported).
    pub minimum_version: Option<ApiVersion>
}

/// Trait representing a service type.
pub trait ServiceType {
    /// Service type to pass to the catalog.
    fn catalog_type() -> &'static str;

    /// Get basic service information.
    fn service_info(endpoint: Url, auth: &AuthMethod) -> Result<ServiceInfo>;

    /// Return headers to set for this API version.
    fn api_version_headers(_version: ApiVersion) -> Option<Headers> { None }
}

/// Trait representing a service with API version support.
pub trait ApiVersioning {}

impl ServiceInfo {
    /// Pick an API version.
    pub fn pick_api_version(&self, request: ApiVersionRequest)
            -> Option<ApiVersion> {
        match request {
            ApiVersionRequest::Minimum =>
                self.minimum_version,
            ApiVersionRequest::Latest =>
                self.current_version,
            ApiVersionRequest::LatestFrom(from, to) => {
                match (self.current_version, self.minimum_version) {
                    (Some(max), None) if max >= from && max <= to => Some(max),
                    (None, Some(min)) if min >= from && min <= to => Some(min),
                    (Some(max), Some(min)) if to >= min && from <= max =>
                        Some(cmp::min(max, to)),
                    _ => None
                }
            },
            ApiVersionRequest::Exact(req) => {
                self.current_version.and_then(|max| {
                    match self.minimum_version {
                        Some(min) if req >= min && req <= max => Some(req),
                        None if req == max => Some(req),
                        _ => None
                    }
                })
            },
            ApiVersionRequest::Choice(vec) => {
                if vec.is_empty() {
                    return None;
                }

                self.current_version.and_then(|max| {
                    match self.minimum_version {
                        Some(min) => vec.into_iter().filter(|x| {
                            *x >= min && *x <= max
                        }).max(),
                        None =>vec.into_iter().find(|x| *x == max)
                    }
                })
            }
        }
    }
}

/// Trait representing something that has an ID.
pub trait ResourceId {
    /// Identifier of the current resource.
    fn resource_id(&self) -> String;
}

/// Trait representing something that can be listed from a session.
pub trait ListResources<'a> {
    /// Default limit to use with this resource.
    const DEFAULT_LIMIT: usize;

    /// List the resources from the session.
    fn list_resources<Q: Serialize + Debug>(session: &'a Session, query: Q)
        -> Result<Vec<Self>> where Self: Sized;
}

/// Generic implementation of a `FallibleIterator` over resources.
#[derive(Debug)]
pub struct ResourceIterator<'session, T> {
    session: &'session Session,
    query: Query,
    cache: Option<vec::IntoIter<T>>,
    marker: Option<String>,
    can_paginate: bool,
}

impl<'session, T> ResourceIterator<'session, T> {
    #[allow(dead_code)]  // unused with --no-default-features
    pub(crate) fn new(session: &'session Session, query: Query)
            -> ResourceIterator<'session, T> {
        let can_paginate = query.0.iter().all(|pair| {
            pair.0 != "limit" && pair.0 != "marker"
        });

        ResourceIterator {
            session: session,
            query: query,
            cache: None,
            marker: None,
            can_paginate: can_paginate
        }
    }
}

impl<'session, T> FallibleIterator for ResourceIterator<'session, T>
        where T: ListResources<'session> + ResourceId {
    type Item = T;

    type Error = Error;

    fn next(&mut self) -> Result<Option<T>> {
        let maybe_next = self.cache.as_mut().and_then(|cache| cache.next());
        Ok(if maybe_next.is_some() {
            maybe_next
        } else {
            if self.cache.is_some() && ! self.can_paginate {
                // We have exhausted the results and pagination is not possible
                None
            } else {
                let mut query = self.query.clone();

                if self.can_paginate {
                    // can_paginate=true implies no limit was provided
                    query.push("limit", T::DEFAULT_LIMIT);
                    if let Some(marker) = self.marker.take() {
                        query.push_str("marker", marker);
                    }
                }

                let mut servers_iter = T::list_resources(self.session,
                                                         &query.0)?
                    .into_iter();
                let maybe_next = servers_iter.next();
                self.cache = Some(servers_iter);

                maybe_next
            }
        }.map(|next| {
            self.marker = Some(next.resource_id());
            next
        }))
    }
}

#[cfg(test)]
pub mod test {
    use reqwest::Url;

    use super::super::{ApiVersion, ApiVersionRequest};
    use super::ServiceInfo;

    fn service_info(min: Option<u16>, max: Option<u16>) -> ServiceInfo {
        ServiceInfo {
            root_url: Url::parse("http://127.0.0.1").unwrap(),
            minimum_version: min.map(|x| ApiVersion(2, x)),
            current_version: max.map(|x| ApiVersion(2, x)),
        }
    }

    #[test]
    fn test_pick_version_exact() {
        let info = service_info(Some(1), Some(24));
        let version = ApiVersion(2, 22);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version))
            .unwrap();
        assert_eq!(result, version);
    }

    #[test]
    fn test_pick_version_exact_mismatch() {
        let info = service_info(Some(1), Some(24));
        let version = ApiVersion(2, 25);
        let res1 = info.pick_api_version(ApiVersionRequest::Exact(version));
        assert!(res1.is_none());
        let version2 = ApiVersion(1, 11);
        let res2 = info.pick_api_version(ApiVersionRequest::Exact(version2));
        assert!(res2.is_none());
    }

    #[test]
    fn test_pick_version_exact_current_only() {
        let info = service_info(None, Some(24));
        let version = ApiVersion(2, 24);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version))
            .unwrap();
        assert_eq!(result, version);
    }

    #[test]
    fn test_pick_version_exact_current_only_mismatch() {
        let info = service_info(None, Some(24));
        let version = ApiVersion(2, 22);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version));
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_minimum() {
        let info = service_info(Some(1), Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Minimum)
            .unwrap();
        assert_eq!(result, ApiVersion(2, 1));
    }

    #[test]
    fn test_pick_version_minimum_unknown() {
        let info = service_info(None, Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Minimum);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest() {
        let info = service_info(Some(1), Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Latest)
            .unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_latest_unknown() {
        let info = service_info(Some(1), None);
        let result = info.pick_api_version(ApiVersionRequest::Latest);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest_from_within_range() {
        let info = service_info(Some(1), Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 5),
                                                ApiVersion(2, 20));
        let result = info.pick_api_version(req).unwrap();
        assert_eq!(result, ApiVersion(2, 20));
    }

    #[test]
    fn test_pick_version_latest_from_outside_range() {
        let info = service_info(Some(1), Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 0),
                                                ApiVersion(2, 50));
        let result = info.pick_api_version(req).unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_latest_from_mismatch_above() {
        let info = service_info(Some(1), Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 25),
                                                ApiVersion(2, 50));
        let result = info.pick_api_version(req);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest_from_mismatch_below() {
        let info = service_info(Some(5), Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 1),
                                                ApiVersion(2, 4));
        let result = info.pick_api_version(req);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest_from_only_current() {
        let info = service_info(None, Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 5),
                                                ApiVersion(2, 50));
        let result = info.pick_api_version(req).unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_latest_from_only_current_mismatch() {
        let info = service_info(None, Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 5),
                                                ApiVersion(2, 10));
        let result = info.pick_api_version(req);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest_from_only_minimum() {
        let info = service_info(Some(1), None);
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 0),
                                                ApiVersion(2, 50));
        let result = info.pick_api_version(req).unwrap();
        assert_eq!(result, ApiVersion(2, 1));
    }

    #[test]
    fn test_pick_version_latest_from_only_minimum_mismatch() {
        let info = service_info(Some(1), None);
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 5),
                                                ApiVersion(2, 10));
        let result = info.pick_api_version(req);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_choice() {
        let info = service_info(Some(1), Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 22), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice))
            .unwrap();
        assert_eq!(result, ApiVersion(2, 22));
    }

    #[test]
    fn test_pick_version_choice_mismatch() {
        let info = service_info(Some(1), Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice));
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_choice_current_only() {
        let info = service_info(None, Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 24), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice))
            .unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_choice_current_only_mismatch() {
        let info = service_info(None, Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 22), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice));
        assert!(result.is_none());
    }
}
<commit_msg>feat(service): derive Clone for ResourceIterator<commit_after>// Copyright 2017 Dmitry Tantsur <divius.inside@gmail.com>
//
// 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.

//! Generic API bits for implementing new services.

use std::cmp;
use std::fmt::Debug;
use std::vec;

use fallible_iterator::FallibleIterator;
use reqwest::Url;
use reqwest::header::Headers;
use serde::Serialize;

use super::{Error, Result, ApiVersion, ApiVersionRequest};
use super::auth::AuthMethod;
use super::session::Session;
use super::utils::Query;

/// Information about API endpoint.
#[derive(Clone, Debug)]
pub struct ServiceInfo {
    /// Root endpoint.
    pub root_url: Url,
    /// Current API version (if supported).
    pub current_version: Option<ApiVersion>,
    /// Minimum API version (if supported).
    pub minimum_version: Option<ApiVersion>
}

/// Trait representing a service type.
pub trait ServiceType {
    /// Service type to pass to the catalog.
    fn catalog_type() -> &'static str;

    /// Get basic service information.
    fn service_info(endpoint: Url, auth: &AuthMethod) -> Result<ServiceInfo>;

    /// Return headers to set for this API version.
    fn api_version_headers(_version: ApiVersion) -> Option<Headers> { None }
}

/// Trait representing a service with API version support.
pub trait ApiVersioning {}

impl ServiceInfo {
    /// Pick an API version.
    pub fn pick_api_version(&self, request: ApiVersionRequest)
            -> Option<ApiVersion> {
        match request {
            ApiVersionRequest::Minimum =>
                self.minimum_version,
            ApiVersionRequest::Latest =>
                self.current_version,
            ApiVersionRequest::LatestFrom(from, to) => {
                match (self.current_version, self.minimum_version) {
                    (Some(max), None) if max >= from && max <= to => Some(max),
                    (None, Some(min)) if min >= from && min <= to => Some(min),
                    (Some(max), Some(min)) if to >= min && from <= max =>
                        Some(cmp::min(max, to)),
                    _ => None
                }
            },
            ApiVersionRequest::Exact(req) => {
                self.current_version.and_then(|max| {
                    match self.minimum_version {
                        Some(min) if req >= min && req <= max => Some(req),
                        None if req == max => Some(req),
                        _ => None
                    }
                })
            },
            ApiVersionRequest::Choice(vec) => {
                if vec.is_empty() {
                    return None;
                }

                self.current_version.and_then(|max| {
                    match self.minimum_version {
                        Some(min) => vec.into_iter().filter(|x| {
                            *x >= min && *x <= max
                        }).max(),
                        None =>vec.into_iter().find(|x| *x == max)
                    }
                })
            }
        }
    }
}

/// Trait representing something that has an ID.
pub trait ResourceId {
    /// Identifier of the current resource.
    fn resource_id(&self) -> String;
}

/// Trait representing something that can be listed from a session.
pub trait ListResources<'a> {
    /// Default limit to use with this resource.
    const DEFAULT_LIMIT: usize;

    /// List the resources from the session.
    fn list_resources<Q: Serialize + Debug>(session: &'a Session, query: Q)
        -> Result<Vec<Self>> where Self: Sized;
}

/// Generic implementation of a `FallibleIterator` over resources.
#[derive(Debug, Clone)]
pub struct ResourceIterator<'session, T> {
    session: &'session Session,
    query: Query,
    cache: Option<vec::IntoIter<T>>,
    marker: Option<String>,
    can_paginate: bool,
}

impl<'session, T> ResourceIterator<'session, T> {
    #[allow(dead_code)]  // unused with --no-default-features
    pub(crate) fn new(session: &'session Session, query: Query)
            -> ResourceIterator<'session, T> {
        let can_paginate = query.0.iter().all(|pair| {
            pair.0 != "limit" && pair.0 != "marker"
        });

        ResourceIterator {
            session: session,
            query: query,
            cache: None,
            marker: None,
            can_paginate: can_paginate
        }
    }
}

impl<'session, T> FallibleIterator for ResourceIterator<'session, T>
        where T: ListResources<'session> + ResourceId {
    type Item = T;

    type Error = Error;

    fn next(&mut self) -> Result<Option<T>> {
        let maybe_next = self.cache.as_mut().and_then(|cache| cache.next());
        Ok(if maybe_next.is_some() {
            maybe_next
        } else {
            if self.cache.is_some() && ! self.can_paginate {
                // We have exhausted the results and pagination is not possible
                None
            } else {
                let mut query = self.query.clone();

                if self.can_paginate {
                    // can_paginate=true implies no limit was provided
                    query.push("limit", T::DEFAULT_LIMIT);
                    if let Some(marker) = self.marker.take() {
                        query.push_str("marker", marker);
                    }
                }

                let mut servers_iter = T::list_resources(self.session,
                                                         &query.0)?
                    .into_iter();
                let maybe_next = servers_iter.next();
                self.cache = Some(servers_iter);

                maybe_next
            }
        }.map(|next| {
            self.marker = Some(next.resource_id());
            next
        }))
    }
}

#[cfg(test)]
pub mod test {
    use reqwest::Url;

    use super::super::{ApiVersion, ApiVersionRequest};
    use super::ServiceInfo;

    fn service_info(min: Option<u16>, max: Option<u16>) -> ServiceInfo {
        ServiceInfo {
            root_url: Url::parse("http://127.0.0.1").unwrap(),
            minimum_version: min.map(|x| ApiVersion(2, x)),
            current_version: max.map(|x| ApiVersion(2, x)),
        }
    }

    #[test]
    fn test_pick_version_exact() {
        let info = service_info(Some(1), Some(24));
        let version = ApiVersion(2, 22);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version))
            .unwrap();
        assert_eq!(result, version);
    }

    #[test]
    fn test_pick_version_exact_mismatch() {
        let info = service_info(Some(1), Some(24));
        let version = ApiVersion(2, 25);
        let res1 = info.pick_api_version(ApiVersionRequest::Exact(version));
        assert!(res1.is_none());
        let version2 = ApiVersion(1, 11);
        let res2 = info.pick_api_version(ApiVersionRequest::Exact(version2));
        assert!(res2.is_none());
    }

    #[test]
    fn test_pick_version_exact_current_only() {
        let info = service_info(None, Some(24));
        let version = ApiVersion(2, 24);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version))
            .unwrap();
        assert_eq!(result, version);
    }

    #[test]
    fn test_pick_version_exact_current_only_mismatch() {
        let info = service_info(None, Some(24));
        let version = ApiVersion(2, 22);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version));
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_minimum() {
        let info = service_info(Some(1), Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Minimum)
            .unwrap();
        assert_eq!(result, ApiVersion(2, 1));
    }

    #[test]
    fn test_pick_version_minimum_unknown() {
        let info = service_info(None, Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Minimum);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest() {
        let info = service_info(Some(1), Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Latest)
            .unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_latest_unknown() {
        let info = service_info(Some(1), None);
        let result = info.pick_api_version(ApiVersionRequest::Latest);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest_from_within_range() {
        let info = service_info(Some(1), Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 5),
                                                ApiVersion(2, 20));
        let result = info.pick_api_version(req).unwrap();
        assert_eq!(result, ApiVersion(2, 20));
    }

    #[test]
    fn test_pick_version_latest_from_outside_range() {
        let info = service_info(Some(1), Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 0),
                                                ApiVersion(2, 50));
        let result = info.pick_api_version(req).unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_latest_from_mismatch_above() {
        let info = service_info(Some(1), Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 25),
                                                ApiVersion(2, 50));
        let result = info.pick_api_version(req);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest_from_mismatch_below() {
        let info = service_info(Some(5), Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 1),
                                                ApiVersion(2, 4));
        let result = info.pick_api_version(req);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest_from_only_current() {
        let info = service_info(None, Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 5),
                                                ApiVersion(2, 50));
        let result = info.pick_api_version(req).unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_latest_from_only_current_mismatch() {
        let info = service_info(None, Some(24));
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 5),
                                                ApiVersion(2, 10));
        let result = info.pick_api_version(req);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest_from_only_minimum() {
        let info = service_info(Some(1), None);
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 0),
                                                ApiVersion(2, 50));
        let result = info.pick_api_version(req).unwrap();
        assert_eq!(result, ApiVersion(2, 1));
    }

    #[test]
    fn test_pick_version_latest_from_only_minimum_mismatch() {
        let info = service_info(Some(1), None);
        let req = ApiVersionRequest::LatestFrom(ApiVersion(2, 5),
                                                ApiVersion(2, 10));
        let result = info.pick_api_version(req);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_choice() {
        let info = service_info(Some(1), Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 22), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice))
            .unwrap();
        assert_eq!(result, ApiVersion(2, 22));
    }

    #[test]
    fn test_pick_version_choice_mismatch() {
        let info = service_info(Some(1), Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice));
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_choice_current_only() {
        let info = service_info(None, Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 24), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice))
            .unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_choice_current_only_mismatch() {
        let info = service_info(None, Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 22), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice));
        assert!(result.is_none());
    }
}
<|endoftext|>


<commit_before>use sodiumoxide::crypto::onetimeauth::poly1305;
use sodiumoxide::crypto::hash::sha512;
use sodiumoxide::crypto::scalarmult::curve25519;
use sodiumoxide::crypto::stream::chacha20;
use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305;
//use sodiumoxide::randombytes::randombytes;
use byteorder::{LittleEndian, WriteBytesExt};

macro_rules! make_fixed {
    ($t:ty, $n:expr, $v:expr) => ({
        let mut res : [$t; $n] = [0; $n];
        assert!($v.len() == $n);
        for i in 0..$n { res[i] = $v[i] }
        res
    })
}

macro_rules! concat_vec {
    ($x:expr, $($y:expr),+) => ({
        $x.iter() $(.chain($y.iter()))+ .cloned().collect::<Vec<u8>>()
    })
}

pub fn pad16(input: &[u8]) -> Vec<u8> {
    let mut out = input.iter().cloned().collect::<Vec<u8>>();
    for _ in (out.len() % 16)..16 {
        out.push(0);
    }
    out
}

pub const MAC_LEN: usize = 16;
pub const CV_LEN: usize = 48;
pub const H_LEN: usize = 64;
pub const DH_LEN: usize = 32;
// "Noise255" followed by 16 zeros
pub const SUITE_NAME: [u8; 24] = [0x4E, 0x6F, 0x69, 0x73, 0x65, 0x32, 0x35, 0x35,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

pub fn hmac_sha512(key: &[u8], message: &[u8]) -> sha512::Digest {
    let nkey = if key.len() > sha512::HASHBYTES {
        sha512::hash(key).0
    } else {
        let mut arr = [0u8; sha512::HASHBYTES];
        for i in 0..key.len() { arr[i] = key[i] }
        arr
    };
    let o_pad = nkey.iter().map(|x| x^0x5c).collect::<Vec<u8>>();
    let i_pad = nkey.iter().map(|x| x^0x36).collect::<Vec<u8>>();

    let in1 : sha512::Digest = sha512::hash(&concat_vec!(i_pad, message)[..]);
    sha512::hash(&concat_vec!(o_pad, in1.0)[..])
}

pub fn getkey(key: &chacha20::Key, nonce: &chacha20::Nonce) -> chacha20::Key {
    chacha20::Key(make_fixed!(u8, chacha20::KEYBYTES, chacha20::stream(chacha20::KEYBYTES, nonce, key)))
}

pub fn kdf(key: &chacha20::Key, nonce: &chacha20::Nonce, input: &[u8]) -> chacha20::Key {
    chacha20::Key(make_fixed!(u8, 32, hmac_sha512(&getkey(key, nonce).0[..], input).0[..32]))
}

pub fn dh(privkey: &[u8; DH_LEN], pubkey: &[u8; DH_LEN]) -> [u8; DH_LEN] {
    curve25519::scalarmult(&curve25519::Scalar(*privkey), &curve25519::GroupElement(*pubkey)).0
}

pub struct NoiseBody {
    ciphertext: Vec<u8>,
    mac: poly1305::Tag
}

#[derive(Clone)]
pub struct PubKey(pub [u8; DH_LEN]);
#[derive(Clone)]
pub struct PrivKey(pub [u8; DH_LEN]);

#[derive(Clone)]
pub struct KeyPair {
    pub pubkey: PubKey,
    pub privkey: PrivKey
}

pub struct Session {
    pub s: Option<KeyPair>,
    e: Option<KeyPair>,
    pub rs: Option<PubKey>,
    re: Option<PubKey>,
    pub k: Option<chacha20::Key>,
    pub n: u64,
    pub h: sha512::Digest
}

pub enum Descriptor {
    Ephemeral,
    Static,
    DHSS,
    DHEE,
    DHSE,
    DHES
}

pub fn gen_keypair() -> KeyPair {
    let bkp = curve25519xsalsa20poly1305::gen_keypair();
    KeyPair {
        pubkey: PubKey((bkp.0).0),
        privkey: PrivKey((bkp.1).0)
    }
}

impl Session {
    pub fn new(local: Option<KeyPair>, remote: Option<PubKey>) -> Session {
        Session {
            s: local,
            e: None,
            rs: remote,
            re: None,
            k: None,
            n: 0,
            h: sha512::Digest([0u8; 64])
        }
    }

    pub fn get_nonce(&mut self) -> chacha20::Nonce {
        let mut n = vec![];
        n.write_u64::<LittleEndian>(self.n).unwrap();
        self.n += 1;
        chacha20::Nonce::from_slice(&n[..]).unwrap()
    }

    pub fn derive(&mut self) -> Session {
        let n = self.get_nonce();
        Session {
            s: self.s.clone(),
            e: None,
            rs: self.rs.clone(),
            re: None,
            k: match self.k {
                Some(ref k) => {
                    Some(getkey(&k, &n))
                },
                None => None
            },
            n: 0,
            h: self.h.clone()
        }
    }

    fn session_dh(&mut self, sender: &PrivKey, receiver: &PubKey) {
        let n = self.get_nonce();
        let k = self.k.clone().unwrap_or(chacha20::Key([0; 32]));
        self.k = Some(kdf(&k, &n, &dh(&sender.0, &receiver.0)[..]));
    }

    pub fn create(&mut self, prologue: &[u8], descriptors: &[Descriptor], payload: &[u8]) -> Vec<u8> {
        assert!(prologue.len() < 256);
        let mut buf = vec![];
        buf.push(prologue.len() as u8);
        buf.extend(prologue.iter().cloned());

        macro_rules! dh_branch {
            ($a:ident, $b:ident) => ({
                let $a = self.$a.clone().unwrap().privkey;
                let $b = self.$b.clone().unwrap();
                self.session_dh(&$a, &$b)
            })
        }

        for d in descriptors.iter() {
            match *d {
                Descriptor::Ephemeral => {
                    self.e = Some(gen_keypair());
                    buf.extend(self.e.clone().unwrap().pubkey.0.iter().cloned())
                },
                Descriptor::Static => {
                    let k = self.k.clone().unwrap();
                    let n = self.get_nonce();
                    let s = self.s.clone().unwrap().pubkey.0;
                    let a = concat_vec!(buf, self.h.0);
                    buf.extend(NoiseBody::encrypt(&k, &n, &a[..], &s[..])
                               .write().iter().cloned());
                },
                Descriptor::DHSS => dh_branch!(s, rs),
                Descriptor::DHEE => dh_branch!(e, re),
                Descriptor::DHSE => dh_branch!(s, re),
                Descriptor::DHES => dh_branch!(e, rs)
            }
        }
        let n = self.get_nonce();
        let a = concat_vec!(buf, self.h.0);
        match self.k {
            Some(ref k) => {
                buf.extend(NoiseBody::encrypt(&k, &n, &a[..], payload).write().iter().cloned());
            }
            None => buf.extend(payload.iter().cloned())
        }
        if descriptors.len() > 0 {
            self.h = sha512::hash(&concat_vec!(self.h.0, buf)[..]);
        }

        buf
    }

    pub fn consume(&mut self, data: &[u8], descriptors: &[Descriptor])
                   -> Result<(Vec<u8>, Vec<u8>), ()> {
        assert!(data.len() > 0);
        let plen = data[0] as usize;
        let prologue = data[1..plen+1].to_vec();
        let mut off = plen + 1;

        macro_rules! dh_branch {
            ($a:ident, $b:ident) => ({
                let $a = self.$a.clone().unwrap().privkey;
                let $b = self.$b.clone().unwrap();
                self.session_dh(&$a, &$b)
            })
        }

        for d in descriptors.iter() {
            match *d {
                Descriptor::Ephemeral => {
                    self.re = Some(PubKey(make_fixed!(u8, DH_LEN, data[off..off+DH_LEN])));
                    off += DH_LEN;
                },
                Descriptor::Static => {
                    let k = self.k.clone().unwrap();
                    let n = self.get_nonce();
                    let a = concat_vec!(data[..off], self.h.0);
                    self.rs = Some(PubKey(make_fixed!(u8, DH_LEN, try!(NoiseBody::read(&data[off..off+DH_LEN+MAC_LEN])
                                                                       .decrypt(&k, &n, &a[..])))));
                    off += DH_LEN + MAC_LEN;
                },
                Descriptor::DHSS => dh_branch!(s, rs),
                Descriptor::DHEE => dh_branch!(e, re),
                Descriptor::DHSE => dh_branch!(e, rs), // reversed because consuming instead of creating
                Descriptor::DHES => dh_branch!(s, re)
            }
        }

        let n = self.get_nonce();
        let a = concat_vec!(data[..off], self.h.0);
        let payload = match self.k {
            Some(ref k) =>
                try!(NoiseBody::read(&data[off..]).decrypt(&k, &n, &a[..])),
            None => data[off..].to_vec()
        };
        if descriptors.len() > 0 {
            self.h = sha512::hash(&concat_vec!(self.h.0, data)[..]);
        }

        Ok((prologue, payload))
    }
}

impl NoiseBody {
    pub fn read(buf: &[u8]) -> NoiseBody {
        NoiseBody {
            ciphertext: buf[..buf.len() - MAC_LEN].to_vec(),
            mac: poly1305::Tag(make_fixed!(u8, MAC_LEN, buf[buf.len() - MAC_LEN..]))
        }
    }

    pub fn write(&self) -> Vec<u8> {
        let mut out = self.ciphertext.clone();
        out.extend(self.mac.0.iter().cloned());
        out
    }

    pub fn encrypt(key: &chacha20::Key, nonce: &chacha20::Nonce, authtext: &[u8], plaintext: &[u8]) -> NoiseBody {
        let mut message = vec![0u8; 64];
        message.extend(plaintext.iter().cloned());

        let keystream = chacha20::stream_xor(&message[..], nonce, key);
        let mac_key = make_fixed!(u8, 32, keystream[..32]);
        // ignore 32..64
        let ciphertext = &keystream[64..];

        let mut to_be_authenticated = pad16(authtext);
        to_be_authenticated.extend(pad16(&ciphertext[..]).iter().cloned());
        to_be_authenticated.write_u64::<LittleEndian>(authtext.len() as u64).unwrap();
        to_be_authenticated.write_u64::<LittleEndian>(plaintext.len() as u64).unwrap();
        let mac = poly1305::authenticate(&to_be_authenticated[..], &poly1305::Key(mac_key));

        NoiseBody {
            ciphertext: ciphertext.to_vec(),
            mac: mac
        }
    }

    /* pub fn encrypt_padded(key: &chacha20::Key, nonce: &chacha20::Nonce, pad_len: usize, app_data: &[u8], authtext: &[u8]) -> NoiseBody {
        let mut plaintext = vec![];
        plaintext.extend(app_data.iter().cloned());
        for _ in 0..pad_len { plaintext.push(0); } // TODO: Random padding
        plaintext.write_u32::<LittleEndian>(pad_len as u32).unwrap();
        self.encrypt(&plaintext[..], authtext)
    }*/

    pub fn decrypt(&self, key: &chacha20::Key, nonce: &chacha20::Nonce, authtext: &[u8]) -> Result<Vec<u8>, ()> {
        let mut input = vec![0u8; 64];
        input.extend(self.ciphertext.iter().cloned());

        let keystream = chacha20::stream_xor(&input[..], nonce, key);
        let mac_key = make_fixed!(u8, 32, keystream[..32]);
        // ignore 32..64
        let plaintext = &keystream[64..];

        let mut to_be_authenticated = pad16(authtext);
        to_be_authenticated.extend(pad16(&self.ciphertext[..]).iter().cloned());
        to_be_authenticated.write_u64::<LittleEndian>(authtext.len() as u64).unwrap();
        to_be_authenticated.write_u64::<LittleEndian>(plaintext.len() as u64).unwrap();

        if poly1305::verify(&self.mac, &to_be_authenticated[..], &poly1305::Key(mac_key)) {
            Ok(plaintext.to_vec())
        } else {
            Err(())
        }
    }
}

#[test]
fn test_encrypt() {
    let key = chacha20::gen_key();
    let nonce = chacha20::gen_nonce();
    let input = "hello, world";
    let auth = "test";
    let body = NoiseBody::encrypt(&key, &nonce, auth.as_bytes(), input.as_bytes());
    let res = body.decrypt(&key, &nonce, auth.as_bytes());
    match res {
        Ok(v) => assert!(&v[..] == input.as_bytes()),
        Err(_) => assert!(false)
    }
}
<commit_msg>Use SHA256 as per spec<commit_after>use sodiumoxide::crypto::onetimeauth::poly1305;
use sodiumoxide::crypto::hash::sha256;
use sodiumoxide::crypto::scalarmult::curve25519;
use sodiumoxide::crypto::stream::chacha20;
use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305;
//use sodiumoxide::randombytes::randombytes;
use byteorder::{LittleEndian, WriteBytesExt};

macro_rules! make_fixed {
    ($t:ty, $n:expr, $v:expr) => ({
        let mut res : [$t; $n] = [0; $n];
        assert!($v.len() == $n);
        for i in 0..$n { res[i] = $v[i] }
        res
    })
}

macro_rules! concat_vec {
    ($x:expr, $($y:expr),+) => ({
        $x.iter() $(.chain($y.iter()))+ .cloned().collect::<Vec<u8>>()
    })
}

pub fn pad16(input: &[u8]) -> Vec<u8> {
    let mut out = input.iter().cloned().collect::<Vec<u8>>();
    for _ in (out.len() % 16)..16 {
        out.push(0);
    }
    out
}

pub const MAC_LEN: usize = 16;
pub const CV_LEN: usize = 48;
pub const H_LEN: usize = 64;
pub const DH_LEN: usize = 32;
// "Noise255" followed by 16 zeros
pub const SUITE_NAME: [u8; 24] = [0x4E, 0x6F, 0x69, 0x73, 0x65, 0x32, 0x35, 0x35,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

pub fn hmac_sha256(key: &[u8], message: &[u8]) -> sha256::Digest {
    let nkey = if key.len() > sha256::HASHBYTES {
        sha256::hash(key).0
    } else {
        let mut arr = [0u8; sha256::HASHBYTES];
        for i in 0..key.len() { arr[i] = key[i] }
        arr
    };
    let o_pad = nkey.iter().map(|x| x^0x5c).collect::<Vec<u8>>();
    let i_pad = nkey.iter().map(|x| x^0x36).collect::<Vec<u8>>();

    let in1 : sha256::Digest = sha256::hash(&concat_vec!(i_pad, message)[..]);
    sha256::hash(&concat_vec!(o_pad, in1.0)[..])
}

pub fn getkey(key: &chacha20::Key, nonce: &chacha20::Nonce) -> chacha20::Key {
    chacha20::Key(make_fixed!(u8, chacha20::KEYBYTES, chacha20::stream(chacha20::KEYBYTES, nonce, key)))
}

pub fn kdf(key: &chacha20::Key, nonce: &chacha20::Nonce, input: &[u8]) -> chacha20::Key {
    chacha20::Key(make_fixed!(u8, 32, hmac_sha256(&getkey(key, nonce).0[..], input).0[..32]))
}

pub fn dh(privkey: &[u8; DH_LEN], pubkey: &[u8; DH_LEN]) -> [u8; DH_LEN] {
    curve25519::scalarmult(&curve25519::Scalar(*privkey), &curve25519::GroupElement(*pubkey)).0
}

pub struct NoiseBody {
    ciphertext: Vec<u8>,
    mac: poly1305::Tag
}

#[derive(Clone)]
pub struct PubKey(pub [u8; DH_LEN]);
#[derive(Clone)]
pub struct PrivKey(pub [u8; DH_LEN]);

#[derive(Clone)]
pub struct KeyPair {
    pub pubkey: PubKey,
    pub privkey: PrivKey
}

pub struct Session {
    pub s: Option<KeyPair>,
    e: Option<KeyPair>,
    pub rs: Option<PubKey>,
    re: Option<PubKey>,
    pub k: Option<chacha20::Key>,
    pub n: u64,
    pub h: sha256::Digest
}

pub enum Descriptor {
    Ephemeral,
    Static,
    DHSS,
    DHEE,
    DHSE,
    DHES
}

pub fn gen_keypair() -> KeyPair {
    let bkp = curve25519xsalsa20poly1305::gen_keypair();
    KeyPair {
        pubkey: PubKey((bkp.0).0),
        privkey: PrivKey((bkp.1).0)
    }
}

impl Session {
    pub fn new(local: Option<KeyPair>, remote: Option<PubKey>) -> Session {
        Session {
            s: local,
            e: None,
            rs: remote,
            re: None,
            k: None,
            n: 0,
            h: sha256::Digest([0u8; 32])
        }
    }

    pub fn get_nonce(&mut self) -> chacha20::Nonce {
        let mut n = vec![];
        n.write_u64::<LittleEndian>(self.n).unwrap();
        self.n += 1;
        chacha20::Nonce::from_slice(&n[..]).unwrap()
    }

    pub fn derive(&mut self) -> Session {
        let n = self.get_nonce();
        Session {
            s: self.s.clone(),
            e: None,
            rs: self.rs.clone(),
            re: None,
            k: match self.k {
                Some(ref k) => {
                    Some(getkey(&k, &n))
                },
                None => None
            },
            n: 0,
            h: self.h.clone()
        }
    }

    fn session_dh(&mut self, sender: &PrivKey, receiver: &PubKey) {
        let n = self.get_nonce();
        let k = self.k.clone().unwrap_or(chacha20::Key([0; 32]));
        self.k = Some(kdf(&k, &n, &dh(&sender.0, &receiver.0)[..]));
    }

    pub fn create(&mut self, prologue: &[u8], descriptors: &[Descriptor], payload: &[u8]) -> Vec<u8> {
        assert!(prologue.len() < 256);
        let mut buf = vec![];
        buf.push(prologue.len() as u8);
        buf.extend(prologue.iter().cloned());

        macro_rules! dh_branch {
            ($a:ident, $b:ident) => ({
                let $a = self.$a.clone().unwrap().privkey;
                let $b = self.$b.clone().unwrap();
                self.session_dh(&$a, &$b)
            })
        }

        for d in descriptors.iter() {
            match *d {
                Descriptor::Ephemeral => {
                    self.e = Some(gen_keypair());
                    buf.extend(self.e.clone().unwrap().pubkey.0.iter().cloned())
                },
                Descriptor::Static => {
                    let k = self.k.clone().unwrap();
                    let n = self.get_nonce();
                    let s = self.s.clone().unwrap().pubkey.0;
                    let a = concat_vec!(buf, self.h.0);
                    buf.extend(NoiseBody::encrypt(&k, &n, &a[..], &s[..])
                               .write().iter().cloned());
                },
                Descriptor::DHSS => dh_branch!(s, rs),
                Descriptor::DHEE => dh_branch!(e, re),
                Descriptor::DHSE => dh_branch!(s, re),
                Descriptor::DHES => dh_branch!(e, rs)
            }
        }
        let n = self.get_nonce();
        let a = concat_vec!(buf, self.h.0);
        match self.k {
            Some(ref k) => {
                buf.extend(NoiseBody::encrypt(&k, &n, &a[..], payload).write().iter().cloned());
            }
            None => buf.extend(payload.iter().cloned())
        }
        if descriptors.len() > 0 {
            self.h = sha256::hash(&concat_vec!(self.h.0, buf)[..]);
        }

        buf
    }

    pub fn consume(&mut self, data: &[u8], descriptors: &[Descriptor])
                   -> Result<(Vec<u8>, Vec<u8>), ()> {
        assert!(data.len() > 0);
        let plen = data[0] as usize;
        let prologue = data[1..plen+1].to_vec();
        let mut off = plen + 1;

        macro_rules! dh_branch {
            ($a:ident, $b:ident) => ({
                let $a = self.$a.clone().unwrap().privkey;
                let $b = self.$b.clone().unwrap();
                self.session_dh(&$a, &$b)
            })
        }

        for d in descriptors.iter() {
            match *d {
                Descriptor::Ephemeral => {
                    self.re = Some(PubKey(make_fixed!(u8, DH_LEN, data[off..off+DH_LEN])));
                    off += DH_LEN;
                },
                Descriptor::Static => {
                    let k = self.k.clone().unwrap();
                    let n = self.get_nonce();
                    let a = concat_vec!(data[..off], self.h.0);
                    self.rs = Some(PubKey(make_fixed!(u8, DH_LEN, try!(NoiseBody::read(&data[off..off+DH_LEN+MAC_LEN])
                                                                       .decrypt(&k, &n, &a[..])))));
                    off += DH_LEN + MAC_LEN;
                },
                Descriptor::DHSS => dh_branch!(s, rs),
                Descriptor::DHEE => dh_branch!(e, re),
                Descriptor::DHSE => dh_branch!(e, rs), // reversed because consuming instead of creating
                Descriptor::DHES => dh_branch!(s, re)
            }
        }

        let n = self.get_nonce();
        let a = concat_vec!(data[..off], self.h.0);
        let payload = match self.k {
            Some(ref k) =>
                try!(NoiseBody::read(&data[off..]).decrypt(&k, &n, &a[..])),
            None => data[off..].to_vec()
        };
        if descriptors.len() > 0 {
            self.h = sha256::hash(&concat_vec!(self.h.0, data)[..]);
        }

        Ok((prologue, payload))
    }
}

impl NoiseBody {
    pub fn read(buf: &[u8]) -> NoiseBody {
        NoiseBody {
            ciphertext: buf[..buf.len() - MAC_LEN].to_vec(),
            mac: poly1305::Tag(make_fixed!(u8, MAC_LEN, buf[buf.len() - MAC_LEN..]))
        }
    }

    pub fn write(&self) -> Vec<u8> {
        let mut out = self.ciphertext.clone();
        out.extend(self.mac.0.iter().cloned());
        out
    }

    pub fn encrypt(key: &chacha20::Key, nonce: &chacha20::Nonce, authtext: &[u8], plaintext: &[u8]) -> NoiseBody {
        let mut message = vec![0u8; 64];
        message.extend(plaintext.iter().cloned());

        let keystream = chacha20::stream_xor(&message[..], nonce, key);
        let mac_key = make_fixed!(u8, 32, keystream[..32]);
        // ignore 32..64
        let ciphertext = &keystream[64..];

        let mut to_be_authenticated = pad16(authtext);
        to_be_authenticated.extend(pad16(&ciphertext[..]).iter().cloned());
        to_be_authenticated.write_u64::<LittleEndian>(authtext.len() as u64).unwrap();
        to_be_authenticated.write_u64::<LittleEndian>(plaintext.len() as u64).unwrap();
        let mac = poly1305::authenticate(&to_be_authenticated[..], &poly1305::Key(mac_key));

        NoiseBody {
            ciphertext: ciphertext.to_vec(),
            mac: mac
        }
    }

    /* pub fn encrypt_padded(key: &chacha20::Key, nonce: &chacha20::Nonce, pad_len: usize, app_data: &[u8], authtext: &[u8]) -> NoiseBody {
        let mut plaintext = vec![];
        plaintext.extend(app_data.iter().cloned());
        for _ in 0..pad_len { plaintext.push(0); } // TODO: Random padding
        plaintext.write_u32::<LittleEndian>(pad_len as u32).unwrap();
        self.encrypt(&plaintext[..], authtext)
    }*/

    pub fn decrypt(&self, key: &chacha20::Key, nonce: &chacha20::Nonce, authtext: &[u8]) -> Result<Vec<u8>, ()> {
        let mut input = vec![0u8; 64];
        input.extend(self.ciphertext.iter().cloned());

        let keystream = chacha20::stream_xor(&input[..], nonce, key);
        let mac_key = make_fixed!(u8, 32, keystream[..32]);
        // ignore 32..64
        let plaintext = &keystream[64..];

        let mut to_be_authenticated = pad16(authtext);
        to_be_authenticated.extend(pad16(&self.ciphertext[..]).iter().cloned());
        to_be_authenticated.write_u64::<LittleEndian>(authtext.len() as u64).unwrap();
        to_be_authenticated.write_u64::<LittleEndian>(plaintext.len() as u64).unwrap();

        if poly1305::verify(&self.mac, &to_be_authenticated[..], &poly1305::Key(mac_key)) {
            Ok(plaintext.to_vec())
        } else {
            Err(())
        }
    }
}

#[test]
fn test_encrypt() {
    let key = chacha20::gen_key();
    let nonce = chacha20::gen_nonce();
    let input = "hello, world";
    let auth = "test";
    let body = NoiseBody::encrypt(&key, &nonce, auth.as_bytes(), input.as_bytes());
    let res = body.decrypt(&key, &nonce, auth.as_bytes());
    match res {
        Ok(v) => assert!(&v[..] == input.as_bytes()),
        Err(_) => assert!(false)
    }
}
<|endoftext|>


<commit_before>use std::any::{AnyRefExt, AnyMutRefExt};
use std::collections::HashMap;
use std::fmt::Show;
use std::str;
use serialize::base64::{FromBase64, ToBase64, STANDARD};

use conduit::{Request, Response};
use conduit_middleware;
use cookie::Cookie;

use super::RequestCookies;

pub struct SessionMiddleware {
    cookie_name: String,
}

impl SessionMiddleware {
    pub fn new(cookie: &str) -> SessionMiddleware {
        SessionMiddleware { cookie_name: cookie.to_string() }
    }

    pub fn decode(&self, cookie: &Cookie) -> HashMap<String, String> {
        let mut ret = HashMap::new();
        println!("decoding: {}", cookie.value);
        let bytes = cookie.value.as_slice().from_base64().unwrap_or(Vec::new());
        let mut parts = bytes.as_slice().split(|&a| a == 0xff);
        loop {
            match (parts.next(), parts.next()) {
                (Some(key), Some(value)) => {
                    match (str::from_utf8(key), str::from_utf8(value)) {
                        (Some(key), Some(value)) => {
                            ret.insert(key.to_string(), value.to_string());
                        }
                        _ => {}
                    }
                }
                _ => break
            }
        }
        return ret;
    }

    pub fn encode(&self, h: &HashMap<String, String>) -> String {
        let mut ret = Vec::new();
        for (i, (k, v)) in h.iter().enumerate() {
            if i != 0 { ret.push(0xff) }
            ret.push_all(k.as_bytes());
            ret.push(0xff);
            ret.push_all(v.as_bytes());
        }
        ret.as_slice().to_base64(STANDARD)
    }
}

impl conduit_middleware::Middleware for SessionMiddleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show>> {
        let session = {
            let jar = req.cookies();
            jar.find(self.cookie_name.as_slice()).map(|cookie| {
                self.decode(cookie)
            }).unwrap_or_else(|| HashMap::new())
        };
        req.mut_extensions().insert("conduit.cookie.session", box session);
        Ok(())
    }

    fn after(&self, req: &mut Request, res: Result<Response, Box<Show>>)
        -> Result<Response, Box<Show>>
    {
        let session = req.mut_extensions().pop(&"conduit.cookie.session");
        let session = session.expect("session must be present after request");
        let session = session.as_ref::<HashMap<String, String>>().unwrap();
        let encoded = self.encode(session);
        req.cookies().add(Cookie::new(self.cookie_name.to_string(), encoded));
        return res;
    }
}

pub trait RequestSession<'a> {
    fn session(self) -> &'a mut HashMap<String, String>;
}

impl<'a> RequestSession<'a> for &'a mut Request {
    fn session(self) -> &'a mut HashMap<String, String> {
        self.mut_extensions().find_mut(&"conduit.cookie.session")
            .and_then(|a| a.as_mut::<HashMap<String, String>>())
            .expect("missing cookie session")
    }
}

#[cfg(test)]
mod test {

    use conduit::{Request, Response, Handler, Post};
    use conduit_middleware::MiddlewareBuilder;
    use test::MockRequest;
    use std::collections::HashMap;
    use std::io::MemReader;

    use {RequestSession, Middleware, SessionMiddleware};

    #[test]
    fn simple() {
        let mut req = MockRequest::new(Post, "/articles");

        // Set the session cookie
        let mut app = MiddlewareBuilder::new(set_session);
        app.add(Middleware::new());
        app.add(SessionMiddleware::new("lol"));
        let response = app.call(&mut req).ok().unwrap();

        let v = response.headers.get(&"Set-Cookie".to_string());
        assert!(v.as_slice()[0].as_slice().starts_with("lol"));

        // Use the session cookie
        req.header("Cookie", v.as_slice()[0].as_slice());
        let mut app = MiddlewareBuilder::new(use_session);
        app.add(Middleware::new());
        app.add(SessionMiddleware::new("lol"));
        assert!(app.call(&mut req).is_ok());

        fn set_session(req: &mut Request) -> Result<Response, String> {
            assert!(req.session().insert("foo".to_string(), "bar".to_string()));
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
        fn use_session(req: &mut Request) -> Result<Response, String> {
            assert_eq!(req.session().find_equiv(&"foo").unwrap().as_slice(),
                       "bar");
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
    }
}
<commit_msg>Removing println<commit_after>use std::any::{AnyRefExt, AnyMutRefExt};
use std::collections::HashMap;
use std::fmt::Show;
use std::str;
use serialize::base64::{FromBase64, ToBase64, STANDARD};

use conduit::{Request, Response};
use conduit_middleware;
use cookie::Cookie;

use super::RequestCookies;

pub struct SessionMiddleware {
    cookie_name: String,
}

impl SessionMiddleware {
    pub fn new(cookie: &str) -> SessionMiddleware {
        SessionMiddleware { cookie_name: cookie.to_string() }
    }

    pub fn decode(&self, cookie: &Cookie) -> HashMap<String, String> {
        let mut ret = HashMap::new();
        let bytes = cookie.value.as_slice().from_base64().unwrap_or(Vec::new());
        let mut parts = bytes.as_slice().split(|&a| a == 0xff);
        loop {
            match (parts.next(), parts.next()) {
                (Some(key), Some(value)) => {
                    match (str::from_utf8(key), str::from_utf8(value)) {
                        (Some(key), Some(value)) => {
                            ret.insert(key.to_string(), value.to_string());
                        }
                        _ => {}
                    }
                }
                _ => break
            }
        }
        return ret;
    }

    pub fn encode(&self, h: &HashMap<String, String>) -> String {
        let mut ret = Vec::new();
        for (i, (k, v)) in h.iter().enumerate() {
            if i != 0 { ret.push(0xff) }
            ret.push_all(k.as_bytes());
            ret.push(0xff);
            ret.push_all(v.as_bytes());
        }
        ret.as_slice().to_base64(STANDARD)
    }
}

impl conduit_middleware::Middleware for SessionMiddleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show>> {
        let session = {
            let jar = req.cookies();
            jar.find(self.cookie_name.as_slice()).map(|cookie| {
                self.decode(cookie)
            }).unwrap_or_else(|| HashMap::new())
        };
        req.mut_extensions().insert("conduit.cookie.session", box session);
        Ok(())
    }

    fn after(&self, req: &mut Request, res: Result<Response, Box<Show>>)
        -> Result<Response, Box<Show>>
    {
        let session = req.mut_extensions().pop(&"conduit.cookie.session");
        let session = session.expect("session must be present after request");
        let session = session.as_ref::<HashMap<String, String>>().unwrap();
        let encoded = self.encode(session);
        req.cookies().add(Cookie::new(self.cookie_name.to_string(), encoded));
        return res;
    }
}

pub trait RequestSession<'a> {
    fn session(self) -> &'a mut HashMap<String, String>;
}

impl<'a> RequestSession<'a> for &'a mut Request {
    fn session(self) -> &'a mut HashMap<String, String> {
        self.mut_extensions().find_mut(&"conduit.cookie.session")
            .and_then(|a| a.as_mut::<HashMap<String, String>>())
            .expect("missing cookie session")
    }
}

#[cfg(test)]
mod test {

    use conduit::{Request, Response, Handler, Post};
    use conduit_middleware::MiddlewareBuilder;
    use test::MockRequest;
    use std::collections::HashMap;
    use std::io::MemReader;

    use {RequestSession, Middleware, SessionMiddleware};

    #[test]
    fn simple() {
        let mut req = MockRequest::new(Post, "/articles");

        // Set the session cookie
        let mut app = MiddlewareBuilder::new(set_session);
        app.add(Middleware::new());
        app.add(SessionMiddleware::new("lol"));
        let response = app.call(&mut req).ok().unwrap();

        let v = response.headers.get(&"Set-Cookie".to_string());
        assert!(v.as_slice()[0].as_slice().starts_with("lol"));

        // Use the session cookie
        req.header("Cookie", v.as_slice()[0].as_slice());
        let mut app = MiddlewareBuilder::new(use_session);
        app.add(Middleware::new());
        app.add(SessionMiddleware::new("lol"));
        assert!(app.call(&mut req).is_ok());

        fn set_session(req: &mut Request) -> Result<Response, String> {
            assert!(req.session().insert("foo".to_string(), "bar".to_string()));
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
        fn use_session(req: &mut Request) -> Result<Response, String> {
            assert_eq!(req.session().find_equiv(&"foo").unwrap().as_slice(),
                       "bar");
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

use std::str::from_utf8;
use std::thread;
use std::time::Duration;

use rustc_serialize::json;
use curl::http;

pub const SESSION_TTL: &'static str = "15s";

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct SessionCreate {
    Name: String,
    TTL: String
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct SessionID {
    ID: String
}

pub struct Session {
    endpoint: String
}

impl Session {
    pub fn new(address: &str) ->  Session {
        Session {
            endpoint: format!("http://{}/v1/session", address)
        }
    }

    pub fn create(&self, name: String) -> Option<String> {
        let url = format!("{}/create", self.endpoint);
        let session = SessionCreate {
            Name: name,
            TTL: self::SESSION_TTL.to_owned()
        };
        let json_str = json::encode(&session).unwrap();

        let resp = http::handle()
            .put(url, &json_str)
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Consul: Error creating a session! Response: {}", resp);
        }
        let result = from_utf8(resp.get_body()).unwrap();
        let json_data = match json::Json::from_str(result) {
            Ok(value) => value,
            Err(err) => panic!("consul: Could not convert to json: {:?}. Err: {}", result, err)
        };
        super::get_string(&json_data, &["ID"])
    }

    pub fn renew(&self, session_id: &String) -> bool {
        for _ in 0..10 {
            let url = format!("{}/renew/{}", self.endpoint, session_id);
            let resp = http::handle()
                .put(url, "")
                .content_type("application/json")
                .exec().unwrap();
            if resp.get_code() != 200 {
                println!("Could not renew session: {}, returned HTTP code: {:?}. Sleeping for 2 seconds", session_id, resp.get_code());
                thread::sleep(Duration::from_millis(2000u64));
            }
            else {
                return true;
            }
        }
        false
    }

    pub fn end(&self, session_id: &String) {
        let url = format!("{}/destroy/{}", self.endpoint, session_id);
        let resp = http::handle()
            .put(url, "")
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Cound not destroy session: {}", session_id);
        }

    }

}
<commit_msg>Retry session renewal 10 times<commit_after>#![allow(non_snake_case)]

use std::str::from_utf8;
use std::thread;
use std::time::Duration;

use rustc_serialize::json;
use curl::http;

pub const SESSION_TTL: &'static str = "15s";

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct SessionCreate {
    Name: String,
    TTL: String
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct SessionID {
    ID: String
}

pub struct Session {
    endpoint: String
}

impl Session {
    pub fn new(address: &str) ->  Session {
        Session {
            endpoint: format!("http://{}/v1/session", address)
        }
    }

    pub fn create(&self, name: String) -> Option<String> {
        let url = format!("{}/create", self.endpoint);
        let session = SessionCreate {
            Name: name,
            TTL: self::SESSION_TTL.to_owned()
        };
        let json_str = json::encode(&session).unwrap();

        let resp = http::handle()
            .put(url, &json_str)
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Consul: Error creating a session! Response: {}", resp);
        }
        let result = from_utf8(resp.get_body()).unwrap();
        let json_data = match json::Json::from_str(result) {
            Ok(value) => value,
            Err(err) => panic!("consul: Could not convert to json: {:?}. Err: {}", result, err)
        };
        super::get_string(&json_data, &["ID"])
    }

    pub fn renew(&self, session_id: &String) -> bool {
        for _ in 0..10 {
            let url = format!("{}/renew/{}", self.endpoint, session_id);
            let resp = http::handle()
                .put(url, "")
                .content_type("application/json")
                .exec().unwrap();
            if resp.get_code() != 200 {
                println!("Could not renew session: {}, returned HTTP code: {:?}. Sleeping for 2 seconds", session_id, resp.get_code());
                thread::sleep(Duration::from_millis(2000u64));
            }
            else {
                return true;
            }
        }
        panic!("Could not renew session: {} after 10 tries.", session_id);
        false
    }

    pub fn end(&self, session_id: &String) {
        let url = format!("{}/destroy/{}", self.endpoint, session_id);
        let resp = http::handle()
            .put(url, "")
            .content_type("application/json")
            .exec().unwrap();
        if resp.get_code() != 200 {
            panic!("Cound not destroy session: {}", session_id);
        }

    }

}
<|endoftext|>


<commit_before>/// Basic sorting algorithms, just for fun.

#[warn(non_camel_case_types)]
#[warn(non_snake_case)]
#[warn(unused_qualifications)]
#[warn(non_upper_case_globals)]
#[warn(missing_docs)]

use std;

fn choose_pivot<T : Ord>(slice : &[T]) -> uint {
	// if slice.len() <= 2 {return slice.len() - 1;};
	let (mut ismall, imid, mut ibig) = (0, slice.len() / 2, slice.len() - 1);
	if slice[ibig] < slice[ismall] {std::mem::swap(&mut ibig, &mut ismall);}
	if slice[imid] <= slice[ismall] {ismall}
	else if slice[ibig] <= slice[imid] {ibig}
	else{imid}
}

/// choose a pivot, then reorder so that everything to the left of the pivot is smaller, and
/// everything to the right is greater
/// Assumes slice.len() > 2
fn partition<T : Ord>(slice : &mut [T], pivot : uint) -> uint {
	let mut pivot = pivot;
	let mxix = slice.len() - 1;
	let (mut left, mut right) = (0, mxix);
	while left + 1 < right {
		let mut retry = false;
		if slice[left] < slice[pivot] {left += 1; retry = true;}
		if slice[right] > slice[pivot] {right -= 1; retry = true;}
		if left == pivot {left += 1; retry == true;}
		if right == pivot {right -= 1; retry == true;}
		if retry {continue;}

		slice.swap(left, right);
	}

	if pivot < left && pivot < right && slice[left] < slice[pivot] {slice.swap(left, pivot); pivot = left;}
	else if pivot > right && pivot > left && slice[right] > slice[pivot] {slice.swap(right, pivot); pivot = right;};

	return pivot;
}

/// The quicksort algorithm, for sorting an array.
pub fn quicksort<T : Ord>(slice : &mut [T]){
	if slice.len() <= 1 {return;}
	else if slice.len() == 2 {
		if slice[0] >= slice[1] {slice.swap(0,1);}
		return;
	}

	let pivot = choose_pivot(slice);
	let pivot = partition(slice, pivot);
	let (left_slice, right_slice) = slice.split_at_mut(pivot);
	// left_slice is [0 - pivot-1], right_slice is [pivot, end]. We don't want to include the
	// pivot, so reassign right_slice
	let right_slice = right_slice.tail_mut();

	quicksort(left_slice);
	quicksort(right_slice);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Quicksort tests
#[test]
fn test_partition() {
	let tests : &mut [uint] = [1u,2,3];
	let result : &mut [uint] = [1,2,3];
	let p = partition(tests, 1);
	assert_eq!(&tests, &result);
	assert_eq!(p, 1);
	let p = partition(tests, 0);
	assert_eq!(&tests, &result);
	assert_eq!(p, 0);
	let p = partition(tests, 2);
	assert_eq!(&tests, &result);
	assert_eq!(p, 2);

	let tests : &mut [uint] = [1u,3,2];
	let p = partition(tests, 1);
	let result : &mut [uint] = [1,2,3];
	assert_eq!(&tests, &result);
	assert_eq!(p, 2);

	let tests : &mut [uint] = [1u,3,2];
	let p = partition(tests, 0);
	let result : &mut [uint] = [1,3,2];
	assert_eq!(&tests, &result);
	assert_eq!(p, 0);

	let tests : &mut [uint] = [1u,3,2];
	let p = partition(tests, 2);
	let result : &mut [uint] = [1,2,3];
	assert_eq!(&tests, &result);
	assert_eq!(p, 1);
}

/// Test if a slice is in a sorted state.
pub fn is_sorted<T : Ord>(slice: &[T]) -> bool {
	for win in slice.windows(2){
		match win {
			[ref a, ref b] if a < b => continue,
			[_, _] => return false,
			_ => panic!("slice.windows(2) returned a window with size {} != 2", win.len())
		}
	}
	true
}

#[cfg(test)]
fn get_test_vecs() -> Vec<Vec<uint>> {
	vec!(
		vec!(), vec!(1), vec!(1,2), vec!(2,1), vec!(1,2,3), vec!(2,1,3), vec!(3,1,2),
		vec!(8,5,2,6,9,3), vec!(2,3,5,6,8,9), vec!(9,8,6,5,3,2)
	)
}

#[test]
fn test_quicksort(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let test_slice = test_vec.as_mut_slice();
		quicksort(test_slice);
		assert!(is_sorted(test_slice));
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Heapsort

/// Index of parent node
#[inline]
fn get_parent(ix : uint) -> uint {
	(ix+1) / 2 - 1
}

/// Index of leaf nodes
#[inline]
fn get_leaves(ix : uint) -> (uint, uint) {
	(ix*2 + 1, ix*2+2)
}

/// Turn the array into a maximal heap
pub fn heapify<T : Ord>(slice : &mut [T]){
	for ix in range(1, slice.len()){
		let mut curix = ix;
		while curix > 0 {
			let pix = get_parent(curix);
			if slice[pix] > slice[curix] {break;}

			slice.swap(pix, curix);
			curix = pix;
		}
	}
}

/// Assuming our slice is a heap, take the maximal element (element 0), swap it to the end,
/// take that end-element / now root and filter it down the heap until its in the right place.
/// At the end of this function, the max element is at the end, and elements 0 to (end-1) are a heap
/// again.
fn heap_pop<T : Ord>(slice : &mut [T]){
	if slice.len() <= 1 {return;}
	let mxix = slice.len() - 2; // last index in the new heap
	slice.swap(0, mxix+1);

	// Now we filter downwards.
	let mut curix = 0;
	loop {
		let (l,r) = get_leaves(curix);
		if l > mxix {
			// we reached the bottom, there are no more leaves.
			break;
		}
		let switch_ix = if (r > mxix) || (slice[l] > slice[r]) {l} else {r};
		if slice[curix] >= slice[switch_ix] {break;}
		slice.swap(curix, switch_ix);
		curix = switch_ix;
	}
}

/// Turn a heap-array into a sorted array
pub fn heap_to_sorted<T : Ord>(slice : &mut [T]){
	//~ let mut portion = slice;
	//~ while portion.len() > 1 {
		//~ heap_pop(portion);
		//~ portion = portion.init_mut();
	//~ }

	let ln = slice.len();
	if ln <= 1 {return;}
	for i in range(0, ln - 1){
		let portion = slice.slice_to_mut(ln - i);
		heap_pop(portion);
	}
}

/// The heapsort algorithm.
/// This turns the array into an in-place binary max heap, then uses that to sort the list.
pub fn heapsort<T : Ord>(slice : &mut [T]){
	heapify(slice);
	heap_to_sorted(slice);
}

#[test]
fn test_indexing(){
	assert_eq!(get_parent(1), 0);
	assert_eq!(get_parent(2), 0);
	assert_eq!(get_parent(3), 1);
	assert_eq!(get_parent(4), 1);
	assert_eq!(get_parent(5), 2);
	assert_eq!(get_parent(6), 2);
	assert_eq!(get_parent(7), 3);

	for i in range(0, 21){
		let (l, r) = get_leaves(i);
		assert_eq!(get_parent(l), i);
		assert_eq!(get_parent(r), i);
	}
}

#[cfg(test)]
fn is_max_heap<T : Ord>(slice : &[T]) -> bool{
	for i in range(1, slice.len()){
		let p = get_parent(i);
		if slice[p] < slice[i] {return false;}
	}
	return true;
}

#[test]
fn test_heapify(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let unsorted_vec = test_vec.clone();
		let test_slice = test_vec.as_mut_slice();
		heapify(test_slice);
		println!("Heapifying: {} -> {}", unsorted_vec.as_slice(), test_slice)
		assert!(is_max_heap(test_slice));
	}
}

#[test]
fn test_heapsort(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let test_slice = test_vec.as_mut_slice();
		heapsort(test_slice);
		assert!(is_sorted(test_slice));
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Merge Sort

/// Merge two sorted arrays into a single vector
pub fn merge<T : Ord + Clone>(slice1 : &[T], slice2 : &[T]) -> Vec<T> {
	let mut vec = Vec::with_capacity(slice1.len() + slice2.len());

	let (mut it1, mut it2) = (slice1.iter().peekable(), slice2.iter().peekable());

	loop {
		let push_v = match (it1.peek(), it2.peek()) {
			(None, None) => break,
			(Some(&v), None) => {it1.next(); v.clone()},
			(Some(&v1), Some(&v2)) if v1 <= v2 => {it1.next(); v1.clone()},
			(_, Some(&v)) => {it2.next(); v.clone()}
		};
		vec.push(push_v);
	}
	return vec;
}

//~ /// Merge two sorted arrays into a single vector
//~ pub fn merge_into<T : Ord + Clone>(slice1 : &[T], slice2 : &[T], into :&mut [T]) {
	//~ assert!(slice1.len() + slice2.len() == into.len());
	//~
	//~ let (mut it1, mut it2) = (slice1.iter().peekable(), slice2.iter().peekable());
	//~
	//~ for v in into.iter_mut() {
		//~ let push_v = match (it1.peek(), it2.peek()) {
			//~ (None, None) => panic!("This should never happen!"),
			//~ (Some(&v), None) => {it1.next(); v.clone()},
			//~ (Some(&v1), Some(&v2)) if v1 <= v2 => {it1.next(); v1.clone()},
			//~ (_, Some(&v)) => {it2.next(); v.clone()}
		//~ };
		//~ *v = push_v;
	//~ }
//~ }

pub fn mergesort<T : Ord + Clone>(slice : &[T]) -> Vec<T> {
	match slice {
		[] => {return vec!();},
		[ref v] => {return vec!(v.clone());},
		_ => {}
	}
	let (s1, s2) = slice.split_at(slice.len() / 2);
	let v1 = mergesort(s1);
	let v2 = mergesort(s2);

	merge(v1.as_slice(), v2.as_slice())
}

#[test]
fn test_merge(){
	let (test_slice1, test_slice2) : (&[uint], &[uint]) = ([], []);
	assert_eq!(merge(test_slice1, test_slice2), vec!());

	let test_slice3 = [1,2,4,5];
	assert_eq!(merge(test_slice1, test_slice3), vec!(1,2,4,5));
	assert_eq!(merge(test_slice3, test_slice1), vec!(1,2,4,5));
	assert_eq!(merge(test_slice3, test_slice3), vec!(1,1,2,2,4,4,5,5));

	let test_slice4 = [3];
	assert_eq!(merge(test_slice3, test_slice4), vec!(1,2,3,4,5));
	assert_eq!(merge(test_slice4, test_slice3), vec!(1,2,3,4,5));
}

#[test]
fn test_mergesort(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let test_slice = test_vec.as_mut_slice();
		let v = mergesort(test_slice);
		assert!(is_sorted(v.as_slice()));
	}
}
<commit_msg>Added bubblesort<commit_after>/// Basic sorting algorithms, just for fun.

#[warn(non_camel_case_types)]
#[warn(non_snake_case)]
#[warn(unused_qualifications)]
#[warn(non_upper_case_globals)]
#[warn(missing_docs)]

use std;

fn choose_pivot<T : Ord>(slice : &[T]) -> uint {
	// if slice.len() <= 2 {return slice.len() - 1;};
	let (mut ismall, imid, mut ibig) = (0, slice.len() / 2, slice.len() - 1);
	if slice[ibig] < slice[ismall] {std::mem::swap(&mut ibig, &mut ismall);}
	if slice[imid] <= slice[ismall] {ismall}
	else if slice[ibig] <= slice[imid] {ibig}
	else{imid}
}

/// choose a pivot, then reorder so that everything to the left of the pivot is smaller, and
/// everything to the right is greater
/// Assumes slice.len() > 2
fn partition<T : Ord>(slice : &mut [T], pivot : uint) -> uint {
	let mut pivot = pivot;
	let mxix = slice.len() - 1;
	let (mut left, mut right) = (0, mxix);
	while left + 1 < right {
		let mut retry = false;
		if slice[left] < slice[pivot] {left += 1; retry = true;}
		if slice[right] > slice[pivot] {right -= 1; retry = true;}
		if left == pivot {left += 1; retry == true;}
		if right == pivot {right -= 1; retry == true;}
		if retry {continue;}

		slice.swap(left, right);
	}

	if pivot < left && pivot < right && slice[left] < slice[pivot] {slice.swap(left, pivot); pivot = left;}
	else if pivot > right && pivot > left && slice[right] > slice[pivot] {slice.swap(right, pivot); pivot = right;};

	return pivot;
}

/// The quicksort algorithm, for sorting an array.
pub fn quicksort<T : Ord>(slice : &mut [T]){
	if slice.len() <= 1 {return;}
	else if slice.len() == 2 {
		if slice[0] >= slice[1] {slice.swap(0,1);}
		return;
	}

	let pivot = choose_pivot(slice);
	let pivot = partition(slice, pivot);
	let (left_slice, right_slice) = slice.split_at_mut(pivot);
	// left_slice is [0 - pivot-1], right_slice is [pivot, end]. We don't want to include the
	// pivot, so reassign right_slice
	let right_slice = right_slice.tail_mut();

	quicksort(left_slice);
	quicksort(right_slice);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Quicksort tests
#[test]
fn test_partition() {
	let tests : &mut [uint] = [1u,2,3];
	let result : &mut [uint] = [1,2,3];
	let p = partition(tests, 1);
	assert_eq!(&tests, &result);
	assert_eq!(p, 1);
	let p = partition(tests, 0);
	assert_eq!(&tests, &result);
	assert_eq!(p, 0);
	let p = partition(tests, 2);
	assert_eq!(&tests, &result);
	assert_eq!(p, 2);

	let tests : &mut [uint] = [1u,3,2];
	let p = partition(tests, 1);
	let result : &mut [uint] = [1,2,3];
	assert_eq!(&tests, &result);
	assert_eq!(p, 2);

	let tests : &mut [uint] = [1u,3,2];
	let p = partition(tests, 0);
	let result : &mut [uint] = [1,3,2];
	assert_eq!(&tests, &result);
	assert_eq!(p, 0);

	let tests : &mut [uint] = [1u,3,2];
	let p = partition(tests, 2);
	let result : &mut [uint] = [1,2,3];
	assert_eq!(&tests, &result);
	assert_eq!(p, 1);
}

/// Test if a slice is in a sorted state.
pub fn is_sorted<T : Ord>(slice: &[T]) -> bool {
	for win in slice.windows(2){
		match win {
			[ref a, ref b] if a < b => continue,
			[_, _] => return false,
			_ => panic!("slice.windows(2) returned a window with size {} != 2", win.len())
		}
	}
	true
}

#[cfg(test)]
fn get_test_vecs() -> Vec<Vec<uint>> {
	vec!(
		vec!(), vec!(1), vec!(1,2), vec!(2,1), vec!(1,2,3), vec!(2,1,3), vec!(3,1,2),
		vec!(8,5,2,6,9,3), vec!(2,3,5,6,8,9), vec!(9,8,6,5,3,2)
	)
}

#[test]
fn test_quicksort(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let test_slice = test_vec.as_mut_slice();
		quicksort(test_slice);
		assert!(is_sorted(test_slice));
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Heapsort

/// Index of parent node
#[inline]
fn get_parent(ix : uint) -> uint {
	(ix+1) / 2 - 1
}

/// Index of leaf nodes
#[inline]
fn get_leaves(ix : uint) -> (uint, uint) {
	(ix*2 + 1, ix*2+2)
}

/// Turn the array into a maximal heap
pub fn heapify<T : Ord>(slice : &mut [T]){
	for ix in range(1, slice.len()){
		let mut curix = ix;
		while curix > 0 {
			let pix = get_parent(curix);
			if slice[pix] > slice[curix] {break;}

			slice.swap(pix, curix);
			curix = pix;
		}
	}
}

/// Assuming our slice is a heap, take the maximal element (element 0), swap it to the end,
/// take that end-element / now root and filter it down the heap until its in the right place.
/// At the end of this function, the max element is at the end, and elements 0 to (end-1) are a heap
/// again.
fn heap_pop<T : Ord>(slice : &mut [T]){
	if slice.len() <= 1 {return;}
	let mxix = slice.len() - 2; // last index in the new heap
	slice.swap(0, mxix+1);

	// Now we filter downwards.
	let mut curix = 0;
	loop {
		let (l,r) = get_leaves(curix);
		if l > mxix {
			// we reached the bottom, there are no more leaves.
			break;
		}
		let switch_ix = if (r > mxix) || (slice[l] > slice[r]) {l} else {r};
		if slice[curix] >= slice[switch_ix] {break;}
		slice.swap(curix, switch_ix);
		curix = switch_ix;
	}
}

/// Turn a heap-array into a sorted array
pub fn heap_to_sorted<T : Ord>(slice : &mut [T]){
	//~ let mut portion = slice;
	//~ while portion.len() > 1 {
		//~ heap_pop(portion);
		//~ portion = portion.init_mut();
	//~ }

	let ln = slice.len();
	if ln <= 1 {return;}
	for i in range(0, ln - 1){
		let portion = slice.slice_to_mut(ln - i);
		heap_pop(portion);
	}
}

/// The heapsort algorithm.
/// This turns the array into an in-place binary max heap, then uses that to sort the list.
pub fn heapsort<T : Ord>(slice : &mut [T]){
	heapify(slice);
	heap_to_sorted(slice);
}

#[test]
fn test_indexing(){
	assert_eq!(get_parent(1), 0);
	assert_eq!(get_parent(2), 0);
	assert_eq!(get_parent(3), 1);
	assert_eq!(get_parent(4), 1);
	assert_eq!(get_parent(5), 2);
	assert_eq!(get_parent(6), 2);
	assert_eq!(get_parent(7), 3);

	for i in range(0, 21){
		let (l, r) = get_leaves(i);
		assert_eq!(get_parent(l), i);
		assert_eq!(get_parent(r), i);
	}
}

#[cfg(test)]
fn is_max_heap<T : Ord>(slice : &[T]) -> bool{
	for i in range(1, slice.len()){
		let p = get_parent(i);
		if slice[p] < slice[i] {return false;}
	}
	return true;
}

#[test]
fn test_heapify(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let unsorted_vec = test_vec.clone();
		let test_slice = test_vec.as_mut_slice();
		heapify(test_slice);
		println!("Heapifying: {} -> {}", unsorted_vec.as_slice(), test_slice)
		assert!(is_max_heap(test_slice));
	}
}

#[test]
fn test_heapsort(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let test_slice = test_vec.as_mut_slice();
		heapsort(test_slice);
		assert!(is_sorted(test_slice));
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Merge Sort

/// Merge two sorted arrays into a single vector
pub fn merge<T : Ord + Clone>(slice1 : &[T], slice2 : &[T]) -> Vec<T> {
	let mut vec = Vec::with_capacity(slice1.len() + slice2.len());

	let (mut it1, mut it2) = (slice1.iter().peekable(), slice2.iter().peekable());

	loop {
		let push_v = match (it1.peek(), it2.peek()) {
			(None, None) => break,
			(Some(&v), None) => {it1.next(); v.clone()},
			(Some(&v1), Some(&v2)) if v1 <= v2 => {it1.next(); v1.clone()},
			(_, Some(&v)) => {it2.next(); v.clone()}
		};
		vec.push(push_v);
	}
	return vec;
}

//~ /// Merge two sorted arrays into a single vector
//~ pub fn merge_into<T : Ord + Clone>(slice1 : &[T], slice2 : &[T], into :&mut [T]) {
	//~ assert!(slice1.len() + slice2.len() == into.len());
	//~
	//~ let (mut it1, mut it2) = (slice1.iter().peekable(), slice2.iter().peekable());
	//~
	//~ for v in into.iter_mut() {
		//~ let push_v = match (it1.peek(), it2.peek()) {
			//~ (None, None) => panic!("This should never happen!"),
			//~ (Some(&v), None) => {it1.next(); v.clone()},
			//~ (Some(&v1), Some(&v2)) if v1 <= v2 => {it1.next(); v1.clone()},
			//~ (_, Some(&v)) => {it2.next(); v.clone()}
		//~ };
		//~ *v = push_v;
	//~ }
//~ }

pub fn mergesort<T : Ord + Clone>(slice : &[T]) -> Vec<T> {
	match slice {
		[] => {return vec!();},
		[ref v] => {return vec!(v.clone());},
		_ => {}
	}
	let (s1, s2) = slice.split_at(slice.len() / 2);
	let v1 = mergesort(s1);
	let v2 = mergesort(s2);

	merge(v1.as_slice(), v2.as_slice())
}

#[test]
fn test_merge(){
	let (test_slice1, test_slice2) : (&[uint], &[uint]) = ([], []);
	assert_eq!(merge(test_slice1, test_slice2), vec!());

	let test_slice3 = [1,2,4,5];
	assert_eq!(merge(test_slice1, test_slice3), vec!(1,2,4,5));
	assert_eq!(merge(test_slice3, test_slice1), vec!(1,2,4,5));
	assert_eq!(merge(test_slice3, test_slice3), vec!(1,1,2,2,4,4,5,5));

	let test_slice4 = [3];
	assert_eq!(merge(test_slice3, test_slice4), vec!(1,2,3,4,5));
	assert_eq!(merge(test_slice4, test_slice3), vec!(1,2,3,4,5));
}

#[test]
fn test_mergesort(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let test_slice = test_vec.as_mut_slice();
		let v = mergesort(test_slice);
		assert!(is_sorted(v.as_slice()));
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Bubblesort

/// The bubblesort algorithm.
pub fn bubblesort<T : Ord>(slice : &mut [T]){
	for n in std::iter::range_step(slice.len() as int, 1i, -1i){
		for m in range(1, n as uint){
			if slice[m] < slice[m-1] {slice.swap(m, m-1);}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Bubblesort Tests

#[test]
fn test_bubblesort(){
	let mut test_slices = get_test_vecs();

	for test_vec in test_slices.iter_mut(){
		let test_slice = test_vec.as_mut_slice();
		bubblesort(test_slice);
		assert!(is_sorted(test_slice));
	}
}
<|endoftext|>