<commit_before>//! Implementation of the `import!` macro.

use std::any::Any;
use std::borrow::Cow;
use std::sync::{Arc, Mutex, RwLock};
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::{Path, PathBuf};

use base::ast::{Expr, Literal, SpannedExpr, TypedIdent};
use base::metadata::Metadata;
use base::pos;
use base::symbol::Symbol;
use vm::macros::{Error as MacroError, Macro, MacroExpander};
use vm::thread::{Thread, ThreadInternal};
use vm::internal::Value;
use super::{filename_to_module, Compiler};
use base::fnv::FnvMap;

quick_error! {
    /// Error type for the import macro
    #[derive(Debug)]
    pub enum Error {
        /// The importer found a cyclic dependency when loading files
        CyclicDependency(module: String) {
            description("Cyclic dependency")
            display("Module '{}' occurs in a cyclic dependency", module)
        }
        /// Generic message error
        String(message: String) {
            description(message)
            display("{}", message)
        }
        /// The importer could not load the imported file
        IO(err: io::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
    }
}

macro_rules! std_libs {
    ($($file: expr),*) => {
        [$((concat!("std/", $file, ".glu"), include_str!(concat!("../std/", $file, ".glu")))),*]
    }
}
// Include the standard library distribution in the binary
static STD_LIBS: [(&'static str, &'static str); 7] = std_libs!(
    "prelude",
    "types",
    "map",
    "string",
    "state",
    "test",
    "writer"
);

pub trait Importer: Any + Clone + Sync + Send {
    fn import(
        &self,
        compiler: &mut Compiler,
        vm: &Thread,
        modulename: &str,
        input: &str,
        expr: SpannedExpr<Symbol>,
    ) -> Result<(), MacroError>;
}

#[derive(Clone)]
pub struct DefaultImporter;
impl Importer for DefaultImporter {
    fn import(
        &self,
        compiler: &mut Compiler,
        vm: &Thread,
        modulename: &str,
        input: &str,
        expr: SpannedExpr<Symbol>,
    ) -> Result<(), MacroError> {
        use compiler_pipeline::*;

        MacroValue { expr: expr }
            .load_script(compiler, vm, modulename, input, None)
            .sync_or_error()?;
        Ok(())
    }
}

#[derive(Clone, Default)]
pub struct CheckImporter(pub Arc<Mutex<FnvMap<String, SpannedExpr<Symbol>>>>);
impl CheckImporter {
    pub fn new() -> CheckImporter {
        CheckImporter::default()
    }
}
impl Importer for CheckImporter {
    fn import(
        &self,
        compiler: &mut Compiler,
        vm: &Thread,
        module_name: &str,
        input: &str,
        expr: SpannedExpr<Symbol>,
    ) -> Result<(), MacroError> {
        use compiler_pipeline::*;

        let macro_value = MacroValue { expr: expr };
        let TypecheckValue { expr, typ } = macro_value.typecheck(compiler, vm, module_name, input)?;
        self.0.lock().unwrap().insert(module_name.into(), expr);
        let metadata = Metadata::default();
        // Insert a global to ensure the globals type can be looked up
        vm.global_env()
            .set_global(Symbol::from(module_name), typ, metadata, Value::Int(0))?;
        Ok(())
    }
}

/// Macro which rewrites occurances of `import! "filename"` to a load of that file if it is not
/// already loaded and then a global access to the loaded module
pub struct Import<I = DefaultImporter> {
    pub paths: RwLock<Vec<PathBuf>>,
    pub importer: I,
}

impl<I> Import<I> {
    /// Creates a new import macro
    pub fn new(importer: I) -> Import<I> {
        Import {
            paths: RwLock::new(vec![PathBuf::from(".")]),
            importer: importer,
        }
    }

    /// Adds a path to the list of paths which the importer uses to find files
    pub fn add_path<P: Into<PathBuf>>(&self, path: P) {
        self.paths.write().unwrap().push(path.into());
    }

    pub fn read_file<P>(&self, filename: P) -> Result<Cow<'static, str>, MacroError>
    where
        P: AsRef<Path>,
    {
        self.read_file_(filename.as_ref())
    }
    fn read_file_(&self, filename: &Path) -> Result<Cow<'static, str>, MacroError> {
        let mut buffer = String::new();

        // Retrieve the source, first looking in the standard library included in the
        // binary
        let std_file = filename
            .to_str()
            .and_then(|filename| STD_LIBS.iter().find(|tup| tup.0 == filename));
        Ok(match std_file {
            Some(tup) => Cow::Borrowed(tup.1),
            None => {
                let file = self.paths
                    .read()
                    .unwrap()
                    .iter()
                    .filter_map(|p| {
                        let base = p.join(filename);
                        match File::open(&base) {
                            Ok(file) => Some(file),
                            Err(_) => None,
                        }
                    })
                    .next();
                let mut file = file.ok_or_else(|| {
                    Error::String(format!("Could not find file '{}'", filename.display()))
                })?;
                file.read_to_string(&mut buffer)?;
                Cow::Owned(buffer)
            }
        })
    }
}

fn get_state<'m>(macros: &'m mut MacroExpander) -> &'m mut State {
    macros
        .state
        .entry(String::from("import"))
        .or_insert_with(|| {
            Box::new(State {
                visited: Vec::new(),
            })
        })
        .downcast_mut::<State>()
        .unwrap()
}

struct State {
    visited: Vec<String>,
}

impl<I> Macro for Import<I>
where
    I: Importer,
{
    fn expand(
        &self,
        macros: &mut MacroExpander,
        args: &mut [SpannedExpr<Symbol>],
    ) -> Result<SpannedExpr<Symbol>, MacroError> {
        use compiler_pipeline::*;

        if args.len() != 1 {
            return Err(
                Error::String("Expected import to get 1 argument".into()).into(),
            );
        }
        match args[0].value {
            Expr::Literal(Literal::String(ref filename)) => {
                let vm = macros.vm;

                let modulename = filename_to_module(filename);
                // Only load the script if it is not already loaded
                let name = Symbol::from(&*modulename);
                debug!("Import '{}' {:?}", modulename, get_state(macros).visited);
                if !vm.global_env().global_exists(&modulename) {
                    {
                        let state = get_state(macros);
                        if state.visited.iter().any(|m| **m == **filename) {
                            return Err(Error::CyclicDependency(filename.clone()).into());
                        }
                        state.visited.push(filename.clone());
                    }

                    // Retrieve the source, first looking in the standard library included in the
                    // binary
                    let file_contents = self.read_file(filename)?;

                    let mut compiler = Compiler::new().implicit_prelude(modulename != "std.types");
                    let errors = macros.errors.len();
                    let macro_result =
                        file_contents.expand_macro_with(&mut compiler, macros, &modulename)?;
                    if errors != macros.errors.len() {
                        // If macro expansion of the imported module fails we need to stop
                        // compilation of that module. To return an error we return one of the
                        // already emitted errors (which will be pushed back after this function
                        // returns)
                        if let Some(err) = macros.errors.pop() {
                            return Err(err);
                        }
                    }
                    get_state(macros).visited.pop();
                    self.importer.import(
                        &mut compiler,
                        vm,
                        &modulename,
                        &file_contents,
                        macro_result.expr,
                    )?;
                }
                // FIXME Does not handle shadowing
                Ok(pos::spanned(
                    args[0].span,
                    Expr::Ident(TypedIdent::new(name)),
                ))
            }
            _ => Err(
                Error::String("Expected a string literal to import".into()).into(),
            ),
        }
    }
}
<commit_msg>Update included gluon libs<commit_after>//! Implementation of the `import!` macro.

use std::any::Any;
use std::borrow::Cow;
use std::sync::{Arc, Mutex, RwLock};
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::{Path, PathBuf};

use base::ast::{Expr, Literal, SpannedExpr, TypedIdent};
use base::metadata::Metadata;
use base::pos;
use base::symbol::Symbol;
use vm::macros::{Error as MacroError, Macro, MacroExpander};
use vm::thread::{Thread, ThreadInternal};
use vm::internal::Value;
use super::{filename_to_module, Compiler};
use base::fnv::FnvMap;

