<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Batches are structures containing all the data required for the draw call,
//! except for the target frame. Here we define the `Batch` trait as well as
//! `RefBatch` and `OwnedBatch` implementations.

use draw_state::DrawState;

use device::{Resources, PrimitiveType};
use device::handle::Program as ProgramHandle;
use render::mesh;
use render::mesh::ToSlice;
use shade::{ParameterError, ShaderParam};
use super::ParamStorage;

/// An error occurring at batch creation
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
    /// Error connecting mesh attributes
    Mesh(mesh::Error),
    /// Error connecting shader parameters
    Parameters(ParameterError),
    /// Another kind of error
    Other(String),
}

/// Return type for `Batch::get_data()``
pub type BatchData<'a, R: Resources> = (&'a mesh::Mesh<R>, mesh::AttributeIter,
                                        &'a mesh::Slice<R>, &'a DrawState);

/// Abstract batch trait
pub trait Batch<R: Resources> {
    /// Obtain information about the mesh, program, and state
    fn get_data(&self) -> Result<BatchData<R>, Error>;
    /// Fill shader parameter values
    fn fill_params(&self, &mut ParamStorage<R>) -> Result<&ProgramHandle<R>, Error>;
}

/// A batch that is constructed on the fly when rendering.
/// Meant to be a struct, blocked by #614
pub type Implicit<'a, T: ShaderParam> = (
    &'a mesh::Mesh<T::Resources>,
    mesh::Slice<T::Resources>,
    &'a ProgramHandle<T::Resources>,
    &'a T,
    &'a DrawState
);

/// Create an implicit batch
pub fn bind<'a, T: ShaderParam>(draw_state: &'a DrawState,
             mesh: &'a mesh::Mesh<T::Resources>,
             slice: mesh::Slice<T::Resources>,
             program: &'a ProgramHandle<T::Resources>,
             data: &'a T) -> Implicit<'a, T> {
    (mesh, slice, program, data, draw_state)
}

impl<'a, T: ShaderParam> Batch<T::Resources> for Implicit<'a, T> {
    fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
        let (mesh, ref slice, program, _, state) = *self;
        match mesh::Link::new(mesh, program.get_info()) {
            Ok(link) => Ok((mesh, link.to_iter(), &slice, state)),
            Err(e) => Err(Error::Mesh(e)),
        }
    }

    fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, Error> {
        let (_, _, program, params, _) = *self;
        match ShaderParam::create_link(None::<&T>, program.get_info()) {
            Ok(link) => {
                values.reserve(program.get_info());
                params.fill_params(&link, values);
                Ok(program)
            },
            Err(e) => return Err(Error::Parameters(e)),
        }
    }
}

/// Full batch - contains everything needed for rendering.
#[derive(Clone)]
pub struct Full<T: ShaderParam> {
    mesh: mesh::Mesh<T::Resources>,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice<T::Resources>,
    /// Parameter data.
    pub params: T,
    program: ProgramHandle<T::Resources>,
    param_link: T::Link,
    /// Draw state
    pub state: DrawState,
}

impl<T: ShaderParam> Full<T> {
    /// Create a new full batch
    pub fn new(mesh: mesh::Mesh<T::Resources>, program: ProgramHandle<T::Resources>, params: T)
           -> Result<Full<T>, Error> {
        let slice = mesh.to_slice(PrimitiveType::TriangleList);
        let mesh_link = match mesh::Link::new(&mesh, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Mesh(e)),
        };
        let param_link = match ShaderParam::create_link(Some(&params), program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Parameters(e)),
        };
        Ok(Full {
            mesh: mesh,
            mesh_link: mesh_link,
            slice: slice,
            program: program,
            params: params,
            param_link: param_link,
            state: DrawState::new(),
        })
    }
}

impl<T: ShaderParam> Batch<T::Resources> for Full<T> {
    fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
        Ok((&self.mesh, self.mesh_link.to_iter(), &self.slice, &self.state))
    }

    fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, Error> {
        values.reserve(self.program.get_info());
        self.params.fill_params(&self.param_link, values);
        Ok(&self.program)
    }
}

/// Core batch - a minimal sealed batch.
#[derive(Clone)]
pub struct Core<T: ShaderParam> {
    mesh: mesh::Mesh<T::Resources>,
    mesh_link: mesh::Link,
    program: ProgramHandle<T::Resources>,
    param_link: T::Link,
}

/// A `Core` completed by a mesh slice, shader parameters, and a state.
/// Implements `Batch` thus can be drawn.
/// It is meant to be a struct, but we have lots of lifetime issues
/// with associated resources, binding which looks nasty (#614)
pub type Complete<'a, T: ShaderParam> = (
    &'a Core<T>,
    &'a mesh::Slice<T::Resources>,
    &'a T,
    &'a DrawState
);

impl<T: ShaderParam> Core<T> {
    /// Create a new core batch.
    pub fn new(mesh: mesh::Mesh<T::Resources>, program: ProgramHandle<T::Resources>)
           -> Result<Core<T>, Error> {
        let mesh_link = match mesh::Link::new(&mesh, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Mesh(e)),
        };
        let param_link = match ShaderParam::create_link(None::<&T>, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Parameters(e)),
        };
        Ok(Core {
            mesh: mesh,
            mesh_link: mesh_link,
            program: program,
            param_link: param_link,
        })
    }

    /// Add missing components to complete the batch for rendering.
    pub fn with<'a>(&'a self, slice: &'a mesh::Slice<T::Resources>,
                params: &'a T, state: &'a DrawState)
                -> Complete<'a, T> {
        (self, slice, params, state)
    }
}

impl<'a, T: ShaderParam + 'a> Batch<T::Resources> for Complete<'a, T> {
    fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
        let (b, slice, _, state) = *self;
        Ok((&b.mesh, b.mesh_link.to_iter(), slice, state))
    }

    fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, Error> {
        let (b, _, data, _) = *self;
        values.reserve(b.program.get_info());
        data.fill_params(&b.param_link, values);
        Ok(&b.program)
    }
}
<commit_msg>Added functions to get access to program/mesh, needed for gfx_scene<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

//! Batches are structures containing all the data required for the draw call,
//! except for the target frame. Here we define the `Batch` trait as well as
//! `RefBatch` and `OwnedBatch` implementations.

use draw_state::DrawState;

use device::{Resources, PrimitiveType};
use device::handle::Program as ProgramHandle;
use render::mesh;
use render::mesh::ToSlice;
use shade::{ParameterError, ShaderParam};
use super::ParamStorage;

/// An error occurring at batch creation
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
    /// Error connecting mesh attributes
    Mesh(mesh::Error),
    /// Error connecting shader parameters
    Parameters(ParameterError),
    /// Another kind of error
    Other(String),
}

/// Return type for `Batch::get_data()``
pub type BatchData<'a, R: Resources> = (&'a mesh::Mesh<R>, mesh::AttributeIter,
                                        &'a mesh::Slice<R>, &'a DrawState);

/// Abstract batch trait
pub trait Batch<R: Resources> {
    /// Obtain information about the mesh, program, and state
    fn get_data(&self) -> Result<BatchData<R>, Error>;
    /// Fill shader parameter values
    fn fill_params(&self, &mut ParamStorage<R>) -> Result<&ProgramHandle<R>, Error>;
}

/// A batch that is constructed on the fly when rendering.
/// Meant to be a struct, blocked by #614
pub type Implicit<'a, T: ShaderParam> = (
    &'a mesh::Mesh<T::Resources>,
    mesh::Slice<T::Resources>,
    &'a ProgramHandle<T::Resources>,
    &'a T,
    &'a DrawState
);

/// Create an implicit batch
pub fn bind<'a, T: ShaderParam>(draw_state: &'a DrawState,
             mesh: &'a mesh::Mesh<T::Resources>,
             slice: mesh::Slice<T::Resources>,
             program: &'a ProgramHandle<T::Resources>,
             data: &'a T) -> Implicit<'a, T> {
    (mesh, slice, program, data, draw_state)
}

impl<'a, T: ShaderParam> Batch<T::Resources> for Implicit<'a, T> {
    fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
        let (mesh, ref slice, program, _, state) = *self;
        match mesh::Link::new(mesh, program.get_info()) {
            Ok(link) => Ok((mesh, link.to_iter(), &slice, state)),
            Err(e) => Err(Error::Mesh(e)),
        }
    }

    fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, Error> {
        let (_, _, program, params, _) = *self;
        match ShaderParam::create_link(None::<&T>, program.get_info()) {
            Ok(link) => {
                values.reserve(program.get_info());
                params.fill_params(&link, values);
                Ok(program)
            },
            Err(e) => return Err(Error::Parameters(e)),
        }
    }
}

/// Full batch - contains everything needed for rendering.
#[derive(Clone)]
pub struct Full<T: ShaderParam> {
    mesh: mesh::Mesh<T::Resources>,
    mesh_link: mesh::Link,
    /// Mesh slice
    pub slice: mesh::Slice<T::Resources>,
    /// Parameter data.
    pub params: T,
    program: ProgramHandle<T::Resources>,
    param_link: T::Link,
    /// Draw state
    pub state: DrawState,
}

impl<T: ShaderParam> Full<T> {
    /// Create a new full batch
    pub fn new(mesh: mesh::Mesh<T::Resources>, program: ProgramHandle<T::Resources>, params: T)
           -> Result<Full<T>, Error> {
        let slice = mesh.to_slice(PrimitiveType::TriangleList);
        let mesh_link = match mesh::Link::new(&mesh, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Mesh(e)),
        };
        let param_link = match ShaderParam::create_link(Some(&params), program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Parameters(e)),
        };
        Ok(Full {
            mesh: mesh,
            mesh_link: mesh_link,
            slice: slice,
            program: program,
            params: params,
            param_link: param_link,
            state: DrawState::new(),
        })
    }
}

impl<T: ShaderParam> Batch<T::Resources> for Full<T> {
    fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
        Ok((&self.mesh, self.mesh_link.to_iter(), &self.slice, &self.state))
    }

    fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, Error> {
        values.reserve(self.program.get_info());
        self.params.fill_params(&self.param_link, values);
        Ok(&self.program)
    }
}

/// Core batch - a minimal sealed batch.
#[derive(Clone)]
pub struct Core<T: ShaderParam> {
    mesh: mesh::Mesh<T::Resources>,
    mesh_link: mesh::Link,
    program: ProgramHandle<T::Resources>,
    param_link: T::Link,
}

/// A `Core` completed by a mesh slice, shader parameters, and a state.
/// Implements `Batch` thus can be drawn.
/// It is meant to be a struct, but we have lots of lifetime issues
/// with associated resources, binding which looks nasty (#614)
pub type Complete<'a, T: ShaderParam> = (
    &'a Core<T>,
    &'a mesh::Slice<T::Resources>,
    &'a T,
    &'a DrawState
);

impl<T: ShaderParam> Core<T> {
    /// Create a new core batch.
    pub fn new(mesh: mesh::Mesh<T::Resources>, program: ProgramHandle<T::Resources>)
           -> Result<Core<T>, Error> {
        let mesh_link = match mesh::Link::new(&mesh, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Mesh(e)),
        };
        let param_link = match ShaderParam::create_link(None::<&T>, program.get_info()) {
            Ok(l) => l,
            Err(e) => return Err(Error::Parameters(e)),
        };
        Ok(Core {
            mesh: mesh,
            mesh_link: mesh_link,
            program: program,
            param_link: param_link,
        })
    }

    /// Add missing components to complete the batch for rendering.
    pub fn with<'a>(&'a self, slice: &'a mesh::Slice<T::Resources>,
                params: &'a T, state: &'a DrawState)
                -> Complete<'a, T> {
        (self, slice, params, state)
    }

    /// Read the ProgramHandle
    pub fn program(&self) -> &ProgramHandle<T::Resources> {
        &self.program
    }

    /// Read the Mesh
    pub fn mesh(&self) -> &mesh::Mesh<T::Resources> {
        &self.mesh
    }
}

