<commit_before>use Parameter;
use fa::QFunction;
use utils::dot;
use agents::ControlAgent;
use domains::Transition;
use geometry::{Space, ActionSpace};
use policies::{Policy, Greedy};

use std::marker::PhantomData;
use std::collections::VecDeque;

/// Watkins' classical off policy temporal difference control algorithm.
///
/// C. J. C. H. Watkins and P. Dayan, “Q-learning,” Mach. Learn., vol. 8, no. 3–4, pp. 279–292,
/// 1992.
pub struct QLearning<S: Space, Q: QFunction<S>, P: Policy>
{
    q_func: Q,
    policy: P,

    alpha: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, Q, P> QLearning<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    pub fn new<T1, T2>(q_func: Q, policy: P,
                       alpha: T1, gamma: T2) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>
    {
        QLearning {
            q_func: q_func,
            policy: policy,

            alpha: alpha.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, Q, P> ControlAgent<S, ActionSpace> for QLearning<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    fn pi(&mut self, s: &S::Repr) -> usize {
        self.policy.sample(self.q_func.evaluate(s).as_slice())
    }

    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S::Repr) -> usize {
        p.sample(self.q_func.evaluate(s).as_slice())
    }

    fn handle_transition(&mut self, t: &Transition<S, ActionSpace>) {
        let (s, ns) = (t.from.state(), t.to.state());

        let qs = self.q_func.evaluate(s);
        let nqs = self.q_func.evaluate(ns);

        let a = t.action;
        let na = Greedy.sample(nqs.as_slice());

        let td_error = t.reward + self.gamma*nqs[na] - qs[a];

        self.q_func.update_action(s, a, self.alpha*td_error);
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();

        self.policy.handle_terminal();
    }
}

/// Classical on policy temporal difference control algorithm.
pub struct SARSA<S: Space, Q: QFunction<S>, P: Policy>
{
    q_func: Q,
    policy: P,

    alpha: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>
}

impl<S: Space, Q, P> SARSA<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    pub fn new<T1, T2>(q_func: Q, policy: P,
                       alpha: T1, gamma: T2) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>
    {
        SARSA {
            q_func: q_func,
            policy: policy,

            alpha: alpha.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, Q, P> ControlAgent<S, ActionSpace> for SARSA<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    fn pi(&mut self, s: &S::Repr) -> usize {
        self.policy.sample(self.q_func.evaluate(s).as_slice())
    }

    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S::Repr) -> usize {
        p.sample(self.q_func.evaluate(s).as_slice())
    }

    fn handle_transition(&mut self, t: &Transition<S, ActionSpace>) {
        let (s, ns) = (t.from.state(), t.to.state());

        let qs = self.q_func.evaluate(s);
        let nqs = self.q_func.evaluate(ns);

        let a = t.action;
        let na = self.policy.sample(nqs.as_slice());

        let td_error = t.reward + self.gamma*nqs[na] - qs[a];

        self.q_func.update_action(s, a, self.alpha*td_error);
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();

        self.policy.handle_terminal();
    }
}

/// Expected SARSA.
pub struct ExpectedSARSA<S: Space, Q: QFunction<S>, P: Policy>
{
    q_func: Q,
    policy: P,

    alpha: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>
}

impl<S: Space, Q, P> ExpectedSARSA<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    pub fn new<T1, T2>(q_func: Q, policy: P,
                       alpha: T1, gamma: T2) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>
    {
        ExpectedSARSA {
            q_func: q_func,
            policy: policy,

            alpha: alpha.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, Q, P> ControlAgent<S, ActionSpace> for ExpectedSARSA<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    fn pi(&mut self, s: &S::Repr) -> usize {
        self.policy.sample(self.q_func.evaluate(s).as_slice())
    }

    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S::Repr) -> usize {
        p.sample(self.q_func.evaluate(s).as_slice())
    }

    fn handle_transition(&mut self, t: &Transition<S, ActionSpace>) {
        let (s, ns) = (t.from.state(), t.to.state());

        let qs = self.q_func.evaluate(s);
        let nqs = self.q_func.evaluate(ns);

        let a = t.action;

        let exp_nqs = dot(&nqs, &self.policy.probabilities(nqs.as_slice()));
        let td_error = t.reward + self.gamma*exp_nqs - qs[a];

        self.q_func.update_action(s, a, self.alpha*td_error);
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();

        self.policy.handle_terminal();
    }
}

struct BackupEntry<S: Space> {
    pub s1: S::Repr,
    pub a1: usize,
    pub s2: S::Repr,
    pub a2: usize,

    pub q1: f64,
    pub q2: f64,
    pub delta: f64,

    pub sigma: f64,
    pub pi: f64,
    pub mu: f64,
}

/// General multi-step temporal-difference learning algorithm.
///
/// The sigma parameter varies the degree of sampling, yielding classical
/// learning algorithms as special cases:
///
/// * `0` - `ExpectedSARSA` | `TreeBackup`
/// * `1` - `SARSA`
///
/// De Asis, Kristopher, et al. "Multi-step Reinforcement Learning: A Unifying
/// Algorithm." arXiv preprint arXiv:1703.01327 (2017).
pub struct QSigma<S: Space, Q: QFunction<S>, P: Policy>
{
    q_func: Q,
    policy: P,

    alpha: Parameter,
    gamma: Parameter,
    sigma: Parameter,

    n_steps: usize,
    backup: VecDeque<BackupEntry<S>>,
}

impl<S: Space, Q, P> QSigma<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    pub fn new<T1, T2, T3>(q_func: Q, policy: P,
                           alpha: T1, gamma: T2,
                           sigma: T3, n_steps: usize) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>,
    {
        QSigma {
            q_func: q_func,
            policy: policy,

            alpha: alpha.into(),
            gamma: gamma.into(),
            sigma: sigma.into(),

            n_steps: n_steps,
            backup: VecDeque::new(),
        }
    }

    fn consume_backup(&mut self) {
        let td_error = (1..self.n_steps).fold(self.backup[0].delta, |acc, k| {
            // Calculate the cumulative discount factor:
            let gamma = self.gamma.value();
            let df = (1..k).fold(1.0, |acc, i| {
                let b = &self.backup[i];

                acc * gamma*((1.0 - b.sigma)*b.pi + b.sigma)
            });

            acc + self.backup[k].delta*df
        });

        let isr = (1..self.n_steps).fold(1.0, |acc, k| {
            let b = &self.backup[k];

            acc * (b.sigma*b.mu/b.pi + 1.0 - b.sigma)
        });

        self.q_func.update_action(&self.backup[0].s1, self.backup[0].a1,
                                  self.alpha*isr*td_error);

        self.backup.pop_front();
    }
}

impl<S: Space, Q, P> ControlAgent<S, ActionSpace> for QSigma<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    fn pi(&mut self, s: &S::Repr) -> usize {
        self.policy.sample(self.q_func.evaluate(s).as_slice())
    }

    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S::Repr) -> usize {
        p.sample(self.q_func.evaluate(s).as_slice())
    }

    fn handle_transition(&mut self, t: &Transition<S, ActionSpace>) {
        let (s, ns) = (t.from.state(), t.to.state());

        let q = self.q_func.evaluate_action(s, t.action);
        let nqs = self.q_func.evaluate(ns);

        let npi = self.policy.probabilities(nqs.as_slice());
        let exp_nqs = dot(&nqs, &npi);

        let na = self.policy.sample(nqs.as_slice());
        let nq = nqs[na];

        let sigma = { self.sigma = self.sigma.step(); self.sigma.value() };
        let td_error =
            t.reward + self.gamma*(sigma*nq + (1.0-sigma)*exp_nqs) - q;

        // Update backup sequence:
        self.backup.push_back(BackupEntry {
            s1: s.clone(),
            a1: t.action,
            s2: ns.clone(),
            a2: na,

            q1: q,
            q2: nq,
            delta: td_error,

            sigma: sigma,
            pi: npi[na],
            mu: Greedy.probabilities(&nqs)[na],
        });

        // Learn of latest backup sequence if we have `n_steps` entries:
        if self.backup.len() >= self.n_steps {
            self.consume_backup()
        }
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        // TODO: Handle terminal update according to Sutton's pseudocode.
        //       It's likely that this will require a change to the interface :(
        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();
        self.sigma = self.sigma.step();

        self.policy.handle_terminal();
    }
}
<commit_msg>Re-organised some code in agents/control/td.rs<commit_after>use Parameter;
use fa::QFunction;
use utils::dot;
use agents::ControlAgent;
use domains::Transition;
use geometry::{Space, ActionSpace};
use policies::{Policy, Greedy};

use std::marker::PhantomData;
use std::collections::VecDeque;

/// Watkins' classical off policy temporal difference control algorithm.
///
/// C. J. C. H. Watkins and P. Dayan, “Q-learning,” Mach. Learn., vol. 8, no. 3–4, pp. 279–292,
/// 1992.
pub struct QLearning<S: Space, Q: QFunction<S>, P: Policy>
{
    q_func: Q,
    policy: P,

    alpha: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, Q, P> QLearning<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    pub fn new<T1, T2>(q_func: Q, policy: P,
                       alpha: T1, gamma: T2) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>
    {
        QLearning {
            q_func: q_func,
            policy: policy,

            alpha: alpha.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, Q, P> ControlAgent<S, ActionSpace> for QLearning<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    fn pi(&mut self, s: &S::Repr) -> usize {
        self.policy.sample(self.q_func.evaluate(s).as_slice())
    }

    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S::Repr) -> usize {
        p.sample(self.q_func.evaluate(s).as_slice())
    }

    fn handle_transition(&mut self, t: &Transition<S, ActionSpace>) {
        let (s, ns) = (t.from.state(), t.to.state());

        let qs = self.q_func.evaluate(s);
        let nqs = self.q_func.evaluate(ns);

        let a = t.action;
        let na = Greedy.sample(nqs.as_slice());

        let td_error = t.reward + self.gamma*nqs[na] - qs[a];

        self.q_func.update_action(s, a, self.alpha*td_error);
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();

        self.policy.handle_terminal();
    }
}

/// Classical on policy temporal difference control algorithm.
pub struct SARSA<S: Space, Q: QFunction<S>, P: Policy>
{
    q_func: Q,
    policy: P,