quick_error! {
    /// Error type for the import macro
    #[derive(Debug)]
    pub enum Error {
        /// The importer found a cyclic dependency when loading files
        CyclicDependency(module: String) {
            description("Cyclic dependency")
            display("Module '{}' occurs in a cyclic dependency", module)
        }
        /// Generic message error
        String(message: String) {
            description(message)
            display("{}", message)
        }
        /// The importer could not load the imported file
        IO(err: io::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
    }
}

macro_rules! std_libs {
    ($($file: expr),*) => {
        [$((concat!("std/", $file, ".glu"), include_str!(concat!("../std/", $file, ".glu")))),*]
    }
}
// Include the standard library distribution in the binary
static STD_LIBS: [(&str, &str); 15] = std_libs!(
    "prelude",
    "types",

    "bool",
    "char",
    "list",
    "map",
    "option",
    "parser",
    "result",
    "state",
    "stream",
    "string",
    "test",
    "unit",
    "writer"
);

pub trait Importer: Any + Clone + Sync + Send {
    fn import(
        &self,
        compiler: &mut Compiler,
        vm: &Thread,
        modulename: &str,
        input: &str,
        expr: SpannedExpr<Symbol>,
    ) -> Result<(), MacroError>;
}

#[derive(Clone)]
pub struct DefaultImporter;
impl Importer for DefaultImporter {
    fn import(
        &self,
        compiler: &mut Compiler,
        vm: &Thread,
        modulename: &str,
        input: &str,
        expr: SpannedExpr<Symbol>,
    ) -> Result<(), MacroError> {
        use compiler_pipeline::*;

        MacroValue { expr: expr }
            .load_script(compiler, vm, modulename, input, None)
            .sync_or_error()?;
        Ok(())
    }
}

#[derive(Clone, Default)]
pub struct CheckImporter(pub Arc<Mutex<FnvMap<String, SpannedExpr<Symbol>>>>);
impl CheckImporter {
    pub fn new() -> CheckImporter {
        CheckImporter::default()
    }
}
impl Importer for CheckImporter {
    fn import(
        &self,
        compiler: &mut Compiler,
        vm: &Thread,
        module_name: &str,
        input: &str,
        expr: SpannedExpr<Symbol>,
    ) -> Result<(), MacroError> {
        use compiler_pipeline::*;

        let macro_value = MacroValue { expr: expr };
        let TypecheckValue { expr, typ } = macro_value.typecheck(compiler, vm, module_name, input)?;
        self.0.lock().unwrap().insert(module_name.into(), expr);
        let metadata = Metadata::default();
        // Insert a global to ensure the globals type can be looked up
        vm.global_env().set_global(
            Symbol::from(module_name),
            typ,
            metadata,
            Value::Int(0),
        )?;
        Ok(())
    }
}

/// Macro which rewrites occurances of `import! "filename"` to a load of that file if it is not
/// already loaded and then a global access to the loaded module
pub struct Import<I = DefaultImporter> {
    pub paths: RwLock<Vec<PathBuf>>,
    pub importer: I,
}

impl<I> Import<I> {
    /// Creates a new import macro
    pub fn new(importer: I) -> Import<I> {
        Import {
            paths: RwLock::new(vec![PathBuf::from(".")]),
            importer: importer,
        }
    }

    /// Adds a path to the list of paths which the importer uses to find files
    pub fn add_path<P: Into<PathBuf>>(&self, path: P) {
        self.paths.write().unwrap().push(path.into());
    }

    pub fn read_file<P>(&self, filename: P) -> Result<Cow<'static, str>, MacroError>
    where
        P: AsRef<Path>,
    {
        self.read_file_(filename.as_ref())
    }
    fn read_file_(&self, filename: &Path) -> Result<Cow<'static, str>, MacroError> {
        let mut buffer = String::new();

        // Retrieve the source, first looking in the standard library included in the
        // binary
        let std_file = filename.to_str().and_then(|filename| {
            STD_LIBS.iter().find(|tup| tup.0 == filename)
        });
        Ok(match std_file {
            Some(tup) => Cow::Borrowed(tup.1),
            None => {
                let file = self.paths
                    .read()
                    .unwrap()
                    .iter()
                    .filter_map(|p| {
                        let base = p.join(filename);
                        match File::open(&base) {
                            Ok(file) => Some(file),
                            Err(_) => None,
                        }
                    })
                    .next();
                let mut file = file.ok_or_else(|| {
                    Error::String(format!("Could not find file '{}'", filename.display()))
                })?;
                file.read_to_string(&mut buffer)?;
                Cow::Owned(buffer)
            }
        })
    }
}

fn get_state<'m>(macros: &'m mut MacroExpander) -> &'m mut State {
    macros
        .state
        .entry(String::from("import"))
        .or_insert_with(|| Box::new(State { visited: Vec::new() }))
        .downcast_mut::<State>()
        .unwrap()
}

struct State {
    visited: Vec<String>,
}

impl<I> Macro for Import<I>
where
    I: Importer,
{
    fn expand(
        &self,
        macros: &mut MacroExpander,
        args: &mut [SpannedExpr<Symbol>],
    ) -> Result<SpannedExpr<Symbol>, MacroError> {
        use compiler_pipeline::*;

        if args.len() != 1 {
            return Err(
                Error::String("Expected import to get 1 argument".into()).into(),
            );
        }
        match args[0].value {
            Expr::Literal(Literal::String(ref filename)) => {
                let vm = macros.vm;

                let modulename = filename_to_module(filename);
                // Only load the script if it is not already loaded
                let name = Symbol::from(&*modulename);
                debug!("Import '{}' {:?}", modulename, get_state(macros).visited);
                if !vm.global_env().global_exists(&modulename) {
                    {
                        let state = get_state(macros);
                        if state.visited.iter().any(|m| **m == **filename) {
                            return Err(Error::CyclicDependency(filename.clone()).into());
                        }
                        state.visited.push(filename.clone());
                    }

                    // Retrieve the source, first looking in the standard library included in the
                    // binary
                    let file_contents = self.read_file(filename)?;

                    let mut compiler = Compiler::new().implicit_prelude(modulename != "std.types");
                    let errors = macros.errors.len();
                    let macro_result = file_contents.expand_macro_with(
                        &mut compiler,
                        macros,
                        &modulename,
                    )?;
                    if errors != macros.errors.len() {
                        // If macro expansion of the imported module fails we need to stop
                        // compilation of that module. To return an error we return one of the
                        // already emitted errors (which will be pushed back after this function
                        // returns)
                        if let Some(err) = macros.errors.pop() {
                            return Err(err);
                        }
                    }
                    get_state(macros).visited.pop();
                    self.importer.import(
                        &mut compiler,
                        vm,
                        &modulename,
                        &file_contents,
                        macro_result.expr,
                    )?;
                }
                // FIXME Does not handle shadowing
                Ok(pos::spanned(
                    args[0].span,
                    Expr::Ident(TypedIdent::new(name)),
                ))
            }
            _ => Err(
                Error::String("Expected a string literal to import".into()).into(),
            ),
        }
    }
}
<|endoftext|>


<commit_before>pub mod dim4 {
    use bounding_volume::AABB;
    use geom::{Ball, Box, Cylinder, Cone, Plane, Compound, Triangle, Mesh, Geom};
    use nalgebra::na::{Vec4, Mat4, Iso4};

    type LV<N> = Vec4<N>;
    type II<N> = Mat4<N>;
    type M<N>  = Iso4<N>;

    pub type Ball4d<N>         = Ball<N>;
    pub type Box4d<N>          = Box<N, LV<N>>;
    pub type Cylinder4d<N>     = Cylinder<N>;
    pub type Cone4d<N>         = Cone<N>;
    pub type Plane4d<N>        = Plane<N, LV<N>>;
    pub type Compound4d<N>     = Compound<N, LV<N>, M<N>, II<N>>;
    pub type Triangle4d<N>     = Triangle<N, LV<N>>;
    pub type Segment4d<N>      = Triangle<N, LV<N>>;
    pub type TriangleMesh4d<N> = Mesh<N, LV<N>, M<N>, II<N>, Triangle4d<N>>;
    pub type LineStrip4d<N>    = Mesh<N, LV<N>, M<N>, II<N>, Segment4d<N>>;
    pub type Geom4dRef<'a, N>  = &'a Geom<N, LV<N>, M<N>, II<N>>;
    pub type Geom4d<N>         = ~Geom<N, LV<N>, M<N>, II<N>>;
    pub type AABB4d<N>         = AABB<N, LV<N>>;
}

pub mod dim3 {
    use bounding_volume::AABB;
    use geom::{Ball, Box, Cylinder, Cone, Plane, Compound, Triangle, Mesh, Geom};
    use nalgebra::na::{Vec3, Mat3, Iso3};

    type LV<N> = Vec3<N>;
    type II<N> = Mat3<N>;
    type M<N>  = Iso3<N>;

    pub type Ball3d<N>         = Ball<N>;
    pub type Box3d<N>          = Box<N, LV<N>>;
    pub type Cylinder3d<N>     = Cylinder<N>;
    pub type Cone3d<N>         = Cone<N>;
    pub type Plane3d<N>        = Plane<N, LV<N>>;
    pub type Compound3d<N>     = Compound<N, LV<N>, M<N>, II<N>>;
    pub type Triangle3d<N>     = Triangle<N, LV<N>>;
    pub type Segment3d<N>      = Triangle<N, LV<N>>;
    pub type TriangleMesh3d<N> = Mesh<N, LV<N>, M<N>, II<N>, Triangle3d<N>>;
    pub type LineStrip3d<N>    = Mesh<N, LV<N>, M<N>, II<N>, Segment3d<N>>;
    pub type Geom3dRef<'a, N>  = &'a Geom<N, LV<N>, M<N>, II<N>>;
    pub type Geom3d<N>         = ~Geom<N, LV<N>, M<N>, II<N>>;
    pub type AABB3d<N>         = AABB<N, LV<N>>;
}

pub mod dim2 {
    use bounding_volume::AABB;
    use geom::{Ball, Box, Cylinder, Cone, Plane, Compound, Triangle, Mesh, Geom};
    use nalgebra::na::{Vec2, Mat2, Iso2};

    type LV<N> = Vec2<N>;
    type II<N> = Mat2<N>;
    type M<N>  = Iso2<N>;