impl<'a, T: ShaderParam + 'a> Batch<T::Resources> for Complete<'a, T> {
    fn get_data(&self) -> Result<BatchData<T::Resources>, Error> {
        let (b, slice, _, state) = *self;
        Ok((&b.mesh, b.mesh_link.to_iter(), slice, state))
    }

    fn fill_params(&self, values: &mut ParamStorage<T::Resources>)
                   -> Result<&ProgramHandle<T::Resources>, Error> {
        let (b, _, data, _) = *self;
        values.reserve(b.program.get_info());
        data.fill_params(&b.param_link, values);
        Ok(&b.program)
    }
}
<|endoftext|>


<commit_before>use hyper::server::{Request, Response};

pub fn get(request: Request, mut response: Response) {
    let (remote_addr, _, headers, uri, version, payload) = request.deconstruct();
    println!("**  Handling GET {}", uri);
    println!("*** Incoming headers {:?}", headers);
}

// // #[get("/")]
// fn index() -> content::HTML<&'static str> {
//     content::HTML("<!DOCTYPE html>
//
//
//             <title>HTTPTIN</title>
//
//
//
HTTPTIN - HTTP tester in Rust and Rocket

//
//     ")
// }
//
// // #[get("/test")]
// fn test(data: IndexData) -> content::HTML<String> {
//     content::HTML(format!("<!DOCTYPE html>
//
//
//             <title>HTTPTIN></title>
//
//         {}
//     ",
//                           data))
// }

//#[get("/ip")]
fn origin() -> String {
    String::from("Remote address decoding is not implemented yet")
}

struct GetData {
    args: String,
    headers: String,
}

// //#[get("/status/")]
// pub fn status<'r>(code: u16) -> Response<'r> {
//     Response::build().status(Status::raw(code)).finalize()
// }
<commit_msg>Simple dispatch on GET method<commit_after>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 }
        $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    // let (remote_addr, _, headers, uri, version, payload) = request.deconstruct();
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status") => status(&request, response),
            path.starts_with("/test") => test(&request, response),
        ];
    }
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes());
}

fn status(request: &Request, mut response: Response) {
    *response.status_mut() = StatusCode::ImATeapot;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes());
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes());
}

struct GetData {
    args: String,
    headers: String,
}

// //#[get("/status/")]
// pub fn status<'r>(code: u16) -> Response<'r> {
//     Response::build().status(Status::raw(code)).finalize()
// }
<|endoftext|>


<commit_before>use std::path::Path;
use std::str;

use duct::cmd;
use git2::{Config, Error, Repository};
use log::debug;
use shellexpand;

/// Update old `req.key` config format to include remote name, i.e, `req.remote_name.key`
fn migrate_legacy(field_name: &str, remote_name: &str) {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let mut cfg = repo.config().unwrap();

    if let Ok(ref value) = cfg.get_string(&format!("req.{}", field_name)) {
        cfg.set_str(&format!("req.{}.{}", remote_name, field_name), value)
            .unwrap();
        cfg.remove(&format!("req.{}", field_name)).unwrap();
    }
}

/// Convert a domain string into a configuration slug
fn slugify_domain(domain: &str) -> String {
    str::replace(domain, ".", "|")
}

/// Get the URL of the given remote
pub fn get_remote_url(remote: &str) -> String {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let remote = repo.find_remote(remote).unwrap();
    String::from(remote.url().unwrap())
}

/// Get a value fom the repository config
pub fn get_repo_info(repo_field: &str) -> Result<String, Error> {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let cfg = repo.config().unwrap();
    cfg.get_string(repo_field)
}

/// Get a value for the given project-local git-req config
pub fn get_config(field_name: &str, remote_name: &str) -> Option<String> {
    migrate_legacy(field_name, "origin");
    let key = format!("req.{}.{}", remote_name, field_name);
    match get_repo_info(&key) {
        Ok(val) => Some(val),
        Err(_) => None,
    }
}

/// Set a value for the project-local git-req configuration
pub fn set_config(field_name: &str, remote_name: &str, value: &str) {
    migrate_legacy(field_name, "origin");
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let mut cfg = repo.config().unwrap();
    cfg.set_str(&format!("req.{}.{}", remote_name, field_name), value)
        .unwrap();
}

/// Delete the entry for the project-local git-req config field with the provided name
pub fn delete_config(field_name: &str, remote_name: &str) {
    migrate_legacy(field_name, "origin");
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let mut cfg = repo.config().unwrap();
    cfg.remove(&format!("req.{}.{}", remote_name, field_name))
        .unwrap();
}

/// Get a value for the given global git-req config
pub fn get_req_config(domain: &str, field: &str) -> Option<String> {
    let slug = slugify_domain(domain);
    let cfg = Config::open(&Path::new(
        &shellexpand::tilde("~/.gitreqconfig").to_string(),
    ))
    .unwrap();
    match cfg.get_string(&format!("req.{}.{}", slug, field)) {
        Ok(val) => Some(val),
        Err(_) => None,
    }
}

/// Set a value for the global git-req configuration
pub fn set_req_config(domain: &str, field: &str, value: &str) {
    let slug = slugify_domain(domain);
    let mut cfg = Config::open(&Path::new(
        &shellexpand::tilde("~/.gitreqconfig").to_string(),
    ))
    .unwrap();
    cfg.set_str(&format!("req.{}.{}", slug, field), value)
        .unwrap();
}

/// Clear the value for the lobal git-req configuration
pub fn delete_req_config(domain: &str, field: &str) -> Result<(), Error> {
    let slug = slugify_domain(domain);
    let mut cfg = Config::open(&Path::new(
        &shellexpand::tilde("~/.gitreqconfig").to_string(),
    ))
    .unwrap();
    cfg.remove(&format!("req.{}.{}", slug, field))
}

/// Check out a branch by name
pub fn checkout_branch(
    remote_name: &str,
    remote_branch_name: &str,
    local_branch_name: &str,
) -> Result<bool, String> {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let local_branch_name = &format!("{}/{}", remote_name, local_branch_name);

    // Fetch the remote branch if there's no local branch with the correct name
    if repo.revparse_single(local_branch_name).is_err() {
        cmd!(
            "git",
            "fetch",
            remote_name,
            &format!("{}:{}", remote_branch_name, local_branch_name)
        )
        .run()
        .unwrap();
        if repo.revparse_single(&local_branch_name).is_err() {
            return Err(format!(
                "Could not find remote branch: {}",
                local_branch_name
            ));
        }
    }
    debug!("Checking out branch!");
    match cmd!("git", "checkout", local_branch_name).run() {
        Ok(_) => Ok(true),
        Err(err) => Err(format!("Could not check out local branch: {}", err)),
    }
}
<commit_msg>Apply the remote name as the branch prefix for local branches checked out from non-default remotes.<commit_after>use std::path::Path;
use std::str;

use duct::cmd;
use git2::{Config, Error, Repository};
use log::{debug, trace};
use shellexpand;

/// Update old `req.key` config format to include remote name, i.e, `req.remote_name.key`
fn migrate_legacy(field_name: &str, remote_name: &str) {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let mut cfg = repo.config().unwrap();

    if let Ok(ref value) = cfg.get_string(&format!("req.{}", field_name)) {
        cfg.set_str(&format!("req.{}.{}", remote_name, field_name), value)
            .unwrap();
        cfg.remove(&format!("req.{}", field_name)).unwrap();
    }
}

/// Convert a domain string into a configuration slug
fn slugify_domain(domain: &str) -> String {
    str::replace(domain, ".", "|")
}

/// Get the URL of the given remote
pub fn get_remote_url(remote: &str) -> String {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let remote = repo.find_remote(remote).expect("Couldn't find the remote");
    String::from(remote.url().unwrap())
}

/// Get a value fom the repository config
pub fn get_repo_info(repo_field: &str) -> Result<String, Error> {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let cfg = repo.config().unwrap();
    cfg.get_string(repo_field)
}

/// Get a value for the given project-local git-req config
pub fn get_config(field_name: &str, remote_name: &str) -> Option<String> {
    migrate_legacy(field_name, "origin");
    let key = format!("req.{}.{}", remote_name, field_name);
    match get_repo_info(&key) {
        Ok(val) => Some(val),
        Err(_) => None,
    }
}

/// Set a value for the project-local git-req configuration
pub fn set_config(field_name: &str, remote_name: &str, value: &str) {
    migrate_legacy(field_name, "origin");
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let mut cfg = repo.config().unwrap();
    cfg.set_str(&format!("req.{}.{}", remote_name, field_name), value)
        .unwrap();
}

/// Delete the entry for the project-local git-req config field with the provided name
pub fn delete_config(field_name: &str, remote_name: &str) {
    migrate_legacy(field_name, "origin");
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let mut cfg = repo.config().unwrap();
    cfg.remove(&format!("req.{}.{}", remote_name, field_name))
        .unwrap();
}

/// Get a value for the given global git-req config
pub fn get_req_config(domain: &str, field: &str) -> Option<String> {
    let slug = slugify_domain(domain);
    let cfg = Config::open(&Path::new(
        &shellexpand::tilde("~/.gitreqconfig").to_string(),
    ))
    .unwrap();
    match cfg.get_string(&format!("req.{}.{}", slug, field)) {
        Ok(val) => Some(val),
        Err(_) => None,
    }
}

/// Set a value for the global git-req configuration
pub fn set_req_config(domain: &str, field: &str, value: &str) {
    let slug = slugify_domain(domain);
    let mut cfg = Config::open(&Path::new(
        &shellexpand::tilde("~/.gitreqconfig").to_string(),
    ))
    .unwrap();
    cfg.set_str(&format!("req.{}.{}", slug, field), value)
        .unwrap();
}

/// Clear the value for the lobal git-req configuration
pub fn delete_req_config(domain: &str, field: &str) -> Result<(), Error> {
    let slug = slugify_domain(domain);
    let mut cfg = Config::open(&Path::new(
        &shellexpand::tilde("~/.gitreqconfig").to_string(),
    ))
    .unwrap();
    cfg.remove(&format!("req.{}.{}", slug, field))
}

/// Get the name of the default remote
#[allow(clippy::match_wild_err_arm)]
pub fn get_default_remote_name() -> Result<String, String> {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let remotes = repo.remotes().expect("Couldn't fetch the list of remotes");
    match remotes.len() {
        0 => panic!("Could not find any remotes"),
        1 => Ok(String::from(remotes.get(0).unwrap())),
        _ => match repo.find_remote("origin") {
            Ok(_) => Ok(String::from("origin")),
            Err(_) => Err(String::from("No origin remote found")),
        },
    }
}

/// Check out a branch by name
pub fn checkout_branch(
    remote_name: &str,
    remote_branch_name: &str,
    local_branch_name: &str,
) -> Result<bool, String> {
    let repo = Repository::open_from_env().expect("Couldn't find repository");
    let local_branch_name = match get_default_remote_name() {
        Ok(default_remote_name) => {
            if remote_name != default_remote_name {
                trace!("Non-default remote name requested: {}", remote_name);
                format!("{}/{}", remote_name, local_branch_name)
            } else {
                trace!("Default remote name requested: {}", remote_name);
                String::from(local_branch_name)
            }
        }
        Err(_) => {
            trace!(
                "Multiple remotes found, but none named origin: {}",
                remote_name
            );
            format!("{}/{}", remote_name, local_branch_name)
        }
    };

    // Fetch the remote branch if there's no local branch with the correct name
    if repo.revparse_single(&local_branch_name).is_err() {
        if cmd!(
            "git",
            "fetch",
            remote_name,
            &format!("{}:{}", remote_branch_name, local_branch_name)
        )
        .run()
        .is_err()
        {
            return Err(format!(
                "Could not fetch remote branch '{}' to local ref '{}'",
                remote_branch_name, local_branch_name
            ));
        }
        if repo.revparse_single(&local_branch_name).is_err() {
            return Err(format!(
                "Could not find remote branch: {}",
                local_branch_name
            ));
        }
    }
    debug!("Checking out branch: {}", local_branch_name);
    match cmd!("git", "checkout", local_branch_name).run() {
        Ok(_) => Ok(true),
        Err(err) => Err(format!("Could not check out local branch: {}", err)),
    }
}
<|endoftext|>


