<commit_before>use super::node::write_node;
use super::node::NodeWriteGuard;
use super::search::MutSearchResult;
use super::BPlusTree;
use super::LevelTree;
use super::NodeCellRef;
use super::*;
use itertools::Itertools;
use std::fmt::Debug;
use std::cmp::{min, max};
use std::sync::atomic::Ordering;

pub const LEVEL_PAGE_DIFF_MULTIPLIER: usize = 4;
pub const LEVEL_TREE_DEPTH: u32 = 2;

pub const LEVEL_M: usize = 16; // Smaller can be faster but more fragmented
pub const LEVEL_1: usize = LEVEL_M * LEVEL_PAGE_DIFF_MULTIPLIER;
pub const LEVEL_2: usize = LEVEL_1 * LEVEL_PAGE_DIFF_MULTIPLIER;

pub const NUM_LEVELS: usize = 3;

enum NodeSelection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    WholePage(Vec<NodeWriteGuard<KS, PS>>, NodeWriteGuard<KS, PS>),
    PartialPage(Vec<NodeWriteGuard<KS, PS>>, NodeWriteGuard<KS, PS>),
}

// NEVER MAKE THIS ASYNC
fn merge_prune<KS, PS>(
    level: usize,
    node: &NodeCellRef,
    src_tree: &BPlusTree<KS, PS>,
    dest_tree: &dyn LevelTree,
    boundary: &EntryKey,
    lsm: usize
) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_first::<KS, PS>(node);
    match search {
        MutSearchResult::External => {
            if let NodeSelection::WholePage(nodes, mut new_first) =
                select_nodes_in_boundary::<KS, PS>(node, boundary, level, lsm)
            {
                let new_first_ref = new_first.node_ref().clone();
                let head_id = nodes[0].ext_id();
                new_first.extnode_mut(src_tree).id = head_id;
                new_first.left_ref_mut().map(|lr| *lr = Default::default());
                drop(new_first);
                debug_assert!(
                    !nodes.is_empty(),
                    "Cannot find any keys in range in external with boundary {:?}",
                    boundary
                );
                let mut num_keys_merged = 0;
                debug!("Selected {} pages to merge", nodes.len());
                for mut node in nodes {
                    let node_id = node.ext_id();
                    let node_len = node.len();
                    let deleted_keys = node
                        .keys()
                        .iter()
                        .filter(|k| src_tree.deleted.contains(k))
                        .cloned()
                        .collect_vec();
                    let merging_keys = node.extnode_mut_no_persist().keys.as_slice()[..node_len]
                        .iter_mut()
                        .filter(|k| !src_tree.deleted.contains(k))
                        .map(|k| mem::take(k))
                        .collect_vec();
                    let num_merging_keys = merging_keys.len();
                    num_keys_merged += num_merging_keys;
                    debug!(
                        "Collected {} keys, merging to destination tree",
                        num_merging_keys
                    );
                    dest_tree.merge_with_keys(box merging_keys);
                    debug!("Merge completed, cleanup");
                    // Update delete set in source
                    for dk in deleted_keys {
                        src_tree.deleted.remove(&dk);
                    }
                    clear_node(node, &new_first_ref);
                    if node_id != head_id {
                        external::make_deleted::<KS, PS>(&node_id);
                    }
                    src_tree.len.fetch_sub(num_merging_keys, Ordering::Relaxed);
                }
                debug!("Merge prune completed in external level");
                return num_keys_merged;
            } else {
                unreachable!();
            }
        }
        MutSearchResult::Internal(sub_node) => {
            let num_keys_merged = merge_prune(level + 1, &sub_node, src_tree, dest_tree, boundary, lsm);
            match select_nodes_in_boundary::<KS, PS>(node, boundary, level, lsm) {
                NodeSelection::WholePage(nodes, right_node) => {
                    let right_ref = right_node.node_ref().clone();
                    drop(right_node);
                    clear_nodes(nodes, &right_ref);
                }
                NodeSelection::PartialPage(nodes, mut terminal_node) => {
                    clear_nodes(nodes, terminal_node.node_ref());
                    let search_pos = terminal_node.keys().binary_search(boundary);
                    let pos = match search_pos {
                        Ok(n) => n + 1,
                        Err(n) => n
                    };
                    let mut new_keys = KS::init();
                    let mut new_ptrs = PS::init();
                    let mut num_keys = 0;
                    for (i, k) in terminal_node.keys()[pos..].iter().enumerate() {
                        new_keys.as_slice()[i] = k.clone();
                        num_keys += 1;
                    }
                    for (i, p) in terminal_node.ptrs()[pos..].iter().enumerate() {
                        new_ptrs.as_slice()[i] = p.clone();
                    }
                    let root_innode = terminal_node.innode_mut();
                    root_innode.keys = new_keys;
                    root_innode.ptrs = new_ptrs;
                    root_innode.len = num_keys;
                }
            }
            return num_keys_merged;
        }
    }
}

fn clear_node<KS, PS>(mut node: NodeWriteGuard<KS, PS>, right_ref: &NodeCellRef)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    node.make_empty_node(false);
    *node.right_ref_mut().unwrap() = right_ref.clone();
    node.left_ref_mut().map(|r| *r = right_ref.clone());
}

fn clear_nodes<KS, PS>(nodes: Vec<NodeWriteGuard<KS, PS>>, right_ref: &NodeCellRef)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    for node in nodes {
        clear_node(node, right_ref);
    }
}

fn select_nodes_in_boundary<KS, PS>(
    first_node: &NodeCellRef,
    right_boundary: &EntryKey,
    level: usize,
    lsm: usize,
) -> NodeSelection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(first_node);
    if first_node.right_bound() > right_boundary {
        return NodeSelection::PartialPage(vec![], first_node);
    }
    let mut next_node = write_node(first_node.right_ref().unwrap());
    let mut collected = vec![first_node];
    loop {
        let first_key = next_node.first_key();
        let node_right = next_node.right_bound();
        debug_assert!(
            first_key < right_boundary,
            "First key {:?} out of bound {:?}, collected {}. Level {}, LSM {}",
            first_key,
            right_boundary,
            collected.len(),
            level,
            lsm
        );
        if node_right <= right_boundary {
            let next_right = write_node(next_node.right_ref().unwrap());
            collected.push(next_node);
            next_node = next_right;
            if next_node.first_key() >= right_boundary {
                trace!("Collected {} nodes at level {}", collected.len(), level);
                return NodeSelection::WholePage(collected, next_node);
            }
        } else {
            return NodeSelection::PartialPage(collected, next_node);
        }
    }
}

fn select_boundary<KS, PS>(node: &NodeCellRef) -> EntryKey
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let res = read_node(node, |node: &NodeReadHandler<KS, PS>| {
        let node_keys = node.keys();
        let node_len = node_keys.len();
        if node.len() < 2 {
            return Err(node.ptrs()[0].clone());
        }
        // Pick half of the keys in the root
        // Genreally, higher level sub tree in LSM tree will select more keys to merged
        // into next level
        let mid_idx = min(node_len / 2, 8);
        // Return the mid key as the boundary for selection (cut)
        Ok(node_keys[mid_idx].clone())
    });
    match res {
        Ok(key) => key.clone(),
        Err(r) => select_boundary::<KS, PS>(&r)
    }
}

pub async fn level_merge<KS, PS>(
    level: usize,
    src_tree: &BPlusTree<KS, PS>,
    dest_tree: &dyn LevelTree,
) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    debug!("Merging LSM tree level {}", level);
    debug_assert!(verification::tree_has_no_empty_node(&src_tree));
    debug_assert!(verification::is_tree_in_order(&src_tree, level));
    let root = src_tree.get_root();
    let key_boundary = select_boundary::<KS, PS>(&root);
    debug!(
        "Level merge level {} with boundary {:?}",
        level, key_boundary
    );
    let num_keys = merge_prune(0, &src_tree.get_root(), src_tree, dest_tree, &key_boundary, level);
    debug_assert!(verification::tree_has_no_empty_node(&src_tree));
    debug_assert!(verification::is_tree_in_order(&src_tree, level));
    debug!("Merge and pruned level {}, waiting for storage", level);
    storage::wait_until_updated().await;
    debug!("MERGE LEVEL {} COMPLETED", level);
    return num_keys;
}
<commit_msg>attempting level shrinking<commit_after>use super::node::write_node;
use super::node::NodeWriteGuard;
use super::search::MutSearchResult;
use super::BPlusTree;
use super::LevelTree;
use super::NodeCellRef;
use super::*;
use itertools::Itertools;
use std::fmt::Debug;
use std::cmp::{min, max};
use std::sync::atomic::Ordering;

pub const LEVEL_PAGE_DIFF_MULTIPLIER: usize = 4;
pub const LEVEL_TREE_DEPTH: u32 = 2;

pub const LEVEL_M: usize = 16; // Smaller can be faster but more fragmented
pub const LEVEL_1: usize = LEVEL_M * LEVEL_PAGE_DIFF_MULTIPLIER;
pub const LEVEL_2: usize = LEVEL_1 * LEVEL_PAGE_DIFF_MULTIPLIER;

pub const NUM_LEVELS: usize = 3;

enum NodeSelection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    WholePage(Vec<NodeWriteGuard<KS, PS>>, NodeWriteGuard<KS, PS>),
    PartialPage(Vec<NodeWriteGuard<KS, PS>>, NodeWriteGuard<KS, PS>),
}

