<commit_before>//! Generic, fixed-size bitsets
//!
//! Sudoku strategies deal with sets of various things such as [`Digit`s](crate::board::Digit) and [`House`s](crate::board::House) a lot.
//! Efficient storage is important for maximal performance, but it should not be possible
//! to confuse bitmasks for different things. This module contains type-safe, space-efficient
//! fixed-length bitsets for digits and various sudoku positions.

use crate::board::{Cell, Col, Digit, House, Line, Position, Row};
use crate::helper::Unsolvable;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};

/// Generic, fixed-size bitset
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Set<T: SetElement>(pub(crate) T::Storage);

/// Iterator over the elements contained in a [`Set`]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Iter<T: SetElement>(T::Storage);

impl<T: SetElement> IntoIterator for Set<T>
where
    Iter<T>: Iterator,
{
    type Item = <Iter<T> as Iterator>::Item;
    type IntoIter = Iter<T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter(self.0)
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////
//                                  Bitops
///////////////////////////////////////////////////////////////////////////////////////////////

macro_rules! impl_binary_bitops {
    ( $( $trait:ident, $fn_name:ident);* $(;)* ) => {
        $(
            impl<T: SetElement> $trait for Set<T> {
                type Output = Self;

                #[inline(always)]
                fn $fn_name(self, other: Self) -> Self {
                    Set(
                        $trait::$fn_name(self.0, other.0)
                    )
                }
            }

            impl<T: SetElement> $trait<T> for Set<T> {
                type Output = Self;

                #[inline(always)]
                fn $fn_name(self, other: T) -> Self {
                    $trait::$fn_name(self, other.as_set())
                }
            }
        )*
    };
}

macro_rules! impl_bitops_assign {
    ( $( $trait:ident, $fn_name:ident);* $(;)* ) => {
        $(
            impl<T: SetElement> $trait for Set<T> {
                #[inline(always)]
                fn $fn_name(&mut self, other: Self) {
                    $trait::$fn_name(&mut self.0, other.0)
                }
            }

            impl<T: SetElement> $trait<T> for Set<T> {
                #[inline(always)]
                fn $fn_name(&mut self, other: T) {
                    $trait::$fn_name(self, other.as_set())
                }
            }
        )*
    };
}

impl_binary_bitops!(
    BitAnd, bitand;
    BitOr, bitor;
    BitXor, bitxor;
);

impl_bitops_assign!(
    BitAndAssign, bitand_assign;
    BitOrAssign, bitor_assign;
    BitXorAssign, bitxor_assign;
);

impl<T: SetElement> Not for Set<T>
where
    Self: PartialEq + Copy,
{
    type Output = Self;
    fn not(self) -> Self {
        Self::ALL.without(self)
    }
}

/// Potential return value for [`Set::unique`]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Empty;

impl From<Empty> for Unsolvable {
    fn from(_: Empty) -> Unsolvable {
        Unsolvable
    }
}

impl<T: SetElement> Set<T>
where
    // TODO: properly implement the traits for Set and Iter
    //       bounded on T::Storage, not on T (which derive does)
    Self: PartialEq + Copy,
{
    /// Set containing all possible elements
    pub const ALL: Set<T> = Set(<T as SetElement>::ALL);

    /// Empty Set
    pub const NONE: Set<T> = Set(<T as SetElement>::NONE);

    /// Construct a bitset from a raw integer.
    ///
    /// # Panic
    /// Panics, if the integer contains bits above [`Set::ALL`]
    pub fn from_bits(mask: T::Storage) -> Self {
        assert!(mask <= <T as SetElement>::ALL);
        Set(mask)
    }

    /// Return the raw integer backing the set.
    pub fn bits(self) -> T::Storage {
        self.0
    }

    /// Returns the set of elements in this set, that aren't present in `other`.
    pub fn without(self, other: Self) -> Self {
        Set(self.0 & !other.0)
    }

    /// Deletes all elements from this set that are present in `other`.
    pub fn remove(&mut self, other: Self) {
        self.0 &= !other.0;
    }

    /// Checks if `self` and `other` contain any common element.
    pub fn overlaps(&self, other: Self) -> bool {
        *self & other != Set::NONE
    }

    /// Checks if `self` contains `other`.
    pub fn contains(&self, other: impl Into<Self>) -> bool {
        let other = other.into();
        *self & other == other
    }

    /// Returns the number of elements in this set.
    pub fn len(&self) -> u8 {
        T::count_possibilities(self.0) as u8
    }

    /// Checks whether this set contains any element.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Checks whether this set contains all possible elements.
    pub fn is_full(&self) -> bool {
        *self == Self::ALL
    }

    /// Returns the only element in this set, iff only 1 element exists.
    /// If no elements exist, it returns `Err(Empty)`.
    /// If more than 1 element exists, it returns `Ok(None)`.
    pub fn unique(self) -> Result<Option<T>, Empty>
    where
        Iter<T>: Iterator<Item = T>,
    {
        match self.len() {
            1 => {
                let element = self.into_iter().next();
                debug_assert!(element.is_some());
                Ok(element)
            }
            0 => Err(Empty),
            _ => Ok(None),
        }
    }

    /// Returns one of the elements in this set.
    /// It is equivalent to `self.into_iter().next().unwrap()`
    ///
    /// # Panic
    /// Panics, if the set is empty
    #[allow(unused)]
    pub(crate) fn one_possibility(self) -> T
    where
        Iter<T>: Iterator<Item = T>,
    {
        self.into_iter().next().expect("mask is empty")
    }
}

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

/// Trait for types that can be stored in a [`Set`]
#[allow(missing_docs)]
pub trait SetElement: Sized + set_element::Sealed {
    const ALL: Self::Storage;
    const NONE: Self::Storage;

    type Storage: BitAnd<Output = Self::Storage>
        + BitAndAssign
        + BitOr<Output = Self::Storage>
        + BitOrAssign
        + BitXor<Output = Self::Storage>
        + BitXorAssign
        + Not<Output = Self::Storage>
        + PartialOrd
        + std::fmt::Binary
        + Copy;

    fn count_possibilities(set: Self::Storage) -> u32;
    fn as_set(self) -> Set<Self>;
}
mod set_element {
    use super::*;
    pub trait Sealed {}

    macro_rules! impl_sealed {
        ($($type:ty),*) => {
            $(
                impl Sealed for $type {}
            )*
        };
    }

    impl_sealed! {
        Cell, Digit, Row, Col, House, Line, Position<Line>, Position<House>
    }
}

macro_rules! impl_setelement {
    ( $( $type:ty => $storage_ty:ty, $all:expr),* $(,)* ) => {
        $(
            impl SetElement for $type {
                const ALL: $storage_ty = $all;
                const NONE: $storage_ty = 0;

                type Storage = $storage_ty;

                fn count_possibilities(set: Self::Storage) -> u32 {
                    set.count_ones()
                }

                fn as_set(self) -> Set<Self> {
                    Set(1 << self.as_index() as u8)
                }
            }

            impl $type {
                /// Returns a `Set<Self>` with the bit corresponding to this element set.
                pub fn as_set(self) -> Set<Self> {
                    SetElement::as_set(self)
                }
            }
        )*
    };
}

impl_setelement!(
    // 81 cells
    Cell => u128, 0o777_777_777___777_777_777___777_777_777,
    // 9 digits
    Digit => u16, 0o777,

    // 9 of each house
    //Row => u16, 0o777,
    //Col => u16, 0o777,
    //Block => u16, 0o777,
    Line => u32, 0o777_777,      // both Rows and Cols
    House => u32, 0o777_777_777, // Rows, Cols, Blocks

    // 9 positions per house
    //Position<Row> => u16, 0o777,
    //Position<Col> => u16, 0o777,
    Position<Line> => u16, 0o777,
    Position<House> => u16, 0o777,
    // 27 positions per chute
    //Position<Band> => u32, 0o777_777_777,
    //Position<Stack> => u32, 0o777_777_777,
    //Position<Chute> => u32, 0o777_777_777,
);

macro_rules! impl_iter_for_setiter {
    ( $( $type:ty => $constructor:expr ),* $(,)* ) => {
        $(
            impl Iterator for Iter<$type> {
                type Item = $type;

                fn next(&mut self) -> Option<Self::Item> {
                    debug_assert!(self.0 <= <Set<$type>>::ALL.0, "{:o}", self.0);
                    if self.0 == 0 {
                        return None;
                    }
                    let lowest_bit = self.0 & (!self.0 + 1);
                    let bit_pos = lowest_bit.trailing_zeros() as u8;
                    self.0 ^= lowest_bit;
                    Some($constructor(bit_pos))
                }
            }
        )*
    };
}

// can't do this generically
impl_iter_for_setiter!(
    Cell => Cell::new,
    Digit => Digit::from_index,
    Line => Line::new,
    House => House::new,
    //Position<Row> => Position::new,
    //Position<Col> => Position::new,
    Position<Line> => Position::new,
    Position<House> => Position::new,
    //Position<Band> => Position::new,
    //Position<Stack> => Position::new,
    //Position<Chute> => Position::new,
);

use std::fmt;
impl<T: SetElement> fmt::Binary for Set<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:b}", self.0)
    }
}
<commit_msg>generate bitset from size<commit_after>//! Generic, fixed-size bitsets
//!
//! Sudoku strategies deal with sets of various things such as [`Digit`s](crate::board::Digit) and [`House`s](crate::board::House) a lot.
//! Efficient storage is important for maximal performance, but it should not be possible
//! to confuse bitmasks for different things. This module contains type-safe, space-efficient
//! fixed-length bitsets for digits and various sudoku positions.

