<commit_before>//! This module contains code to equate the input/output types appearing
//! in the MIR with the expected input/output types from the function
//! signature. This requires a bit of processing, as the expected types
//! are supplied to us before normalization and may contain opaque
//! `impl Trait` instances. In contrast, the input/output types found in
//! the MIR (specifically, in the special local variables for the
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).

use rustc::mir::*;
use rustc::ty::Ty;
use rustc_infer::infer::LateBoundRegionConversionTime;

use rustc_index::vec::Idx;
use rustc_span::Span;

use crate::borrow_check::universal_regions::UniversalRegions;

use super::{Locations, TypeChecker};

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
    pub(super) fn equate_inputs_and_outputs(
        &mut self,
        body: &Body<'tcx>,
        universal_regions: &UniversalRegions<'tcx>,
        normalized_inputs_and_output: &[Ty<'tcx>],
    ) {
        let (&normalized_output_ty, normalized_input_tys) =
            normalized_inputs_and_output.split_last().unwrap();

        // If the user explicitly annotated the input types, extract
        // those.
        //
        // e.g., `|x: FxHashMap<_, &'static u32>| ...`
        let user_provided_sig;
        if !self.tcx().is_closure(self.mir_def_id) {
            user_provided_sig = None;
        } else {
            let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id);
            user_provided_sig = match typeck_tables.user_provided_sigs.get(&self.mir_def_id) {
                None => None,
                Some(user_provided_poly_sig) => {
                    // Instantiate the canonicalized variables from
                    // user-provided signature (e.g., the `_` in the code
                    // above) with fresh variables.
                    let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
                        body.span,
                        &user_provided_poly_sig,
                    );

                    // Replace the bound items in the fn sig with fresh
                    // variables, so that they represent the view from
                    // "inside" the closure.
                    Some(
                        self.infcx
                            .replace_bound_vars_with_fresh_vars(
                                body.span,
                                LateBoundRegionConversionTime::FnCall,
                                &poly_sig,
                            )
                            .0,
                    )
                }
            }
        };

        // Equate expected input tys with those in the MIR.
        for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) {
            // In MIR, argument N is stored in local N+1.
            let local = Local::new(argument_index + 1);

            debug!("equate_inputs_and_outputs: normalized_input_ty = {:?}", normalized_input_ty);

            let mir_input_ty = body.local_decls[local].ty;
            let mir_input_span = body.local_decls[local].source_info.span;
            self.equate_normalized_input_or_output(
                normalized_input_ty,
                mir_input_ty,
                mir_input_span,
            );
        }

        if let Some(user_provided_sig) = user_provided_sig {
            for (&user_provided_input_ty, argument_index) in
                user_provided_sig.inputs().iter().zip(0..)
            {
                // In MIR, closures begin an implicit `self`, so
                // argument N is stored in local N+2.
                let local = Local::new(argument_index + 2);
                let mir_input_ty = body.local_decls[local].ty;
                let mir_input_span = body.local_decls[local].source_info.span;

                // If the user explicitly annotated the input types, enforce those.
                let user_provided_input_ty =
                    self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
                self.equate_normalized_input_or_output(
                    user_provided_input_ty,
                    mir_input_ty,
                    mir_input_span,
                );
            }
        }

        assert!(
            body.yield_ty.is_some() && universal_regions.yield_ty.is_some()
                || body.yield_ty.is_none() && universal_regions.yield_ty.is_none()
        );
        if let Some(mir_yield_ty) = body.yield_ty {
            let ur_yield_ty = universal_regions.yield_ty.unwrap();
            let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
            self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
        }

        // Return types are a bit more complex. They may contain opaque `impl Trait` types.
        let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
        let output_span = body.local_decls[RETURN_PLACE].source_info.span;
        if let Err(terr) = self.eq_opaque_type_and_type(
            mir_output_ty,
            normalized_output_ty,
            self.mir_def_id,
            Locations::All(output_span),
            ConstraintCategory::BoringNoLocation,
        ) {
            span_mirbug!(
                self,
                Location::START,
                "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                normalized_output_ty,
                mir_output_ty,
                terr
            );
        };

        // If the user explicitly annotated the output types, enforce those.
        // Note that this only happens for closures.
        if let Some(user_provided_sig) = user_provided_sig {
            let user_provided_output_ty = user_provided_sig.output();
            let user_provided_output_ty =
                self.normalize(user_provided_output_ty, Locations::All(output_span));
            if let Err(err) = self.eq_opaque_type_and_type(
                mir_output_ty,
                user_provided_output_ty,
                self.mir_def_id,
                Locations::All(output_span),
                ConstraintCategory::BoringNoLocation,
            ) {
                span_mirbug!(
                    self,
                    Location::START,
                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                    mir_output_ty,
                    user_provided_output_ty,
                    err
                );
            }
        }
    }

    fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
        debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);

        if let Err(terr) =
            self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
        {
            span_mirbug!(
                self,
                Location::START,
                "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
                a,
                b,
                terr
            );
        }
    }
}
<commit_msg>Improve debug log in MIR type check<commit_after>//! This module contains code to equate the input/output types appearing
//! in the MIR with the expected input/output types from the function
//! signature. This requires a bit of processing, as the expected types
//! are supplied to us before normalization and may contain opaque
//! `impl Trait` instances. In contrast, the input/output types found in
//! the MIR (specifically, in the special local variables for the
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).

use rustc::mir::*;
use rustc::ty::Ty;
use rustc_infer::infer::LateBoundRegionConversionTime;

use rustc_index::vec::Idx;
use rustc_span::Span;

use crate::borrow_check::universal_regions::UniversalRegions;

use super::{Locations, TypeChecker};

impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
    pub(super) fn equate_inputs_and_outputs(
        &mut self,
        body: &Body<'tcx>,
        universal_regions: &UniversalRegions<'tcx>,
        normalized_inputs_and_output: &[Ty<'tcx>],
    ) {
        let (&normalized_output_ty, normalized_input_tys) =
            normalized_inputs_and_output.split_last().unwrap();

        // If the user explicitly annotated the input types, extract
        // those.
        //
        // e.g., `|x: FxHashMap<_, &'static u32>| ...`
        let user_provided_sig;
        if !self.tcx().is_closure(self.mir_def_id) {
            user_provided_sig = None;
        } else {
            let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id);
            user_provided_sig = match typeck_tables.user_provided_sigs.get(&self.mir_def_id) {
                None => None,
                Some(user_provided_poly_sig) => {
                    // Instantiate the canonicalized variables from
                    // user-provided signature (e.g., the `_` in the code
                    // above) with fresh variables.
                    let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
                        body.span,
                        &user_provided_poly_sig,
                    );

                    // Replace the bound items in the fn sig with fresh
                    // variables, so that they represent the view from
                    // "inside" the closure.
                    Some(
                        self.infcx
                            .replace_bound_vars_with_fresh_vars(
                                body.span,
                                LateBoundRegionConversionTime::FnCall,
                                &poly_sig,
                            )
                            .0,
                    )
                }
            }
        };

        debug!(
            "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}",
            normalized_input_tys, body.local_decls
        );

        // Equate expected input tys with those in the MIR.
        for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) {
            // In MIR, argument N is stored in local N+1.
            let local = Local::new(argument_index + 1);

            let mir_input_ty = body.local_decls[local].ty;
            let mir_input_span = body.local_decls[local].source_info.span;
            self.equate_normalized_input_or_output(
                normalized_input_ty,
                mir_input_ty,
                mir_input_span,
            );
        }

        if let Some(user_provided_sig) = user_provided_sig {
            for (&user_provided_input_ty, argument_index) in
                user_provided_sig.inputs().iter().zip(0..)
            {
                // In MIR, closures begin an implicit `self`, so
                // argument N is stored in local N+2.
                let local = Local::new(argument_index + 2);
                let mir_input_ty = body.local_decls[local].ty;
                let mir_input_span = body.local_decls[local].source_info.span;

                // If the user explicitly annotated the input types, enforce those.
                let user_provided_input_ty =
                    self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
                self.equate_normalized_input_or_output(
                    user_provided_input_ty,
                    mir_input_ty,
                    mir_input_span,
                );
            }
        }

        assert!(
            body.yield_ty.is_some() && universal_regions.yield_ty.is_some()
                || body.yield_ty.is_none() && universal_regions.yield_ty.is_none()
        );
        if let Some(mir_yield_ty) = body.yield_ty {
            let ur_yield_ty = universal_regions.yield_ty.unwrap();
            let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
            self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
        }

        // Return types are a bit more complex. They may contain opaque `impl Trait` types.
        let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
        let output_span = body.local_decls[RETURN_PLACE].source_info.span;
        if let Err(terr) = self.eq_opaque_type_and_type(
            mir_output_ty,
            normalized_output_ty,
            self.mir_def_id,
            Locations::All(output_span),
            ConstraintCategory::BoringNoLocation,
        ) {
            span_mirbug!(
                self,
                Location::START,
                "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                normalized_output_ty,
                mir_output_ty,
                terr
            );
        };

        // If the user explicitly annotated the output types, enforce those.
        // Note that this only happens for closures.
        if let Some(user_provided_sig) = user_provided_sig {
            let user_provided_output_ty = user_provided_sig.output();
            let user_provided_output_ty =
                self.normalize(user_provided_output_ty, Locations::All(output_span));
            if let Err(err) = self.eq_opaque_type_and_type(
                mir_output_ty,
                user_provided_output_ty,
                self.mir_def_id,
                Locations::All(output_span),
                ConstraintCategory::BoringNoLocation,
            ) {
                span_mirbug!(
                    self,
                    Location::START,
                    "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
                    mir_output_ty,
                    user_provided_output_ty,
                    err
                );
            }
        }
    }

    fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
        debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);

        if let Err(terr) =
            self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
        {
            span_mirbug!(
                self,
                Location::START,
                "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
                a,
                b,
                terr
            );
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 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.

use spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
use spec::abi::{Abi};

pub fn target() -> TargetResult {
    Ok(Target {
        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
        llvm_target: "riscv32".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: "".to_string(),
        target_vendor: "unknown".to_string(),
        arch: "riscv32".to_string(),
        linker_flavor: LinkerFlavor::Ld,

        options: TargetOptions {
            linker: Some("riscv32-unknown-elf-ld".to_string()),
            cpu: "generic-rv32".to_string(),
            max_atomic_width: Some(32),
            features: "+m,+a,+c".to_string(),
            executables: true,
            panic_strategy: PanicStrategy::Abort,
            relocation_model: "static".to_string(),
            abi_blacklist: vec![
                Abi::Cdecl,
                Abi::Stdcall,
                Abi::Fastcall,
                Abi::Vectorcall,
                Abi::Thiscall,
                Abi::Aapcs,
                Abi::Win64,
                Abi::SysV64,
                Abi::PtxKernel,
                Abi::Msp430Interrupt,
                Abi::X86Interrupt,
            ],
            .. Default::default()
        },
    })
}
<commit_msg>[RISCV] Disable c extension and atomic_cas.<commit_after>// Copyright 2018 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.

use spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
use spec::abi::{Abi};

pub fn target() -> TargetResult {
    Ok(Target {
        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
        llvm_target: "riscv32".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: "".to_string(),
        target_vendor: "unknown".to_string(),
        arch: "riscv32".to_string(),
        linker_flavor: LinkerFlavor::Ld,

        options: TargetOptions {
            linker: Some("riscv32-unknown-elf-ld".to_string()),
            cpu: "generic-rv32".to_string(),
            max_atomic_width: Some(32),
            atomic_cas: false, // incomplete +a extension
            features: "+m,+a".to_string(), // disable +c extension
            executables: true,
            panic_strategy: PanicStrategy::Abort,
            relocation_model: "static".to_string(),
            abi_blacklist: vec![
                Abi::Cdecl,
                Abi::Stdcall,
                Abi::Fastcall,
                Abi::Vectorcall,
                Abi::Thiscall,
                Abi::Aapcs,
                Abi::Win64,
                Abi::SysV64,
                Abi::PtxKernel,
                Abi::Msp430Interrupt,
                Abi::X86Interrupt,
            ],
            .. Default::default()
        },
    })
}
<|endoftext|>


<commit_before>use std;
use std::{ mem, slice, string };
use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use raw::{ SVt_PVAV, SVt_PVHV, SVt_PVCV, SVt_PVGV };
use array::{ AV };
use hash::{ HV };
use convert::{ IntoSV, FromSV, TryFromSV };

/// Perl scalar object.
pub struct SV(Owned<raw::SV>);

impl SV {
    method! {
        /// Return true if SV is a real scalar value.
        simple fn is_scalar() -> bool = sv_type() < SVt_PVAV
    }
    method! {
        /// Return true if SV contains array.
        simple fn is_array() -> bool = sv_type() == SVt_PVAV
    }
    method! {
        /// Return true if SV contains hash.
        simple fn is_hash() -> bool = sv_type() == SVt_PVHV
    }
    method! {
        /// Return true if SV contains subroutine.
        simple fn is_code() -> bool = sv_type() == SVt_PVCV
    }
    method! {
        /// Return true if SV contains glob.
        simple fn is_glob() -> bool = sv_type() == SVt_PVGV
    }
    method! {
        /// Return true if SV is defined.
        ///
        /// [`SvOK`](http://perldoc.perl.org/perlapi.html#SvOK).
        simple fn ok() -> bool = sv_ok() != 0
    }
    method! {
        /// Return true if SV contains a signed integer.
        ///
        /// Perl macro:[`SvIOK`](http://perldoc.perl.org/perlapi.html#SvIOK).
        simple fn iv_ok() -> bool = sv_iok() != 0
    }
    method! {
        /// Coerce the given SV to an integer and return it.
        ///
        /// Perl macro: [`SvIV`](http://perldoc.perl.org/perlapi.html#SvIV).
        simple fn iv() -> IV = sv_iv()
    }
    method! {
        /// Return true if SV contains a unsigned integer.
        ///
        /// Perl macro:[`SvUOK`](http://perldoc.perl.org/perlapi.html#SvUOK).
        simple fn uv_ok() -> bool = sv_uok() != 0
    }
    method! {
        /// Coerce the given SV to an unsigned integer and return it.
        ///
        /// Perl macro: [`SvUV`](http://perldoc.perl.org/perlapi.html#SvUV).
        simple fn uv() -> UV = sv_uv()
    }
    method! {
        /// Return true if SV contains a floating point value.
        ///
        /// Perl macro:[`SvNOK`](http://perldoc.perl.org/perlapi.html#SvNOK).
        simple fn nv_ok() -> bool = sv_nok() != 0
    }
    method! {
        /// Coerce the given SV to a floating point value and return it.
        ///
        /// Perl macro: [`SvNV`](http://perldoc.perl.org/perlapi.html#SvNV).
        simple fn nv() -> NV = sv_nv()
    }
    method! {
        /// Return true if SV contains a string.
        ///
        /// Perl macro:[`SvPOK`](http://perldoc.perl.org/perlapi.html#SvPOK).
        simple fn pv_ok() -> bool = sv_pok() != 0
    }
    method! {
        /// Return UTF8 flag on the SV.
        ///
        /// You should use this after a call to `to_vec` or `to_string`, in case any call to string
        /// overloading updates the internal flag.
        ///
        /// Perl macro: [`SvUTF8`](http://perldoc.perl.org/perlapi.html#SvUTF8).
        simple fn utf8() -> bool = sv_utf8() != 0
    }

    /// Get a slice of the internal string buffer of the SV.
    ///
    /// This method is unsafe, because the buffer may be changed, moved or freed by the interpreter
    /// whenever this SV is accessed or modified. To be safe, code that uses this method should not
    /// access interpreter context, this or any other perl value while the slice is in scope.
    ///
    /// For example, this use is okay:
    ///
    /// ```ignore
    /// let chars = unsafe { sv.as_slice().chars().count() };
    /// ```
    ///
    /// And this code may potentially access freed memory:
    ///
    /// ```ignore
    /// let msg = unsafe { sv1.as_slice() };
    /// let pos = sv2.iv();
    /// println!("{}", &msg[pos..]);
    /// ```
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub unsafe fn as_slice(&self) -> &[u8] {
        let mut len = 0;
        let ptr = self.pthx().sv_pv(self.as_ptr(), &mut len);
        slice::from_raw_parts(ptr as *const u8, len as usize)
    }

    /// Return a copy of string in the SV as a vector of bytes.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn to_vec(&self) -> Vec<u8> {
        unsafe {
            self.as_slice().to_owned()
        }
    }

    /// Return a copy of string in the SV.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn to_string(&self) -> Result<String, string::FromUtf8Error> {
        String::from_utf8(self.to_vec())
    }

    method! {
        /// Return true if SV contains a Perl reference.
        ///
        /// Perl macro:[`SvROK`](http://perldoc.perl.org/perlapi.html#SvROK).
        simple fn rv_ok() -> bool = sv_rok() != 0
    }

    #[inline]
    unsafe fn deref_raw(&self) -> *mut raw::SV {
        self.pthx().sv_rv(self.as_ptr())
    }

    /// Dereference RV.
    ///
    /// Return `None` if `self` is not a valid Perl reference.
    #[inline]
    pub fn deref(&self) -> Option<SV> {
        if self.rv_ok() {
            Some(unsafe { SV::from_raw_borrowed(self.pthx(), self.deref_raw()) })
        } else {
            None
        }
    }

    /// Dereference RV into AV.
    ///
    /// Return `None` if `self` is not an array reference.
    #[inline]
    pub fn deref_av(&self) -> Option<AV> {
        self.deref().and_then(|sv| sv.into_av())
    }

    /// Dereference RV into HV.
    ///
    /// Return `None` if `self` is not a hash reference.
    #[inline]
    pub fn deref_hv(&self) -> Option<HV> {
        self.deref().and_then(|sv| sv.into_hv())
    }

    /// Cast SV into AV.
    #[inline]
    pub fn into_av(self) -> Option<AV> {
        if self.is_array() {
            Some(unsafe { AV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Cast SV into HV.
    #[inline]
    pub fn into_hv(self) -> Option<HV> {
        if self.is_hash() {
            Some(unsafe { HV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Consume SV and convert into raw pointer.
    ///
    /// Does not decrement reference count. Returned pointer must be correctly disposed of to avoid
    /// memory leaks.
    #[inline]
    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    /// Construct new instance from a raw SV pointer without incrementing reference counter.
    ///
    /// Owned SV pointers are returned by assorted
    /// [`newSV`](http://perldoc.perl.org/perlapi.html#newSV) functions.
    #[inline]
    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    /// Construct new instance from a raw SV pointer and increment reference counter.
    ///
    /// Borrowed SV pointers exist on stack and are returned by functions like
    /// [`av_fetch`](http://perldoc.perl.org/perlapi.html#av_fetch) or
    /// [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
    #[inline]
    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl Clone for SV {
    fn clone(&self) -> SV {
        unsafe {
            SV::from_raw_borrowed(self.pthx(), self.as_ptr())
        }
    }
}

impl FromSV for IV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromSV for UV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> UV {
        pthx.sv_uv(raw)
    }
}

impl FromSV for NV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> NV {
        pthx.sv_nv(raw)
    }
}

impl FromSV for SV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl TryFromSV for String {
    type Error = std::str::Utf8Error;

    #[inline]
    unsafe fn try_from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> Result<Self, Self::Error> {
        let mut len = 0;
        let ptr = pthx.sv_pv(raw, &mut len);
        let bytes = slice::from_raw_parts(ptr as *const u8, len as usize);
        Ok(try!(std::str::from_utf8(bytes)).to_owned())
    }
}

impl IntoSV for IV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl IntoSV for bool {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let raw = if self { pthx.sv_yes() } else { pthx.sv_no() };
            SV::from_raw_owned(pthx, raw)
        }
    }
}

impl IntoSV for String {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        (&self[..]).into_sv(pthx)
    }
}

impl<'a> IntoSV for &'a str {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let svp = pthx.new_sv_pvn(self.as_ptr() as *const i8,
                                      self.len() as raw::STRLEN,
                                      raw::SVf_UTF8 as raw::U32);
            SV::from_raw_owned(pthx, svp)
        }
    }
}

impl IntoSV for SV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        assert!(self.pthx() == pthx);
        self
    }
}
<commit_msg>Implement IntoSV for &SV.<commit_after>use std;
use std::{ mem, slice, string };
use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use raw::{ SVt_PVAV, SVt_PVHV, SVt_PVCV, SVt_PVGV };
use array::{ AV };
use hash::{ HV };
use convert::{ IntoSV, FromSV, TryFromSV };

/// Perl scalar object.
pub struct SV(Owned<raw::SV>);