// NEVER MAKE THIS ASYNC
fn merge_prune<KS, PS>(
    level: usize,
    node: &NodeCellRef,
    src_tree: &BPlusTree<KS, PS>,
    dest_tree: &dyn LevelTree,
    boundary: &EntryKey,
    lsm: usize
) -> (usize, Option<NodeWriteGuard<KS, PS>>)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_first::<KS, PS>(node);
    match search {
        MutSearchResult::External => {
            if let NodeSelection::WholePage(nodes, mut new_first) =
                select_nodes_in_boundary::<KS, PS>(node, boundary, level, lsm)
            {
                let new_first_ref = new_first.node_ref().clone();
                let head_id = nodes[0].ext_id();
                new_first.extnode_mut(src_tree).id = head_id;
                new_first.left_ref_mut().map(|lr| *lr = Default::default());
                drop(new_first);
                debug_assert!(
                    !nodes.is_empty(),
                    "Cannot find any keys in range in external with boundary {:?}",
                    boundary
                );
                let mut num_keys_merged = 0;
                debug!("Selected {} pages to merge", nodes.len());
                for mut node in nodes {
                    let node_id = node.ext_id();
                    let node_len = node.len();
                    let deleted_keys = node
                        .keys()
                        .iter()
                        .filter(|k| src_tree.deleted.contains(k))
                        .cloned()
                        .collect_vec();
                    let merging_keys = node.extnode_mut_no_persist().keys.as_slice()[..node_len]
                        .iter_mut()
                        .filter(|k| !src_tree.deleted.contains(k))
                        .map(|k| mem::take(k))
                        .collect_vec();
                    let num_merging_keys = merging_keys.len();
                    num_keys_merged += num_merging_keys;
                    debug!(
                        "Collected {} keys, merging to destination tree",
                        num_merging_keys
                    );
                    dest_tree.merge_with_keys(box merging_keys);
                    debug!("Merge completed, cleanup");
                    // Update delete set in source
                    for dk in deleted_keys {
                        src_tree.deleted.remove(&dk);
                    }
                    clear_node(node, &new_first_ref);
                    if node_id != head_id {
                        external::make_deleted::<KS, PS>(&node_id);
                    }
                    src_tree.len.fetch_sub(num_merging_keys, Ordering::Relaxed);
                }
                debug!("Merge prune completed in external level");
                return (num_keys_merged, None);
            } else {
                unreachable!();
            }
        }
        MutSearchResult::Internal(sub_node) => {
            enum RightCheck<KS, PS>
              where
                KS: Slice<EntryKey> + Debug + 'static,
                PS: Slice<NodeCellRef> + 'static,
            {
                SinglePtr,
                LevelTerminal(NodeWriteGuard<KS, PS>),
                Normal
            }
            let check_right = |node: NodeWriteGuard<KS, PS>| {
                if node.right_ref().unwrap().is_default() {
                    debug_assert_eq!(node.right_bound(), &EntryKey::max());
                    if node.len() == 0 {
                        RightCheck::SinglePtr
                    } else {
                        RightCheck::LevelTerminal(node)
                    }
                } else {
                    debug_assert_ne!(node.right_bound(), &EntryKey::max());
                    debug_assert!(node.len() > 0);
                    RightCheck::Normal
                }
            };
            let (num_keys_merged, sub_level_new_root) = merge_prune(level + 1, &sub_node, src_tree, dest_tree, boundary, lsm);
            let right_node = match select_nodes_in_boundary::<KS, PS>(node, boundary, level, lsm) {
                NodeSelection::WholePage(nodes, right_node) => {
                    let right_ref = right_node.node_ref().clone();
                    let right_checks = check_right(right_node);
                    clear_nodes(nodes, &right_ref);
                    right_checks
                }
                NodeSelection::PartialPage(nodes, mut terminal_node) => {
                    clear_nodes(nodes, terminal_node.node_ref());
                    let search_pos = terminal_node.keys().binary_search(boundary);
                    let pos = match search_pos {
                        Ok(n) => n + 1,
                        Err(n) => n
                    };
                    let mut new_keys = KS::init();
                    let mut new_ptrs = PS::init();
                    let mut num_keys = 0;
                    for (i, k) in terminal_node.keys()[pos..].iter().enumerate() {
                        new_keys.as_slice()[i] = k.clone();
                        num_keys += 1;
                    }
                    for (i, p) in terminal_node.ptrs()[pos..].iter().enumerate() {
                        new_ptrs.as_slice()[i] = p.clone();
                    }
                    {
                        let innode = terminal_node.innode_mut();
                        innode.keys = new_keys;
                        innode.ptrs = new_ptrs;
                        innode.len = num_keys;
                    }
                    check_right(terminal_node)
                }
            };
            let new_root = {
                if let Some(sub_level_new_root) = sub_level_new_root {
                    if cfg!(debug_assertions) {
                        match right_node {
                            RightCheck::SinglePtr => {},
                            _ => panic!("Unexpected node status")
                        }
                    }
                    Some(sub_level_new_root)
                } else {
                    match right_node {
                        RightCheck::Normal => None,
                        RightCheck::LevelTerminal(node) => Some(node),
                        RightCheck::SinglePtr => unreachable!(),
                    }
                }
            };
            return (num_keys_merged, new_root);
        }
    }
}

fn clear_node<KS, PS>(mut node: NodeWriteGuard<KS, PS>, right_ref: &NodeCellRef)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    node.make_empty_node(false);
    *node.right_ref_mut().unwrap() = right_ref.clone();
    node.left_ref_mut().map(|r| *r = right_ref.clone());
}

fn clear_nodes<KS, PS>(nodes: Vec<NodeWriteGuard<KS, PS>>, right_ref: &NodeCellRef)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    for node in nodes {
        clear_node(node, right_ref);
    }
}

fn select_nodes_in_boundary<KS, PS>(
    first_node: &NodeCellRef,
    right_boundary: &EntryKey,
    level: usize,
    lsm: usize,
) -> NodeSelection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(first_node);
    if first_node.right_bound() > right_boundary {
        return NodeSelection::PartialPage(vec![], first_node);
    }
    let mut next_node = write_node(first_node.right_ref().unwrap());
    let mut collected = vec![first_node];
    loop {
        let first_key = next_node.first_key();
        let node_right = next_node.right_bound();
        debug_assert!(
            first_key < right_boundary,
            "First key {:?} out of bound {:?}, collected {}. Level {}, LSM {}",
            first_key,
            right_boundary,
            collected.len(),
            level,
            lsm
        );
        if node_right <= right_boundary {
            let next_right = write_node(next_node.right_ref().unwrap());
            collected.push(next_node);
            next_node = next_right;
            if next_node.first_key() >= right_boundary {
                trace!("Collected {} nodes at level {}", collected.len(), level);
                return NodeSelection::WholePage(collected, next_node);
            }
        } else {
            return NodeSelection::PartialPage(collected, next_node);
        }
    }
}

fn select_boundary<KS, PS>(node: &NodeCellRef) -> EntryKey
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let res = read_node(node, |node: &NodeReadHandler<KS, PS>| {
        let node_keys = node.keys();
        let node_len = node_keys.len();
        if node.len() < 2 {
            return Err(node.ptrs()[0].clone());
        }
        // Pick half of the keys in the root
        // Genreally, higher level sub tree in LSM tree will select more keys to merged
        // into next level
        let mid_idx = min(node_len / 2, 8);
        // Return the mid key as the boundary for selection (cut)
        Ok(node_keys[mid_idx].clone())
    });
    match res {
        Ok(key) => key.clone(),
        Err(r) => select_boundary::<KS, PS>(&r)
    }
}

pub async fn level_merge<KS, PS>(
    level: usize,
    src_tree: &BPlusTree<KS, PS>,
    dest_tree: &dyn LevelTree,
) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    debug!("Merging LSM tree level {}", level);
    debug_assert!(verification::tree_has_no_empty_node(&src_tree));
    debug_assert!(verification::is_tree_in_order(&src_tree, level));
    let root = src_tree.get_root();
    let key_boundary = select_boundary::<KS, PS>(&root);
    debug!(
        "Level merge level {} with boundary {:?}",
        level, key_boundary
    );
    let (num_keys, new_root) = merge_prune(0, &src_tree.get_root(), src_tree, dest_tree, &key_boundary, level);
    if let Some(new_root) = new_root {
        let new_root_ref = new_root.node_ref().clone();
        debug!("Level merge update source root {:?}", &new_root_ref);
        *src_tree.root.write() = new_root_ref;
    }
    debug_assert!(verification::tree_has_no_empty_node(&src_tree));
    debug_assert!(verification::is_tree_in_order(&src_tree, level));
    debug!("Merge and pruned level {}, waiting for storage", level);
    storage::wait_until_updated().await;
    debug!("MERGE LEVEL {} COMPLETED", level);
    return num_keys;
}
<|endoftext|>


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

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::env;

use ast;
use ast::{Ident, Name, TokenTree};
use codemap::Span;
use ext::base::{ExtCtxt, MacEager, MacResult};
use ext::build::AstBuilder;
use parse::token;
use ptr::P;
use util::small_vector::SmallVector;

use diagnostics::metadata::output_metadata;

// Maximum width of any line in an extended error description (inclusive).
const MAX_DESCRIPTION_WIDTH: usize = 80;

thread_local! {
    static REGISTERED_DIAGNOSTICS: RefCell<ErrorMap> = {
        RefCell::new(BTreeMap::new())
    }
}

