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

use nalgebra::{DMat, Transpose};
use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use helpers::random01;

use ndarray::ArrayBase;
use ndarray::blas::AsBlas;

pub struct OrthogonalNMFBlas<FloatT> {
    pub hidden: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub weights: ArrayBase<Vec<FloatT>, (usize, usize)>,

    // these hold temporary results during an iteration.
    // kept in struct to prevent unnecessary memory allocations.
    // pub weights_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub weights_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub weights_divisor_reconstruction: ArrayBase<Vec<FloatT>, (usize, usize)>,
    //
    // pub hidden_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub hidden_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub hidden_divisor_tmp: ArrayBase<Vec<FloatT>, (usize, usize)>,
}

impl<FloatT> OrthogonalNMFBlas<FloatT>
    where FloatT: Float + Mul + Zero,
          Closed01<FloatT>: Rand
{
    pub fn init_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas<FloatT> {
        let mut hidden = ArrayBase::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = ArrayBase::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::init(hidden, weights)
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: ArrayBase<Vec<FloatT>, (usize, usize)>, weights: ArrayBase<Vec<FloatT>, (usize, usize)>) -> OrthogonalNMFBlas<FloatT> {
        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

//     // TODO how many iterations ?
//     // TODO compare this to the seoung solution
//     /// it gets better and better with each iteration.
//     /// one observed per column.
//     /// one sample per row.
//     pub fn iterate(&mut self, alpha: FloatT, data: &DMat<FloatT>) {
//         assert_eq!(self.nsamples(), data.shape()[0]);
//         assert_eq!(self.nobserved(), data.shape()[1]);
//
//         // has the same shape as weights
//         let new_weights_dividend = data.clone().mul(&hidden_transposed);
//         // has the same shape as weights
//         let new_weights_divisor = self.weights.clone().mul(&self.hidden).mul(&hidden_transposed);
//
//         // has the same shape as hidden
//         let new_hidden_dividend = weights_transposed.clone().mul(data);
//
//         // gamma is a symetric matrix with diagonal elements equal to zero
//         // and other elements = alpha
//         let gamma_size = self.nhidden();
//         let mut gamma = DMat::from_elem(gamma_size, gamma_size, alpha);
//
//         // set diagonal to zero
//         for i in 0..gamma_size {
//             gamma[(i, i)] = FloatT::zero();
//         }
//
//         // has the same shape as hidden
//         let new_hidden_divisor = weights_transposed.clone()
//             .mul(&self.weights)
//             .mul(&self.hidden)
//             // we add the previous latents
//             // multiplied by alpha except for the diag which is set to zero
//             .add(gamma.mul(&self.hidden));
//
//         // compute new weights
//         // TODO possibly use simd for this
//         for col in 0..self.weights.ncols() {
//             for row in 0..self.weights.nrows() {
//                 let index = (row, col);
//                 // if we have any zero in any of the matrizes
//                 // self.weights or self.hidden then
//                 // new_weights_divisor[index] will be zero
//                 // TODO how to deal with this
//                 let mut divisor = new_weights_divisor[index];
//                 if FloatT::zero() == divisor {
//                     divisor = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != divisor);
//                 self.weights[index] =
//                     self.weights[index] *
//                     new_weights_dividend[index] /
//                     divisor;
//                 if FloatT::zero() == self.weights[index] {
//                     self.weights[index] = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != self.weights[index]);
//             }
//         }
//
//         // compute new hidden
//         // TODO possibly use simd for this
//         for col in 0..self.hidden.ncols() {
//             for row in 0..self.hidden.nrows() {
//                 let index = (row, col);
//                 let mut divisor = new_hidden_divisor[index];
//                 if FloatT::zero() == divisor {
//                     divisor = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != divisor);
//                 self.hidden[index] =
//                     self.hidden[index] *
//                     new_hidden_dividend[index] /
//                     divisor;
//                 if FloatT::zero() == self.hidden[index] {
//                     self.hidden[index] = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != self.hidden[index]);
//             }
//         }
//     }
}
<commit_msg>ortho nmf blas: stub for iterate<commit_after>use std::ops::{Mul, Add};

use nalgebra::{DMat, Transpose};
use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use helpers::random01;

use ndarray::ArrayBase;
use ndarray::blas::AsBlas;

pub struct OrthogonalNMFBlas<FloatT> {
    pub hidden: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub weights: ArrayBase<Vec<FloatT>, (usize, usize)>,

    // these hold temporary results during an iteration.
    // kept in struct to prevent unnecessary memory allocations.
    // pub weights_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub weights_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub weights_divisor_reconstruction: ArrayBase<Vec<FloatT>, (usize, usize)>,
    //
    // pub hidden_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub hidden_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub hidden_divisor_tmp: ArrayBase<Vec<FloatT>, (usize, usize)>,
}

impl<FloatT> OrthogonalNMFBlas<FloatT>
    where FloatT: Float + Mul + Zero,
          Closed01<FloatT>: Rand
{
    pub fn init_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas<FloatT> {
        let mut hidden = ArrayBase::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = ArrayBase::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::init(hidden, weights)
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: ArrayBase<Vec<FloatT>, (usize, usize)>, weights: ArrayBase<Vec<FloatT>, (usize, usize)>) -> OrthogonalNMFBlas<FloatT> {
        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, alpha: FloatT, data: &ArrayBase<Vec<FloatT>, (usize, usize)>) {
        assert_eq!(self.nsamples(), data.shape()[0]);
        assert_eq!(self.nobserved(), data.shape()[1]);
//
//         // has the same shape as weights
//         let new_weights_dividend = data.clone().mul(&hidden_transposed);
//         // has the same shape as weights
//         let new_weights_divisor = self.weights.clone().mul(&self.hidden).mul(&hidden_transposed);
//
//         // has the same shape as hidden
//         let new_hidden_dividend = weights_transposed.clone().mul(data);
//
//         // gamma is a symetric matrix with diagonal elements equal to zero
//         // and other elements = alpha
//         let gamma_size = self.nhidden();
//         let mut gamma = DMat::from_elem(gamma_size, gamma_size, alpha);
//
//         // set diagonal to zero
//         for i in 0..gamma_size {
//             gamma[(i, i)] = FloatT::zero();
//         }
//
//         // has the same shape as hidden
//         let new_hidden_divisor = weights_transposed.clone()
//             .mul(&self.weights)
//             .mul(&self.hidden)
//             // we add the previous latents
//             // multiplied by alpha except for the diag which is set to zero
//             .add(gamma.mul(&self.hidden));
//
//         // compute new weights
//         // TODO possibly use simd for this
//         for col in 0..self.weights.ncols() {
//             for row in 0..self.weights.nrows() {
//                 let index = (row, col);
//                 // if we have any zero in any of the matrizes
//                 // self.weights or self.hidden then
//                 // new_weights_divisor[index] will be zero
//                 // TODO how to deal with this
//                 let mut divisor = new_weights_divisor[index];
//                 if FloatT::zero() == divisor {
//                     divisor = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != divisor);
//                 self.weights[index] =
//                     self.weights[index] *
//                     new_weights_dividend[index] /
//                     divisor;
//                 if FloatT::zero() == self.weights[index] {
//                     self.weights[index] = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != self.weights[index]);
//             }
//         }
//
//         // compute new hidden
//         // TODO possibly use simd for this
//         for col in 0..self.hidden.ncols() {
//             for row in 0..self.hidden.nrows() {
//                 let index = (row, col);
//                 let mut divisor = new_hidden_divisor[index];
//                 if FloatT::zero() == divisor {
//                     divisor = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != divisor);
//                 self.hidden[index] =
//                     self.hidden[index] *
//                     new_hidden_dividend[index] /
//                     divisor;
//                 if FloatT::zero() == self.hidden[index] {
//                     self.hidden[index] = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != self.hidden[index]);
//             }
//         }
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // M[A] <- M[B] x M[C]
            9 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b * c;
                self.counter += 4;
            },

            // M[A] <- M[B] / M[C]
            10 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b / c;
                self.counter += 4;
            },

            // M[A] <- M[B] modulo M[C]
            11 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b % c;
                self.counter += 4;
            },

            // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
            12 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                if b < c {
                  self.memory[a as usize] = 1;
                } else {
                  self.memory[a as usize] = 0;
                }
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

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

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_then_branch() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else_branch() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(4, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(5, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(6, 1, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(7, 0, 1, 2);
        assert_eq!(Some(&5), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        let mut m = Machine::with_data(vec![0, 3, 2]);

        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(8, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_9() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(9, 0, 1, 2);
        assert_eq!(Some(&6), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_10() {
        let mut m = Machine::with_data(vec![1, 6, 2]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(10, 0, 1, 2);
        assert_eq!(Some(&3), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_11() {
        let mut m = Machine::with_data(vec![1, 11, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(11, 0, 1, 2);
        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_then_branch() {
        let mut m = Machine::with_data(vec![2, 3, 4]);

        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(12, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_else_branch() {
        let mut m = Machine::with_data(vec![2, 4, 3]);

        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(12, 0, 1, 2);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<commit_msg>Replace exec with step for opcode 1.<commit_after>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn step(&mut self) {
        let counter = self.counter as usize;
        let opcode = self.memory[counter];
        let a = self.memory[counter + 1];
        let b = self.memory[counter + 2];
        let c = self.memory[counter + 3];
        self.exec(opcode, a, b, c);
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // M[A] <- M[B] x M[C]
            9 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b * c;
                self.counter += 4;
            },

            // M[A] <- M[B] / M[C]
            10 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b / c;
                self.counter += 4;
            },

            // M[A] <- M[B] modulo M[C]
            11 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b % c;
                self.counter += 4;
            },

            // If M[B] < M[C], then M[A] <- 1, else M[A] <- 0
            12 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                if b < c {
                  self.memory[a as usize] = 1;
                } else {
                  self.memory[a as usize] = 0;
                }
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

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

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        // PC <- M[A]
        let mut m = Machine::with_data(vec![1, 3, 0, 2]);

        assert_eq!(0, m.loc());
        m.step();
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_then_branch() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else_branch() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(4, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(5, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(6, 1, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(7, 0, 1, 2);
        assert_eq!(Some(&5), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        let mut m = Machine::with_data(vec![0, 3, 2]);

        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(8, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_9() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(9, 0, 1, 2);
        assert_eq!(Some(&6), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_10() {
        let mut m = Machine::with_data(vec![1, 6, 2]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(10, 0, 1, 2);
        assert_eq!(Some(&3), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_11() {
        let mut m = Machine::with_data(vec![1, 11, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(11, 0, 1, 2);
        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_then_branch() {
        let mut m = Machine::with_data(vec![2, 3, 4]);

        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(12, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_12_else_branch() {
        let mut m = Machine::with_data(vec![2, 4, 3]);

        assert_eq!(Some(&2), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(12, 0, 1, 2);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc_front::hir::*;
use rustc::middle::ty;
use syntax::ast::Lit_::LitBool;

use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block};

declare_lint!(pub SINGLE_MATCH, Warn,
              "a match statement with a single nontrivial arm (i.e, where the other arm \
               is `_ => {}`) is used; recommends `if let` instead");
declare_lint!(pub MATCH_REF_PATS, Warn,
              "a match has all arms prefixed with `&`; the match expression can be \
               dereferenced instead");
declare_lint!(pub MATCH_BOOL, Warn,
              "a match on boolean expression; recommends `if..else` block instead");

#[allow(missing_copy_implementations)]
pub struct MatchPass;

impl LintPass for MatchPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL)
    }
}

impl LateLintPass for MatchPass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) { return; }
        if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node {
            // check preconditions for SINGLE_MATCH
                // only two arms
            if arms.len() == 2 &&
                // both of the arms have a single pattern and no guard
                arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
                arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
                // and the second pattern is a `_` wildcard: this is not strictly necessary,
                // since the exhaustiveness check will ensure the last one is a catch-all,
                // but in some cases, an explicit match is preferred to catch situations
                // when an enum is extended, so we don't consider these cases
                arms[1].pats[0].node == PatWild &&
                // we don't want any content in the second arm (unit or empty block)
                is_unit_expr(&arms[1].body) &&
                // finally, MATCH_BOOL doesn't apply here
                (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow)
            {
                span_help_and_lint(cx, SINGLE_MATCH, expr.span,
                                   "you seem to be trying to use match for destructuring a \
                                    single pattern. Consider using `if let`",
                                   &format!("try\nif let {} = {} {}",
                                            snippet(cx, arms[0].pats[0].span, ".."),
                                            snippet(cx, ex.span, ".."),
                                            expr_block(cx, &arms[0].body, None, "..")));
            }

            // check preconditions for MATCH_BOOL
            // type of expression == bool
            if cx.tcx.expr_ty(ex).sty == ty::TyBool {
                if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards
                    let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node {
                        if let ExprLit(ref lit) = arm_bool.node {
                            if let LitBool(val) = lit.node {
                                if val {
                                    Some((&*arms[0].body, &*arms[1].body))
                                } else {
                                    Some((&*arms[1].body, &*arms[0].body))
                                }
                            } else { None }
                        } else { None }
                    } else { None };
                    if let Some((ref true_expr, ref false_expr)) = exprs {
                        if !is_unit_expr(true_expr) {
                            if !is_unit_expr(false_expr) {
                                span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                    "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block:",
                                   &format!("try\nif {} {} else {}",
                                        snippet(cx, ex.span, "b"),
                                        expr_block(cx, true_expr, None, ".."),
                                        expr_block(cx, false_expr, None, "..")));
                            } else {
                                span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                    "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block:",
                                   &format!("try\nif {} {}",
                                        snippet(cx, ex.span, "b"),
                                        expr_block(cx, true_expr, None, "..")));
                            }
                        } else if !is_unit_expr(false_expr) {
                            span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                "you seem to be trying to match on a boolean expression. \
                               Consider using an if..else block:",
                               &format!("try\nif !{} {}",
                                    snippet(cx, ex.span, "b"),
                                    expr_block(cx, false_expr, None, "..")));
                        } else {
                            span_lint(cx, MATCH_BOOL, expr.span,
                                   "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block");
                        }
                    } else {
                        span_lint(cx, MATCH_BOOL, expr.span,
                            "you seem to be trying to match on a boolean expression. \
                            Consider using an if..else block");
                    }
                } else {
                    span_lint(cx, MATCH_BOOL, expr.span,
                        "you seem to be trying to match on a boolean expression. \
                        Consider using an if..else block");
                }
            }
        }
        if let ExprMatch(ref ex, ref arms, source) = expr.node {
            // check preconditions for MATCH_REF_PATS
            if has_only_ref_pats(arms) {
                if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node {
                    let template = match_template(source, "", &snippet(cx, inner.span, ".."));
                    span_lint(cx, MATCH_REF_PATS, expr.span, &format!(
                        "you don't need to add `&` to both the expression \
                         and the patterns: use `{}`", template));
                } else {
                    let template = match_template(source, "*", &snippet(cx, ex.span, ".."));
                    span_lint(cx, MATCH_REF_PATS, expr.span, &format!(
                        "instead of prefixing all patterns with `&`, you can dereference the \
                         expression: `{}`", template));
                }
            }
        }
    }
}

fn is_unit_expr(expr: &Expr) -> bool {
    match expr.node {
        ExprTup(ref v) if v.is_empty() => true,
        ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true,
        _ => false,
    }
}

fn has_only_ref_pats(arms: &[Arm]) -> bool {
    let mapped = arms.iter().flat_map(|a| &a.pats).map(|p| match p.node {
        PatRegion(..) => Some(true),  // &-patterns
        PatWild(..) => Some(false),   // an "anything" wildcard is also fine
        _ => None,                    // any other pattern is not fine
    }).collect::<Option<Vec<bool>>>();
    // look for Some(v) where there's at least one true element
    mapped.map_or(false, |v| v.iter().any(|el| *el))
}

fn match_template(source: MatchSource, op: &str, expr: &str) -> String {
    match source {
        MatchSource::Normal => {
            format!("match {}{} {{ ...", op, expr)
        }
        MatchSource::IfLetDesugar { .. } => {
            format!("if let ... = {}{} {{", op, expr)
        }
        MatchSource::WhileLetDesugar => {
            format!("while let ... = {}{} {{", op, expr)
        }
        MatchSource::ForLoopDesugar => {
            panic!("for loop desugared to match with &-patterns!")
        }
    }
}
<commit_msg>Don't panic<commit_after>use rustc::lint::*;
use rustc_front::hir::*;
use rustc::middle::ty;
use syntax::ast::Lit_::LitBool;
use syntax::codemap::Span;

use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block};

declare_lint!(pub SINGLE_MATCH, Warn,
              "a match statement with a single nontrivial arm (i.e, where the other arm \
               is `_ => {}`) is used; recommends `if let` instead");
declare_lint!(pub MATCH_REF_PATS, Warn,
              "a match has all arms prefixed with `&`; the match expression can be \
               dereferenced instead");
declare_lint!(pub MATCH_BOOL, Warn,
              "a match on boolean expression; recommends `if..else` block instead");

#[allow(missing_copy_implementations)]
pub struct MatchPass;

impl LintPass for MatchPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL)
    }
}

impl LateLintPass for MatchPass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) { return; }
        if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node {
            // check preconditions for SINGLE_MATCH
                // only two arms
            if arms.len() == 2 &&
                // both of the arms have a single pattern and no guard
                arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
                arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
                // and the second pattern is a `_` wildcard: this is not strictly necessary,
                // since the exhaustiveness check will ensure the last one is a catch-all,
                // but in some cases, an explicit match is preferred to catch situations
                // when an enum is extended, so we don't consider these cases
                arms[1].pats[0].node == PatWild &&
                // we don't want any content in the second arm (unit or empty block)
                is_unit_expr(&arms[1].body) &&
                // finally, MATCH_BOOL doesn't apply here
                (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow)
            {
                span_help_and_lint(cx, SINGLE_MATCH, expr.span,
                                   "you seem to be trying to use match for destructuring a \
                                    single pattern. Consider using `if let`",
                                   &format!("try\nif let {} = {} {}",
                                            snippet(cx, arms[0].pats[0].span, ".."),
                                            snippet(cx, ex.span, ".."),
                                            expr_block(cx, &arms[0].body, None, "..")));
            }

            // check preconditions for MATCH_BOOL
            // type of expression == bool
            if cx.tcx.expr_ty(ex).sty == ty::TyBool {
                if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards
                    let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node {
                        if let ExprLit(ref lit) = arm_bool.node {
                            if let LitBool(val) = lit.node {
                                if val {
                                    Some((&*arms[0].body, &*arms[1].body))
                                } else {
                                    Some((&*arms[1].body, &*arms[0].body))
                                }
                            } else { None }
                        } else { None }
                    } else { None };
                    if let Some((ref true_expr, ref false_expr)) = exprs {
                        if !is_unit_expr(true_expr) {
                            if !is_unit_expr(false_expr) {
                                span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                    "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block:",
                                   &format!("try\nif {} {} else {}",
                                        snippet(cx, ex.span, "b"),
                                        expr_block(cx, true_expr, None, ".."),
                                        expr_block(cx, false_expr, None, "..")));
                            } else {
                                span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                    "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block:",
                                   &format!("try\nif {} {}",
                                        snippet(cx, ex.span, "b"),
                                        expr_block(cx, true_expr, None, "..")));
                            }
                        } else if !is_unit_expr(false_expr) {
                            span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                "you seem to be trying to match on a boolean expression. \
                               Consider using an if..else block:",
                               &format!("try\nif !{} {}",
                                    snippet(cx, ex.span, "b"),
                                    expr_block(cx, false_expr, None, "..")));
                        } else {
                            span_lint(cx, MATCH_BOOL, expr.span,
                                   "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block");
                        }
                    } else {
                        span_lint(cx, MATCH_BOOL, expr.span,
                            "you seem to be trying to match on a boolean expression. \
                            Consider using an if..else block");
                    }
                } else {
                    span_lint(cx, MATCH_BOOL, expr.span,
                        "you seem to be trying to match on a boolean expression. \
                        Consider using an if..else block");
                }
            }
        }
        if let ExprMatch(ref ex, ref arms, source) = expr.node {
            // check preconditions for MATCH_REF_PATS
            if has_only_ref_pats(arms) {
                if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node {
                    let template = match_template(cx, expr.span, source, "", inner);
                    span_lint(cx, MATCH_REF_PATS, expr.span, &format!(
                        "you don't need to add `&` to both the expression \
                         and the patterns: use `{}`", template));
                } else {
                    let template = match_template(cx, expr.span, source, "*", ex);
                    span_lint(cx, MATCH_REF_PATS, expr.span, &format!(
                        "instead of prefixing all patterns with `&`, you can dereference the \
                         expression: `{}`", template));
                }
            }
        }
    }
}

fn is_unit_expr(expr: &Expr) -> bool {
    match expr.node {
        ExprTup(ref v) if v.is_empty() => true,
        ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true,
        _ => false,
    }
}

fn has_only_ref_pats(arms: &[Arm]) -> bool {
    let mapped = arms.iter().flat_map(|a| &a.pats).map(|p| match p.node {
        PatRegion(..) => Some(true),  // &-patterns
        PatWild(..) => Some(false),   // an "anything" wildcard is also fine
        _ => None,                    // any other pattern is not fine
    }).collect::<Option<Vec<bool>>>();
    // look for Some(v) where there's at least one true element
    mapped.map_or(false, |v| v.iter().any(|el| *el))
}

fn match_template(cx: &LateContext,
                  span: Span,
                  source: MatchSource,
                  op: &str,
                  expr: &Expr) -> String {
    let expr_snippet = snippet(cx, expr.span, "..");
    match source {
        MatchSource::Normal => {
            format!("match {}{} {{ ...", op, expr_snippet)
        }
        MatchSource::IfLetDesugar { .. } => {
            format!("if let ... = {}{} {{", op, expr_snippet)
        }
        MatchSource::WhileLetDesugar => {
            format!("while let ... = {}{} {{", op, expr_snippet)
        }
        MatchSource::ForLoopDesugar => {
            cx.sess().span_bug(span, "for loop desugared to match with &-patterns!")
        }
    }
}
<|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 log::{error, warn};

use crate::args::Args;

// TODO: Unexpose this function, make it possible to only send the high-level
// types (`Item`, `Status`).
pub fn send_raw(message: rrg_proto::jobs::GrrMessage) {
        let data = protobuf::Message::write_to_bytes(&message)
            // Encoding can fail only if the buffer is insufficiently large. But
            // since we use growable vector this should never happen (provided
            // that we have enough memory).
            .expect("message encoding failure");

        let message = fleetspeak::Message {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data,
        };

        if let Err(error) = fleetspeak::send(message) {
            // If we failed to deliver the message through Fleetspeak, it means
            // that our communication is broken (e.g. the pipe was closed) and
            // the agent should be killed.
            panic!("message delivery failure: {}", error)
        };
}

// TODO: Unexpose this function, make it possible to only receive the high-level
// type (`Request`).
pub fn receive_raw(heartbeat_rate: std::time::Duration) -> Option<rrg_proto::jobs::GrrMessage> {
    use fleetspeak::ReadError::*;

    let message = match fleetspeak::receive_with_heartbeat(heartbeat_rate) {
        Ok(message) => message,
        Err(Malformed(error)) => {
            error!("received a malformed message: {}", error);
            return None;
        }
        Err(Decode(error)) => {
            error!("failed to decode a message: {}", error);
            return None;
        }
        Err(error) => {
            // If we failed to collect the message because of I/O error or magic
            // check, it means that our communication is broken (e.g. the pipe
            // was closed) and the agent should be killed.
            panic!("failed to collect a message: {}", error)
        }
    };

    if message.service != "GRR" {
        warn!("message send by '{}' service (instead of GRR)", message.service);
    }

    match message.kind {
        Some(ref kind) if kind != "GrrMessage" => {
            warn!("message with unrecognized type '{}'", kind);
        }
        Some(_) => (),
        None => {
            warn!("message with missing type specification");
        }
    }

    match protobuf::Message::parse_from_bytes(&message.data[..]) {
        Ok(message) => Some(message),
        Err(error) => {
            error!("failed to decode the data: {}", error);
            None
        }
    }
}
<commit_msg>Remove an unused import.<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 log::{error, warn};

// TODO: Unexpose this function, make it possible to only send the high-level
// types (`Item`, `Status`).
pub fn send_raw(message: rrg_proto::jobs::GrrMessage) {
        let data = protobuf::Message::write_to_bytes(&message)
            // Encoding can fail only if the buffer is insufficiently large. But
            // since we use growable vector this should never happen (provided
            // that we have enough memory).
            .expect("message encoding failure");

        let message = fleetspeak::Message {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data,
        };

        if let Err(error) = fleetspeak::send(message) {
            // If we failed to deliver the message through Fleetspeak, it means
            // that our communication is broken (e.g. the pipe was closed) and
            // the agent should be killed.
            panic!("message delivery failure: {}", error)
        };
}

// TODO: Unexpose this function, make it possible to only receive the high-level
// type (`Request`).
pub fn receive_raw(heartbeat_rate: std::time::Duration) -> Option<rrg_proto::jobs::GrrMessage> {
    use fleetspeak::ReadError::*;

    let message = match fleetspeak::receive_with_heartbeat(heartbeat_rate) {
        Ok(message) => message,
        Err(Malformed(error)) => {
            error!("received a malformed message: {}", error);
            return None;
        }
        Err(Decode(error)) => {
            error!("failed to decode a message: {}", error);
            return None;
        }
        Err(error) => {
            // If we failed to collect the message because of I/O error or magic
            // check, it means that our communication is broken (e.g. the pipe
            // was closed) and the agent should be killed.
            panic!("failed to collect a message: {}", error)
        }
    };

    if message.service != "GRR" {
        warn!("message send by '{}' service (instead of GRR)", message.service);
    }

    match message.kind {
        Some(ref kind) if kind != "GrrMessage" => {
            warn!("message with unrecognized type '{}'", kind);
        }
        Some(_) => (),
        None => {
            warn!("message with missing type specification");
        }
    }

    match protobuf::Message::parse_from_bytes(&message.data[..]) {
        Ok(message) => Some(message),
        Err(error) => {
            error!("failed to decode the data: {}", error);
            None
        }
    }
}
<|endoftext|>


<commit_before>/// Modifiers which can be injected by the application logic to change the state

use std::any::Any;
use ::api;
use ::api::optional::Optional;

/// `StatusModifier`s are used to modify the status
pub trait StatusModifier: Send + Sync {
    /// Called after all registered sensors are read
    fn modify(&self, status: &mut api::Status);
}

pub struct StateFromPeopleNowPresent;

impl StatusModifier for StateFromPeopleNowPresent {
    fn modify(&self, status: &mut api::Status) {
        // Update state depending on number of people present
        let people_now_present: Option<u64> = status.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .map(|people_now_present| people_now_present[0].value)
            .into();
        if let Some(count) = people_now_present {
            status.state.open = Some(count > 0);
            if count == 1 {
                status.state.message = Optional::Value(format!("{} person here right now", count));
            } else if count > 1 {
                status.state.message = Optional::Value(format!("{} people here right now", count));
            }
        }
    }
}

<commit_msg>Remove unused Any import<commit_after>/// Modifiers which can be injected by the application logic to change the state

use ::api;
use ::api::optional::Optional;

/// `StatusModifier`s are used to modify the status
pub trait StatusModifier: Send + Sync {
    /// Called after all registered sensors are read
    fn modify(&self, status: &mut api::Status);
}

pub struct StateFromPeopleNowPresent;

impl StatusModifier for StateFromPeopleNowPresent {
    fn modify(&self, status: &mut api::Status) {
        // Update state depending on number of people present
        let people_now_present: Option<u64> = status.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .map(|people_now_present| people_now_present[0].value)
            .into();
        if let Some(count) = people_now_present {
            status.state.open = Some(count > 0);
            if count == 1 {
                status.state.message = Optional::Value(format!("{} person here right now", count));
            } else if count > 1 {
                status.state.message = Optional::Value(format!("{} people here right now", count));
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::str::FromStr;
use std::any::Any;

macro_rules! blanket_impl {
  ($trait_: ident for $($type_: ty),*) => {
    $(
      impl $trait_ for $type_ {}
    )*
  };
}

macro_rules! impl_graphql_type_for {
    ($tt: ty where name = $name: expr, description = $desc: expr) => {
        impl GraphQLType for $tt {
            fn name(&self) -> &str { $name }
            fn description(&self) -> Option<&str> { Some($desc) }
        }
    };

    ($($type_: ty),*) => {
      $(
        impl GraphQLType for $type_ {
            fn name(&self) -> &str { self.name.as_ref() }

            fn description(&self) -> Option<&str> {
                self.description.as_ref().map(|s| s.as_ref())
            }
        }
      )*
    };
}

pub trait GraphQLType {
  fn name(&self) -> &str;
  fn description(&self) -> Option<&str>;
}
impl_graphql_type_for! { GraphQLEnum }

pub trait GraphQLScalar: GraphQLType {
  type ValueType: Any;
  fn coerce_literal(&self, value: &str) -> Option<Self::ValueType>;
}

pub struct GraphQLInt;
impl_graphql_type_for! {
    GraphQLInt where
    name = "Int",
    description = "The Int scalar type represents a signed 32‐bit numeric non‐fractional values."
}

impl GraphQLScalar for GraphQLInt {
  type ValueType = i32;
  fn coerce_literal(&self, value: &str) -> Option<Self::ValueType> {
    i32::from_str(value).ok()
  }
}

pub struct GraphQLFloat;
impl_graphql_type_for! {
    GraphQLFloat where
    name = "Float",
    description = "The Float scalar type represents signed double-precision fractional values as specified by IEEE 754."
}

impl GraphQLScalar for GraphQLFloat {
  type ValueType = f64;
  fn coerce_literal(&self, value: &str) -> Option<Self::ValueType> {
    f64::from_str(value).ok()
  }
}

pub struct GraphQLString;
impl_graphql_type_for! {
    GraphQLString where
    name = "String",
    description = "The String scalar type represents textual data, represented as UTF-8 character sequences."
}

impl GraphQLScalar for GraphQLString {
  type ValueType = String;
  fn coerce_literal(&self, value: &str) -> Option<Self::ValueType> {
    String::from_str(value).ok()
  }
}

pub struct GraphQLBoolean;
impl_graphql_type_for! {
    GraphQLBoolean where
    name = "Boolean",
    description = "The Boolean scalar type represents true or false."
}

impl GraphQLScalar for GraphQLBoolean {
  type ValueType = bool;
  fn coerce_literal(&self, value: &str) -> Option<Self::ValueType> {
    bool::from_str(value).ok()
  }
}

pub struct GraphQLEnum {
  name: String,
  description: Option<String>,
  values: HashMap<String, GraphQLEnumValue>,
}

impl GraphQLEnum {
  fn values(&self) -> &HashMap<String, GraphQLEnumValue> {
    &self.values
  }
}

pub struct GraphQLEnumValue {
  value: String,
  description: Option<String>,
  depreciation_reason: Option<String>,
}

impl GraphQLEnumValue {
  pub fn new(value: &str) -> GraphQLEnumValue {
    GraphQLEnumValue {
      value: value.to_owned(),
      description: None,
      depreciation_reason: None,
    }
  }

  pub fn value(&self) -> &str {
    self.value.as_ref()
  }

  pub fn description(&self) -> Option<&str> {
    self.description.as_ref().map(|s| s.as_ref())
  }

  pub fn with_description(mut self, description: &str) -> GraphQLEnumValue {
    self.description = Some(description.to_owned());
    self
  }

  pub fn mark_depreciated(mut self, depreciation_reason: &str) -> GraphQLEnumValue {
    let reason = depreciation_reason.trim().to_owned();
    if reason.len() == 0 {
      panic!("Deprecation reason for enum value {:?} cannot be empty",
             self.value);
    }
    self.depreciation_reason = Some(reason);
    self
  }
}

pub struct GraphQLEnumBuilder {
  name: String,
  description: Option<String>,
  values: HashMap<String, GraphQLEnumValue>,
}

impl GraphQLEnumBuilder {
  fn new(name: &str) -> GraphQLEnumBuilder {
    GraphQLEnumBuilder {
      name: name.to_owned(),
      description: None,
      values: HashMap::new(),
    }
  }

  fn with_description(mut self, description: &str) -> GraphQLEnumBuilder {
    self.description = Some(description.to_owned());
    self
  }

  fn value_fn<F>(mut self, name: &str, f: F) -> GraphQLEnumBuilder
    where F: FnOnce(GraphQLEnumValue) -> GraphQLEnumValue
  {
    let v = f(GraphQLEnumValue::new(name));
    self.values.insert(v.value.clone(), v);
    self
  }

  fn value(mut self, name: &str) -> GraphQLEnumBuilder {
    self.values.insert(name.to_owned(), GraphQLEnumValue::new(name));
    self
  }

  fn build(self) -> GraphQLEnum {
    if self.values.len() == 0 {
      panic!("Enum {:?} must has at least one value defined.", self.name);
    }

    GraphQLEnum {
      name: self.name,
      description: self.description,
      values: self.values,
    }
  }
}

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

  #[test]
  fn test_scalar_type() {
    let int_t = GraphQLInt;
    assert_eq!("Int", int_t.name());
    assert_eq!(Some(10), int_t.coerce_literal("10"));
    assert_eq!(None, int_t.coerce_literal("10.1"));
    assert_eq!(None, int_t.coerce_literal("a"));
    assert_eq!(None, int_t.coerce_literal(&i64::max_value().to_string()));
    assert_eq!(None, int_t.coerce_literal(&i64::min_value().to_string()));

    let float_t = GraphQLFloat;
    assert_eq!("Float", float_t.name());
    assert_eq!(Some(2.0), float_t.coerce_literal("2.0"));
    assert_eq!(Some(2.0), float_t.coerce_literal("2"));
    assert_eq!(None, float_t.coerce_literal("2.0a"));

    let string_t = GraphQLString;
    assert_eq!("String", string_t.name());
    assert_eq!(Some(String::from("abc")), string_t.coerce_literal("abc"));
    assert_eq!(Some(String::from("2.0")), string_t.coerce_literal("2.0"));

    let boolean_t = GraphQLBoolean;
    assert_eq!("Boolean", boolean_t.name());
    assert_eq!(Some(true), boolean_t.coerce_literal("true"));
    assert_eq!(Some(false), boolean_t.coerce_literal("false"));
    assert_eq!(None, boolean_t.coerce_literal("1"));
    assert_eq!(None, boolean_t.coerce_literal("0"));
    assert_eq!(None, boolean_t.coerce_literal("True"));
    assert_eq!(None, boolean_t.coerce_literal("False"));
    assert_eq!(None, boolean_t.coerce_literal("TRUE"));
    assert_eq!(None, boolean_t.coerce_literal("FALSE"));
  }

  #[test]
  fn test_enum_type() {
    let rgb = GraphQLEnumBuilder::new("RGB")
                .value("RED")
                .value("GREEN")
                .value("BLUE")
                .build();
    assert_eq!(3, rgb.values().len());

    let days = GraphQLEnumBuilder::new("DAYS")
                 .with_description("Days of the week")
                 .value_fn("SAT", |v| v.with_description("Satarday"))
                 .value_fn("SUN", |v| v.with_description("Sunday"))
                 .value_fn("MON", |v| v.with_description("Monday"))
                 .value_fn("TUE", |v| v.with_description("Tuesday"))
                 .value_fn("WED", |v| v.with_description("Wedsday"))
                 .value_fn("THU", |v| v.with_description("Thusday"))
                 .value_fn("FRI", |v| v.with_description("Friday"))
                 .build();
    assert_eq!("Days of the week", days.description().unwrap_or(""));
    assert_eq!("Monday", days.values()["MON"].description().unwrap_or(""));;
  }
}
<commit_msg>add marco impl_scalar_type_for<commit_after>use std::collections::HashMap;
use std::str::FromStr;
use std::any::Any;

macro_rules! blanket_impl {
  ($trait_: ident for $($type_: ty),*) => {
    $(
      impl $trait_ for $type_ {}
    )*
  };
}

macro_rules! impl_graphql_type_for {
    ($tt: ty where name = $name: expr, description = $desc: expr) => {
        impl GraphQLType for $tt {
            fn name(&self) -> &str { $name }
            fn description(&self) -> Option<&str> { Some($desc) }
        }
    };

    ($($type_: ty),*) => {
      $(
        impl GraphQLType for $type_ {
            fn name(&self) -> &str { self.name.as_ref() }

            fn description(&self) -> Option<&str> {
                self.description.as_ref().map(|s| s.as_ref())
            }
        }
      )*
    };
}

macro_rules! impl_scalar_type_for {
    ($tt: ty as $value_type: ident where name = $name: expr, description = $desc: expr) => {
      impl_graphql_type_for! { $tt where name = $name, description = $desc }

      impl GraphQLScalar for $tt {
        type ValueType = $value_type;
        fn coerce_literal(&self, value: &str) -> Option<Self::ValueType> {
          $value_type::from_str(value).ok()
        }
      }
    };
}

pub trait GraphQLType {
  fn name(&self) -> &str;
  fn description(&self) -> Option<&str>;
}
impl_graphql_type_for! { GraphQLEnum }

pub trait GraphQLScalar: GraphQLType {
  type ValueType: Any;
  fn coerce_literal(&self, value: &str) -> Option<Self::ValueType>;
}

pub struct GraphQLInt;
impl_scalar_type_for! { GraphQLInt as i32 where
  name = "Int",
  description = "The Int scalar type represents a signed 32‐bit numeric non‐fractional values."
}

pub struct GraphQLFloat;
impl_scalar_type_for! { GraphQLFloat as f64 where
  name = "Float",
  description = "The Float scalar type represents signed double-precision fractional values as specified by IEEE 754."
}

pub struct GraphQLString;
impl_scalar_type_for! { GraphQLString as String where
  name = "String",
  description = "The String scalar type represents textual data, represented as UTF-8 character sequences."
}

pub struct GraphQLBoolean;
impl_scalar_type_for! { GraphQLBoolean as bool where
  name = "Boolean",
  description = "The Boolean scalar type represents true or false."
}

pub struct GraphQLEnum {
  name: String,
  description: Option<String>,
  values: HashMap<String, GraphQLEnumValue>,
}

impl GraphQLEnum {
  fn values(&self) -> &HashMap<String, GraphQLEnumValue> {
    &self.values
  }
}

pub struct GraphQLEnumValue {
  value: String,
  description: Option<String>,
  depreciation_reason: Option<String>,
}

impl GraphQLEnumValue {
  pub fn new(value: &str) -> GraphQLEnumValue {
    GraphQLEnumValue {
      value: value.to_owned(),
      description: None,
      depreciation_reason: None,
    }
  }

  pub fn value(&self) -> &str {
    self.value.as_ref()
  }

  pub fn description(&self) -> Option<&str> {
    self.description.as_ref().map(|s| s.as_ref())
  }

  pub fn with_description(mut self, description: &str) -> GraphQLEnumValue {
    self.description = Some(description.to_owned());
    self
  }

  pub fn mark_depreciated(mut self, depreciation_reason: &str) -> GraphQLEnumValue {
    let reason = depreciation_reason.trim().to_owned();
    if reason.len() == 0 {
      panic!("Deprecation reason for enum value {:?} cannot be empty",
             self.value);
    }
    self.depreciation_reason = Some(reason);
    self
  }
}

pub struct GraphQLEnumBuilder {
  name: String,
  description: Option<String>,
  values: HashMap<String, GraphQLEnumValue>,
}

impl GraphQLEnumBuilder {
  fn new(name: &str) -> GraphQLEnumBuilder {
    GraphQLEnumBuilder {
      name: name.to_owned(),
      description: None,
      values: HashMap::new(),
    }
  }

  fn with_description(mut self, description: &str) -> GraphQLEnumBuilder {
    self.description = Some(description.to_owned());
    self
  }

  fn value_fn<F>(mut self, name: &str, f: F) -> GraphQLEnumBuilder
    where F: FnOnce(GraphQLEnumValue) -> GraphQLEnumValue
  {
    let v = f(GraphQLEnumValue::new(name));
    self.values.insert(v.value.clone(), v);
    self
  }

  fn value(mut self, name: &str) -> GraphQLEnumBuilder {
    self.values.insert(name.to_owned(), GraphQLEnumValue::new(name));
    self
  }

  fn build(self) -> GraphQLEnum {
    if self.values.len() == 0 {
      panic!("Enum {:?} must has at least one value defined.", self.name);
    }

    GraphQLEnum {
      name: self.name,
      description: self.description,
      values: self.values,
    }
  }
}

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

  #[test]
  fn test_scalar_type() {
    let int_t = GraphQLInt;
    assert_eq!("Int", int_t.name());
    assert_eq!(Some(10), int_t.coerce_literal("10"));
    assert_eq!(None, int_t.coerce_literal("10.1"));
    assert_eq!(None, int_t.coerce_literal("a"));
    assert_eq!(None, int_t.coerce_literal(&i64::max_value().to_string()));
    assert_eq!(None, int_t.coerce_literal(&i64::min_value().to_string()));

    let float_t = GraphQLFloat;
    assert_eq!("Float", float_t.name());
    assert_eq!(Some(2.0), float_t.coerce_literal("2.0"));
    assert_eq!(Some(2.0), float_t.coerce_literal("2"));
    assert_eq!(None, float_t.coerce_literal("2.0a"));

    let string_t = GraphQLString;
    assert_eq!("String", string_t.name());
    assert_eq!(Some(String::from("abc")), string_t.coerce_literal("abc"));
    assert_eq!(Some(String::from("2.0")), string_t.coerce_literal("2.0"));

    let boolean_t = GraphQLBoolean;
    assert_eq!("Boolean", boolean_t.name());
    assert_eq!(Some(true), boolean_t.coerce_literal("true"));
    assert_eq!(Some(false), boolean_t.coerce_literal("false"));
    assert_eq!(None, boolean_t.coerce_literal("1"));
    assert_eq!(None, boolean_t.coerce_literal("0"));
    assert_eq!(None, boolean_t.coerce_literal("True"));
    assert_eq!(None, boolean_t.coerce_literal("False"));
    assert_eq!(None, boolean_t.coerce_literal("TRUE"));
    assert_eq!(None, boolean_t.coerce_literal("FALSE"));
  }

  #[test]
  fn test_enum_type() {
    let rgb = GraphQLEnumBuilder::new("RGB")
                .value("RED")
                .value("GREEN")
                .value("BLUE")
                .build();
    assert_eq!(3, rgb.values().len());

    let days = GraphQLEnumBuilder::new("DAYS")
                 .with_description("Days of the week")
                 .value_fn("SAT", |v| v.with_description("Satarday"))
                 .value_fn("SUN", |v| v.with_description("Sunday"))
                 .value_fn("MON", |v| v.with_description("Monday"))
                 .value_fn("TUE", |v| v.with_description("Tuesday"))
                 .value_fn("WED", |v| v.with_description("Wedsday"))
                 .value_fn("THU", |v| v.with_description("Thusday"))
                 .value_fn("FRI", |v| v.with_description("Friday"))
                 .build();
    assert_eq!("Days of the week", days.description().unwrap_or(""));
    assert_eq!("Monday", days.values()["MON"].description().unwrap_or(""));;
  }
}
<|endoftext|>


<commit_before>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::borrow::Borrow;
use std::cmp::Ordering;
use std::ffi::{CStr, CString, OsStr};
use std::fmt;
use std::ops::Deref;
use std::os::raw::c_char;
use std::ptr;
use std::slice;
use std::string::String;
use translate::*;
use types::{StaticType, Type};
use libc;

use gobject_ffi;
use ffi as glib_ffi;
use value::{FromValueOptional, Value, SetValueOptional, SetValue};

#[derive(Debug)]
pub enum GString {
    ForeignOwned(CString),
    Borrowed(*const c_char, usize),
    Owned(*mut c_char, usize)
}

impl GString {
    pub unsafe fn new(ptr: *mut c_char) -> Self {
        assert!(!ptr.is_null());
        GString::Owned(ptr, libc::strlen(ptr))
    }

    pub unsafe fn new_borrowed(ptr: *const c_char) -> Self {
        assert!(!ptr.is_null());
        GString::Borrowed(ptr, libc::strlen(ptr))
    }

    pub fn as_str(&self) -> &str {
        let cstr = match self {
            GString::Borrowed(ptr, length) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            }
            GString::Owned(ptr, length) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            }
            GString::ForeignOwned(cstring) => {
                cstring.as_c_str()
            }
        };
        cstr.to_str().unwrap()
    }
}

impl Drop for GString {
    fn drop(&mut self) {
        if let GString::Owned(ptr, _len) = self {
            unsafe {
                glib_ffi::g_free(*ptr as *mut _);
            }
        }
    }
}

impl fmt::Display for GString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl Borrow<str> for GString {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl Ord for GString {
    fn cmp(&self, other: &GString) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl PartialOrd for GString {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for GString {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for String {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<str> for GString {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl<'a> PartialEq<&'a str> for GString {
    fn eq(&self, other: &&'a str) -> bool {
        self.as_str() == *other
    }
}

impl<'a> PartialEq<GString> for &'a str {
    fn eq(&self, other: &GString) -> bool {
        *self == other.as_str()
    }
}

impl PartialEq<String> for GString {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for str {
    fn eq(&self, other: &GString) -> bool {
        self == other.as_str()
    }
}

impl PartialOrd<GString> for String {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&String::from(other.as_str())))
    }
}

impl PartialOrd<String> for GString {
    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
        Some(self.as_str().cmp(other.as_str()))
    }
}

impl PartialOrd<GString> for str {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&other))
    }
}

impl PartialOrd<str> for GString {
    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
        Some(self.as_str().cmp(other))
    }
}

impl Eq for GString {}

impl AsRef<str> for GString {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<OsStr> for GString {
    fn as_ref(&self) -> &OsStr {
        OsStr::new(self.as_str())
    }
}

impl Deref for GString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl From<GString> for String {
    #[inline]
    fn from(s: GString) -> Self {
        String::from(s.as_str())
    }
}

impl From<GString> for Box<str> {
    #[inline]
    fn from(s: GString) -> Self {
        let st: String = s.into();
        st.into_boxed_str()
    }
}

impl From<String> for GString {
    #[inline]
    fn from(s: String) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Box<str>> for GString {
    #[inline]
    fn from(s: Box<str>) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl<'a> From<&'a str> for GString {
    #[inline]
    fn from(s: &'a str) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Vec<u8>> for GString {
    #[inline]
    fn from(s: Vec<u8>) -> Self {
        let cstring = CString::new(s).expect("CString::new failed");
        cstring.into()
    }
}

impl From<CString> for GString {
    #[inline]
    fn from(s: CString) -> Self {
        GString::ForeignOwned(s)
    }
}

impl<'a> From<&'a CStr> for GString {
    #[inline]
    fn from(c: &'a CStr) -> Self {
        CString::from(c).into()
    }
}

impl FromGlibPtrFull<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrFull<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut u8) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrFull<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut i8) -> Self {
        GString::new(ptr)
    }
}

impl FromGlibPtrNone<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

impl FromGlibPtrNone<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut u8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut i8);
        cstr.into()
    }
}

impl FromGlibPtrNone<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut i8) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

impl FromGlibPtrBorrow<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *const c_char) -> Self {
        GString::new_borrowed(ptr)
    }
}

impl FromGlibPtrBorrow<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut u8) -> Self {
        GString::new_borrowed(ptr as *const c_char)
    }
}