    alpha: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>
}

impl<S: Space, Q, P> SARSA<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    pub fn new<T1, T2>(q_func: Q, policy: P,
                       alpha: T1, gamma: T2) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>
    {
        SARSA {
            q_func: q_func,
            policy: policy,

            alpha: alpha.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, Q, P> ControlAgent<S, ActionSpace> for SARSA<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    fn pi(&mut self, s: &S::Repr) -> usize {
        self.policy.sample(self.q_func.evaluate(s).as_slice())
    }

    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S::Repr) -> usize {
        p.sample(self.q_func.evaluate(s).as_slice())
    }

    fn handle_transition(&mut self, t: &Transition<S, ActionSpace>) {
        let (s, ns) = (t.from.state(), t.to.state());

        let qs = self.q_func.evaluate(s);
        let nqs = self.q_func.evaluate(ns);

        let a = t.action;
        let na = self.policy.sample(nqs.as_slice());

        let td_error = t.reward + self.gamma*nqs[na] - qs[a];

        self.q_func.update_action(s, a, self.alpha*td_error);
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();

        self.policy.handle_terminal();
    }
}

/// Expected SARSA.
pub struct ExpectedSARSA<S: Space, Q: QFunction<S>, P: Policy>
{
    q_func: Q,
    policy: P,

    alpha: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>
}

impl<S: Space, Q, P> ExpectedSARSA<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    pub fn new<T1, T2>(q_func: Q, policy: P,
                       alpha: T1, gamma: T2) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>
    {
        ExpectedSARSA {
            q_func: q_func,
            policy: policy,

            alpha: alpha.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, Q, P> ControlAgent<S, ActionSpace> for ExpectedSARSA<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    fn pi(&mut self, s: &S::Repr) -> usize {
        self.policy.sample(self.q_func.evaluate(s).as_slice())
    }

    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S::Repr) -> usize {
        p.sample(self.q_func.evaluate(s).as_slice())
    }

    fn handle_transition(&mut self, t: &Transition<S, ActionSpace>) {
        let (s, ns) = (t.from.state(), t.to.state());

        let qs = self.q_func.evaluate(s);
        let nqs = self.q_func.evaluate(ns);

        let a = t.action;

        let exp_nqs = dot(&nqs, &self.policy.probabilities(nqs.as_slice()));
        let td_error = t.reward + self.gamma*exp_nqs - qs[a];

        self.q_func.update_action(s, a, self.alpha*td_error);
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();

        self.policy.handle_terminal();
    }
}

/// General multi-step temporal-difference learning algorithm (off-policy).
///
/// The sigma parameter varies the degree of sampling, yielding classical
/// learning algorithms as special cases:
///
/// * `0` - `ExpectedSARSA` | `TreeBackup`
/// * `1` - `SARSA`
///
/// De Asis, Kristopher, et al. "Multi-step Reinforcement Learning: A Unifying
/// Algorithm." arXiv preprint arXiv:1703.01327 (2017).
pub struct QSigma<S: Space, Q: QFunction<S>, P: Policy>
{
    q_func: Q,
    policy: P,

    alpha: Parameter,
    gamma: Parameter,
    sigma: Parameter,

    n_steps: usize,
    backup: VecDeque<BackupEntry<S>>,
}

impl<S: Space, Q, P> QSigma<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    pub fn new<T1, T2, T3>(q_func: Q, policy: P,
                           alpha: T1, gamma: T2,
                           sigma: T3, n_steps: usize) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>,
    {
        QSigma {
            q_func: q_func,
            policy: policy,

            alpha: alpha.into(),
            gamma: gamma.into(),
            sigma: sigma.into(),

            n_steps: n_steps,
            backup: VecDeque::new(),
        }
    }

    fn consume_backup(&mut self) {
        let td_error = (1..self.n_steps).fold(self.backup[0].delta, |acc, k| {
            // Calculate the cumulative discount factor:
            let gamma = self.gamma.value();
            let df = (1..k).fold(1.0, |acc, i| {
                let b = &self.backup[i];

                acc * gamma*((1.0 - b.sigma)*b.pi + b.sigma)
            });

            acc + self.backup[k].delta*df
        });

        let isr = (1..self.n_steps).fold(1.0, |acc, k| {
            let b = &self.backup[k];

            acc * (b.sigma*b.mu/b.pi + 1.0 - b.sigma)
        });

        self.q_func.update_action(&self.backup[0].s1, self.backup[0].a1,
                                  self.alpha*isr*td_error);

        self.backup.pop_front();
    }
}

struct BackupEntry<S: Space> {
    pub s1: S::Repr,
    pub a1: usize,
    pub s2: S::Repr,
    pub a2: usize,

    pub q1: f64,
    pub q2: f64,
    pub delta: f64,

    pub sigma: f64,
    pub pi: f64,
    pub mu: f64,
}