/// Error information type.
pub struct ErrorInfo {
    pub description: Option<Name>,
    pub use_site: Option
}

/// Mapping from error codes to metadata.
pub type ErrorMap = BTreeMap<Name, ErrorInfo>;

fn with_registered_diagnostics<T, F>(f: F) -> T where
    F: FnOnce(&mut ErrorMap) -> T,
{
    REGISTERED_DIAGNOSTICS.with(move |slot| {
        f(&mut *slot.borrow_mut())
    })
}

pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
                                   span: Span,
                                   token_tree: &[TokenTree])
                                   -> Box<MacResult+'cx> {
    let code = match (token_tree.len(), token_tree.get(0)) {
        (1, Some(&TokenTree::Token(_, token::Ident(code, _)))) => code,
        _ => unreachable!()
    };

    with_registered_diagnostics(|diagnostics| {
        match diagnostics.get_mut(&code.name) {
            // Previously used errors.
            Some(&mut ErrorInfo { description: _, use_site: Some(previous_span) }) => {
                ecx.struct_span_warn(span, &format!(
                    "diagnostic code {} already used", code
                )).span_note(previous_span, "previous invocation")
                  .emit();
            }
            // Newly used errors.
            Some(ref mut info) => {
                info.use_site = Some(span);
            }
            // Unregistered errors.
            None => {
                ecx.span_err(span, &format!(
                    "used diagnostic code {} not registered", code
                ));
            }
        }
    });
    MacEager::expr(ecx.expr_tuple(span, Vec::new()))
}

pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
                                       span: Span,
                                       token_tree: &[TokenTree])
                                       -> Box<MacResult+'cx> {
    let (code, description) = match (
        token_tree.len(),
        token_tree.get(0),
        token_tree.get(1),
        token_tree.get(2)
    ) {
        (1, Some(&TokenTree::Token(_, token::Ident(ref code, _))), None, None) => {
            (code, None)
        },
        (3, Some(&TokenTree::Token(_, token::Ident(ref code, _))),
            Some(&TokenTree::Token(_, token::Comma)),
            Some(&TokenTree::Token(_, token::Literal(token::StrRaw(description, _), None)))) => {
            (code, Some(description))
        }
        _ => unreachable!()
    };

    // Check that the description starts and ends with a newline and doesn't
    // overflow the maximum line width.
    description.map(|raw_msg| {
        let msg = raw_msg.as_str();
        if !msg.starts_with("\n") || !msg.ends_with("\n") {
            ecx.span_err(span, &format!(
                "description for error code {} doesn't start and end with a newline",
                code
            ));
        }

        // URLs can be unavoidably longer than the line limit, so we allow them.
        // Allowed format is: `[name]: https://www.rust-lang.org/`
        let is_url = |l: &str| l.starts_with('[') && l.contains("]:") && l.contains("http");

        if msg.lines().any(|line| line.len() > MAX_DESCRIPTION_WIDTH && !is_url(line)) {
            ecx.span_err(span, &format!(
                "description for error code {} contains a line longer than {} characters.\n\
                 if you're inserting a long URL use the footnote style to bypass this check.",
                code, MAX_DESCRIPTION_WIDTH
            ));
        }
    });
    // Add the error to the map.
    with_registered_diagnostics(|diagnostics| {
        let info = ErrorInfo {
            description: description,
            use_site: None
        };
        if diagnostics.insert(code.name, info).is_some() {
            ecx.span_err(span, &format!(
                "diagnostic code {} already registered", code
            ));
        }
    });
    let sym = Ident::with_empty_ctxt(token::gensym(&format!(
        "__register_diagnostic_{}", code
    )));
    MacEager::items(SmallVector::many(vec![
        ecx.item_mod(
            span,
            span,
            sym,
            Vec::new(),
            Vec::new()
        )
    ]))
}

pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
                                          span: Span,
                                          token_tree: &[TokenTree])
                                          -> Box<MacResult+'cx> {
    assert_eq!(token_tree.len(), 3);
    let (crate_name, name) = match (&token_tree[0], &token_tree[2]) {
        (
            // Crate name.
            &TokenTree::Token(_, token::Ident(ref crate_name, _)),
            // DIAGNOSTICS ident.
            &TokenTree::Token(_, token::Ident(ref name, _))
        ) => (*&crate_name, name),
        _ => unreachable!()
    };

    // Output error metadata to `tmp/extended-errors/<target arch>/<crate name>.json`
    let target_triple = env::var("CFG_COMPILER_HOST_TRIPLE")
        .ok().expect("unable to determine target arch from $CFG_COMPILER_HOST_TRIPLE");

    with_registered_diagnostics(|diagnostics| {
        if let Err(e) = output_metadata(ecx,
                                        &target_triple,
                                        &crate_name.name.as_str(),
                                        &diagnostics) {
            ecx.span_bug(span, &format!(
                "error writing metadata for triple `{}` and crate `{}`, error: {}, cause: {:?}",
                target_triple, crate_name, e.description(), e.cause()
            ));
        }
    });

    // Construct the output expression.
    let (count, expr) =
        with_registered_diagnostics(|diagnostics| {
            let descriptions: Vec<P<ast::Expr>> =
                diagnostics.iter().filter_map(|(code, info)| {
                    info.description.map(|description| {
                        ecx.expr_tuple(span, vec![
                            ecx.expr_str(span, code.as_str()),
                            ecx.expr_str(span, description.as_str())
                        ])
                    })
                }).collect();
            (descriptions.len(), ecx.expr_vec(span, descriptions))
        });

    let static_ = ecx.lifetime(span, ecx.name_of("'static"));
    let ty_str = ecx.ty_rptr(
        span,
        ecx.ty_ident(span, ecx.ident_of("str")),
        Some(static_),
        ast::MutImmutable,
    );

    let ty = ecx.ty(
        span,
        ast::TyFixedLengthVec(
            ecx.ty(
                span,
                ast::TyTup(vec![ty_str.clone(), ty_str])
            ),
            ecx.expr_usize(span, count),
        ),
    );

    MacEager::items(SmallVector::many(vec![
        P(ast::Item {
            ident: name.clone(),
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemConst(
                ty,
                expr,
            ),
            vis: ast::Public,
            span: span,
        })
    ]))
}
<commit_msg>Avoid ICE if environment variable is not set<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::env;

use ast;
use ast::{Ident, Name, TokenTree};
use codemap::Span;
use ext::base::{ExtCtxt, MacEager, MacResult};
use ext::build::AstBuilder;
use parse::token;
use ptr::P;
use util::small_vector::SmallVector;

use diagnostics::metadata::output_metadata;

// Maximum width of any line in an extended error description (inclusive).
const MAX_DESCRIPTION_WIDTH: usize = 80;

thread_local! {
    static REGISTERED_DIAGNOSTICS: RefCell<ErrorMap> = {
        RefCell::new(BTreeMap::new())
    }
}

/// Error information type.
pub struct ErrorInfo {
    pub description: Option<Name>,
    pub use_site: Option
}

/// Mapping from error codes to metadata.
pub type ErrorMap = BTreeMap<Name, ErrorInfo>;

fn with_registered_diagnostics<T, F>(f: F) -> T where
    F: FnOnce(&mut ErrorMap) -> T,
{
    REGISTERED_DIAGNOSTICS.with(move |slot| {
        f(&mut *slot.borrow_mut())
    })
}

pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
                                   span: Span,
                                   token_tree: &[TokenTree])
                                   -> Box<MacResult+'cx> {
    let code = match (token_tree.len(), token_tree.get(0)) {
        (1, Some(&TokenTree::Token(_, token::Ident(code, _)))) => code,
        _ => unreachable!()
    };

    with_registered_diagnostics(|diagnostics| {
        match diagnostics.get_mut(&code.name) {
            // Previously used errors.
            Some(&mut ErrorInfo { description: _, use_site: Some(previous_span) }) => {
                ecx.struct_span_warn(span, &format!(
                    "diagnostic code {} already used", code
                )).span_note(previous_span, "previous invocation")
                  .emit();
            }
            // Newly used errors.
            Some(ref mut info) => {
                info.use_site = Some(span);
            }
            // Unregistered errors.
            None => {
                ecx.span_err(span, &format!(
                    "used diagnostic code {} not registered", code
                ));
            }
        }
    });
    MacEager::expr(ecx.expr_tuple(span, Vec::new()))
}

pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
                                       span: Span,
                                       token_tree: &[TokenTree])
                                       -> Box<MacResult+'cx> {
    let (code, description) = match (
        token_tree.len(),
        token_tree.get(0),
        token_tree.get(1),
        token_tree.get(2)
    ) {
        (1, Some(&TokenTree::Token(_, token::Ident(ref code, _))), None, None) => {
            (code, None)
        },
        (3, Some(&TokenTree::Token(_, token::Ident(ref code, _))),
            Some(&TokenTree::Token(_, token::Comma)),
            Some(&TokenTree::Token(_, token::Literal(token::StrRaw(description, _), None)))) => {
            (code, Some(description))
        }
        _ => unreachable!()
    };

    // Check that the description starts and ends with a newline and doesn't
    // overflow the maximum line width.
    description.map(|raw_msg| {
        let msg = raw_msg.as_str();
        if !msg.starts_with("\n") || !msg.ends_with("\n") {
            ecx.span_err(span, &format!(
                "description for error code {} doesn't start and end with a newline",
                code
            ));
        }

        // URLs can be unavoidably longer than the line limit, so we allow them.
        // Allowed format is: `[name]: https://www.rust-lang.org/`
        let is_url = |l: &str| l.starts_with('[') && l.contains("]:") && l.contains("http");

        if msg.lines().any(|line| line.len() > MAX_DESCRIPTION_WIDTH && !is_url(line)) {
            ecx.span_err(span, &format!(
                "description for error code {} contains a line longer than {} characters.\n\
                 if you're inserting a long URL use the footnote style to bypass this check.",
                code, MAX_DESCRIPTION_WIDTH
            ));
        }
    });
    // Add the error to the map.
    with_registered_diagnostics(|diagnostics| {
        let info = ErrorInfo {
            description: description,
            use_site: None
        };
        if diagnostics.insert(code.name, info).is_some() {
            ecx.span_err(span, &format!(
                "diagnostic code {} already registered", code
            ));
        }
    });
    let sym = Ident::with_empty_ctxt(token::gensym(&format!(
        "__register_diagnostic_{}", code
    )));
    MacEager::items(SmallVector::many(vec![
        ecx.item_mod(
            span,
            span,
            sym,
            Vec::new(),
            Vec::new()
        )
    ]))
}

pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
                                          span: Span,
                                          token_tree: &[TokenTree])
                                          -> Box<MacResult+'cx> {
    assert_eq!(token_tree.len(), 3);
    let (crate_name, name) = match (&token_tree[0], &token_tree[2]) {
        (
            // Crate name.
            &TokenTree::Token(_, token::Ident(ref crate_name, _)),
            // DIAGNOSTICS ident.
            &TokenTree::Token(_, token::Ident(ref name, _))
        ) => (*&crate_name, name),
        _ => unreachable!()
    };

    // Output error metadata to `tmp/extended-errors/<target arch>/<crate name>.json`
    if let Ok(target_triple) = env::var("CFG_COMPILER_HOST_TRIPLE") {
        with_registered_diagnostics(|diagnostics| {
            if let Err(e) = output_metadata(ecx,
                                            &target_triple,
                                            &crate_name.name.as_str(),
                                            &diagnostics) {
                ecx.span_bug(span, &format!(
                    "error writing metadata for triple `{}` and crate `{}`, error: {}, \
                     cause: {:?}",
                    target_triple, crate_name, e.description(), e.cause()
                ));
            }
        });
    } else {
        ecx.span_err(span, &format!(
            "failed to write metadata for crate `{}` because $CFG_COMPILER_HOST_TRIPLE is not set",
            crate_name));
    }

    // Construct the output expression.
    let (count, expr) =
        with_registered_diagnostics(|diagnostics| {
            let descriptions: Vec<P<ast::Expr>> =
                diagnostics.iter().filter_map(|(code, info)| {
                    info.description.map(|description| {
                        ecx.expr_tuple(span, vec![
                            ecx.expr_str(span, code.as_str()),
                            ecx.expr_str(span, description.as_str())
                        ])
                    })
                }).collect();
            (descriptions.len(), ecx.expr_vec(span, descriptions))
        });

    let static_ = ecx.lifetime(span, ecx.name_of("'static"));
    let ty_str = ecx.ty_rptr(
        span,
        ecx.ty_ident(span, ecx.ident_of("str")),
        Some(static_),
        ast::MutImmutable,
    );

    let ty = ecx.ty(
        span,
        ast::TyFixedLengthVec(
            ecx.ty(
                span,
                ast::TyTup(vec![ty_str.clone(), ty_str])
            ),
            ecx.expr_usize(span, count),
        ),
    );

    MacEager::items(SmallVector::many(vec![
        P(ast::Item {
            ident: name.clone(),
            attrs: Vec::new(),
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemConst(
                ty,
                expr,
            ),
            vis: ast::Public,
            span: span,
        })
    ]))
}
<|endoftext|>


<commit_before>use specs;

use crate::game::constants::TILE_SIZE;
use crate::graphics::orientation::Orientation;
use crate::shaders::Position;
use crate::terrain_shape::TerrainShapeDrawable;

fn set_position(x: isize, y: isize) -> Position {
  Position::new(
    TILE_SIZE * x as f32,
    TILE_SIZE * 0.9 * y as f32
  )
}

pub struct TerrainShapeObjects {
  pub objects: Vec<TerrainShapeDrawable>,
}

impl TerrainShapeObjects {
  pub fn new() -> TerrainShapeObjects {
    TerrainShapeObjects {
      objects: vec![
        TerrainShapeDrawable::new(set_position(-1, 5), Orientation::DownLeft),
        TerrainShapeDrawable::new(set_position(0, 4), Orientation::DownLeft),
        TerrainShapeDrawable::new(set_position(1, 3), Orientation::DownLeft),
        TerrainShapeDrawable::new(set_position(2, 2), Orientation::DownLeft),
      ]
    }
  }
}

impl specs::prelude::Component for TerrainShapeObjects {
  type Storage = specs::storage::VecStorage<TerrainShapeObjects>;
}
<commit_msg>Generate slope tiles across map<commit_after>use specs;

use crate::game::constants::TILE_SIZE;
use crate::graphics::orientation::Orientation;
use crate::shaders::Position;
use crate::terrain_shape::TerrainShapeDrawable;

fn set_position(x: isize, y: isize) -> Position {
  Position::new(
    TILE_SIZE * x as f32,
    TILE_SIZE * 0.9 * y as f32
  )
}

pub struct TerrainShapeObjects {
  pub objects: Vec<TerrainShapeDrawable>,
}

impl TerrainShapeObjects {
  pub fn new() -> TerrainShapeObjects {
    let mut objects = Vec::new();

    for idx in -60..65 {
      objects.push(TerrainShapeDrawable::new(set_position(idx, -idx+4), Orientation::DownLeft))
    }

    TerrainShapeObjects {
      objects
    }
  }
}

impl specs::prelude::Component for TerrainShapeObjects {
  type Storage = specs::storage::VecStorage<TerrainShapeObjects>;
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::hash::Hash;

/// An associative map data structure for representing scopes.
///
/// A `ForkTable` functions similarly to a standard associative map
/// data structure (such as a `HashMap`), but with the ability to
/// fork children off of each level of the map. If a key exists in any
/// of a child's parents, the child will 'pass through' that key. If a
/// new value is bound to a key in a child level, that child will overwrite
/// the previous entry with the new one, but the previous `key` -> `value`
/// mapping will remain in the level it is defined. This means that the parent
/// level will still provide the previous value for that key.
///
/// This is an implementation of the ForkTable data structure for
/// representing scopes. The ForkTable was initially described by
/// Max Clive. This implemention is based primarily by the Scala
/// reference implementation written by Hawk Weisman for the Decaf
/// compiler, which is available [here](https://github.com/hawkw/decaf/blob/master/src/main/scala/com/meteorcode/common/ForkTable.scala).
#[derive(Debug)]
pub struct ForkTable<'a, K:'a +  Eq + Hash,V: 'a>  {
    table: HashMap<K, V>,
    whiteouts: HashSet<K>,
    parent: Option<&'a mut ForkTable<'a, K,V>>
}

impl<'a, K,V> ForkTable<'a, K, V> where K: Eq + Hash {

    /// Returns a reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// assert_eq!(table.get(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get(&1isize), Some(&"One"));
    /// ```
    pub fn get<'b>(&'b self, key: &K) -> Option<&'b V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get(key)
                .or(match self.parent {
                        Some(ref parent)    => parent.get(key),
                        None                => None
                    })
        }
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&mut V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get_mut(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get_mut(&1isize), Some(&mut "One"));
    /// assert_eq!(table.get_mut(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get_mut(&1isize), Some(&mut "One"));
    /// ```
   pub fn get_mut<'b>(&'b mut self, key: &K) -> Option<&'b mut V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get_mut(key)
                .or(match self.parent {
                        Some(ref mut parent)    => parent.get_mut(key),
                        None                    => None
                    })
        }
    }

    /// Removes a key from the map, returning the value at the key if
    /// the key was previously in the map.
    ///
    /// If the removed value exists in a lower level of the table,
    /// it will be whited out at this level. This means that the entry
    /// will be 'removed' at this level and this table will not provide
    /// access to it, but the mapping will still exist in the level where
    /// it was defined. Note that the key will not be returned if it is
    /// defined in a lower level of the table.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to remove
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// table.insert(1isize, "One");
    ///
    /// assert_eq!(table.remove(&1isize), Some("One"));
    /// assert_eq!(table.contains_key(&1isize), false);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// assert_eq!(level_2.remove(&1isize), None);
    /// assert_eq!(level_2.chain_contains_key(&1isize), false);
    /// assert_eq!(level_1.chain_contains_key(&1isize), true);
    /// ```
    ///
    pub fn remove(&mut self, key: &K) -> Option<V> where K: Clone {
            if self.table.contains_key(key) {
                self.table.remove(key)
            } else if self.chain_contains_key(key) {
                self.whiteouts.insert(key.clone()); // TODO: could just white out specific hashes?
                None
            } else {
                None
            }
    }

    /// Inserts a key-value pair from the map.
    ///
    /// If the key already had a value present in the map, that
    /// value is returned. Otherwise, `None` is returned.
    ///
    /// If the key is currently whited out (i.e. it was defined
    /// in a lower level of the map and was removed) then it will
    /// be un-whited out and added at this level.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to add
    ///  + `v`  - the value to associate with that key
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if a previous entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// Simply inserting an entry:
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// ```
    ///
    /// Overwriting the value associated with a key:
    ///
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// assert_eq!(table.insert(1isize, "two"), None);
    /// assert_eq!(table.get(&1isize), Some(&"two"));
    ///
    /// assert_eq!(table.insert(2isize, "Two"), Some("two"));
    /// assert_eq!(table.get(&2isize), Some(&"Two"));
    /// ```
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
        self.table.insert(k, v)
    }

    /// Returns true if this level contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in this level of the
    ///    table, `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.contains_key(&1isize), false);
    /// ```
    pub fn contains_key(&self, key: &K) -> bool  {
        self.table.contains_key(key)
    }

    /// Returns true if the key is defined in this level of the table, or
    /// in any of its' parents and is not whited out.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in the table,
    ///    `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.chain_contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.chain_contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.chain_contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.chain_contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// ```
    pub fn chain_contains_key(&self, key: &K) -> bool {
        self.table.contains_key(key) ||
        (self.whiteouts.contains(key) &&
            match self.parent {
                Some(ref p) => p.chain_contains_key(key),
                None        => false
            })
    }

    /// Forks this table, returning a new `ForkTable<K,V>`.
    ///
    /// This level of the table will be set as the child's
    /// parent. The child will be created with an empty backing
    /// `HashMap` and no keys whited out.
    ///
    /// Note that the new `ForkTable<K,V>` has a lifetime
    /// bound ensuring that it will live at least as long as the
    /// parent `ForkTable`.
    ///
    /// TODO: should whiteouts be carried over? look into this.
    pub fn fork(&'a mut self) -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: Some(self)
        }
    }

    /// Constructs a new `ForkTable<K,V>`
    pub fn new() -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: None
        }
    }
}<commit_msg>Remove unsupported functionality from test<commit_after>use std::collections::{HashMap, HashSet};
use std::hash::Hash;