impl FromGlibPtrBorrow<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut i8) -> Self {
        GString::new_borrowed(ptr as *const c_char)
    }
}

impl<'a> ToGlibPtr<'a, *const c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
        Stash(self.as_ptr() as *const _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *const c_char {
        unsafe {
            glib_ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *const c_char
        }
    }
}

impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
        Stash(self.as_ptr() as *mut _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut c_char {
        unsafe {
            glib_ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *mut c_char
        }
    }
}

impl GlibPtrDefault for GString {
    type GlibType = *const c_char;
}

impl StaticType for GString {
    fn static_type() -> Type {
        String::static_type()
    }
}

impl StaticType for Vec<GString> {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

impl<'a> FromValueOptional<'a> for GString {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        let val = value.to_glib_none().0;
        if val.is_null() {
            None
        } else {
            let ptr = gobject_ffi::g_value_dup_string(val);
            Some(GString::new(ptr))
        }
    }
}

impl SetValue for GString {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl SetValueOptional for GString {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl_from_glib_container_as_vec_string!(GString, *const c_char);
impl_from_glib_container_as_vec_string!(GString, *mut c_char);

#[cfg(test)]
mod tests {
    use gstring::GString;
    use std::ffi::CString;
    use ffi as glib_ffi;

    #[test]
    fn test_gstring() {
        let data = CString::new("foo").unwrap();
        let ptr = data.into_raw();

        unsafe {
            let ptr_copy = glib_ffi::g_strdup(ptr);
            let gstring = GString::new(ptr_copy);
            assert_eq!(gstring.as_str(), "foo");
            let foo: Box<str> = gstring.into();
            assert_eq!(foo.as_ref(), "foo");
        }
    }

