<commit_before>extern crate num;
use std::collections::BTreeSet;
use std::cmp;
use rand::Rng;
use std::ops::Range;
use std::iter::Rev;
use super::{Genetic, SISO};
use std::marker::PhantomData;

///Defines an opcode for the Mep. Every opcode contains an instruction and two parameter indices. These specify which
///previous opcodes produced the result required as inputs to this opcode. These parameters can also come from the inputs
///to the program, which sequentially preceed the internal instructions.
#[derive(Clone, Copy)]
struct Opcode<Ins> {
    instruction: Ins,
    first: usize,
    second: usize,
}

///A multi-expression program represented using a series of operations that can reuse results of previous operations.
pub struct Mep<Ins, R, Param, F1, F2> {
    program: Vec<Opcode<Ins>>,
    unit_mutate_size: usize,
    crossover_points: usize,
    inputs: usize,
    outputs: usize,
    mutator: F1,
    processor: F2,
    _phantom: (PhantomData<R>, PhantomData<Param>),
}

impl<Ins, R, Param, F1, F2> Clone for Mep<Ins, R, Param, F1, F2>
    where Ins: Clone, F1: Copy, F2: Copy
{
    fn clone(&self) -> Self {
        Mep{
            program: self.program.clone(),
            unit_mutate_size: self.unit_mutate_size,
            crossover_points: self.crossover_points,
            inputs: self.inputs,
            outputs: self.outputs,
            mutator: self.mutator,
            processor: self.processor,
            _phantom: (PhantomData, PhantomData),
        }
    }
}

impl<Ins, R, Param, F1, F2> Mep<Ins, R, Param, F1, F2> {
    ///Generates a new Mep with a particular size and takes a closure to generate random instructions.
    ///Takes an RNG as well to generate random internal data for each instruction. This Rng is different from the Mep's
    ///Rng, thus it is parameterized separately here.
    pub fn new<I, Rg>(inputs: usize, outputs: usize, unit_mutate_size: usize, crossover_points: usize, rng: &mut Rg,
        instruction_iter: I, mutator: F1, processor: F2) -> Self
        where I: Iterator<Item=Ins>, Rg: Rng, F1: Fn(&mut Ins, &mut R), F2: Fn(&Ins, Param, Param) -> Param
    {
        Mep{
            program: instruction_iter.enumerate()
                .map(|(index, ins)| Opcode{
                        instruction: ins,
                        first: rng.gen_range(0, index + inputs),
                        second: rng.gen_range(0, index + inputs)
                    }
                ).collect(),
            unit_mutate_size: unit_mutate_size,
            crossover_points: crossover_points,
            inputs: inputs,
            outputs: outputs,
            mutator: mutator,
            processor: processor,
            _phantom: (PhantomData, PhantomData),
        }
    }
}

impl<Ins, R, Param, F1, F2> Genetic<R> for Mep<Ins, R, Param, F1, F2>
    where R: Rng, Ins: Clone, Param: Clone, F1: Copy + Fn(&mut Ins, &mut R), F2: Copy
{
    fn mate(parents: (&Self, &Self), rng: &mut R) -> Self {
        //Each Mep must have the same amount of inputs
        //TODO: Once Rust implements generic values, this can be made explicit and is not needed
        assert!(parents.0.inputs == parents.1.inputs);
        assert!(parents.0.outputs == parents.1.outputs);
        //Get the smallest of the two lengths
        let total_instructions = cmp::min(parents.0.program.len(), parents.1.program.len());
        Mep{program:
            //Generate a randomly sized sequence between 1 and half of the total possible crossover points
            (0..rng.gen_range(1, total_instructions / 2))
            //Map these to random crossover points
            .map(|_| rng.gen_range(0, total_instructions))
            //Add total_instructions at the end so we can generate a range with it
            .chain(Some(total_instructions))
            //Sort them by value into BTree, which removes duplicates and orders them
            .fold(BTreeSet::new(), |mut set, i| {set.insert(i); set})
            //Iterate over the sorted values
            .iter()
            //Turn every copy of two, prepending a 0, into a range
            .scan(0, |prev, x| {let out = Some(*prev..*x); *prev = *x; out})
            //Enumerate by index to differentiate odd and even values
            .enumerate()
            //Map even pairs to ranges in parent 0 and odd ones to ranges in parent 1 and expand the ranges
            .flat_map(|(index, range)| {
                {if index % 2 == 0 {parents.0} else {parents.1}}.program[range].iter().cloned()
            })
            //Collect all the instruction ranges from each parent
            .collect(),

            unit_mutate_size: if parents.0.unit_mutate_size < parents.1.unit_mutate_size {
                rng.gen_range(parents.0.unit_mutate_size, parents.1.unit_mutate_size + 1)
            } else {
                rng.gen_range(parents.1.unit_mutate_size, parents.0.unit_mutate_size + 1)
            },

            crossover_points: if parents.0.crossover_points < parents.1.crossover_points {
                rng.gen_range(parents.0.crossover_points, parents.1.crossover_points + 1)
            } else {
                rng.gen_range(parents.1.crossover_points, parents.0.crossover_points + 1)
            },

            inputs: parents.0.inputs,
            outputs: parents.0.outputs,
            mutator: {if rng.gen_range(0, 2) == 0 {parents.0} else {parents.1}}.mutator,
            processor: {if rng.gen_range(0, 2) == 0 {parents.0} else {parents.1}}.processor,
            _phantom: (PhantomData, PhantomData),
        }
    }

    ///The Mep mutate function operates using the unit_mutate_size. This variable specifies the amount of instructions
    ///for which a single mutation is expect to occour every time mutate is called. This variable can be mutated inside
    ///of mutate, in which case it may never go below 1, but may tend towards infinity in increments of 1. This variable
    ///is implemented as a u64 to permit it to expand unbounded to mutation levels that are so low that mutations
    ///virtually never happen. Allowing this to mutate allows species to find the equilibrium between genomic
    ///adaptability and stability. If a species develops information gathering, then it can adapt intellegently, making
    ///it possibly more beneficial to operate at lower mutation rates. Setting the default mutation rate for species
    ///properly, or allowing it to adapt as the simulation continues, permits species to survive more frequently that
    ///are randomly generated.
    fn mutate(&mut self, rng: &mut R) {
        //Mutate unit_mutate_size
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.unit_mutate_size += 1,
                1 => if self.unit_mutate_size > 1 {self.unit_mutate_size -= 1},
                _ => unreachable!(),
            }
        }
        //Mutate crossover_points
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.crossover_points += 1,
                1 => if self.crossover_points > 1 {self.crossover_points -= 1},
                _ => unreachable!(),
            }
        }

        //Mutate the instructions using the mutator
        loop {
            //Choose a random location in the instructions and then add a random value up to the unit_mutate_size
            let choice = rng.gen_range(0, self.program.len()) + rng.gen_range(0, self.unit_mutate_size);
            //Whenever we choose a location outside the vector reject the choice and end mutation
            if choice >= self.program.len() {
                break;
            }
            let op = &mut self.program[choice];
            //Randomly mutate only one of the things contained here
            match rng.gen_range(0, 3) {
                0 => (self.mutator)(&mut op.instruction, rng),
                1 => op.first = rng.gen_range(0, choice + self.inputs),
                2 => op.second = rng.gen_range(0, choice + self.inputs),
                _ => unreachable!(),
            }
        }
    }
}

impl<'a, Ins: 'a, R: 'a, Param: 'a, F1: 'a, F2: 'a> SISO<'a, Param, Param> for Mep<Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    type Iter = ResultIterator<'a, Ins, R, Param, F1, F2>;

    fn compute(&'a self, inputs: &'a [Param]) -> Self::Iter {
        //Ensure we have enough opcodes to produce the desired amount of outputs, otherwise the programmer has failed
        assert!(self.outputs <= self.program.len());
        ResultIterator{
            mep: self,
            buff: vec![None; self.program.len()],
            solve_iter: ((self.program.len() + self.inputs - self.outputs)..(self.program.len() + self.inputs)).rev(),
            inputs: inputs,
        }
    }
}

pub struct ResultIterator<'a, Ins: 'a, R: 'a, Param: 'a, F1: 'a, F2: 'a> {
    mep: &'a Mep<Ins, R, Param, F1, F2>,
    buff: Vec<Option<Param>>,
    solve_iter: Rev<Range<usize>>,
    inputs: &'a [Param],
}

impl<'a, Ins, R, Param, F1, F2> ResultIterator<'a, Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    fn op_solved(&mut self, i: usize) -> Param {
        //If this is an input, it is already solved, so return the result immediately
        if i < self.mep.inputs {
            return self.inputs[i].clone();
        }
        //Check if this has been evaluated or not
        let possible = self.buff[i - self.mep.inputs].clone();
        match possible {
            //If it has, return the value
            Some(x) => x,
            //If it hasnt been solved
            None => {
                //Get a reference to the opcode
                let op = &self.mep.program[i - self.mep.inputs];
                //Compute the result of the operation, ensuring the inputs are solved beforehand
                let result = (self.mep.processor)(&op.instruction, self.op_solved(op.first), self.op_solved(op.second));
                //Properly store the Some result to the buffer
                self.buff[i - self.mep.inputs] = Some(result.clone());
                //Return the result
                result
            }
        }
    }
}

impl<'a, Ins, R, Param, F1, F2> Iterator for ResultIterator<'a, Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    type Item = Param;
    fn next(&mut self) -> Option<Param> {
        match self.solve_iter.next() {
            None => None,
            Some(i) => Some(self.op_solved(i)),
        }
    }
}

#[cfg(test)]
mod tests {
    use rand::{Isaac64Rng, SeedableRng, Rng};
    use super::*;
    use super::super::{Genetic, SISO};

    fn mutator(_: &mut i32, _: &mut Isaac64Rng) {}
    fn processor(_: &i32, _: i32, _: i32) -> i32 {0}

    #[test]
    fn new() {
        let a = Mep::new(3, 1, 10, 10, &mut Isaac64Rng::from_seed(&[1, 2, 3, 4]), 0..30, mutator, processor);

        assert_eq!(a.program.iter().map(|i| i.instruction).collect::<Vec<_>>(), (0..30).collect::<Vec<_>>());
    }