impl SV {
    method! {
        /// Return true if SV is a real scalar value.
        simple fn is_scalar() -> bool = sv_type() < SVt_PVAV
    }
    method! {
        /// Return true if SV contains array.
        simple fn is_array() -> bool = sv_type() == SVt_PVAV
    }
    method! {
        /// Return true if SV contains hash.
        simple fn is_hash() -> bool = sv_type() == SVt_PVHV
    }
    method! {
        /// Return true if SV contains subroutine.
        simple fn is_code() -> bool = sv_type() == SVt_PVCV
    }
    method! {
        /// Return true if SV contains glob.
        simple fn is_glob() -> bool = sv_type() == SVt_PVGV
    }
    method! {
        /// Return true if SV is defined.
        ///
        /// [`SvOK`](http://perldoc.perl.org/perlapi.html#SvOK).
        simple fn ok() -> bool = sv_ok() != 0
    }
    method! {
        /// Return true if SV contains a signed integer.
        ///
        /// Perl macro:[`SvIOK`](http://perldoc.perl.org/perlapi.html#SvIOK).
        simple fn iv_ok() -> bool = sv_iok() != 0
    }
    method! {
        /// Coerce the given SV to an integer and return it.
        ///
        /// Perl macro: [`SvIV`](http://perldoc.perl.org/perlapi.html#SvIV).
        simple fn iv() -> IV = sv_iv()
    }
    method! {
        /// Return true if SV contains a unsigned integer.
        ///
        /// Perl macro:[`SvUOK`](http://perldoc.perl.org/perlapi.html#SvUOK).
        simple fn uv_ok() -> bool = sv_uok() != 0
    }
    method! {
        /// Coerce the given SV to an unsigned integer and return it.
        ///
        /// Perl macro: [`SvUV`](http://perldoc.perl.org/perlapi.html#SvUV).
        simple fn uv() -> UV = sv_uv()
    }
    method! {
        /// Return true if SV contains a floating point value.
        ///
        /// Perl macro:[`SvNOK`](http://perldoc.perl.org/perlapi.html#SvNOK).
        simple fn nv_ok() -> bool = sv_nok() != 0
    }
    method! {
        /// Coerce the given SV to a floating point value and return it.
        ///
        /// Perl macro: [`SvNV`](http://perldoc.perl.org/perlapi.html#SvNV).
        simple fn nv() -> NV = sv_nv()
    }
    method! {
        /// Return true if SV contains a string.
        ///
        /// Perl macro:[`SvPOK`](http://perldoc.perl.org/perlapi.html#SvPOK).
        simple fn pv_ok() -> bool = sv_pok() != 0
    }
    method! {
        /// Return UTF8 flag on the SV.
        ///
        /// You should use this after a call to `to_vec` or `to_string`, in case any call to string
        /// overloading updates the internal flag.
        ///
        /// Perl macro: [`SvUTF8`](http://perldoc.perl.org/perlapi.html#SvUTF8).
        simple fn utf8() -> bool = sv_utf8() != 0
    }

    /// Get a slice of the internal string buffer of the SV.
    ///
    /// This method is unsafe, because the buffer may be changed, moved or freed by the interpreter
    /// whenever this SV is accessed or modified. To be safe, code that uses this method should not
    /// access interpreter context, this or any other perl value while the slice is in scope.
    ///
    /// For example, this use is okay:
    ///
    /// ```ignore
    /// let chars = unsafe { sv.as_slice().chars().count() };
    /// ```
    ///
    /// And this code may potentially access freed memory:
    ///
    /// ```ignore
    /// let msg = unsafe { sv1.as_slice() };
    /// let pos = sv2.iv();
    /// println!("{}", &msg[pos..]);
    /// ```
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub unsafe fn as_slice(&self) -> &[u8] {
        let mut len = 0;
        let ptr = self.pthx().sv_pv(self.as_ptr(), &mut len);
        slice::from_raw_parts(ptr as *const u8, len as usize)
    }

    /// Return a copy of string in the SV as a vector of bytes.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn to_vec(&self) -> Vec<u8> {
        unsafe {
            self.as_slice().to_owned()
        }
    }

    /// Return a copy of string in the SV.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn to_string(&self) -> Result<String, string::FromUtf8Error> {
        String::from_utf8(self.to_vec())
    }

    method! {
        /// Return true if SV contains a Perl reference.
        ///
        /// Perl macro:[`SvROK`](http://perldoc.perl.org/perlapi.html#SvROK).
        simple fn rv_ok() -> bool = sv_rok() != 0
    }

    #[inline]
    unsafe fn deref_raw(&self) -> *mut raw::SV {
        self.pthx().sv_rv(self.as_ptr())
    }

    /// Dereference RV.
    ///
    /// Return `None` if `self` is not a valid Perl reference.
    #[inline]
    pub fn deref(&self) -> Option<SV> {
        if self.rv_ok() {
            Some(unsafe { SV::from_raw_borrowed(self.pthx(), self.deref_raw()) })
        } else {
            None
        }
    }

    /// Dereference RV into AV.
    ///
    /// Return `None` if `self` is not an array reference.
    #[inline]
    pub fn deref_av(&self) -> Option<AV> {
        self.deref().and_then(|sv| sv.into_av())
    }

    /// Dereference RV into HV.
    ///
    /// Return `None` if `self` is not a hash reference.
    #[inline]
    pub fn deref_hv(&self) -> Option<HV> {
        self.deref().and_then(|sv| sv.into_hv())
    }

    /// Cast SV into AV.
    #[inline]
    pub fn into_av(self) -> Option<AV> {
        if self.is_array() {
            Some(unsafe { AV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Cast SV into HV.
    #[inline]
    pub fn into_hv(self) -> Option<HV> {
        if self.is_hash() {
            Some(unsafe { HV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Consume SV and convert into raw pointer.
    ///
    /// Does not decrement reference count. Returned pointer must be correctly disposed of to avoid
    /// memory leaks.
    #[inline]
    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    /// Construct new instance from a raw SV pointer without incrementing reference counter.
    ///
    /// Owned SV pointers are returned by assorted
    /// [`newSV`](http://perldoc.perl.org/perlapi.html#newSV) functions.
    #[inline]
    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    /// Construct new instance from a raw SV pointer and increment reference counter.
    ///
    /// Borrowed SV pointers exist on stack and are returned by functions like
    /// [`av_fetch`](http://perldoc.perl.org/perlapi.html#av_fetch) or
    /// [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
    #[inline]
    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl Clone for SV {
    fn clone(&self) -> SV {
        unsafe {
            SV::from_raw_borrowed(self.pthx(), self.as_ptr())
        }
    }
}

impl FromSV for IV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromSV for UV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> UV {
        pthx.sv_uv(raw)
    }
}

impl FromSV for NV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> NV {
        pthx.sv_nv(raw)
    }
}

impl FromSV for SV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl TryFromSV for String {
    type Error = std::str::Utf8Error;

    #[inline]
    unsafe fn try_from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> Result<Self, Self::Error> {
        let mut len = 0;
        let ptr = pthx.sv_pv(raw, &mut len);
        let bytes = slice::from_raw_parts(ptr as *const u8, len as usize);
        Ok(try!(std::str::from_utf8(bytes)).to_owned())
    }
}

impl IntoSV for IV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl IntoSV for bool {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let raw = if self { pthx.sv_yes() } else { pthx.sv_no() };
            SV::from_raw_owned(pthx, raw)
        }
    }
}

impl IntoSV for String {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        (&self[..]).into_sv(pthx)
    }
}

impl<'a> IntoSV for &'a str {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let svp = pthx.new_sv_pvn(self.as_ptr() as *const i8,
                                      self.len() as raw::STRLEN,
                                      raw::SVf_UTF8 as raw::U32);
            SV::from_raw_owned(pthx, svp)
        }
    }
}

impl IntoSV for SV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        assert!(self.pthx() == pthx);
        self
    }
}

impl<'a> IntoSV for &'a SV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        assert!(self.pthx() == pthx);
        self.clone()
    }
}
<|endoftext|>


<commit_before>pub use crate::bitset::BitSet;
use std::fmt::Debug;
use std::mem::{size_of, transmute};
use std::ops::Range;
use std::str;

#[cfg(target_endian = "little")]
macro_rules! include_slice {
    ($T:ty, $name:ident, $size:expr, $file:expr) => {
        pub const $name: &[$T; $size] = {
            const BYTES: &[u8; $size * size_of::<$T>()] = include_bytes!($file);

            const TS: &[$T; $size] = unsafe { &transmute(*BYTES) };

            TS
        };
    };
}

#[derive(Copy, Clone, PartialEq)]
pub struct Character {
    /// 8 MSB = length
    /// 24 LSB = index
    pos: u32,
    literal: char,
}

impl Debug for Character {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?} {}", self.literal, self.name())
    }
}

impl Character {
    pub fn range(&self) -> Range<usize> {
        let start = self.pos & 0xFF_FF_FF;
        let end = start + (self.pos >> 24);

        start as usize..end as usize
    }

    pub fn from_codepoint(cp: u32) -> Option<Self> {
        CHARACTERS
            .binary_search_by_key(&cp, |character| character.codepoint())
            .map(|pos| CHARACTERS[pos])
            .ok()
    }

    fn name(self) -> &'static str {
        &NAMES[self.range()]
    }

    pub fn codepoint(self) -> u32 {
        self.literal as u32
    }
}

pub const CHARS_LEN: usize = 34592;
const TABLE_LEN: usize = 893901;
const NAMES_LEN: usize = 928493;

pub type Characters = &'static [Character; CHARS_LEN];

#[allow(clippy::unusual_byte_groupings)]
pub const CHARACTERS: Characters = include!("./characters.rs");

pub const NAMES: &str = include_str!("./names.txt");
include_slice!(u32, SUFFIX_TABLE, TABLE_LEN, "./suffix_array.u32");
include_slice!(u16, INDICES, NAMES_LEN, "./indices.u16");

fn binary_search(mut left: usize, f: impl Fn(&str) -> bool) -> usize {
    let mut right = TABLE_LEN;

    while left < right {
        let mid = (left + right) / 2;

        let suffix = &NAMES[SUFFIX_TABLE[mid] as usize..];

        if f(suffix) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }

    left
}

pub fn search(pattern: &str, characters: &mut Vec<Character>, character_indices: &mut BitSet) {
    let start = binary_search(0, |suffix| pattern > suffix);
    let end = binary_search(start, |suffix| suffix.starts_with(pattern));

    for &suffix in &SUFFIX_TABLE[start..end] {
        let index = INDICES[suffix as usize];

        character_indices.insert(index.into());
    }

    character_indices.drain_ones(|i| characters.push(CHARACTERS[i as usize]));
}

#[cfg(test)]
mod tests {
    use super::*;
    use proptest::prelude::*;
    use proptest::sample::select;
    use regex::Regex;

    fn naive_search(pattern: &str) -> Vec<Character> {
        CHARACTERS
            .iter()
            .copied()
            .filter(|character| character.name().contains(pattern))
            .collect()
    }