    #[test]
    fn test_owned_glib_string() {
        let data = CString::new("foo").unwrap();
        let ptr = data.into_raw();
        unsafe {
            let ptr_copy = glib_ffi::g_strdup(ptr);
            let gstr = GString::new(ptr_copy);
            assert_eq!(gstr, "foo");
        }
    }

    #[test]
    fn test_gstring_from_str() {
        let gstring: GString = "foo".into();
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_gstring_from_cstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_string_from_gstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let s = String::from(gstring);
        assert_eq!(s, "foo");
    }

    #[test]
    fn test_vec_u8_to_gstring() {
        let v = "foo".as_bytes();
        let s: GString = Vec::from(v).into();
        assert_eq!(s.as_str(), "foo");
    }

}
<commit_msg>Fixes compilation on aarch64<commit_after>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::borrow::Borrow;
use std::cmp::Ordering;
use std::ffi::{CStr, CString, OsStr};
use std::fmt;
use std::ops::Deref;
use std::os::raw::c_char;
use std::ptr;
use std::slice;
use std::string::String;
use translate::*;
use types::{StaticType, Type};
use libc;

use gobject_ffi;
use ffi as glib_ffi;
use value::{FromValueOptional, Value, SetValueOptional, SetValue};

#[derive(Debug)]
pub enum GString {
    ForeignOwned(CString),
    Borrowed(*const c_char, usize),
    Owned(*mut c_char, usize)
}

impl GString {
    pub unsafe fn new(ptr: *mut c_char) -> Self {
        assert!(!ptr.is_null());
        GString::Owned(ptr, libc::strlen(ptr))
    }