<commit_before>use module::{DataDefinition, encode_binding_identifier};
use core::*;
use renamer::{Name, NameSupply};
use types::*;
use interner::intern;

use std::vec::FromVec;

pub fn generate_deriving(bindings: &mut Vec<Binding<Id<Name>>>, data: &DataDefinition<Name>) {
    let mut gen = DerivingGen { name_supply: NameSupply::new() };
    for deriving in data.deriving.iter() {
        match deriving.as_slice() {
            "Eq" => {
                bindings.push(gen.generate_eq(data));
            }
            "Ord" => {
                let b = gen.generate_ord(data);
                debug!("Generated Ord {} ->>\n{}", data.typ, b);
                bindings.push(b);
            }
            x => fail!("Cannot generate instance for class {}", x)
        }
    }
}

struct DerivingGen {
    name_supply: NameSupply
}
impl DerivingGen {
    fn generate_eq(&mut self, data: &DataDefinition<Name>) -> Binding<Id<Name>> {
        self.make_binop("==", data, |this, id_l, id_r| {
            let alts = this.match_same_constructors(data, &id_r, |this, l, r| this.eq_fields(l, r));
            Case(box Identifier(id_l.clone()), alts)
        })
    }

    fn eq_fields(&mut self, args_l: &[Id<Name>], args_r: &[Id<Name>]) -> Expr<Id<Name>> {
        if args_l.len() >= 1 {
            let first = bool_binop("==", Identifier(args_l[0].clone()), Identifier(args_r[0].clone()));
            args_l.iter().skip(1).zip(args_r.iter().skip(1)).fold(first, |acc, (l, r)| {
                let test = bool_binop("==", Identifier(l.clone()), Identifier(r.clone()));
                bool_binop("&&", acc, test)
            })
        }
        else {
            true_expr()
        }
    }

    fn generate_ord(&mut self, data: &DataDefinition<Name>) -> Binding<Id<Name>> {
        self.make_binop("compare", data, |this, id_l, id_r| {
            //We first compare the tags of the arguments since this would otherwise the last of the alternatives
            let when_eq = {
                let alts = this.match_same_constructors(data, &id_r, |this, l, r| this.ord_fields(l, r));
                Case(box Identifier(id_l.clone()), alts)
            };
            let cmp = compare_tags(Identifier(id_l), Identifier(id_r));
            this.eq_or_default(cmp, when_eq)
        })
    }

    fn ord_fields(&mut self, args_l: &[Id<Name>], args_r: &[Id<Name>]) -> Expr<Id<Name>> {
        let ordering = Type::new_op(intern("Ordering"), box []);
        if args_l.len() >= 1 {
            let mut iter = args_l.iter().zip(args_r.iter()).rev();
            let (x, y) = iter.next().unwrap();
            let last = binop("compare", Identifier(x.clone()), Identifier(y.clone()), ordering.clone());
            iter.fold(last, |acc, (l, r)| {
                let test = bool_binop("compare", Identifier(l.clone()), Identifier(r.clone()));
                self.eq_or_default(test, acc)
            })
        }
        else {
            Identifier(id("EQ", ordering))
        }
    }

    ///Creates a binary function binding with the name 'funcname' which is a function in an instance for 'data'
    ///This function takes two parameters of the type of 'data'
    fn make_binop(&mut self, funcname: &str, data: &DataDefinition<Name>, func: |&mut DerivingGen, Id<Name>, Id<Name>| -> Expr<Id<Name>>) -> Binding<Id<Name>> {
        let arg_l = self.name_supply.anonymous();
        let arg_r = self.name_supply.anonymous();
        let id_r = Id::new(arg_r, data.typ.value.clone(), data.typ.constraints.clone());
        let id_l = Id::new(arg_l, data.typ.value.clone(), data.typ.constraints.clone());
        let expr = func(self, id_l.clone(), id_r.clone());
        let lambda_expr = Lambda(id_l, box Lambda(id_r, box expr));//TODO types
        let data_name = extract_applied_type(&data.typ.value).ctor().name;
        let name = encode_binding_identifier(data_name, intern(funcname));
        Binding {
            name: Id::new(Name { name: name, uid: 0 }, lambda_expr.get_type().clone(), box []),
            expression: lambda_expr
        }
    }

    fn eq_or_default(&mut self, cmp: Expr<Id<Name>>, def: Expr<Id<Name>>) -> Expr<Id<Name>> {
        let match_id = Id::new(self.name_supply.anonymous(), Type::new_op(intern("Ordering"), box []), box []);
        Case(box cmp, box [
            Alternative {
                pattern: ConstructorPattern(id("EQ", Type::new_op(intern("Ordering"), box [])), box []),
                expression: def
            },
            Alternative { pattern: IdentifierPattern(match_id.clone()), expression: Identifier(match_id) }
        ])
    }

    fn match_same_constructors(&mut self, data: &DataDefinition<Name>, id_r: &Id<Name>, f: |&mut DerivingGen, &[Id<Name>], &[Id<Name>]| -> Expr<Id<Name>>) -> ~[Alternative<Id<Name>>] {
        let alts: Vec<Alternative<Id<Name>>> = data.constructors.iter().map(|constructor| {
            let args_l: ~[Id<Name>] = FromVec::<Id<Name>>::from_vec(
                ArgIterator { typ: &constructor.typ.value }
                .map(|arg| Id::new(self.name_supply.anonymous(), arg.clone(), constructor.typ.constraints.clone()))
                .collect());
            let iter = ArgIterator { typ: &constructor.typ.value };
            let args_r: ~[Id<Name>] = FromVec::<Id<Name>>::from_vec(iter
                .map(|arg| Id::new(self.name_supply.anonymous(), arg.clone(), constructor.typ.constraints.clone()))
                .collect());
            let ctor_id = Id::new(constructor.name, iter.typ.clone(), constructor.typ.constraints.clone());
            let expr = f(self, args_l, args_r);
            let pattern_r = ConstructorPattern(ctor_id.clone(), args_r);
            let inner = Case(box Identifier(id_r.clone()), box [
                Alternative { pattern: pattern_r, expression: expr },
                Alternative {
                    pattern: WildCardPattern,
                    expression: Identifier(Id::new(Name { uid: 0, name: intern("False") }, bool_type(), box []))
                }
            ]);
            Alternative { pattern: ConstructorPattern(ctor_id, args_l), expression: inner }
        }).collect();
        FromVec::from_vec(alts)
    }
}

fn id(s: &str, typ: Type) -> Id<Name> {
    Id::new(Name {name: intern(s), uid: 0 }, typ, box [])
}

fn compare_tags(lhs: Expr<Id<Name>>, rhs: Expr<Id<Name>>) -> Expr<Id<Name>> {
    let var = Type::new_var(intern("a"));
    let typ = function_type_(var.clone(), function_type_(var.clone(), Type::new_op(intern("Ordering"), box [])));
    let id = Id::new(Name { name: intern("#compare_tags"), uid: 0 }, typ, box []);
    Apply(box Apply(box Identifier(id), box lhs), box rhs)
}

fn bool_binop(op: &str, lhs: Expr<Id<Name>>, rhs: Expr<Id<Name>>) -> Expr<Id<Name>> {
    binop(op, lhs, rhs, bool_type())
}
fn binop(op: &str, lhs: Expr<Id<Name>>, rhs: Expr<Id<Name>>, return_type: Type) -> Expr<Id<Name>> {
    let typ = function_type_(lhs.get_type().clone(), function_type_(rhs.get_type().clone(), return_type));
    let f = Identifier(Id::new(Name { name: intern(op), uid: 0 }, typ, box []));
    Apply(box Apply(box f, box lhs), box rhs)
}

fn true_expr() -> Expr<Id<Name>> {
    Identifier(Id::new(Name { uid: 0, name: intern("True") }, bool_type(), box []))
}

struct ArgIterator<'a> {
    typ: &'a Type
}
impl <'a> Iterator<&'a Type> for ArgIterator<'a> {
    fn next(&mut self) -> Option<&'a Type> {
        use types::try_get_function;
        match try_get_function(self.typ) {
            Some((arg, rest)) => {
                self.typ = rest;
                Some(arg)
            }
            None => None
        }
    }
}
fn extract_applied_type<'a>(typ: &'a Type) -> &'a Type {
    match typ {
        &TypeApplication(ref lhs, _) => extract_applied_type(*lhs),
        _ => typ
    }
}
<commit_msg>Generate constraints when creating derived instances for types with type parameters<commit_after>use module::{DataDefinition, encode_binding_identifier};
use core::*;
use renamer::{Name, NameSupply};
use types::*;
use interner::{intern, InternedStr};

use std::vec::FromVec;

pub fn generate_deriving(bindings: &mut Vec<Binding<Id<Name>>>, data: &DataDefinition<Name>) {
    let mut gen = DerivingGen { name_supply: NameSupply::new() };
    for deriving in data.deriving.iter() {
        match deriving.as_slice() {
            "Eq" => {
                bindings.push(gen.generate_eq(data));
            }
            "Ord" => {
                let b = gen.generate_ord(data);
                debug!("Generated Ord {} ->>\n{}", data.typ, b);
                bindings.push(b);
            }
            x => fail!("Cannot generate instance for class {}", x)
        }
    }
}

struct DerivingGen {
    name_supply: NameSupply
}
impl DerivingGen {
    fn generate_eq(&mut self, data: &DataDefinition<Name>) -> Binding<Id<Name>> {
        self.make_binop("Eq", "==", data, |this, id_l, id_r| {
            let alts = this.match_same_constructors(data, &id_r, |this, l, r| this.eq_fields(l, r));
            Case(box Identifier(id_l.clone()), alts)
        })
    }

    fn eq_fields(&mut self, args_l: &[Id<Name>], args_r: &[Id<Name>]) -> Expr<Id<Name>> {
        if args_l.len() >= 1 {
            let first = bool_binop("==", Identifier(args_l[0].clone()), Identifier(args_r[0].clone()));
            args_l.iter().skip(1).zip(args_r.iter().skip(1)).fold(first, |acc, (l, r)| {
                let test = bool_binop("==", Identifier(l.clone()), Identifier(r.clone()));
                bool_binop("&&", acc, test)
            })
        }
        else {
            true_expr()
        }
    }

    fn generate_ord(&mut self, data: &DataDefinition<Name>) -> Binding<Id<Name>> {
        self.make_binop("Ord", "compare", data, |this, id_l, id_r| {
            //We first compare the tags of the arguments since this would otherwise the last of the alternatives
            let when_eq = {
                let alts = this.match_same_constructors(data, &id_r, |this, l, r| this.ord_fields(l, r));
                Case(box Identifier(id_l.clone()), alts)
            };
            let cmp = compare_tags(Identifier(id_l), Identifier(id_r));
            this.eq_or_default(cmp, when_eq)
        })
    }