    #[test]
    fn crossover() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let (a, b) = {
            let mut clos = || Mep::new(3, 1, 10, 10, &mut rng, 0..30, mutator, processor);
            (clos(), clos())
        };
        let old_rngs: Vec<_> = rng.clone().gen_iter::<i32>().take(5).collect();
        let _ = Mep::mate((&a, &b), &mut rng);
        //Ensure that rng was borrowed mutably
        assert!(rng.clone().gen_iter::<i32>().take(5).collect::<Vec<_>>() != old_rngs);
    }

    #[test]
    fn compute() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let a = Mep::new(3, 1, 10, 10, &mut rng, 0..30, mutator, processor);

        let inputs = [2, 3, 4];
        assert_eq!(a.compute(&inputs[..]).collect::<Vec<_>>(), [0]);
    }
}
<commit_msg>let users access hidden Mep variables<commit_after>extern crate num;
use std::collections::BTreeSet;
use std::cmp;
use rand::Rng;
use std::ops::Range;
use std::iter::Rev;
use super::{Genetic, SISO};
use std::marker::PhantomData;

///Defines an opcode for the Mep. Every opcode contains an instruction and two parameter indices. These specify which
///previous opcodes produced the result required as inputs to this opcode. These parameters can also come from the inputs
///to the program, which sequentially preceed the internal instructions.
#[derive(Clone, Copy)]
struct Opcode<Ins> {
    instruction: Ins,
    first: usize,
    second: usize,
}

///A multi-expression program represented using a series of operations that can reuse results of previous operations.
pub struct Mep<Ins, R, Param, F1, F2> {
    program: Vec<Opcode<Ins>>,
    pub unit_mutate_size: usize,
    pub crossover_points: usize,
    inputs: usize,
    outputs: usize,
    mutator: F1,
    processor: F2,
    _phantom: (PhantomData<R>, PhantomData<Param>),
}

impl<Ins, R, Param, F1, F2> Clone for Mep<Ins, R, Param, F1, F2>
    where Ins: Clone, F1: Copy, F2: Copy
{
    fn clone(&self) -> Self {
        Mep{
            program: self.program.clone(),
            unit_mutate_size: self.unit_mutate_size,
            crossover_points: self.crossover_points,
            inputs: self.inputs,
            outputs: self.outputs,
            mutator: self.mutator,
            processor: self.processor,
            _phantom: (PhantomData, PhantomData),
        }
    }
}

impl<Ins, R, Param, F1, F2> Mep<Ins, R, Param, F1, F2> {
    ///Generates a new Mep with a particular size and takes a closure to generate random instructions.
    ///Takes an RNG as well to generate random internal data for each instruction. This Rng is different from the Mep's
    ///Rng, thus it is parameterized separately here.
    pub fn new<I, Rg>(inputs: usize, outputs: usize, unit_mutate_size: usize, crossover_points: usize, rng: &mut Rg,
        instruction_iter: I, mutator: F1, processor: F2) -> Self
        where I: Iterator<Item=Ins>, Rg: Rng, F1: Fn(&mut Ins, &mut R), F2: Fn(&Ins, Param, Param) -> Param
    {
        Mep{
            program: instruction_iter.enumerate()
                .map(|(index, ins)| Opcode{
                        instruction: ins,
                        first: rng.gen_range(0, index + inputs),
                        second: rng.gen_range(0, index + inputs)
                    }
                ).collect(),
            unit_mutate_size: unit_mutate_size,
            crossover_points: crossover_points,
            inputs: inputs,
            outputs: outputs,
            mutator: mutator,
            processor: processor,
            _phantom: (PhantomData, PhantomData),
        }
    }
}

impl<Ins, R, Param, F1, F2> Genetic<R> for Mep<Ins, R, Param, F1, F2>
    where R: Rng, Ins: Clone, Param: Clone, F1: Copy + Fn(&mut Ins, &mut R), F2: Copy
{
    fn mate(parents: (&Self, &Self), rng: &mut R) -> Self {
        //Each Mep must have the same amount of inputs
        //TODO: Once Rust implements generic values, this can be made explicit and is not needed
        assert!(parents.0.inputs == parents.1.inputs);
        assert!(parents.0.outputs == parents.1.outputs);
        //Get the smallest of the two lengths
        let total_instructions = cmp::min(parents.0.program.len(), parents.1.program.len());
        Mep{program:
            //Generate a randomly sized sequence between 1 and half of the total possible crossover points
            (0..rng.gen_range(1, total_instructions / 2))
            //Map these to random crossover points
            .map(|_| rng.gen_range(0, total_instructions))
            //Add total_instructions at the end so we can generate a range with it
            .chain(Some(total_instructions))
            //Sort them by value into BTree, which removes duplicates and orders them
            .fold(BTreeSet::new(), |mut set, i| {set.insert(i); set})
            //Iterate over the sorted values
            .iter()
            //Turn every copy of two, prepending a 0, into a range
            .scan(0, |prev, x| {let out = Some(*prev..*x); *prev = *x; out})
            //Enumerate by index to differentiate odd and even values
            .enumerate()
            //Map even pairs to ranges in parent 0 and odd ones to ranges in parent 1 and expand the ranges
            .flat_map(|(index, range)| {
                {if index % 2 == 0 {parents.0} else {parents.1}}.program[range].iter().cloned()
            })
            //Collect all the instruction ranges from each parent
            .collect(),

            unit_mutate_size: if parents.0.unit_mutate_size < parents.1.unit_mutate_size {
                rng.gen_range(parents.0.unit_mutate_size, parents.1.unit_mutate_size + 1)
            } else {
                rng.gen_range(parents.1.unit_mutate_size, parents.0.unit_mutate_size + 1)
            },

            crossover_points: if parents.0.crossover_points < parents.1.crossover_points {
                rng.gen_range(parents.0.crossover_points, parents.1.crossover_points + 1)
            } else {
                rng.gen_range(parents.1.crossover_points, parents.0.crossover_points + 1)
            },

            inputs: parents.0.inputs,
            outputs: parents.0.outputs,
            mutator: {if rng.gen_range(0, 2) == 0 {parents.0} else {parents.1}}.mutator,
            processor: {if rng.gen_range(0, 2) == 0 {parents.0} else {parents.1}}.processor,
            _phantom: (PhantomData, PhantomData),
        }
    }

    ///The Mep mutate function operates using the unit_mutate_size. This variable specifies the amount of instructions
    ///for which a single mutation is expect to occour every time mutate is called. This variable can be mutated inside
    ///of mutate, in which case it may never go below 1, but may tend towards infinity in increments of 1. This variable
    ///is implemented as a u64 to permit it to expand unbounded to mutation levels that are so low that mutations
    ///virtually never happen. Allowing this to mutate allows species to find the equilibrium between genomic
    ///adaptability and stability. If a species develops information gathering, then it can adapt intellegently, making
    ///it possibly more beneficial to operate at lower mutation rates. Setting the default mutation rate for species
    ///properly, or allowing it to adapt as the simulation continues, permits species to survive more frequently that
    ///are randomly generated.
    fn mutate(&mut self, rng: &mut R) {
        //Mutate unit_mutate_size
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.unit_mutate_size += 1,
                1 => if self.unit_mutate_size > 1 {self.unit_mutate_size -= 1},
                _ => unreachable!(),
            }
        }
        //Mutate crossover_points
        if rng.gen_range(0, self.unit_mutate_size) == 0 {
            //Make it possibly go up or down by 1
            match rng.gen_range(0, 2) {
                0 => self.crossover_points += 1,
                1 => if self.crossover_points > 1 {self.crossover_points -= 1},
                _ => unreachable!(),
            }
        }

        //Mutate the instructions using the mutator
        loop {
            //Choose a random location in the instructions and then add a random value up to the unit_mutate_size
            let choice = rng.gen_range(0, self.program.len()) + rng.gen_range(0, self.unit_mutate_size);
            //Whenever we choose a location outside the vector reject the choice and end mutation
            if choice >= self.program.len() {
                break;
            }
            let op = &mut self.program[choice];
            //Randomly mutate only one of the things contained here
            match rng.gen_range(0, 3) {
                0 => (self.mutator)(&mut op.instruction, rng),
                1 => op.first = rng.gen_range(0, choice + self.inputs),
                2 => op.second = rng.gen_range(0, choice + self.inputs),
                _ => unreachable!(),
            }
        }
    }
}

impl<'a, Ins: 'a, R: 'a, Param: 'a, F1: 'a, F2: 'a> SISO<'a, Param, Param> for Mep<Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    type Iter = ResultIterator<'a, Ins, R, Param, F1, F2>;

    fn compute(&'a self, inputs: &'a [Param]) -> Self::Iter {
        //Ensure we have enough opcodes to produce the desired amount of outputs, otherwise the programmer has failed
        assert!(self.outputs <= self.program.len());
        ResultIterator{
            mep: self,
            buff: vec![None; self.program.len()],
            solve_iter: ((self.program.len() + self.inputs - self.outputs)..(self.program.len() + self.inputs)).rev(),
            inputs: inputs,
        }
    }
}

pub struct ResultIterator<'a, Ins: 'a, R: 'a, Param: 'a, F1: 'a, F2: 'a> {
    mep: &'a Mep<Ins, R, Param, F1, F2>,
    buff: Vec<Option<Param>>,
    solve_iter: Rev<Range<usize>>,
    inputs: &'a [Param],
}

impl<'a, Ins, R, Param, F1, F2> ResultIterator<'a, Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    fn op_solved(&mut self, i: usize) -> Param {
        //If this is an input, it is already solved, so return the result immediately
        if i < self.mep.inputs {
            return self.inputs[i].clone();
        }
        //Check if this has been evaluated or not
        let possible = self.buff[i - self.mep.inputs].clone();
        match possible {
            //If it has, return the value
            Some(x) => x,
            //If it hasnt been solved
            None => {
                //Get a reference to the opcode
                let op = &self.mep.program[i - self.mep.inputs];
                //Compute the result of the operation, ensuring the inputs are solved beforehand
                let result = (self.mep.processor)(&op.instruction, self.op_solved(op.first), self.op_solved(op.second));
                //Properly store the Some result to the buffer
                self.buff[i - self.mep.inputs] = Some(result.clone());
                //Return the result
                result
            }
        }
    }
}

impl<'a, Ins, R, Param, F1, F2> Iterator for ResultIterator<'a, Ins, R, Param, F1, F2>
    where F2: Fn(&Ins, Param, Param) -> Param, Param: Clone
{
    type Item = Param;
    fn next(&mut self) -> Option<Param> {
        match self.solve_iter.next() {
            None => None,
            Some(i) => Some(self.op_solved(i)),
        }
    }
}

#[cfg(test)]
mod tests {
    use rand::{Isaac64Rng, SeedableRng, Rng};
    use super::*;
    use super::super::{Genetic, SISO};

    fn mutator(_: &mut i32, _: &mut Isaac64Rng) {}
    fn processor(_: &i32, _: i32, _: i32) -> i32 {0}