/// An associative map data structure for representing scopes.
///
/// A `ForkTable` functions similarly to a standard associative map
/// data structure (such as a `HashMap`), but with the ability to
/// fork children off of each level of the map. If a key exists in any
/// of a child's parents, the child will 'pass through' that key. If a
/// new value is bound to a key in a child level, that child will overwrite
/// the previous entry with the new one, but the previous `key` -> `value`
/// mapping will remain in the level it is defined. This means that the parent
/// level will still provide the previous value for that key.
///
/// This is an implementation of the ForkTable data structure for
/// representing scopes. The ForkTable was initially described by
/// Max Clive. This implemention is based primarily by the Scala
/// reference implementation written by Hawk Weisman for the Decaf
/// compiler, which is available [here](https://github.com/hawkw/decaf/blob/master/src/main/scala/com/meteorcode/common/ForkTable.scala).
#[derive(Debug)]
pub struct ForkTable<'a, K:'a +  Eq + Hash,V: 'a>  {
    table: HashMap<K, V>,
    whiteouts: HashSet<K>,
    parent: Option<&'a mut ForkTable<'a, K,V>>
}

impl<'a, K,V> ForkTable<'a, K, V> where K: Eq + Hash {

    /// Returns a reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// assert_eq!(table.get(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get(&1isize), Some(&"One"));
    /// ```
    pub fn get<'b>(&'b self, key: &K) -> Option<&'b V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get(key)
                .or(match self.parent {
                        Some(ref parent)    => parent.get(key),
                        None                => None
                    })
        }
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// If the key is defined in this level of the table, or in any
    /// of its' parents, a reference to the associated value will be
    /// returned.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `Some(&mut V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get_mut(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get_mut(&1isize), Some(&mut "One"));
    /// assert_eq!(table.get_mut(&2isize), None);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.get_mut(&1isize), Some(&mut "One"));
    /// ```
    /// TODO: consider only allowing `get_mut()` from the current
    ///       level, to remove the need to keep a mutable borrow
    ///       on the parent level. We could allow an overwrite here
    ///       instead.
   pub fn get_mut<'b>(&'b mut self, key: &K) -> Option<&'b mut V> {
        if self.whiteouts.contains(key) {
            None
        } else {
            self.table
                .get_mut(key)
                .or(match self.parent {
                        Some(ref mut parent)    => parent.get_mut(key),
                        None                    => None
                    })
        }
    }

    /// Removes a key from the map, returning the value at the key if
    /// the key was previously in the map.
    ///
    /// If the removed value exists in a lower level of the table,
    /// it will be whited out at this level. This means that the entry
    /// will be 'removed' at this level and this table will not provide
    /// access to it, but the mapping will still exist in the level where
    /// it was defined. Note that the key will not be returned if it is
    /// defined in a lower level of the table.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `key`  - the key to remove
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if an entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// table.insert(1isize, "One");
    ///
    /// assert_eq!(table.remove(&1isize), Some("One"));
    /// assert_eq!(table.contains_key(&1isize), false);
    /// ```
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// assert_eq!(level_2.remove(&1isize), None);
    /// assert_eq!(level_2.chain_contains_key(&1isize), false);
    /// ```
    ///
    pub fn remove(&mut self, key: &K) -> Option<V> where K: Clone {
            if self.table.contains_key(key) {
                self.table.remove(key)
            } else if self.chain_contains_key(key) {
                self.whiteouts.insert(key.clone()); // TODO: could just white out specific hashes?
                None
            } else {
                None
            }
    }

    /// Inserts a key-value pair from the map.
    ///
    /// If the key already had a value present in the map, that
    /// value is returned. Otherwise, `None` is returned.
    ///
    /// If the key is currently whited out (i.e. it was defined
    /// in a lower level of the map and was removed) then it will
    /// be un-whited out and added at this level.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to add
    ///  + `v`  - the value to associate with that key
    ///
    /// # Return Value
    ///
    ///  + `Some(V)` if a previous entry for the given key exists in the
    ///     table, or `None` if there is no entry for that key.
    ///
    /// # Examples
    ///
    /// Simply inserting an entry:
    ///
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.get(&1isize), Some(&"One"));
    /// ```
    ///
    /// Overwriting the value associated with a key:
    ///
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.get(&1isize), None);
    /// assert_eq!(table.insert(1isize, "two"), None);
    /// assert_eq!(table.get(&1isize), Some(&"two"));
    ///
    /// assert_eq!(table.insert(2isize, "Two"), Some("two"));
    /// assert_eq!(table.get(&2isize), Some(&"Two"));
    /// ```
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if self.whiteouts.contains(&k) { self.whiteouts.remove(&k); };
        self.table.insert(k, v)
    }

    /// Returns true if this level contains a value for the specified key.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in this level of the
    ///    table, `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.contains_key(&1isize), false);
    /// ```
    pub fn contains_key(&self, key: &K) -> bool  {
        self.table.contains_key(key)
    }

    /// Returns true if the key is defined in this level of the table, or
    /// in any of its' parents and is not whited out.
    ///
    /// The key may be any borrowed form of the map's key type, but
    /// `Hash` and `Eq` on the borrowed form *must* match those for
    /// the key type.
    ///
    /// # Arguments
    ///
    ///  + `k`  - the key to search for
    ///
    /// # Return Value
    ///
    ///  + `true` if the given key is defined in the table,
    ///    `false` if it does not.
    ///
    /// # Examples
    /// ```
    /// # use seax_scheme::ForkTable;
    /// let mut table: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(table.chain_contains_key(&1isize), false);
    /// table.insert(1isize, "One");
    /// assert_eq!(table.chain_contains_key(&1isize), true);
    /// ```
    /// ```ignore
    /// # use seax_scheme::ForkTable;
    /// let mut level_1: ForkTable<isize,&str> = ForkTable::new();
    /// assert_eq!(level_1.chain_contains_key(&1isize), false);
    /// level_1.insert(1isize, "One");
    /// assert_eq!(level_1.chain_contains_key(&1isize), true);
    ///
    /// let mut level_2: ForkTable<isize,&str> = level_1.fork();
    /// assert_eq!(level_2.chain_contains_key(&1isize), true);
    /// ```
    pub fn chain_contains_key(&self, key: &K) -> bool {
        self.table.contains_key(key) ||
        (self.whiteouts.contains(key) &&
            match self.parent {
                Some(ref p) => p.chain_contains_key(key),
                None        => false
            })
    }

    /// Forks this table, returning a new `ForkTable<K,V>`.
    ///
    /// This level of the table will be set as the child's
    /// parent. The child will be created with an empty backing
    /// `HashMap` and no keys whited out.
    ///
    /// Note that the new `ForkTable<K,V>` has a lifetime
    /// bound ensuring that it will live at least as long as the
    /// parent `ForkTable`.
    ///
    /// TODO: should whiteouts be carried over? look into this.
    pub fn fork(&'a mut self) -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: Some(self)
        }
    }

    /// Constructs a new `ForkTable<K,V>`
    pub fn new() -> ForkTable<'a, K,V> {
        ForkTable {
            table: HashMap::new(),
            whiteouts: HashSet::new(),
            parent: None
        }
    }
}<|endoftext|>


<commit_before>//! Window-wrangling, polygon-pushing and input-grabbing
//!

#[macro_use]
extern crate glium;
extern crate image;
extern crate cgmath;
extern crate calx_window;
extern crate calx_color;
extern crate calx_layout;
extern crate calx_cache;