    pub unsafe fn new_borrowed(ptr: *const c_char) -> Self {
        assert!(!ptr.is_null());
        GString::Borrowed(ptr, libc::strlen(ptr))
    }

    pub fn as_str(&self) -> &str {
        let cstr = match self {
            GString::Borrowed(ptr, length) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            }
            GString::Owned(ptr, length) => unsafe {
                let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1);
                CStr::from_bytes_with_nul_unchecked(bytes)
            }
            GString::ForeignOwned(cstring) => {
                cstring.as_c_str()
            }
        };
        cstr.to_str().unwrap()
    }
}

impl Drop for GString {
    fn drop(&mut self) {
        if let GString::Owned(ptr, _len) = self {
            unsafe {
                glib_ffi::g_free(*ptr as *mut _);
            }
        }
    }
}

impl fmt::Display for GString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

impl Borrow<str> for GString {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl Ord for GString {
    fn cmp(&self, other: &GString) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl PartialOrd for GString {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for GString {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for String {
    fn eq(&self, other: &GString) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<str> for GString {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl<'a> PartialEq<&'a str> for GString {
    fn eq(&self, other: &&'a str) -> bool {
        self.as_str() == *other
    }
}

impl<'a> PartialEq<GString> for &'a str {
    fn eq(&self, other: &GString) -> bool {
        *self == other.as_str()
    }
}

impl PartialEq<String> for GString {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other.as_str()
    }
}

impl PartialEq<GString> for str {
    fn eq(&self, other: &GString) -> bool {
        self == other.as_str()
    }
}

impl PartialOrd<GString> for String {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&String::from(other.as_str())))
    }
}

impl PartialOrd<String> for GString {
    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
        Some(self.as_str().cmp(other.as_str()))
    }
}

impl PartialOrd<GString> for str {
    fn partial_cmp(&self, other: &GString) -> Option<Ordering> {
        Some(self.cmp(&other))
    }
}

impl PartialOrd<str> for GString {
    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
        Some(self.as_str().cmp(other))
    }
}