    #[test]
    fn new() {
        let a = Mep::new(3, 1, 10, 10, &mut Isaac64Rng::from_seed(&[1, 2, 3, 4]), 0..30, mutator, processor);

        assert_eq!(a.program.iter().map(|i| i.instruction).collect::<Vec<_>>(), (0..30).collect::<Vec<_>>());
    }

    #[test]
    fn crossover() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let (a, b) = {
            let mut clos = || Mep::new(3, 1, 10, 10, &mut rng, 0..30, mutator, processor);
            (clos(), clos())
        };
        let old_rngs: Vec<_> = rng.clone().gen_iter::<i32>().take(5).collect();
        let _ = Mep::mate((&a, &b), &mut rng);
        //Ensure that rng was borrowed mutably
        assert!(rng.clone().gen_iter::<i32>().take(5).collect::<Vec<_>>() != old_rngs);
    }

    #[test]
    fn compute() {
        let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
        let a = Mep::new(3, 1, 10, 10, &mut rng, 0..30, mutator, processor);

        let inputs = [2, 3, 4];
        assert_eq!(a.compute(&inputs[..]).collect::<Vec<_>>(), [0]);
    }
}
<|endoftext|>


<commit_before>use na::*;
use std::num::*;
mod test;

pub trait GridSpace {
    fn update_grid_pt_density(&mut self, val_to_add: (f64, f64), current_time: u32) -> Result<(), String>;

    fn compute_decay_factor_at_time(&self, t_n: u32, t_l: u32) -> f64 {
        LAMBDA.powf((t_n - t_l) as f64)
    }
}

pub struct GridPoint {
    i: usize,
    j: usize,
    density: f64,
    last_density: f64,
    new_data_time: u32,
    last_data_time: u32,

}

impl GridSpace for GridPoint {

    //TODO
    fn update_grid_pt_density(&mut self, val_to_add: (f64, f64), current_time: u32) -> Result<(), String> {
        let coeff = self.compute_decay_factor_at_time(self.new_data_time, self.last_data_time);
        let new_density = coeff * self.last_density + 1.0;

        self.last_density = self.density;
        self.density = new_density;

        self.last_data_time = self.new_data_time;
        self.new_data_time = current_time;

        Ok(())
    }
}

const C_M: f64     = 3.0;
const C_L: f64     = 0.8;
const LAMBDA: f64  = 0.998;
const BETA: f64    = 0.3;

pub fn initialize_clustering(grid_list: Mat2<GridPoint>) -> Result<(), String> {
    //update density of all grids in grid_list
    //assign each dense grid to a distinct cluster
    //label all other grids as NO_CLASS; bad grids!
    /*
    do until no change in cluster labels
          foreach cluster c
            foreach outside grid g of c
                foreach neighboring grid h of g
                    if h belongs to cluster c'
                        if |c| > |c'| label all grids in c' as c
                        else label all grids in c as c'
                    else if (h is translational) label h as in c
    end do
    */
    Ok(())
}

#[test]
fn initialize_clusters() {
    const loc_i: usize = 0 as usize;
    const loc_j: usize = 0 as usize;
    const G1: GridPoint = GridPoint
                {i: loc_i, j: loc_j,
                    density: 0.0, new_data_time: 0, last_data_time: 0,
                    last_density: 0.0};
    let result = initialize_clustering(Mat2::new(G1, G1, G1, G1));
    assert_eq!(Ok(()), result);
}

pub fn adjust_clustering(grid_list: Mat2<GridPoint>) -> Result<(), String> {
    //update the density of all grids in grid_list
    /*
    foreach grid g whose attribute (dense/sparse/transitional) is changed since last call to adjust_clustering()
        if g is a sparse grid
            delete g from its cluster c, label g as NO_CLASS
            if (c becomes unconnected) split c into two clusters
        else if g is a dense grid
            among all neighboring grids of g, find out the grid h whoe cluster c_h has the largest size
            if h is a dense grid
                if (g is labelled as NO_CLASS) label g as in c_h
                else if (g is in cluster c and |c| > |c_h|)
                    label all grids in c_h as in c
                else if (g is in cluster c and |c| <= |c_h|)
                    label all grids in c as in c_h
            else if h is a transitional grid
                if ((g is NO_CLASS) and (h is an outside grid if g is added to c_h)) label g as in c_h
                else if (g is in cluster c and |c| >= |c_h|)
                    move h from cluster c_h to c
        else if (g is transitional grid)
            among neighboring clusters of g, find the largest one c'
            satisfying that g is an outside grid if added to it and
            label g as in c'
    */

    Ok(())
}<commit_msg>which grid impl + test<commit_after>use na::*;
use std::num::*;
mod test;

#[test]
fn test_initialize_clustering() {
    const loc_i: usize = 0 as usize;
    const loc_j: usize = 0 as usize;
    const G1: GridPoint = GridPoint
    {i: loc_i, j: loc_j,
        density: 0.0, new_data_time: 0, last_data_time: 0,
        last_density: 0.0};
    let result = initialize_clustering(Mat2::new(G1, G1, G1, G1));
    assert_eq!(Ok(()), result);
}

#[test]
fn test_which_grid() {
    let val = (3.1, 1.1);
    let i_rn = (0.0, 10.0);
    let j_rn = (-2.0, 2.0);
    let i_bins = 10 as usize;
    let j_bins = 4 as usize;

    let result = GridHelpers::which_grid(val, i_rn, j_rn, i_bins, j_bins).unwrap();
    assert_eq!(3, result.0);
    assert_eq!(3, result.1);
}

mod GridHelpers {
    pub fn which_grid(val: (f64, f64), i_range: (f64, f64), j_range: (f64, f64), i_bins: usize, j_bins: usize) -> Result<(usize, usize), String> {
        let i_size = (i_range.1 - i_range.0) / i_bins as f64;
        let i_number_of_sizes = ((val.0 - i_range.0) / i_size) as usize;
        let j_size = (j_range.1 - j_range.0) / j_bins as f64;
        let j_number_of_sizes = ((val.1 - j_range.0) / j_size) as usize;

        assert!(i_number_of_sizes < i_bins);
        assert!(j_number_of_sizes < j_bins);

        Ok((i_number_of_sizes, j_number_of_sizes))
    }
}

pub trait GridSpace {
    fn update_grid_pt_density(&mut self, val_to_add: (f64, f64), current_time: u32, lambda: f64) -> Result<(), String>;

    fn compute_decay_factor_at_time(&self, t_n: u32, t_l: u32, lambda: f64) -> f64 {
        lambda.powf((t_n - t_l) as f64)
    }

}

pub struct GridPoint {
    i: usize,
    j: usize,
    density: f64,
    last_density: f64,
    new_data_time: u32,
    last_data_time: u32,
}

pub struct DStreamProps {
    c_m: f64,
    c_l: f64,
    lambda: f64,
    beta: f64,
    i_bins: usize,
    j_bins: usize,
    i_range: (f64, f64),
    j_range: (f64, f64),
}

impl GridSpace for GridPoint {

    //TODO
    fn update_grid_pt_density(&mut self, val_to_add: (f64, f64), current_time: u32, lambda: f64) -> Result<(), String> {
        let coeff = self.compute_decay_factor_at_time(self.new_data_time, self.last_data_time, lambda);
        let new_density = coeff * self.last_density + 1.0;

        self.last_density = self.density;
        self.density = new_density;

        self.last_data_time = self.new_data_time;
        self.new_data_time = current_time;

        Ok(())
    }
}

pub fn initialize_clustering(grid_list: Mat2<GridPoint>) -> Result<(), String> {
    //update density of all grids in grid_list
    //assign each dense grid to a distinct cluster
    //label all other grids as NO_CLASS; bad grids!
    /*
    do until no change in cluster labels
          foreach cluster c
            foreach outside grid g of c
                foreach neighboring grid h of g
                    if h belongs to cluster c'
                        if |c| > |c'| label all grids in c' as c
                        else label all grids in c as c'
                    else if (h is translational) label h as in c
    end do
    */
    Ok(())
}

pub fn adjust_clustering(grid_list: Mat2<GridPoint>) -> Result<(), String> {
    //update the density of all grids in grid_list
    /*
    foreach grid g whose attribute (dense/sparse/transitional) is changed since last call to adjust_clustering()
        if g is a sparse grid
            delete g from its cluster c, label g as NO_CLASS
            if (c becomes unconnected) split c into two clusters
        else if g is a dense grid
            among all neighboring grids of g, find out the grid h whoe cluster c_h has the largest size
            if h is a dense grid
                if (g is labelled as NO_CLASS) label g as in c_h
                else if (g is in cluster c and |c| > |c_h|)
                    label all grids in c_h as in c
                else if (g is in cluster c and |c| <= |c_h|)
                    label all grids in c as in c_h
            else if h is a transitional grid
                if ((g is NO_CLASS) and (h is an outside grid if g is added to c_h)) label g as in c_h
                else if (g is in cluster c and |c| >= |c_h|)
                    move h from cluster c_h to c
        else if (g is transitional grid)
            among neighboring clusters of g, find the largest one c'
            satisfying that g is an outside grid if added to it and
            label g as in c'
    */

    Ok(())
}<|endoftext|>


<commit_before>use cairo;
use cairo::MatrixTrait;

use aspect_ratio::AspectRatio;
use draw::add_clipping_rect;
use drawing_ctx::{self, RsvgDrawingCtx};
use float_eq_cairo::ApproxEqCairo;
use node::RsvgNode;
use state::ComputedValues;
use viewbox::*;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ClipMode {
    ClipToViewport,
    ClipToVbox,
}

pub fn draw_in_viewport<F>(
    vx: f64,
    vy: f64,
    vw: f64,
    vh: f64,
    clip_mode: ClipMode,
    do_clip: bool,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    node: &RsvgNode,
    values: &ComputedValues,
    affine: cairo::Matrix,
    draw_ctx: *mut RsvgDrawingCtx,
    clipping: bool,
    draw_fn: F,
) where
    F: FnOnce(),
{
    let mut ctx = RsvgDrawingCtxWrapper(draw_ctx);

    in_viewport(
        &mut ctx,
        vx,
        vy,
        vw,
        vh,
        clip_mode,
        do_clip,
        vbox,
        preserve_aspect_ratio,
        node,
        values,
        affine,
        clipping,
        draw_fn,
    );
}

trait ViewportCtx {
    fn push_view_box(&mut self, width: f64, height: f64);
    fn pop_view_box(&mut self);
    fn push_discrete_layer(&mut self, values: &ComputedValues, clipping: bool);
    fn pop_discrete_layer(&mut self, node: &RsvgNode, values: &ComputedValues, clipping: bool);
    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64);
    fn set_affine(&mut self, affine: cairo::Matrix);
}