    pub type Ball2d<N>         = Ball<N>;
    pub type Box2d<N>          = Box<N, LV<N>>;
    pub type Cylinder2d<N>     = Cylinder<N>;
    pub type Cone2d<N>         = Cone<N>;
    pub type Plane2d<N>        = Plane<N, LV<N>>;
    pub type Compound2d<N>     = Compound<N, LV<N>, M<N>, II<N>>;
    pub type Triangle2d<N>     = Triangle<N, LV<N>>;
    pub type Segment2d<N>      = Triangle<N, LV<N>>;
    pub type TriangleMesh2d<N> = Mesh<N, LV<N>, M<N>, II<N>, Triangle2d<N>>;
    pub type LineStrip2d<N>    = Mesh<N, LV<N>, M<N>, II<N>, Segment2d<N>>;
    pub type Geom2dRef<'a, N>  = &'a Geom<N, LV<N>, M<N>, II<N>>;
    pub type Geom2d<N>         = ~Geom<N, LV<N>, M<N>, II<N>>;
    pub type AABB2d<N>         = AABB<N, LV<N>>;
}
<commit_msg>Fix 2d aliases.<commit_after>pub mod dim4 {
    use bounding_volume::AABB;
    use geom::{Ball, Box, Cylinder, Cone, Plane, Compound, Triangle, Mesh, Geom};
    use nalgebra::na::{Vec4, Mat4, Iso4};

    type LV<N> = Vec4<N>;
    type II<N> = Mat4<N>;
    type M<N>  = Iso4<N>;

    pub type Ball4d<N>         = Ball<N>;
    pub type Box4d<N>          = Box<N, LV<N>>;
    pub type Cylinder4d<N>     = Cylinder<N>;
    pub type Cone4d<N>         = Cone<N>;
    pub type Plane4d<N>        = Plane<N, LV<N>>;
    pub type Compound4d<N>     = Compound<N, LV<N>, M<N>, II<N>>;
    pub type Triangle4d<N>     = Triangle<N, LV<N>>;
    pub type Segment4d<N>      = Triangle<N, LV<N>>;
    pub type TriangleMesh4d<N> = Mesh<N, LV<N>, M<N>, II<N>, Triangle4d<N>>;
    pub type LineStrip4d<N>    = Mesh<N, LV<N>, M<N>, II<N>, Segment4d<N>>;
    pub type Geom4dRef<'a, N>  = &'a Geom<N, LV<N>, M<N>, II<N>>;
    pub type Geom4d<N>         = ~Geom<N, LV<N>, M<N>, II<N>>;
    pub type AABB4d<N>         = AABB<N, LV<N>>;
}

pub mod dim3 {
    use bounding_volume::AABB;
    use geom::{Ball, Box, Cylinder, Cone, Plane, Compound, Triangle, Mesh, Geom};
    use nalgebra::na::{Vec3, Mat3, Iso3};

    type LV<N> = Vec3<N>;
    type II<N> = Mat3<N>;
    type M<N>  = Iso3<N>;

    pub type Ball3d<N>         = Ball<N>;
    pub type Box3d<N>          = Box<N, LV<N>>;
    pub type Cylinder3d<N>     = Cylinder<N>;
    pub type Cone3d<N>         = Cone<N>;
    pub type Plane3d<N>        = Plane<N, LV<N>>;
    pub type Compound3d<N>     = Compound<N, LV<N>, M<N>, II<N>>;
    pub type Triangle3d<N>     = Triangle<N, LV<N>>;
    pub type Segment3d<N>      = Triangle<N, LV<N>>;
    pub type TriangleMesh3d<N> = Mesh<N, LV<N>, M<N>, II<N>, Triangle3d<N>>;
    pub type LineStrip3d<N>    = Mesh<N, LV<N>, M<N>, II<N>, Segment3d<N>>;
    pub type Geom3dRef<'a, N>  = &'a Geom<N, LV<N>, M<N>, II<N>>;
    pub type Geom3d<N>         = ~Geom<N, LV<N>, M<N>, II<N>>;
    pub type AABB3d<N>         = AABB<N, LV<N>>;
}

pub mod dim2 {
    use bounding_volume::AABB;
    use geom::{Ball, Box, Cylinder, Cone, Plane, Compound, Triangle, Mesh, Geom};
    use nalgebra::na::{Mat1, Vec2, Iso2};

    type LV<N> = Vec2<N>;
    type II<N> = Mat1<N>;
    type M<N>  = Iso2<N>;