impl Eq for GString {}

impl AsRef<str> for GString {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<OsStr> for GString {
    fn as_ref(&self) -> &OsStr {
        OsStr::new(self.as_str())
    }
}

impl Deref for GString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl From<GString> for String {
    #[inline]
    fn from(s: GString) -> Self {
        String::from(s.as_str())
    }
}

impl From<GString> for Box<str> {
    #[inline]
    fn from(s: GString) -> Self {
        let st: String = s.into();
        st.into_boxed_str()
    }
}

impl From<String> for GString {
    #[inline]
    fn from(s: String) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Box<str>> for GString {
    #[inline]
    fn from(s: Box<str>) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl<'a> From<&'a str> for GString {
    #[inline]
    fn from(s: &'a str) -> Self {
        s.as_bytes().to_vec().into()
    }
}

impl From<Vec<u8>> for GString {
    #[inline]
    fn from(s: Vec<u8>) -> Self {
        let cstring = CString::new(s).expect("CString::new failed");
        cstring.into()
    }
}

impl From<CString> for GString {
    #[inline]
    fn from(s: CString) -> Self {
        GString::ForeignOwned(s)
    }
}

impl<'a> From<&'a CStr> for GString {
    #[inline]
    fn from(c: &'a CStr) -> Self {
        CString::from(c).into()
    }
}

impl FromGlibPtrFull<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *const c_char) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrFull<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut u8) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrFull<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut i8) -> Self {
        GString::new(ptr as *mut _)
    }
}