use crate::board::{Cell, Col, Digit, House, Line, Position, Row};
use crate::helper::Unsolvable;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};

/// Generic, fixed-size bitset
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Set<T: SetElement>(pub(crate) T::Storage);

/// Iterator over the elements contained in a [`Set`]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Iter<T: SetElement>(T::Storage);

impl<T: SetElement> IntoIterator for Set<T>
where
    Iter<T>: Iterator,
{
    type Item = <Iter<T> as Iterator>::Item;
    type IntoIter = Iter<T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter(self.0)
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////
//                                  Bitops
///////////////////////////////////////////////////////////////////////////////////////////////

macro_rules! impl_binary_bitops {
    ( $( $trait:ident, $fn_name:ident);* $(;)* ) => {
        $(
            impl<T: SetElement> $trait for Set<T> {
                type Output = Self;

                #[inline(always)]
                fn $fn_name(self, other: Self) -> Self {
                    Set(
                        $trait::$fn_name(self.0, other.0)
                    )
                }
            }

            impl<T: SetElement> $trait<T> for Set<T> {
                type Output = Self;

                #[inline(always)]
                fn $fn_name(self, other: T) -> Self {
                    $trait::$fn_name(self, other.as_set())
                }
            }
        )*
    };
}

macro_rules! impl_bitops_assign {
    ( $( $trait:ident, $fn_name:ident);* $(;)* ) => {
        $(
            impl<T: SetElement> $trait for Set<T> {
                #[inline(always)]
                fn $fn_name(&mut self, other: Self) {
                    $trait::$fn_name(&mut self.0, other.0)
                }
            }

            impl<T: SetElement> $trait<T> for Set<T> {
                #[inline(always)]
                fn $fn_name(&mut self, other: T) {
                    $trait::$fn_name(self, other.as_set())
                }
            }
        )*
    };
}

impl_binary_bitops!(
    BitAnd, bitand;
    BitOr, bitor;
    BitXor, bitxor;
);

impl_bitops_assign!(
    BitAndAssign, bitand_assign;
    BitOrAssign, bitor_assign;
    BitXorAssign, bitxor_assign;
);

impl<T: SetElement> Not for Set<T>
where
    Self: PartialEq + Copy,
{
    type Output = Self;
    fn not(self) -> Self {
        Self::ALL.without(self)
    }
}

/// Potential return value for [`Set::unique`]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Empty;

impl From<Empty> for Unsolvable {
    fn from(_: Empty) -> Unsolvable {
        Unsolvable
    }
}

impl<T: SetElement> Set<T>
where
    // TODO: properly implement the traits for Set and Iter
    //       bounded on T::Storage, not on T (which derive does)
    Self: PartialEq + Copy,
{
    /// Set containing all possible elements
    pub const ALL: Set<T> = Set(<T as SetElement>::ALL);

    /// Empty Set
    pub const NONE: Set<T> = Set(<T as SetElement>::NONE);

    /// Construct a bitset from a raw integer.
    ///
    /// # Panic
    /// Panics, if the integer contains bits above [`Set::ALL`]
    pub fn from_bits(mask: T::Storage) -> Self {
        assert!(mask <= <T as SetElement>::ALL);
        Set(mask)
    }

    /// Return the raw integer backing the set.
    pub fn bits(self) -> T::Storage {
        self.0
    }

    /// Returns the set of elements in this set, that aren't present in `other`.
    pub fn without(self, other: Self) -> Self {
        Set(self.0 & !other.0)
    }

    /// Deletes all elements from this set that are present in `other`.
    pub fn remove(&mut self, other: Self) {
        self.0 &= !other.0;
    }

    /// Checks if `self` and `other` contain any common element.
    pub fn overlaps(&self, other: Self) -> bool {
        *self & other != Set::NONE
    }

    /// Checks if `self` contains `other`.
    pub fn contains(&self, other: impl Into<Self>) -> bool {
        let other = other.into();
        *self & other == other
    }

    /// Returns the number of elements in this set.
    pub fn len(&self) -> u8 {
        T::count_possibilities(self.0) as u8
    }

    /// Checks whether this set contains any element.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Checks whether this set contains all possible elements.
    pub fn is_full(&self) -> bool {
        *self == Self::ALL
    }

    /// Returns the only element in this set, iff only 1 element exists.
    /// If no elements exist, it returns `Err(Empty)`.
    /// If more than 1 element exists, it returns `Ok(None)`.
    pub fn unique(self) -> Result<Option<T>, Empty>
    where
        Iter<T>: Iterator<Item = T>,
    {
        match self.len() {
            1 => {
                let element = self.into_iter().next();
                debug_assert!(element.is_some());
                Ok(element)
            }
            0 => Err(Empty),
            _ => Ok(None),
        }
    }

    /// Returns one of the elements in this set.
    /// It is equivalent to `self.into_iter().next().unwrap()`
    ///
    /// # Panic
    /// Panics, if the set is empty
    #[allow(unused)]
    pub(crate) fn one_possibility(self) -> T
    where
        Iter<T>: Iterator<Item = T>,
    {
        self.into_iter().next().expect("mask is empty")
    }
}

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

/// Trait for types that can be stored in a [`Set`]
#[allow(missing_docs)]
pub trait SetElement: Sized + set_element::Sealed {
    const ALL: Self::Storage;
    const NONE: Self::Storage;

    type Storage: BitAnd<Output = Self::Storage>
        + BitAndAssign
        + BitOr<Output = Self::Storage>
        + BitOrAssign
        + BitXor<Output = Self::Storage>
        + BitXorAssign
        + Not<Output = Self::Storage>
        + PartialOrd
        + std::fmt::Binary
        + Copy;

    fn count_possibilities(set: Self::Storage) -> u32;
    fn as_set(self) -> Set<Self>;
}
mod set_element {
    use super::*;
    pub trait Sealed {}

    macro_rules! impl_sealed {
        ($($type:ty),*) => {
            $(
                impl Sealed for $type {}
            )*
        };
    }

    impl_sealed! {
        Cell, Digit, Row, Col, House, Line, Position<Line>, Position<House>
    }
}

// returns a bitmask with the lowest `bitset_size` number of bits set
const fn n_bits_set(bitset_size: u8) -> u128 {
    (1 << bitset_size) - 1
}

macro_rules! impl_setelement {
    ( $( $type:ty => $storage_ty:ty, $bitset_size:expr),* $(,)* ) => {
        $(
            impl SetElement for $type {
                // try_into() would be better to avoid silent truncation
                // but trait methods can't be constified yet.
                const ALL: $storage_ty = n_bits_set($bitset_size) as $storage_ty;
                const NONE: $storage_ty = 0;

                type Storage = $storage_ty;

                fn count_possibilities(set: Self::Storage) -> u32 {
                    set.count_ones()
                }

                fn as_set(self) -> Set<Self> {
                    Set(1 << self.as_index() as u8)
                }
            }

            impl $type {
                /// Returns a `Set<Self>` with the bit corresponding to this element set.
                pub fn as_set(self) -> Set<Self> {
                    SetElement::as_set(self)
                }
            }
        )*
    };
}

impl_setelement!(
    // 81 cells
    Cell => u128, 81,
    // 9 digits
    Digit => u16, 9,

    // 9 of each house
    //Row => u16, 9,
    //Col => u16, 9,
    //Block => u16, 9,
    Line => u32, 18,      // both Rows and Cols
    House => u32, 27, // Rows, Cols, Blocks

    // 9 positions per house
    //Position<Row> => u16, 9,
    //Position<Col> => u16, 9,
    Position<Line> => u16, 9,
    Position<House> => u16, 9,
    // 27 positions per chute
    //Position<Band> => u32, 27,
    //Position<Stack> => u32, 27,
    //Position<Chute> => u32, 27,
);

macro_rules! impl_iter_for_setiter {
    ( $( $type:ty => $constructor:expr ),* $(,)* ) => {
        $(
            impl Iterator for Iter<$type> {
                type Item = $type;

                fn next(&mut self) -> Option<Self::Item> {
                    debug_assert!(self.0 <= <Set<$type>>::ALL.0, "{:o}", self.0);
                    if self.0 == 0 {
                        return None;
                    }
                    let lowest_bit = self.0 & (!self.0 + 1);
                    let bit_pos = lowest_bit.trailing_zeros() as u8;
                    self.0 ^= lowest_bit;
                    Some($constructor(bit_pos))
                }
            }
        )*
    };
}

// can't do this generically
impl_iter_for_setiter!(
    Cell => Cell::new,
    Digit => Digit::from_index,
    Line => Line::new,
    House => House::new,
    //Position<Row> => Position::new,
    //Position<Col> => Position::new,
    Position<Line> => Position::new,
    Position<House> => Position::new,
    //Position<Band> => Position::new,
    //Position<Stack> => Position::new,
    //Position<Chute> => Position::new,
);

use std::fmt;
impl<T: SetElement> fmt::Binary for Set<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:b}", self.0)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use scope::Scope;
use ast::{Expr, EvalResult};
use ast::EvalError::*;