    fn search(pattern: &str) -> Vec<Character> {
        let mut set = BitSet::new();
        let mut chars = Vec::new();

        super::search(pattern, &mut chars, &mut set);

        chars
    }

    #[test]
    fn searches() {
        assert_eq!(search("LINE FEED"), search("INE FEED"));

        let names: Vec<&str> = search("LINE FEED")
            .into_iter()
            .map(|ch| ch.name())
            .collect();

        assert_eq!(
            names,
            &[
                "LINE FEED",
                "REVERSE LINE FEED",
                "SYMBOL FOR LINE FEED",
                "IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL"
            ]
        );
    }

    proptest! {
        #[test]
        fn same_result_as_naive_search(s in "[A-Z0-9 -]*") {
            assert_eq!(
                search(&s),
                naive_search(&s)
            );
        }

        #[test]
        fn guaranteed_match(ch in select(&CHARACTERS[..]), start: usize, len: usize) {
            let name = ch.name();

            let name = &name[start % name.len()..];
            let name = &name[..len % name.len()];

            let results = search(name);
            assert!(results.contains(&ch));

            assert_eq!(results, naive_search(name));
        }
    }

    #[test]
    fn html_safe_characters() {
        let expected = Regex::new("^[A-Z0-9 -]+$").unwrap();

        for character in CHARACTERS {
            assert!(expected.is_match(character.name()), "{:?}", character);
        }
    }
}
<commit_msg>Allow Characters with unindexed names<commit_after>pub use crate::bitset::BitSet;
use std::fmt::Debug;
use std::mem::{size_of, transmute};
use std::ops::Range;
use std::str;

#[cfg(target_endian = "little")]
macro_rules! include_slice {
    ($T:ty, $name:ident, $size:expr, $file:expr) => {
        pub const $name: &[$T; $size] = {
            const BYTES: &[u8; $size * size_of::<$T>()] = include_bytes!($file);

            const TS: &[$T; $size] = unsafe { &transmute(*BYTES) };

            TS
        };
    };
}

#[derive(Copy, Clone, PartialEq)]
pub struct Character {
    /// 8 MSB = length
    /// 24 LSB = index
    pos: u32,
    literal: char,
}

impl Debug for Character {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?} {}", self.literal, self.name())
    }
}

impl Character {
    pub fn range(&self) -> Range<usize> {
        let start = self.pos & 0xFF_FF_FF;
        let end = start + (self.pos >> 24);

        start as usize..end as usize
    }

    pub fn from_codepoint(cp: u32) -> Option<Self> {
        if let Ok(pos) = CHARACTERS.binary_search_by_key(&cp, |character| character.codepoint()) {
            Some(CHARACTERS[pos])
        } else if let Ok(literal) = cp.try_into() {
            Some(Character { pos: 0, literal })
        } else {
            None
        }
    }

    fn name(self) -> &'static str {
        &NAMES[self.range()]
    }

    pub fn codepoint(self) -> u32 {
        self.literal as u32
    }
}

pub const CHARS_LEN: usize = 34592;
const TABLE_LEN: usize = 893901;
const NAMES_LEN: usize = 928493;

pub type Characters = &'static [Character; CHARS_LEN];

#[allow(clippy::unusual_byte_groupings)]
pub const CHARACTERS: Characters = include!("./characters.rs");

pub const NAMES: &str = include_str!("./names.txt");
include_slice!(u32, SUFFIX_TABLE, TABLE_LEN, "./suffix_array.u32");
include_slice!(u16, INDICES, NAMES_LEN, "./indices.u16");

fn binary_search(mut left: usize, f: impl Fn(&str) -> bool) -> usize {
    let mut right = TABLE_LEN;

    while left < right {
        let mid = (left + right) / 2;

        let suffix = &NAMES[SUFFIX_TABLE[mid] as usize..];

        if f(suffix) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }

    left
}

pub fn search(pattern: &str, characters: &mut Vec<Character>, character_indices: &mut BitSet) {
    let start = binary_search(0, |suffix| pattern > suffix);
    let end = binary_search(start, |suffix| suffix.starts_with(pattern));

    for &suffix in &SUFFIX_TABLE[start..end] {
        let index = INDICES[suffix as usize];

        character_indices.insert(index.into());
    }

    character_indices.drain_ones(|i| characters.push(CHARACTERS[i as usize]));
}

#[cfg(test)]
mod tests {
    use super::*;
    use proptest::prelude::*;
    use proptest::sample::select;
    use regex::Regex;

    fn naive_search(pattern: &str) -> Vec<Character> {
        CHARACTERS
            .iter()
            .copied()
            .filter(|character| character.name().contains(pattern))
            .collect()
    }

    fn search(pattern: &str) -> Vec<Character> {
        let mut set = BitSet::new();
        let mut chars = Vec::new();

        super::search(pattern, &mut chars, &mut set);

        chars
    }

    #[test]
    fn searches() {
        assert_eq!(search("LINE FEED"), search("INE FEED"));

        let names: Vec<&str> = search("LINE FEED")
            .into_iter()
            .map(|ch| ch.name())
            .collect();

        assert_eq!(
            names,
            &[
                "LINE FEED",
                "REVERSE LINE FEED",
                "SYMBOL FOR LINE FEED",
                "IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL"
            ]
        );
    }

    proptest! {
        #[test]
        fn same_result_as_naive_search(s in "[A-Z0-9 -]*") {
            assert_eq!(
                search(&s),
                naive_search(&s)
            );
        }

        #[test]
        fn guaranteed_match(ch in select(&CHARACTERS[..]), start: usize, len: usize) {
            let name = ch.name();

            let name = &name[start % name.len()..];
            let name = &name[..len % name.len()];

            let results = search(name);
            assert!(results.contains(&ch));

            assert_eq!(results, naive_search(name));
        }
    }

    #[test]
    fn html_safe_characters() {
        let expected = Regex::new("^[A-Z0-9 -]+$").unwrap();

        for character in CHARACTERS {
            assert!(expected.is_match(character.name()), "{:?}", character);
        }
    }
}
<|endoftext|>


<commit_before>use std::io::net::ip::{SocketAddr, IpAddr, Port};

use http;
use http::server::{Config, Server, Request, ResponseWriter};

use middleware::MiddlewareStack;
use request;
use response;

#[deriving(Clone)]
pub struct Server {
    middleware_stack: MiddlewareStack,
    ip: IpAddr,
    port: Port
}

impl http::server::Server for Server {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr { ip: self.ip, port: self.port } }
    }

    fn handle_request(&self, req: Request, res: &mut ResponseWriter) {

        let nickel_req = &mut request::Request::from_internal(&req);
        let nickel_res = &mut response::Response::from_internal(res);

        self.middleware_stack.invoke(nickel_req, nickel_res);
    }
}

impl Server {
    pub fn new(middleware_stack: MiddlewareStack, ip: IpAddr, port: Port) -> Server {
        Server {
            middleware_stack: middleware_stack,
            ip: ip,
            port: port
        }
    }

    // why do we need this? Is the http::Server.serve_forever method protected in C# terms?
    pub fn serve (self) {
        self.serve_forever();
    }
}
<commit_msg>fix up the "import conflicts" error of server module.<commit_after>use std::io::net::ip::{SocketAddr, IpAddr, Port};

use http::server::{Config, Request, ResponseWriter};
use http::server::Server as HttpServer;

use middleware::MiddlewareStack;
use request;
use response;

#[deriving(Clone)]
pub struct Server {
    middleware_stack: MiddlewareStack,
    ip: IpAddr,
    port: Port
}

impl HttpServer for Server {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr { ip: self.ip, port: self.port } }
    }

    fn handle_request(&self, req: Request, res: &mut ResponseWriter) {

        let nickel_req = &mut request::Request::from_internal(&req);
        let nickel_res = &mut response::Response::from_internal(res);

        self.middleware_stack.invoke(nickel_req, nickel_res);
    }
}

impl Server {
    pub fn new(middleware_stack: MiddlewareStack, ip: IpAddr, port: Port) -> Server {
        Server {
            middleware_stack: middleware_stack,
            ip: ip,
            port: port
        }
    }

    // why do we need this? Is the http::Server.serve_forever method protected in C# terms?
    pub fn serve (self) {
        self.serve_forever();
    }
}
<|endoftext|>


<commit_before>//! `Server` listens for HTTP requests.
//!
//!```rust
//!# use rustful::server::Server;
//!# use rustful::router::Router;
//!# let routes = [];
//!let server = Server {
//!	router: ~Router::from_routes(routes),
//!	port: 8080
//!};
//!
//!server.run();
//!```

use router::Router;
use request::Request;
use response::Response;
use response::status::NotFound;

use http;
use http::server::{ResponseWriter, Config};
use http::server::request::{AbsoluteUri, AbsolutePath};
use http::headers::content_type::MediaType;
use http::method::Post;

use std::io::net::ip::{SocketAddr, Ipv4Addr, Port};
use std::hashmap::HashMap;
use std::str::from_utf8;
use std::uint;
use std::io::BufReader;

use extra::time;

use HTTP = http::server::Server;

///A handler function for routing.
pub type HandlerFn = fn(&Request, &mut Response);

#[deriving(Clone)]
pub struct Server {
	///A routing tree with response handlers
	router: ~Router<HandlerFn>,

	///The port where the server will listen for requests
	port: Port
}

impl Server {
	///Start the server and run forever.
	///This will only return if the initial connection fails.
	pub fn run(&self) {
		self.clone().serve_forever();
	}
}

impl HTTP for Server {
	fn get_config(&self) -> Config {
		Config {
			bind_address: SocketAddr {
				ip: Ipv4Addr(0, 0, 0, 0),
				port: self.port
			}
		}
	}

	fn handle_request(&self, request: &http::server::request::Request, writer: &mut ResponseWriter) {
		let mut response = Response::new(writer);
		response.headers.date = Some(time::now_utc());
		response.headers.content_type = Some(MediaType {
			type_: ~"text",
			subtype: ~"plain",
			parameters: ~[(~"charset", ~"UTF-8")]
		});
		response.headers.server = Some(~"rustful");

		let found = match build_request(request) {
			Some(mut request) => match self.router.find(request.method.clone(), request.path) {
				Some((&handler, variables)) => {
					request.variables = variables;
					handler(&request, response);
					true
				},
				None => false
			},
			None => false
		};

		if !found {
			let content = bytes!("File not found");
			response.headers.content_length = Some(content.len());
			response.status = NotFound;
			match response.write(content.to_owned()) {
				Err(e) => println!("error while writing 404: {}", e),
				_ => {}
			}
		}
	}
}