// pub use canvas::{CanvasBuilder, Canvas};
// pub use canvas::{Image};
pub use draw_util::DrawUtil;
// pub use fonter::{Fonter, Align};
pub use wall::{Wall, Vertex};

// mod canvas;
mod draw_util;
// mod fonter;
mod wall;

/// Drawable images stored in the atlas texture of a Mesh.
///
/// By convention, Default Image is assumed to contain a solid-color texel for
/// drawing solid polygons.
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct Image(usize);

/// UI Widget static identifier, unique for a specific site in source code.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct WidgetId {
    filename: &'static str,
    line: u32,
    column: u32,
}

impl WidgetId {
    pub fn new(filename: &'static str, line: u32, column: u32) -> WidgetId {
        WidgetId {
            filename: filename,
            line: line,
            column: column,
        }
    }

    pub fn dummy() -> WidgetId {
        WidgetId {
            filename: "n/a",
            line: 666666,
            column: 666666,
        }
    }
}

#[macro_export]
/// Generate a static identifier for the current source code position. Used
/// with imgui API.
macro_rules! widget_id {
    () => {
        ::calx::backend::WidgetId::new(concat!(module_path!(), "/", file!()), line!(), column!())
    }
}
<commit_msg>Clean up some obsolete stuff<commit_after>//! Window-wrangling, polygon-pushing and input-grabbing
//!

#[macro_use]
extern crate glium;
extern crate image;
extern crate cgmath;
extern crate calx_window;
extern crate calx_color;
extern crate calx_layout;
extern crate calx_cache;

pub use draw_util::DrawUtil;
// pub use fonter::{Fonter, Align};
pub use wall::{Wall, Vertex};

mod draw_util;
// mod fonter;
mod wall;

/// UI Widget static identifier, unique for a specific site in source code.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct WidgetId {
    filename: &'static str,
    line: u32,
    column: u32,
}

impl WidgetId {
    pub fn new(filename: &'static str, line: u32, column: u32) -> WidgetId {
        WidgetId {
            filename: filename,
            line: line,
            column: column,
        }
    }

    pub fn dummy() -> WidgetId {
        WidgetId {
            filename: "n/a",
            line: 666666,
            column: 666666,
        }
    }
}

#[macro_export]
/// Generate a static identifier for the current source code position. Used
/// with imgui API.
macro_rules! widget_id {
    () => {
        ::calx::backend::WidgetId::new(concat!(module_path!(), "/", file!()), line!(), column!())
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use glium::{self, DrawParameters, LinearBlendingFactor, Program, VertexBuffer};
use glium::draw_parameters::{BlendingFunction, DepthTest};
use super::camera::Camera;
use util::ToArr;
use base::math::*;
use base::world::PillarIndex;
use GameContext;
use std::rc::Rc;
use std::f32::consts::PI;

const BOX_SIZE: f32 = 20.0;

#[derive(Copy, Clone)]
pub struct Vertex {
    point: [f32; 3],
}
implement_vertex!(Vertex, point);

#[derive(Debug, Copy, Clone)]
pub enum Form {
    None = 0,
    Rain = 1,
    Snow = 2,
    Pollen = 3,
}

#[derive(Debug, Copy, Clone)]
pub enum Strength {
    Weak = 1,
    Medium = 2,
    Heavy = 3,
}

#[derive(Copy, Clone)]
pub struct Particle {
    vertices: [Vertex; 4],
    position: Point3<f32>,
    velocity: f32,
    trans_x: f32,
    trans_y: f32,
    trans_z: f32,
}

#[derive(Copy, Clone)]
pub struct Instance {
    position: [f32; 3],
}
implement_vertex!(Instance, position);

impl Particle {
    pub fn new(cam_pos: Point3<f32>) -> Particle {
        let mut radius: f32 = 0.0;
        let mut spawn = false;

        // loop provides better distribution of particles, by rolling a dice
        // which equalizes the chance for every radius inside the circle
        while !spawn {
            radius = rand::random::<f32>();

            let dice = rand::random::<f32>();

            spawn = dice < radius;
        }

        radius = radius * BOX_SIZE;

        let angle = Rad::new(rand::random::<f32>() * PI * 2.0);

        let mut velocity = rand::random::<f32>();
        if velocity < 0.25 {
            velocity = velocity + 0.25;
        }
        if velocity > 0.75 {
            velocity = velocity - 0.25;
        }

        Particle {
            vertices: [Vertex { point: [1.0, 1.0, 0.0] },
                       Vertex { point: [-1.0, 1.0, 0.0] },
                       Vertex { point: [1.0, -1.0, 0.0] },
                       Vertex { point: [-1.0, -1.0, 0.0] }],
            position: Point3::new(cam_pos.x + radius * Rad::sin(angle),
                                  cam_pos.y + radius * Rad::cos(angle),
                                  cam_pos.z + BOX_SIZE),
            velocity: velocity,
            trans_x: rand::random::<f32>() * PI * 2.0,
            trans_y: rand::random::<f32>() * PI * 2.0,
            trans_z: rand::random::<f32>() * PI * 2.0,
        }
    }
}

pub struct Weather {
    particles: Vec<Particle>,
    program: Program,
    indices: glium::index::NoIndices,
    context: Rc<GameContext>,
    camera: Camera,
    particle_buf: VertexBuffer<Instance>,
    actual_buf: VertexBuffer<Instance>,
    form: Form,
    strength: Strength,
}

impl Weather {
    pub fn new(context: Rc<GameContext>) -> Weather {
        let vec: Vec<Particle> = Vec::new();
        let index_buffer = glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip);
        let weather_program = context.load_program("weather").unwrap();
        let camera = Camera::default();
        let sections = glium::VertexBuffer::new(context.get_facade(), &[]).unwrap();
        let sections2 = glium::VertexBuffer::new(context.get_facade(), &[]).unwrap();
        Weather {
            particles: vec,
            program: weather_program,
            indices: index_buffer,
            context: context,
            camera: camera,
            particle_buf: sections,
            actual_buf: sections2,
            form: Form::Pollen,
            strength: Strength::Medium,
        }
    }

    pub fn draw<S: glium::Surface>(&mut self, surface: &mut S, camera: &Camera) {
        if self.form as u8 == 0 {
            return;
        }

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            blend: glium::Blend {
                color: BlendingFunction::Addition {
                    source: LinearBlendingFactor::SourceAlpha,
                    destination: LinearBlendingFactor::OneMinusSourceAlpha,
                },
                ..Default::default()
            },
            ..Default::default()
        };

        let buffer = vec![Vertex { point: [1.0, 1.0, 0.0] },
                          Vertex { point: [-1.0, 1.0, 0.0] },
                          Vertex { point: [1.0, -1.0, 0.0] },
                          Vertex { point: [-1.0, -1.0, 0.0] }];
        let vertex_buffer = glium::VertexBuffer::new(self.context.get_facade(), &buffer).unwrap();
        let mut scaling = Matrix4::from_cols(Vector4f::new(1.0, 0.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 1.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 1.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.0, 1.0));
        let view = camera.view_matrix();
        let mut color = Vector4f::new(0.0, 0.0, 0.0, 0.0);
        match self.form {
            Form::Snow => {
                color = Vector4f::new(0.7, 0.7, 0.7, 1.0);

                scaling = Matrix4::from_cols(Vector4f::new(0.05, 0.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.05, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.05, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.0, 1.0));
            }
            Form::Rain => {
                color = Vector4f::new(0.35, 0.43, 0.47, 1.0);

                scaling = Matrix4::from_cols(Vector4f::new(0.01, 0.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.05, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.5, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.0, 1.0));
            }
            Form::Pollen => {
                color = Vector4f::new(0.5, 0.5, 0.5, 1.0);

                scaling = Matrix4::from_cols(Vector4f::new(0.05, 0.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.05, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.05, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.0, 1.0));
            }
            _ => (),
        };

        let uniforms = uniform!{
                form: self.form as i32,
                view_matrix: view.to_arr(),
                proj_matrix: camera.proj_matrix().to_arr(),
                scaling_matrix: scaling.to_arr(),
                color: color.to_arr(),
            };

        surface.draw((&vertex_buffer, self.actual_buf.per_instance().unwrap()),
                  &self.indices,
                  &self.program,
                  &uniforms,
                  &params)
            .unwrap();

    }

    pub fn update(&mut self, camera: &Camera, delta: f32, world_manager: &super::WorldManager) {
        if self.form as u8 == 0 {
            return;
        }
        self.camera = *camera;
        let max_count: usize;
        match self.form {
            Form::Pollen => max_count = 25 * self.strength as usize,
            _ => max_count = 750 * self.strength as usize,
        }
        if self.particles.len() < max_count {
            let count = max_count / 10;
            for _ in 0..count {
                self.particles.push(Particle::new(camera.position));
            }
            let mut tmp = Vec::new();
            for particle in self.particles.iter() {
                tmp.push(Instance {
                    position: [particle.position.x, particle.position.y, particle.position.z],
                })
            }
            let vertex_buffer = glium::VertexBuffer::new(self.context.get_facade(), &tmp).unwrap();
            self.particle_buf = vertex_buffer;
        }

        let mut mapping = self.particle_buf.map();
        let mut tmp2 = Vec::new();
        for (particle, instance) in &mut self.particles.iter_mut().zip(mapping.iter_mut()) {
            match self.form {
                Form::Snow => {
                    instance.position[2] = instance.position[2] - (particle.velocity * 3.0 * delta);
                    instance.position[0] += particle.trans_x.sin() * 0.05;
                    instance.position[1] += particle.trans_y.cos() * 0.05;
                    particle.trans_y += PI * 0.005 * (rand::random::<f32>() - 0.5);
                    particle.trans_x += PI * 0.005 * (rand::random::<f32>() - 0.5);
                }

                Form::Rain => {
                    instance.position[2] = instance.position[2] -
                                           ((particle.velocity + 0.5) * 50.0 * delta)
                }
                Form::Pollen => {
                    instance.position[0] += particle.trans_x.sin() * 0.025;
                    instance.position[1] += particle.trans_y.cos() * 0.025;
                    instance.position[2] += (particle.trans_z.sin() - 0.7) * 0.5 * delta;
                    particle.trans_y += PI * 0.005 * (rand::random::<f32>() - 0.5);
                    particle.trans_x += PI * 0.005 * (rand::random::<f32>() - 0.5);
                    particle.trans_z += PI * 0.005 * (rand::random::<f32>() - 0.1);
                }
                _ => (),

            }

            let pix_vec = Point2::new(instance.position[0], instance.position[1]);
            let cam_vec = Point2::new(camera.position.x, camera.position.y);
            let tmp = pix_vec - cam_vec;
            let len = ((tmp.x * tmp.x) + (tmp.y * tmp.y)).sqrt();

            let size = match self.form {
                Form::Pollen => BOX_SIZE / 4.0,
                _ => 1.0,
            };

            if len > BOX_SIZE - size || len < -BOX_SIZE - size {
                instance.position[0] = instance.position[0] - (1.95 * tmp.x);
                instance.position[1] = instance.position[1] - (1.95 * tmp.y);
            }
            if instance.position[2] < self.camera.position.z - BOX_SIZE / size {
                instance.position[2] += 1.9 * (BOX_SIZE / size);
            }
            if instance.position[2] > self.camera.position.z + BOX_SIZE / size {
                instance.position[2] -= 1.9 * (BOX_SIZE / size);
            }
            let tmp_point = Point3::new(instance.position[0],
                                        instance.position[1],
                                        instance.position[2]);
            let mut height = 0.0;

            let world = world_manager.get_world();
            let relevant_pos = Point2f::new(instance.position[0], instance.position[1]);
            let pillar_index = PillarIndex(AxialPoint::from_real(relevant_pos));
            let vec_len = world.pillar_at(pillar_index)
                .map(|pillar| pillar.sections().len())
                .unwrap_or(0);
            let pillar_vec = world.pillar_at(pillar_index).map(|pillar| pillar.sections());
            if pillar_vec.is_some() {
                let new_pillar_vec = pillar_vec.unwrap();

                if vec_len == 1 {
                    height = new_pillar_vec[0].top.to_real();
                } else {
                    for i in 0..vec_len {
                        if i != vec_len - 1 {
                            if new_pillar_vec[i].top.to_real() < instance.position[2] &&
                               instance.position[2] < new_pillar_vec[i + 1].bottom.to_real() {
                                height = new_pillar_vec[i].top.to_real();
                                break;
                            } else {
                                continue;
                            }
                        } else {
                            height = new_pillar_vec[i].top.to_real();
                            break;
                        }
                    }
                }
            }
            // let vec = world.pillar_at(pillar_index);
            if ((tmp_point - camera.position).dot(camera.get_look_at_vector())) > 0.0 &&
               instance.position[2] > height {
                tmp2.push(Instance {
                    position: [instance.position[0], instance.position[1], instance.position[2]],
                })
            }
        }
        let vertex_buffer = glium::VertexBuffer::new(self.context.get_facade(), &tmp2).unwrap();

        self.actual_buf = vertex_buffer;
    }

    pub fn set_weather(&mut self, form: Form, strength: Strength) {
        self.form = form;
        self.strength = strength;
    }
}
<commit_msg>changed default weather to none<commit_after>extern crate rand;