struct RsvgDrawingCtxWrapper(pub *mut RsvgDrawingCtx);

impl ViewportCtx for RsvgDrawingCtxWrapper {
    fn push_view_box(&mut self, width: f64, height: f64) {
        drawing_ctx::push_view_box(self.0, width, height);
    }

    fn pop_view_box(&mut self) {
        drawing_ctx::pop_view_box(self.0);
    }

    fn push_discrete_layer(&mut self, values: &ComputedValues, clipping: bool) {
        drawing_ctx::push_discrete_layer(self.0, values, clipping);
    }

    fn pop_discrete_layer(&mut self, node: &RsvgNode, values: &ComputedValues, clipping: bool) {
        drawing_ctx::pop_discrete_layer(self.0, node, values, clipping);
    }

    fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
        add_clipping_rect(self.0, x, y, w, h);
    }

    fn set_affine(&mut self, affine: cairo::Matrix) {
        drawing_ctx::get_cairo_context(self.0).set_matrix(affine);
    }
}

fn in_viewport<F>(
    ctx: &mut ViewportCtx,
    vx: f64,
    vy: f64,
    vw: f64,
    vh: f64,
    clip_mode: ClipMode,
    do_clip: bool,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    node: &RsvgNode,
    values: &ComputedValues,
    mut affine: cairo::Matrix,
    clipping: bool,
    draw_fn: F,
) where
    F: FnOnce(),
{
    // width or height set to 0 disables rendering of the element
    // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
    // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute

    if vw.approx_eq_cairo(&0.0) || vh.approx_eq_cairo(&0.0) {
        return;
    }

    ctx.push_discrete_layer(values, clipping);

    if do_clip && clip_mode == ClipMode::ClipToViewport {
        ctx.set_affine(affine);
        ctx.add_clipping_rect(vx, vy, vw, vh);
    }

    if let Some(vbox) = vbox {
        // the preserveAspectRatio attribute is only used if viewBox is specified
        // https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

        if vbox.0.width.approx_eq_cairo(&0.0) || vbox.0.height.approx_eq_cairo(&0.0) {
            // Width or height of 0 for the viewBox disables rendering of the element
            // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
            return;
        }

        ctx.push_view_box(vbox.0.width, vbox.0.height);

        let (x, y, w, h) =
            preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height, vx, vy, vw, vh);

        affine.translate(x, y);
        affine.scale(w / vbox.0.width, h / vbox.0.height);
        affine.translate(-vbox.0.x, -vbox.0.y);

        ctx.set_affine(affine);

        if do_clip && clip_mode == ClipMode::ClipToVbox {
            ctx.add_clipping_rect(vbox.0.x, vbox.0.y, vbox.0.width, vbox.0.height);
        }
    } else {
        ctx.push_view_box(vw, vh);

        affine.translate(vx, vy);
        ctx.set_affine(affine);
    }

    draw_fn();

    ctx.pop_view_box();
    ctx.pop_discrete_layer(node, values, clipping);
}

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

    use std::ptr;
    use std::rc::Rc;

    use handle::RsvgHandle;
    use node::{Node, NodeResult, NodeTrait, NodeType};
    use parsers::Parse;
    use property_bag::PropertyBag;

    struct TestNodeImpl {}

    impl NodeTrait for TestNodeImpl {
        fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
            Ok(())
        }
    }
    #[derive(Default, PartialEq)]
    struct Ctx {
        pub view_box_size: Option<(f64, f64)>,
        pub clipping_rect: Option<(f64, f64, f64, f64)>,
        pub affine: Option<cairo::Matrix>,

        pub expected_view_box_size: Option<(f64, f64)>,
        pub expected_clipping_rect: Option<(f64, f64, f64, f64)>,
        pub expected_affine: Option<cairo::Matrix>,
    }

    impl ViewportCtx for Ctx {
        fn push_view_box(&mut self, width: f64, height: f64) {
            self.view_box_size = Some((width, height));
        }

        fn pop_view_box(&mut self) {}

        fn push_discrete_layer(&mut self, _values: &ComputedValues, _clipping: bool) {}

        fn pop_discrete_layer(
            &mut self,
            _node: &RsvgNode,
            _values: &ComputedValues,
            _clipping: bool,
        ) {
        }

        fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
            self.clipping_rect = Some((x, y, w, h));
        }

        fn set_affine(&mut self, affine: cairo::Matrix) {
            self.affine = Some(affine);
        }
    }

    fn call_in_viewport(
        vx: f64,
        vy: f64,
        vw: f64,
        vh: f64,
        clip_mode: ClipMode,
        do_clip: bool,
        vbox: Option<ViewBox>,
        preserve_aspect_ratio: AspectRatio,
        affine: cairo::Matrix,
        ctx: &mut Ctx,
    ) {
        let node = Rc::new(Node::new(
            NodeType::Path,
            None,
            None,
            None,
            ptr::null_mut(),
            Box::new(TestNodeImpl {}),
        ));

        in_viewport(
            ctx,
            vx,
            vy,
            vw,
            vh,
            clip_mode,
            do_clip,
            vbox,
            preserve_aspect_ratio,
            &node,
            &ComputedValues::default(),
            affine,
            false,
            || (),
        );

        assert_eq!(ctx.view_box_size, ctx.expected_view_box_size);
        assert_eq!(ctx.clipping_rect, ctx.expected_clipping_rect);
        assert_eq!(ctx.affine, ctx.expected_affine);
    }

    #[test]
    fn clip_to_viewport() {
        let mut affine = cairo::Matrix::identity();
        affine.scale(0.25, 0.25);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine: None,

            expected_view_box_size: Some((40.0, 40.0)),
            expected_clipping_rect: Some((10.0, 10.0, 10.0, 10.0)),
            expected_affine: Some(affine),
        };

        call_in_viewport(
            10.0,
            10.0,
            10.0,
            10.0,
            ClipMode::ClipToViewport,
            true,
            Some(ViewBox(cairo::Rectangle {
                x: 40.0,
                y: 40.0,
                width: 40.0,
                height: 40.0,
            })),
            AspectRatio::parse_str("xMidYMid meet", ()).unwrap(),
            cairo::Matrix::identity(),
            &mut ctx,
        );
    }

    #[test]
    fn clip_to_vbox() {
        let mut affine = cairo::Matrix::identity();
        affine.translate(10.0, 10.0);
        affine.scale(0.40, 0.40);

        let mut ctx = Ctx {
            view_box_size: None,
            clipping_rect: None,
            affine: None,

            expected_view_box_size: Some((50.0, 50.0)),
            expected_clipping_rect: Some((0.0, 0.0, 50.0, 50.0)),
            expected_affine: Some(affine),
        };

        call_in_viewport(
            10.0,
            10.0,
            20.0,
            20.0,
            ClipMode::ClipToVbox,
            true,
            Some(ViewBox(cairo::Rectangle {
                x: 0.0,
                y: 0.0,
                width: 50.0,
                height: 50.0,
            })),
            AspectRatio::parse_str("xMidYMid meet", ()).unwrap(),
            cairo::Matrix::identity(),
            &mut ctx,
        );
    }
}
<commit_msg>viewport.rs: Inline everything into draw_in_viewport(); remove the tests (!)<commit_after>use cairo;
use cairo::MatrixTrait;

use aspect_ratio::AspectRatio;
use draw::add_clipping_rect;
use drawing_ctx::{self, RsvgDrawingCtx};
use float_eq_cairo::ApproxEqCairo;
use node::RsvgNode;
use state::ComputedValues;
use viewbox::*;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ClipMode {
    ClipToViewport,
    ClipToVbox,
}

pub fn draw_in_viewport<F>(
    vx: f64,
    vy: f64,
    vw: f64,
    vh: f64,
    clip_mode: ClipMode,
    do_clip: bool,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    node: &RsvgNode,
    values: &ComputedValues,
    mut affine: cairo::Matrix,
    draw_ctx: *mut RsvgDrawingCtx,
    clipping: bool,
    draw_fn: F,
) where
    F: FnOnce(),
{
    // width or height set to 0 disables rendering of the element
    // https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
    // https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
    // https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute

    if vw.approx_eq_cairo(&0.0) || vh.approx_eq_cairo(&0.0) {
        return;
    }

    drawing_ctx::push_discrete_layer(draw_ctx, values, clipping);

    if do_clip && clip_mode == ClipMode::ClipToViewport {
        drawing_ctx::get_cairo_context(draw_ctx).set_matrix(affine);
        add_clipping_rect(draw_ctx, vx, vy, vw, vh);
    }

    if let Some(vbox) = vbox {
        // the preserveAspectRatio attribute is only used if viewBox is specified
        // https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute

        if vbox.0.width.approx_eq_cairo(&0.0) || vbox.0.height.approx_eq_cairo(&0.0) {
            // Width or height of 0 for the viewBox disables rendering of the element
            // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
            return;
        }

        drawing_ctx::push_view_box(draw_ctx, vbox.0.width, vbox.0.height);

        let (x, y, w, h) =
            preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height, vx, vy, vw, vh);

        affine.translate(x, y);
        affine.scale(w / vbox.0.width, h / vbox.0.height);
        affine.translate(-vbox.0.x, -vbox.0.y);

        drawing_ctx::get_cairo_context(draw_ctx).set_matrix(affine);

        if do_clip && clip_mode == ClipMode::ClipToVbox {
            add_clipping_rect(draw_ctx, vbox.0.x, vbox.0.y, vbox.0.width, vbox.0.height);
        }
    } else {
        drawing_ctx::push_view_box(draw_ctx, vw, vh);

        affine.translate(vx, vy);
        drawing_ctx::get_cairo_context(draw_ctx).set_matrix(affine);
    }

    draw_fn();

    drawing_ctx::pop_view_box(draw_ctx);
    drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate atty;

use self::super::Size;
use self::libc::{c_ulong, c_ushort, STDOUT_FILENO};
use self::libc::ioctl;

#[cfg(not(target_os = "macos"))]
const TIOCGWINSZ: c_ulong = 0x00005413;

#[cfg(target_os = "macos")]
const TIOCGWINSZ: c_ulong = 0x40087468;

/// A representation of the size of the current terminal
#[repr(C)]
#[derive(Debug)]
pub struct UnixSize {
  /// number of rows
  pub rows: c_ushort,
  /// number of columns
  pub cols: c_ushort,
  x: c_ushort,
  y: c_ushort
}