fn build_request(request: &http::server::request::Request) -> Option<Request> {
	let path = match request.request_uri {
		AbsoluteUri(ref url) => {
			let query = ~url.query.iter().map(|&(ref a, ref b)| {
				(a.to_str(), b.to_str())
			}).collect();
			Some((url.path.to_str(), query, url.fragment.to_str()))
		},
		AbsolutePath(ref path) => Some(parse_path(path.to_str())),
		_ => None
	};

	match path {
		Some((path, query, fragment)) => {
			let post = if request.method == Post {
				parse_parameters(request.body)
			} else {
				~HashMap::new()
			};

			Some(Request {
				headers: request.headers.clone(),
				method: request.method.clone(),
				path: path.to_owned(),
				variables: ~HashMap::new(),
				post: post,
				query: query,
				fragment: fragment,
				body: request.body.to_str()
			})
		}
		None => None
	}
}

fn parse_parameters(source: &str) -> ~HashMap<~str, ~str> {
	let mut parameters = ~HashMap::new();
	for parameter in source.split('&') {
		let parts = parameter.split('=').collect::<~[&str]>();
		match parts.as_slice() {
			[name, value] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[name] => {
				parameters.insert(url_decode(name), ~"");
			},
			[name, value, ..] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[] => {}
		}
	}

	parameters
}

fn parse_path(path: &str) -> (~str, ~HashMap<~str, ~str>, ~str) {
	match path.find('?') {
		Some(index) => {
			let (query, fragment) = parse_fragment(path.slice(index+1, path.len()));
			(path.slice(0, index).to_str(), parse_parameters(query), fragment)
		},
		None => {
			let (path, fragment) = parse_fragment(path);
			(path, ~HashMap::new(), fragment)
		}
	}
}

fn parse_fragment(path: &str) -> (~str, ~str) {
	match path.find('#') {
		Some(index) => (path.slice(0, index).to_str(), path.slice(index+1, path.len()).to_str()),
		None => (path.to_str(), ~"")
	}
}

fn url_decode(string: &str) -> ~str {
	let mut rdr = BufReader::new(string.as_bytes());
	let mut out = ~[];

	loop {
		let mut buf = [0];
		let ch = match rdr.read(buf) {
			Err(..) => break,
			Ok(..) => buf[0] as char
		};
		match ch {
			'%' => {
				let mut bytes = [0, 0];
				match rdr.read(bytes) {
					Ok(2) => {}
					_ => fail!()
				}
				let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8;
				out.push(ch);
			}
			ch => out.push(ch as u8)
		}
	}

	match from_utf8(out) {
		Some(result) => result.to_str(),
		None => string.to_str()
	}
}

#[test]
fn parsing_parameters() {
	let parameters = parse_parameters("a=1&aa=2&ab=202");
	let a = ~"1";
	let aa = ~"2";
	let ab = ~"202";
	assert_eq!(parameters.find(&~"a"), Some(&a));
	assert_eq!(parameters.find(&~"aa"), Some(&aa));
	assert_eq!(parameters.find(&~"ab"), Some(&ab));
}

#[test]
fn parsing_strange_parameters() {
	let parameters = parse_parameters("a=1=2&=2&ab=");
	let a = ~"1";
	let aa = ~"2";
	let ab = ~"";
	assert_eq!(parameters.find(&~"a"), Some(&a));
	assert_eq!(parameters.find(&~""), Some(&aa));
	assert_eq!(parameters.find(&~"ab"), Some(&ab));
}

#[test]
fn parse_path_parts() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=that#lol");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"lol");
}

#[test]
fn parse_strange_path() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=what?#");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=what?");
	assert_eq!(fragment, ~"");
}

#[test]
fn parse_missing_path_parts() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=that");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"");

	let (path, query, fragment) = parse_path("/path/to/something#lol");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"");
	assert_eq!(fragment, ~"lol");

	let (path, query, fragment) = parse_path("?whith=this&and=that#lol");
	assert_eq!(path, ~"");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"lol");
}<commit_msg>Fixed errors in tests<commit_after>//! `Server` listens for HTTP requests.
//!
//!```rust
//!# use rustful::server::Server;
//!# use rustful::router::Router;
//!# let routes = [];
//!let server = Server {
//!	router: ~Router::from_routes(routes),
//!	port: 8080
//!};
//!
//!server.run();
//!```

use router::Router;
use request::Request;
use response::Response;
use response::status::NotFound;

use http;
use http::server::{ResponseWriter, Config};
use http::server::request::{AbsoluteUri, AbsolutePath};
use http::headers::content_type::MediaType;
use http::method::Post;

use std::io::net::ip::{SocketAddr, Ipv4Addr, Port};
use std::hashmap::HashMap;
use std::str::from_utf8;
use std::uint;
use std::io::BufReader;

use extra::time;

use HTTP = http::server::Server;

///A handler function for routing.
pub type HandlerFn = fn(&Request, &mut Response);

#[deriving(Clone)]
pub struct Server {
	///A routing tree with response handlers
	router: ~Router<HandlerFn>,

	///The port where the server will listen for requests
	port: Port
}

impl Server {
	///Start the server and run forever.
	///This will only return if the initial connection fails.
	pub fn run(&self) {
		self.clone().serve_forever();
	}
}

impl HTTP for Server {
	fn get_config(&self) -> Config {
		Config {
			bind_address: SocketAddr {
				ip: Ipv4Addr(0, 0, 0, 0),
				port: self.port
			}
		}
	}

	fn handle_request(&self, request: &http::server::request::Request, writer: &mut ResponseWriter) {
		let mut response = Response::new(writer);
		response.headers.date = Some(time::now_utc());
		response.headers.content_type = Some(MediaType {
			type_: ~"text",
			subtype: ~"plain",
			parameters: ~[(~"charset", ~"UTF-8")]
		});
		response.headers.server = Some(~"rustful");

		let found = match build_request(request) {
			Some(mut request) => match self.router.find(request.method.clone(), request.path) {
				Some((&handler, variables)) => {
					request.variables = variables;
					handler(&request, response);
					true
				},
				None => false
			},
			None => false
		};

		if !found {
			let content = bytes!("File not found");
			response.headers.content_length = Some(content.len());
			response.status = NotFound;
			match response.write(content.to_owned()) {
				Err(e) => println!("error while writing 404: {}", e),
				_ => {}
			}
		}
	}
}

fn build_request(request: &http::server::request::Request) -> Option<Request> {
	let path = match request.request_uri {
		AbsoluteUri(ref url) => {
			let query = ~url.query.iter().map(|&(ref a, ref b)| {
				(a.to_str(), b.to_str())
			}).collect();
			Some((url.path.to_str(), query, url.fragment.to_str()))
		},
		AbsolutePath(ref path) => Some(parse_path(path.to_str())),
		_ => None
	};

	match path {
		Some((path, query, fragment)) => {
			let post = if request.method == Post {
				parse_parameters(request.body)
			} else {
				~HashMap::new()
			};

			Some(Request {
				headers: request.headers.clone(),
				method: request.method.clone(),
				path: path.to_owned(),
				variables: ~HashMap::new(),
				post: post,
				query: query,
				fragment: fragment,
				body: request.body.to_str()
			})
		}
		None => None
	}
}

fn parse_parameters(source: &str) -> ~HashMap<~str, ~str> {
	let mut parameters = ~HashMap::new();
	for parameter in source.split('&') {
		let parts = parameter.split('=').collect::<~[&str]>();
		match parts.as_slice() {
			[name, value] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[name] => {
				parameters.insert(url_decode(name), ~"");
			},
			[name, value, ..] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[] => {}
		}
	}

	parameters
}

fn parse_path(path: &str) -> (~str, ~HashMap<~str, ~str>, ~str) {
	match path.find('?') {
		Some(index) => {
			let (query, fragment) = parse_fragment(path.slice(index+1, path.len()));
			(path.slice(0, index).to_str(), parse_parameters(query), fragment)
		},
		None => {
			let (path, fragment) = parse_fragment(path);
			(path, ~HashMap::new(), fragment)
		}
	}
}

fn parse_fragment(path: &str) -> (~str, ~str) {
	match path.find('#') {
		Some(index) => (path.slice(0, index).to_str(), path.slice(index+1, path.len()).to_str()),
		None => (path.to_str(), ~"")
	}
}

fn url_decode(string: &str) -> ~str {
	let mut rdr = BufReader::new(string.as_bytes());
	let mut out = ~[];

	loop {
		let mut buf = [0];
		let ch = match rdr.read(buf) {
			Err(..) => break,
			Ok(..) => buf[0] as char
		};
		match ch {
			'%' => {
				let mut bytes = [0, 0];
				match rdr.read(bytes) {
					Ok(2) => {}
					_ => fail!()
				}
				let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8;
				out.push(ch);
			}
			ch => out.push(ch as u8)
		}
	}

	match from_utf8(out) {
		Some(result) => result.to_str(),
		None => string.to_str()
	}
}

#[test]
fn parsing_parameters() {
	let parameters = parse_parameters("a=1&aa=2&ab=202");
	let a = ~"1";
	let aa = ~"2";
	let ab = ~"202";
	assert_eq!(parameters.find(&~"a"), Some(&a));
	assert_eq!(parameters.find(&~"aa"), Some(&aa));
	assert_eq!(parameters.find(&~"ab"), Some(&ab));
}

#[test]
fn parsing_strange_parameters() {
	let parameters = parse_parameters("a=1=2&=2&ab=");
	let a = ~"1";
	let aa = ~"2";
	let ab = ~"";
	assert_eq!(parameters.find(&~"a"), Some(&a));
	assert_eq!(parameters.find(&~""), Some(&aa));
	assert_eq!(parameters.find(&~"ab"), Some(&ab));
}

#[test]
fn parse_path_parts() {
	let with = ~"this";
	let and = ~"that";
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that#lol");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query.find(&~"with"), Some(&with));
	assert_eq!(query.find(&~"and"), Some(&and));
	assert_eq!(fragment, ~"lol");
}

#[test]
fn parse_strange_path() {
	let with = ~"this";
	let and = ~"what?";
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=what?#");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query.find(&~"with"), Some(&with));
	assert_eq!(query.find(&~"and"), Some(&and));
	assert_eq!(fragment, ~"");
}

#[test]
fn parse_missing_path_parts() {
	let with = ~"this";
	let and = ~"that";
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query.find(&~"with"), Some(&with));
	assert_eq!(query.find(&~"and"), Some(&and));
	assert_eq!(fragment, ~"");

	let (path, query, fragment) = parse_path("/path/to/something#lol");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query.len(), 0);
	assert_eq!(fragment, ~"lol");

	let (path, query, fragment) = parse_path("?with=this&and=that#lol");
	assert_eq!(path, ~"");
	assert_eq!(query.find(&~"with"), Some(&with));
	assert_eq!(query.find(&~"and"), Some(&and));
	assert_eq!(fragment, ~"lol");
}<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
use serde_json;