    fn ord_fields(&mut self, args_l: &[Id<Name>], args_r: &[Id<Name>]) -> Expr<Id<Name>> {
        let ordering = Type::new_op(intern("Ordering"), box []);
        if args_l.len() >= 1 {
            let mut iter = args_l.iter().zip(args_r.iter()).rev();
            let (x, y) = iter.next().unwrap();
            let last = binop("compare", Identifier(x.clone()), Identifier(y.clone()), ordering.clone());
            iter.fold(last, |acc, (l, r)| {
                let test = bool_binop("compare", Identifier(l.clone()), Identifier(r.clone()));
                self.eq_or_default(test, acc)
            })
        }
        else {
            Identifier(id("EQ", ordering))
        }
    }

    ///Creates a binary function binding with the name 'funcname' which is a function in an instance for 'data'
    ///This function takes two parameters of the type of 'data'
    fn make_binop(&mut self, class: &str, funcname: &str, data: &DataDefinition<Name>, func: |&mut DerivingGen, Id<Name>, Id<Name>| -> Expr<Id<Name>>) -> Binding<Id<Name>> {
        let arg_l = self.name_supply.anonymous();
        let arg_r = self.name_supply.anonymous();
        let mut id_r = Id::new(arg_r, data.typ.value.clone(), data.typ.constraints.clone());
        let mut id_l = Id::new(arg_l, data.typ.value.clone(), data.typ.constraints.clone());
        let expr = func(self, id_l.clone(), id_r.clone());
        id_r.typ.value = function_type_(data.typ.value.clone(), bool_type());
        id_l.typ.value = function_type_(data.typ.value.clone(), function_type_(data.typ.value.clone(), bool_type()));
        let lambda_expr = Lambda(id_l, box Lambda(id_r, box expr));//TODO types
        let data_name = extract_applied_type(&data.typ.value).ctor().name;
        let name = encode_binding_identifier(data_name, intern(funcname));
        //Create a constraint for each type parameter
        fn make_constraints(mut result: Vec<Constraint>, class: InternedStr, typ: &Type) -> ~[Constraint] {
            match typ {
                &TypeApplication(ref f, ref param) => {
                    result.push(Constraint { class: class, variables: box [param.var().clone()] });
                    make_constraints(result, class, *f)
                }
                _ => FromVec::from_vec(result)
            }
        }
        let constraints = make_constraints(Vec::new(), intern(class), &data.typ.value);
        Binding {
            name: Id::new(Name { name: name, uid: 0 }, lambda_expr.get_type().clone(), constraints),
            expression: lambda_expr
        }
    }

    fn eq_or_default(&mut self, cmp: Expr<Id<Name>>, def: Expr<Id<Name>>) -> Expr<Id<Name>> {
        let match_id = Id::new(self.name_supply.anonymous(), Type::new_op(intern("Ordering"), box []), box []);
        Case(box cmp, box [
            Alternative {
                pattern: ConstructorPattern(id("EQ", Type::new_op(intern("Ordering"), box [])), box []),
                expression: def
            },
            Alternative { pattern: IdentifierPattern(match_id.clone()), expression: Identifier(match_id) }
        ])
    }

    fn match_same_constructors(&mut self, data: &DataDefinition<Name>, id_r: &Id<Name>, f: |&mut DerivingGen, &[Id<Name>], &[Id<Name>]| -> Expr<Id<Name>>) -> ~[Alternative<Id<Name>>] {
        let alts: Vec<Alternative<Id<Name>>> = data.constructors.iter().map(|constructor| {
            let args_l: ~[Id<Name>] = FromVec::<Id<Name>>::from_vec(
                ArgIterator { typ: &constructor.typ.value }
                .map(|arg| Id::new(self.name_supply.anonymous(), arg.clone(), constructor.typ.constraints.clone()))
                .collect());
            let iter = ArgIterator { typ: &constructor.typ.value };
            let args_r: ~[Id<Name>] = FromVec::<Id<Name>>::from_vec(iter
                .map(|arg| Id::new(self.name_supply.anonymous(), arg.clone(), constructor.typ.constraints.clone()))
                .collect());
            let ctor_id = Id::new(constructor.name, iter.typ.clone(), constructor.typ.constraints.clone());
            let expr = f(self, args_l, args_r);
            let pattern_r = ConstructorPattern(ctor_id.clone(), args_r);
            let inner = Case(box Identifier(id_r.clone()), box [
                Alternative { pattern: pattern_r, expression: expr },
                Alternative {
                    pattern: WildCardPattern,
                    expression: Identifier(Id::new(Name { uid: 0, name: intern("False") }, bool_type(), box []))
                }
            ]);
            Alternative { pattern: ConstructorPattern(ctor_id, args_l), expression: inner }
        }).collect();
        FromVec::from_vec(alts)
    }
}

fn id(s: &str, typ: Type) -> Id<Name> {
    Id::new(Name {name: intern(s), uid: 0 }, typ, box [])
}

fn compare_tags(lhs: Expr<Id<Name>>, rhs: Expr<Id<Name>>) -> Expr<Id<Name>> {
    let var = Type::new_var(intern("a"));
    let typ = function_type_(var.clone(), function_type_(var.clone(), Type::new_op(intern("Ordering"), box [])));
    let id = Id::new(Name { name: intern("#compare_tags"), uid: 0 }, typ, box []);
    Apply(box Apply(box Identifier(id), box lhs), box rhs)
}

fn bool_binop(op: &str, lhs: Expr<Id<Name>>, rhs: Expr<Id<Name>>) -> Expr<Id<Name>> {
    binop(op, lhs, rhs, bool_type())
}
fn binop(op: &str, lhs: Expr<Id<Name>>, rhs: Expr<Id<Name>>, return_type: Type) -> Expr<Id<Name>> {
    let typ = function_type_(lhs.get_type().clone(), function_type_(rhs.get_type().clone(), return_type));
    let f = Identifier(Id::new(Name { name: intern(op), uid: 0 }, typ, box []));
    Apply(box Apply(box f, box lhs), box rhs)
}

fn true_expr() -> Expr<Id<Name>> {
    Identifier(Id::new(Name { uid: 0, name: intern("True") }, bool_type(), box []))
}

struct ArgIterator<'a> {
    typ: &'a Type
}
impl <'a> Iterator<&'a Type> for ArgIterator<'a> {
    fn next(&mut self) -> Option<&'a Type> {
        use types::try_get_function;
        match try_get_function(self.typ) {
            Some((arg, rest)) => {
                self.typ = rest;
                Some(arg)
            }
            None => None
        }
    }
}
fn extract_applied_type<'a>(typ: &'a Type) -> &'a Type {
    match typ {
        &TypeApplication(ref lhs, _) => extract_applied_type(*lhs),
        _ => typ
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::logger::log;
use serde::Deserialize;

/// Somewhat of an abstraction/combination of command line arguments and a
/// configuration file.
#[derive(Default, Clone, Debug)]
pub struct Settings {
    pub config: config::Config,
    pub args: clap::ArgMatches<'static>,
}

impl Settings {
    pub fn new(args: &clap::ArgMatches<'static>) -> Self {
        fix_deprecated_env_vars();
        let mut config = Settings {
            config: config::Config::default(),
            args: args.clone(),
        };
        config.load();
        config
    }

    fn load(&mut self) {
        let config_from_args: Option<String> = if let Some(config) = self.args.value_of("config") {
            Some(config.to_string())
        } else {
            None
        };
        if let Some(config) = config_from_args {
            self.merge_file(&config).unwrap();
        } else {
            // Check environment for configuration filename.
            if let Ok(config) = std::env::var("EVEBOX_CONFIG") {
                self.merge_file(&config).unwrap();
            }
        }

        self.config
            .merge(config::Environment::with_prefix("EVEBOX").separator("_"))
            .unwrap();
    }

    pub fn merge_file(&mut self, path: &str) -> Result<(), config::ConfigError> {
        let config_file = config::File::new(path, config::FileFormat::Yaml);
        self.config.merge(config_file)?;
        Ok(())
    }

    pub fn merge_yaml_str(&mut self, yaml: &str) -> Result<(), config::ConfigError> {
        let file = config::File::from_str(yaml, config::FileFormat::Yaml);
        self.config.merge(file)?;
        Ok(())
    }

    // There is a bit of a dance to get values in the following priority order...
    // - command line argument
    // - environment variable
    // - configuration file
    // - default set in clap
    pub fn get<'de, T: Deserialize<'de>>(&mut self, key: &str) -> Result<T, config::ConfigError> {
        if self.args.occurrences_of(key) > 0 {
            self.set_from_args(key);
        }
        match self.config.get(key) {
            Ok(val) => Ok(val),
            Err(err) => {
                if let config::ConfigError::NotFound(_) = err {
                    self.set_from_args(key);
                    return self.config.get(key);
                }
                Err(err)
            }
        }
    }

    pub fn get_or_none<'de, T: Deserialize<'de>>(
        &mut self,
        key: &str,
    ) -> Result<Option<T>, config::ConfigError> {
        match self.get(key) {
            Ok(val) => Ok(Some(val)),
            Err(config::ConfigError::NotFound(_)) => Ok(None),
            Err(err) => return Err(err),
        }
    }

    pub fn get_bool(&self, key: &str) -> Result<bool, config::ConfigError> {
        if self.args.occurrences_of(key) > 0 {
            return Ok(true);
        }
        match self.config.get_bool(key) {
            Ok(val) => Ok(val),
            Err(err) => {
                if let config::ConfigError::NotFound(_) = err {
                    Ok(false)
                } else {
                    return Err(err);
                }
            }
        }
    }

    pub fn count_of(&self, key: &str) -> u64 {
        if self.args.occurrences_of(key) > 0 {
            return self.args.occurrences_of(key);
        }
        if let Ok(_) = self.config.get::<config::Value>(key) {
            return 1;
        }
        return 0;
    }

    fn set_from_args(&mut self, key: &str) {
        if self.args.is_present(key) {
            self.config
                .set(key, self.args.value_of(key).unwrap())
                .unwrap();
        }
    }

    /// Return a value as an array of strings.
    pub fn get_string_array(&mut self, key: &str) -> Result<Vec<String>, config::ConfigError> {
        if self.args.occurrences_of(key) > 0 {
            let val = self
                .args
                .values_of(key)
                .unwrap()
                .map(String::from)
                .collect();
            return Ok(val);
        } else {
            let _: config::Value = self.config.get(key)?;
            if let Ok(val) = self.get::<Vec<String>>(key) {
                return Ok(val);
            }
            let val: String = self.get(key)?;
            return Ok(vec![val]);
        };
    }

    pub fn exists(&self, key: &str) -> bool {
        if self.args.value_of(key).is_some() {
            return true;
        }
        if let Ok(_) = self.config.get::<config::Value>(key) {
            return true;
        }
        return false;
    }
}

fn fix_deprecated_env_vars() {
    let mut vars = std::collections::HashMap::new();
    vars.insert("EVEBOX_TLS_ENABLED", "EVEBOX_HTTP_TLS_ENABLED");
    vars.insert("EVEBOX_TLS_CERT", "EVEBOX_HTTP_TLS_CERTIFICATE");
    vars.insert("EVEBOX_TLS_KEY", "EVEBOX_HTTP_TLS_KEY");
    for (old, new) in vars {
        if let Ok(val) = std::env::var(old) {
            log::info!(
                "Found deprecated environment variable {}, setting {}",
                old,
                new
            );
            std::env::set_var(new, val);
        }
    }
}

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

    const TEST_YAML: &str = r#"
verbose: true
    "#;

    #[test]
    fn test_bool() {
        let args: &[&str] = &["test-args"];
        let parser = App::new("EveBox").arg(Arg::with_name("verbose").short("v").multiple(true));
        let matches = parser.get_matches_from(args);
        let settings = Settings::new(&matches);
        assert_eq!(settings.get_bool("verbose").unwrap(), false);
        assert_eq!(settings.count_of("verbose"), 0);

        let args: &[&str] = &["test-args", "-v"];
        let parser = App::new("EveBox").arg(Arg::with_name("verbose").short("v").multiple(true));
        let matches = parser.get_matches_from(args);
        let settings = Settings::new(&matches);
        assert_eq!(settings.get_bool("verbose").unwrap(), true);
        assert_eq!(settings.count_of("verbose"), 1);

        let args: &[&str] = &["test-args", "-v", "-v"];
        let parser = App::new("EveBox").arg(Arg::with_name("verbose").short("v").multiple(true));
        let matches = parser.get_matches_from(args);
        let settings = Settings::new(&matches);
        assert_eq!(settings.get_bool("verbose").unwrap(), true);
        assert_eq!(settings.count_of("verbose"), 2);

        let args: &[&str] = &["test-args"];
        let parser = App::new("EveBox").arg(Arg::with_name("verbose").short("v").multiple(true));
        let matches = parser.get_matches_from(args);
        let mut settings = Settings::new(&matches);
        settings.merge_yaml_str(TEST_YAML).unwrap();
        assert_eq!(settings.get_bool("verbose").unwrap(), true);
        assert_eq!(settings.count_of("verbose"), 1);
    }
}
<commit_msg>server: handle env var ELASTICSEARCH_URL<commit_after>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::logger::log;
use serde::Deserialize;