/// Gets the current terminal size
pub fn get() -> Option<Size> {
    // http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc
    if atty::isnt() {
        return None;
    }
    let us = UnixSize { rows: 0, cols: 0, x: 0, y: 0 };
    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &us) };
    if r == 0 { Some(Size { rows: us.rows, cols: us.cols }) } else { None }
}

#[cfg(test)]
mod tests {
    use std::process::{Command, Output};
    use std::process::Stdio;
    use super::super::Size;
    use super::get;

    #[cfg(target_os = "macos")]
    fn stty_size() -> Output {
        Command::new("stty")
            .arg("-f").arg("/dev/stderr")
            .arg("size")
            .stderr(Stdio::inherit())
            .output()
            .unwrap()
    }

    #[cfg(not(target_os = "macos"))]
    fn stty_size() -> Output {
        Command::new("stty")
            .arg("-F").arg("/dev/stderr")
            .arg("size")
            .stderr(Stdio::inherit())
            .output()
            .unwrap()
    }

    #[test]
    fn test_shell() {
        let output = stty_size();
        assert!(output.status.success());
        let stdout = String::from_utf8(
             output.stdout
        ).unwrap();
        let mut data = stdout.split_whitespace();
        let rs = data.next().unwrap().parse::<u16>().unwrap();
        let cs = data.next().unwrap().parse::<u16>().unwrap();
        if let Some(Size { rows, cols }) = get() {
            assert_eq!(rows, rs);
            assert_eq!(cols, cs);
        }
    }
}
<commit_msg>import cleanup<commit_after>extern crate libc;
extern crate atty;

use self::super::Size;
use self::libc::{c_ulong, c_ushort, STDOUT_FILENO};
use self::libc::ioctl;

#[cfg(not(target_os = "macos"))]
const TIOCGWINSZ: c_ulong = 0x00005413;

#[cfg(target_os = "macos")]
const TIOCGWINSZ: c_ulong = 0x40087468;

/// A representation of the size of the current terminal
#[repr(C)]
#[derive(Debug)]
pub struct UnixSize {
  /// number of rows
  pub rows: c_ushort,
  /// number of columns
  pub cols: c_ushort,
  x: c_ushort,
  y: c_ushort
}

/// Gets the current terminal size
pub fn get() -> Option<Size> {
    // http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc
    if atty::isnt() {
        return None;
    }
    let us = UnixSize { rows: 0, cols: 0, x: 0, y: 0 };
    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &us) };
    if r == 0 { Some(Size { rows: us.rows, cols: us.cols }) } else { None }
}

#[cfg(test)]
mod tests {
    use std::process::{Command, Output, Stdio};
    use super::super::Size;
    use super::get;

    #[cfg(target_os = "macos")]
    fn stty_size() -> Output {
        Command::new("stty")
            .arg("-f").arg("/dev/stderr")
            .arg("size")
            .stderr(Stdio::inherit())
            .output()
            .unwrap()
    }

    #[cfg(not(target_os = "macos"))]
    fn stty_size() -> Output {
        Command::new("stty")
            .arg("-F").arg("/dev/stderr")
            .arg("size")
            .stderr(Stdio::inherit())
            .output()
            .unwrap()
    }

    #[test]
    fn test_shell() {
        let output = stty_size();
        assert!(output.status.success());
        let stdout = String::from_utf8(
             output.stdout
        ).unwrap();
        let mut data = stdout.split_whitespace();
        let rs = data.next().unwrap().parse::<u16>().unwrap();
        let cs = data.next().unwrap().parse::<u16>().unwrap();
        if let Some(Size { rows, cols }) = get() {
            assert_eq!(rows, rs);
            assert_eq!(cols, cs);
        }
    }
}
<|endoftext|>


<commit_before>use std::time::{SystemTime, UNIX_EPOCH};
use std::sync::{Mutex, Arc};
use std::cell::RefCell;
use std::str::FromStr;
use std::path::*;

pub mod block;
pub mod index;
pub mod store;

pub use self::store::BlockStore;
pub use self::index::Indexer;
pub use self::block::*;

use crypto::*;
use asset::*;
use tx::*;

pub struct Blockchain {
    indexer: Arc<Indexer>,
    store: Mutex<RefCell<BlockStore>>
}

impl Blockchain {

    ///
    /// Creates a new `Blockchain` with an associated indexer and backing
    /// storage is automatically created based on the given `path`.
    ///
    pub fn new(path: &Path) -> Blockchain {
        let indexer = Arc::new(Indexer::new(&Path::join(path, "index")));
        let store = BlockStore::new(&Path::join(path, "blklog"), Arc::clone(&indexer));
        Blockchain {
            indexer,
            store: Mutex::new(RefCell::new(store))
        }
    }

    #[inline(always)]
    pub fn get_bond(&self, minter: &PublicKey) -> Option<BondTx> {
        self.indexer.get_bond(minter)
    }

    #[inline(always)]
    pub fn get_chain_height(&self) -> u64 {
        self.indexer.get_chain_height()
    }

    pub fn get_chain_head(&self) -> Arc<SignedBlock> {
        let lock = self.store.lock().unwrap();
        let store = lock.borrow();
        let height = store.get_chain_height();
        store.get(height).expect("Failed to get blockchain head")
    }

    pub fn get_block(&self, height: u64) -> Option<Arc<SignedBlock>> {
        let lock = self.store.lock().unwrap();
        let store = lock.borrow();
        store.get(height)
    }

    pub fn insert_block(&self, block: SignedBlock) -> Result<(), &'static str> {
        self.verify_block(&block, &self.get_chain_head())?;
        for tx in &block.transactions {
            self.index_tx(tx);
        }

        let lock = self.store.lock().unwrap();
        let store = &mut lock.borrow_mut();
        store.insert(block);

        Ok(())
    }

    fn verify_block(&self, block: &SignedBlock, prev_block: &SignedBlock) -> Result<(), &'static str> {
        if prev_block.height + 1 != block.height {
            return Err("invalid block height")
        } else if !block.verify_tx_merkle_root() {
            return Err("invalid merkle root")
        } else if !block.verify_previous_hash(prev_block) {
            return Err("invalid previous hash")
        }

        if self.indexer.get_bond(&block.sig_pair.pub_key).is_none() {
            return Err("bond not found")
        } if !block.sig_pair.verify(block.calc_hash().as_ref()) {
            return Err("invalid bond signature")
        }

        for tx in &block.transactions {
            self.verify_tx(tx)?;
        }

        Ok(())
    }

    fn verify_tx(&self, tx: &TxVariant) -> Result<(), &'static str> {
        // TODO
        Ok(())
    }

    fn index_tx(&self, tx: &TxVariant) {
        match tx {
            TxVariant::BondTx(tx) => {
                let mut bal = self.indexer.get_balance(&tx.staker).unwrap_or_default();
                bal.sub(&tx.fee).sub(&tx.bond_fee).sub(&tx.stake_amt);
                self.indexer.set_balance(&tx.staker, &bal);
            },
            TxVariant::RewardTx(tx) => {
                let mut bal = self.indexer.get_balance(&tx.to).unwrap_or_default();
                for r in &tx.rewards {
                    bal.add(r);
                }
                self.indexer.set_balance(&tx.to, &bal);
            },
            TxVariant::TransferTx(tx) => {
                let mut from_bal = self.indexer.get_balance(&tx.from).unwrap_or_default();
                let mut to_bal = self.indexer.get_balance(&tx.to).unwrap_or_default();

                from_bal.sub(&tx.fee).sub(&tx.amount);
                to_bal.add(&tx.amount);

                self.indexer.set_balance(&tx.from, &from_bal);
                self.indexer.set_balance(&tx.to, &to_bal);
            }
        }
    }

    ///
    /// Create and store a generated genesis block. By default the provided
    /// `minter_key` will be the genesis minter and will stake with a small
    /// amount of GOLD tokens.
    ///
    pub fn create_genesis_block(&mut self, minter_key: &KeyPair) {
        use sodiumoxide::crypto::hash::sha256::Digest;

        info!("=> Generating new block chain");
        let staker_key = KeyPair::gen_keypair();
        info!("=> Staker private key: {}", staker_key.1.to_wif());
        info!("=> Staker public key: {}", staker_key.0.to_wif());

        let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as u32;

        let bond_tx = BondTx {
            base: Tx {
                tx_type: TxType::BOND,
                fee: Asset::from_str("0 GOLD").unwrap(),
                timestamp,
                signature_pairs: Vec::new()
            },
            minter: minter_key.0.clone(),
            staker: staker_key.0.clone(),
            bond_fee: EMPTY_GOLD,
            stake_amt: Asset::from_str("1 GOLD").unwrap()
        };

        let transactions = {
            let mut vec = Vec::new();
            vec.push(TxVariant::RewardTx(RewardTx {
                base: Tx {
                    tx_type: TxType::REWARD,
                    fee: Asset::from_str("0 GOLD").unwrap(),
                    timestamp,
                    signature_pairs: Vec::new()
                },
                to: staker_key.0.clone(),
                rewards: vec![Asset::from_str("1 GOLD").unwrap()]
            }));
            vec.push(TxVariant::BondTx(bond_tx.clone()));
            vec
        };

        let block = (Block {
            height: 0,
            previous_hash: Digest::from_slice(&[0u8; 32]).unwrap(),
            tx_merkle_root: Digest::from_slice(&[0u8; 32]).unwrap(),
            timestamp: timestamp as u32,
            transactions
        }).sign(&minter_key);

        let lock = self.store.lock().unwrap();
        let store = &mut lock.borrow_mut();
        store.insert_genesis(block);
        self.indexer.set_bond(&bond_tx);
    }
}
<commit_msg>Tidying and error handling improvements to block appending<commit_after>use std::time::{SystemTime, UNIX_EPOCH};
use std::sync::{Mutex, Arc};
use std::cell::RefCell;
use std::str::FromStr;
use std::path::*;

pub mod block;
pub mod index;
pub mod store;

pub use self::store::BlockStore;
pub use self::index::Indexer;
pub use self::block::*;

use crypto::*;
use asset::*;
use tx::*;

pub struct Blockchain {
    indexer: Arc<Indexer>,
    store: Mutex<RefCell<BlockStore>>
}

impl Blockchain {

    ///
    /// Creates a new `Blockchain` with an associated indexer and backing
    /// storage is automatically created based on the given `path`.
    ///
    pub fn new(path: &Path) -> Blockchain {
        let indexer = Arc::new(Indexer::new(&Path::join(path, "index")));
        let store = BlockStore::new(&Path::join(path, "blklog"), Arc::clone(&indexer));
        Blockchain {
            indexer,
            store: Mutex::new(RefCell::new(store))
        }
    }