pub struct State<'s> {
    default_ns: String,
    namespaces: HashMap<String, Scope<'s>>,
}

impl<'s> State<'s> {
    pub fn new(default: String) -> State<'s> {
        State {
            default_ns: default,
            namespaces: HashMap::new(),
        }
    }

    pub fn eval(&self, expr: &Expr) -> EvalResult {
        match try!(self.expand(expr)) {
            ref sym_expr @ Expr::Symbol { .. } => {
                self.eval_symbol(sym_expr)
            },
            ref def_expr @ Expr::Def { .. } => {
                self.eval_def(def_expr)
            },
            ref call_expr @ Expr::Call { .. } => {
                self.eval_call(call_expr)
            },
            ref let_expr @ Expr::Let { .. } => {
                self.eval_let(let_expr)
            },
            other_expr => {
                Ok(other_expr)
            },
        }
    }

    fn eval_symbol(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_def(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_call(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_let(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand(&self, expr: &Expr) -> EvalResult {
        if let Expr::List(ref l) = *expr {
            if l.len() > 0 {
                if let Expr::Symbol { ref name, .. } = l[0] {
                    match &name[..] {
                        "def" => {
                            return self.expand_def(expr)
                        },
                        "fn" => {
                            return self.expand_fn(expr)
                        },
                        "macro" => {
                            return self.expand_macro(expr)
                        },
                        "quote" => {
                            return self.expand_quote(expr)
                        },
                        "unquote" => {
                            return self.expand_unquote(expr)
                        },
                        "unquote-splicing" => {
                            return self.expand_unquote_splicing(expr)
                        },
                        "let" => {
                            return self.expand_let(expr)
                        },
                        _ => {
                            return self.expand_call(expr)
                        }
                    }
                } else {
                    return Err(DispatchError(l[0].clone()))
                }
            }
        }
        Ok(expr.clone())
    }

    fn expand_def(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_fn(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_macro(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_quote(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_unquote(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_unquote_splicing(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_let(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_call(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

}
<commit_msg>Implement eval_symbol method of state<commit_after>use std::collections::HashMap;
use scope::Scope;
use ast::{Expr, EvalResult};
use ast::EvalError::*;

pub struct State<'s> {
    default_ns: String,
    namespaces: HashMap<String, Scope<'s>>,
}

impl<'s> State<'s> {
    pub fn new(default: String) -> State<'s> {
        State {
            default_ns: default,
            namespaces: HashMap::new(),
        }
    }

    pub fn eval(&self, expr: &Expr) -> EvalResult {
        match try!(self.expand(expr)) {
            ref sym_expr @ Expr::Symbol { .. } => {
                self.eval_symbol(sym_expr)
            },
            ref def_expr @ Expr::Def { .. } => {
                self.eval_def(def_expr)
            },
            ref call_expr @ Expr::Call { .. } => {
                self.eval_call(call_expr)
            },
            ref let_expr @ Expr::Let { .. } => {
                self.eval_let(let_expr)
            },
            other_expr => {
                Ok(other_expr)
            },
        }
    }

    fn eval_symbol(&self, expr: &Expr) -> EvalResult {
        if let Expr::Symbol { ref ns, ref name , .. } = *expr {
            let ns_name = ns.as_ref().unwrap_or(&self.default_ns);
            match self.namespaces.get(ns_name) {
                Some(scope) => {
                    scope.get(name)
                         .map_or(Err(ResolveError(name.clone())), |e| Ok(e.clone()))
                },
                None => {
                    Err(ResolveError(ns_name.clone()))
                }
            }
        } else {
            Err(DispatchError(expr.clone()))
        }
    }

    fn eval_def(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_call(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_let(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand(&self, expr: &Expr) -> EvalResult {
        if let Expr::List(ref l) = *expr {
            if l.len() > 0 {
                if let Expr::Symbol { ref name, .. } = l[0] {
                    match &name[..] {
                        "def" => {
                            return self.expand_def(expr)
                        },
                        "fn" => {
                            return self.expand_fn(expr)
                        },
                        "macro" => {
                            return self.expand_macro(expr)
                        },
                        "quote" => {
                            return self.expand_quote(expr)
                        },
                        "unquote" => {
                            return self.expand_unquote(expr)
                        },
                        "unquote-splicing" => {
                            return self.expand_unquote_splicing(expr)
                        },
                        "let" => {
                            return self.expand_let(expr)
                        },
                        _ => {
                            return self.expand_call(expr)
                        }
                    }
                } else {
                    return Err(DispatchError(l[0].clone()))
                }
            }
        }
        Ok(expr.clone())
    }

    fn expand_def(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_fn(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_macro(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_quote(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_unquote(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_unquote_splicing(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_let(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_call(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

}
<|endoftext|>


<commit_before>use std::rc::Rc;

use Message;
use MiliSec;
use timer::TimerEvent;
use context::BaseContext;

#[derive(Debug)]
pub struct State {
    elapsed_time: MiliSec,
    elapsed_time_since_last_message: MiliSec,
    messages: Vec<Rc<Message>>,
    opened: bool,
}

impl State {
    pub fn new() -> State {
        State {
            elapsed_time: 0,
            elapsed_time_since_last_message: 0,
            messages: Vec::new(),
            opened: false,
        }
    }

    pub fn is_open(&self) -> bool {
        self.opened
    }

    pub fn open(&mut self) {
        self.opened = true;
    }

    pub fn close(&mut self, context: &BaseContext) {
        trace!("Context: closing state; uuid={}", context.uuid());
        for i in context.actions() {
            i.execute(self, context);
        }
        self.reset();
    }

    pub fn elapsed_time(&self) -> MiliSec {
        self.elapsed_time
    }

    pub fn elapsed_time_since_last_message(&self) -> MiliSec {
        self.elapsed_time_since_last_message
    }

    pub fn messages(&self) -> &[Rc<Message>] {
        &self.messages
    }

    pub fn add_message(&mut self, message: Rc<Message>) {
        self.messages.push(message);
        self.elapsed_time_since_last_message = 0;
    }

    pub fn on_timer(&mut self, event: &TimerEvent, context: &BaseContext) {
        if self.is_open() {
            self.update_timers(event);
            if context.conditions().is_closing(self) {
                self.close(context);
            }
        }
    }

    pub fn on_message(&mut self, event: Rc<Message>, context: &BaseContext) {
        if self.is_open() {
            self.add_message(event);
            if context.conditions().is_closing(self) {
                self.close(context);
            }
        } else if context.conditions().is_opening(&event) {
            trace!("Context: opening state; uuid={}", context.uuid());
            self.add_message(event);
            self.open();
        }
    }

    pub fn update_timers(&mut self, event: &TimerEvent) {
        let delta = event.0;
        self.elapsed_time += delta;
        self.elapsed_time_since_last_message += delta;
    }

    fn reset(&mut self) {
        self.elapsed_time = 0;
        self.elapsed_time_since_last_message = 0;
        self.messages.clear();
        self.opened = false;
    }
}
<commit_msg>State: check close conditions when the context is just opened<commit_after>use std::rc::Rc;

use Message;
use MiliSec;
use timer::TimerEvent;
use context::BaseContext;

#[derive(Debug)]
pub struct State {
    elapsed_time: MiliSec,
    elapsed_time_since_last_message: MiliSec,
    messages: Vec<Rc<Message>>,
    opened: bool,
}

impl State {
    pub fn new() -> State {
        State {
            elapsed_time: 0,
            elapsed_time_since_last_message: 0,
            messages: Vec::new(),
            opened: false,
        }
    }

    pub fn is_open(&self) -> bool {
        self.opened
    }

    pub fn open(&mut self) {
        self.opened = true;
    }

    pub fn close(&mut self, context: &BaseContext) {
        trace!("Context: closing state; uuid={}", context.uuid());
        for i in context.actions() {
            i.execute(self, context);
        }
        self.reset();
    }

    pub fn elapsed_time(&self) -> MiliSec {
        self.elapsed_time
    }

    pub fn elapsed_time_since_last_message(&self) -> MiliSec {
        self.elapsed_time_since_last_message
    }

    pub fn messages(&self) -> &[Rc<Message>] {
        &self.messages
    }

    pub fn add_message(&mut self, message: Rc<Message>) {
        self.messages.push(message);
        self.elapsed_time_since_last_message = 0;
    }

    pub fn on_timer(&mut self, event: &TimerEvent, context: &BaseContext) {
        if self.is_open() {
            self.update_timers(event);
        }
        if context.conditions().is_closing(self) {
            self.close(context);
        }
    }

    pub fn on_message(&mut self, event: Rc<Message>, context: &BaseContext) {
        if self.is_open() {
            self.add_message(event);
        } else if context.conditions().is_opening(&event) {
            trace!("Context: opening state; uuid={}", context.uuid());
            self.add_message(event);
            self.open();
        }

        if context.conditions().is_closing(self) {
            self.close(context);
        }
    }

    pub fn update_timers(&mut self, event: &TimerEvent) {
        let delta = event.0;
        self.elapsed_time += delta;
        self.elapsed_time_since_last_message += delta;
    }

    fn reset(&mut self) {
        self.elapsed_time = 0;
        self.elapsed_time_since_last_message = 0;
        self.messages.clear();
        self.opened = false;
    }
}
<|endoftext|>


<commit_before>use error::{BrokerResult, BrokerError};
use redis::{self, Commands};

#[derive(Clone)]
pub struct Store {
    pub client: redis::Client,
    pub expire_sessions: usize, // TTL of session keys, in seconds
    pub expire_cache: usize, // TTL of cache keys, in seconds
}

impl Store {
    pub fn new(url: &str, expire_sessions: usize, expire_cache: usize)
               -> Result<Store, &'static str> {

        match redis::Client::open(url) {
            Err(_) => Err("error opening store connection"),
            Ok(client) => Ok(Store {
                client: client,
                expire_sessions: expire_sessions,
                expire_cache: expire_cache,
            }),
        }
    }

    pub fn store_session(&self, session_id: &str, data: &str)
            -> BrokerResult<()> {
        let key = Self::format_session_key(session_id);
        self.client.set_ex(&key, data, self.expire_sessions)
            .map_err(|e| BrokerError::Internal(format!("could not save a session: {}", e)))
    }

    pub fn get_session(&self, session_id: &str)
            -> BrokerResult<String> {
        let key = Self::format_session_key(session_id);
        let stored: String = self.client.get(&key)
            .map_err(|e| BrokerError::Internal(format!("could not load a session: {}", e)))?;
        if stored.is_empty() {
            return Err(BrokerError::Input("session not found".to_owned()));
        }
        Ok(stored)
    }

    pub fn remove_session(&self, session_id: &str)
            -> BrokerResult<()> {
        let key = Self::format_session_key(session_id);
        self.client.del(&key)
            .map_err(|e| BrokerError::Internal(format!("could not remove a session: {}", e)))
    }

    fn format_session_key(session_id: &str) -> String {
        format!("session:{}", session_id)
    }
}
<commit_msg>Fix 'session not found' scenario<commit_after>use error::{BrokerResult, BrokerError};
use redis::{self, Commands};

#[derive(Clone)]
pub struct Store {
    pub client: redis::Client,
    pub expire_sessions: usize, // TTL of session keys, in seconds
    pub expire_cache: usize, // TTL of cache keys, in seconds
}

impl Store {
    pub fn new(url: &str, expire_sessions: usize, expire_cache: usize)
               -> Result<Store, &'static str> {

        match redis::Client::open(url) {
            Err(_) => Err("error opening store connection"),
            Ok(client) => Ok(Store {
                client: client,
                expire_sessions: expire_sessions,
                expire_cache: expire_cache,
            }),
        }
    }

    pub fn store_session(&self, session_id: &str, data: &str)
            -> BrokerResult<()> {
        let key = Self::format_session_key(session_id);
        self.client.set_ex(&key, data, self.expire_sessions)
            .map_err(|e| BrokerError::Internal(format!("could not save a session: {}", e)))
    }

    pub fn get_session(&self, session_id: &str)
            -> BrokerResult<String> {
        let key = Self::format_session_key(session_id);
        let stored: Option<String> = self.client.get(&key)
            .map_err(|e| BrokerError::Internal(format!("could not load a session: {}", e)))?;
        stored.ok_or_else(|| BrokerError::Input("session not found".to_owned()))
    }

    pub fn remove_session(&self, session_id: &str)
            -> BrokerResult<()> {
        let key = Self::format_session_key(session_id);
        self.client.del(&key)
            .map_err(|e| BrokerError::Internal(format!("could not remove a session: {}", e)))
    }

    fn format_session_key(session_id: &str) -> String {
        format!("session:{}", session_id)
    }
}
<|endoftext|>


<commit_before>use categories;
use common::{TransactionType, Transactions};
use error::{BResult, BudgetError};
use fintime::Timeframe::*;
use fintime::{Date, Timeframe};
use std::collections::HashMap;
use std::path::Path;
use csv;
use std::io::Write;
use rustc_serialize::json::{Json, ToJson};

fn cell(col: usize, row: usize) -> String {
    format!("{}{}", ('A' as usize + col) as u8 as char, row)
}

#[derive(Debug, RustcEncodable)]
struct BudgetCategory {
    name: String,
    previous_periods: Vec<f64>,
    current_period: f64,
    goal: f64,
}

impl ToJson for BudgetCategory {
    fn to_json(&self) -> Json {
        let mut m = HashMap::new();
        m.insert("name".to_owned(), self.name.to_json());
        m.insert("previous_periods".to_owned(),
                 self.previous_periods.to_json());
        m.insert("current_period".to_owned(), self.current_period.to_json());
        m.insert("most_recent_period".to_owned(),
                 self.previous_periods[self.previous_periods.len() - 1].to_json());
        m.insert("goal".to_owned(), self.goal.to_json());
        m.insert("remains".to_owned(),
                 (self.goal - self.current_period).to_json());
        m.insert("over_budget".to_owned(),
                 (self.current_period > self.goal).to_json());

        m.to_json()
    }
}

impl BudgetCategory {
    pub fn write_to_file<W: Write>(&self,
                                   row: usize,
                                   writer: &mut csv::Writer<W>)
                                   -> BResult<usize> {
        let mut current_row = Vec::new();

        current_row.push(format!("{}", self.name));

        let base_period = if self.previous_periods.len() > 0 {
            self.previous_periods.len() + 1
        } else {
            0
        };

        if self.previous_periods.len() > 0 {
            for value in &self.previous_periods {
                current_row.push(format!("${:.2}", value));
            }
            current_row.push(format!("=AVERAGE({}:{})",
                                     cell(1, row + 2),
                                     cell(self.previous_periods.len(), row + 2)));
        }

        current_row.push(format!("${:.2}", self.current_period));
        current_row.push(format!("${:.2}", self.goal));
        current_row.push(format!("={}-{}",
                                 cell(base_period + 2, row + 2),
                                 cell(base_period + 1, row + 2)));

        try!(writer.write(current_row.iter()));

        Ok(1)
    }
}

#[derive(Debug, RustcEncodable, ToJson)]
pub struct Budget {
    pub end_date: Date,
    period_length: Timeframe,

    period_start_dates: Vec<Date>,
    period_names: Vec<String>,
    current_period_start_date: Date,
    categories: HashMap<String, BudgetCategory>,
    any_over_budget: bool,
    has_historical: bool,
    current_period_sums: f64,
    remaining_sum: f64,
    previous_period_sums: Vec<f64>,
}

impl Budget {
    pub fn calculate(period: &Timeframe,
                     periods: usize,
                     transactions: &Transactions)
                     -> BResult<Budget> {
        let now = try! {
                transactions.date_of_last_transaction()
                    .ok_or(BudgetError::NoTransactionError)
            };
        let mut start_date = now;
        for _ in 0..periods {
            start_date -= period;
        }
        match *period {
            Weeks(_) => start_date.align_to_week(),
            Months(_) => start_date.align_to_month(),
            Quarters(_) => start_date.align_to_quarter(),
            Years(_) => start_date.align_to_year(),
            Days(_) => {},
        }

        let mut end_date = start_date + period;
        let mut ix = 0;

        let mut budget = Budget {
            period_length: *period,
            period_start_dates: vec![start_date],
            period_names: vec![format!("{} - {}", start_date, start_date + period - Days(1))],
            current_period_start_date: now,
            end_date: now,
            categories: HashMap::new(),
            has_historical: periods > 0,
            any_over_budget: false,

            current_period_sums: 0.0,
            remaining_sum: 0.0,
            previous_period_sums: Vec::new(),
        };

        let factor = period / Months(1);
        for limited_category in categories::LIMITS.keys().cloned() {
            budget.categories
                  .insert(limited_category.to_owned(),
                          BudgetCategory {
                              name: limited_category.to_owned(),
                              previous_periods: vec![0.0; periods],
                              current_period: 0.0,
                              goal: categories::LIMITS[limited_category] * factor,
                          });
        }

        for t in transactions.iter() {
            if t.date >= end_date {
                ix += 1;
                start_date += period;
                end_date += period;

                if ix < periods {
                    budget.period_start_dates.push(start_date);
                    budget.period_names.push(format!("{} - {}", start_date, end_date - Days(1)));
                } else if ix == periods {
                    budget.current_period_start_date = start_date;
                }
            }

            if t.transaction_type == TransactionType::Debit && t.date >= start_date &&
               t.date < end_date {
                let ref mut budget_category = budget.categories
                                                    .entry(t.category.to_owned())
                                                    .or_insert(BudgetCategory {
                                                        name: t.category.to_owned(),
                                                        previous_periods: vec![0.0; periods],
                                                        current_period: 0.0,
                                                        goal: 0.0,
                                                    });

                if ix < periods {
                    *budget_category.previous_periods
                                    .get_mut(ix)
                                    .expect(&format!("Tried to get index {}. Too big {}",
                                                     ix,
                                                     periods)) += t.amount;
                } else if ix == periods {
                    budget_category.current_period += t.amount;
                }
            }
        }

        budget.any_over_budget = budget.categories
                                       .iter()
                                       .filter(|&(_, c)| c.current_period > c.goal)
                                       .count() > 0;

        budget.current_period_sums = budget.categories
                                           .iter()
                                           .fold(0.0, |acc, (&_, ref c)| acc + c.current_period);

        budget.remaining_sum = budget.categories
                                     .iter()
                                     .fold(0.0, |acc, (&_, ref c)| acc + c.goal - c.current_period);

        budget.previous_period_sums = budget.categories
                                            .iter()
                                            .fold(vec![0.0; periods], |acc, (&_, ref c)| {
                                                acc.iter()
                                                   .enumerate()
                                                   .map(|(ix, &val)| c.previous_periods[ix] + val)
                                                   .collect()
                                            });

        Ok(budget)
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> BResult<usize> {
        let mut keys: Vec<_> = self.categories.keys().collect();
        let mut outfile = try!(csv::Writer::from_file(path));
        keys.sort();

        let mut current_row = Vec::new();
        current_row.push("Category".to_owned());
        if self.has_historical {
            for period_start in &self.period_start_dates {
                current_row.push(format!("{} - {}",
                                         period_start,
                                         period_start + self.period_length - Days(1)));
            }
            current_row.push("Average".to_owned());
        }
        let base_period = if self.has_historical {
            self.period_start_dates.len() + 1
        } else {
            0
        };
        current_row.push(format!("{} - {}", self.current_period_start_date, self.end_date));
        current_row.append(&mut vec!["Target Budget".to_owned(), "Budget Left".to_owned()]);
        try!(outfile.write(current_row.iter()));
        for (row, category_name) in keys.iter().enumerate() {
            current_row.clear();

            try!(self.categories[*category_name].write_to_file(row, &mut outfile));
        }

        current_row.clear();
        current_row.push("Total".to_owned());
        for i in 0..base_period + 3 {
            current_row.push(format!("=sum({}:{})", cell(i + 1, 2), cell(i + 1, keys.len() + 1)));
        }
        try!(outfile.write(current_row.iter()));

        Ok(self.categories.len())
    }
}
<commit_msg>Include income in budget calculation<commit_after>use categories;
use common::{TransactionType, Transactions};
use error::{BResult, BudgetError};
use fintime::Timeframe::*;
use fintime::{Date, Timeframe};
use std::collections::HashMap;
use std::path::Path;
use csv;
use std::io::Write;
use rustc_serialize::json::{Json, ToJson};

fn cell(col: usize, row: usize) -> String {
    format!("{}{}", ('A' as usize + col) as u8 as char, row)
}

#[derive(Debug, RustcEncodable)]
struct BudgetCategory {
    name: String,
    previous_periods: Vec<f64>,
    current_period: f64,
    goal: f64,
}

impl ToJson for BudgetCategory {
    fn to_json(&self) -> Json {
        let mut m = HashMap::new();
        m.insert("name".to_owned(), self.name.to_json());
        m.insert("previous_periods".to_owned(),
                 self.previous_periods.to_json());
        m.insert("current_period".to_owned(), self.current_period.to_json());
        m.insert("most_recent_period".to_owned(),
                 self.previous_periods[self.previous_periods.len() - 1].to_json());
        m.insert("goal".to_owned(), self.goal.to_json());
        m.insert("remains".to_owned(),
                 (self.goal - self.current_period).to_json());
        m.insert("over_budget".to_owned(),
                 (self.current_period > self.goal).to_json());

        m.to_json()
    }
}

impl BudgetCategory {
    pub fn write_to_file<W: Write>(&self,
                                   row: usize,
                                   writer: &mut csv::Writer<W>)
                                   -> BResult<usize> {
        let mut current_row = Vec::new();

        current_row.push(format!("{}", self.name));

        let base_period = if self.previous_periods.len() > 0 {
            self.previous_periods.len() + 1
        } else {
            0
        };

        if self.previous_periods.len() > 0 {
            for value in &self.previous_periods {
                current_row.push(format!("${:.2}", value));
            }
            current_row.push(format!("=AVERAGE({}:{})",
                                     cell(1, row + 2),
                                     cell(self.previous_periods.len(), row + 2)));
        }

        current_row.push(format!("${:.2}", self.current_period));
        current_row.push(format!("${:.2}", self.goal));
        current_row.push(format!("={}-{}",
                                 cell(base_period + 2, row + 2),
                                 cell(base_period + 1, row + 2)));

        try!(writer.write(current_row.iter()));

        Ok(1)
    }
}

#[derive(Debug, RustcEncodable, ToJson)]
pub struct Budget {
    pub end_date: Date,
    period_length: Timeframe,

    period_start_dates: Vec<Date>,
    period_names: Vec<String>,
    current_period_start_date: Date,
    categories: HashMap<String, BudgetCategory>,

    income: BudgetCategory,

    any_over_budget: bool,
    has_historical: bool,
    current_period_sums: f64,
    remaining_sum: f64,
    previous_period_sums: Vec<f64>,
}

impl Budget {
    pub fn calculate(period: &Timeframe,
                     periods: usize,
                     transactions: &Transactions)
                     -> BResult<Budget> {
        let now = try! {
                transactions.date_of_last_transaction()
                    .ok_or(BudgetError::NoTransactionError)
            };
        let mut start_date = now;
        for _ in 0..periods {
            start_date -= period;
        }
        match *period {
            Weeks(_) => start_date.align_to_week(),
            Months(_) => start_date.align_to_month(),
            Quarters(_) => start_date.align_to_quarter(),
            Years(_) => start_date.align_to_year(),
            Days(_) => {},
        }

        let mut end_date = start_date + period;
        let mut ix = 0;

        let mut budget = Budget {
            period_length: *period,
            period_start_dates: vec![start_date],
            period_names: vec![format!("{} - {}", start_date, start_date + period - Days(1))],
            current_period_start_date: now,
            end_date: now,
            categories: HashMap::new(),
            has_historical: periods > 0,
            any_over_budget: false,

            income: BudgetCategory {
                name: "Income".to_owned(),
                previous_periods: vec![0.0; periods],
                current_period: 0.0,
                goal: 0.0,
            },

            current_period_sums: 0.0,
            remaining_sum: 0.0,
            previous_period_sums: Vec::new(),
        };

        let factor = period / Months(1);
        for limited_category in categories::LIMITS.keys().cloned() {
            budget.categories
                  .insert(limited_category.to_owned(),
                          BudgetCategory {
                              name: limited_category.to_owned(),
                              previous_periods: vec![0.0; periods],
                              current_period: 0.0,
                              goal: categories::LIMITS[limited_category] * factor,
                          });
        }

        for t in transactions.iter() {
            if t.date >= end_date {
                ix += 1;
                start_date += period;
                end_date += period;

                if ix < periods {
                    budget.period_start_dates.push(start_date);
                    budget.period_names.push(format!("{} - {}", start_date, end_date - Days(1)));
                } else if ix == periods {
                    budget.current_period_start_date = start_date;
                }
            }

            if t.transaction_type == TransactionType::Debit && t.date >= start_date &&
               t.date < end_date {
                let ref mut budget_category = budget.categories
                                                    .entry(t.category.to_owned())
                                                    .or_insert(BudgetCategory {
                                                        name: t.category.to_owned(),
                                                        previous_periods: vec![0.0; periods],
                                                        current_period: 0.0,
                                                        goal: 0.0,
                                                    });

                if ix < periods {
                    *budget_category.previous_periods
                                    .get_mut(ix)
                                    .expect(&format!("Tried to get index {}. Too big {}",
                                                     ix,
                                                     periods)) += t.amount;
                } else if ix == periods {
                    budget_category.current_period += t.amount;
                }
            } else if t.transaction_type == TransactionType::Credit && t.date >= start_date &&
               t.date < end_date {

                if ix < periods {
                    *budget.income
                           .previous_periods
                           .get_mut(ix)
                           .expect(&format!("Tried to get index {}. Too big {}", ix, periods)) +=
                        t.amount;
                } else if ix == periods {
                    budget.income.current_period += t.amount;
                }

            }
        }

        budget.any_over_budget = budget.categories
                                       .iter()
                                       .filter(|&(_, c)| c.current_period > c.goal)
                                       .count() > 0;

        budget.current_period_sums = budget.categories
                                           .iter()
                                           .fold(0.0, |acc, (&_, ref c)| acc + c.current_period);

        budget.remaining_sum = budget.categories
                                     .iter()
                                     .fold(0.0, |acc, (&_, ref c)| acc + c.goal - c.current_period);

        budget.previous_period_sums = budget.categories
                                            .iter()
                                            .fold(vec![0.0; periods], |acc, (&_, ref c)| {
                                                acc.iter()
                                                   .enumerate()
                                                   .map(|(ix, &val)| c.previous_periods[ix] + val)
                                                   .collect()
                                            });

        Ok(budget)
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> BResult<usize> {
        let mut keys: Vec<_> = self.categories.keys().collect();
        let mut outfile = try!(csv::Writer::from_file(path));
        keys.sort();

        let mut current_row = Vec::new();
        current_row.push("Category".to_owned());
        if self.has_historical {
            for period_start in &self.period_start_dates {
                current_row.push(format!("{} - {}",
                                         period_start,
                                         period_start + self.period_length - Days(1)));
            }
            current_row.push("Average".to_owned());
        }
        let base_period = if self.has_historical {
            self.period_start_dates.len() + 1
        } else {
            0
        };
        current_row.push(format!("{} - {}", self.current_period_start_date, self.end_date));
        current_row.append(&mut vec!["Target Budget".to_owned(), "Budget Left".to_owned()]);
        try!(outfile.write(current_row.iter()));
        for (row, category_name) in keys.iter().enumerate() {
            if **category_name != "Income".to_owned() {
                current_row.clear();

                try!(self.categories[*category_name].write_to_file(row, &mut outfile));
            }
        }

        current_row.clear();
        current_row.push("Total".to_owned());
        for i in 0..base_period + 3 {
            current_row.push(format!("=sum({}:{})", cell(i + 1, 2), cell(i + 1, keys.len() + 1)));
        }
        try!(outfile.write(current_row.iter()));

        current_row.clear();
        current_row.push("".to_owned());
        for _ in 0..base_period + 3 {
            current_row.push("".to_owned());
        }
        try!(outfile.write(current_row.iter()));
        try!(outfile.write(current_row.iter()));

        try!(self.income.write_to_file(keys.len() + 3, &mut outfile));

        current_row.clear();
        current_row.push("Money Saved".to_owned());
        for i in 0..base_period + 3 {
            current_row.push(format!("={} - {}",
                                     cell(i + 1, keys.len() + 5),
                                     cell(i + 1, keys.len() + 2)));
        }
        try!(outfile.write(current_row.iter()));

        Ok(self.categories.len())
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, Div};
use std::time;

use euclid::{TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D};

use defs::*;
use math;
use math::*;
use shape::*;

// TODO: Do I need a custom AATransform that manages precision
// somehow?

// TODO: think about how movement will work: this is tricky. When a
// chunk is broken in to pieces, we need to make sure our
// current_shape and target_shape are switched to being ones that are
// in the correct chunk

#[derive(Debug)]
pub struct CameraState {
    pub camera_bounds: TypedRect<f32, DrawSpace>,

    pub current_chunk: TopChunk,
    pub current_neutral_transform: TypedTransform2D<f32, UniverseSpace, DrawSpace>,
    pub current_transform: TypedTransform2D<f32, UniverseSpace, DrawSpace>,

    pub target_chunk: TopChunk, // This should always be the parent chunk of the player chunk
    pub target_neutral_transform: TypedTransform2D<f32, UniverseSpace, DrawSpace>,

    pub current_to_target_path: MonotonePath, // This should stay in sync with the above...
}

impl CameraState {
    fn center<T, U>(rect: &TypedRect<T, U>) -> TypedPoint2D<T, U>
    where
        T: Copy + Add<T, Output = T> + Div<T, Output = T> + From<f32>,
    {
        TypedPoint2D::new(
            rect.origin.x + rect.size.width / T::from(2.0),
            rect.origin.y + rect.size.height / T::from(2.0),
        )
    }

    fn intended_target_chunk(logical_state: &LogicalState) -> TopChunk {
        logical_state
            .universe
            .parent_of(&logical_state.player_chunk)
    }

    fn target_transform_for(
        chunk: &TopChunk,
        logical_state: &LogicalState,
        bounds: TypedRect<f32, DrawSpace>,
    ) -> TypedTransform2D<f32, UniverseSpace, DrawSpace> {
        let chunk_bounds = logical_state
            .universe
            .region_of_chunk(chunk)
            .bounding_box(&logical_state.universe);

        transform::fit_rect_in(
            &chunk_bounds
                .to_f32()
                .inflate(DRAW_PARENT_MARGIN, DRAW_PARENT_MARGIN),
            &bounds,
        )
    }

    pub fn new(
        resolution: &TypedSize2D<u32, ScreenSpace>,
        logical_state: &LogicalState,
    ) -> CameraState {
        let camera_bounds = TypedRect::new(
            TypedPoint2D::zero(),
            TypedSize2D::new(resolution.width as f32, resolution.height as f32),
        );

        let start_chunk = CameraState::intended_target_chunk(&logical_state);
        let transform =
            CameraState::target_transform_for(&start_chunk, logical_state, camera_bounds);

        CameraState {
            camera_bounds: camera_bounds,

            current_chunk: start_chunk.clone(),
            current_transform: transform,
            current_neutral_transform: transform,

            target_chunk: start_chunk.clone(),
            target_neutral_transform: transform,

            current_to_target_path: MonotonePath::Zero,
        }
    }

    pub fn do_zoom(&mut self, logical_state: &LogicalState) -> () {
        // At this point, the logical state has already been zoomed.

        self.current_chunk = logical_state.universe.recalculate_chunk(&self.current_chunk);

        let new_target = CameraState::intended_target_chunk(logical_state);
        self.target_chunk = new_target.clone();
        self.target_neutral_transform =
            CameraState::target_transform_for(&new_target, logical_state, self.camera_bounds);

        self.current_to_target_path = self.current_to_target_path.down_target_to(new_target.origin_id);
    }

    pub fn scale_from_neutral(&self) -> f32 {
        transform::scale(
            &self
                .current_transform
                .post_mul(&self.current_neutral_transform.inverse().unwrap()),
        )
    }

    pub fn current_visual_level(&self) -> f32 {
        self.scale_from_neutral().log(ZOOM_SCALE as f32)
    }

    fn target_to_current_transform(
        &self,
        logical_state: &LogicalState,
    ) -> TypedTransform2D<f32, UniverseSpace, UniverseSpace> {
        self.current_to_target_path
            .as_delta_from(&logical_state.universe, &self.current_chunk)
            .0
            .invert()
            .to_scale_transform()
    }

    fn true_target_transform(
        &self,
        logical_state: &LogicalState,
    ) -> TypedTransform2D<f32, UniverseSpace, DrawSpace> {
        self.target_to_current_transform(logical_state)
            .post_mul(&self.target_neutral_transform)
    }

    pub fn update(&mut self, logical_state: &LogicalState, time_delta: time::Duration) -> () {
        // TODO: This is currently busted but somehow I get away with it?

        self.current_transform = transform::lerp(
            &self.current_transform,
            &self.true_target_transform(logical_state),
            1.0 - (-math::time::duration_to_secs(time_delta) * CAMERA_LERP_SPEED).exp(),
        );

        self.normalise(logical_state);
    }

    fn normalise(&mut self, logical_state: &LogicalState) -> () {
        let scale_from_neutral = self.scale_from_neutral();

        // MUST TODO: This will break if the individual chunks get too
        // big, need to scale by the size of the target/current chunk?
        // println!("{:#?}", scale_from_neutral);

        let need_normalisation = (scale_from_neutral > CAMERA_UPPER_NORMALISE_TRIGGER
            && self.current_to_target_path.zdelta() < 0)
            || (scale_from_neutral < CAMERA_LOWER_NORMALISE_TRIGGER
                && self.current_to_target_path.zdelta() > 0);

        if need_normalisation {
            let (adjustment, new_current_chunk) = self
                .current_to_target_path
                .take(1)
                .as_delta_from(&logical_state.universe, &self.current_chunk);

            self.current_neutral_transform = CameraState::target_transform_for(
                &new_current_chunk,
                logical_state,
                self.camera_bounds,
            );
            self.current_chunk = new_current_chunk;

            self.current_transform = self
                .current_transform
                .pre_mul(&adjustment.to_scale_transform());

            self.current_to_target_path = self.current_to_target_path.drop(1);
        }
    }

    // MUST TODO: This will start to matter when chunks are made
    pub fn recenter(&mut self, logical_state: &LogicalState) -> () {
        // unimplemented!();

        // let old_target_chunk = &self.target_chunk;
        // let new_target_chunk = CameraState::intended_target(logical_state);

        // self.target_chunk = new_target_chunk;

        // let old_current_chunk = &self.current_chunk;
        // let new_current_chunk = CameraState::intended_target(logical_state);

        // self.current_chunk = new_current_chunk;

        //unimplemented!();
    }
}
<commit_msg>Implement camera recentering to stop crash<commit_after>use std::ops::{Add, Div};
use std::time;

use euclid::{TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D};

use defs::*;
use math;
use math::*;
use shape::*;

// TODO: Do I need a custom AATransform that manages precision
// somehow?

// TODO: think about how movement will work: this is tricky. When a
// chunk is broken in to pieces, we need to make sure our
// current_shape and target_shape are switched to being ones that are
// in the correct chunk

#[derive(Debug)]
pub struct CameraState {
    pub camera_bounds: TypedRect<f32, DrawSpace>,

    pub current_chunk: TopChunk,
    pub current_neutral_transform: TypedTransform2D<f32, UniverseSpace, DrawSpace>,
    pub current_transform: TypedTransform2D<f32, UniverseSpace, DrawSpace>,

    pub target_chunk: TopChunk, // This should always be the parent chunk of the player chunk
    pub target_neutral_transform: TypedTransform2D<f32, UniverseSpace, DrawSpace>,

    pub current_to_target_path: MonotonePath, // This should stay in sync with the above...
}

impl CameraState {
    fn center<T, U>(rect: &TypedRect<T, U>) -> TypedPoint2D<T, U>
    where
        T: Copy + Add<T, Output = T> + Div<T, Output = T> + From<f32>,
    {
        TypedPoint2D::new(
            rect.origin.x + rect.size.width / T::from(2.0),
            rect.origin.y + rect.size.height / T::from(2.0),
        )
    }

    fn intended_target_chunk(logical_state: &LogicalState) -> TopChunk {
        logical_state
            .universe
            .parent_of(&logical_state.player_chunk)
    }

    fn target_transform_for(
        chunk: &TopChunk,
        logical_state: &LogicalState,
        bounds: TypedRect<f32, DrawSpace>,
    ) -> TypedTransform2D<f32, UniverseSpace, DrawSpace> {
        let chunk_bounds = logical_state
            .universe
            .region_of_chunk(chunk)
            .bounding_box(&logical_state.universe);

        transform::fit_rect_in(
            &chunk_bounds
                .to_f32()
                .inflate(DRAW_PARENT_MARGIN, DRAW_PARENT_MARGIN),
            &bounds,
        )
    }

    pub fn new(
        resolution: &TypedSize2D<u32, ScreenSpace>,
        logical_state: &LogicalState,
    ) -> CameraState {
        let camera_bounds = TypedRect::new(
            TypedPoint2D::zero(),
            TypedSize2D::new(resolution.width as f32, resolution.height as f32),
        );

        let start_chunk = CameraState::intended_target_chunk(&logical_state);
        let transform =
            CameraState::target_transform_for(&start_chunk, logical_state, camera_bounds);

        CameraState {
            camera_bounds: camera_bounds,

            current_chunk: start_chunk.clone(),
            current_transform: transform,
            current_neutral_transform: transform,

            target_chunk: start_chunk.clone(),
            target_neutral_transform: transform,

            current_to_target_path: MonotonePath::Zero,
        }
    }

    pub fn do_zoom(&mut self, logical_state: &LogicalState) -> () {
        // At this point, the logical state has already been zoomed.

        self.recenter(logical_state);

        let new_target = CameraState::intended_target_chunk(logical_state);
        self.target_chunk = new_target.clone();
        self.target_neutral_transform =
            CameraState::target_transform_for(&new_target, logical_state, self.camera_bounds);

        self.current_to_target_path = self
            .current_to_target_path
            .down_target_to(new_target.origin_id);
    }

    pub fn scale_from_neutral(&self) -> f32 {
        transform::scale(
            &self
                .current_transform
                .post_mul(&self.current_neutral_transform.inverse().unwrap()),
        )
    }

    pub fn current_visual_level(&self) -> f32 {
        self.scale_from_neutral().log(ZOOM_SCALE as f32)
    }

    fn target_to_current_transform(
        &self,
        logical_state: &LogicalState,
    ) -> TypedTransform2D<f32, UniverseSpace, UniverseSpace> {
        self.current_to_target_path
            .as_delta_from(&logical_state.universe, &self.current_chunk)
            .0
            .invert()
            .to_scale_transform()
    }

    fn true_target_transform(
        &self,
        logical_state: &LogicalState,
    ) -> TypedTransform2D<f32, UniverseSpace, DrawSpace> {
        self.target_to_current_transform(logical_state)
            .post_mul(&self.target_neutral_transform)
    }

    pub fn update(&mut self, logical_state: &LogicalState, time_delta: time::Duration) -> () {
        // TODO: This is currently busted but somehow I get away with it?

        self.current_transform = transform::lerp(
            &self.current_transform,
            &self.true_target_transform(logical_state),
            1.0 - (-math::time::duration_to_secs(time_delta) * CAMERA_LERP_SPEED).exp(),
        );

        self.normalise(logical_state);
    }

    fn normalise(&mut self, logical_state: &LogicalState) -> () {
        let scale_from_neutral = self.scale_from_neutral();

        // MUST TODO: This will break if the individual chunks get too
        // big, need to scale by the size of the target/current chunk?
        // println!("{:#?}", scale_from_neutral);

        let need_normalisation = (scale_from_neutral > CAMERA_UPPER_NORMALISE_TRIGGER
            && self.current_to_target_path.zdelta() < 0)
            || (scale_from_neutral < CAMERA_LOWER_NORMALISE_TRIGGER
                && self.current_to_target_path.zdelta() > 0);

        if need_normalisation {
            let (adjustment, new_current_chunk) = self
                .current_to_target_path
                .take(1)
                .as_delta_from(&logical_state.universe, &self.current_chunk);

            self.current_neutral_transform = CameraState::target_transform_for(
                &new_current_chunk,
                logical_state,
                self.camera_bounds,
            );
            self.current_chunk = new_current_chunk;

            self.current_transform = self
                .current_transform
                .pre_mul(&adjustment.to_scale_transform());

            self.current_to_target_path = self.current_to_target_path.drop(1);
        }
    }

    // We need to pick the chunk in the region that actually contains
    // the player
    pub fn recenter(&mut self, logical_state: &LogicalState) -> () {
        let old_current_chunk = &self.current_chunk;
        let region = logical_state.universe.region_of_chunk(old_current_chunk);

        let mut new_current_chunk_shape_id = logical_state.player_chunk.origin_id;
        while !region
            .top_shape_ids
            .contains_key(&new_current_chunk_shape_id)
        {
            new_current_chunk_shape_id = *logical_state.universe.shapes[&new_current_chunk_shape_id]
                .parent_ids
                .keys()
                .min()
                .unwrap();
        }
        let new_current_chunk: TopChunk = logical_state
            .universe
            .explore(new_current_chunk_shape_id)
            .into();

        let adjustment = region.top_shape_ids[&new_current_chunk.origin_id]
            - region.top_shape_ids[&old_current_chunk.origin_id];

        self.current_transform = self.current_transform.pre_translate(adjustment.to_f32());
        self.current_neutral_transform = CameraState::target_transform_for(
            &new_current_chunk,
            logical_state,
            self.camera_bounds,
        );
        self.current_chunk = new_current_chunk;

        let new_target = CameraState::intended_target_chunk(logical_state);
        self.target_chunk = new_target.clone();
        self.target_neutral_transform =
            CameraState::target_transform_for(&new_target, logical_state, self.camera_bounds);
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use byteorder::{LittleEndian, WriteBytesExt};
use fleetspeak_proto::common::{Message, Address};
use prost;
use prost_types;
use std::io::{Read, Write, Result, Error, ErrorKind};

pub struct Connection<'r, 'w, R, W> {
    pub input: &'r mut R,
    pub output: &'w mut W,
    buf: Vec<u8>,
}

impl<'r, 'w, R: Read, W: Write> Connection<'r, 'w, R, W> {

    pub fn new(input: &'r mut R, output: &'w mut W) -> Self {
        Connection {
            input: input,
            output: output,
            buf: vec!(0; 2 * 1024 * 1024), // TODO: Magic.
        }
    }

    pub fn send<M>(&mut self, service: &str, kind: &str, data: M) -> Result<()>
    where
        M: prost::Message,
    {
        self.encode(data)?;

        let msg = Message {
            message_type: kind.to_string(),
            destination: Some(Address {
                service_name: service.to_string(),
                ..Default::default()
            }),
            data: Some(prost_types::Any {
                value: self.buf.to_vec(),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    fn emit(&mut self, msg: Message) -> Result<()> {
        let len = prost::Message::encoded_len(&msg);
        self.encode(msg)?;

        self.output.write_u32::<LittleEndian>(len as u32)?;
        self.output.write(&self.buf[..len])?;
        self.output.write_u32::<LittleEndian>(0xf1ee1001)?; // TODO: Magic.

        Ok(())
    }

    fn encode<M>(&mut self, msg: M) -> Result<()>
    where
        M: prost::Message,
    {
        if let Err(err) = msg.encode(&mut self.buf) {
            let err = Error::new(ErrorKind::InvalidData, Box::new(err));
            return Err(err);
        };

        Ok(())
    }
}
<commit_msg>Add methods for receiving Fleetspeak messages.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fleetspeak_proto::common::{Message, Address};
use prost;
use prost_types;
use std::io::{Read, Write, Result, Error, ErrorKind};

pub struct Connection<'r, 'w, R, W> {
    pub input: &'r mut R,
    pub output: &'w mut W,
    buf: Vec<u8>,
}

impl<'r, 'w, R: Read, W: Write> Connection<'r, 'w, R, W> {

    pub fn new(input: &'r mut R, output: &'w mut W) -> Self {
        Connection {
            input: input,
            output: output,
            buf: vec!(0; 2 * 1024 * 1024), // TODO: Magic.
        }
    }

    pub fn send<M>(&mut self, service: &str, kind: &str, data: M) -> Result<()>
    where
        M: prost::Message,
    {
        self.encode(data)?;

        let msg = Message {
            message_type: kind.to_string(),
            destination: Some(Address {
                service_name: service.to_string(),
                ..Default::default()
            }),
            data: Some(prost_types::Any {
                value: self.buf.to_vec(),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn receive<M>(&mut self) -> Result<M>
    where
        M: prost::Message + Default,
    {
        let msg = self.collect()?;

        // It is not clear what is the best approach here. If there is no data,
        // should we error-out or return a default value? For the time being we
        // stick to the default approach, but if this proves to be not working
        // well in practice, it might be reconsidered.
        let data = match msg.data {
            Some(data) => data,
            None => return Ok(Default::default()),
        };

        match prost::Message::decode(&data.value[..]) {
            Ok(data) => Ok(data),
            Err(err) => {
                let err = Error::new(ErrorKind::InvalidData, Box::new(err));
                Err(err)
            },
        }
    }

    fn emit(&mut self, msg: Message) -> Result<()> {
        let len = prost::Message::encoded_len(&msg);
        self.encode(msg)?;

        self.output.write_u32::<LittleEndian>(len as u32)?;
        self.output.write(&self.buf[..len])?;
        self.output.write_u32::<LittleEndian>(0xf1ee1001)?; // TODO: Magic.

        Ok(())
    }

    fn collect(&mut self) -> Result<Message> {
        let len = self.input.read_i32::<LittleEndian>()? as usize;
        self.input.read_exact(&mut self.buf[..len])?;

        match prost::Message::decode(&self.buf[..len]) {
            Ok(msg) => Ok(msg),
            Err(err) => {
                let err = Error::new(ErrorKind::InvalidData, Box::new(err));
                Err(err)
            },
        }
    }

    fn encode<M>(&mut self, msg: M) -> Result<()>
    where
        M: prost::Message,
    {
        if let Err(err) = msg.encode(&mut self.buf) {
            let err = Error::new(ErrorKind::InvalidData, Box::new(err));
            return Err(err);
        };

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