/// Somewhat of an abstraction/combination of command line arguments and a
/// configuration file.
#[derive(Default, Clone, Debug)]
pub struct Settings {
    pub config: config::Config,
    pub args: clap::ArgMatches<'static>,
}

impl Settings {
    pub fn new(args: &clap::ArgMatches<'static>) -> Self {
        fix_deprecated_env_vars();
        let mut config = Settings {
            config: config::Config::default(),
            args: args.clone(),
        };
        config.load();
        config
    }

    fn load(&mut self) {
        let config_from_args: Option<String> = if let Some(config) = self.args.value_of("config") {
            Some(config.to_string())
        } else {
            None
        };
        if let Some(config) = config_from_args {
            self.merge_file(&config).unwrap();
        } else {
            // Check environment for configuration filename.
            if let Ok(config) = std::env::var("EVEBOX_CONFIG") {
                self.merge_file(&config).unwrap();
            }
        }

        // Migrate some old environment variables if found.
        if let Ok(val) = std::env::var("ELASTICSEARCH_URL") {
            if let Err(_) = std::env::var("EVEBOX_DATABASE_ELASTICSEARCH_URL") {
                log::debug!(
                    "Setting EVEBOX_DATABASE_ELASTICSEARCH_URL to {} from ELASTICSEARCH_URL",
                    val
                );
                std::env::set_var("EVEBOX_DATABASE_ELASTICSEARCH_URL", val);
            }
        }

        self.config
            .merge(config::Environment::with_prefix("EVEBOX").separator("_"))
            .unwrap();
    }

    pub fn merge_file(&mut self, path: &str) -> Result<(), config::ConfigError> {
        let config_file = config::File::new(path, config::FileFormat::Yaml);
        self.config.merge(config_file)?;
        Ok(())
    }

    pub fn merge_yaml_str(&mut self, yaml: &str) -> Result<(), config::ConfigError> {
        let file = config::File::from_str(yaml, config::FileFormat::Yaml);
        self.config.merge(file)?;
        Ok(())
    }

    // There is a bit of a dance to get values in the following priority order...
    // - command line argument
    // - environment variable
    // - configuration file
    // - default set in clap
    pub fn get<'de, T: Deserialize<'de>>(&mut self, key: &str) -> Result<T, config::ConfigError> {
        if self.args.occurrences_of(key) > 0 {
            self.set_from_args(key);
        }
        match self.config.get(key) {
            Ok(val) => Ok(val),
            Err(err) => {
                if let config::ConfigError::NotFound(_) = err {
                    self.set_from_args(key);
                    return self.config.get(key);
                }
                Err(err)
            }
        }
    }

    pub fn get_or_none<'de, T: Deserialize<'de>>(
        &mut self,
        key: &str,
    ) -> Result<Option<T>, config::ConfigError> {
        match self.get(key) {
            Ok(val) => Ok(Some(val)),
            Err(config::ConfigError::NotFound(_)) => Ok(None),
            Err(err) => return Err(err),
        }
    }

    pub fn get_bool(&self, key: &str) -> Result<bool, config::ConfigError> {
        if self.args.occurrences_of(key) > 0 {
            return Ok(true);
        }
        match self.config.get_bool(key) {
            Ok(val) => Ok(val),
            Err(err) => {
                if let config::ConfigError::NotFound(_) = err {
                    Ok(false)
                } else {
                    return Err(err);
                }
            }
        }
    }

    pub fn count_of(&self, key: &str) -> u64 {
        if self.args.occurrences_of(key) > 0 {
            return self.args.occurrences_of(key);
        }
        if let Ok(_) = self.config.get::<config::Value>(key) {
            return 1;
        }
        return 0;
    }

    fn set_from_args(&mut self, key: &str) {
        if self.args.is_present(key) {
            self.config
                .set(key, self.args.value_of(key).unwrap())
                .unwrap();
        }
    }

    /// Return a value as an array of strings.
    pub fn get_string_array(&mut self, key: &str) -> Result<Vec<String>, config::ConfigError> {
        if self.args.occurrences_of(key) > 0 {
            let val = self
                .args
                .values_of(key)
                .unwrap()
                .map(String::from)
                .collect();
            return Ok(val);
        } else {
            let _: config::Value = self.config.get(key)?;
            if let Ok(val) = self.get::<Vec<String>>(key) {
                return Ok(val);
            }
            let val: String = self.get(key)?;
            return Ok(vec![val]);
        };
    }

    pub fn exists(&self, key: &str) -> bool {
        if self.args.value_of(key).is_some() {
            return true;
        }
        if let Ok(_) = self.config.get::<config::Value>(key) {
            return true;
        }
        return false;
    }
}

fn fix_deprecated_env_vars() {
    let mut vars = std::collections::HashMap::new();
    vars.insert("EVEBOX_TLS_ENABLED", "EVEBOX_HTTP_TLS_ENABLED");
    vars.insert("EVEBOX_TLS_CERT", "EVEBOX_HTTP_TLS_CERTIFICATE");
    vars.insert("EVEBOX_TLS_KEY", "EVEBOX_HTTP_TLS_KEY");
    for (old, new) in vars {
        if let Ok(val) = std::env::var(old) {
            log::info!(
                "Found deprecated environment variable {}, setting {}",
                old,
                new
            );
            std::env::set_var(new, val);
        }
    }
}

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

    const TEST_YAML: &str = r#"
verbose: true
    "#;

    #[test]
    fn test_bool() {
        let args: &[&str] = &["test-args"];
        let parser = App::new("EveBox").arg(Arg::with_name("verbose").short("v").multiple(true));
        let matches = parser.get_matches_from(args);
        let settings = Settings::new(&matches);
        assert_eq!(settings.get_bool("verbose").unwrap(), false);
        assert_eq!(settings.count_of("verbose"), 0);

        let args: &[&str] = &["test-args", "-v"];
        let parser = App::new("EveBox").arg(Arg::with_name("verbose").short("v").multiple(true));
        let matches = parser.get_matches_from(args);
        let settings = Settings::new(&matches);
        assert_eq!(settings.get_bool("verbose").unwrap(), true);
        assert_eq!(settings.count_of("verbose"), 1);

        let args: &[&str] = &["test-args", "-v", "-v"];
        let parser = App::new("EveBox").arg(Arg::with_name("verbose").short("v").multiple(true));
        let matches = parser.get_matches_from(args);
        let settings = Settings::new(&matches);
        assert_eq!(settings.get_bool("verbose").unwrap(), true);
        assert_eq!(settings.count_of("verbose"), 2);

        let args: &[&str] = &["test-args"];
        let parser = App::new("EveBox").arg(Arg::with_name("verbose").short("v").multiple(true));
        let matches = parser.get_matches_from(args);
        let mut settings = Settings::new(&matches);
        settings.merge_yaml_str(TEST_YAML).unwrap();
        assert_eq!(settings.get_bool("verbose").unwrap(), true);
        assert_eq!(settings.count_of("verbose"), 1);
    }
}
<|endoftext|>


<commit_before>#[allow(dead_code)]

#[deriving(Clone, PartialEq)]
pub enum ExprAst {
    Int(IntNode),
    Str(StrNode),
    Bool(BoolNode),
    Pair(PairNode),
    Symbol(SymbolNode),
    Char(CharNode),
    Proc(ProcNode),
    CompProc(CompProcNode),
    EmptyList(EmptyListNode),
}

pub trait Ast {
    fn print(&self);
}

impl Ast for ExprAst {
    fn print(&self) {
        match *self {
            ExprAst::Int(ref ast) => ast.print(),
            ExprAst::Str(ref ast) => ast.print(),
            ExprAst::Bool(ref ast) => ast.print(),
            ExprAst::Pair(ref ast) => ast.print(),
            ExprAst::Symbol(ref ast) => ast.print(),
            ExprAst::Char(ref ast) => ast.print(),
            ExprAst::Proc(ref ast) => ast.print(),
            ExprAst::CompProc(ref ast) => ast.print(),
            ExprAst::EmptyList(ref ast) => ast.print(),
        }
    }
}

impl ExprAst {
    fn as_bool(&self) -> bool {
        match *self {
            ExprAst::Bool(ref ast) => ast.value,
            _ => panic!("error type: expect BoolNode")
        }
    }

    fn as_int(&self) -> i32 {
        match *self {
            ExprAst::Int(ref ast) => ast.value,
            _ => panic!("error type: expect IntNode")
        }
    }