impl<S: Space, Q, P> ControlAgent<S, ActionSpace> for QSigma<S, Q, P>
    where Q: QFunction<S>,
          P: Policy
{
    fn pi(&mut self, s: &S::Repr) -> usize {
        self.policy.sample(self.q_func.evaluate(s).as_slice())
    }

    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S::Repr) -> usize {
        p.sample(self.q_func.evaluate(s).as_slice())
    }

    fn handle_transition(&mut self, t: &Transition<S, ActionSpace>) {
        let (s, ns) = (t.from.state(), t.to.state());

        let q = self.q_func.evaluate_action(s, t.action);
        let nqs = self.q_func.evaluate(ns);

        let npi = self.policy.probabilities(nqs.as_slice());
        let exp_nqs = dot(&nqs, &npi);

        let na = self.policy.sample(nqs.as_slice());
        let nq = nqs[na];

        let sigma = { self.sigma = self.sigma.step(); self.sigma.value() };
        let td_error =
            t.reward + self.gamma*(sigma*nq + (1.0 - sigma)*exp_nqs) - q;

        // Update backup sequence:
        self.backup.push_back(BackupEntry {
            s1: s.clone(),
            a1: t.action,
            s2: ns.clone(),
            a2: na,

            q1: q,
            q2: nq,
            delta: td_error,

            sigma: sigma,
            pi: npi[na],
            mu: Greedy.probabilities(&nqs)[na],
        });

        // Learn of latest backup sequence if we have `n_steps` entries:
        if self.backup.len() >= self.n_steps {
            self.consume_backup()
        }
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        // TODO: Handle terminal update according to Sutton's pseudocode.
        //       It's likely that this will require a change to the interface
        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();

        self.policy.handle_terminal();
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate derive_more;

#[derive(From)]
#[derive(Eq, PartialEq, Debug)]
#[derive(Add)]
#[derive(Mul)]
#[derive(Neg)]
struct MyInt(i32);
#[derive(Eq, PartialEq, Debug)]
#[derive(Not)]
#[derive(From)]
struct MyBool(bool);

#[derive(Add)]
#[derive(Eq, PartialEq, Debug)]
#[derive(Mul)]
struct MyUInt(u64, u64);

#[derive(Add, Sub, Mul, Div, Rem, BitAnd, BitOr, BitXor, Shr, Shl)]
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
struct NormalStruct{int1: u64, int2: u64}

#[derive(From)]
#[derive(Eq, PartialEq, Debug)]
struct NestedInt(MyInt);

#[derive(Eq, PartialEq, Debug)]
#[derive(From)]
#[derive(Add, Sub)]
enum SimpleMyIntEnum{
    Int(i32),
    UnsignedOne(u32),
    UnsignedTwo(u32),
}
#[derive(Eq, PartialEq, Debug)]
#[derive(From)]
#[derive(Neg)]
enum SimpleSignedIntEnum{
    Int(i32),
    Int2(i16),
}

#[derive(Eq, PartialEq, Debug)]
#[derive(From)]
#[derive(Add, Sub)]
#[derive(Neg)]
enum SimpleEnum{
    Int(i32),
    Ints(i32, i32),
    LabeledInts{a: i32, b: i32},
    SomeUnit,
}

#[derive(Eq, PartialEq, Debug)]
#[derive(From)]
#[derive(Add, Sub)]
enum MyIntEnum{
    SmallInt(i32),
    BigInt(i64),
    TwoInts(i32, i32),
    UnsignedOne(u32),
    UnsignedTwo(u32),
    Nothing,
}

#[derive(Eq, PartialEq, Debug)]
#[derive(Add, Mul)]
struct DoubleUInt(u32, u32);

#[derive(Eq, PartialEq, Debug)]
#[derive(Add, Mul)]
struct DoubleUIntStruct{x:u32, y:u32}

#[test]
fn main() {
    let _: MyInt = 5.into();
    let _: SimpleMyIntEnum = 5i32.into();
    let _: MyIntEnum = 5i32.into();
    let _: MyIntEnum = 6i64.into();
    assert_eq!(MyInt(5), 5.into());
    assert_eq!(-MyInt(5), (-5).into());
    assert_eq!(!MyBool(true), false.into());
    assert_eq!(MyIntEnum::SmallInt(5), 5.into());

    assert_eq!(MyInt(4) + MyInt(1), 5.into());
    assert_eq!(MyUInt(4, 5) + MyUInt(1, 2), MyUInt(5, 7));
    let s1 = NormalStruct{int1: 1, int2: 2};
    let s2 = NormalStruct{int1: 2, int2: 3};
    let s3 = NormalStruct{int1: 3, int2: 5};
    assert_eq!(s1 + s2, s3);
    assert_eq!(s3 - s2, s1);
    assert_eq!((SimpleMyIntEnum::Int(6) + 5.into()).unwrap(), 11.into());
    assert_eq!((SimpleMyIntEnum::Int(6) - 5.into()).unwrap(), 1.into());
    assert_eq!((SimpleMyIntEnum::Int(6) - 5.into()).unwrap(), 1.into());
    assert_eq!(-SimpleSignedIntEnum::Int(6), (-6i32).into());
    assert_eq!((SimpleEnum::LabeledInts{a: 6, b: 5} + SimpleEnum::LabeledInts{a: 1, b: 4}).unwrap(),
                SimpleEnum::LabeledInts{a: 7, b: 9});

    let _ = (MyIntEnum::SmallInt(5) + 6.into()).unwrap();
    assert_eq!((-SimpleEnum::Int(5)).unwrap(), (-5).into());

    assert_eq!(MyInt(50), MyInt(5) * 10);
    assert_eq!(DoubleUInt(5, 6) * 10, DoubleUInt(50, 60));
    // assert_eq!(DoubleUIntStruct{x:5, y:6} * 10, DoubleUIntStruct{x:50, y:60});
}
<commit_msg>Fix unused code warnings<commit_after>#[macro_use]
extern crate derive_more;

#[derive(From)]
#[derive(Eq, PartialEq, Debug)]
#[derive(Add)]
#[derive(Mul)]
#[derive(Neg)]
struct MyInt(i32);
#[derive(Eq, PartialEq, Debug)]
#[derive(Not)]
#[derive(From)]
struct MyBool(bool);

#[derive(Add)]
#[derive(Eq, PartialEq, Debug)]
#[derive(Mul)]
struct MyUInt(u64, u64);

#[derive(Add, Sub, Mul, Div, Rem, BitAnd, BitOr, BitXor, Shr, Shl)]
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
struct NormalStruct{int1: u64, int2: u64}

#[derive(From)]
#[derive(Eq, PartialEq, Debug)]
struct NestedInt(MyInt);

#[derive(Eq, PartialEq, Debug)]
#[derive(From)]
#[derive(Add, Sub)]
enum SimpleMyIntEnum{
    Int(i32),
    _UnsignedOne(u32),
    _UnsignedTwo(u32),
}
#[derive(Eq, PartialEq, Debug)]
#[derive(From)]
#[derive(Neg)]
enum SimpleSignedIntEnum{
    Int(i32),
    Int2(i16),
}

#[derive(Eq, PartialEq, Debug)]
#[derive(From)]
#[derive(Add, Sub)]
#[derive(Neg)]
enum SimpleEnum{
    Int(i32),
    _Ints(i32, i32),
    LabeledInts{a: i32, b: i32},
    _SomeUnit,
}

#[derive(Eq, PartialEq, Debug)]
#[derive(From)]
#[derive(Add, Sub)]
enum MyIntEnum{
    SmallInt(i32),
    BigInt(i64),
    _TwoInts(i32, i32),
    _UnsignedOne(u32),
    _UnsignedTwo(u32),
    _Nothing,
}

#[derive(Eq, PartialEq, Debug)]
#[derive(Add, Mul)]
struct DoubleUInt(u32, u32);

#[derive(Eq, PartialEq, Debug)]
#[derive(Add, Mul)]
struct DoubleUIntStruct{x:u32, y:u32}

#[test]
fn main() {
    let _: MyInt = 5.into();
    let _: SimpleMyIntEnum = 5i32.into();
    let _: MyIntEnum = 5i32.into();
    let _: MyIntEnum = 6i64.into();
    assert_eq!(MyInt(5), 5.into());
    assert_eq!(-MyInt(5), (-5).into());
    assert_eq!(!MyBool(true), false.into());
    assert_eq!(MyIntEnum::SmallInt(5), 5.into());

    assert_eq!(MyInt(4) + MyInt(1), 5.into());
    assert_eq!(MyUInt(4, 5) + MyUInt(1, 2), MyUInt(5, 7));
    let s1 = NormalStruct{int1: 1, int2: 2};
    let s2 = NormalStruct{int1: 2, int2: 3};
    let s3 = NormalStruct{int1: 3, int2: 5};
    assert_eq!(s1 + s2, s3);
    assert_eq!(s3 - s2, s1);
    assert_eq!((SimpleMyIntEnum::Int(6) + 5.into()).unwrap(), 11.into());
    assert_eq!((SimpleMyIntEnum::Int(6) - 5.into()).unwrap(), 1.into());
    assert_eq!((SimpleMyIntEnum::Int(6) - 5.into()).unwrap(), 1.into());
    assert_eq!(-SimpleSignedIntEnum::Int(6), (-6i32).into());
    assert_eq!((SimpleEnum::LabeledInts{a: 6, b: 5} + SimpleEnum::LabeledInts{a: 1, b: 4}).unwrap(),
                SimpleEnum::LabeledInts{a: 7, b: 9});

    let _ = (MyIntEnum::SmallInt(5) + 6.into()).unwrap();
    assert_eq!((-SimpleEnum::Int(5)).unwrap(), (-5).into());

    assert_eq!(MyInt(50), MyInt(5) * 10);
    assert_eq!(DoubleUInt(5, 6) * 10, DoubleUInt(50, 60));
    // assert_eq!(DoubleUIntStruct{x:5, y:6} * 10, DoubleUIntStruct{x:50, y:60});
}
<|endoftext|>


<commit_before>extern crate pink_spider;

#[test]
fn it_works() {
  assert!(true);
}

#[test]
fn fetch_apple_music_track() {
    let song = pink_spider::apple_music::fetch_song("jp", "1160715431").unwrap();
    let track = pink_spider::model::Track::from_am_song(&song);
    assert_eq!(track.identifier, "1160715431");
    assert_eq!(track.title, "A Short Film");
    assert_eq!(track.owner_name.unwrap_or_default(), "LILI LIMIT");
    let artists = track.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "LILI LIMIT");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}

#[test]
fn fetch_apple_music_album() {
    let am_album = pink_spider::apple_music::fetch_album("jp", "1160715126").unwrap();
    let album = pink_spider::model::Album::from_am_album(&am_album);
    assert_eq!(album.identifier, "1160715126");
    assert_eq!(album.title, "a.k.a");
    assert_eq!(album.owner_name.unwrap_or_default(), "LILI LIMIT");
    let artists = album.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "LILI LIMIT");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}

#[test]
fn fetch_spotify_track() {
    let sp_track = pink_spider::spotify::fetch_track("3n3Ppam7vgaVa1iaRUc9Lp").unwrap();
    let track = pink_spider::model::Track::from_sp_track(&sp_track);
    assert_eq!(track.identifier, "3n3Ppam7vgaVa1iaRUc9Lp");
    assert_eq!(track.title, "Mr. Brightside");
    assert_eq!(track.owner_name.unwrap_or_default(), "The Killers");
    let artists = track.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "The Killers");
    println!("{:?}", artist);
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}

#[test]
fn fetch_spotify_album() {
    let sp_album = pink_spider::spotify::fetch_album("4OHNH3sDzIxnmUADXzv2kT").unwrap();
    let album = pink_spider::model::Album::from_sp_album(&sp_album);
    assert_eq!(album.identifier, "4OHNH3sDzIxnmUADXzv2kT");
    assert_eq!(album.title, "Hot Fuss (Deluxe Version)");
    assert_eq!(album.owner_name.unwrap_or_default(), "The Killers");
    let artists = album.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "The Killers");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
    assert!(album.tracks.len() > 0);
}

#[test]
fn fetch_soundcloud_track() {
    let sc_track = pink_spider::soundcloud::fetch_track("371851634").unwrap();
    let track = pink_spider::model::Track::from_sc_track(&sc_track);
    assert_eq!(track.identifier, "371851634");
    assert_eq!(track.title, "Down Wit That");
    assert_eq!(track.owner_name.unwrap_or_default(), "\"Chance The Rapper\"");
    let artists = track.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "\"Chance The Rapper\"");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}

#[test]
fn fetch_youtube_track() {
    let yt_video = pink_spider::youtube::fetch_video("Wr5f6hpYxmE").unwrap();
    let track = pink_spider::model::Track::from_yt_video(&yt_video);
    assert_eq!(track.identifier, "Wr5f6hpYxmE");
    assert_eq!(track.title, "Cornelius 『あなたがいるなら』If You're Here");
    assert_eq!(track.owner_name.unwrap_or_default(), "corneliusofficial");
    let artists = track.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "corneliusofficial");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}
<commit_msg>Fix broken apple music api test<commit_after>extern crate pink_spider;

#[test]
fn it_works() {
  assert!(true);
}

#[test]
fn fetch_apple_music_track() {
    let song = pink_spider::apple_music::fetch_song("jp", "1160715431").unwrap();
    let track = pink_spider::model::Track::from_am_song(&song);
    assert_eq!(track.identifier, "1160715431");
    assert_eq!(track.title, "A Short Film");
    assert_eq!(track.owner_name.unwrap_or_default(), "LILI LIMIT");
    let artists = track.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "LILI LIMIT");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}

#[test]
fn fetch_apple_music_album() {
    let am_album = pink_spider::apple_music::fetch_album("jp", "1160715126").unwrap();
    let album = pink_spider::model::Album::from_am_album(&am_album);
    assert_eq!(album.identifier, "1160715126");
    assert_eq!(album.title, "a.k.a");
    assert_eq!(album.owner_name.unwrap_or_default(), "LILI LIMIT");
    let artists = album.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "LILI LIMIT");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}