    pub type Ball2d<N>         = Ball<N>;
    pub type Box2d<N>          = Box<N, LV<N>>;
    pub type Cylinder2d<N>     = Cylinder<N>;
    pub type Cone2d<N>         = Cone<N>;
    pub type Plane2d<N>        = Plane<N, LV<N>>;
    pub type Compound2d<N>     = Compound<N, LV<N>, M<N>, II<N>>;
    pub type Triangle2d<N>     = Triangle<N, LV<N>>;
    pub type Segment2d<N>      = Triangle<N, LV<N>>;
    pub type TriangleMesh2d<N> = Mesh<N, LV<N>, M<N>, II<N>, Triangle2d<N>>;
    pub type LineStrip2d<N>    = Mesh<N, LV<N>, M<N>, II<N>, Segment2d<N>>;
    pub type Geom2dRef<'a, N>  = &'a Geom<N, LV<N>, M<N>, II<N>>;
    pub type Geom2d<N>         = ~Geom<N, LV<N>, M<N>, II<N>>;
    pub type AABB2d<N>         = AABB<N, LV<N>>;
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate httpd = "tiny-http";

use std::io::Command;

#[test]
#[ignore]
// TODO: obtain time
fn curl_bench() {
    let (server, port) = httpd::Server::new_with_random_port().unwrap();
    let num_requests = 10u;

    match Command::new("curl")
        .arg("-s")
        .arg(format!("http://localhost:{}/?[1-{}]", port, num_requests).as_slice())
        .output()
    {
        Ok(p) => p,
        Err(err) => return,       // ignoring test
    };
}
<commit_msg>Add two crashing benchmarks<commit_after>#![feature(phase)]

extern crate httpd = "tiny-http";
extern crate test;

use std::io::Command;

#[test]
#[ignore]
// TODO: obtain time
fn curl_bench() {
    let (server, port) = httpd::Server::new_with_random_port().unwrap();
    let num_requests = 10u;

    match Command::new("curl")
        .arg("-s")
        .arg(format!("http://localhost:{}/?[1-{}]", port, num_requests).as_slice())
        .output()
    {
        Ok(p) => p,
        Err(err) => return,       // ignoring test
    };
}

#[bench]
fn sequential_requests(bencher: &mut test::Bencher) {
    let (server, port) = httpd::Server::new_with_random_port().unwrap();

    let mut stream = std::io::net::tcp::TcpStream::connect("127.0.0.1", port).unwrap();

    bencher.auto_bench(|_| {
        write!(stream, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n");

        let request = server.recv().unwrap();

        assert!(request.get_method().equiv(&"get"));

        request.respond(httpd::Response::new_empty(httpd::StatusCode(204)));
    });
}

#[bench]
fn parallel_requests(bencher: &mut test::Bencher) {
    let (server, port) = httpd::Server::new_with_random_port().unwrap();

    bencher.bench_n(5, |_| {
        let mut streams = Vec::new();

        for _ in range(0u, 1000) {
            let mut stream = std::io::net::tcp::TcpStream::connect("127.0.0.1", port).unwrap();
            write!(stream, "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n");
            streams.push(stream);
        }

        loop {
            let request = match server.try_recv().unwrap() {
                None => break,
                Some(rq) => rq
            };

            assert!(request.get_method().equiv(&"get"));

            request.respond(httpd::Response::new_empty(httpd::StatusCode(204)));
        }
    });
}
<|endoftext|>


<commit_before>use crate::{generate::*, norm::Norm, types::*};
use ndarray::*;

#[derive(Debug, Clone)]
pub struct MGS<A> {
    dim: usize,
    q: Vec<Array1<A>>,
    r: Vec<Array1<A>>,
}

impl<A: Scalar + Lapack> MGS<A> {
    pub fn new(dim: usize) -> Self {
        Self {
            dim,
            q: Vec::new(),
            r: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dim
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>) -> A::Real
    where
        S: Data<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut a = a.into_owned();
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = a.dot(q);
            azip!(mut a, q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        self.r.push(coef);
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        nrm
    }

    pub fn get_q(&self) -> Array2<A> {
        hstack(&self.q).unwrap()
    }

    pub fn get_r(&self) -> Array2<A> {
        let len = self.len();
        let mut r = Array2::zeros((len, len));
        for i in 0..len {
            for j in 0..=i {
                r[(j, i)] = self.r[i][j];
            }
        }
        r
    }
}

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

    const N: usize = 5;

    #[test]
    fn new() {
        let mgs: MGS<f32> = MGS::new(N);
        assert_eq!(mgs.dim(), N);
        assert_eq!(mgs.len(), 0);
    }

    #[test]
    fn append_random() {
        let mut mgs: MGS<f64> = MGS::new(N);
        let a: Array2<f64> = random((N, 3));
        dbg!(&a);
        for col in a.axis_iter(Axis(1)) {
            let res = mgs.append(col);
            dbg!(res);
        }
        let q = mgs.get_q();
        dbg!(&q);
        let r = mgs.get_r();
        dbg!(&r);

        dbg!(q.dot(&r));
        close_l2(&q.dot(&r), &a, 1e-9).unwrap();

        dbg!(q.t().dot(&q));
        close_l2(&q.t().dot(&q), &Array2::eye(3), 1e-9).unwrap();
    }
}
<commit_msg>Add test for complex<commit_after>use crate::{generate::*, norm::Norm, types::*};
use ndarray::*;

#[derive(Debug, Clone)]
pub struct MGS<A> {
    dim: usize,
    q: Vec<Array1<A>>,
    r: Vec<Array1<A>>,
}

impl<A: Scalar + Lapack> MGS<A> {
    pub fn new(dim: usize) -> Self {
        Self {
            dim,
            q: Vec::new(),
            r: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dim
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>) -> A::Real
    where
        S: Data<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut a = a.into_owned();
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = a.dot(q);
            azip!(mut a, q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        self.r.push(coef);
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        nrm
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Array2<A> {
        hstack(&self.q).unwrap()
    }

    /// Get each vector norm and coefficients as R matrix
    pub fn get_r(&self) -> Array2<A> {
        let len = self.len();
        let mut r = Array2::zeros((len, len));
        for i in 0..len {
            for j in 0..=i {
                r[(j, i)] = self.r[i][j];
            }
        }
        r
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::assert::*;
    use rand::{distributions::Standard, prelude::*};

    const N: usize = 5;

    #[test]
    fn new() {
        let mgs: MGS<f32> = MGS::new(N);
        assert_eq!(mgs.dim(), N);
        assert_eq!(mgs.len(), 0);
    }

    fn test<A: Scalar + Lapack>(rtol: A::Real)
    where
        Standard: Distribution<A>,
    {
        let mut mgs: MGS<A> = MGS::new(N);
        let a: Array2<A> = crate::generate::random((N, 3));
        dbg!(&a);
        for col in a.axis_iter(Axis(1)) {
            let res = mgs.append(col);
            dbg!(res);
        }
        let q = mgs.get_q();
        dbg!(&q);
        let r = mgs.get_r();
        dbg!(&r);

        dbg!(q.dot(&r));
        close_l2(&q.dot(&r), &a, rtol).unwrap();

        dbg!(q.t().dot(&q));
        close_l2(&q.t().dot(&q), &Array2::eye(3), rtol).unwrap();
    }

    #[test]
    fn test_f32() {
        test::<f32>(1e-5);
    }

    #[test]
    fn test_c32() {
        test::<c32>(1e-5);
    }
}
<|endoftext|>


<commit_before>use std::error::Error;

pub trait AsDynError {
    fn as_dyn_error(&self) -> &(dyn Error + 'static);
}

impl<T: Error + 'static> AsDynError for T {
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}

impl AsDynError for dyn Error + 'static {
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}

impl AsDynError for dyn Error + Send + Sync + 'static {
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}
<commit_msg>Make the trivial as_dyn_error impls inlinable<commit_after>use std::error::Error;

pub trait AsDynError {
    fn as_dyn_error(&self) -> &(dyn Error + 'static);
}

impl<T: Error + 'static> AsDynError for T {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}

impl AsDynError for dyn Error + 'static {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}

impl AsDynError for dyn Error + Send + Sync + 'static {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}
<|endoftext|>


<commit_before>extern crate crates_index_diff;
extern crate tempdir;

use crates_index_diff::*;
use tempdir::TempDir;
use std::env;
use std::path::PathBuf;

const NUM_VERSIONS_AT_RECENT_COMMIT: usize = 39752;
const REV_ONE_ADDED: &'static str = "615c9c41942a3ba13e088fbcb1470c61b169a187";
const REV_RECENT_COMMIT: &'static str = REV_ONE_ADDED;
const REV_ONE_YANKED: &'static str = "8cf8fbad7876586ced34c4b778f6a80fadd2a59b";
const REV_ONE_UNYANKED: &'static str = "f8cb00181";
const REV_FIRST_COMMIT: &'static str = "a33de1c98";

#[test]
fn clone_if_needed() {
    let tmp = TempDir::new("new-index").unwrap();
    Index::at_path(tmp.path()).expect("successful clone to be created");
    Index::at_path(tmp.path()).expect("second instance re-uses existing clone");
}

fn make_index() -> (Index, TempDir) {
    let tmp = TempDir::new("new-index").unwrap();
    let index = Index::at_path(env::var("CRATES_INDEX_DIFF_TEST_EXISTING_INDEX")
            .map(PathBuf::from)
            .unwrap_or(tmp.path().to_owned()))
        .expect("successful clone");
    (index, tmp)
}

#[test]
fn quick_changes_since_last_fetch() {
    let (index, _) = make_index();
    let origin_master = || index.repository().find_reference("refs/remotes/origin/master").unwrap();
    index.last_seen_reference().and_then(|mut r| r.delete()).ok();
    let num_changes_since_first_commit = index.fetch_changes().unwrap().len();
    assert!(num_changes_since_first_commit >= NUM_VERSIONS_AT_RECENT_COMMIT);
    let mut seen_marker_ref = index.last_seen_reference().expect("must be created/update now");
    assert!(seen_marker_ref == origin_master());

    // reset to previous one
    seen_marker_ref.set_target(index.repository().revparse_single(REV_ONE_UNYANKED).unwrap().id(),
                    "resetting to previous commit")
        .expect("reset success");
    let num_seen_after_reset = index.fetch_changes().unwrap().len();
    assert!(seen_marker_ref == origin_master());
    assert!(num_seen_after_reset < num_changes_since_first_commit);
    assert!(num_seen_after_reset < NUM_VERSIONS_AT_RECENT_COMMIT);
    assert!(num_seen_after_reset > 1000);

    // nothing if there was no change
    assert_eq!(index.fetch_changes().unwrap().len(), 0);
}

fn changes_of(index: &Index, commit: &str) -> Vec<Crate> {
    index.changes(format!("{}~1^{{tree}}", commit), format!("{}", commit))
        .expect("id to be valid and diff OK")
}

#[test]
fn quick_traverse_unyanked_crates() {
    let (index, _) = make_index();

    let crates = changes_of(&index, REV_ONE_UNYANKED);
    assert_eq!(crates,
               vec![Crate {
                        name: "gfx_text".to_owned(),
                        state: ChangeType::Added,
                        version: "0.13.2".to_owned(),
                    }]);
}

#[test]
fn quick_traverse_yanked_crates() {
    let (index, _) = make_index();

    let crates = changes_of(&index, REV_ONE_YANKED);
    assert_eq!(crates,
               vec![Crate {
                        name: "sha3".to_owned(),
                        state: ChangeType::Yanked,
                        version: "0.0.0".to_owned(),
                    }]);
}

#[test]
fn quick_traverse_all_crates() {
    let (index, _) = make_index();
    let changes = index.changes(format!("{}", REV_FIRST_COMMIT),
                 format!("{}", REV_RECENT_COMMIT))
        .expect("id to be valid and diff OK");
    assert_eq!(changes.len(), NUM_VERSIONS_AT_RECENT_COMMIT);
}

#[test]
fn quick_traverse_added_crates() {
    let (index, _) = make_index();
    assert_eq!(index.changes("foo", REV_ONE_ADDED).is_err(), true);
    assert_eq!(index.changes(REV_ONE_ADDED, "bar").is_err(), true);

    let crates = changes_of(&index, REV_ONE_ADDED);
    assert_eq!(crates,
               vec![Crate {
                        name: "rpwg".to_owned(),
                        state: ChangeType::Added,
                        version: "0.1.0".to_owned(),
                    }]);
}
<commit_msg>test(index): remove duplicate<commit_after>extern crate crates_index_diff;
extern crate tempdir;

use crates_index_diff::*;
use tempdir::TempDir;
use std::env;
use std::path::PathBuf;

const NUM_VERSIONS_AT_RECENT_COMMIT: usize = 39752;
const REV_ONE_ADDED: &'static str = "615c9c41942a3ba13e088fbcb1470c61b169a187";
const REV_RECENT_COMMIT: &'static str = REV_ONE_ADDED;
const REV_ONE_YANKED: &'static str = "8cf8fbad7876586ced34c4b778f6a80fadd2a59b";
const REV_ONE_UNYANKED: &'static str = "f8cb00181";
const REV_FIRST_COMMIT: &'static str = "a33de1c98";

#[test]
fn clone_if_needed() {
    let tmp = TempDir::new("new-index").unwrap();
    Index::at_path(tmp.path()).expect("successful clone to be created");
    Index::at_path(tmp.path()).expect("second instance re-uses existing clone");
}

fn make_index() -> (Index, TempDir) {
    let tmp = TempDir::new("new-index").unwrap();
    let index = Index::at_path(env::var("CRATES_INDEX_DIFF_TEST_EXISTING_INDEX")
            .map(PathBuf::from)
            .unwrap_or(tmp.path().to_owned()))
        .expect("successful clone");
    (index, tmp)
}

#[test]
fn quick_changes_since_last_fetch() {
    let (index, _) = make_index();
    let origin_master = || index.repository().find_reference("refs/remotes/origin/master").unwrap();
    index.last_seen_reference().and_then(|mut r| r.delete()).ok();
    let num_changes_since_first_commit = index.fetch_changes().unwrap().len();
    assert!(num_changes_since_first_commit >= NUM_VERSIONS_AT_RECENT_COMMIT);
    let mut seen_marker_ref = index.last_seen_reference().expect("must be created/update now");
    assert!(seen_marker_ref == origin_master());

    // reset to previous one
    seen_marker_ref.set_target(index.repository().revparse_single(REV_ONE_UNYANKED).unwrap().id(),
                    "resetting to previous commit")
        .expect("reset success");
    let num_seen_after_reset = index.fetch_changes().unwrap().len();
    assert!(seen_marker_ref == origin_master());
    assert!(num_seen_after_reset < num_changes_since_first_commit);
    assert!(num_seen_after_reset < NUM_VERSIONS_AT_RECENT_COMMIT);
    assert!(num_seen_after_reset > 1000);

    // nothing if there was no change
    assert_eq!(index.fetch_changes().unwrap().len(), 0);
}

fn changes_of(index: &Index, commit: &str) -> Vec<Crate> {
    index.changes(format!("{}~1^{{tree}}", commit), format!("{}", commit))
        .expect("id to be valid and diff OK")
}

#[test]
fn quick_traverse_unyanked_crates() {
    let (index, _) = make_index();

    let crates = changes_of(&index, REV_ONE_UNYANKED);
    assert_eq!(crates,
               vec![Crate {
                        name: "gfx_text".to_owned(),
                        state: ChangeType::Added,
                        version: "0.13.2".to_owned(),
                    }]);
}

#[test]
fn quick_traverse_yanked_crates() {
    let (index, _) = make_index();

    let crates = changes_of(&index, REV_ONE_YANKED);
    assert_eq!(crates,
               vec![Crate {
                        name: "sha3".to_owned(),
                        state: ChangeType::Yanked,
                        version: "0.0.0".to_owned(),
                    }]);
}

#[test]
fn quick_traverse_added_crates() {
    let (index, _) = make_index();
    assert_eq!(index.changes("foo", REV_ONE_ADDED).is_err(), true);
    assert_eq!(index.changes(REV_ONE_ADDED, "bar").is_err(), true);

    let crates = changes_of(&index, REV_ONE_ADDED);
    assert_eq!(crates,
               vec![Crate {
                        name: "rpwg".to_owned(),
                        state: ChangeType::Added,
                        version: "0.1.0".to_owned(),
                    }]);
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
use std::cmp;
use std::mem;
use std::ptr;
use libc::c_int;
use num::complex::{
    Complex32,
    Complex64,
};
use error::Error;
use ll::*;
use matrix::{
    Matrix,
};
use scalar::Scalar;
use types::Layout;
use util::transpose_data;

pub trait Gels: Sized {
    fn gels(layout: Layout, a: &mut Matrix<Self>, b: &mut Matrix<Self>) -> Result<(), Error>;
    fn gels_work(layout: Layout, a: &mut Matrix<Self>, b: &mut Matrix<Self>, work: &mut [Self]) -> Result<(), Error>;
    fn gels_work_len(a: &mut Matrix<Self>, b: &mut Matrix<Self>) -> Result<usize, Error>;
}

macro_rules! least_sq_impl(($($t: ident), +) => ($(
    impl Gels for $t {
        fn gels(layout: Layout, a: &mut Matrix<Self>, b: &mut Matrix<Self>) -> Result<(), Error> {
            //TODO: nancheck

            let work_len = try!(Gels::gels_work_len(a, b));
            let mut work: Vec<$t> = Vec::with_capacity(work_len as usize);
            unsafe {
                work.set_len(work_len as usize);
            }

            Gels::gels_work(layout, a, b, &mut work[..])
        }

        fn gels_work(layout: Layout, a: &mut Matrix<Self>, b: &mut Matrix<Self>, work: &mut [Self]) -> Result<(), Error> {
            let mut info: c_int = 0;

            let m = a.rows();
            let n = a.cols();
            let nrhs = b.cols();
            let lda = m;
            let ldb = b.rows();

            match layout {
                Layout::ColMajor => unsafe {
                    prefix!($t, gels_)(
                        a.transpose().as_i8().as_mut(),
                        m.as_mut(), n.as_mut(),
                        nrhs.as_mut(),
                        a.as_mut_ptr(), lda.as_mut(),
                        b.as_mut_ptr(), ldb.as_mut(),
                        work.as_mut_ptr(), (work.len() as c_int).as_mut(),
                        &mut info as *mut c_int);
                },
                Layout::RowMajor => {
                    let mrhs = cmp::max(m, n);

                    let lda_t = cmp::max(1, m);
                    let ldb_t = cmp::max(1, mrhs);

                    let a_t_len = (lda_t * cmp::max(1, n)) as usize;
                    let b_t_len = (ldb_t * cmp::max(1, nrhs)) as usize;
                    let mut a_t = Vec::with_capacity(a_t_len);
                    let mut b_t = Vec::with_capacity(b_t_len);

                    unsafe {
                        a_t.set_len(a_t_len);
                        b_t.set_len(b_t_len);

                        transpose_data(Layout::RowMajor, m as isize, n as isize, a.as_ptr(), m as isize, a_t.as_mut_ptr(), lda_t as isize);
                        transpose_data(Layout::RowMajor, mrhs as isize, nrhs as isize, b.as_ptr(), mrhs as isize, b_t.as_mut_ptr(), ldb_t as isize);

                        prefix!($t, gels_)(
                            a.transpose().as_i8().as_mut(),
                            m.as_mut(), n.as_mut(),
                            nrhs.as_mut(),
                            a_t.as_mut_ptr(), lda_t.as_mut(),
                            b_t.as_mut_ptr(), ldb_t.as_mut(),
                            work.as_mut_ptr(), (work.len() as c_int).as_mut(),
                            &mut info as *mut c_int);

                        transpose_data(Layout::ColMajor, m as isize, n as isize, a_t.as_ptr(), lda_t as isize, a.as_mut_ptr(), m as isize);
                        transpose_data(Layout::ColMajor, mrhs as isize, nrhs as isize, b_t.as_ptr(), ldb_t as isize, b.as_mut_ptr(), mrhs as isize);
                    }
                }
            }

            match info {
                0 => Ok(()),
                x if x < 0 => Err(Error::IllegalParameter(-x as usize)),
                x => Err(Error::DiagonalElementZero(x as usize)),
            }
        }

        fn gels_work_len(a: &mut Matrix<Self>, b: &mut Matrix<Self>) -> Result<usize, Error> {
            let mut info: c_int = 0;
            let mut len_info: $t = unsafe { mem::zeroed() };
            let len_ptr = (&mut len_info) as *mut $t;

            let m = a.rows();
            let n = a.cols();
            let nrhs = b.cols();
            let lda_t = cmp::max(1, m);
            let ldb_t = cmp::max(1, cmp::max(m, n));

            unsafe {
                prefix!($t, gels_)(
                    a.transpose().as_i8().as_mut(),
                    m.as_mut(), n.as_mut(),
                    nrhs.as_mut(),
                    a.as_mut_ptr(), lda_t.as_mut(),
                    b.as_mut_ptr(), ldb_t.as_mut(),
                    len_ptr, (-1 as c_int).as_mut(),
                    &mut info as *mut c_int);
            };

            match info {
                0 => Ok(len_info.as_work()),
                x if x < 0 => Err(Error::IllegalParameter(-x as usize)),
                x => Err(Error::DiagonalElementZero(x as usize)),
            }
        }
    }
)+));

least_sq_impl!(f32, f64, Complex32, Complex64);

#[cfg(test)]
mod gesv_tests {
    use types::Layout::*;
    use least_squares::Gels;

    #[test]
    fn col_major() {
        let mut a = (3i32, 2i32, vec![2.0f32,4.0,7.0,3.0,9.0,4.0]);
        let mut b = (3i32, 2i32, vec![2.0f32,4.0,7.0,6.0,18.0,8.0]);

        Gels::gels(ColMajor, &mut a, &mut b).unwrap();

        let (_, _, x) = b;
        assert_eq!(x, vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0]);
    }
}
<commit_msg>Add row major test<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
use std::cmp;
use std::mem;
use std::ptr;
use libc::c_int;
use num::complex::{
    Complex32,
    Complex64,
};
use error::Error;
use ll::*;
use matrix::{
    Matrix,
};
use scalar::Scalar;
use types::Layout;
use util::transpose_data;

pub trait Gels: Sized {
    fn gels(layout: Layout, a: &mut Matrix<Self>, b: &mut Matrix<Self>) -> Result<(), Error>;
    fn gels_work(layout: Layout, a: &mut Matrix<Self>, b: &mut Matrix<Self>, work: &mut [Self]) -> Result<(), Error>;
    fn gels_work_len(a: &mut Matrix<Self>, b: &mut Matrix<Self>) -> Result<usize, Error>;
}

macro_rules! least_sq_impl(($($t: ident), +) => ($(
    impl Gels for $t {
        fn gels(layout: Layout, a: &mut Matrix<Self>, b: &mut Matrix<Self>) -> Result<(), Error> {
            //TODO: nancheck

            let work_len = try!(Gels::gels_work_len(a, b));
            let mut work: Vec<$t> = Vec::with_capacity(work_len as usize);
            unsafe {
                work.set_len(work_len as usize);
            }

            Gels::gels_work(layout, a, b, &mut work[..])
        }

        fn gels_work(layout: Layout, a: &mut Matrix<Self>, b: &mut Matrix<Self>, work: &mut [Self]) -> Result<(), Error> {
            let mut info: c_int = 0;

            let m = a.rows();
            let n = a.cols();
            let nrhs = b.cols();
            let lda = m;
            let ldb = b.rows();

            match layout {
                Layout::ColMajor => unsafe {
                    prefix!($t, gels_)(
                        a.transpose().as_i8().as_mut(),
                        m.as_mut(), n.as_mut(),
                        nrhs.as_mut(),
                        a.as_mut_ptr(), lda.as_mut(),
                        b.as_mut_ptr(), ldb.as_mut(),
                        work.as_mut_ptr(), (work.len() as c_int).as_mut(),
                        &mut info as *mut c_int);
                },
                Layout::RowMajor => {
                    let mrhs = cmp::max(m, n);

                    let lda_t = cmp::max(1, m);
                    let ldb_t = cmp::max(1, mrhs);

                    let a_t_len = (lda_t * cmp::max(1, n)) as usize;
                    let b_t_len = (ldb_t * cmp::max(1, nrhs)) as usize;
                    let mut a_t = Vec::with_capacity(a_t_len);
                    let mut b_t = Vec::with_capacity(b_t_len);

                    unsafe {
                        a_t.set_len(a_t_len);
                        b_t.set_len(b_t_len);

                        transpose_data(Layout::RowMajor, m as isize, n as isize, a.as_ptr(), m as isize, a_t.as_mut_ptr(), lda_t as isize);
                        transpose_data(Layout::RowMajor, mrhs as isize, nrhs as isize, b.as_ptr(), mrhs as isize, b_t.as_mut_ptr(), ldb_t as isize);

                        prefix!($t, gels_)(
                            a.transpose().as_i8().as_mut(),
                            m.as_mut(), n.as_mut(),
                            nrhs.as_mut(),
                            a_t.as_mut_ptr(), lda_t.as_mut(),
                            b_t.as_mut_ptr(), ldb_t.as_mut(),
                            work.as_mut_ptr(), (work.len() as c_int).as_mut(),
                            &mut info as *mut c_int);

                        transpose_data(Layout::ColMajor, m as isize, n as isize, a_t.as_ptr(), lda_t as isize, a.as_mut_ptr(), m as isize);
                        transpose_data(Layout::ColMajor, mrhs as isize, nrhs as isize, b_t.as_ptr(), ldb_t as isize, b.as_mut_ptr(), mrhs as isize);
                    }
                }
            }

            match info {
                0 => Ok(()),
                x if x < 0 => Err(Error::IllegalParameter(-x as usize)),
                x => Err(Error::DiagonalElementZero(x as usize)),
            }
        }

        fn gels_work_len(a: &mut Matrix<Self>, b: &mut Matrix<Self>) -> Result<usize, Error> {
            let mut info: c_int = 0;
            let mut len_info: $t = unsafe { mem::zeroed() };
            let len_ptr = (&mut len_info) as *mut $t;

            let m = a.rows();
            let n = a.cols();
            let nrhs = b.cols();
            let lda_t = cmp::max(1, m);
            let ldb_t = cmp::max(1, cmp::max(m, n));

            unsafe {
                prefix!($t, gels_)(
                    a.transpose().as_i8().as_mut(),
                    m.as_mut(), n.as_mut(),
                    nrhs.as_mut(),
                    a.as_mut_ptr(), lda_t.as_mut(),
                    b.as_mut_ptr(), ldb_t.as_mut(),
                    len_ptr, (-1 as c_int).as_mut(),
                    &mut info as *mut c_int);
            };

            match info {
                0 => Ok(len_info.as_work()),
                x if x < 0 => Err(Error::IllegalParameter(-x as usize)),
                x => Err(Error::DiagonalElementZero(x as usize)),
            }
        }
    }
)+));

least_sq_impl!(f32, f64, Complex32, Complex64);

#[cfg(test)]
mod gesv_tests {
    use types::Layout::*;
    use least_squares::Gels;

    #[test]
    fn col_major() {
        let mut a = (3i32, 2i32, vec![2.0f32,4.0,7.0,3.0,9.0,4.0]);
        let mut b = (3i32, 2i32, vec![2.0f32,4.0,7.0,6.0,18.0,8.0]);

        Gels::gels(ColMajor, &mut a, &mut b).unwrap();

        let (_, _, x) = b;
        assert_eq!(x, vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0]);
    }

    #[test]
    fn row_major() {
        let mut a = (3i32, 2i32, vec![2.0f32,3.0,4.0,9.0,7.0,4.0]);
        let mut b = (3i32, 2i32, vec![2.0f32,3.0,4.0,9.0,7.0,4.0]);

        Gels::gels(RowMajor, &mut a, &mut b).unwrap();

        let (_, _, x) = b;
        assert_eq!(x, vec![1.0, 0.0, 4.0, 0.0, 1.0, 4.0]);
    }
}
<|endoftext|>


<commit_before>use std::{usize, u8, u16, u32, u64};
use std::{isize, i8, i16, i32, i64};
use std::{f32, f64};
use std::num::Wrapping;

/// Numbers which have upper and lower bounds
pub trait Bounded {
    // FIXME (#5527): These should be associated constants
    /// returns the smallest finite number this type can represent
    fn min_value() -> Self;
    /// returns the largest finite number this type can represent
    fn max_value() -> Self;
}

macro_rules! bounded_impl {
    ($t:ty, $min:expr, $max:expr) => {
        impl Bounded for $t {
            #[inline]
            fn min_value() -> $t { $min }

            #[inline]
            fn max_value() -> $t { $max }
        }
    }
}

bounded_impl!(usize, usize::MIN, usize::MAX);
bounded_impl!(u8,    u8::MIN,    u8::MAX);
bounded_impl!(u16,   u16::MIN,   u16::MAX);
bounded_impl!(u32,   u32::MIN,   u32::MAX);
bounded_impl!(u64,   u64::MIN,   u64::MAX);

bounded_impl!(isize, isize::MIN, isize::MAX);
bounded_impl!(i8,    i8::MIN,    i8::MAX);
bounded_impl!(i16,   i16::MIN,   i16::MAX);
bounded_impl!(i32,   i32::MIN,   i32::MAX);
bounded_impl!(i64,   i64::MIN,   i64::MAX);

impl<T: Bounded> Bounded for Wrapping<T> {
    #[inline] fn min_value() -> Self { Wrapping(T::min_value()) }
    #[inline] fn max_value() -> Self { Wrapping(T::max_value()) }
}

bounded_impl!(f32, f32::MIN, f32::MAX);

macro_rules! for_each_tuple_ {
    ( $m:ident !! ) => (
        $m! { }
    );
    ( $m:ident !! $h:ident, $($t:ident,)* ) => (
        $m! { $h $($t)* }
        for_each_tuple_! { $m !! $($t,)* }
    );
}
macro_rules! for_each_tuple {
    ( $m:ident ) => (
        for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
    );
}

macro_rules! bounded_tuple {
    ( $($name:ident)* ) => (
        impl<$($name: Bounded,)*> Bounded for ($($name,)*) {
            #[inline]
            fn min_value() -> Self {
                ($($name::min_value(),)*)
            }
            #[inline]
            fn max_value() -> Self {
                ($($name::max_value(),)*)
            }
        }
    );
}

for_each_tuple!(bounded_tuple);
bounded_impl!(f64, f64::MIN, f64::MAX);
<commit_msg>Removed some #[inline] hints again<commit_after>use std::{usize, u8, u16, u32, u64};
use std::{isize, i8, i16, i32, i64};
use std::{f32, f64};
use std::num::Wrapping;

/// Numbers which have upper and lower bounds
pub trait Bounded {
    // FIXME (#5527): These should be associated constants
    /// returns the smallest finite number this type can represent
    fn min_value() -> Self;
    /// returns the largest finite number this type can represent
    fn max_value() -> Self;
}

macro_rules! bounded_impl {
    ($t:ty, $min:expr, $max:expr) => {
        impl Bounded for $t {
            #[inline]
            fn min_value() -> $t { $min }

            #[inline]
            fn max_value() -> $t { $max }
        }
    }
}

bounded_impl!(usize, usize::MIN, usize::MAX);
bounded_impl!(u8,    u8::MIN,    u8::MAX);
bounded_impl!(u16,   u16::MIN,   u16::MAX);
bounded_impl!(u32,   u32::MIN,   u32::MAX);
bounded_impl!(u64,   u64::MIN,   u64::MAX);

bounded_impl!(isize, isize::MIN, isize::MAX);
bounded_impl!(i8,    i8::MIN,    i8::MAX);
bounded_impl!(i16,   i16::MIN,   i16::MAX);
bounded_impl!(i32,   i32::MIN,   i32::MAX);
bounded_impl!(i64,   i64::MIN,   i64::MAX);

impl<T: Bounded> Bounded for Wrapping<T> {
    fn min_value() -> Self { Wrapping(T::min_value()) }
    fn max_value() -> Self { Wrapping(T::max_value()) }
}

bounded_impl!(f32, f32::MIN, f32::MAX);

macro_rules! for_each_tuple_ {
    ( $m:ident !! ) => (
        $m! { }
    );
    ( $m:ident !! $h:ident, $($t:ident,)* ) => (
        $m! { $h $($t)* }
        for_each_tuple_! { $m !! $($t,)* }
    );
}
macro_rules! for_each_tuple {
    ( $m:ident ) => (
        for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
    );
}

macro_rules! bounded_tuple {
    ( $($name:ident)* ) => (
        impl<$($name: Bounded,)*> Bounded for ($($name,)*) {
            #[inline]
            fn min_value() -> Self {
                ($($name::min_value(),)*)
            }
            #[inline]
            fn max_value() -> Self {
                ($($name::max_value(),)*)
            }
        }
    );
}

for_each_tuple!(bounded_tuple);
bounded_impl!(f64, f64::MIN, f64::MAX);
<|endoftext|>


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

use crate::bundle::{Bundle, Exchange, Request, Response, Uri, Version};
use crate::prelude::*;
use headers::{ContentLength, ContentType, HeaderMapExt as _, HeaderValue};
use http::StatusCode;
use std::path::{Path, PathBuf};
use url::Url;
use walkdir::WalkDir;

/// A Bundle builder.
#[derive(Default)]
pub struct Builder {
    version: Option<Version>,
    primary_url: Option<Uri>,
    manifest: Option<Uri>,
    exchanges: Vec<Exchange>,
}

impl Builder {
    pub(crate) fn new() -> Self {
        Default::default()
    }

    /// Sets the version.
    pub fn version(mut self, version: Version) -> Self {
        self.version = Some(version);
        self
    }

    /// Sets the primary url.
    pub fn primary_url(mut self, primary_url: Uri) -> Self {
        self.primary_url = Some(primary_url);
        self
    }

    /// Sets the manifest url.
    pub fn manifest(mut self, manifest: Uri) -> Self {
        self.manifest = Some(manifest);
        self
    }

    /// Adds the exchange.
    pub fn exchange(mut self, exchange: Exchange) -> Self {
        self.exchanges.push(exchange);
        self
    }

    /// Append exchanges from files rooted at the given directory.
    ///
    /// `base_url` will be used as a prefix for each resource. A relative path
    /// from the given directory to each file is appended to `base_url`.
    ///
    /// One exchange is created for each file, however, two exchanges
    /// are created for `index.html` file, as follows:
    ///
    /// 1. The pareent directory **serves** the contents of `index.html` file.
    /// 2. The URL for `index.html` file is a redirect to the parent directory
    ///    (`301` MOVED PERMANENTLY).
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use webbundle::{Bundle, Version};
    /// let bundle = Bundle::builder()
    ///     .version(Version::VersionB1)
    ///     .primary_url("https://example.com/".parse()?)
    ///     .exchanges_from_dir("build", "https://example.com".parse()?)?
    ///     .build()?;
    /// # Result::Ok::<(), anyhow::Error>(())
    /// ```
    pub fn exchanges_from_dir(mut self, dir: impl AsRef<Path>, base_url: Url) -> Result<Self> {
        self.exchanges.append(
            &mut ExchangeBuilder::new(PathBuf::from(dir.as_ref()), base_url)
                .walk()?
                .build(),
        );
        Ok(self)
    }

    /// Builds the bundle.
    pub fn build(self) -> Result<Bundle> {
        Ok(Bundle {
            version: self.version.context("no version")?,
            primary_url: self.primary_url.context("no primary_url")?,
            manifest: self.manifest,
            exchanges: self.exchanges,
        })
    }
}

#[allow(dead_code)]
struct ExchangeBuilder {
    base_url: Url,
    base_dir: PathBuf,
    exchanges: Vec<Exchange>,
}

#[allow(dead_code)]
impl ExchangeBuilder {
    fn new(base_dir: PathBuf, base_url: Url) -> Self {
        ExchangeBuilder {
            base_dir,
            base_url,
            exchanges: Vec::new(),
        }
    }

    fn walk(mut self) -> Result<Self> {
        for entry in WalkDir::new(&self.base_dir) {
            let entry = entry?;
            log::info!("visit: {:?}", entry);
            let file_type = entry.file_type();
            if file_type.is_symlink() {
                log::warn!(
                    "path is symbolink link. Skipping. {}",
                    entry.path().display()
                );
                continue;
            }
            if !file_type.is_file() {
                continue;
            }
            if entry.path().file_name().unwrap() == "index.html" {
                let dir = entry.path().parent().unwrap();

                let relative_url = pathdiff::diff_paths(dir, &self.base_dir).unwrap();
                let relative_path = pathdiff::diff_paths(entry.path(), &self.base_dir).unwrap();
                // for <dir> -> Serves the contents of <dir>/index.html
                self = self.exchange(&relative_url, &relative_path)?;

                // for <dir>/index.html -> redirect to "./"
                self = self.exchange_redirect(&relative_path, "./")?;
            } else {
                let relative_path = pathdiff::diff_paths(entry.path(), &self.base_dir).unwrap();
                self = self.exchange(&relative_path, &relative_path)?;
            }
        }
        Ok(self)
    }

    fn build(self) -> Vec<Exchange> {
        self.exchanges
    }

    fn url_from_relative_path(&self, relative_path: &Path) -> Result<Uri> {
        ensure!(
            relative_path.is_relative(),
            format!("Path is not relative: {}", relative_path.display())
        );
        Ok(self
            .base_url
            .join(&relative_path.display().to_string())?
            .to_string()
            .parse()?)
    }

    fn url_join(&self, relative_url: &str) -> Result<Uri> {
        Ok(self.base_url.join(relative_url)?.to_string().parse()?)
    }

    fn exchange(
        mut self,
        relative_url: impl AsRef<Path>,
        relative_path: impl AsRef<Path>,
    ) -> Result<Self> {
        self.exchanges.push(Exchange {
            request: Request::get(self.url_from_relative_path(relative_url.as_ref())?).body(())?,
            response: self.create_response(relative_path)?,
        });
        Ok(self)
    }

    fn exchange_redirect(mut self, relative_url: &Path, location: &str) -> Result<Self> {
        self.exchanges.push(Exchange {
            request: Request::get(self.url_from_relative_path(relative_url)?).body(())?,
            response: Self::create_redirect(location)?,
        });
        Ok(self)
    }

    fn create_redirect(location: &str) -> Result<Response> {
        let mut response = Response::new(Vec::new());
        *response.status_mut() = StatusCode::MOVED_PERMANENTLY;
        response
            .headers_mut()
            .insert("Location", HeaderValue::from_str(location)?);
        Ok(response)
    }

    fn create_response(&self, relative_path: impl AsRef<Path>) -> Result<Response> {
        ensure!(
            relative_path.as_ref().is_relative(),
            format!("Path is not relative: {}", relative_path.as_ref().display())
        );
        let path = self.base_dir.join(relative_path);
        let body = std::fs::read(&path)?;

        let content_length = ContentLength(body.len() as u64);
        let content_type = ContentType::from(mime_guess::from_path(&path).first_or_octet_stream());

        let mut response = Response::new(body);
        *response.status_mut() = StatusCode::OK;
        response.headers_mut().typed_insert(content_length);
        response.headers_mut().typed_insert(content_type);
        Ok(response)
    }
}

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

    #[test]
    fn build_fail() {
        assert!(Builder::new().build().is_err());
    }

    #[test]
    fn build() -> Result<()> {
        let bundle = Builder::new()
            .version(Version::Version1)
            .primary_url("https://example.com".parse()?)
            .build()?;
        assert_eq!(bundle.version, Version::Version1);
        assert_eq!(bundle.primary_url, "https://example.com".parse::<Uri>()?);
        Ok(())
    }

    #[test]
    fn exchange_builder() -> Result<()> {
        let base_dir = {
            let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            path.push("tests/builder");
            path
        };

        let exchanges = ExchangeBuilder::new(base_dir.clone(), "https://example.com/".parse()?)
            .exchange(".", "index.html")?
            .build();
        assert_eq!(exchanges.len(), 1);
        let exchange = &exchanges[0];
        assert_eq!(
            exchange.request.uri(),
            &"https://example.com/".parse::<Uri>()?
        );
        assert_eq!(exchange.response.status(), StatusCode::OK);
        assert_eq!(exchange.response.headers()["content-type"], "text/html");
        assert_eq!(
            exchange.response.headers()["content-length"],
            std::fs::read(base_dir.join("index.html"))?
                .len()
                .to_string()
        );
        assert_eq!(
            exchange.response.body(),
            &std::fs::read(base_dir.join("index.html"))?
        );
        Ok(())
    }

    #[test]
    fn walk() -> Result<()> {
        let base_dir = {
            let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            path.push("tests/builder");
            path
        };

        let exchanges = ExchangeBuilder::new(base_dir, "https://example.com/".parse()?)
            .walk()?
            .build();
        assert_eq!(exchanges.len(), 3);
        let urls = exchanges
            .into_iter()
            .map(|e| e.request.uri().to_string())
            .collect::<HashSet<_>>();
        assert!(urls.contains("https://example.com/"));
        assert!(urls.contains("https://example.com/index.html"));
        assert!(urls.contains("https://example.com/js/hello.js"));
        Ok(())
    }
}
<commit_msg>Update tests for builder<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::bundle::{Bundle, Exchange, Request, Response, Uri, Version};
use crate::prelude::*;
use headers::{ContentLength, ContentType, HeaderMapExt as _, HeaderValue};
use http::StatusCode;
use std::path::{Path, PathBuf};
use url::Url;
use walkdir::WalkDir;

/// A Bundle builder.
#[derive(Default)]
pub struct Builder {
    version: Option<Version>,
    primary_url: Option<Uri>,
    manifest: Option<Uri>,
    exchanges: Vec<Exchange>,
}

impl Builder {
    pub(crate) fn new() -> Self {
        Default::default()
    }

    /// Sets the version.
    pub fn version(mut self, version: Version) -> Self {
        self.version = Some(version);
        self
    }

    /// Sets the primary url.
    pub fn primary_url(mut self, primary_url: Uri) -> Self {
        self.primary_url = Some(primary_url);
        self
    }

    /// Sets the manifest url.
    pub fn manifest(mut self, manifest: Uri) -> Self {
        self.manifest = Some(manifest);
        self
    }

    /// Adds the exchange.
    pub fn exchange(mut self, exchange: Exchange) -> Self {
        self.exchanges.push(exchange);
        self
    }

    /// Append exchanges from files rooted at the given directory.
    ///
    /// `base_url` will be used as a prefix for each resource. A relative path
    /// from the given directory to each file is appended to `base_url`.
    ///
    /// One exchange is created for each file, however, two exchanges
    /// are created for `index.html` file, as follows:
    ///
    /// 1. The pareent directory **serves** the contents of `index.html` file.
    /// 2. The URL for `index.html` file is a redirect to the parent directory
    ///    (`301` MOVED PERMANENTLY).
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use webbundle::{Bundle, Version};
    /// let bundle = Bundle::builder()
    ///     .version(Version::VersionB1)
    ///     .primary_url("https://example.com/".parse()?)
    ///     .exchanges_from_dir("build", "https://example.com".parse()?)?
    ///     .build()?;
    /// # Result::Ok::<(), anyhow::Error>(())
    /// ```
    pub fn exchanges_from_dir(mut self, dir: impl AsRef<Path>, base_url: Url) -> Result<Self> {
        self.exchanges.append(
            &mut ExchangeBuilder::new(PathBuf::from(dir.as_ref()), base_url)
                .walk()?
                .build(),
        );
        Ok(self)
    }

    /// Builds the bundle.
    pub fn build(self) -> Result<Bundle> {
        Ok(Bundle {
            version: self.version.context("no version")?,
            primary_url: self.primary_url.context("no primary_url")?,
            manifest: self.manifest,
            exchanges: self.exchanges,
        })
    }
}

#[allow(dead_code)]
struct ExchangeBuilder {
    base_url: Url,
    base_dir: PathBuf,
    exchanges: Vec<Exchange>,
}

#[allow(dead_code)]
impl ExchangeBuilder {
    fn new(base_dir: PathBuf, base_url: Url) -> Self {
        ExchangeBuilder {
            base_dir,
            base_url,
            exchanges: Vec::new(),
        }
    }

    fn walk(mut self) -> Result<Self> {
        for entry in WalkDir::new(&self.base_dir) {
            let entry = entry?;
            log::info!("visit: {:?}", entry);
            let file_type = entry.file_type();
            if file_type.is_symlink() {
                log::warn!(
                    "path is symbolink link. Skipping. {}",
                    entry.path().display()
                );
                continue;
            }
            if !file_type.is_file() {
                continue;
            }
            if entry.path().file_name().unwrap() == "index.html" {
                let dir = entry.path().parent().unwrap();

                let relative_url = pathdiff::diff_paths(dir, &self.base_dir).unwrap();
                let relative_path = pathdiff::diff_paths(entry.path(), &self.base_dir).unwrap();
                // for <dir> -> Serves the contents of <dir>/index.html
                self = self.exchange(&relative_url, &relative_path)?;

                // for <dir>/index.html -> redirect to "./"
                self = self.exchange_redirect(&relative_path, "./")?;
            } else {
                let relative_path = pathdiff::diff_paths(entry.path(), &self.base_dir).unwrap();
                self = self.exchange(&relative_path, &relative_path)?;
            }
        }
        Ok(self)
    }

    fn build(self) -> Vec<Exchange> {
        self.exchanges
    }

    fn url_from_relative_path(&self, relative_path: &Path) -> Result<Uri> {
        ensure!(
            relative_path.is_relative(),
            format!("Path is not relative: {}", relative_path.display())
        );
        Ok(self
            .base_url
            .join(&relative_path.display().to_string())?
            .to_string()
            .parse()?)
    }

    fn url_join(&self, relative_url: &str) -> Result<Uri> {
        Ok(self.base_url.join(relative_url)?.to_string().parse()?)
    }

    fn exchange(
        mut self,
        relative_url: impl AsRef<Path>,
        relative_path: impl AsRef<Path>,
    ) -> Result<Self> {
        self.exchanges.push(Exchange {
            request: Request::get(self.url_from_relative_path(relative_url.as_ref())?).body(())?,
            response: self.create_response(relative_path)?,
        });
        Ok(self)
    }

    fn exchange_redirect(mut self, relative_url: &Path, location: &str) -> Result<Self> {
        self.exchanges.push(Exchange {
            request: Request::get(self.url_from_relative_path(relative_url)?).body(())?,
            response: Self::create_redirect(location)?,
        });
        Ok(self)
    }

    fn create_redirect(location: &str) -> Result<Response> {
        let mut response = Response::new(Vec::new());
        *response.status_mut() = StatusCode::MOVED_PERMANENTLY;
        response
            .headers_mut()
            .insert("Location", HeaderValue::from_str(location)?);
        Ok(response)
    }

    fn create_response(&self, relative_path: impl AsRef<Path>) -> Result<Response> {
        ensure!(
            relative_path.as_ref().is_relative(),
            format!("Path is not relative: {}", relative_path.as_ref().display())
        );
        let path = self.base_dir.join(relative_path);
        let body = std::fs::read(&path)?;

        let content_length = ContentLength(body.len() as u64);
        let content_type = ContentType::from(mime_guess::from_path(&path).first_or_octet_stream());

        let mut response = Response::new(body);
        *response.status_mut() = StatusCode::OK;
        response.headers_mut().typed_insert(content_length);
        response.headers_mut().typed_insert(content_type);
        Ok(response)
    }
}

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

    #[test]
    fn build_invalid_bundle() -> Result<()> {
        assert!(Builder::new().build().is_err());
        assert!(Builder::new()
            .primary_url("https://example.com/".parse()?)
            .build()
            .is_err());
        Ok(())
    }

    #[test]
    fn build() -> Result<()> {
        let bundle = Builder::new()
            .version(Version::Version1)
            .primary_url("https://example.com".parse()?)
            .build()?;
        assert_eq!(bundle.version, Version::Version1);
        assert_eq!(bundle.primary_url, "https://example.com".parse::<Uri>()?);
        Ok(())
    }

    #[test]
    fn exchange_builder() -> Result<()> {
        let base_dir = {
            let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            path.push("tests/builder");
            path
        };

        let exchanges = ExchangeBuilder::new(base_dir.clone(), "https://example.com/".parse()?)
            .exchange(".", "index.html")?
            .build();
        assert_eq!(exchanges.len(), 1);
        let exchange = &exchanges[0];
        assert_eq!(
            exchange.request.uri(),
            &"https://example.com/".parse::<Uri>()?
        );
        assert_eq!(exchange.response.status(), StatusCode::OK);
        assert_eq!(exchange.response.headers()["content-type"], "text/html");
        assert_eq!(
            exchange.response.headers()["content-length"],
            std::fs::read(base_dir.join("index.html"))?
                .len()
                .to_string()
        );
        assert_eq!(
            exchange.response.body(),
            &std::fs::read(base_dir.join("index.html"))?
        );
        Ok(())
    }

    #[test]
    fn walk() -> Result<()> {
        let base_dir = {
            let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            path.push("tests/builder");
            path
        };

        let exchanges = ExchangeBuilder::new(base_dir, "https://example.com/".parse()?)
            .walk()?
            .build();
        assert_eq!(exchanges.len(), 3);

        let top_dir = find_exchange_by_uri(&exchanges, "https://example.com/")?;
        assert_eq!(top_dir.response.status(), StatusCode::OK);

        let index_html = find_exchange_by_uri(&exchanges, "https://example.com/index.html")?;
        assert_eq!(index_html.response.status(), StatusCode::MOVED_PERMANENTLY);

        let a_js = find_exchange_by_uri(&exchanges, "https://example.com/js/hello.js")?;
        assert_eq!(a_js.response.status(), StatusCode::OK);

        Ok(())
    }

    fn find_exchange_by_uri<'a>(exchanges: &'a [Exchange], uri: &str) -> Result<&'a Exchange> {
        exchanges
            .iter()
            .find(|e| e.request.uri() == uri)
            .context("not fouond")
    }
}
<|endoftext|>