    #[inline(always)]
    pub fn get_bond(&self, minter: &PublicKey) -> Option<BondTx> {
        self.indexer.get_bond(minter)
    }

    #[inline(always)]
    pub fn get_chain_height(&self) -> u64 {
        self.indexer.get_chain_height()
    }

    pub fn get_chain_head(&self) -> Arc<SignedBlock> {
        let lock = self.store.lock().unwrap();
        let store = lock.borrow();
        let height = store.get_chain_height();
        store.get(height).expect("Failed to get blockchain head")
    }

    pub fn get_block(&self, height: u64) -> Option<Arc<SignedBlock>> {
        let lock = self.store.lock().unwrap();
        let store = lock.borrow();
        store.get(height)
    }

    pub fn insert_block(&self, block: SignedBlock) -> Result<(), String> {
        self.verify_block(&block, &self.get_chain_head())?;
        for tx in &block.transactions { self.index_tx(tx); }

        let lock = self.store.lock().unwrap();
        let store = &mut lock.borrow_mut();
        store.insert(block);

        Ok(())
    }

    fn verify_block(&self, block: &SignedBlock, prev_block: &SignedBlock) -> Result<(), String> {
        if prev_block.height + 1 != block.height {
            return Err("invalid block height".to_owned())
        } else if !block.verify_tx_merkle_root() {
            return Err("invalid merkle root".to_owned())
        } else if !block.verify_previous_hash(prev_block) {
            return Err("invalid previous hash".to_owned())
        }

        if self.indexer.get_bond(&block.sig_pair.pub_key).is_none() {
            return Err("bond not found".to_owned())
        } else if !block.sig_pair.verify(block.calc_hash().as_ref()) {
            return Err("invalid bond signature".to_owned())
        }

        for tx in &block.transactions {
            if let Err(s) = self.verify_tx(tx) {
                return Err(format!("tx verification failed: {}", s))
            }
        }

        Ok(())
    }

    fn verify_tx(&self, tx: &TxVariant) -> Result<(), String> {
        match tx {
            TxVariant::RewardTx(tx) => {
                if tx.signature_pairs.len() != 0 {
                    return Err("reward transaction must not be signed".to_owned())
                }
            },
            TxVariant::BondTx(tx) => {
                // TODO get address fee
                // TODO validate bond fee is sufficient
                // TODO validate stake amt is greater than 0
            },
            TxVariant::TransferTx(tx) => {
                // TODO get address fee
                // TODO validate "from" has enough balance
            }
        }
        Ok(())
    }

    fn index_tx(&self, tx: &TxVariant) {
        match tx {
            TxVariant::RewardTx(tx) => {
                let mut bal = self.indexer.get_balance(&tx.to).unwrap_or_default();
                for r in &tx.rewards {
                    bal.add(r);
                }
                self.indexer.set_balance(&tx.to, &bal);
            },
            TxVariant::BondTx(tx) => {
                let mut bal = self.indexer.get_balance(&tx.staker).unwrap_or_default();
                bal.sub(&tx.fee).sub(&tx.bond_fee).sub(&tx.stake_amt);
                self.indexer.set_balance(&tx.staker, &bal);
            },
            TxVariant::TransferTx(tx) => {
                let mut from_bal = self.indexer.get_balance(&tx.from).unwrap_or_default();
                let mut to_bal = self.indexer.get_balance(&tx.to).unwrap_or_default();

                from_bal.sub(&tx.fee).sub(&tx.amount);
                to_bal.add(&tx.amount);

                self.indexer.set_balance(&tx.from, &from_bal);
                self.indexer.set_balance(&tx.to, &to_bal);
            }
        }
    }

    ///
    /// Create and store a generated genesis block. By default the provided
    /// `minter_key` will be the genesis minter and will stake with a small
    /// amount of GOLD tokens.
    ///
    pub fn create_genesis_block(&mut self, minter_key: &KeyPair) {
        use sodiumoxide::crypto::hash::sha256::Digest;

        info!("=> Generating new block chain");
        let staker_key = KeyPair::gen_keypair();
        info!("=> Staker private key: {}", staker_key.1.to_wif());
        info!("=> Staker public key: {}", staker_key.0.to_wif());

        let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as u32;

        let bond_tx = BondTx {
            base: Tx {
                tx_type: TxType::BOND,
                fee: Asset::from_str("0 GOLD").unwrap(),
                timestamp,
                signature_pairs: Vec::new()
            },
            minter: minter_key.0.clone(),
            staker: staker_key.0.clone(),
            bond_fee: EMPTY_GOLD,
            stake_amt: Asset::from_str("1 GOLD").unwrap()
        };

        let transactions = {
            let mut vec = Vec::new();
            vec.push(TxVariant::RewardTx(RewardTx {
                base: Tx {
                    tx_type: TxType::REWARD,
                    fee: Asset::from_str("0 GOLD").unwrap(),
                    timestamp,
                    signature_pairs: Vec::new()
                },
                to: staker_key.0.clone(),
                rewards: vec![Asset::from_str("1 GOLD").unwrap()]
            }));
            vec.push(TxVariant::BondTx(bond_tx.clone()));
            vec
        };

        let block = (Block {
            height: 0,
            previous_hash: Digest::from_slice(&[0u8; 32]).unwrap(),
            tx_merkle_root: Digest::from_slice(&[0u8; 32]).unwrap(),
            timestamp: timestamp as u32,
            transactions
        }).sign(&minter_key);

        let lock = self.store.lock().unwrap();
        let store = &mut lock.borrow_mut();
        store.insert_genesis(block);
        self.indexer.set_bond(&bond_tx);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Arun Raghavan <arun@asymptotic.io>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ffv1::constants::{RGB, YCBCR};
use ffv1::decoder::{Decoder, Frame};
use ffv1::record::ConfigRecord;

use gst::glib;
use gst::prelude::*;
use gst::subclass::prelude::*;
use gst_video::prelude::*;
use gst_video::subclass::prelude::*;
use gst_video::VideoFormat;

use once_cell::sync::Lazy;
use std::sync::Mutex;

enum DecoderState {
    Stopped,
    Started {
        output_info: Option<gst_video::VideoInfo>,
        decoder: Box<Decoder>,
    },
}

impl Default for DecoderState {
    fn default() -> Self {
        DecoderState::Stopped
    }
}

#[derive(Default)]
pub struct Ffv1Dec {
    state: Mutex<DecoderState>,
}

fn get_all_video_formats() -> Vec<glib::SendValue> {
    let values = [
        VideoFormat::Gray8,
        // VideoFormat::Gray16Le,
        // VideoFormat::Gray16Be,
        VideoFormat::Y444,
        // VideoFormat::Y44410le,
        // VideoFormat::Y44410be,
        // VideoFormat::A44410le,
        // VideoFormat::A44410be,
        // VideoFormat::Y44412le,
        // VideoFormat::Y44412be,
        // VideoFormat::Y44416le,
        // VideoFormat::Y44416be,
        VideoFormat::A420,
        VideoFormat::Y42b,
        // VideoFormat::I42210le,
        // VideoFormat::I42210be,
        // VideoFormat::A42210le,
        // VideoFormat::A42210be,
        // VideoFormat::I42212le,
        // VideoFormat::I42212be,
        VideoFormat::I420,
        // VideoFormat::I42010le,
        // VideoFormat::I42010be,
        // VideoFormat::I42012le,
        // VideoFormat::I42012be,
        VideoFormat::Gbra,
        VideoFormat::Gbr,
        // VideoFormat::Gbr10le,
        // VideoFormat::Gbr10be,
        // VideoFormat::Gbra10le,
        // VideoFormat::Gbra10be,
        // VideoFormat::Gbr12le,
        // VideoFormat::Gbr12be,
        // VideoFormat::Gbra12le,
        // VideoFormat::Gbra12be,
    ];

    values.iter().map(|i| i.to_str().to_send_value()).collect()
}

fn get_output_format(record: &ConfigRecord) -> Option<VideoFormat> {
    const IS_LITTLE_ENDIAN: bool = cfg!(target_endian = "little");

    match record.colorspace_type as usize {
        YCBCR => match (
            record.chroma_planes,
            record.log2_v_chroma_subsample,
            record.log2_h_chroma_subsample,
            record.bits_per_raw_sample,
            record.extra_plane,
            IS_LITTLE_ENDIAN,
        ) {
            // Interpret luma-only as grayscale
            (false, _, _, 8, false, _) => Some(VideoFormat::Gray8),
            // (false, _, _, 16, false, true) => Some(VideoFormat::Gray16Le),
            // (false, _, _, 16, false, false) => Some(VideoFormat::Gray16Be),
            // 4:4:4
            (true, 4, 4, 8, false, _) => Some(VideoFormat::Y444),
            // (true, 4, 4, 10, false, true) => Some(VideoFormat::Y44410le),
            // (true, 4, 4, 10, false, false) => Some(VideoFormat::Y44410be),
            // (true, 4, 4, 10, true, true) => Some(VideoFormat::A44410le),
            // (true, 4, 4, 10, true, false) => Some(VideoFormat::A44410be),
            // (true, 4, 4, 12, false, true) => Some(VideoFormat::Y44412le),
            // (true, 4, 4, 12, false, false) => Some(VideoFormat::Y44412be),
            // (true, 4, 4, 16, false, true) => Some(VideoFormat::Y44416le),
            // (true, 4, 4, 16, false, false) => Some(VideoFormat::Y44416be),
            // 4:2:2
            (true, 2, 2, 8, false, _) => Some(VideoFormat::Y42b),
            // (true, 2, 2, 10, false, true) => Some(VideoFormat::I42210le),
            // (true, 2, 2, 10, false, false) => Some(VideoFormat::I42210be),
            // (true, 2, 2, 10, true, true) => Some(VideoFormat::A42210le),
            // (true, 2, 2, 10, true, false) => Some(VideoFormat::A42210be),
            // (true, 2, 2, 12, false, true) => Some(VideoFormat::I42212le),
            // (true, 2, 2, 12, false, false) => Some(VideoFormat::I42212be),
            // 4:2:0
            (true, 1, 1, 8, false, _) => Some(VideoFormat::I420),
            (true, 1, 1, 8, true, _) => Some(VideoFormat::A420),
            // (true, 1, 1, 10, false, true) => Some(VideoFormat::I42010le),
            // (true, 1, 1, 10, false, false) => Some(VideoFormat::I42010be),
            // (true, 1, 1, 12, false, true) => Some(VideoFormat::I42012le),
            // (true, 1, 1, 12, false, false) => Some(VideoFormat::I42012be),
            // Nothing matched
            (_, _, _, _, _, _) => None,
        },
        RGB => match (
            record.bits_per_raw_sample,
            record.extra_plane,
            IS_LITTLE_ENDIAN,
        ) {
            (8, true, _) => Some(VideoFormat::Gbra),
            (8, false, _) => Some(VideoFormat::Gbr),
            // (10, false, true) => Some(VideoFormat::Gbr10le),
            // (10, false, false) => Some(VideoFormat::Gbr10be),
            // (10, true, true) => Some(VideoFormat::Gbra10le),
            // (10, true, false) => Some(VideoFormat::Gbra10be),
            // (12, false, true) => Some(VideoFormat::Gbr12le),
            // (12, false, false) => Some(VideoFormat::Gbr12be),
            // (12, true, true) => Some(VideoFormat::Gbra12le),
            // (12, true, false) => Some(VideoFormat::Gbra12be),
            (_, _, _) => None,
        },
        _ => panic!("Unknown color_space type"),
    }
}

impl Ffv1Dec {
    // FIXME: Implement other pixel depths
    pub fn get_decoded_frame(
        &self,
        mut decoded_frame: Frame,
        output_info: &gst_video::VideoInfo,
    ) -> gst::Buffer {
        let mut buf = gst::Buffer::new();
        let mut_buf = buf.make_mut();
        let format_info = output_info.format_info();

        // Greater depths are not yet supported
        assert_eq!(decoded_frame.bit_depth, 8);

        for (plane, decoded_plane) in decoded_frame.buf.drain(..).enumerate() {
            let component = format_info
                .plane()
                .iter()
                .position(|&p| p == plane as u32)
                .unwrap() as u8;

            let comp_height = format_info.scale_height(component, output_info.height()) as usize;
            let src_stride = decoded_plane.len() / comp_height;
            let dest_stride = output_info.stride()[plane] as usize;

            // FIXME: we can also do this if we have video meta support and differing strides
            let mem = if src_stride == dest_stride {
                // Just wrap the decoded frame vecs and push them out
                gst::Memory::from_mut_slice(decoded_plane)
            } else {
                // Mismatched stride, let's copy
                let out_plane = gst::Memory::with_size(dest_stride * comp_height);
                let mut out_plane_mut = out_plane.into_mapped_memory_writable().unwrap();

                for (in_line, out_line) in decoded_plane
                    .as_slice()
                    .chunks_exact(src_stride)
                    .zip(out_plane_mut.as_mut_slice().chunks_exact_mut(dest_stride))
                {
                    out_line[..src_stride].copy_from_slice(in_line);
                }

                out_plane_mut.into_memory()
            };

            mut_buf.append_memory(mem);
        }

        // FIXME: attach video meta if supported

        buf
    }
}

static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
    gst::DebugCategory::new(
        "ffv1dec",
        gst::DebugColorFlags::empty(),
        Some("FFV1 decoder"),
    )
});