#[test]
fn fetch_spotify_track() {
    let sp_track = pink_spider::spotify::fetch_track("3n3Ppam7vgaVa1iaRUc9Lp").unwrap();
    let track = pink_spider::model::Track::from_sp_track(&sp_track);
    assert_eq!(track.identifier, "3n3Ppam7vgaVa1iaRUc9Lp");
    assert_eq!(track.title, "Mr. Brightside");
    assert_eq!(track.owner_name.unwrap_or_default(), "The Killers");
    let artists = track.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "The Killers");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}

#[test]
fn fetch_spotify_album() {
    let sp_album = pink_spider::spotify::fetch_album("4OHNH3sDzIxnmUADXzv2kT").unwrap();
    let album = pink_spider::model::Album::from_sp_album(&sp_album);
    assert_eq!(album.identifier, "4OHNH3sDzIxnmUADXzv2kT");
    assert_eq!(album.title, "Hot Fuss");
    assert_eq!(album.owner_name.unwrap_or_default(), "The Killers");
    let artists = album.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "The Killers");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
    assert!(album.tracks.len() > 0);
}

#[test]
fn fetch_soundcloud_track() {
    let sc_track = pink_spider::soundcloud::fetch_track("371851634").unwrap();
    let track = pink_spider::model::Track::from_sc_track(&sc_track);
    assert_eq!(track.identifier, "371851634");
    assert_eq!(track.title, "Down Wit That");
    assert_eq!(track.owner_name.unwrap_or_default(), "\"Chance The Rapper\"");
    let artists = track.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "\"Chance The Rapper\"");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}

#[test]
fn fetch_youtube_track() {
    let yt_video = pink_spider::youtube::fetch_video("Wr5f6hpYxmE").unwrap();
    let track = pink_spider::model::Track::from_yt_video(&yt_video);
    assert_eq!(track.identifier, "Wr5f6hpYxmE");
    assert_eq!(track.title, "Cornelius 『あなたがいるなら』If You're Here");
    assert_eq!(track.owner_name.unwrap_or_default(), "corneliusofficial");
    let artists = track.artists.unwrap();
    let artist = &artists[0];
    assert_eq!(artist.name, "corneliusofficial");
    assert!(artist.clone().artwork_url.unwrap().len() > 0);
}
<|endoftext|>


<commit_before>extern crate trustines;

mod memory {
    use trustines::memory::Memory;
    #[test]
    fn write() {
        let mut m = Memory::new();
        m.write(0, &[0,1,2]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(1,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
        m.write(1, &[3]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(3,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
    }

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.write(0,&[5,10]);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.write(0,&[2,1,0]);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;
    use trustines::cpu::OpcodeClass;
    use trustines::cpu::AddressMode;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }
    fn build_memory(instr:u8,index:u16, ops: &[u8]) -> Memory {
        let mut m = Memory::new();
        update_memory(&mut m,instr,index,ops);
        return m;
    }
    fn update_memory(m:&mut Memory, instr:u8,index:u16, ops: &[u8]) {
        m.write8(index,instr);
        if ops.len() > 0 {
            m.write(index+1,ops);
        }
    }

    // NOTE: the opcodes specified in build_memory are not being executed, so the
    //       opcode class (ADC, ASL, BRK, etc) don't actually matter.  What matters
    //       is the addressing mode (Absolute, AbsoluteX, ZeroPage, etc)
    //

// ------------------ Non-Indexed, Non-Memory ------------------ //

    #[test]
    fn accumulator() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x0A,0, &[]);// 0x0A = ASL Accumulator
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x0A);
    }
    #[test]
    fn immediate() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x69,0, &[]);// 0x69 = ADC Immediate
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x69);
    }
    #[test]
    fn implied() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x00,0, &[]);// 0x00 = BRK Implied
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x00);
    }

// ------------------ Non-Indexed, Memory ------------------ //

    #[test]
    fn absolute() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x6D,0, &[]); //0x6D = ADC Absolute
        let exec = build_executor();

        //mem.write8(0,0x6D);
        mem.write16(1,300);
        mem.write8(300,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);
        let s = OpcodeClass::ADC;

        assert_eq!(0x6D,cpu.instruction_register);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }

        assert_eq!(300,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x6C,0, &[]);// 0x6C = JMP Indirect
        let exec = build_executor();

        //mem.write8(0,0x6C);
        mem.write16(1,300);
        mem.write16(300,500);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x6C);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::JMP => {},
            _ => panic!("Expected JMP opcode class")
        }

        assert_eq!(300,cpu.decode_register.addr_intermediate.unwrap());
        assert_eq!(500,cpu.decode_register.addr_final.unwrap());
    }
    #[test]
    fn relative() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x90,0, &[]);// 0x90 = BCC IndirectIndexed
        let exec = build_executor();

        mem.write8(1,100);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x90);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::BCC => {},
            _ => panic!("Expected BCC opcode class")
        }
        assert_eq!(1,cpu.decode_register.addr_final.unwrap());
        assert_eq!(100,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn zeropage() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x65,0, &[]);// 0x65 = ADC IndirectIndexed
        let exec = build_executor();

        mem.write8(1,100);
        mem.write8(100,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x65);
        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        assert_eq!(100,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }

// ------------------ Indexed, Memory ------------------ //

    #[test]
    fn absolute_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x7D,0, &[]); // 0x7D = ADC AbsoluteX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x7D);
    }
    #[test]
    fn absolute_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x79,0, &[]);// 0x79 = ADC AbsoluteY
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x79);
    }
    #[test]
    fn zeropage_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x75,0, &[]);// 0x75 = LDX ZeroPageX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x75);
    }
    #[test]
    fn zeropage_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0xB6,0, &[]);// 0xB6 = LDX IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0xB6);
    }
    #[test]
    fn indexed_indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x61,0, &[]);// 0x61 = ADC IndexedIndirect
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x61);
    }
    #[test]
    fn indirect_indexed() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x71,0, &[]);// 0x71 = ADC IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x71);
    }
}

<commit_msg>refactored mem object creation and added OpcodeClass checks to tests<commit_after>extern crate trustines;

mod memory {
    use trustines::memory::Memory;
    #[test]
    fn write() {
        let mut m = Memory::new();
        m.write(0, &[0,1,2]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(1,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
        m.write(1, &[3]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(3,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
    }

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.write(0,&[5,10]);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.write(0,&[2,1,0]);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;
    use trustines::cpu::OpcodeClass;
    use trustines::cpu::AddressMode;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }
    fn build_memory(instr:u8,index:u16, ops: &[u8]) -> Memory {
        let mut m = Memory::new();
        update_memory(&mut m,instr,index,ops);
        return m;
    }
    fn update_memory(m:&mut Memory, instr:u8,index:u16, ops: &[u8]) {
        m.write8(index,instr);
        if ops.len() > 0 {
            m.write(index+1,ops);
        }
    }

    // NOTE: the opcodes specified in build_memory are not being executed, so the
    //       opcode class (ADC, ASL, BRK, etc) don't actually matter.  What matters
    //       is the addressing mode (Absolute, AbsoluteX, ZeroPage, etc)
    //

// ------------------ Non-Indexed, Non-Memory ------------------ //

    #[test]
    fn accumulator() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x0A); // 0x0A = ASL Accumulator

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x0A);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ASL => {},
            _ => panic!("Expected ASL opcode class")
        }
    }
    #[test]
    fn immediate() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x69); // 0x69 = ADC Immediate

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x69);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
    }
    #[test]
    fn implied() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x00); // 0x00 = BRK Implied

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x00);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::BRK => {},
            _ => panic!("Expected BRK opcode class")
        }
    }

// ------------------ Non-Indexed, Memory ------------------ //

    #[test]
    fn absolute() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x6D); //0x6D = ADC Absolute
        mem.write16(1,300);
        mem.write8(300,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);
        let s = OpcodeClass::ADC;

        assert_eq!(0x6D,cpu.instruction_register);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }

        assert_eq!(300,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x6C); // 0x6C = JMP Indirect
        mem.write16(1,300);
        mem.write16(300,500);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x6C);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::JMP => {},
            _ => panic!("Expected JMP opcode class")
        }

        assert_eq!(300,cpu.decode_register.addr_intermediate.unwrap());
        assert_eq!(500,cpu.decode_register.addr_final.unwrap());
    }
    #[test]
    fn relative() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x90); // 0x90 = BCC IndirectIndexed
        mem.write8(1,100);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x90);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::BCC => {},
            _ => panic!("Expected BCC opcode class")
        }
        assert_eq!(1,cpu.decode_register.addr_final.unwrap());
        assert_eq!(100,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn zeropage() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = Memory::new();
        let exec = build_executor();

        mem.write8(0,0x65); // 0x65 = ADC IndirectIndexed
        mem.write8(1,100);
        mem.write8(100,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x65);
        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        assert_eq!(100,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }

// ------------------ Indexed, Memory ------------------ //

    #[test]
    fn absolute_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x7D,0, &[]); // 0x7D = ADC AbsoluteX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x7D);
    }
    #[test]
    fn absolute_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x79,0, &[]);// 0x79 = ADC AbsoluteY
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x79);
    }
    #[test]
    fn zeropage_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x75,0, &[]);// 0x75 = LDX ZeroPageX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x75);
    }
    #[test]
    fn zeropage_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0xB6,0, &[]);// 0xB6 = LDX IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0xB6);
    }
    #[test]
    fn indexed_indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x61,0, &[]);// 0x61 = ADC IndexedIndirect
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x61);
    }
    #[test]
    fn indirect_indexed() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x71,0, &[]);// 0x71 = ADC IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x71);
    }
}

<|endoftext|>