use rs_es::Client;

use iron::prelude::*;
use iron::{status, Handler, Headers};
use iron::mime::Mime;

use http_logger::Logger as HTTPLogger;

use router::Router;

use params::*;

use oath::*;

use config::*;
use resource::Resource;
use logger::Logger;

use std::collections::HashMap;
use std::env;
use std::io::Read;
use std::marker::PhantomData;

macro_rules! try_or_422 {
  ($expr:expr) => (match $expr {
    Ok(val)  => val,
    Err(err) => {
      let error_message = err.to_string();
      error!("{}", error_message);

      let mut error = HashMap::new();
      error.insert("error", error_message);

      let content_type = "application/json".parse::<Mime>().unwrap();
      return Ok(Response::with(
        (content_type, status::UnprocessableEntity, serde_json::to_string(&error).unwrap())
      ))
    }
  })
}

macro_rules! unauthorized {
  () => ({
    return Ok(Response::with(
      (status::Unauthorized)
    ))
  })
}

macro_rules! authorization {
  ($trait_name:ident, $mode:ident) => {
    trait $trait_name {
      fn is_authorized(&self, auth_config: AuthConfig, headers: &Headers) -> bool {
        if auth_config.enabled == false {
          return true;
        }

        match headers.get_raw("Authorization") {
          Some(header) => match String::from_utf8(header[0].to_owned()) {
            Ok(header) => {
              match header.split("token ").collect::<Vec<&str>>().last() {
                Some(token) => {
                  match token.parse::<u64>() {
                    Ok(token) => totp_raw(auth_config.$mode.as_bytes(), 6, 0, 30) == token,
                    Err(_)    => false,
                  }
                },
                None => false
              }
            },
            Err(_) => false
          },
          None => false
        }
      }
    }
  }
}

pub struct Server<R: Resource> {
  config:   Config,
  endpoint: String,
  resource: PhantomData<R>
}

authorization!(ReadableEndpoint, read);
authorization!(WritableEndpoint, write);

pub struct SearchableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> SearchableHandler<R> {
  fn new(config: Config) -> Self {
    SearchableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> ReadableEndpoint for SearchableHandler<R> {}

impl<R: Resource> Handler for SearchableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.auth.to_owned(), &req.headers) {
      unauthorized!();
    }

    let mut client = Client::new(&*self.config.es.url).unwrap();

    let params = try_or_422!(req.get_ref::<Params>());

    let response = R::search(&mut client, &*self.config.es.index, params);

    let content_type = "application/json".parse::<Mime>().unwrap();
    Ok(Response::with(
      (content_type, status::Ok, try_or_422!(serde_json::to_string(&response)))
    ))
  }
}

pub struct IndexableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> IndexableHandler<R> {
  fn new(config: Config) -> Self {
    IndexableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> WritableEndpoint for IndexableHandler<R> {}

impl<R: Resource> Handler for IndexableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.auth.to_owned(), &req.headers) {
      unauthorized!();
    }

    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let mut client = Client::new(&*self.config.es.url).unwrap();

    let resources: Vec<R> = try_or_422!(serde_json::from_str(&payload));
    try_or_422!(R::index(&mut client, &*self.config.es.index, resources));

    Ok(Response::with(status::Created))
  }
}

pub struct DeletableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> DeletableHandler<R> {
  fn new(config: Config) -> Self {
    DeletableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> WritableEndpoint for DeletableHandler<R> {}

impl<R: Resource> Handler for DeletableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.auth.to_owned(), &req.headers) {
      unauthorized!();
    }

    let mut client = Client::new(&*self.config.es.url).unwrap();
    let ref id     = try_or_422!(req.extensions.get::<Router>().unwrap()
                                                               .find("id")
                                                               .ok_or("DELETE#:id not found"));

    match R::delete(&mut client, id, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(e) => {
        let error_message = e.to_string();
        error!("{}", error_message);

        let content_type = "application/json".parse::<Mime>().unwrap();
        Ok(Response::with(
          (content_type, status::UnprocessableEntity, error_message)
        ))
      }
    }
  }
}

pub struct ResettableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> ResettableHandler<R> {
  fn new(config: Config) -> Self {
    ResettableHandler::<R> { resource: PhantomData, config: config }
  }
}

impl<R: Resource> WritableEndpoint for ResettableHandler<R> {}

impl<R: Resource> Handler for ResettableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.auth.to_owned(), &req.headers) {
      unauthorized!();
    }

    let mut client = Client::new(&*self.config.es.url).unwrap();
    match R::reset_index(&mut client, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(e) => {
        let error_message = e.to_string();
        error!("{}", error_message);

        let content_type = "application/json".parse::<Mime>().unwrap();
        Ok(Response::with(
          (content_type, status::UnprocessableEntity, error_message)
        ))
      }
    }
  }
}

impl<R: Resource> Server<R> {
  pub fn new(endpoint: &str) -> Self {
    let config = match env::args().nth(1) {
      Some(file) => Config::from_file(file),
      None       => Config::from_env()
    };

    Server {
      config:   config,
      endpoint: endpoint.to_owned(),
      resource: PhantomData
    }
  }

  pub fn start(&self) {
    Logger::init().unwrap();

    let host = format!("{}:{}", self.config.http.host, self.config.http.port);

    println!("Searchspot v{}\n{}\n{}\n", env!("CARGO_PKG_VERSION"),
                                         self.config.es,
                                         self.config.http);

    let mut router = Router::new();
    router.get(&self.endpoint,    SearchableHandler::<R>::new(self.config.to_owned()), "search");
    router.post(&self.endpoint,   IndexableHandler::<R>::new(self.config.to_owned()),  "index");
    router.delete(&self.endpoint, ResettableHandler::<R>::new(self.config.to_owned()), "reset");

    let deletable_endpoint = format!("{}/:id", self.endpoint);
    router.delete(deletable_endpoint, DeletableHandler::<R>::new(self.config.to_owned()), "delete");

    match env::var("DYNO") { // for some reasons, chain::link makes heroku crash
      Ok(_)  => Iron::new(router).http(&*host),
      Err(_) => {
        let mut chain = Chain::new(router);
        chain.link(HTTPLogger::new(None));
        Iron::new(chain).http(&*host)
      }
    }.unwrap();
  }
}

#[cfg(test)]
mod tests {
  use resource::Resource;

  use params::*;

  use rs_es::Client;
  use rs_es::operations::bulk::{BulkResult, Action};
  use rs_es::operations::delete::DeleteResult;
  use rs_es::operations::mapping::{MappingOperation, MappingResult};
  use rs_es::error::EsError;

  #[derive(Serialize, Deserialize, Clone, Debug)]
  pub struct TestResource {
    pub id: u32
  }

  const ES_TYPE: &'static str = "test_resource";

  impl Resource for TestResource {
    type Results = Vec<u32>;

    fn search(_: &mut Client, _: &str, _: &Map) -> Self::Results {
      vec![]
    }

    fn index(mut es: &mut Client, index: &str, resources: Vec<Self>) -> Result<BulkResult, EsError> {
      es.bulk(&resources.into_iter()
                        .map(|r| {
                            let id = r.id.to_string();
                            Action::index(r).with_id(id)
                        })
                        .collect::<Vec<Action<TestResource>>>())
        .with_index(index)
        .with_doc_type(ES_TYPE)
        .send()
    }

    fn delete(mut es: &mut Client, id: &str, index: &str) -> Result<DeleteResult, EsError> {
      es.delete(index, ES_TYPE, id)
        .send()
    }

    fn reset_index(mut es: &mut Client, index: &str) -> Result<MappingResult, EsError> {
      MappingOperation::new(&mut es, index).send()
    }
  }
}
<commit_msg>server: put ES client inside a keepalive Mutex<commit_after>#![allow(non_upper_case_globals)]
use serde_json;

use rs_es::Client;

use iron::prelude::*;
use iron::{status, Handler, Headers};
use iron::mime::Mime;

use http_logger::Logger as HTTPLogger;

use router::Router;

use params::*;

use oath::*;

use config::*;
use resource::Resource;
use logger::Logger;

use std::collections::HashMap;
use std::env;
use std::io::Read;
use std::marker::PhantomData;
use std::sync::Mutex;

macro_rules! try_or_422 {
  ($expr:expr) => (match $expr {
    Ok(val)  => val,
    Err(err) => {
      let error_message = err.to_string();
      error!("{}", error_message);

      let mut error = HashMap::new();
      error.insert("error", error_message);

      let content_type = "application/json".parse::<Mime>().unwrap();
      return Ok(Response::with(
        (content_type, status::UnprocessableEntity, serde_json::to_string(&error).unwrap())
      ))
    }
  })
}

macro_rules! unauthorized {
  () => ({
    return Ok(Response::with(
      (status::Unauthorized)
    ))
  })
}

macro_rules! authorization {
  ($trait_name:ident, $mode:ident) => {
    trait $trait_name {
      fn is_authorized(&self, auth_config: AuthConfig, headers: &Headers) -> bool {
        if auth_config.enabled == false {
          return true;
        }

        match headers.get_raw("Authorization") {
          Some(header) => match String::from_utf8(header[0].to_owned()) {
            Ok(header) => {
              match header.split("token ").collect::<Vec<&str>>().last() {
                Some(token) => {
                  match token.parse::<u64>() {
                    Ok(token) => totp_raw(auth_config.$mode.as_bytes(), 6, 0, 30) == token,
                    Err(_)    => false,
                  }
                },
                None => false
              }
            },
            Err(_) => false
          },
          None => false
        }
      }
    }
  }
}

pub struct Server<R: Resource> {
  config:   Config,
  endpoint: String,
  resource: PhantomData<R>
}

authorization!(ReadableEndpoint, read);
authorization!(WritableEndpoint, write);

pub struct SearchableHandler<R> {
  config:   Config,
  client:   Mutex<Client>,
  resource: PhantomData<R>
}

impl<R: Resource> SearchableHandler<R> {
  fn new(config: Config) -> Self {
    SearchableHandler::<R> {
      resource: PhantomData,
      client:   Mutex::new(Client::new(&*config.es.url).unwrap()),
      config:   config
    }
  }
}

impl<R: Resource> ReadableEndpoint for SearchableHandler<R> {}

impl<R: Resource> Handler for SearchableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.auth.to_owned(), &req.headers) {
      unauthorized!();
    }

    let params = try_or_422!(req.get_ref::<Params>());

    let response = R::search(&mut self.client.lock().unwrap(), &*self.config.es.index, params);

    let content_type = "application/json".parse::<Mime>().unwrap();
    Ok(Response::with(
      (content_type, status::Ok, try_or_422!(serde_json::to_string(&response)))
    ))
  }
}