    fn as_str(&self) -> String {
        match *self {
            ExprAst::Str(ref ast) => ast.value.clone(),
            _ => panic!("error type: expect StrNode")
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct IntNode {
    pub value: i32
}

#[allow(dead_code)]
impl IntNode {
    pub fn new(val: i32) -> IntNode {
        IntNode{ value: val}
    }
}

impl Ast for IntNode {
    fn print(&self) {
        println!("IntNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct StrNode {
    pub value: String
}

impl Ast for StrNode {
    fn print(&self) {
        println!("StrNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl StrNode {
    pub fn new(val: String) -> StrNode {
        StrNode{ value: val}
    }
}

#[deriving(Clone, PartialEq)]
pub struct BoolNode {
    pub value: bool
}

#[allow(dead_code)]
impl BoolNode {
    pub fn new(val: bool) -> BoolNode {
        BoolNode{ value: val}
    }
}

impl Ast for BoolNode {
    fn print(&self) {
        println!("BoolNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct PairNode{
    pub car: Box<ExprAst>,
    pub cdr: Box<ExprAst>
}

#[allow(dead_code)]
impl PairNode {
    pub fn new(_car: Box<ExprAst>, _cdr: Box<ExprAst>) -> PairNode {
        PairNode {
            car: _car,
            cdr: _cdr
        }
    }
}

impl Ast for PairNode {
    fn print(&self) {
        println!("PairNode (");
        self.car.print();
        self.cdr.print();
        //self.car.print();
        //self.cdr.print();
        println!(")");
    }
}

#[deriving(Clone, PartialEq)]
pub struct SymbolNode {
    pub value: String
}

impl Ast for SymbolNode {
    fn print(&self) {
        println!("SymbolNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl SymbolNode {
    pub fn new(val: String) -> SymbolNode {
        SymbolNode {
            value: val
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct CharNode {
    pub value: char
}

impl Ast for CharNode {
    fn print(&self) {
        println!("CharNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl CharNode {
    pub fn new(val: char) -> CharNode {
        CharNode {
            value: val
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct ProcNode {
    pub value: String
}

impl Ast for ProcNode {
    fn print(&self) {
        println!("ProcNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
struct EmptyListNode;

impl Ast for EmptyListNode{
    fn print(&self) {
        println!("EmptyListNode: nil");
    }
}

#[deriving(Clone, PartialEq)]
pub struct CompProcNode {
    pub params: Box<ExprAst>,
    pub body:   Box<ExprAst>,
    pub env:    Box<ExprAst>
}

impl Ast for CompProcNode {
    fn print(&self) {
        println!("CompProcNode: ");
        self.params.print();
        self.body.print();
        self.env.print();
    }
}

#[test]
fn test_ast_int() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_int() == 3);
}

#[test]
#[should_fail]
fn test_ast_int_fail() {
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    assert!(str_node.as_int() == 3);
}

#[test]
fn test_ast_bool() {
    let bool_node = ExprAst::Bool(BoolNode::new(false));
    assert!(bool_node.as_bool() == false);
}

#[test]
#[should_fail]
fn test_ast_bool_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_bool() == false);
}

#[test]
fn test_ast_str() {
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    assert!(str_node.as_str() == "hello".to_string());
}

#[test]
#[should_fail]
fn test_ast_str_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_str() == "3".to_string());
}

#[test]
fn test_ast_pair() {
    let int_node = ExprAst::Int(IntNode::new(3));
    int_node.print();
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    str_node.print();
    let pair_node = ExprAst::Pair(PairNode::new(box int_node, box str_node));

    pair_node.print();
}
<commit_msg>more on ast<commit_after>#[allow(dead_code)]

#[deriving(Clone, PartialEq)]
pub enum ExprAst {
    Int(IntNode),
    Str(StrNode),
    Bool(BoolNode),
    Pair(PairNode),
    Symbol(SymbolNode),
    Char(CharNode),
    Proc(ProcNode),
    CompProc(CompProcNode),
    EmptyList(EmptyListNode),
}

pub trait Ast {
    fn print(&self);
}

impl Ast for ExprAst {
    fn print(&self) {
        match *self {
            ExprAst::Int(ref ast) => ast.print(),
            ExprAst::Str(ref ast) => ast.print(),
            ExprAst::Bool(ref ast) => ast.print(),
            ExprAst::Pair(ref ast) => ast.print(),
            ExprAst::Symbol(ref ast) => ast.print(),
            ExprAst::Char(ref ast) => ast.print(),
            ExprAst::Proc(ref ast) => ast.print(),
            ExprAst::CompProc(ref ast) => ast.print(),
            ExprAst::EmptyList(ref ast) => ast.print(),
        }
    }
}

impl ExprAst {
    fn as_bool(&self) -> bool {
        match *self {
            ExprAst::Bool(ref ast) => ast.value,
            _ => panic!("error type: expect BoolNode")
        }
    }

    fn as_int(&self) -> i32 {
        match *self {
            ExprAst::Int(ref ast) => ast.value,
            _ => panic!("error type: expect IntNode")
        }
    }

    fn as_str(&self) -> String {
        match *self {
            ExprAst::Str(ref ast) => ast.value.clone(),
            _ => panic!("error type: expect StrNode")
        }
    }

    fn as_char(&self) -> char {
        match *self {
            ExprAst::Char(ref ast) => ast.value,
            _ => panic!("error type: expect CharNode")
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct IntNode {
    pub value: i32
}

#[allow(dead_code)]
impl IntNode {
    pub fn new(val: i32) -> IntNode {
        IntNode{ value: val}
    }
}

impl Ast for IntNode {
    fn print(&self) {
        println!("IntNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct StrNode {
    pub value: String
}

impl Ast for StrNode {
    fn print(&self) {
        println!("StrNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl StrNode {
    pub fn new(val: String) -> StrNode {
        StrNode{ value: val}
    }
}

#[deriving(Clone, PartialEq)]
pub struct BoolNode {
    pub value: bool
}

#[allow(dead_code)]
impl BoolNode {
    pub fn new(val: bool) -> BoolNode {
        BoolNode{ value: val}
    }
}

impl Ast for BoolNode {
    fn print(&self) {
        println!("BoolNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct PairNode{
    pub car: Box<ExprAst>,
    pub cdr: Box<ExprAst>
}

#[allow(dead_code)]
impl PairNode {
    pub fn new(_car: Box<ExprAst>, _cdr: Box<ExprAst>) -> PairNode {
        PairNode {
            car: _car,
            cdr: _cdr
        }
    }
}

impl Ast for PairNode {
    fn print(&self) {
        println!("PairNode (");
        self.car.print();
        self.cdr.print();
        //self.car.print();
        //self.cdr.print();
        println!(")");
    }
}

#[deriving(Clone, PartialEq)]
pub struct SymbolNode {
    pub value: String
}

impl Ast for SymbolNode {
    fn print(&self) {
        println!("SymbolNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl SymbolNode {
    pub fn new(val: String) -> SymbolNode {
        SymbolNode {
            value: val
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct CharNode {
    pub value: char
}

impl Ast for CharNode {
    fn print(&self) {
        println!("CharNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl CharNode {
    pub fn new(val: char) -> CharNode {
        CharNode {
            value: val
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct ProcNode {
    pub value: String
}

impl Ast for ProcNode {
    fn print(&self) {
        println!("ProcNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
struct EmptyListNode;

impl Ast for EmptyListNode{
    fn print(&self) {
        println!("EmptyListNode: nil");
    }
}

#[deriving(Clone, PartialEq)]
pub struct CompProcNode {
    pub params: Box<ExprAst>,
    pub body:   Box<ExprAst>,
    pub env:    Box<ExprAst>
}

impl Ast for CompProcNode {
    fn print(&self) {
        println!("CompProcNode: ");
        self.params.print();
        self.body.print();
        self.env.print();
    }
}

#[test]
fn test_ast_int() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_int() == 3);
}

#[test]
#[should_fail]
fn test_ast_int_fail() {
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    assert!(str_node.as_int() == 3);
}

#[test]
fn test_ast_bool() {
    let bool_node = ExprAst::Bool(BoolNode::new(false));
    assert!(bool_node.as_bool() == false);
}

#[test]
#[should_fail]
fn test_ast_bool_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_bool() == false);
}

#[test]
fn test_ast_char() {
    let char_node = ExprAst::Char(CharNode::new('a'));
    assert!(char_node.as_char() == 'a');
}

#[test]
#[should_fail]
fn test_ast_char_fail() {
    let int_node = ExprAst::Int(IntNode::new(1));
    assert!(int_node.as_char() == 'a');
}

#[test]
fn test_ast_str() {
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    assert!(str_node.as_str() == "hello".to_string());
}

#[test]
#[should_fail]
fn test_ast_str_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_str() == "3".to_string());
}

#[test]
fn test_ast_pair() {
    let int_node = ExprAst::Int(IntNode::new(3));
    int_node.print();
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    str_node.print();
    let pair_node = ExprAst::Pair(PairNode::new(box int_node, box str_node));

    pair_node.print();
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::cell::{RefCell, RefMut};

use reqwest::{Response};

use errors::*;
use client::MatrixClient;
use matrix_types::Event;

#[derive(Clone)]
pub struct RoomEvent<'a> {
    pub room_id: &'a str,
    pub raw_event: &'a Event,
}

pub struct Bot <'a, 'b> {
    client: RefCell<&'b mut MatrixClient>,
    root_services: Vec<&'a str>,
    all_services: HashMap<&'a str, RefCell<Box<Node<'a>>>>,

    rooms: RefCell<Vec<String>>,
}

impl<'a, 'b> Bot<'a, 'b> {
    pub fn new(client: &'b mut MatrixClient) -> Self{
        Bot {
            client: RefCell::new(client),
            root_services: Vec::new(),
            all_services: HashMap::new(),
            rooms: RefCell::new(Vec::new()),
        }
    }

    pub fn join(&self, room_id: &str) -> Result<Response, RustixError>{
        self.rooms.borrow_mut().push(room_id.clone().to_string());

        self.client.borrow().join(room_id)
    }

    pub fn say(&self, room_id: &str, message: &str) -> Result<Response, RustixError> {
        self.client.borrow_mut().send_msg(room_id, message)
    }

    pub fn reply(&self, event: &RoomEvent, message: &str) -> Result<Response, RustixError> {
        self.say(event.room_id, message)
    }

    /*
    pub fn action(&self, room_id: &str, action: &str) {
    }

    pub fn set_name(&self, name: &str) {
    }
    */

    pub fn register_service(&mut self,
                            name: &'a str,
                            parent: Option<&'a str>,
                            mut service: Box<Node<'a>>) -> Option<&'a str> {
        match parent {
            Some(p) => {
                self.all_services.get_mut(p).expect("Invalid parent node")
                    .borrow_mut().register_child(name)
            },
            None => self.root_services.push(name),
        };

        service.on_load();

        self.all_services.insert(name, RefCell::new(service));

        Some(name)
    }

    pub fn get_service(&self, name: &str) -> RefMut<Box<Node<'a>>> {
        self.all_services.get(name).unwrap().borrow_mut()
    }

    pub fn propagate_event(&self, event: &RoomEvent) {
        for service in &self.root_services {
            self.all_services.get(service).unwrap()
                .borrow_mut().handle(self, event.clone());
        }
    }

    pub fn run(&mut self) {
        let initial_rooms = vec!["test", "test2", "#geeks"];
        for room in initial_rooms {
            if let Some(rid) = self.client.borrow().get_public_room_id(room) {
                println!("Joining {} id: {}", &room, &rid);
                self.join(&rid);
            }
        }

        let mut next_batch: String = self.client.borrow().sync(None).unwrap().next_batch;

        loop {
            let sync_data = self.client.borrow().sync(Some(&next_batch)).unwrap();

            for room_id in self.rooms.borrow().iter() {
                if let Some(room) = sync_data.rooms.join.get(room_id) {
                    for raw_event in &room.timeline.events {
                        self.propagate_event(
                            &RoomEvent{room_id, raw_event}
                        );
                    }
                }
            }

            next_batch = sync_data.next_batch;
        }
    }
}

pub trait Node<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        None
    }

    fn register_child(&mut self, name: &'a str) {
    }

    fn propagate_event(&self, bot: &Bot, event: RoomEvent) {
        if let Some(children) = self.children() {
            for child in children {
                bot.get_service(child).handle(bot, event.clone());
            }
        }
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        self.propagate_event(bot, event);
    }

    fn on_load(&mut self) { }

    fn on_exit(&self) { }
}

/*
if let Ok(x) = serde_json::to_string_pretty(&res.rooms.join) {
    println!("{}", x);
} */
<commit_msg>Throttle sync calls to 800ms<commit_after>use std::collections::HashMap;
use std::{thread, time};
use std::cell::{RefCell, RefMut};

use reqwest::{Response};

use errors::*;
use client::MatrixClient;
use matrix_types::Event;

#[derive(Clone)]
pub struct RoomEvent<'a> {
    pub room_id: &'a str,
    pub raw_event: &'a Event,
}

pub struct Bot <'a, 'b> {
    client: RefCell<&'b mut MatrixClient>,
    root_services: Vec<&'a str>,
    all_services: HashMap<&'a str, RefCell<Box<Node<'a>>>>,

    rooms: RefCell<Vec<String>>,
}

impl<'a, 'b> Bot<'a, 'b> {
    pub fn new(client: &'b mut MatrixClient) -> Self{
        Bot {
            client: RefCell::new(client),
            root_services: Vec::new(),
            all_services: HashMap::new(),
            rooms: RefCell::new(Vec::new()),
        }
    }

    pub fn join(&self, room_id: &str) -> Result<Response, RustixError>{
        self.rooms.borrow_mut().push(room_id.clone().to_string());

        self.client.borrow().join(room_id)
    }

    pub fn say(&self, room_id: &str, message: &str) -> Result<Response, RustixError> {
        self.client.borrow_mut().send_msg(room_id, message)
    }

    pub fn reply(&self, event: &RoomEvent, message: &str) -> Result<Response, RustixError> {
        self.say(event.room_id, message)
    }

    /*
    pub fn action(&self, room_id: &str, action: &str) {
    }

    pub fn set_name(&self, name: &str) {
    }
    */

    pub fn register_service(&mut self,
                            name: &'a str,
                            parent: Option<&'a str>,
                            mut service: Box<Node<'a>>) -> Option<&'a str> {
        match parent {
            Some(p) => {
                self.all_services.get_mut(p).expect("Invalid parent node")
                    .borrow_mut().register_child(name)
            },
            None => self.root_services.push(name),
        };

        service.on_load();

        self.all_services.insert(name, RefCell::new(service));

        Some(name)
    }

    pub fn get_service(&self, name: &str) -> RefMut<Box<Node<'a>>> {
        self.all_services.get(name).unwrap().borrow_mut()
    }

    pub fn propagate_event(&self, event: &RoomEvent) {
        for service in &self.root_services {
            self.all_services.get(service).unwrap()
                .borrow_mut().handle(self, event.clone());
        }
    }

    pub fn run(&mut self) {
        let initial_rooms = vec!["test", "test2", "#geeks"];
        for room in initial_rooms {
            if let Some(rid) = self.client.borrow().get_public_room_id(room) {
                println!("Joining {} id: {}", &room, &rid);
                self.join(&rid);
            }
        }

        let mut next_batch: String = self.client.borrow().sync(None).unwrap().next_batch;

        let delay = time::Duration::from_millis(800);

        loop {
            let sync_data = self.client.borrow().sync(Some(&next_batch)).unwrap();

            for room_id in self.rooms.borrow().iter() {
                if let Some(room) = sync_data.rooms.join.get(room_id) {
                    for raw_event in &room.timeline.events {
                        self.propagate_event(
                            &RoomEvent{room_id, raw_event}
                        );
                    }
                }
            }

            next_batch = sync_data.next_batch;
            thread::sleep(delay);
        }
    }
}

pub trait Node<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        None
    }

    fn register_child(&mut self, name: &'a str) {
    }

    fn propagate_event(&self, bot: &Bot, event: RoomEvent) {
        if let Some(children) = self.children() {
            for child in children {
                bot.get_service(child).handle(bot, event.clone());
            }
        }
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        self.propagate_event(bot, event);
    }

    fn on_load(&mut self) { }

    fn on_exit(&self) { }
}

/*
if let Ok(x) = serde_json::to_string_pretty(&res.rooms.join) {
    println!("{}", x);
} */
<|endoftext|>


<commit_before>use std::slice;
use elf::strtab;
use elf::sym;

static HASH_SEED: u32 = 5381;

/// GNU hash function
pub fn hash(symbol: &str) -> u32 {
    let bytes = symbol.as_bytes();
    let mut hash = HASH_SEED;
    for b in bytes {
        hash = hash.wrapping_mul(32).wrapping_add(*b as u32).wrapping_add(hash);
    }
    hash
}

/// TODO add proper writeup for how this is constructed, how it resolves symbols, and how it works, see: https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
/// A Gnu Hash table as 4 sections:
/// 1. Header
/// 2. Bloom Filter
/// 3. Hash Buckets
/// 4. Hash Values
/// The header has is an array of four (4) u32s:
/// a. nbuckets
/// b. symndx
/// c. maskwords
/// d. shift2
pub struct GnuHash<'process> {
    nbuckets: u32,
    symindex: usize,
    shift2: u32,
    maskbits: u32,
    bloomwords: &'process [usize], // either 32 or 64 bit masks, depending on platform
    maskwords_bitmask: u32,
    buckets: &'process [u32],
    hashvalues: &'process [u32],
}

impl<'process> GnuHash<'process> {
    pub fn new(hashtab: *const u32, total_dynsyms: usize) -> GnuHash<'process> {
        unsafe {
            let nbuckets = *hashtab;
            let symindex = *hashtab.offset(1) as usize;
            let maskwords = *hashtab.offset(2) as usize; // how many words our bloom filter mask has
            let shift2 = *hashtab.offset(3);
            let bloomwords_ptr = hashtab.offset(4) as *const usize;
            let buckets_ptr = bloomwords_ptr.offset(maskwords as isize) as *const u32;
            let buckets = slice::from_raw_parts(buckets_ptr, nbuckets as usize);
            let hashvalues_ptr = buckets_ptr.offset(nbuckets as isize);
            let hashvalues = slice::from_raw_parts(hashvalues_ptr, total_dynsyms - symindex);
            let bloomwords = slice::from_raw_parts(bloomwords_ptr, maskwords);
            GnuHash {
                nbuckets: nbuckets,
                symindex: symindex,
                shift2: shift2,
                maskbits: 64, // because we don't have a compile time sizeof(usize) yet...
                bloomwords: bloomwords,
                hashvalues: hashvalues,
                buckets: buckets,
                maskwords_bitmask: ((maskwords as i32) - 1) as u32,
            }
        }
    }

    #[inline(always)]
    fn lookup(&self,
              hash: u32,
              symbol: &str,
              bias: u64,
              strtab: &'process strtab::Strtab,
              symtab: &'process [sym::Sym])
              -> Option<u64> {
        let mut idx = self.buckets[(hash % self.nbuckets) as usize] as usize;
        // println!("lookup idx = buckets[hash % nbuckets] = {}", idx);
        if idx == 0 {
            return None;
        }
        let mut hash_idx = idx - self.symindex;
        let hash = hash & !1;
        // TODO: replace this with an iterator
        loop {
            let symbol_ = &symtab[idx];
            let h2 = self.hashvalues[hash_idx];
            idx += 1;
            hash_idx += 1;
            let name = &strtab[symbol_.st_name as usize];
            // println!("{}: h2 0x{:x} resolves to: {}", i, h2, name);
            if hash == (h2 & !1) && name == symbol {
                // println!("lookup match for {} at: 0x{:x}", symbol, symbol_.st_value);
                return Some(symbol_.st_value + bias);
            }
            if h2 & 1 == 1 {
                break;
            } // end of chain
        }
        None
    }

    #[inline(always)]
    fn filter(&self, hash: u32) -> bool {
        let bloom_idx = (hash / self.maskbits) & self.maskwords_bitmask;
        let h2 = hash >> self.shift2;
        let bitmask = (1u64 << (hash % self.maskbits)) | (1u64 << (h2 % self.maskbits));
        // println!("lookup: maskwords: {} bloom_idx: {} bitmask: {} shift2: {}", self.maskwords, bloom_idx, bitmask, self.shift2);
        let filter = self.bloomwords[bloom_idx as usize];
        filter & (bitmask as usize) != (bitmask as usize) // if true, def _don't have_
    }

    /// Provide a name, a hash of that name, and the so to look in (which should have a reference to this self) -
    /// and we'll return an address option.
    pub fn find(&self,
                hash: u32,
                name: &str,
                bias: u64,
                strtab: &'process strtab::Strtab,
                symtab: &'process [sym::Sym])
                -> Option<u64> {
        if self.filter(hash) {
            None
        } else {
            self.lookup(hash, name, bias, strtab, symtab)
        }
    }
}
<commit_msg>elf.gnu_hash: return proper Sym, remove bias parameter<commit_after>use std::slice;
use elf::strtab;
use elf::sym;

static HASH_SEED: u32 = 5381;

/// GNU hash function
pub fn hash(symbol: &str) -> u32 {
    let bytes = symbol.as_bytes();
    let mut hash = HASH_SEED;
    for b in bytes {
        hash = hash.wrapping_mul(32).wrapping_add(*b as u32).wrapping_add(hash);
    }
    hash
}

/// TODO add proper writeup for how this is constructed, how it resolves symbols, and how it works, see: https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
/// A Gnu Hash table as 4 sections:
/// 1. Header
/// 2. Bloom Filter
/// 3. Hash Buckets
/// 4. Hash Values
/// The header has is an array of four (4) u32s:
/// a. nbuckets
/// b. symndx
/// c. maskwords
/// d. shift2
pub struct GnuHash<'process> {
    nbuckets: u32,
    symindex: usize,
    shift2: u32,
    maskbits: u32,
    bloomwords: &'process [usize], // either 32 or 64 bit masks, depending on platform
    maskwords_bitmask: u32,
    buckets: &'process [u32],
    hashvalues: &'process [u32],
}

impl<'process> GnuHash<'process> {
    pub fn new(hashtab: *const u32, total_dynsyms: usize) -> GnuHash<'process> {
        unsafe {
            let nbuckets = *hashtab;
            let symindex = *hashtab.offset(1) as usize;
            let maskwords = *hashtab.offset(2) as usize; // how many words our bloom filter mask has
            let shift2 = *hashtab.offset(3);
            let bloomwords_ptr = hashtab.offset(4) as *const usize;
            let buckets_ptr = bloomwords_ptr.offset(maskwords as isize) as *const u32;
            let buckets = slice::from_raw_parts(buckets_ptr, nbuckets as usize);
            let hashvalues_ptr = buckets_ptr.offset(nbuckets as isize);
            let hashvalues = slice::from_raw_parts(hashvalues_ptr, total_dynsyms - symindex);
            let bloomwords = slice::from_raw_parts(bloomwords_ptr, maskwords);
            GnuHash {
                nbuckets: nbuckets,
                symindex: symindex,
                shift2: shift2,
                maskbits: 64, // because we don't have a compile time sizeof(usize) yet...
                bloomwords: bloomwords,
                hashvalues: hashvalues,
                buckets: buckets,
                maskwords_bitmask: ((maskwords as i32) - 1) as u32,
            }
        }
    }

    #[inline(always)]
    fn lookup(&self,
              hash: u32,
              symbol: &str,
              strtab: &'process strtab::Strtab,
              symtab: &'process [sym::Sym])
              -> Option<sym::Sym> {
        let mut idx = self.buckets[(hash % self.nbuckets) as usize] as usize;
        // println!("lookup idx = buckets[hash % nbuckets] = {}", idx);
        if idx == 0 {
            return None;
        }
        let mut hash_idx = idx - self.symindex;
        let hash = hash & !1;
        // TODO: replace this with an iterator
        loop {
            let symbol_ = &symtab[idx];
            let h2 = self.hashvalues[hash_idx];
            idx += 1;
            hash_idx += 1;
            let name = &strtab[symbol_.st_name as usize];
            // println!("{}: h2 0x{:x} resolves to: {}", i, h2, name);
            if hash == (h2 & !1) && name == symbol {
                // println!("lookup match for {} at: 0x{:x}", symbol, symbol_.st_value);
                return Some(symbol_.clone());
            }
            if h2 & 1 == 1 {
                break;
            } // end of chain
        }
        None
    }

    #[inline(always)]
    fn filter(&self, hash: u32) -> bool {
        let bloom_idx = (hash / self.maskbits) & self.maskwords_bitmask;
        let h2 = hash >> self.shift2;
        let bitmask = (1u64 << (hash % self.maskbits)) | (1u64 << (h2 % self.maskbits));
        // println!("lookup: maskwords: {} bloom_idx: {} bitmask: {} shift2: {}", self.maskwords, bloom_idx, bitmask, self.shift2);
        let filter = self.bloomwords[bloom_idx as usize];
        filter & (bitmask as usize) != (bitmask as usize) // if true, def _don't have_
    }

    /// Given a name, a hash of that name, a strtab and corresponding symtab to look in, maybe returns a Sym
    pub fn find(&self,
                name: &str,
                hash: u32,
                strtab: &'process strtab::Strtab,
                symtab: &'process [sym::Sym])
                -> Option<sym::Sym> {
        if self.filter(hash) {
            None
        } else {
            self.lookup(hash, name, strtab, symtab)
        }
    }
}
<|endoftext|>


<commit_before>/// Calculates the tetrahedron (four) coordinates
///
/// # Output
///
/// * `zeta` -- the tetrahedron coordinates (len = 4)
///
/// # Input
///
/// * `xa,xb,xc,xd` -- corners (each has len = 3)
/// * `xp` -- the point to calculate the coordinates (len = 3)
///
/// # Panics
///
/// This function will panic if the array sizes are incorrect
pub fn tetrahedron_coords(zeta: &mut [f64], xa: &[f64], xb: &[f64], xc: &[f64], xd: &[f64], xp: &[f64]) {
    let (x1, y1, z1) = (xa[0], xa[1], xa[2]);
    let (x2, y2, z2) = (xb[0], xb[1], xb[2]);
    let (x3, y3, z3) = (xc[0], xc[1], xc[2]);
    let (x4, y4, z4) = (xd[0], xd[1], xd[2]);
    let (x, y, z) = (xp[0], xp[1], xp[2]);
    let v6 = (x2 - x1) * ((y2 - y3) * (z3 - z4) - (y3 - y4) * (z2 - z3))
        + (x3 - x2) * ((y3 - y4) * (z1 - z2) - (y1 - y2) * (z3 - z4))
        + (x4 - x3) * ((y1 - y2) * (z2 - z3) - (y2 - y3) * (z1 - z2));
    zeta[0] = ((x2 * (y3 * z4 - y4 * z3) + x3 * (y4 * z2 - y2 * z4) + x4 * (y2 * z3 - y3 * z2))
        + x * ((y4 - y2) * (z3 - z2) - (y3 - y2) * (z4 - z2))
        + y * ((x3 - x2) * (z4 - z2) - (x4 - x2) * (z3 - z2))
        + z * ((x4 - x2) * (y3 - y2) - (x3 - x2) * (y4 - y2)))
        / v6;
    zeta[1] = ((x1 * (y4 * z3 - y3 * z4) + x3 * (y1 * z4 - y4 * z1) + x4 * (y3 * z1 - y1 * z3))
        + x * ((y3 - y1) * (z4 - z3) - (y3 - y4) * (z1 - z3))
        + y * ((x4 - x3) * (z3 - z1) - (x1 - x3) * (z3 - z4))
        + z * ((x3 - x1) * (y4 - y3) - (x3 - x4) * (y1 - y3)))
        / v6;
    zeta[2] = ((x1 * (y2 * z4 - y4 * z2) + x2 * (y4 * z1 - y1 * z4) + x4 * (y1 * z2 - y2 * z1))
        + x * ((y2 - y4) * (z1 - z4) - (y1 - y4) * (z2 - z4))
        + y * ((x1 - x4) * (z2 - z4) - (x2 - x4) * (z1 - z4))
        + z * ((x2 - x4) * (y1 - y4) - (x1 - x4) * (y2 - y4)))
        / v6;
    zeta[3] = ((x1 * (y3 * z2 - y2 * z3) + x2 * (y1 * z3 - y3 * z1) + x3 * (y2 * z1 - y1 * z2))
        + x * ((y1 - y3) * (z2 - z1) - (y1 - y2) * (z3 - z1))
        + y * ((x2 - x1) * (z1 - z3) - (x3 - x1) * (z1 - z2))
        + z * ((x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1)))
        / v6;
}

/// Indicates if a point is inside a tetrahedron by looking at its tetrahedron coordinates (zeta)
///
/// Note: the point is inside (or on a face) if all zeta are positive (or zero)
#[inline]
pub fn in_tetrahedron(zeta: &[f64]) -> bool {
    for v in zeta {
        if *v < 0.0 {
            return false;
        }
    }
    return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{in_tetrahedron, tetrahedron_coords};
    use crate::util::ONE_BY_3;
    use russell_chk::assert_vec_approx_eq;

    #[test]
    fn tetrahedron_coords_works() {
        let xa = &[0.0, 0.0, 0.0];
        let xb = &[1.0, 0.0, 0.0];
        let xc = &[0.0, 1.0, 0.0];
        let xd = &[0.0, 0.0, 1.0];
        let mut zeta = vec![0.0; 4];
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.0, 0.0, 0.0]);
        assert_eq!(zeta, &[1.0, 0.0, 0.0, 0.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[1.0, 0.0, 0.0]);
        assert_eq!(zeta, &[0.0, 1.0, 0.0, 0.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.0, 1.0, 0.0]);
        assert_eq!(zeta, &[0.0, 0.0, 1.0, 0.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.0, 0.0, 1.0]);
        assert_eq!(zeta, &[0.0, 0.0, 0.0, 1.0]);

        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.5, 0.5, 0.0]);
        assert_eq!(zeta, &[0.0, 0.5, 0.5, 0.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.5, 0.5, 0.5]);
        assert_eq!(zeta, &[-0.5, 0.5, 0.5, 0.5]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[1.0, 1.0, 1.0]);
        assert_eq!(zeta, &[-2.0, 1.0, 1.0, 1.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[ONE_BY_3, ONE_BY_3, ONE_BY_3]);
        assert_vec_approx_eq!(zeta, &[0.0, ONE_BY_3, ONE_BY_3, ONE_BY_3], 1e-15);
    }

    #[test]
    fn in_tetrahedron_works() {
        assert_eq!(in_tetrahedron(&[-1.0, 0.0, 0.0, 0.0]), false);
        assert_eq!(in_tetrahedron(&[0.0, -1.0, 0.0, 0.0]), false);
        assert_eq!(in_tetrahedron(&[0.0, 0.0, -1.0, 0.0]), false);
        assert_eq!(in_tetrahedron(&[0.0, 0.0, 0.0, -1.0]), false);
        assert_eq!(in_tetrahedron(&[0.0, 0.0, 0.0, 0.0]), true);
    }
}
<commit_msg>Improve in_tet function<commit_after>/// Calculates the tetrahedron (four) coordinates
///
/// # Output
///
/// * `zeta` -- the tetrahedron coordinates (len = 4)
///
/// # Input
///
/// * `xa,xb,xc,xd` -- corners (each has len = 3)
/// * `xp` -- the point to calculate the coordinates (len = 3)
///
/// # Panics
///
/// This function will panic if the array sizes are incorrect
pub fn tetrahedron_coords(zeta: &mut [f64], xa: &[f64], xb: &[f64], xc: &[f64], xd: &[f64], xp: &[f64]) {
    let (x1, y1, z1) = (xa[0], xa[1], xa[2]);
    let (x2, y2, z2) = (xb[0], xb[1], xb[2]);
    let (x3, y3, z3) = (xc[0], xc[1], xc[2]);
    let (x4, y4, z4) = (xd[0], xd[1], xd[2]);
    let (x, y, z) = (xp[0], xp[1], xp[2]);
    let v6 = (x2 - x1) * ((y2 - y3) * (z3 - z4) - (y3 - y4) * (z2 - z3))
        + (x3 - x2) * ((y3 - y4) * (z1 - z2) - (y1 - y2) * (z3 - z4))
        + (x4 - x3) * ((y1 - y2) * (z2 - z3) - (y2 - y3) * (z1 - z2));
    zeta[0] = ((x2 * (y3 * z4 - y4 * z3) + x3 * (y4 * z2 - y2 * z4) + x4 * (y2 * z3 - y3 * z2))
        + x * ((y4 - y2) * (z3 - z2) - (y3 - y2) * (z4 - z2))
        + y * ((x3 - x2) * (z4 - z2) - (x4 - x2) * (z3 - z2))
        + z * ((x4 - x2) * (y3 - y2) - (x3 - x2) * (y4 - y2)))
        / v6;
    zeta[1] = ((x1 * (y4 * z3 - y3 * z4) + x3 * (y1 * z4 - y4 * z1) + x4 * (y3 * z1 - y1 * z3))
        + x * ((y3 - y1) * (z4 - z3) - (y3 - y4) * (z1 - z3))
        + y * ((x4 - x3) * (z3 - z1) - (x1 - x3) * (z3 - z4))
        + z * ((x3 - x1) * (y4 - y3) - (x3 - x4) * (y1 - y3)))
        / v6;
    zeta[2] = ((x1 * (y2 * z4 - y4 * z2) + x2 * (y4 * z1 - y1 * z4) + x4 * (y1 * z2 - y2 * z1))
        + x * ((y2 - y4) * (z1 - z4) - (y1 - y4) * (z2 - z4))
        + y * ((x1 - x4) * (z2 - z4) - (x2 - x4) * (z1 - z4))
        + z * ((x2 - x4) * (y1 - y4) - (x1 - x4) * (y2 - y4)))
        / v6;
    zeta[3] = ((x1 * (y3 * z2 - y2 * z3) + x2 * (y1 * z3 - y3 * z1) + x3 * (y2 * z1 - y1 * z2))
        + x * ((y1 - y3) * (z2 - z1) - (y1 - y2) * (z3 - z1))
        + y * ((x2 - x1) * (z1 - z3) - (x3 - x1) * (z1 - z2))
        + z * ((x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1)))
        / v6;
}

/// Indicates if a point is inside a tetrahedron by looking at its tetrahedron coordinates (zeta)
///
/// Note: the point is inside (or on a face) if all zeta are positive (or zero)
#[inline]
pub fn in_tetrahedron(zeta: &[f64]) -> bool {
    if zeta[0] < 0.0 || zeta[1] < 0.0 || zeta[2] < 0.0 || zeta[3] < 0.0 {
        false
    } else {
        true
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{in_tetrahedron, tetrahedron_coords};
    use crate::util::ONE_BY_3;
    use russell_chk::assert_vec_approx_eq;

    #[test]
    fn tetrahedron_coords_works() {
        let xa = &[0.0, 0.0, 0.0];
        let xb = &[1.0, 0.0, 0.0];
        let xc = &[0.0, 1.0, 0.0];
        let xd = &[0.0, 0.0, 1.0];
        let mut zeta = vec![0.0; 4];
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.0, 0.0, 0.0]);
        assert_eq!(zeta, &[1.0, 0.0, 0.0, 0.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[1.0, 0.0, 0.0]);
        assert_eq!(zeta, &[0.0, 1.0, 0.0, 0.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.0, 1.0, 0.0]);
        assert_eq!(zeta, &[0.0, 0.0, 1.0, 0.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.0, 0.0, 1.0]);
        assert_eq!(zeta, &[0.0, 0.0, 0.0, 1.0]);

        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.5, 0.5, 0.0]);
        assert_eq!(zeta, &[0.0, 0.5, 0.5, 0.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[0.5, 0.5, 0.5]);
        assert_eq!(zeta, &[-0.5, 0.5, 0.5, 0.5]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[1.0, 1.0, 1.0]);
        assert_eq!(zeta, &[-2.0, 1.0, 1.0, 1.0]);
        tetrahedron_coords(&mut zeta, xa, xb, xc, xd, &[ONE_BY_3, ONE_BY_3, ONE_BY_3]);
        assert_vec_approx_eq!(zeta, &[0.0, ONE_BY_3, ONE_BY_3, ONE_BY_3], 1e-15);
    }

    #[test]
    fn in_tetrahedron_works() {
        assert_eq!(in_tetrahedron(&[-1.0, 0.0, 0.0, 0.0]), false);
        assert_eq!(in_tetrahedron(&[0.0, -1.0, 0.0, 0.0]), false);
        assert_eq!(in_tetrahedron(&[0.0, 0.0, -1.0, 0.0]), false);
        assert_eq!(in_tetrahedron(&[0.0, 0.0, 0.0, -1.0]), false);
        assert_eq!(in_tetrahedron(&[0.0, 0.0, 0.0, 0.0]), true);
    }
}
<|endoftext|>