<commit_before>extern crate codespawn;
#[test]
fn check_from_xml() {
    let raw_code = codespawn::from_xml("examples/sample.xml").unwrap();

    for c in raw_code.configs.iter() {
        println!("{}", c.1);
    }

    println!("{}", raw_code);
    println!("{}", raw_code.to_cpp());
    println!("{}", raw_code.to_rust());

    // save to .rst file instead of .rs so that subsequent test don't get confused
    let _ = raw_code.to_rust().to_file("tests/sample.rst");
    let _ = raw_code.to_cpp().to_file("tests/sample.cpp");
}

#[test]
fn check_from_json() {
    let raw_code = codespawn::from_json("examples/sample.json").unwrap();

    for c in raw_code.configs.iter() {
        println!("{}", c.1);
    }

    println!("{}", raw_code);
    println!("{}", raw_code.to_cpp());
    println!("{}", raw_code.to_rust());

    // save to .rst file instead of .rs so that subsequent test don't get confused
    let _ = raw_code.to_rust().to_file("tests/sample.rst");
    let _ = raw_code.to_cpp().to_file("tests/sample.cpp");
}

#[test]
#[should_panic]
fn check_from_xml_fail() {
    let _ = codespawn::from_xml("foobar").unwrap(); }

#[test]
#[should_panic]
fn check_from_json_fail() {
    let _ = codespawn::from_json("foobar").unwrap(); }

#[test]
#[should_panic]
fn check_from_xml_fail_cfg() {
    let _ = codespawn::from_xml_str("<config file=\"foobar\"/><var name=\"x\" type=\"int\"/>").unwrap(); }

#[test]
#[should_panic]
fn check_from_json_fail_cfg() {
    let _ = codespawn::from_json_str("{\"config\": { \"file\": \"foobar\" }, \"var\": {\"name\": \"x\", \"type\":\"int\" }}").unwrap(); }

#[test]
#[should_panic]
fn check_from_xml_fail_malformed() {
    let _ = codespawn::from_xml_str("<config file=\"foobar\"/>var name=\"x\" type=\"int\"/>").unwrap(); }

#[test]
#[should_panic]
fn check_from_json_fail_malformed() {
    let _ = codespawn::from_json_str("{\"config\": { \"file\": \"examples/rust.json\" } \"var\": {\"name\": \"x\", \"type\":\"int\" }}").unwrap(); }

#[test]
#[should_panic]
fn check_from_xml_fail_enum() {
    let rc = codespawn::from_xml_str("<enum name=\"Foo\"><func name=\"x\" type=\"int\"/></enum>").unwrap();
    rc.to_rust().to_string(); }

#[test]
#[should_panic]
fn check_from_json_fail_enum() {
    let rc = codespawn::from_json_str("{\"enum\":{ \"name\":\"Foo\",\"func\": { \"name\":\"x\",\"type\":\"int\"}}}").unwrap();
    rc.to_cpp().to_string(); }

#[test]
#[should_panic]
fn check_from_xml_fail_func() {
    let rc = codespawn::from_xml_str("<func name=\"x\" type=\"int\"><enum name=\"Foo\"></enum></func>").unwrap();
    rc.to_rust().to_string(); }

#[test]
#[should_panic]
fn check_from_json_fail_func() {
    let rc = codespawn::from_json_str("{\"func\": {\"name\":\"x\",\"type\":\"int\",\"enum\": {\"name\":\"Foo\"}}}").unwrap();
    rc.to_cpp().to_string(); }

#[test]
#[should_panic]
fn check_from_xml_fail_malformed_cfg() {
    let _ = codespawn::from_xml_str("<config file=\"tests/malformed_cfg.xml\"/><var name=\"x\" type=\"int\"/>").unwrap(); }

#[test]
#[should_panic]
fn check_write_file() {
    let raw_code = codespawn::from_json("examples/sample.xml").unwrap();
    raw_code.to_cpp().to_file("").unwrap(); }
<commit_msg>fixed broken test<commit_after>extern crate codespawn;

#[test]
fn check_from_xml() {
    let raw_code = codespawn::from_xml("examples/sample.xml").unwrap();

    for c in raw_code.configs.iter() {
        println!("{}", c.1);
    }

    println!("{}", raw_code);
    println!("{}", raw_code.to_cpp());
    println!("{}", raw_code.to_rust());

    // save to .rst file instead of .rs so that subsequent test don't get confused
    let _ = raw_code.to_rust().to_file("tests/sample.rst");
    let _ = raw_code.to_cpp().to_file("tests/sample.cpp");
}

#[test]
fn check_from_json() {
    let raw_code = codespawn::from_json("examples/sample.json").unwrap();

    for c in raw_code.configs.iter() {
        println!("{}", c.1);
    }

    println!("{}", raw_code);
    println!("{}", raw_code.to_cpp());
    println!("{}", raw_code.to_rust());

    // save to .rst file instead of .rs so that subsequent test don't get confused
    let _ = raw_code.to_rust().to_file("tests/sample.rst");
    let _ = raw_code.to_cpp().to_file("tests/sample.cpp");
}

#[test]
#[should_panic]
fn check_from_xml_fail() {
    let _ = codespawn::from_xml("foobar").unwrap(); }

#[test]
#[should_panic]
fn check_from_json_fail() {
    let _ = codespawn::from_json("foobar").unwrap(); }

#[test]
#[should_panic]
fn check_from_xml_fail_cfg() {
    let _ = codespawn::from_xml_str("<config file=\"foobar\"/><var name=\"x\" type=\"int\"/>").unwrap(); }

#[test]
#[should_panic]
fn check_from_json_fail_cfg() {
    let _ = codespawn::from_json_str("{\"config\": { \"file\": \"foobar\" }, \"var\": {\"name\": \"x\", \"type\":\"int\" }}").unwrap(); }

#[test]
#[should_panic]
fn check_from_xml_fail_malformed() {
    let _ = codespawn::from_xml_str("<config file=\"foobar\"/>var name=\"x\" type=\"int\"/>").unwrap(); }

#[test]
#[should_panic]
fn check_from_json_fail_malformed() {
    let _ = codespawn::from_json_str("{\"config\": { \"file\": \"examples/rust.json\" } \"var\": {\"name\": \"x\", \"type\":\"int\" }}").unwrap(); }

#[test]
#[should_panic]
fn check_from_xml_fail_enum() {
    let rc = codespawn::from_xml_str("<enum name=\"Foo\"><func name=\"x\" type=\"int\"/></enum>").unwrap();
    rc.to_rust().to_string(); }

#[test]
#[should_panic]
fn check_from_json_fail_enum() {
    let rc = codespawn::from_json_str("{\"enum\":{ \"name\":\"Foo\",\"func\": { \"name\":\"x\",\"type\":\"int\"}}}").unwrap();
    rc.to_cpp().to_string(); }

#[test]
#[should_panic]
fn check_from_xml_fail_func() {
    let rc = codespawn::from_xml_str("<func name=\"x\" type=\"int\"><enum name=\"Foo\"></enum></func>").unwrap();
    rc.to_rust().to_string(); }

#[test]
#[should_panic]
fn check_from_json_fail_func() {
    let rc = codespawn::from_json_str("{\"func\": {\"name\":\"x\",\"type\":\"int\",\"enum\": {\"name\":\"Foo\"}}}").unwrap();
    rc.to_cpp().to_string(); }

#[test]
#[should_panic]
fn check_from_xml_fail_malformed_cfg() {
    let _ = codespawn::from_xml_str("<config file=\"tests/malformed_cfg.xml\"/><var name=\"x\" type=\"int\"/>").unwrap(); }

#[test]
#[should_panic]
fn check_write_file() {
    let raw_code = codespawn::from_xml("examples/sample.xml").unwrap();
    raw_code.to_cpp().to_file("").unwrap(); }
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

extern crate tmx;

#[macro_use]
extern crate assert_matches;

#[test]
fn Map_NonExistentFile_ReturnsIoError() {
    let result = tmx::Map::open("non_existent_file.tmx");
    assert_matches!(result, Err(tmx::Error::Io(..)));
}

#[test]
fn Map_ValidXmlFile_ReturnsMap() {
    let result = tmx::Map::open("data/empty_map.tmx");
    assert_matches!(result, Ok(tmx::Map {..}));
}

#[test]
fn Tileset_NonExistentFile_ReturnsIoError() {
    let result = tmx::Tileset::open("non_existent_file.tsx");
    assert_matches!(result, Err(tmx::Error::Io(..)));
}

#[test]
fn Tileset_ValidXmlFile_ReturnsTileset() {
    let result = tmx::Tileset::open("data/simple_tileset.tsx");
    assert_matches!(result, Ok(tmx::Tileset {..}));
    let tileset = result.unwrap();
    let image = tileset.image().unwrap();
    assert_eq!(image.width(), 480);
    assert_eq!(image.height(), 480);
}

<commit_msg>Renamed integration tests to match unit tests<commit_after>extern crate tmx;

#[macro_use]
extern crate assert_matches;

#[test]
fn when_reading_nonexistent_map_file_expect_io_error() {
    let result = tmx::Map::open("non_existent_file.tmx");
    assert_matches!(result, Err(tmx::Error::Io(..)));
}

#[test]
fn after_reading_valid_tmx_file_expect_valid_map() {
    let result = tmx::Map::open("data/empty_map.tmx");
    assert_matches!(result, Ok(tmx::Map {..}));
}

#[test]
fn when_reading_nonexistent_tileset_file_expect_io_error() {
    let result = tmx::Tileset::open("non_existent_file.tsx");
    assert_matches!(result, Err(tmx::Error::Io(..)));
}