#[glib::object_subclass]
impl ObjectSubclass for Ffv1Dec {
    const NAME: &'static str = "Ffv1Dec";
    type Type = super::Ffv1Dec;
    type ParentType = gst_video::VideoDecoder;
}

impl ObjectImpl for Ffv1Dec {}

impl ElementImpl for Ffv1Dec {
    fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
        static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
            gst::subclass::ElementMetadata::new(
                "FFV1 Decoder",
                "Codec/Decoder/Video",
                "Decode FFV1 video streams",
                "Arun Raghavan <arun@asymptotic.io>",
            )
        });

        Some(&*ELEMENT_METADATA)
    }

    fn pad_templates() -> &'static [gst::PadTemplate] {
        static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
            let sink_caps = gst::Caps::builder("video/x-ffv")
                .field("ffvversion", &1)
                .field("width", &gst::IntRange::<i32>::new(1, i32::MAX))
                .field("height", &gst::IntRange::<i32>::new(1, i32::MAX))
                .field(
                    "framerate",
                    &gst::FractionRange::new(
                        gst::Fraction::new(0, 1),
                        gst::Fraction::new(i32::MAX, 1),
                    ),
                )
                .build();
            let sink_pad_template = gst::PadTemplate::new(
                "sink",
                gst::PadDirection::Sink,
                gst::PadPresence::Always,
                &sink_caps,
            )
            .unwrap();

            let src_caps = gst::Caps::builder("video/x-raw")
                .field("format", &gst::List::from_owned(get_all_video_formats()))
                .field("width", &gst::IntRange::<i32>::new(1, i32::MAX))
                .field("height", &gst::IntRange::<i32>::new(1, i32::MAX))
                .field(
                    "framerate",
                    &gst::FractionRange::new(
                        gst::Fraction::new(0, 1),
                        gst::Fraction::new(i32::MAX, 1),
                    ),
                )
                .build();
            let src_pad_template = gst::PadTemplate::new(
                "src",
                gst::PadDirection::Src,
                gst::PadPresence::Always,
                &src_caps,
            )
            .unwrap();

            vec![sink_pad_template, src_pad_template]
        });

        &*PAD_TEMPLATES
    }
}

impl VideoDecoderImpl for Ffv1Dec {
    /* We allocate the decoder here rather than start() because we need the sink caps */
    fn set_format(
        &self,
        element: &super::Ffv1Dec,
        state: &gst_video::VideoCodecState<'static, gst_video::video_codec_state::Readable>,
    ) -> Result<(), gst::LoggableError> {
        let info = state.info();
        let codec_data = state
            .codec_data()
            .ok_or_else(|| gst::loggable_error!(CAT, "Missing codec_data"))?
            .map_readable()?;
        let decoder = Decoder::new(codec_data.as_slice(), info.width(), info.height())
            .map_err(|err| gst::loggable_error!(CAT, "Could not instantiate decoder: {}", err))?;

        let format = get_output_format(decoder.config_record())
            .ok_or_else(|| gst::loggable_error!(CAT, "Unsupported format"))?;

        let output_state = element
            .set_output_state(format, info.width(), info.height(), Some(state))
            .map_err(|err| gst::loggable_error!(CAT, "Failed to set output params: {}", err))?;

        let output_info = Some(output_state.info());

        element
            .negotiate(output_state)
            .map_err(|err| gst::loggable_error!(CAT, "Negotiation failed: {}", err))?;

        let mut decoder_state = self.state.lock().unwrap();
        *decoder_state = DecoderState::Started {
            output_info,
            decoder: Box::new(decoder),
        };

        self.parent_set_format(element, state)
    }

    fn stop(&self, element: &super::Ffv1Dec) -> Result<(), gst::ErrorMessage> {
        let mut decoder_state = self.state.lock().unwrap();
        *decoder_state = DecoderState::Stopped;

        self.parent_stop(element)
    }

    fn handle_frame(
        &self,
        element: &super::Ffv1Dec,
        mut frame: gst_video::VideoCodecFrame,
    ) -> Result<gst::FlowSuccess, gst::FlowError> {
        let mut state = self.state.lock().unwrap();

        let (output_info, decoder) = match *state {
            DecoderState::Stopped => Err(gst::FlowError::Error),
            DecoderState::Started {
                ref mut output_info,
                ref mut decoder,
            } => Ok((output_info, decoder)),
        }?;

        let input_buffer = frame
            .input_buffer()
            .expect("Frame must have input buffer")
            .map_readable()
            .expect("Could not map input buffer for read");

        let decoded_frame = decoder.decode_frame(input_buffer.as_slice()).map_err(|e| {
            gst::gst_error!(CAT, "Decoding failed: {}", e);
            gst::FlowError::Error
        })?;

        // Drop so we can mutably borrow frame later
        drop(input_buffer);

        //  * Make sure the decoder and output plane orders match for all cases
        let buf = self.get_decoded_frame(decoded_frame, output_info.as_ref().unwrap());

        // We no longer need the state lock
        drop(state);

        frame.set_output_buffer(buf);
        element.finish_frame(frame)?;

        Ok(gst::FlowSuccess::Ok)
    }
}
<commit_msg>ffv1dec: Drop decoder state before calling VideoDecoder::negotiate()<commit_after>// Copyright (C) 2020 Arun Raghavan <arun@asymptotic.io>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ffv1::constants::{RGB, YCBCR};
use ffv1::decoder::{Decoder, Frame};
use ffv1::record::ConfigRecord;

use gst::glib;
use gst::prelude::*;
use gst::subclass::prelude::*;
use gst_video::prelude::*;
use gst_video::subclass::prelude::*;
use gst_video::VideoFormat;

use once_cell::sync::Lazy;
use std::sync::Mutex;

enum DecoderState {
    Stopped,
    Started {
        output_info: Option<gst_video::VideoInfo>,
        decoder: Box<Decoder>,
    },
}

impl Default for DecoderState {
    fn default() -> Self {
        DecoderState::Stopped
    }
}

#[derive(Default)]
pub struct Ffv1Dec {
    state: Mutex<DecoderState>,
}

fn get_all_video_formats() -> Vec<glib::SendValue> {
    let values = [
        VideoFormat::Gray8,
        // VideoFormat::Gray16Le,
        // VideoFormat::Gray16Be,
        VideoFormat::Y444,
        // VideoFormat::Y44410le,
        // VideoFormat::Y44410be,
        // VideoFormat::A44410le,
        // VideoFormat::A44410be,
        // VideoFormat::Y44412le,
        // VideoFormat::Y44412be,
        // VideoFormat::Y44416le,
        // VideoFormat::Y44416be,
        VideoFormat::A420,
        VideoFormat::Y42b,
        // VideoFormat::I42210le,
        // VideoFormat::I42210be,
        // VideoFormat::A42210le,
        // VideoFormat::A42210be,
        // VideoFormat::I42212le,
        // VideoFormat::I42212be,
        VideoFormat::I420,
        // VideoFormat::I42010le,
        // VideoFormat::I42010be,
        // VideoFormat::I42012le,
        // VideoFormat::I42012be,
        VideoFormat::Gbra,
        VideoFormat::Gbr,
        // VideoFormat::Gbr10le,
        // VideoFormat::Gbr10be,
        // VideoFormat::Gbra10le,
        // VideoFormat::Gbra10be,
        // VideoFormat::Gbr12le,
        // VideoFormat::Gbr12be,
        // VideoFormat::Gbra12le,
        // VideoFormat::Gbra12be,
    ];

    values.iter().map(|i| i.to_str().to_send_value()).collect()
}