pub struct IndexableHandler<R> {
  config:   Config,
  client:   Mutex<Client>,
  resource: PhantomData<R>
}

impl<R: Resource> IndexableHandler<R> {
  fn new(config: Config) -> Self {
    IndexableHandler::<R> {
      resource: PhantomData,
      client:   Mutex::new(Client::new(&*config.es.url).unwrap()),
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for IndexableHandler<R> {}

impl<R: Resource> Handler for IndexableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.auth.to_owned(), &req.headers) {
      unauthorized!();
    }

    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let resources: Vec<R> = try_or_422!(serde_json::from_str(&payload));
    try_or_422!(R::index(&mut self.client.lock().unwrap(), &*self.config.es.index, resources));

    Ok(Response::with(status::Created))
  }
}

pub struct DeletableHandler<R> {
  config:   Config,
  client:   Mutex<Client>,
  resource: PhantomData<R>
}

impl<R: Resource> DeletableHandler<R> {
  fn new(config: Config) -> Self {
    DeletableHandler::<R> {
      resource: PhantomData,
      client:   Mutex::new(Client::new(&*config.es.url).unwrap()),
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for DeletableHandler<R> {}

impl<R: Resource> Handler for DeletableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.auth.to_owned(), &req.headers) {
      unauthorized!();
    }

    let ref id = try_or_422!(req.extensions.get::<Router>().unwrap()
                                                           .find("id")
                                                           .ok_or("DELETE#:id not found"));

    match R::delete(&mut self.client.lock().unwrap(), id, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(e) => {
        let error_message = e.to_string();
        error!("{}", error_message);

        let content_type = "application/json".parse::<Mime>().unwrap();
        Ok(Response::with(
          (content_type, status::UnprocessableEntity, error_message)
        ))
      }
    }
  }
}

pub struct ResettableHandler<R> {
  config:   Config,
  client:   Mutex<Client>,
  resource: PhantomData<R>
}

impl<R: Resource> ResettableHandler<R> {
  fn new(config: Config) -> Self {
    ResettableHandler::<R> {
      resource: PhantomData,
      client:   Mutex::new(Client::new(&*config.es.url).unwrap()),
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for ResettableHandler<R> {}

impl<R: Resource> Handler for ResettableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    if !self.is_authorized(self.config.auth.to_owned(), &req.headers) {
      unauthorized!();
    }

    match R::reset_index(&mut self.client.lock().unwrap(), &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(e) => {
        let error_message = e.to_string();
        error!("{}", error_message);

        let content_type = "application/json".parse::<Mime>().unwrap();
        Ok(Response::with(
          (content_type, status::UnprocessableEntity, error_message)
        ))
      }
    }
  }
}

impl<R: Resource> Server<R> {
  pub fn new(endpoint: &str) -> Self {
    let config = match env::args().nth(1) {
      Some(file) => Config::from_file(file),
      None       => Config::from_env()
    };

    Server {
      config:   config,
      endpoint: endpoint.to_owned(),
      resource: PhantomData
    }
  }

  pub fn start(&self) {
    Logger::init().unwrap();

    let host = format!("{}:{}", self.config.http.host, self.config.http.port);

    println!("Searchspot v{}\n{}\n{}\n", env!("CARGO_PKG_VERSION"),
                                         self.config.es,
                                         self.config.http);

    let mut router = Router::new();
    router.get(&self.endpoint,    SearchableHandler::<R>::new(self.config.to_owned()), "search");
    router.post(&self.endpoint,   IndexableHandler::<R>::new(self.config.to_owned()),  "index");
    router.delete(&self.endpoint, ResettableHandler::<R>::new(self.config.to_owned()), "reset");

    let deletable_endpoint = format!("{}/:id", self.endpoint);
    router.delete(deletable_endpoint, DeletableHandler::<R>::new(self.config.to_owned()), "delete");

    match env::var("DYNO") { // for some reasons, chain::link makes heroku crash
      Ok(_)  => Iron::new(router).http(&*host),
      Err(_) => {
        let mut chain = Chain::new(router);
        chain.link(HTTPLogger::new(None));
        Iron::new(chain).http(&*host)
      }
    }.unwrap();
  }
}

#[cfg(test)]
mod tests {
  use resource::Resource;

  use params::*;

  use rs_es::Client;
  use rs_es::operations::bulk::{BulkResult, Action};
  use rs_es::operations::delete::DeleteResult;
  use rs_es::operations::mapping::{MappingOperation, MappingResult};
  use rs_es::error::EsError;

  #[derive(Serialize, Deserialize, Clone, Debug)]
  pub struct TestResource {
    pub id: u32
  }

  const ES_TYPE: &'static str = "test_resource";

  impl Resource for TestResource {
    type Results = Vec<u32>;

    fn search(_: &mut Client, _: &str, _: &Map) -> Self::Results {
      vec![]
    }

    fn index(mut es: &mut Client, index: &str, resources: Vec<Self>) -> Result<BulkResult, EsError> {
      es.bulk(&resources.into_iter()
                        .map(|r| {
                            let id = r.id.to_string();
                            Action::index(r).with_id(id)
                        })
                        .collect::<Vec<Action<TestResource>>>())
        .with_index(index)
        .with_doc_type(ES_TYPE)
        .send()
    }

    fn delete(mut es: &mut Client, id: &str, index: &str) -> Result<DeleteResult, EsError> {
      es.delete(index, ES_TYPE, id)
        .send()
    }

    fn reset_index(mut es: &mut Client, index: &str) -> Result<MappingResult, EsError> {
      MappingOperation::new(&mut es, index).send()
    }
  }
}
<|endoftext|>


<commit_before>fn main() {
}
<commit_msg>Stubbed out listeners<commit_after>extern crate piston;
extern crate string_telephone;
extern crate collections;

use collections::str::{Slice, Owned};
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, NoWindow};
use string_telephone::{Server, ConnectionConfig, UserPacket};

fn deserializer(message: &Vec<u8>) -> String {
    match String::from_utf8_lossy(message.as_slice()) {
        Slice(slice) => slice.to_string(),
        Owned(item) => item
    }
}

fn serializer(packet: &String) -> Vec<u8> {
    packet.clone().into_bytes()
}