#[test]
fn after_reading_valid_tsx_file_expect_valid_tileset() {
    let result = tmx::Tileset::open("data/simple_tileset.tsx");
    assert_matches!(result, Ok(tmx::Tileset {..}));
    let tileset = result.unwrap();
    let image = tileset.image().unwrap();
    assert_eq!(image.width(), 480);
    assert_eq!(image.height(), 480);
}

<|endoftext|>


<commit_before>// Copyright (c) 2017 Anatoly Ikorsky
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use bit_vec::BitVec;
use byteorder::LittleEndian as LE;
use byteorder::{ReadBytesExt, WriteBytesExt};
use connection_like::streamless::Streamless;
use connection_like::{ConnectionLike, ConnectionLikeWrapper, StmtCacheResult};
use consts::{ColumnType, Command};
use errors::*;
use io;
use lib_futures::future::Either::*;
use lib_futures::future::{err, loop_fn, ok, Either, Future, IntoFuture, Loop};
use myc::value::serialize_bin_many;
use prelude::FromRow;
use queryable::query_result::QueryResult;
use queryable::BinaryProtocol;
use std::io::Write;
use BoxFuture;
use Column;
use Params;
use Row;
use Value;
use Value::*;

/// Inner statement representation.
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct InnerStmt {
    /// Positions and names of named parameters
    pub named_params: Option<Vec<String>>,
    pub params: Option<Vec<Column>>,
    pub columns: Option<Vec<Column>>,
    pub statement_id: u32,
    pub num_columns: u16,
    pub num_params: u16,
    pub warning_count: u16,
}

impl InnerStmt {
    // TODO: Consume payload?
    pub fn new(pld: &[u8], named_params: Option<Vec<String>>) -> Result<InnerStmt> {
        let mut reader = &pld[1..];
        let statement_id = reader.read_u32::<LE>()?;
        let num_columns = reader.read_u16::<LE>()?;
        let num_params = reader.read_u16::<LE>()?;
        let warning_count = reader.read_u16::<LE>()?;
        Ok(InnerStmt {
            named_params: named_params,
            statement_id: statement_id,
            num_columns: num_columns,
            num_params: num_params,
            warning_count: warning_count,
            params: None,
            columns: None,
        })
    }
}

/// Prepared statement
pub struct Stmt<T> {
    conn_like: Option<Either<T, Streamless<T>>>,
    inner: InnerStmt,
    /// None => In use elsewhere
    /// Some(Cached) => Should not be closed
    /// Some(NotCached(_)) => Should be closed
    cached: Option<StmtCacheResult>,
}

pub fn new<T>(conn_like: T, inner: InnerStmt, cached: StmtCacheResult) -> Stmt<T>
where
    T: ConnectionLike + Sized + 'static,
{
    Stmt::new(conn_like, inner, cached)
}

impl<T> Stmt<T>
where
    T: ConnectionLike + Sized + 'static,
{
    fn new(conn_like: T, inner: InnerStmt, cached: StmtCacheResult) -> Stmt<T> {
        Stmt {
            conn_like: Some(A(conn_like)),
            inner,
            cached: Some(cached),
        }
    }

    fn send_long_data(
        self,
        params: Vec<Value>,
        large_bitmap: BitVec<u8>,
    ) -> BoxFuture<(Self, Vec<Value>)> {
        let fut = loop_fn(
            (self, params, large_bitmap.into_iter().enumerate()),
            |(this, params, mut large_bitmap)| match large_bitmap.next() {
                Some((i, true)) => {
                    let fut = loop_fn((this, params, i, 0), |(this, params, i, chunk)| {
                        let data_cap = ::consts::MAX_PAYLOAD_LEN - 10;
                        let buf = match params[i] {
                            Bytes(ref x) => {
                                let statement_id = this.inner.statement_id;
                                let mut chunks = x.chunks(data_cap);
                                match chunks.nth(chunk) {
                                    Some(chunk) => {
                                        let mut buf = Vec::with_capacity(chunk.len() + 6);
                                        buf.write_u32::<LE>(statement_id).unwrap();
                                        buf.write_u16::<LE>(i as u16).unwrap();
                                        buf.write_all(chunk).unwrap();
                                        Some(buf)
                                    }
                                    _ => None,
                                }
                            }
                            _ => unreachable!(),
                        };
                        match buf {
                            Some(buf) => {
                                let chunk_len = buf.len() - 6;
                                let fut =
                                    this.write_command_data(Command::COM_STMT_SEND_LONG_DATA, buf)
                                        .map(move |this| {
                                            if chunk_len < data_cap {
                                                Loop::Break((this, params))
                                            } else {
                                                Loop::Continue((this, params, i, chunk + 1))
                                            }
                                        });
                                A(fut)
                            }
                            None => B(ok(Loop::Break((this, params)))),
                        }
                    }).map(|(this, params)| {
                        Loop::Continue((this, params, large_bitmap))
                    });
                    A(fut)
                }
                Some((_, false)) => B(A(ok(Loop::Continue((this, params, large_bitmap))))),
                None => B(B(ok(Loop::Break((this, params))))),
            },
        );
        Box::new(fut)
    }

    /// See `Queriable::execute`
    pub fn execute<P>(self, params: P) -> BoxFuture<QueryResult<Self, BinaryProtocol>>
    where
        P: Into<Params>,
    {
        let params = params.into();
        let fut = match params {
            Params::Positional(params) => {
                if self.inner.num_params as usize != params.len() {
                    let error =
                        ErrorKind::MismatchedStmtParams(self.inner.num_params, params.len() as u16)
                            .into();
                    return Box::new(err(error));
                }

                let fut = self.inner
                    .params
                    .as_ref()
                    .ok_or_else(|| unreachable!())
                    .and_then(|params_def| {
                        serialize_bin_many(&*params_def, &*params).map_err(Error::from)
                    })
                    .into_future()
                    .and_then(|bin_payload| match bin_payload {
                        (row_data, null_bitmap, large_bitmap) => {
                            self.send_long_data(params.into_vec(), large_bitmap.clone())
                                .and_then(|(this, params)| {
                                    let mut data = Vec::new();
                                    write_data(
                                        &mut data,
                                        this.inner.statement_id,
                                        row_data,
                                        params,
                                        this.inner.params.as_ref().unwrap(),
                                        null_bitmap,
                                    );
                                    this.write_command_data(Command::COM_STMT_EXECUTE, data)
                                })
                        }
                    });
                A(fut)
            }
            Params::Named(_) => {
                if self.inner.named_params.is_none() {
                    let error = ErrorKind::NamedParamsForPositionalQuery.into();
                    return Box::new(err(error));
                }

                let positional_params =
                    match params.into_positional(self.inner.named_params.as_ref().unwrap()) {
                        Ok(positional_params) => positional_params,
                        Err(error) => {
                            return Box::new(err(error.into()));
                        }
                    };
                return self.execute(positional_params);
            }
            Params::Empty => {
                if self.inner.num_params > 0 {
                    let error = ErrorKind::MismatchedStmtParams(self.inner.num_params, 0).into();
                    return Box::new(err(error));
                }

                let mut data = Vec::with_capacity(4 + 1 + 4);
                data.write_u32::<LE>(self.inner.statement_id).unwrap();
                data.write_u8(0u8).unwrap();
                data.write_u32::<LE>(1u32).unwrap();

                B(self.write_command_data(Command::COM_STMT_EXECUTE, data))
            }
        };
        Box::new(fut.and_then(|this| this.read_result_set(None)))
    }

    /// See `Queriable::first`
    pub fn first<P, R>(self, params: P) -> BoxFuture<(Self, Option<R>)>
    where
        P: Into<Params>,
        R: FromRow,
    {
        let fut = self.execute(params)
            .and_then(|result| result.collect_and_drop::<Row>())
            .map(|(this, mut rows)| {
                if rows.len() > 1 {
                    (this, Some(FromRow::from_row(rows.swap_remove(0))))
                } else {
                    (this, rows.pop().map(FromRow::from_row))
                }
            });
        Box::new(fut)
    }

    /// See `Queriable::batch`
    pub fn batch<I, P>(self, params_iter: I) -> BoxFuture<Self>
    where
        I: IntoIterator<Item = P> + 'static,
        Params: From<P>,
        P: 'static,
    {
        let params_iter = params_iter.into_iter().map(Params::from);
        let fut = loop_fn(
            (self, params_iter),
            |(this, mut params_iter)| match params_iter.next() {
                Some(params) => {
                    let fut = this.execute(params)
                        .and_then(|result| result.drop_result())
                        .map(|this| Loop::Continue((this, params_iter)));
                    A(fut)
                }
                None => B(ok(Loop::Break(this))),
            },
        );
        Box::new(fut)
    }

    /// This will close statement (it it's not in the cache) and resolve to a wrapped queryable.
    pub fn close(mut self) -> BoxFuture<T> {
        let cached = self.cached.take();
        let fut = match self.conn_like {
            Some(A(conn_like)) => {
                if let Some(StmtCacheResult::NotCached(stmt_id)) = cached {
                    A(conn_like.close_stmt(stmt_id))
                } else {
                    B(ok(conn_like))
                }
            }
            _ => unreachable!(),
        };
        Box::new(fut)
    }

    pub(crate) fn unwrap(mut self) -> (T, Option<StmtCacheResult>) {
        match self.conn_like {
            Some(A(conn_like)) => (conn_like, self.cached.take()),
            _ => unreachable!(),
        }
    }
}