fn get_output_format(record: &ConfigRecord) -> Option<VideoFormat> {
    const IS_LITTLE_ENDIAN: bool = cfg!(target_endian = "little");

    match record.colorspace_type as usize {
        YCBCR => match (
            record.chroma_planes,
            record.log2_v_chroma_subsample,
            record.log2_h_chroma_subsample,
            record.bits_per_raw_sample,
            record.extra_plane,
            IS_LITTLE_ENDIAN,
        ) {
            // Interpret luma-only as grayscale
            (false, _, _, 8, false, _) => Some(VideoFormat::Gray8),
            // (false, _, _, 16, false, true) => Some(VideoFormat::Gray16Le),
            // (false, _, _, 16, false, false) => Some(VideoFormat::Gray16Be),
            // 4:4:4
            (true, 4, 4, 8, false, _) => Some(VideoFormat::Y444),
            // (true, 4, 4, 10, false, true) => Some(VideoFormat::Y44410le),
            // (true, 4, 4, 10, false, false) => Some(VideoFormat::Y44410be),
            // (true, 4, 4, 10, true, true) => Some(VideoFormat::A44410le),
            // (true, 4, 4, 10, true, false) => Some(VideoFormat::A44410be),
            // (true, 4, 4, 12, false, true) => Some(VideoFormat::Y44412le),
            // (true, 4, 4, 12, false, false) => Some(VideoFormat::Y44412be),
            // (true, 4, 4, 16, false, true) => Some(VideoFormat::Y44416le),
            // (true, 4, 4, 16, false, false) => Some(VideoFormat::Y44416be),
            // 4:2:2
            (true, 2, 2, 8, false, _) => Some(VideoFormat::Y42b),
            // (true, 2, 2, 10, false, true) => Some(VideoFormat::I42210le),
            // (true, 2, 2, 10, false, false) => Some(VideoFormat::I42210be),
            // (true, 2, 2, 10, true, true) => Some(VideoFormat::A42210le),
            // (true, 2, 2, 10, true, false) => Some(VideoFormat::A42210be),
            // (true, 2, 2, 12, false, true) => Some(VideoFormat::I42212le),
            // (true, 2, 2, 12, false, false) => Some(VideoFormat::I42212be),
            // 4:2:0
            (true, 1, 1, 8, false, _) => Some(VideoFormat::I420),
            (true, 1, 1, 8, true, _) => Some(VideoFormat::A420),
            // (true, 1, 1, 10, false, true) => Some(VideoFormat::I42010le),
            // (true, 1, 1, 10, false, false) => Some(VideoFormat::I42010be),
            // (true, 1, 1, 12, false, true) => Some(VideoFormat::I42012le),
            // (true, 1, 1, 12, false, false) => Some(VideoFormat::I42012be),
            // Nothing matched
            (_, _, _, _, _, _) => None,
        },
        RGB => match (
            record.bits_per_raw_sample,
            record.extra_plane,
            IS_LITTLE_ENDIAN,
        ) {
            (8, true, _) => Some(VideoFormat::Gbra),
            (8, false, _) => Some(VideoFormat::Gbr),
            // (10, false, true) => Some(VideoFormat::Gbr10le),
            // (10, false, false) => Some(VideoFormat::Gbr10be),
            // (10, true, true) => Some(VideoFormat::Gbra10le),
            // (10, true, false) => Some(VideoFormat::Gbra10be),
            // (12, false, true) => Some(VideoFormat::Gbr12le),
            // (12, false, false) => Some(VideoFormat::Gbr12be),
            // (12, true, true) => Some(VideoFormat::Gbra12le),
            // (12, true, false) => Some(VideoFormat::Gbra12be),
            (_, _, _) => None,
        },
        _ => panic!("Unknown color_space type"),
    }
}

impl Ffv1Dec {
    // FIXME: Implement other pixel depths
    pub fn get_decoded_frame(
        &self,
        mut decoded_frame: Frame,
        output_info: &gst_video::VideoInfo,
    ) -> gst::Buffer {
        let mut buf = gst::Buffer::new();
        let mut_buf = buf.make_mut();
        let format_info = output_info.format_info();

        // Greater depths are not yet supported
        assert_eq!(decoded_frame.bit_depth, 8);

        for (plane, decoded_plane) in decoded_frame.buf.drain(..).enumerate() {
            let component = format_info
                .plane()
                .iter()
                .position(|&p| p == plane as u32)
                .unwrap() as u8;

            let comp_height = format_info.scale_height(component, output_info.height()) as usize;
            let src_stride = decoded_plane.len() / comp_height;
            let dest_stride = output_info.stride()[plane] as usize;

            // FIXME: we can also do this if we have video meta support and differing strides
            let mem = if src_stride == dest_stride {
                // Just wrap the decoded frame vecs and push them out
                gst::Memory::from_mut_slice(decoded_plane)
            } else {
                // Mismatched stride, let's copy
                let out_plane = gst::Memory::with_size(dest_stride * comp_height);
                let mut out_plane_mut = out_plane.into_mapped_memory_writable().unwrap();

                for (in_line, out_line) in decoded_plane
                    .as_slice()
                    .chunks_exact(src_stride)
                    .zip(out_plane_mut.as_mut_slice().chunks_exact_mut(dest_stride))
                {
                    out_line[..src_stride].copy_from_slice(in_line);
                }

                out_plane_mut.into_memory()
            };

            mut_buf.append_memory(mem);
        }

        // FIXME: attach video meta if supported

        buf
    }
}

static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
    gst::DebugCategory::new(
        "ffv1dec",
        gst::DebugColorFlags::empty(),
        Some("FFV1 decoder"),
    )
});

#[glib::object_subclass]
impl ObjectSubclass for Ffv1Dec {
    const NAME: &'static str = "Ffv1Dec";
    type Type = super::Ffv1Dec;
    type ParentType = gst_video::VideoDecoder;
}

impl ObjectImpl for Ffv1Dec {}

impl ElementImpl for Ffv1Dec {
    fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
        static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
            gst::subclass::ElementMetadata::new(
                "FFV1 Decoder",
                "Codec/Decoder/Video",
                "Decode FFV1 video streams",
                "Arun Raghavan <arun@asymptotic.io>",
            )
        });

        Some(&*ELEMENT_METADATA)
    }

    fn pad_templates() -> &'static [gst::PadTemplate] {
        static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
            let sink_caps = gst::Caps::builder("video/x-ffv")
                .field("ffvversion", &1)
                .field("width", &gst::IntRange::<i32>::new(1, i32::MAX))
                .field("height", &gst::IntRange::<i32>::new(1, i32::MAX))
                .field(
                    "framerate",
                    &gst::FractionRange::new(
                        gst::Fraction::new(0, 1),
                        gst::Fraction::new(i32::MAX, 1),
                    ),
                )
                .build();
            let sink_pad_template = gst::PadTemplate::new(
                "sink",
                gst::PadDirection::Sink,
                gst::PadPresence::Always,
                &sink_caps,
            )
            .unwrap();

            let src_caps = gst::Caps::builder("video/x-raw")
                .field("format", &gst::List::from_owned(get_all_video_formats()))
                .field("width", &gst::IntRange::<i32>::new(1, i32::MAX))
                .field("height", &gst::IntRange::<i32>::new(1, i32::MAX))
                .field(
                    "framerate",
                    &gst::FractionRange::new(
                        gst::Fraction::new(0, 1),
                        gst::Fraction::new(i32::MAX, 1),
                    ),
                )
                .build();
            let src_pad_template = gst::PadTemplate::new(
                "src",
                gst::PadDirection::Src,
                gst::PadPresence::Always,
                &src_caps,
            )
            .unwrap();

            vec![sink_pad_template, src_pad_template]
        });

        &*PAD_TEMPLATES
    }
}

impl VideoDecoderImpl for Ffv1Dec {
    /* We allocate the decoder here rather than start() because we need the sink caps */
    fn set_format(
        &self,
        element: &super::Ffv1Dec,
        state: &gst_video::VideoCodecState<'static, gst_video::video_codec_state::Readable>,
    ) -> Result<(), gst::LoggableError> {
        let info = state.info();
        let codec_data = state
            .codec_data()
            .ok_or_else(|| gst::loggable_error!(CAT, "Missing codec_data"))?
            .map_readable()?;
        let decoder = Decoder::new(codec_data.as_slice(), info.width(), info.height())
            .map_err(|err| gst::loggable_error!(CAT, "Could not instantiate decoder: {}", err))?;

        let format = get_output_format(decoder.config_record())
            .ok_or_else(|| gst::loggable_error!(CAT, "Unsupported format"))?;

        let output_state = element
            .set_output_state(format, info.width(), info.height(), Some(state))
            .map_err(|err| gst::loggable_error!(CAT, "Failed to set output params: {}", err))?;

        let output_info = Some(output_state.info());

        let mut decoder_state = self.state.lock().unwrap();
        *decoder_state = DecoderState::Started {
            output_info,
            decoder: Box::new(decoder),
            video_meta_supported: false,
        };
        drop(decoder_state);

        element
            .negotiate(output_state)
            .map_err(|err| gst::loggable_error!(CAT, "Negotiation failed: {}", err))?;

        self.parent_set_format(element, state)
    }

    fn stop(&self, element: &super::Ffv1Dec) -> Result<(), gst::ErrorMessage> {
        let mut decoder_state = self.state.lock().unwrap();
        *decoder_state = DecoderState::Stopped;

        self.parent_stop(element)
    }

    fn handle_frame(
        &self,
        element: &super::Ffv1Dec,
        mut frame: gst_video::VideoCodecFrame,
    ) -> Result<gst::FlowSuccess, gst::FlowError> {
        let mut state = self.state.lock().unwrap();

        let (output_info, decoder) = match *state {
            DecoderState::Stopped => Err(gst::FlowError::Error),
            DecoderState::Started {
                ref mut output_info,
                ref mut decoder,
            } => Ok((output_info, decoder)),
        }?;

        let input_buffer = frame
            .input_buffer()
            .expect("Frame must have input buffer")
            .map_readable()
            .expect("Could not map input buffer for read");

        let decoded_frame = decoder.decode_frame(input_buffer.as_slice()).map_err(|e| {
            gst::gst_error!(CAT, "Decoding failed: {}", e);
            gst::FlowError::Error
        })?;

        // Drop so we can mutably borrow frame later
        drop(input_buffer);

        //  * Make sure the decoder and output plane orders match for all cases
        let buf = self.get_decoded_frame(decoded_frame, output_info.as_ref().unwrap());

        // We no longer need the state lock
        drop(state);

        frame.set_output_buffer(buf);
        element.finish_frame(frame)?;

        Ok(gst::FlowSuccess::Ok)
    }
}
<|endoftext|>