use glium::{self, DrawParameters, LinearBlendingFactor, Program, VertexBuffer};
use glium::draw_parameters::{BlendingFunction, DepthTest};
use super::camera::Camera;
use util::ToArr;
use base::math::*;
use base::world::PillarIndex;
use GameContext;
use std::rc::Rc;
use std::f32::consts::PI;

const BOX_SIZE: f32 = 20.0;

#[derive(Copy, Clone)]
pub struct Vertex {
    point: [f32; 3],
}
implement_vertex!(Vertex, point);

#[derive(Debug, Copy, Clone)]
pub enum Form {
    None = 0,
    Rain = 1,
    Snow = 2,
    Pollen = 3,
}

#[derive(Debug, Copy, Clone)]
pub enum Strength {
    Weak = 1,
    Medium = 2,
    Heavy = 3,
}

#[derive(Copy, Clone)]
pub struct Particle {
    vertices: [Vertex; 4],
    position: Point3<f32>,
    velocity: f32,
    trans_x: f32,
    trans_y: f32,
    trans_z: f32,
}

#[derive(Copy, Clone)]
pub struct Instance {
    position: [f32; 3],
}
implement_vertex!(Instance, position);

impl Particle {
    pub fn new(cam_pos: Point3<f32>) -> Particle {
        let mut radius: f32 = 0.0;
        let mut spawn = false;

        // loop provides better distribution of particles, by rolling a dice
        // which equalizes the chance for every radius inside the circle
        while !spawn {
            radius = rand::random::<f32>();

            let dice = rand::random::<f32>();

            spawn = dice < radius;
        }

        radius = radius * BOX_SIZE;

        let angle = Rad::new(rand::random::<f32>() * PI * 2.0);

        let mut velocity = rand::random::<f32>();
        if velocity < 0.25 {
            velocity = velocity + 0.25;
        }
        if velocity > 0.75 {
            velocity = velocity - 0.25;
        }

        Particle {
            vertices: [Vertex { point: [1.0, 1.0, 0.0] },
                       Vertex { point: [-1.0, 1.0, 0.0] },
                       Vertex { point: [1.0, -1.0, 0.0] },
                       Vertex { point: [-1.0, -1.0, 0.0] }],
            position: Point3::new(cam_pos.x + radius * Rad::sin(angle),
                                  cam_pos.y + radius * Rad::cos(angle),
                                  cam_pos.z + BOX_SIZE),
            velocity: velocity,
            trans_x: rand::random::<f32>() * PI * 2.0,
            trans_y: rand::random::<f32>() * PI * 2.0,
            trans_z: rand::random::<f32>() * PI * 2.0,
        }
    }
}

pub struct Weather {
    particles: Vec<Particle>,
    program: Program,
    indices: glium::index::NoIndices,
    context: Rc<GameContext>,
    camera: Camera,
    particle_buf: VertexBuffer<Instance>,
    actual_buf: VertexBuffer<Instance>,
    form: Form,
    strength: Strength,
}