impl<T: ConnectionLike + 'static> ConnectionLikeWrapper for Stmt<T> {
    type ConnLike = T;

    fn take_stream(self) -> (Streamless<Self>, io::Stream)
    where
        Self: Sized,
    {
        let Stmt {
            conn_like,
            inner,
            cached,
        } = self;
        match conn_like {
            Some(A(conn_like)) => {
                let (streamless, stream) = conn_like.take_stream();
                let this = Stmt {
                    conn_like: Some(B(streamless)),
                    inner,
                    cached,
                };
                (Streamless::new(this), stream)
            }
            _ => unreachable!(),
        }
    }

    fn return_stream(&mut self, stream: io::Stream) {
        let conn_like = self.conn_like.take().unwrap();
        match conn_like {
            B(streamless) => {
                self.conn_like = Some(A(streamless.return_stream(stream)));
            }
            _ => unreachable!(),
        }
    }

    fn conn_like_ref(&self) -> &Self::ConnLike {
        match self.conn_like {
            Some(A(ref conn_like)) => conn_like,
            _ => unreachable!(),
        }
    }

    fn conn_like_mut(&mut self) -> &mut Self::ConnLike {
        match self.conn_like {
            Some(A(ref mut conn_like)) => conn_like,
            _ => unreachable!(),
        }
    }
}

fn write_data(
    writer: &mut Vec<u8>,
    stmt_id: u32,
    row_data: Vec<u8>,
    params: Vec<Value>,
    params_def: &Vec<Column>,
    null_bitmap: BitVec<u8>,
) {
    let capacity = 9 + null_bitmap.storage().len() + 1 + params.len() * 2 + row_data.len();
    writer.reserve(capacity);
    writer.write_u32::<LE>(stmt_id).unwrap();
    writer.write_u8(0u8).unwrap();
    writer.write_u32::<LE>(1u32).unwrap();
    writer.write_all(null_bitmap.storage().as_ref()).unwrap();
    writer.write_u8(1u8).unwrap();
    for i in 0..params.len() {
        let result = match params[i] {
            NULL => writer.write_all(&[params_def[i].column_type() as u8, 0u8]),
            Bytes(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_VAR_STRING as u8, 0u8]),
            Int(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_LONGLONG as u8, 0u8]),
            UInt(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_LONGLONG as u8, 128u8]),
            Float(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_DOUBLE as u8, 0u8]),
            Date(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_DATETIME as u8, 0u8]),
            Time(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_TIME as u8, 0u8]),
        };
        result.unwrap();
    }
    writer.write_all(row_data.as_ref()).unwrap();
}
<commit_msg>Remove BoxFuture from src/queryable/stmt.rs<commit_after>// Copyright (c) 2017 Anatoly Ikorsky
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use bit_vec::BitVec;
use byteorder::LittleEndian as LE;
use byteorder::{ReadBytesExt, WriteBytesExt};
use connection_like::streamless::Streamless;
use connection_like::{ConnectionLike, ConnectionLikeWrapper, StmtCacheResult};
use consts::{ColumnType, Command};
use errors::*;
use io;
use lib_futures::future::Either::*;
use lib_futures::future::{err, loop_fn, ok, Either, Future, IntoFuture, Loop};
use myc::value::serialize_bin_many;
use prelude::FromRow;
use queryable::query_result::QueryResult;
use queryable::BinaryProtocol;
use std::io::Write;
use Column;
use MyFuture;
use Params;
use Row;
use Value;
use Value::*;

/// Inner statement representation.
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct InnerStmt {
    /// Positions and names of named parameters
    pub named_params: Option<Vec<String>>,
    pub params: Option<Vec<Column>>,
    pub columns: Option<Vec<Column>>,
    pub statement_id: u32,
    pub num_columns: u16,
    pub num_params: u16,
    pub warning_count: u16,
}

impl InnerStmt {
    // TODO: Consume payload?
    pub fn new(pld: &[u8], named_params: Option<Vec<String>>) -> Result<InnerStmt> {
        let mut reader = &pld[1..];
        let statement_id = reader.read_u32::<LE>()?;
        let num_columns = reader.read_u16::<LE>()?;
        let num_params = reader.read_u16::<LE>()?;
        let warning_count = reader.read_u16::<LE>()?;
        Ok(InnerStmt {
            named_params: named_params,
            statement_id: statement_id,
            num_columns: num_columns,
            num_params: num_params,
            warning_count: warning_count,
            params: None,
            columns: None,
        })
    }
}

/// Prepared statement
pub struct Stmt<T> {
    conn_like: Option<Either<T, Streamless<T>>>,
    inner: InnerStmt,
    /// None => In use elsewhere
    /// Some(Cached) => Should not be closed
    /// Some(NotCached(_)) => Should be closed
    cached: Option<StmtCacheResult>,
}

pub fn new<T>(conn_like: T, inner: InnerStmt, cached: StmtCacheResult) -> Stmt<T>
where
    T: ConnectionLike + Sized + 'static,
{
    Stmt::new(conn_like, inner, cached)
}

impl<T> Stmt<T>
where
    T: ConnectionLike + Sized + 'static,
{
    fn new(conn_like: T, inner: InnerStmt, cached: StmtCacheResult) -> Stmt<T> {
        Stmt {
            conn_like: Some(A(conn_like)),
            inner,
            cached: Some(cached),
        }
    }

    fn send_long_data_for_index(
        self,
        params: Vec<Value>,
        index: usize,
    ) -> impl MyFuture<(Self, Vec<Value>)> {
        loop_fn((self, params, index, 0), |(this, params, index, chunk)| {
            let data_cap = ::consts::MAX_PAYLOAD_LEN - 10;
            let buf = match params[index] {
                Bytes(ref x) => {
                    let statement_id = this.inner.statement_id;
                    let mut chunks = x.chunks(data_cap);
                    match chunks.nth(chunk) {
                        Some(chunk) => {
                            let mut buf = Vec::with_capacity(chunk.len() + 6);
                            buf.write_u32::<LE>(statement_id).unwrap();
                            buf.write_u16::<LE>(index as u16).unwrap();
                            buf.write_all(chunk).unwrap();
                            Some(buf)
                        }
                        _ => None,
                    }
                }
                _ => unreachable!(),
            };
            match buf {
                Some(buf) => {
                    let chunk_len = buf.len() - 6;
                    let fut = this.write_command_data(Command::COM_STMT_SEND_LONG_DATA, buf)
                        .map(move |this| {
                            if chunk_len < data_cap {
                                Loop::Break((this, params))
                            } else {
                                Loop::Continue((this, params, index, chunk + 1))
                            }
                        });
                    A(fut)
                }
                None => B(ok(Loop::Break((this, params)))),
            }
        })
    }

    fn send_long_data(
        self,
        params: Vec<Value>,
        large_bitmap: BitVec<u8>,
    ) -> impl MyFuture<(Self, Vec<Value>)> {
        let bits = large_bitmap.into_iter().enumerate();

        loop_fn(
            (self, params, bits),
            |(this, params, mut bits)| match bits.next() {
                Some((index, true)) => A(this.send_long_data_for_index(params, index)
                    .map(|(this, params)| Loop::Continue((this, params, bits)))),
                Some((_, false)) => B(ok(Loop::Continue((this, params, bits)))),
                None => B(ok(Loop::Break((this, params)))),
            },
        )
    }

    fn execute_positional<U>(self, params: U) -> impl MyFuture<QueryResult<Self, BinaryProtocol>>
    where
        U: ::std::ops::Deref<Target = [Value]>,
        U: IntoIterator<Item = Value>,
    {
        if self.inner.num_params as usize != params.len() {
            let error =
                ErrorKind::MismatchedStmtParams(self.inner.num_params, params.len() as u16).into();
            return A(err(error));
        }

        let fut = self.inner
            .params
            .as_ref()
            .ok_or_else(|| unreachable!())
            .and_then(|params_def| serialize_bin_many(&*params_def, &*params).map_err(Error::from))
            .into_future()
            .and_then(|bin_payload| match bin_payload {
                (row_data, null_bitmap, large_bitmap) => {
                    self.send_long_data(params.into_iter().collect(), large_bitmap.clone())
                        .and_then(|(this, params)| {
                            let mut data = Vec::new();
                            write_data(
                                &mut data,
                                this.inner.statement_id,
                                row_data,
                                params,
                                this.inner.params.as_ref().unwrap(),
                                null_bitmap,
                            );
                            this.write_command_data(Command::COM_STMT_EXECUTE, data)
                        })
                }
            })
            .and_then(|this| this.read_result_set(None));
        B(fut)
    }

    fn execute_named(self, params: Params) -> impl MyFuture<QueryResult<Self, BinaryProtocol>> {
        if self.inner.named_params.is_none() {
            let error = ErrorKind::NamedParamsForPositionalQuery.into();
            return A(err(error));
        }

        let positional_params =
            match params.into_positional(self.inner.named_params.as_ref().unwrap()) {
                Ok(positional_params) => positional_params,
                Err(error) => {
                    return A(err(error.into()));
                }
            };

        match positional_params {
            Params::Positional(params) => B(self.execute_positional(params)),
            _ => unreachable!(),
        }
    }

    fn execute_empty(self) -> impl MyFuture<QueryResult<Self, BinaryProtocol>> {
        if self.inner.num_params > 0 {
            let error = ErrorKind::MismatchedStmtParams(self.inner.num_params, 0).into();
            return A(err(error));
        }

        let mut data = Vec::with_capacity(4 + 1 + 4);
        data.write_u32::<LE>(self.inner.statement_id).unwrap();
        data.write_u8(0u8).unwrap();
        data.write_u32::<LE>(1u32).unwrap();

        B(self.write_command_data(Command::COM_STMT_EXECUTE, data)
            .and_then(|this| this.read_result_set(None)))
    }

    /// See `Queriable::execute`
    pub fn execute<P>(self, params: P) -> impl MyFuture<QueryResult<Self, BinaryProtocol>>
    where
        P: Into<Params>,
    {
        let params = params.into();
        match params {
            Params::Positional(params) => return A(self.execute_positional(params)),
            Params::Named(_) => return B(A(self.execute_named(params))),
            Params::Empty => return B(B(self.execute_empty())),
        }
    }

    /// See `Queriable::first`
    pub fn first<P, R>(self, params: P) -> impl MyFuture<(Self, Option<R>)>
    where
        P: Into<Params>,
        R: FromRow,
    {
        self.execute(params)
            .and_then(|result| result.collect_and_drop::<Row>())
            .map(|(this, mut rows)| {
                if rows.len() > 1 {
                    (this, Some(FromRow::from_row(rows.swap_remove(0))))
                } else {
                    (this, rows.pop().map(FromRow::from_row))
                }
            })
    }

    /// See `Queriable::batch`
    pub fn batch<I, P>(self, params_iter: I) -> impl MyFuture<Self>
    where
        I: IntoIterator<Item = P> + 'static,
        Params: From<P>,
        P: 'static,
    {
        let params_iter = params_iter.into_iter().map(Params::from);

        loop_fn(
            (self, params_iter),
            |(this, mut params_iter)| match params_iter.next() {
                Some(params) => A(this.execute(params)
                    .and_then(|result| result.drop_result())
                    .map(|this| Loop::Continue((this, params_iter)))),
                None => B(ok(Loop::Break(this))),
            },
        )
    }

    /// This will close statement (it it's not in the cache) and resolve to a wrapped queryable.
    pub fn close(mut self) -> impl MyFuture<T> {
        let cached = self.cached.take();
        match self.conn_like {
            Some(A(conn_like)) => {
                if let Some(StmtCacheResult::NotCached(stmt_id)) = cached {
                    A(conn_like.close_stmt(stmt_id))
                } else {
                    B(ok(conn_like))
                }
            }
            _ => unreachable!(),
        }
    }

    pub(crate) fn unwrap(mut self) -> (T, Option<StmtCacheResult>) {
        match self.conn_like {
            Some(A(conn_like)) => (conn_like, self.cached.take()),
            _ => unreachable!(),
        }
    }
}