impl FromGlibPtrNone<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *const c_char) -> Self {
        let cstr = CStr::from_ptr(ptr);
        cstr.into()
    }
}

impl FromGlibPtrNone<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut u8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut _);
        cstr.into()
    }
}

impl FromGlibPtrNone<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut i8) -> Self {
        let cstr = CStr::from_ptr(ptr as *mut _);
        cstr.into()
    }
}

impl FromGlibPtrBorrow<*const c_char> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *const c_char) -> Self {
        GString::new_borrowed(ptr)
    }
}

impl FromGlibPtrBorrow<*mut u8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut u8) -> Self {
        GString::new_borrowed(ptr as *const c_char)
    }
}

impl FromGlibPtrBorrow<*mut i8> for GString {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut i8) -> Self {
        GString::new_borrowed(ptr as *const c_char)
    }
}

impl<'a> ToGlibPtr<'a, *const c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> {
        Stash(self.as_ptr() as *const _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *const c_char {
        unsafe {
            glib_ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *const c_char
        }
    }
}

impl<'a> ToGlibPtr<'a, *mut c_char> for GString {
    type Storage = &'a Self;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> {
        Stash(self.as_ptr() as *mut _, self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut c_char {
        unsafe {
            glib_ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t)
                as *mut c_char
        }
    }
}

impl GlibPtrDefault for GString {
    type GlibType = *const c_char;
}

impl StaticType for GString {
    fn static_type() -> Type {
        String::static_type()
    }
}

impl StaticType for Vec<GString> {
    fn static_type() -> Type {
        unsafe {
            from_glib(glib_ffi::g_strv_get_type())
        }
    }
}

impl<'a> FromValueOptional<'a> for GString {
    unsafe fn from_value_optional(value: &'a Value) -> Option<Self> {
        let val = value.to_glib_none().0;
        if val.is_null() {
            None
        } else {
            let ptr = gobject_ffi::g_value_dup_string(val);
            Some(GString::new(ptr))
        }
    }
}

impl SetValue for GString {
    unsafe fn set_value(value: &mut Value, this: &Self) {
        gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl SetValueOptional for GString {
    unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) {
        gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full())
    }
}

impl_from_glib_container_as_vec_string!(GString, *const c_char);
impl_from_glib_container_as_vec_string!(GString, *mut c_char);

#[cfg(test)]
mod tests {
    use gstring::GString;
    use std::ffi::CString;
    use ffi as glib_ffi;