impl Weather {
    pub fn new(context: Rc<GameContext>) -> Weather {
        let vec: Vec<Particle> = Vec::new();
        let index_buffer = glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip);
        let weather_program = context.load_program("weather").unwrap();
        let camera = Camera::default();
        let sections = glium::VertexBuffer::new(context.get_facade(), &[]).unwrap();
        let sections2 = glium::VertexBuffer::new(context.get_facade(), &[]).unwrap();
        Weather {
            particles: vec,
            program: weather_program,
            indices: index_buffer,
            context: context,
            camera: camera,
            particle_buf: sections,
            actual_buf: sections2,
            form: Form::None,
            strength: Strength::Medium,
        }
    }

    pub fn draw<S: glium::Surface>(&mut self, surface: &mut S, camera: &Camera) {
        if self.form as u8 == 0 {
            return;
        }

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            blend: glium::Blend {
                color: BlendingFunction::Addition {
                    source: LinearBlendingFactor::SourceAlpha,
                    destination: LinearBlendingFactor::OneMinusSourceAlpha,
                },
                ..Default::default()
            },
            ..Default::default()
        };

        let buffer = vec![Vertex { point: [1.0, 1.0, 0.0] },
                          Vertex { point: [-1.0, 1.0, 0.0] },
                          Vertex { point: [1.0, -1.0, 0.0] },
                          Vertex { point: [-1.0, -1.0, 0.0] }];
        let vertex_buffer = glium::VertexBuffer::new(self.context.get_facade(), &buffer).unwrap();
        let mut scaling = Matrix4::from_cols(Vector4f::new(1.0, 0.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 1.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 1.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.0, 1.0));
        let view = camera.view_matrix();
        let mut color = Vector4f::new(0.0, 0.0, 0.0, 0.0);
        match self.form {
            Form::Snow => {
                color = Vector4f::new(0.7, 0.7, 0.7, 1.0);

                scaling = Matrix4::from_cols(Vector4f::new(0.05, 0.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.05, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.05, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.0, 1.0));
            }
            Form::Rain => {
                color = Vector4f::new(0.35, 0.43, 0.47, 1.0);

                scaling = Matrix4::from_cols(Vector4f::new(0.01, 0.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.05, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.5, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.0, 1.0));
            }
            Form::Pollen => {
                color = Vector4f::new(0.5, 0.5, 0.5, 1.0);

                scaling = Matrix4::from_cols(Vector4f::new(0.05, 0.0, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.05, 0.0, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.05, 0.0),
                                             Vector4f::new(0.0, 0.0, 0.0, 1.0));
            }
            _ => (),
        };

        let uniforms = uniform!{
                form: self.form as i32,
                view_matrix: view.to_arr(),
                proj_matrix: camera.proj_matrix().to_arr(),
                scaling_matrix: scaling.to_arr(),
                color: color.to_arr(),
            };

        surface.draw((&vertex_buffer, self.actual_buf.per_instance().unwrap()),
                  &self.indices,
                  &self.program,
                  &uniforms,
                  &params)
            .unwrap();

    }

    pub fn update(&mut self, camera: &Camera, delta: f32, world_manager: &super::WorldManager) {
        if self.form as u8 == 0 {
            return;
        }
        self.camera = *camera;
        let max_count: usize;
        match self.form {
            Form::Pollen => max_count = 25 * self.strength as usize,
            _ => max_count = 750 * self.strength as usize,
        }
        if self.particles.len() < max_count {
            let count = max_count / 10;
            for _ in 0..count {
                self.particles.push(Particle::new(camera.position));
            }
            let mut tmp = Vec::new();
            for particle in self.particles.iter() {
                tmp.push(Instance {
                    position: [particle.position.x, particle.position.y, particle.position.z],
                })
            }
            let vertex_buffer = glium::VertexBuffer::new(self.context.get_facade(), &tmp).unwrap();
            self.particle_buf = vertex_buffer;
        }

        let mut mapping = self.particle_buf.map();
        let mut tmp2 = Vec::new();
        for (particle, instance) in &mut self.particles.iter_mut().zip(mapping.iter_mut()) {
            match self.form {
                Form::Snow => {
                    instance.position[2] = instance.position[2] - (particle.velocity * 3.0 * delta);
                    instance.position[0] += particle.trans_x.sin() * 0.05;
                    instance.position[1] += particle.trans_y.cos() * 0.05;
                    particle.trans_y += PI * 0.005 * (rand::random::<f32>() - 0.5);
                    particle.trans_x += PI * 0.005 * (rand::random::<f32>() - 0.5);
                }

                Form::Rain => {
                    instance.position[2] = instance.position[2] -
                                           ((particle.velocity + 0.5) * 50.0 * delta)
                }
                Form::Pollen => {
                    instance.position[0] += particle.trans_x.sin() * 0.025;
                    instance.position[1] += particle.trans_y.cos() * 0.025;
                    instance.position[2] += (particle.trans_z.sin() - 0.7) * 0.5 * delta;
                    particle.trans_y += PI * 0.005 * (rand::random::<f32>() - 0.5);
                    particle.trans_x += PI * 0.005 * (rand::random::<f32>() - 0.5);
                    particle.trans_z += PI * 0.005 * (rand::random::<f32>() - 0.1);
                }
                _ => (),

            }

            let pix_vec = Point2::new(instance.position[0], instance.position[1]);
            let cam_vec = Point2::new(camera.position.x, camera.position.y);
            let tmp = pix_vec - cam_vec;
            let len = ((tmp.x * tmp.x) + (tmp.y * tmp.y)).sqrt();

            let size = match self.form {
                Form::Pollen => BOX_SIZE / 4.0,
                _ => 1.0,
            };

            if len > BOX_SIZE - size || len < -BOX_SIZE - size {
                instance.position[0] = instance.position[0] - (1.95 * tmp.x);
                instance.position[1] = instance.position[1] - (1.95 * tmp.y);
            }
            if instance.position[2] < self.camera.position.z - BOX_SIZE / size {
                instance.position[2] += 1.9 * (BOX_SIZE / size);
            }
            if instance.position[2] > self.camera.position.z + BOX_SIZE / size {
                instance.position[2] -= 1.9 * (BOX_SIZE / size);
            }
            let tmp_point = Point3::new(instance.position[0],
                                        instance.position[1],
                                        instance.position[2]);
            let mut height = 0.0;

            let world = world_manager.get_world();
            let relevant_pos = Point2f::new(instance.position[0], instance.position[1]);
            let pillar_index = PillarIndex(AxialPoint::from_real(relevant_pos));
            let vec_len = world.pillar_at(pillar_index)
                .map(|pillar| pillar.sections().len())
                .unwrap_or(0);
            let pillar_vec = world.pillar_at(pillar_index).map(|pillar| pillar.sections());
            if pillar_vec.is_some() {
                let new_pillar_vec = pillar_vec.unwrap();

                if vec_len == 1 {
                    height = new_pillar_vec[0].top.to_real();
                } else {
                    for i in 0..vec_len {
                        if i != vec_len - 1 {
                            if new_pillar_vec[i].top.to_real() < instance.position[2] &&
                               instance.position[2] < new_pillar_vec[i + 1].bottom.to_real() {
                                height = new_pillar_vec[i].top.to_real();
                                break;
                            } else {
                                continue;
                            }
                        } else {
                            height = new_pillar_vec[i].top.to_real();
                            break;
                        }
                    }
                }
            }
            // let vec = world.pillar_at(pillar_index);
            if ((tmp_point - camera.position).dot(camera.get_look_at_vector())) > 0.0 &&
               instance.position[2] > height {
                tmp2.push(Instance {
                    position: [instance.position[0], instance.position[1], instance.position[2]],
                })
            }
        }
        let vertex_buffer = glium::VertexBuffer::new(self.context.get_facade(), &tmp2).unwrap();

        self.actual_buf = vertex_buffer;
    }

    pub fn set_weather(&mut self, form: Form, strength: Strength) {
        self.form = form;
        self.strength = strength;
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

mod bindings;
pub mod operation;
mod queue;
<commit_msg>io_uring: impl IoUring public interface<commit_after>// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

mod bindings;
pub mod operation;
mod queue;

pub use queue::submission::Error as SQueueError;

use std::fs::File;
use std::io::Error as IOError;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};

use bindings::io_uring_params;
use operation::{Cqe, Operation};
use queue::completion::{CompletionQueue, Error as CQueueError};
use queue::submission::SubmissionQueue;
use utils::syscall::SyscallReturnCode;

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    CQueue(CQueueError),
    RegisterEventfd(IOError),
    RegisterFile(IOError),
    Setup(IOError),
    SQueue(SQueueError),
    InvalidFixedFd(i32),
    NoRegisteredFds,
}

pub struct IoUring {
    fd: File,
    registered_fds_count: u32,
    squeue: SubmissionQueue,
    cqueue: CompletionQueue,
}

impl IoUring {
    pub fn new(num_entries: u32) -> Result<Self> {
        let mut params: io_uring_params = Default::default();
        // Safe because values are valid and we check the return value.
        let fd = SyscallReturnCode(unsafe {
            libc::syscall(
                libc::SYS_io_uring_setup,
                num_entries,
                &mut params as *mut io_uring_params,
            ) as libc::c_int
        })
        .into_result()
        .map_err(Error::Setup)? as i32;

        // Safe because the fd is valid and because this struct owns the fd.
        let file = unsafe { File::from_raw_fd(fd) };

        let squeue = SubmissionQueue::new(fd, &params).map_err(Error::SQueue)?;
        let cqueue = CompletionQueue::new(fd, &params).map_err(Error::CQueue)?;

        Ok(Self {
            fd: file,
            squeue,
            cqueue,
            registered_fds_count: 0,
        })
    }

    pub fn push<T>(&mut self, op: Operation<T>) -> std::result::Result<(), (Error, T)> {
        // validate that we actually did register fds
        let fd = op.fd() as i32;
        match self.registered_fds_count {
            0 => Err((Error::NoRegisteredFds, op.user_data())),
            len if fd < 0 || (len as i32 - 1) < fd => {
                Err((Error::InvalidFixedFd(fd), op.user_data()))
            }
            _ => self.squeue.push(unsafe { op.into_sqe() }).map_err(
                |err_tuple: (SQueueError, T)| -> (Error, T) {
                    (Error::SQueue(err_tuple.0), err_tuple.1)
                },
            ),
        }
    }

    pub fn pop<T>(&mut self) -> Result<Option<Cqe<T>>> {
        self.cqueue.pop().map_err(Error::CQueue)
    }

    pub fn submit(&mut self) -> Result<u64> {
        self.squeue.submit(0).map_err(Error::SQueue)
    }

    pub fn submit_and_wait(&mut self, min_complete: u32) -> Result<u64> {
        self.squeue.submit(min_complete).map_err(Error::SQueue)
    }

    pub fn pending_sqes(&self) -> Result<u32> {
        self.squeue.pending().map_err(Error::SQueue)
    }

    pub fn register_file(&mut self, file: &File) -> Result<()> {
        // Safe because values are valid and we check the return value.
        SyscallReturnCode(unsafe {
            libc::syscall(
                libc::SYS_io_uring_register,
                self.fd.as_raw_fd(),
                bindings::IORING_REGISTER_FILES,
                (&[file.as_raw_fd()]).as_ptr() as *const _,
                1,
            ) as libc::c_int
        })
        .into_empty_result()
        .map_err(Error::RegisterFile)?;

        self.registered_fds_count += 1;
        Ok(())
    }

    pub fn register_eventfd(&self, fd: RawFd) -> Result<()> {
        // Safe because values are valid and we check the return value.
        SyscallReturnCode(unsafe {
            libc::syscall(
                libc::SYS_io_uring_register,
                self.fd.as_raw_fd(),
                bindings::IORING_REGISTER_EVENTFD,
                (&fd) as *const _,
                1,
            ) as libc::c_int
        })
        .into_empty_result()
        .map_err(Error::RegisterEventfd)?;

        Ok(())
    }
}
<|endoftext|>