fn main() {
    let mut window = NoWindow::new(WindowSettings {
        title: "SuperMegaTag".to_string(),
        size: [0u32, 0u32],
        samples: 0,
        fullscreen: false,
        exit_on_esc: true,
    });

    let game_iter_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: 10,
        packet_deserializer: deserializer,
        packet_serializer: serializer
    };

    let mut server = match Server::new(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 8869}, settings) {
        Ok(server) => {
            println!("Listening on {}", server.addr);
            server
        },
        Err(e) => fail!("Failed to start listening - {}", e)
    };

    for e in EventIterator::new(&mut window, &game_iter_settings) {
        loop {
            loop {
                match server.poll() {
                    Some((UserPacket(packet), _)) => {
                        server.send_to_all(&packet);
                    },
                    Some(_) => (),
                    None => break
                }
            };
            let culled = server.cull();
            if culled.len() > 0 {
                println!("{}", culled);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::io::Write;
use std::fmt::Display;
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use {Matcher, SERVER_ADDRESS, Request, Mock};

impl Mock {
    fn method_matches(&self, request: &Request) -> bool {
        self.method == request.method
    }

    fn path_matches(&self, request: &Request) -> bool {
        self.path == request.path
    }

    fn headers_match(&self, request: &Request) -> bool {
        for &(ref field, ref value) in &self.headers {
            match request.find_header(field) {
                Some(request_header_value) => {
                    if value == request_header_value { continue }

                    return false
                },
                None => {
                    if value == &Matcher::Missing { continue }

                    return false
                },
            }
        }

        true
    }

    fn body_matches(&self, request: &Request) -> bool {
        self.body == String::from_utf8_lossy(&request.body).into_owned()
    }
}

impl<'a> PartialEq<Request> for &'a mut Mock {
    fn eq(&self, other: &Request) -> bool {
        self.method_matches(other)
            && self.path_matches(other)
            && self.headers_match(other)
            && self.body_matches(other)
    }
}

pub struct State {
    pub mocks: Vec<Mock>,
    pub unmatched_requests: Vec<Request>,
}

impl Default for State {
    fn default() -> Self {
        State {
            mocks: Vec::new(),
            unmatched_requests: Vec::new(),
        }
    }
}

lazy_static! {
    pub static ref STATE: Arc<Mutex<State>> = Arc::new(Mutex::new(State::default()));
}

pub fn try_start() {
    if is_listening() { return }

    start()
}

fn start() {
    thread::spawn(move || {
        let listener = TcpListener::bind(SERVER_ADDRESS).unwrap();
        for stream in listener.incoming() {
            match stream {
                Ok(mut stream) => {
                    let request = Request::from(&mut stream);
                    if request.is_ok() {
                        handle_request(request, stream);
                    } else {
                        let message = request.error().map_or("Could not parse the request.", |err| err.as_str());
                        respond_with_error(stream, message);
                    }
                },
                Err(_) => {},
            }
        }
    });

    while !is_listening() {}
}

fn is_listening() -> bool {
    TcpStream::connect(SERVER_ADDRESS).is_ok()
}

fn handle_request(request: Request, stream: TcpStream) {
    handle_match_mock(request, stream);
}

fn handle_match_mock(request: Request, stream: TcpStream) {
    let found;

    let state_mutex = STATE.clone();
    let mut state = state_mutex.lock().unwrap();

    match state.mocks.iter_mut().rev().find(|mock| mock == &request) {
        Some(mut mock) => {
            found = true;

            mock.hits = mock.hits + 1;

            respond_with_mock(stream, &mock)
        },
        None => {
            found = false;

            respond_with_mock_not_found(stream);
        }
    }

    if !found { state.unmatched_requests.push(request); }
}

fn respond<S: Display>(mut stream: TcpStream, status: S, headers: Option<&str>, body: Option<&str>) {
    let mut response = format!("HTTP/1.1 {}\r\n", status);

    if let Some(headers) = headers {
        response.push_str(headers);
    }

    if let Some(body) = body {
        response.push_str(&format!("content-length: {}\r\n\r\n{}", body.len(), body));
    } else {
        response.push_str("\r\n");
    }

    let _ = stream.write(response.as_bytes());
}

fn respond_with_mock(stream: TcpStream, mock: &Mock) {
    let mut headers = String::new();
    for &(ref key, ref value) in &mock.response.headers {
        headers.push_str(key);
        headers.push_str(": ");
        headers.push_str(value);
        headers.push_str("\r\n");
    }

    respond(stream, &mock.response.status, Some(&headers), Some(&mock.response.body));
}

fn respond_with_mock_not_found(stream: TcpStream) {
    respond(stream, "501 Not Implemented", None, None);
}

fn respond_with_error(stream: TcpStream, message: &str) {
    respond(stream, "422 Unprocessable Entity", None, Some(message));
}
<commit_msg>bind server address once<commit_after>use std::thread;
use std::io::Write;
use std::fmt::Display;
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use {Matcher, SERVER_ADDRESS, Request, Mock};

impl Mock {
    fn method_matches(&self, request: &Request) -> bool {
        self.method == request.method
    }

    fn path_matches(&self, request: &Request) -> bool {
        self.path == request.path
    }

    fn headers_match(&self, request: &Request) -> bool {
        for &(ref field, ref value) in &self.headers {
            match request.find_header(field) {
                Some(request_header_value) => {
                    if value == request_header_value { continue }

                    return false
                },
                None => {
                    if value == &Matcher::Missing { continue }

                    return false
                },
            }
        }

        true
    }

    fn body_matches(&self, request: &Request) -> bool {
        self.body == String::from_utf8_lossy(&request.body).into_owned()
    }
}

impl<'a> PartialEq<Request> for &'a mut Mock {
    fn eq(&self, other: &Request) -> bool {
        self.method_matches(other)
            && self.path_matches(other)
            && self.headers_match(other)
            && self.body_matches(other)
    }
}

pub struct State {
    pub is_listening: bool,
    pub mocks: Vec<Mock>,
    pub unmatched_requests: Vec<Request>,
}

impl Default for State {
    fn default() -> Self {
        State {
            is_listening: is_listening(),
            mocks: Vec::new(),
            unmatched_requests: Vec::new(),
        }
    }
}

lazy_static! {
    pub static ref STATE: Arc<Mutex<State>> = Arc::new(Mutex::new(State::default()));
}

pub fn try_start() {
    if is_listening() { return }

    start()
}

fn start() {

    let state_mutex = STATE.clone();
    let mut state = state_mutex.lock().unwrap();

    if state.is_listening {
        return
    }

    thread::spawn(move || {
        let listener = TcpListener::bind(SERVER_ADDRESS).unwrap();
        for stream in listener.incoming() {
            match stream {
                Ok(mut stream) => {
                    let request = Request::from(&mut stream);
                    if request.is_ok() {
                        handle_request(request, stream);
                    } else {
                        let message = request.error().map_or("Could not parse the request.", |err| err.as_str());
                        respond_with_error(stream, message);
                    }
                },
                Err(_) => {},
            }
        }
    });

    while !is_listening() {}
    state.is_listening = true;
}

fn is_listening() -> bool {
    TcpStream::connect(SERVER_ADDRESS).is_ok()
}

fn handle_request(request: Request, stream: TcpStream) {
    handle_match_mock(request, stream);
}

fn handle_match_mock(request: Request, stream: TcpStream) {
    let found;

    let state_mutex = STATE.clone();
    let mut state = state_mutex.lock().unwrap();

    match state.mocks.iter_mut().rev().find(|mock| mock == &request) {
        Some(mut mock) => {
            found = true;

            mock.hits = mock.hits + 1;

            respond_with_mock(stream, &mock)
        },
        None => {
            found = false;

            respond_with_mock_not_found(stream);
        }
    }

    if !found { state.unmatched_requests.push(request); }
}

fn respond<S: Display>(mut stream: TcpStream, status: S, headers: Option<&str>, body: Option<&str>) {
    let mut response = format!("HTTP/1.1 {}\r\n", status);

    if let Some(headers) = headers {
        response.push_str(headers);
    }

    if let Some(body) = body {
        response.push_str(&format!("content-length: {}\r\n\r\n{}", body.len(), body));
    } else {
        response.push_str("\r\n");
    }

    let _ = stream.write(response.as_bytes());
}

fn respond_with_mock(stream: TcpStream, mock: &Mock) {
    let mut headers = String::new();
    for &(ref key, ref value) in &mock.response.headers {
        headers.push_str(key);
        headers.push_str(": ");
        headers.push_str(value);
        headers.push_str("\r\n");
    }

    respond(stream, &mock.response.status, Some(&headers), Some(&mock.response.body));
}

fn respond_with_mock_not_found(stream: TcpStream) {
    respond(stream, "501 Not Implemented", None, None);
}

fn respond_with_error(stream: TcpStream, message: &str) {
    respond(stream, "422 Unprocessable Entity", None, Some(message));
}
<|endoftext|>


<commit_before>extern crate easy_strings;

pub use self::easy_strings::{EZString, ez};

// Example of some obsolete functions

pub fn upper(s : &EZString) -> EZString {
    s.to_uppercase()
}

pub fn lower(s : &EZString) -> EZString {
    s.to_lowercase()
}
<commit_msg>Add some builtins in prustle::string<commit_after>extern crate easy_strings;

pub use self::easy_strings::{EZString, ez};

// Example of some obsolete functions

pub fn upper(s : &EZString) -> EZString {
    s.to_uppercase()
}

pub fn lower(s : &EZString) -> EZString {
    s.to_lowercase()
}

// Some global builtins that are not locale-dependent:

#[allow(non_upper_case_globals)]
pub static ascii_letter: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

#[allow(non_upper_case_globals)]
pub static ascii_lowercase: &'static str = "abcdefghijklmnopqrstuvwxyz";

#[allow(non_upper_case_globals)]
pub static ascii_upppecase: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

#[allow(non_upper_case_globals)]
pub static digits: &'static str = "0123456789";

#[allow(non_upper_case_globals)]
pub static hexdigits: &'static str = "0123456789abcdefABCDEF";

#[allow(non_upper_case_globals)]
pub static octdigits: &'static str = "01234567";
<|endoftext|>


<commit_before>use error::Error;
use summary::Summary;

/// The results and parameters of a two-sided, unequal-variances t-test.
pub struct TTest {
    pub p: f64,
    pub t: f64,
    pub df: f64,
}

pub fn t_test_2_sided(t: f64, df: f64) -> Result<TTest, Error> {
    let p = 1.0 - t_atv(t.abs(), df as f64)?;

    Ok(TTest { df, p, t })
}

/// Conduct a two-sided t-test that does not assume equal population variances.
pub fn welch_t_test(s1: &Summary, s2: &Summary) -> Result<TTest, Error> {
    let (t, df) = welch_t_statistic(s1, s2);

    t_test_2_sided(t, df)
}

fn welch_t_statistic(s1: &Summary, s2: &Summary) -> (f64, f64) {
    let n1 = s1.size();
    let m1 = s1.mean();
    let var1 = s1.unbiased_variance();

    let n2 = s2.size();
    let m2 = s2.mean();
    let var2 = s2.unbiased_variance();

    let s_delta_bar = ((var1 / n1) + (var2 / n2)).sqrt();
    let t = (m1 - m2) / s_delta_bar;

    let df = welch_satterthwaite_df(var1, n1, var2, n2);

    (t, df)
}

/// Degrees of freedom, approximated using the Welch-Satterthwaite equation [1].
///
/// [1]: http://www.itl.nist.gov/div898/handbook/mpc/section5/mpc571.htm
fn welch_satterthwaite_df(var1: f64, n1: f64, var2: f64, n2: f64) -> f64 {
    let df1 = n1 - 1.0;
    let df2 = n2 - 1.0;

    let num = ((var1 / n1) + (var2 / n2)).powi(2);
    let den = var1.powi(2) / (n1.powi(2) * df1) + var2.powi(2) / (n2.powi(2) * df2);
    let appx = num / den;

    appx
}

/// The definite integral of the density function of Student's t-distribution
/// over an interval [-t, t]. Also called the A(t|ν) function.
///
/// See equation 6.4.9 in [1].
///
/// [1]: "Numerical Recipes in C", 2nd Ed., p. 228
fn t_atv(t: f64, df: f64) -> Result<f64, Error> {
    use num;

    let x = df / (df + t.powi(2));
    let a = 0.5 * df;
    let b = 0.5;
    let ib = num::inc_beta(x, a, b)?;

    Ok(1.0 - ib)
}
<commit_msg>Remove unnecessary `pub` visibility<commit_after>use error::Error;
use summary::Summary;

/// The results and parameters of a two-sided, unequal-variances t-test.
pub struct TTest {
    pub p: f64,
    pub t: f64,
    pub df: f64,
}

fn t_test_2_sided(t: f64, df: f64) -> Result<TTest, Error> {
    let p = 1.0 - t_atv(t.abs(), df as f64)?;

    Ok(TTest { df, p, t })
}

/// Conduct a two-sided t-test that does not assume equal population variances.
pub fn welch_t_test(s1: &Summary, s2: &Summary) -> Result<TTest, Error> {
    let (t, df) = welch_t_statistic(s1, s2);

    t_test_2_sided(t, df)
}

fn welch_t_statistic(s1: &Summary, s2: &Summary) -> (f64, f64) {
    let n1 = s1.size();
    let m1 = s1.mean();
    let var1 = s1.unbiased_variance();

    let n2 = s2.size();
    let m2 = s2.mean();
    let var2 = s2.unbiased_variance();

    let s_delta_bar = ((var1 / n1) + (var2 / n2)).sqrt();
    let t = (m1 - m2) / s_delta_bar;

    let df = welch_satterthwaite_df(var1, n1, var2, n2);

    (t, df)
}

/// Degrees of freedom, approximated using the Welch-Satterthwaite equation [1].
///
/// [1]: http://www.itl.nist.gov/div898/handbook/mpc/section5/mpc571.htm
fn welch_satterthwaite_df(var1: f64, n1: f64, var2: f64, n2: f64) -> f64 {
    let df1 = n1 - 1.0;
    let df2 = n2 - 1.0;

    let num = ((var1 / n1) + (var2 / n2)).powi(2);
    let den = var1.powi(2) / (n1.powi(2) * df1) + var2.powi(2) / (n2.powi(2) * df2);
    let appx = num / den;

    appx
}

/// The definite integral of the density function of Student's t-distribution
/// over an interval [-t, t]. Also called the A(t|ν) function.
///
/// See equation 6.4.9 in [1].
///
/// [1]: "Numerical Recipes in C", 2nd Ed., p. 228
fn t_atv(t: f64, df: f64) -> Result<f64, Error> {
    use num;

    let x = df / (df + t.powi(2));
    let a = 0.5 * df;
    let b = 0.5;
    let ib = num::inc_beta(x, a, b)?;

    Ok(1.0 - ib)
}
<|endoftext|>