impl<T: ConnectionLike + 'static> ConnectionLikeWrapper for Stmt<T> {
    type ConnLike = T;

    fn take_stream(self) -> (Streamless<Self>, io::Stream)
    where
        Self: Sized,
    {
        let Stmt {
            conn_like,
            inner,
            cached,
        } = self;
        match conn_like {
            Some(A(conn_like)) => {
                let (streamless, stream) = conn_like.take_stream();
                let this = Stmt {
                    conn_like: Some(B(streamless)),
                    inner,
                    cached,
                };
                (Streamless::new(this), stream)
            }
            _ => unreachable!(),
        }
    }

    fn return_stream(&mut self, stream: io::Stream) {
        let conn_like = self.conn_like.take().unwrap();
        match conn_like {
            B(streamless) => {
                self.conn_like = Some(A(streamless.return_stream(stream)));
            }
            _ => unreachable!(),
        }
    }

    fn conn_like_ref(&self) -> &Self::ConnLike {
        match self.conn_like {
            Some(A(ref conn_like)) => conn_like,
            _ => unreachable!(),
        }
    }

    fn conn_like_mut(&mut self) -> &mut Self::ConnLike {
        match self.conn_like {
            Some(A(ref mut conn_like)) => conn_like,
            _ => unreachable!(),
        }
    }
}

fn write_data(
    writer: &mut Vec<u8>,
    stmt_id: u32,
    row_data: Vec<u8>,
    params: Vec<Value>,
    params_def: &Vec<Column>,
    null_bitmap: BitVec<u8>,
) {
    let capacity = 9 + null_bitmap.storage().len() + 1 + params.len() * 2 + row_data.len();
    writer.reserve(capacity);
    writer.write_u32::<LE>(stmt_id).unwrap();
    writer.write_u8(0u8).unwrap();
    writer.write_u32::<LE>(1u32).unwrap();
    writer.write_all(null_bitmap.storage().as_ref()).unwrap();
    writer.write_u8(1u8).unwrap();
    for i in 0..params.len() {
        let result = match params[i] {
            NULL => writer.write_all(&[params_def[i].column_type() as u8, 0u8]),
            Bytes(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_VAR_STRING as u8, 0u8]),
            Int(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_LONGLONG as u8, 0u8]),
            UInt(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_LONGLONG as u8, 128u8]),
            Float(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_DOUBLE as u8, 0u8]),
            Date(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_DATETIME as u8, 0u8]),
            Time(..) => writer.write_all(&[ColumnType::MYSQL_TYPE_TIME as u8, 0u8]),
        };
        result.unwrap();
    }
    writer.write_all(row_data.as_ref()).unwrap();
}
<|endoftext|>


<commit_before>use std::os::raw::c_void;

use gl;
use gltf;

use image::DynamicImage::*;
use image::GenericImage;

pub struct Texture {
    pub index: usize, // glTF index
    pub name: Option<String>,

    pub id: u32, // OpenGL id

    // TODO notes
    // sampler - merge here?
    // image -> Rc
}

impl Texture {
    pub fn from_gltf(g_texture: &gltf::texture::Texture) -> Texture {

        // TODO!: share images via Rc? detect if occurs?
        let img = g_texture.source();
        let dyn_img = img.data();
        let format = match *dyn_img {
            ImageLuma8(_) => gl::RED,
            ImageLumaA8(_) => gl::RG,
            ImageRgb8(_) => gl::RGB,
            ImageRgba8(_) => gl::RGBA,
        };

        let data = dyn_img.raw_pixels();

        let mut texture_id = 0;
        unsafe {
            gl::GenTextures(1, &mut texture_id);
            gl::BindTexture(gl::TEXTURE_2D, texture_id);
            gl::TexImage2D(gl::TEXTURE_2D, 0, format as i32, dyn_img.width() as i32, dyn_img.height() as i32,
                0, format, gl::UNSIGNED_BYTE, &data[0] as *const u8 as *const c_void);

            // TODO!!!: get parameters and whether to generate mipmaps from sampler
            // Broken example: BoxTextured
            // let sampler = g_texture.sampler();
            gl::GenerateMipmap(gl::TEXTURE_2D);

            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
        }
        Texture {
            index: g_texture.index(),
            name: g_texture.name().map(|s| s.into()),
            id: texture_id,
        }
    }
}
<commit_msg>use texture sampler parameters<commit_after>use std::os::raw::c_void;

use gl;
use gltf;
use gltf::json::texture::WrappingMode::*;
use gltf::json::texture::{MinFilter, MagFilter};

use image::DynamicImage::*;
use image::GenericImage;

pub struct Texture {
    pub index: usize, // glTF index
    pub name: Option<String>,

    pub id: u32, // OpenGL id

    // TODO notes
    // sampler - merge here?
    // image -> Rc
}

impl Texture {
    pub fn from_gltf(g_texture: &gltf::texture::Texture) -> Texture {
        // TODO!: share images via Rc? detect if occurs?
        let img = g_texture.source();
        let dyn_img = img.data();
        let format = match *dyn_img {
            ImageLuma8(_) => gl::RED,
            ImageLumaA8(_) => gl::RG,
            ImageRgb8(_) => gl::RGB,
            ImageRgba8(_) => gl::RGBA,
        };

        let data = dyn_img.raw_pixels();

        let mut texture_id = 0;
        unsafe {
            gl::GenTextures(1, &mut texture_id);
            gl::BindTexture(gl::TEXTURE_2D, texture_id);
            gl::TexImage2D(gl::TEXTURE_2D, 0, format as i32, dyn_img.width() as i32, dyn_img.height() as i32,
                0, format, gl::UNSIGNED_BYTE, &data[0] as *const u8 as *const c_void);

            let sampler = g_texture.sampler()
                .unwrap(); // NOTE: tmp - see https://github.com/alteous/gltf/issues/56

            let mip_maps = match sampler.min_filter() {
                Some(MinFilter::NearestMipmapNearest) |
                Some(MinFilter::LinearMipmapNearest) |
                Some(MinFilter::NearestMipmapLinear) |
                Some(MinFilter::LinearMipmapLinear) => true,
                _ => false
            };
            if mip_maps {
                gl::GenerateMipmap(gl::TEXTURE_2D);
            }

            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, match sampler.wrap_s() {
                ClampToEdge => gl::CLAMP_TO_EDGE,
                MirroredRepeat => gl::MIRRORED_REPEAT,
                Repeat => gl::REPEAT,
            } as i32);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, match sampler.wrap_s() {
                ClampToEdge => gl::CLAMP_TO_EDGE,
                MirroredRepeat => gl::MIRRORED_REPEAT,
                Repeat => gl::REPEAT,
            } as i32);

            if let Some(min_filter) = sampler.min_filter() {
                let gl_min_filter = match min_filter {
                    MinFilter::Nearest => gl::NEAREST,
                    MinFilter::Linear => gl::LINEAR,
                    MinFilter::NearestMipmapNearest => gl::NEAREST_MIPMAP_NEAREST,
                    MinFilter::LinearMipmapNearest => gl::LINEAR_MIPMAP_NEAREST,
                    MinFilter::NearestMipmapLinear => gl::NEAREST_MIPMAP_LINEAR,
                    MinFilter::LinearMipmapLinear => gl::LINEAR_MIPMAP_LINEAR,
                };
                gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl_min_filter as i32);
            }
            if let Some(mag_filter) = sampler.mag_filter() {
                let gl_mag_filter = match mag_filter {
                    MagFilter::Nearest => gl::NEAREST,
                    MagFilter::Linear => gl::LINEAR
                };
                gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl_mag_filter as i32);
            }
        }
        Texture {
            index: g_texture.index(),
            name: g_texture.name().map(|s| s.into()),
            id: texture_id,
        }
    }
}
<|endoftext|>