    #[test]
    fn test_gstring() {
        let data = CString::new("foo").unwrap();
        let ptr = data.into_raw();

        unsafe {
            let ptr_copy = glib_ffi::g_strdup(ptr);
            let gstring = GString::new(ptr_copy);
            assert_eq!(gstring.as_str(), "foo");
            let foo: Box<str> = gstring.into();
            assert_eq!(foo.as_ref(), "foo");
        }
    }

    #[test]
    fn test_owned_glib_string() {
        let data = CString::new("foo").unwrap();
        let ptr = data.into_raw();
        unsafe {
            let ptr_copy = glib_ffi::g_strdup(ptr);
            let gstr = GString::new(ptr_copy);
            assert_eq!(gstr, "foo");
        }
    }

    #[test]
    fn test_gstring_from_str() {
        let gstring: GString = "foo".into();
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_gstring_from_cstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let foo: Box<str> = gstring.into();
        assert_eq!(foo.as_ref(), "foo");
    }

    #[test]
    fn test_string_from_gstring() {
        let cstr = CString::new("foo").unwrap();
        let gstring = GString::from(cstr);
        assert_eq!(gstring.as_str(), "foo");
        let s = String::from(gstring);
        assert_eq!(s, "foo");
    }

    #[test]
    fn test_vec_u8_to_gstring() {
        let v = "foo".as_bytes();
        let s: GString = Vec::from(v).into();
        assert_eq!(s.as_str(), "foo");
    }

}
<|endoftext|>