<commit_before>use rand::random;
use std::collections::HashMap;

#[derive(Debug,PartialEq)]
pub struct SrcBlock {
    pub name: String,
    pub src: Vec<SrcKind>
}

#[derive(Debug,PartialEq)]
pub struct DefBlock {
    pub name: String,
    pub defs: Vec<(String,VarKind)>
}

#[derive(Debug,PartialEq)]
pub enum BlockKind {
    Src(SrcBlock),
    Def(DefBlock),
}

/// delimited by new line
#[derive(Debug,PartialEq)]
pub enum SrcKind {
    Logic(String, LogicKind), // ex: item_logic has_item

    // references logic in env and emits varkinds;
    // logic must resolve to true
    // ex: if item_logic give_quest
    // Can optionally end execution and begin next node
    If(ExpectKind, Vec<VarKind>, Option<String>),

    Composite(String,ExpectKind,Vec<String>),
    Next(String), // ends execution and begins next node
}

#[derive(Debug,PartialEq)]
pub enum ExpectKind {
    All,
    Any,
    None,

    Ref(String) // references env variable set from logic
}
impl ExpectKind {
    pub fn parse(s: String) -> ExpectKind {
        match &s[..] {
            "all" => ExpectKind::All,
            "any" => ExpectKind::Any,
            "none" => ExpectKind::None,
            _ => ExpectKind::Ref(s),
        }
    }
}

impl SrcKind {
    fn eval<D:Eval> (&self, state: &mut HashMap<String,bool>, data: &D)
                     -> (Vec<VarKind>,Option<String>)
    {
        match self {
            &SrcKind::Next(ref node) => {
                return (vec![],Some(node.clone()))
            },
            &SrcKind::Logic(ref name, ref logic) => { //logic updates state
                let name = name.clone();
                match logic {
                    &LogicKind::Is(ref lookup) => {
                        let r = data.eval(&lookup);
                        if r.is_some() {
                            match r.unwrap() {
                                VarKind::Bool(v) => { state.insert(name,v); },
                                _ => { state.insert(name,true); }, //if exists?
                            }
                        }
                    },
                    &LogicKind::IsNot(ref lookup) => { //inverse state
                        let r = data.eval(&lookup);
                        if r.is_some() {
                            match r.unwrap() {
                                VarKind::Bool(v) => {
                                    if !v { state.insert(name,true); }
                                },
                                _ => { state.insert(name,false); },
                            }
                        }
                    },

                    &LogicKind::GT(ref left, ref right) => {
                        let right = VarKind::get_num::<D>(right,data);
                        let left = VarKind::get_num::<D>(left,data);

                        if left.is_ok() && right.is_ok() {
                            state.insert(name, left.unwrap() > right.unwrap());
                        }
                    },
                    &LogicKind::LT(ref left, ref right) => {
                        let right = VarKind::get_num::<D>(right,data);
                        let left = VarKind::get_num::<D>(left,data);

                        if left.is_ok() && right.is_ok() {
                            state.insert(name, left.unwrap() < right.unwrap());
                        }
                    },
                }

                return (vec![],None) // logic does not return anything
            },
            &SrcKind::Composite(ref name, ref x, ref lookups) => {
                let mut comp_value = false;
                match x {
                    &ExpectKind::All => { // all must pass as true
                        for lookup in lookups.iter() {
                            let val = state.get(lookup);
                            if val.is_some() && *val.unwrap() {
                                comp_value = true;
                            }
                            else { comp_value = false; break }
                        }

                        state.insert(name.clone(),comp_value);
                    },
                    &ExpectKind::Any => { // first truth passes for set
                        for lookup in lookups.iter() {
                            let val = state.get(lookup);
                            if val.is_some() && *val.unwrap() {
                                comp_value = true;
                                break;
                            }
                        }

                        state.insert(name.clone(),comp_value);
                    },
                    &ExpectKind::None => { // inverse of any, none must be true
                        for lookup in lookups.iter() {
                            let val = state.get(lookup);
                            if val.is_some() && *val.unwrap() {
                                comp_value = false;
                                break;
                            }
                        }

                        state.insert(name.clone(),comp_value);
                    },
                    &ExpectKind::Ref(_) => panic!("ERROR: Unexpected parsing") // this should never hit
                }

                return (vec![],None) // composite does not return anything
            },
            &SrcKind::If(ref x, ref v, ref node) => {
                let mut if_value = false;
                match x {
                    &ExpectKind::All => {
                        for n in state.values() {
                            if !n { if_value = false; break }
                            else { if_value = true; }
                        }
                    },
                    &ExpectKind::Any => {
                        for n in state.values() {
                            if *n { if_value = true; break }
                        }
                    },
                    &ExpectKind::None => {
                        for n in state.values() {
                            if !n { if_value = true; }
                            else { if_value = true; break }
                        }
                    },
                    &ExpectKind::Ref(ref lookup) => {
                        let val = state.get(lookup);
                        if let Some(val) = val {
                            if_value = *val;
                        }
                    },
                }

                if if_value { return ((*v).clone(),node.clone()) }
                else { return (vec![],None) }
            }
        }
    }

    pub fn parse(mut exp: Vec<String>) -> SrcKind {
        if exp[0] == "if" {
            if exp.len() < 3 { panic!("ERROR: Invalid IF Logic {:?}",exp) }

            let x = exp.remove(1);

            let mut node = None;
            if exp.len() > 2 {
                let next = &exp[exp.len() - 2] == "next";
                if next {
                    node = exp.pop();
                    let _ = exp.pop(); // remove next tag
                }
            }

            let v = exp.drain(1..).map(|n| VarKind::parse(n)).collect();
            SrcKind::If(ExpectKind::parse(x),
                        v, node)
        }
        else if exp[0] == "next" {
            if exp.len() == 2 {
                SrcKind::Next(exp.pop().unwrap())
            }
            else { panic!("ERROR: Uneven NEXT Logic {:?}",exp) }
        }
        else {
            let keys = exp.remove(0);
            let mut keys: Vec<&str> = keys.split_terminator(':').collect();

            if keys.len() < 2 { // regular logic
                SrcKind::Logic(keys.pop().unwrap().to_owned(),
                               LogicKind::parse(exp))
            }
            else { // composite type
                let kind = ExpectKind::parse(keys.pop().unwrap().to_owned());
                match kind { // only formal expected types allowed
                    ExpectKind::Ref(_) => { panic!("ERROR: Informal ExpectKind found {:?}", kind) },
                    _ => {}
                }
                SrcKind::Composite(keys.pop().unwrap().to_owned(),
                                   kind,
                                   exp)
            }
        }
    }
}

/// delimited by new line
/// should resolve to boolean
#[derive(Debug,PartialEq)]
pub enum LogicKind {
    GT(VarKind,VarKind), // weight > 1
    LT(VarKind,VarKind),

    //boolean checks
    Is(String),
    IsNot(String),
}

impl LogicKind {
    pub fn parse(mut exp: Vec<String>) -> LogicKind {
        let len = exp.len();

        if len == 1 {
            let mut exp = exp.pop().unwrap();
            let inv = exp.remove(0);
            if inv == '!' {
                LogicKind::IsNot(exp)
            }
            else {
                LogicKind::Is(exp)
            }
        }
        else if len == 3 {
            let var = exp.pop().unwrap();
            let var = VarKind::parse(var);

            let sym = exp.pop().unwrap();
            let key = exp.pop().unwrap();
            let key = VarKind::parse(key);

            if sym == ">" {
                LogicKind::GT(key,var)
            }
            else if sym == "<" {
                LogicKind::LT(key,var)
            }
            else { panic!("ERROR: Invalid LogicKind Syntax") }
        }
        else { panic!("ERROR: Unbalanced LogicKind Syntax ({:?})",exp) }
    }
}

#[derive(Debug,PartialEq, Clone)]
pub enum VarKind {
    String(String),
    Num(f32),
    Bool(bool),
}

impl ToString for VarKind {
    fn to_string(&self) -> String {
        match self {
            &VarKind::String(ref s) => s.clone(),
            &VarKind::Num(ref n) => n.to_string(),
            &VarKind::Bool(ref b) => b.to_string(),
        }
    }
}

impl VarKind {
    pub fn parse(t: String) -> VarKind {
        let val;

        if let Ok(v) = t.parse::<f32>() {
            val = VarKind::Num(v);
        }
        else if let Ok(v) = t.parse::<bool>() {
            val = VarKind::Bool(v);
        }
        else { val = VarKind::String(t) }

        val
    }

    pub fn get_num<D:Eval> (&self, data: &D) -> Result<f32,&'static str> {
        let num;
        match self {
            &VarKind::Num(n) => { num = n; },
            &VarKind::String(ref s) => {
                if let Some(n) = data.eval(s) {
                    match n {
                        VarKind::Num(n) => { num = n; },
                        _ => return Err("ERROR: NaN Evaluation")
                    }
                }
                else {  return Err("ERROR: Empty Evaluation") }
            },
            _ =>  return Err("ERROR: NaN Evaluation")
        }

        return Ok(num)
    }
}

pub trait Eval {
    fn eval (&self, data: &str) -> Option<VarKind>;
}

pub struct Parser {
    //state: HashMap<String,usize>, //lookup table
}

impl Parser {
    pub fn eval_block<D:Eval>
        (block: &BlockKind, data: &D)
         -> (Vec<VarKind>,Option<String>)
    {
        let mut r = vec!();
        let mut node = None;

        match block {
            &BlockKind::Src(ref b) => {
                let mut state: HashMap<String,bool> = HashMap::new();
                for src in b.src.iter() {
                    let (mut vars, node_) = src.eval(&mut state, data);
                    for n in vars.drain(..) { r.push(n); }
                    if node_.is_some() { node = node_; break; }
                }
            },
            _ => panic!("ERROR: Unimplemented block evaluation type")
        }

        for var in r.iter_mut() {
            match var {
                &mut VarKind::String(ref mut s) => { //format string
                    let mut fs = String::new();
                    let mut started = false;
                    for word in s.split_whitespace() {
                        if started { fs.push(' '); }

                        if word.chars().next().unwrap() == '`' {
                            if let Some(ref val) = data.eval(&word[1..]) {
                                fs.push_str(&val.to_string());
                            }
                        }
                        else {
                            fs.push_str(word);
                        }

                        started = true;
                    }

                    *s = fs;
                },
                _ => {}
            }
        }

        return (r,node)
    }

    pub fn parse_blocks (src: &str) -> Vec<BlockKind> {
        let mut v = vec!();
        let mut exp = String::new();
        let mut exps: Vec<String> = vec!();
        let mut block: Option<BlockKind> = None;

        let mut in_string = false;
        let mut in_comment = false;
        let mut in_vec = false;

        for c in src.chars() {
            if c == '[' { in_vec = true; continue }
            else if c == ']' { in_vec = false; }
            else if c == '#' && !in_string { in_comment = true; }
            else if  c == '\n' && in_comment && !in_string {
                in_comment = false;
                continue;
            }

            if c == '\n' && in_vec { continue }

            if (c == ']' ||
                c == '#' ||
                c == '\n')
                && !in_string
            {
                for n in exp.split_whitespace() {
                    exps.push(n.trim().to_owned());
                }
                exp = String::new();

                if exps.len() < 1 { continue }

                // determine block type
                if block.is_none() {
                    let name = exps.pop().unwrap();

                    if name == "def" {
                        let b = DefBlock {
                            name: exps.pop().unwrap(),
                            defs: vec!()
                        };

                        block = Some(BlockKind::Def(b));
                    }
                    else {
                        let b = SrcBlock {
                            name: name,
                            src: vec!()
                        };

                        block = Some(BlockKind::Src(b));
                    }
                }
                else { // build block type
                    let mut qsyms = vec!();
                    for n in exps.iter_mut() {
                        if n.chars().next().expect("ERROR: Empty QSYM") == '\'' {
                            let mut qsym = "__".to_owned();
                            let sym = n[1..].trim().to_owned();
                            qsym.push_str(&random::<u16>().to_string());

                            qsyms.push(qsym.clone());
                            qsyms.push(sym);
                            *n = qsym;
                        }
                    }

                    match block {
                        Some(BlockKind::Def(ref mut b)) => {
                            b.defs.push((exps[0].to_owned(),
                                         VarKind::parse(exps[1].to_owned())));
                        },
                        Some(BlockKind::Src(ref mut b)) => {
                            //println!("EXPS{:?}",exps); //DEBUG
                            if qsyms.len() > 1 {
                                b.src.push(SrcKind::parse(qsyms));
                            }

                            b.src.push(SrcKind::parse(exps));
                        },
                        _ => {}
                    }

                    exps = vec!();
                }
            }
            else if c == '"' && !in_comment {
                in_string = !in_string;
                if in_string {
                    for n in exp.split_whitespace() {
                        exps.push(n.trim().to_owned());
                    }
                    exp = String::new();
                }
                else if !in_string {
                    exps.push(exp);
                    exp = String::new();
                }
            }
            else if c == ';' && !in_string && !in_comment {
                //fail otherwise, block should be built!
                v.push(block.unwrap());
                block = None;
            }
            else {
                if !in_comment {
                    exp.push(c);
                }
            }
        }

        v
    }
}
<commit_msg>remove unnecessary<commit_after>use rand::random;
use std::collections::HashMap;

#[derive(Debug,PartialEq)]
pub struct SrcBlock {
    pub name: String,
    pub src: Vec<SrcKind>
}

#[derive(Debug,PartialEq)]
pub struct DefBlock {
    pub name: String,
    pub defs: Vec<(String,VarKind)>
}

#[derive(Debug,PartialEq)]
pub enum BlockKind {
    Src(SrcBlock),
    Def(DefBlock),
}

/// delimited by new line
#[derive(Debug,PartialEq)]
pub enum SrcKind {
    Logic(String, LogicKind), // ex: item_logic has_item

    // references logic in env and emits varkinds;
    // logic must resolve to true
    // ex: if item_logic give_quest
    // Can optionally end execution and begin next node
    If(ExpectKind, Vec<VarKind>, Option<String>),

    Composite(String,ExpectKind,Vec<String>),
    Next(String), // ends execution and begins next node
}

#[derive(Debug,PartialEq)]
pub enum ExpectKind {
    All,
    Any,
    None,

    Ref(String) // references env variable set from logic
}
impl ExpectKind {
    pub fn parse(s: String) -> ExpectKind {
        match &s[..] {
            "all" => ExpectKind::All,
            "any" => ExpectKind::Any,
            "none" => ExpectKind::None,
            _ => ExpectKind::Ref(s),
        }
    }
}

impl SrcKind {
    fn eval<D:Eval> (&self, state: &mut HashMap<String,bool>, data: &D)
                     -> (Vec<VarKind>,Option<String>)
    {
        match self {
            &SrcKind::Next(ref node) => {
                return (vec![],Some(node.clone()))
            },
            &SrcKind::Logic(ref name, ref logic) => { //logic updates state
                let name = name.clone();
                match logic {
                    &LogicKind::Is(ref lookup) => {
                        let r = data.eval(&lookup);
                        if r.is_some() {
                            match r.unwrap() {
                                VarKind::Bool(v) => { state.insert(name,v); },
                                _ => { state.insert(name,true); }, //if exists?
                            }
                        }
                    },
                    &LogicKind::IsNot(ref lookup) => { //inverse state
                        let r = data.eval(&lookup);
                        if r.is_some() {
                            match r.unwrap() {
                                VarKind::Bool(v) => {
                                    if !v { state.insert(name,true); }
                                },
                                _ => { state.insert(name,false); },
                            }
                        }
                    },

                    &LogicKind::GT(ref left, ref right) => {
                        let right = VarKind::get_num::<D>(right,data);
                        let left = VarKind::get_num::<D>(left,data);

                        if left.is_ok() && right.is_ok() {
                            state.insert(name, left.unwrap() > right.unwrap());
                        }
                    },
                    &LogicKind::LT(ref left, ref right) => {
                        let right = VarKind::get_num::<D>(right,data);
                        let left = VarKind::get_num::<D>(left,data);

                        if left.is_ok() && right.is_ok() {
                            state.insert(name, left.unwrap() < right.unwrap());
                        }
                    },
                }

                return (vec![],None) // logic does not return anything
            },
            &SrcKind::Composite(ref name, ref x, ref lookups) => {
                let mut comp_value = false;
                match x {
                    &ExpectKind::All => { // all must pass as true
                        for lookup in lookups.iter() {
                            let val = state.get(lookup);
                            if val.is_some() && *val.unwrap() {
                                comp_value = true;
                            }
                            else { comp_value = false; break }
                        }

                        state.insert(name.clone(),comp_value);
                    },
                    &ExpectKind::Any => { // first truth passes for set
                        for lookup in lookups.iter() {
                            let val = state.get(lookup);
                            if val.is_some() && *val.unwrap() {
                                comp_value = true;
                                break;
                            }
                        }

                        state.insert(name.clone(),comp_value);
                    },
                    &ExpectKind::None => { // inverse of any, none must be true
                        for lookup in lookups.iter() {
                            let val = state.get(lookup);
                            if val.is_some() && *val.unwrap() {
                                comp_value = false;
                                break;
                            }
                        }

                        state.insert(name.clone(),comp_value);
                    },
                    &ExpectKind::Ref(_) => panic!("ERROR: Unexpected parsing") // this should never hit
                }

                return (vec![],None) // composite does not return anything
            },
            &SrcKind::If(ref x, ref v, ref node) => {
                let mut if_value = false;
                match x {
                    &ExpectKind::All => {
                        for n in state.values() {
                            if !n { if_value = false; break }
                            else { if_value = true; }
                        }
                    },
                    &ExpectKind::Any => {
                        for n in state.values() {
                            if *n { if_value = true; break }
                        }
                    },
                    &ExpectKind::None => {
                        for n in state.values() {
                            if !n { if_value = true; }
                            else { if_value = true; break }
                        }
                    },
                    &ExpectKind::Ref(ref lookup) => {
                        let val = state.get(lookup);
                        if let Some(val) = val {
                            if_value = *val;
                        }
                    },
                }

                if if_value { return ((*v).clone(),node.clone()) }
                else { return (vec![],None) }
            }
        }
    }

    pub fn parse(mut exp: Vec<String>) -> SrcKind {
        if exp[0] == "if" {
            if exp.len() < 3 { panic!("ERROR: Invalid IF Logic {:?}",exp) }

            let x = exp.remove(1);

            let mut node = None;
            if exp.len() > 2 {
                let next = &exp[exp.len() - 2] == "next";
                if next {
                    node = exp.pop();
                    let _ = exp.pop(); // remove next tag
                }
            }

            let v = exp.drain(1..).map(|n| VarKind::parse(n)).collect();
            SrcKind::If(ExpectKind::parse(x),
                        v, node)
        }
        else if exp[0] == "next" {
            if exp.len() == 2 {
                SrcKind::Next(exp.pop().unwrap())
            }
            else { panic!("ERROR: Uneven NEXT Logic {:?}",exp) }
        }
        else {
            let keys = exp.remove(0);
            let mut keys: Vec<&str> = keys.split_terminator(':').collect();

            if keys.len() < 2 { // regular logic
                SrcKind::Logic(keys.pop().unwrap().to_owned(),
                               LogicKind::parse(exp))
            }
            else { // composite type
                let kind = ExpectKind::parse(keys.pop().unwrap().to_owned());
                match kind { // only formal expected types allowed
                    ExpectKind::Ref(_) => { panic!("ERROR: Informal ExpectKind found {:?}", kind) },
                    _ => {}
                }
                SrcKind::Composite(keys.pop().unwrap().to_owned(),
                                   kind,
                                   exp)
            }
        }
    }
}

/// delimited by new line
/// should resolve to boolean
#[derive(Debug,PartialEq)]
pub enum LogicKind {
    GT(VarKind,VarKind), // weight > 1
    LT(VarKind,VarKind),

    //boolean checks
    Is(String),
    IsNot(String),
}

impl LogicKind {
    pub fn parse(mut exp: Vec<String>) -> LogicKind {
        let len = exp.len();

        if len == 1 {
            let mut exp = exp.pop().unwrap();
            let inv = exp.remove(0);
            if inv == '!' {
                LogicKind::IsNot(exp)
            }
            else {
                LogicKind::Is(exp)
            }
        }
        else if len == 3 {
            let var = exp.pop().unwrap();
            let var = VarKind::parse(var);

            let sym = exp.pop().unwrap();
            let key = exp.pop().unwrap();
            let key = VarKind::parse(key);

            if sym == ">" {
                LogicKind::GT(key,var)
            }
            else if sym == "<" {
                LogicKind::LT(key,var)
            }
            else { panic!("ERROR: Invalid LogicKind Syntax") }
        }
        else { panic!("ERROR: Unbalanced LogicKind Syntax ({:?})",exp) }
    }
}

#[derive(Debug,PartialEq, Clone)]
pub enum VarKind {
    String(String),
    Num(f32),
    Bool(bool),
}

impl ToString for VarKind {
    fn to_string(&self) -> String {
        match self {
            &VarKind::String(ref s) => s.clone(),
            &VarKind::Num(ref n) => n.to_string(),
            &VarKind::Bool(ref b) => b.to_string(),
        }
    }
}

impl VarKind {
    pub fn parse(t: String) -> VarKind {
        let val;

        if let Ok(v) = t.parse::<f32>() {
            val = VarKind::Num(v);
        }
        else if let Ok(v) = t.parse::<bool>() {
            val = VarKind::Bool(v);
        }
        else { val = VarKind::String(t) }

        val
    }

    pub fn get_num<D:Eval> (&self, data: &D) -> Result<f32,&'static str> {
        let num;
        match self {
            &VarKind::Num(n) => { num = n; },
            &VarKind::String(ref s) => {
                if let Some(n) = data.eval(s) {
                    match n {
                        VarKind::Num(n) => { num = n; },
                        _ => return Err("ERROR: NaN Evaluation")
                    }
                }
                else {  return Err("ERROR: Empty Evaluation") }
            },
            _ =>  return Err("ERROR: NaN Evaluation")
        }

        return Ok(num)
    }
}

pub trait Eval {
    fn eval (&self, data: &str) -> Option<VarKind>;
}

pub struct Parser;
impl Parser {
    pub fn eval_block<D:Eval>
        (block: &BlockKind, data: &D)
         -> (Vec<VarKind>,Option<String>)
    {
        let mut r = vec!();
        let mut node = None;

        match block {
            &BlockKind::Src(ref b) => {
                let mut state: HashMap<String,bool> = HashMap::new();
                for src in b.src.iter() {
                    let (mut vars, node_) = src.eval(&mut state, data);
                    for n in vars.drain(..) { r.push(n); }
                    if node_.is_some() { node = node_; break; }
                }
            },
            _ => panic!("ERROR: Unimplemented block evaluation type")
        }

        for var in r.iter_mut() {
            match var {
                &mut VarKind::String(ref mut s) => { //format string
                    let mut fs = String::new();
                    let mut started = false;
                    for word in s.split_whitespace() {
                        if started { fs.push(' '); }

                        if word.chars().next().unwrap() == '`' {
                            if let Some(ref val) = data.eval(&word[1..]) {
                                fs.push_str(&val.to_string());
                            }
                        }
                        else {
                            fs.push_str(word);
                        }

                        started = true;
                    }

                    *s = fs;
                },
                _ => {}
            }
        }

        return (r,node)
    }

    pub fn parse_blocks (src: &str) -> Vec<BlockKind> {
        let mut v = vec!();
        let mut exp = String::new();
        let mut exps: Vec<String> = vec!();
        let mut block: Option<BlockKind> = None;

        let mut in_string = false;
        let mut in_comment = false;
        let mut in_vec = false;

        for c in src.chars() {
            if c == '[' { in_vec = true; continue }
            else if c == ']' { in_vec = false; }
            else if c == '#' && !in_string { in_comment = true; }
            else if  c == '\n' && in_comment && !in_string {
                in_comment = false;
                continue;
            }

            if c == '\n' && in_vec { continue }

            if (c == ']' ||
                c == '#' ||
                c == '\n')
                && !in_string
            {
                for n in exp.split_whitespace() {
                    exps.push(n.trim().to_owned());
                }
                exp = String::new();

                if exps.len() < 1 { continue }

                // determine block type
                if block.is_none() {
                    let name = exps.pop().unwrap();

                    if name == "def" {
                        let b = DefBlock {
                            name: exps.pop().unwrap(),
                            defs: vec!()
                        };

                        block = Some(BlockKind::Def(b));
                    }
                    else {
                        let b = SrcBlock {
                            name: name,
                            src: vec!()
                        };

                        block = Some(BlockKind::Src(b));
                    }
                }
                else { // build block type
                    let mut qsyms = vec!();
                    for n in exps.iter_mut() {
                        if n.chars().next().expect("ERROR: Empty QSYM") == '\'' {
                            let mut qsym = "__".to_owned();
                            let sym = n[1..].trim().to_owned();
                            qsym.push_str(&random::<u16>().to_string());

                            qsyms.push(qsym.clone());
                            qsyms.push(sym);
                            *n = qsym;
                        }
                    }

                    match block {
                        Some(BlockKind::Def(ref mut b)) => {
                            b.defs.push((exps[0].to_owned(),
                                         VarKind::parse(exps[1].to_owned())));
                        },
                        Some(BlockKind::Src(ref mut b)) => {
                            //println!("EXPS{:?}",exps); //DEBUG
                            if qsyms.len() > 1 {
                                b.src.push(SrcKind::parse(qsyms));
                            }

                            b.src.push(SrcKind::parse(exps));
                        },
                        _ => {}
                    }

                    exps = vec!();
                }
            }
            else if c == '"' && !in_comment {
                in_string = !in_string;
                if in_string {
                    for n in exp.split_whitespace() {
                        exps.push(n.trim().to_owned());
                    }
                    exp = String::new();
                }
                else if !in_string {
                    exps.push(exp);
                    exp = String::new();
                }
            }
            else if c == ';' && !in_string && !in_comment {
                //fail otherwise, block should be built!
                v.push(block.unwrap());
                block = None;
            }
            else {
                if !in_comment {
                    exp.push(c);
                }
            }
        }

        v
    }
}
<|endoftext|>


<commit_before>use bytes::{BufMut, BytesMut};

use futures;

use nom::{IResult, Needed};

use imap_proto;
use imap_proto::types::{Request, RequestId, Response};

use std::io;
use std::mem;

use tokio::net::TcpStream;
use tokio_io::codec::{Decoder, Encoder, Framed};
use tokio_tls::TlsStream;

pub struct ImapCodec {
    decode_need_message_bytes: usize,
}

impl Default for ImapCodec {
    fn default() -> Self {
        Self {
            decode_need_message_bytes: 0,
        }
    }
}

impl<'a> Decoder for ImapCodec {
    type Item = ResponseData;
    type Error = io::Error;
    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
        if self.decode_need_message_bytes > buf.len() {
            return Ok(None);
        }
        let (response, rsp_len) = match imap_proto::parse_response(buf) {
            IResult::Done(remaining, response) => {
                // This SHOULD be acceptable/safe: BytesMut storage memory is
                // allocated on the heap and should not move. It will not be
                // freed as long as we keep a reference alive, which we do
                // by retaining a reference to the split buffer, below.
                let response = unsafe { mem::transmute(response) };
                (response, buf.len() - remaining.len())
            },
            IResult::Incomplete(Needed::Size(min)) => {
                self.decode_need_message_bytes = min;
                return Ok(None);
            },
            IResult::Incomplete(_) => {
                return Ok(None);
            },
            IResult::Error(err) => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("{} during parsing of {:?}", err, buf),
                ));
            },
        };
        let raw = buf.split_to(rsp_len);
        self.decode_need_message_bytes = 0;
        Ok(Some(ResponseData { raw, response }))
    }
}

impl Encoder for ImapCodec {
    type Item = Request;
    type Error = io::Error;
    fn encode(&mut self, msg: Self::Item, dst: &mut BytesMut) -> Result<(), io::Error> {
        dst.put(msg.0.as_bytes());
        dst.put(b' ');
        dst.put(&msg.1);
        dst.put("\r\n");
        Ok(())
    }
}

#[derive(Debug)]
pub struct ResponseData {
    raw: BytesMut,
    // This reference is really scoped to the lifetime of the `raw`
    // member, but unfortunately Rust does not allow that yet. It
    // is transmuted to `'static` by the `Decoder`, instead, and
    // references returned to callers of `ResponseData` are limited
    // to the lifetime of the `ResponseData` struct.
    pub response: Response<'static>,
}

impl ResponseData {
    pub fn request_id(&self) -> Option<&RequestId> {
        match self.response {
            Response::Done { ref tag, .. } => Some(tag),
            _ => None,
        }
    }
    pub fn parsed(&self) -> &Response {
        unsafe { mem::transmute(&self.response) }
    }
}

pub type ImapTls = Framed<TlsStream<TcpStream>, ImapCodec>;

impl ImapTransport for ImapTls {}

pub trait ImapTransport
    : futures::Stream<Item = ResponseData, Error = io::Error>
    + futures::Sink<SinkItem = Request, SinkError = io::Error> {
}
<commit_msg>Freeze byte buffer before storing in ResponseData<commit_after>use bytes::{BufMut, Bytes, BytesMut};

use futures;

use nom::{IResult, Needed};

use imap_proto;
use imap_proto::types::{Request, RequestId, Response};

use std::io;
use std::mem;

use tokio::net::TcpStream;
use tokio_io::codec::{Decoder, Encoder, Framed};
use tokio_tls::TlsStream;

pub struct ImapCodec {
    decode_need_message_bytes: usize,
}

impl Default for ImapCodec {
    fn default() -> Self {
        Self {
            decode_need_message_bytes: 0,
        }
    }
}

impl<'a> Decoder for ImapCodec {
    type Item = ResponseData;
    type Error = io::Error;
    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
        if self.decode_need_message_bytes > buf.len() {
            return Ok(None);
        }
        let (response, rsp_len) = match imap_proto::parse_response(buf) {
            IResult::Done(remaining, response) => {
                // This SHOULD be acceptable/safe: BytesMut storage memory is
                // allocated on the heap and should not move. It will not be
                // freed as long as we keep a reference alive, which we do
                // by retaining a reference to the split buffer, below.
                let response = unsafe { mem::transmute(response) };
                (response, buf.len() - remaining.len())
            },
            IResult::Incomplete(Needed::Size(min)) => {
                self.decode_need_message_bytes = min;
                return Ok(None);
            },
            IResult::Incomplete(_) => {
                return Ok(None);
            },
            IResult::Error(err) => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("{} during parsing of {:?}", err, buf),
                ));
            },
        };
        let raw = buf.split_to(rsp_len).freeze();
        self.decode_need_message_bytes = 0;
        Ok(Some(ResponseData { raw, response }))
    }
}

impl Encoder for ImapCodec {
    type Item = Request;
    type Error = io::Error;
    fn encode(&mut self, msg: Self::Item, dst: &mut BytesMut) -> Result<(), io::Error> {
        dst.put(msg.0.as_bytes());
        dst.put(b' ');
        dst.put(&msg.1);
        dst.put("\r\n");
        Ok(())
    }
}

#[derive(Debug)]
pub struct ResponseData {
    raw: Bytes,
    // This reference is really scoped to the lifetime of the `raw`
    // member, but unfortunately Rust does not allow that yet. It
    // is transmuted to `'static` by the `Decoder`, instead, and
    // references returned to callers of `ResponseData` are limited
    // to the lifetime of the `ResponseData` struct.
    pub response: Response<'static>,
}

impl ResponseData {
    pub fn request_id(&self) -> Option<&RequestId> {
        match self.response {
            Response::Done { ref tag, .. } => Some(tag),
            _ => None,
        }
    }
    pub fn parsed(&self) -> &Response {
        unsafe { mem::transmute(&self.response) }
    }
}

pub type ImapTls = Framed<TlsStream<TcpStream>, ImapCodec>;

impl ImapTransport for ImapTls {}

pub trait ImapTransport
    : futures::Stream<Item = ResponseData, Error = io::Error>
    + futures::Sink<SinkItem = Request, SinkError = io::Error> {
}
<|endoftext|>


<commit_before>/**
Expose GraphQL scalars

The GraphQL language defines a number of built-in scalars: strings, numbers, and
booleans. This macro can be used either to define new types of scalars (e.g.
timestamps), or expose other types as one of the built-in scalars (e.g. bigints
as numbers or strings).

Since the preferred transport protocol for GraphQL responses is JSON, most
custom scalars will be transferred as strings. You therefore need to ensure that
the client library you are sending data to can parse the custom value into a
datatype appropriate for that platform.

```rust
# #[macro_use] extern crate juniper;
# use juniper::{Value, FieldResult};
struct UserID(String);

graphql_scalar!(UserID {
    description: "An opaque identifier, represented as a string"

    resolve(&self) -> Value {
        Value::string(&self.0)
    }

    from_input_value(v: &InputValue) -> Option<UserID> {
        v.as_string_value().map(|s| UserID(s.to_owned()))
    }
});

# fn main() { }
```

In addition to implementing `GraphQLType` for the type in question,
`FromInputValue` and `ToInputValue` is also implemented. This makes the type
usable as arguments and default values.

*/
#[macro_export]
macro_rules! graphql_scalar {
    ( @as_expr, $e:expr) => { $e };

    // Calls $val.$func($arg) if $arg is not None
    ( @maybe_apply, None, $func:ident, $val:expr ) => { $val };
    ( @maybe_apply, $arg:tt, $func:ident, $val:expr ) => { $val.$func($arg) };

    // Each of the @parse match arms accumulates data up to a call to @generate
    //
    // ( $name, $outname, $descr ): the name of the Rust type and the name of the
    // GraphQL scalar (as a string), and the description of the scalar (as a
    // string or none).
    //
    // ( $resolve_selfvar, $resolve_body ): the "self" argument and body for the
    // resolve() method on GraphQLType and the to_input_value() method on ToInputValue.
    //
    // ( $fiv_arg, $fiv_result, $fiv_body ): the method argument, result type,
    // and body for the from() method on FromInputValue.
    (
        @generate,
        ( $name:ty, $outname:tt, $descr:tt ),
        (
            ( $resolve_selfvar:ident, $resolve_body:block ),
            ( $fiv_arg:ident, $fiv_result:ty, $fiv_body:block )
        )
    ) => {
        impl $crate::GraphQLType for $name {
            type Context = ();
            type TypeInfo = ();

            fn name(_: &()) -> Option<&str> {
                Some(graphql_scalar!( @as_expr, $outname ))
            }

            fn meta<'r>(
                info: &(),
                registry: &mut $crate::Registry<'r>
            ) -> $crate::meta::MetaType<'r> {
                graphql_scalar!(
                    @maybe_apply, $descr, description,
                    registry.build_scalar_type::<Self>(info))
                    .into_meta()
            }

            fn resolve(
                &$resolve_selfvar,
                _: &(),
                _: Option<&[$crate::Selection]>,
                _: &$crate::Executor<Self::Context>) -> $crate::Value {
                $resolve_body
            }
        }

        impl $crate::ToInputValue for $name {
            fn to_input_value(&$resolve_selfvar) -> $crate::InputValue {
                $crate::ToInputValue::to_input_value(&$resolve_body)
            }
        }

        impl $crate::FromInputValue for $name {
            fn from_input_value($fiv_arg: &$crate::InputValue) -> $fiv_result {
                $fiv_body
            }
        }
    };

    // No more items to parse
    (
        @parse,
        $meta:tt,
        $acc:tt,
    ) => {
        graphql_scalar!( @generate, $meta, $acc );
    };

    // resolve(&self) -> Value { ... }
    (
        @parse,
        $meta:tt,
        ( $_ignored:tt, $fiv:tt ),
        resolve(&$selfvar:ident) -> Value $body:block $($rest:tt)*
    ) => {
        graphql_scalar!( @parse, $meta, ( ($selfvar, $body), $fiv ), $($rest)* );
    };

    // from_input_value(arg: &InputValue) -> ... { ... }
    (
        @parse,
        $meta:tt,
        ( $resolve:tt, $_ignored:tt ),
        from_input_value($arg:ident: &InputValue) -> $result:ty $body:block $($rest:tt)*
    ) => {
        graphql_scalar!( @parse, $meta, ( $resolve, ( $arg, $result, $body ) ), $($rest)* );
    };

    // description: <description>
    (
        @parse,
        ( $name:ty, $outname:tt, $_ignored:tt ),
        $acc:tt,
        description: $descr:tt $($rest:tt)*
    ) => {
        graphql_scalar!( @parse, ( $name, $outname, $descr ), $acc, $($rest)* );
    };

    // Entry point:
    // RustName as "GraphQLName" { ... }
    ( $name:ty as $outname:tt { $( $items:tt )* }) => {
        graphql_scalar!( @parse, ( $name, $outname, None ), ( None, None ), $($items)* );
    };

    // Entry point
    // RustName { ... }
    ( $name:ty { $( $items:tt )* }) => {
        graphql_scalar!( @parse, ( $name, stringify!($name), None ), ( None, None ), $($items)* );
    };
}
<commit_msg>Change $outname from :tt to :expr<commit_after>/**
Expose GraphQL scalars

The GraphQL language defines a number of built-in scalars: strings, numbers, and
booleans. This macro can be used either to define new types of scalars (e.g.
timestamps), or expose other types as one of the built-in scalars (e.g. bigints
as numbers or strings).

Since the preferred transport protocol for GraphQL responses is JSON, most
custom scalars will be transferred as strings. You therefore need to ensure that
the client library you are sending data to can parse the custom value into a
datatype appropriate for that platform.

```rust
# #[macro_use] extern crate juniper;
# use juniper::{Value, FieldResult};
struct UserID(String);

graphql_scalar!(UserID {
    description: "An opaque identifier, represented as a string"

    resolve(&self) -> Value {
        Value::string(&self.0)
    }

    from_input_value(v: &InputValue) -> Option<UserID> {
        v.as_string_value().map(|s| UserID(s.to_owned()))
    }
});

# fn main() { }
```

In addition to implementing `GraphQLType` for the type in question,
`FromInputValue` and `ToInputValue` is also implemented. This makes the type
usable as arguments and default values.

*/
#[macro_export]
macro_rules! graphql_scalar {
    ( @as_expr, $e:expr) => { $e };

    // Calls $val.$func($arg) if $arg is not None
    ( @maybe_apply, None, $func:ident, $val:expr ) => { $val };
    ( @maybe_apply, $arg:tt, $func:ident, $val:expr ) => { $val.$func($arg) };

    // Each of the @parse match arms accumulates data up to a call to @generate
    //
    // ( $name, $outname, $descr ): the name of the Rust type and the name of the
    // GraphQL scalar (as a string), and the description of the scalar (as a
    // string or none).
    //
    // ( $resolve_selfvar, $resolve_body ): the "self" argument and body for the
    // resolve() method on GraphQLType and the to_input_value() method on ToInputValue.
    //
    // ( $fiv_arg, $fiv_result, $fiv_body ): the method argument, result type,
    // and body for the from() method on FromInputValue.
    (
        @generate,
        ( $name:ty, $outname:expr, $descr:tt ),
        (
            ( $resolve_selfvar:ident, $resolve_body:block ),
            ( $fiv_arg:ident, $fiv_result:ty, $fiv_body:block )
        )
    ) => {
        impl $crate::GraphQLType for $name {
            type Context = ();
            type TypeInfo = ();

            fn name(_: &()) -> Option<&str> {
                Some(graphql_scalar!( @as_expr, $outname ))
            }

            fn meta<'r>(
                info: &(),
                registry: &mut $crate::Registry<'r>
            ) -> $crate::meta::MetaType<'r> {
                graphql_scalar!(
                    @maybe_apply, $descr, description,
                    registry.build_scalar_type::<Self>(info))
                    .into_meta()
            }

            fn resolve(
                &$resolve_selfvar,
                _: &(),
                _: Option<&[$crate::Selection]>,
                _: &$crate::Executor<Self::Context>) -> $crate::Value {
                $resolve_body
            }
        }

        impl $crate::ToInputValue for $name {
            fn to_input_value(&$resolve_selfvar) -> $crate::InputValue {
                $crate::ToInputValue::to_input_value(&$resolve_body)
            }
        }

        impl $crate::FromInputValue for $name {
            fn from_input_value($fiv_arg: &$crate::InputValue) -> $fiv_result {
                $fiv_body
            }
        }
    };

    // No more items to parse
    (
        @parse,
        $meta:tt,
        $acc:tt,
    ) => {
        graphql_scalar!( @generate, $meta, $acc );
    };

    // resolve(&self) -> Value { ... }
    (
        @parse,
        $meta:tt,
        ( $_ignored:tt, $fiv:tt ),
        resolve(&$selfvar:ident) -> Value $body:block $($rest:tt)*
    ) => {
        graphql_scalar!( @parse, $meta, ( ($selfvar, $body), $fiv ), $($rest)* );
    };

    // from_input_value(arg: &InputValue) -> ... { ... }
    (
        @parse,
        $meta:tt,
        ( $resolve:tt, $_ignored:tt ),
        from_input_value($arg:ident: &InputValue) -> $result:ty $body:block $($rest:tt)*
    ) => {
        graphql_scalar!( @parse, $meta, ( $resolve, ( $arg, $result, $body ) ), $($rest)* );
    };

    // description: <description>
    (
        @parse,
        ( $name:ty, $outname:expr, $_ignored:tt ),
        $acc:tt,
        description: $descr:tt $($rest:tt)*
    ) => {
        graphql_scalar!( @parse, ( $name, $outname, $descr ), $acc, $($rest)* );
    };

    // Entry point:
    // RustName as "GraphQLName" { ... }
    ( $name:ty as $outname:tt { $( $items:tt )* }) => {
        graphql_scalar!( @parse, ( $name, $outname, None ), ( None, None ), $($items)* );
    };

    // Entry point
    // RustName { ... }
    ( $name:ty { $( $items:tt )* }) => {
        graphql_scalar!( @parse, ( $name, stringify!($name), None ), ( None, None ), $($items)* );
    };
}
<|endoftext|>


<commit_before>//!
//! Code to create a scaled read-count track
//!
use htslib::bam;
use htslib::bam::Read;
use htslib::bam::Reader;
use htslib::bam::Records;
use std::path::Path;
use std::error::Error;
use std::fs::File;
use std::ffi::OsString;
use std::ffi::OsStr;
use std::io::Read as ioRead;
use std::io::Write as ioWrite;
use std::io::Seek;
use std::io::Error as ioError;
use std::process::exit;
use std::iter::Peekable;
use seqtable::{SeqTable,SequenceInfo};
use std::collections::BTreeMap;
use std::collections::btree_map::Iter;
use bigwig::write_bigwig;
use bigwig::Strand;
use filter::{RecordCheck, PairedChecker, SingleChecker};
use fasta::reverse_complement;

#[derive(Debug)]
pub struct PileUp {
    chroms: Vec<String>,
    chrom_sizes: Vec<u32>,
    counts: Vec<BTreeMap<u32, (f64, f64)>>,
    minus_shift: i32,
    no_scale: bool,
}

impl PileUp {

    fn new(sinfos: &Vec<SequenceInfo>, minus_shift: i32, no_scale: bool) -> PileUp {
        let mut chroms = Vec::new();
        let mut counts = Vec::new();
        let mut chrom_sizes = Vec::new();

        for sinfo in sinfos {
            chroms.push(sinfo.name.clone());
            chrom_sizes.push(sinfo.length);
            counts.push(BTreeMap::new());
        }

        PileUp { chroms: chroms, chrom_sizes: chrom_sizes, counts: counts, minus_shift: minus_shift, no_scale: no_scale}
    }

    fn add_data<R: ioRead+Seek, C: RecordCheck>(&mut self, table: &mut SeqTable<R>, bamrecs: &mut Peekable<Records<Reader>>, tid: &mut i32, map: &Vec<usize>, scale: &Vec<(f64, f64)>, checker: &C) -> bool {
        // skip unmapped sequences (tid = -1)
        if *tid < 0 {
            match bamrecs.next() {
                Some(Ok(ref rec)) => { *tid = rec.tid(); return true; },
                Some(Err(_)) => return false,
                None => return false,
            }
        }

        let sidx = map[*tid as usize];
        let rlen = table.params.read_length as usize;
	let ksze = table.params.kmer_length as u8;
        let slen = table.len_by_idx(sidx).ok().expect("read sequence length") as i32;
        let mut rdr = table.get_sequence_by_idx(sidx).ok().expect("read sequence");

        loop {
            // check if we changed sequence
            match bamrecs.peek() {
                Some(&Ok(ref rec)) => if rec.tid() != *tid { *tid = rec.tid(); return true; },
                Some(&Err(_)) => return false,
                None => return false,
            }

            // if not count position
            if let Some(Ok(record)) = bamrecs.next() {
                if checker.valid(&record) {
                    let pos = checker.vir_pos(&record);
                    if pos < slen {
                        let (plus_idx, minus_idx) = rdr.vir_get(pos).unwrap();

                        if record.is_reverse() {
                            if minus_idx == 0 {
                                /* no data */
                            } else {
                                let inc = if self.no_scale { 1f64 } else { scale[reverse_complement(minus_idx, ksze) as usize].1 };
                                let minus_pos = (checker.vir_pos(&record) + rlen as i32 - 1i32 + self.minus_shift) as u32;
                                self.counts[sidx as usize].entry(minus_pos).or_insert((0f64, 0f64)).1 += inc;
                            }
                        } else {
                            if plus_idx == 0 {
                                /* no data */
                            } else {
                                let inc = if self.no_scale { 1f64 } else { scale[plus_idx as usize].0 };
                                self.counts[sidx as usize].entry(checker.vir_pos(&record) as u32).or_insert((0f64, 0f64)).0 += inc;
                            }
                        }
                    }
                }
            }
        }
    }

    pub fn write_bed(&self, filename: &str, stranded: bool) -> Result<(),ioError> {
        // open new file
        let mut f = try!(File::create(filename));

        // write data
        for i in 0..self.chroms.len() {
            let chrom : &str = &self.chroms[i];

            for (pos, value) in self.counts[i].iter() {

                if stranded {
                    if value.0 > 0f64 {
                        try!(write!(f, "{}\t{}\t{}\t.\t{}\t+\n", chrom, pos, pos + 1, value.0));
                    }
                    if value.1 > 0f64 {
                        try!(write!(f, "{}\t{}\t{}\t.\t{}\t-\n", chrom, pos, pos + 1, -value.1));
                    }
                } else {
                    try!(write!(f, "{}\t{}\t{}\t.\t{}\n", chrom, pos, pos + 1, value.0 + value.1));
                }
            }
        }
        Ok(())
    }

    fn bw_stranded_filename(filename: &str, strand: Strand) -> OsString {
        let def_ext : &OsStr = OsStr::new("bw");
        let mut basename: OsString = Path::new(filename).file_stem().unwrap_or(OsStr::new(filename)).to_os_string();
        let extension = Path::new(filename).extension().unwrap_or(def_ext).to_os_string();

        match strand {
            Strand::Plus => basename.push("_plus."),
            Strand::Minus => basename.push("_minus."),
            Strand::Both => unreachable!(),
        }
        basename.push(extension);

        return basename;
    }

    pub fn write_bw(&self, filename: &str, stranded: bool) -> Result<(String
    , Option<String>), ioError> {
        if stranded {
            let output_plus = PileUp::bw_stranded_filename(filename, Strand::Plus);
            let output_minus = PileUp::bw_stranded_filename(filename, Strand::Minus);

	        match write_bigwig(&output_plus, &self.chroms, &self.chrom_sizes, &self.counts, Strand::Plus) {
                Ok(_) => {
                    try!(write_bigwig(&output_minus, &self.chroms, &self.chrom_sizes, &self.counts, Strand::Minus));
                    Ok((output_plus.into_string().unwrap(), Some(output_minus.into_string().unwrap())))
                },
                Err(err) => Err(err),
            }
        } else {
            try!(write_bigwig(OsStr::new(filename), &self.chroms, &self.chrom_sizes, &self.counts, Strand::Both));
            Ok((String::from(filename), None))
        }
    }

    pub fn chrom_index(&self, chrom: &str) -> Option<usize> {
        self.chroms.iter().position(|x| x == chrom)
    }

    pub fn chrom_size(&self, index: usize) -> Option<u32> {
        self.chrom_sizes.get(index).map(|&x| x)
    }

    pub fn get(&self, chrom_index: usize, position: u32) -> Option<&(f64, f64)> {
        if chrom_index >= self.counts.len() { return None; }
        self.counts[chrom_index].get(&position)
    }

    pub fn chrom_iter(&self, index: usize) -> Iter<u32, (f64, f64)> {
        self.counts[index].iter()
    }
}

fn scale_factor(exp: u64, etotal: u64, obs: u64, ototal: u64) -> f64 {
    let fexp = if etotal > 0 { exp as f64 / etotal as f64 } else { 0f64 };
    let fobs = if ototal > 0 { obs as f64 / ototal as f64 } else { 0f64 };
    if fobs > 0f64 { fexp / fobs } else { 0f64 }
}

fn compute_scale_factors(counts: &Vec<(u64, u64, u64, u64)>) -> Vec<(f64, f64)> {
    // compute totals
    // skip first row which contains unmappable/unusable position counts
    let totals = counts.iter().skip(1).fold((0u64, 0u64, 0u64, 0u64),
        |acc, &(sp, sm, bp, bm)| ( acc.0 + sp, acc.1 + sm, acc.2 + bp, acc.3 + bm));

    // compute scale
    // x = Obs * ExpFreq / ObsFreq
    // scale = ExpFreq / ObsFreq
    counts.iter().map(|&(sp, sm, bp, bm)| {
        ( scale_factor(sp, totals.0, bp, totals.2),
          scale_factor(sm, totals.1, bm, totals.3)
        )
    }).collect()
}

pub fn scale(seqfile: &str, counts: Vec<(u64, u64, u64, u64)>, bamfiles: &Vec<String>, minqual: u8, shift: bool, no_scale: bool, pair_range: &Option<(i32, i32)>, paired: bool, exact_length: bool, tail_edge: bool) -> PileUp {
    // read
    let file = match File::open(seqfile) {
        Ok(value) => value,
        Err(err) => {
            println!("Error: Failed to open sequence table file '{}': {}", seqfile, err.description());
            exit(1);
        },
    };
    let mut table = match SeqTable::open(file) {
        Ok(value) => value,
        Err(e) => {
            println!("Error:tabulate: {}", e.to_string());
            exit(1);
        },
    };

    let seqinfos = table.sequences();
    let rlen = table.params.read_length as usize;
    let minus_shift = if shift {
        let res = (table.params.plus_offset as i16 - (table.params.kmer_length as i16 - table.params.minus_offset as i16 - 1i16)) as i32;
        println!("# minus strand shift = {} bp", res);
        res
    } else {
        0i32
    };

    let mut pileup = PileUp::new(&seqinfos, minus_shift, no_scale);

    for bamfile in bamfiles {
        println!("# scale {}", &bamfile);
        let bam = match bam::Reader::from_path(&Path::new(bamfile)) {
            Ok(value) => value,
            Err(err) => {
                println!("Error: Failed to open BAM file '{}': {}", bamfile, err.description());
                exit(1);
            },
        };
        let names = bam.header().target_names();
        let mut cur_tid = 0;

        // map BAM tid's to SeqTable idx's
        let map : Vec<usize> = names.iter().map(|&id| {
            let chrom = String::from_utf8_lossy(id);
            for i in 0..seqinfos.len() {
                if seqinfos[i].name.eq(&chrom) {
                    return i;
                }
            }
            println!("Error: Unknown sequence name in BAM: {}", chrom);
            exit(1);
        }
        ).collect();

        // reads
        let mut iter = bam.records().peekable();
        let scale = compute_scale_factors(&counts);

        if pair_range.is_some() || paired {
            let checker = match *pair_range {
                Some((min, max)) => PairedChecker {
                    tail_edge: tail_edge,
                    exact_length: exact_length,
                    read_length: rlen,
                    min_quality: minqual,
                    min_dist: min,
                    max_dist: max,
                    force_paired: paired,
                    max_distance: true,
                },
                None => PairedChecker {
                    tail_edge: tail_edge,
                    exact_length: exact_length,
                    read_length: rlen,
                    min_quality: minqual,
                    min_dist: 0,
                    max_dist: 0,
                    force_paired: paired,
                    max_distance: false,
                },
            };
            while pileup.add_data(&mut table, &mut iter, &mut cur_tid, &map, &scale, &checker) {}
        } else {
            let checker = SingleChecker { tail_edge: tail_edge, exact_length: exact_length, read_length: rlen, min_quality: minqual };
            while pileup.add_data(&mut table, &mut iter, &mut cur_tid, &map, &scale, &checker) {}
        }
    }

    pileup
}
<commit_msg>Update scale.rs<commit_after>//!
//! Code to create a scaled read-count track
//!
use htslib::bam;
use htslib::bam::Read;
use htslib::bam::Reader;
use htslib::bam::Records;
use std::path::Path;
use std::error::Error;
use std::fs::File;
use std::ffi::OsString;
use std::ffi::OsStr;
use std::io::Read as ioRead;
use std::io::Write as ioWrite;
use std::io::Seek;
use std::io::Error as ioError;
use std::process::exit;
use std::iter::Peekable;
use seqtable::{SeqTable,SequenceInfo};
use std::collections::BTreeMap;
use std::collections::btree_map::Iter;
use bigwig::write_bigwig;
use bigwig::Strand;
use filter::{RecordCheck, PairedChecker, SingleChecker};
use fasta::reverse_complement;

#[derive(Debug)]
pub struct PileUp {
    chroms: Vec<String>,
    chrom_sizes: Vec<u32>,
    counts: Vec<BTreeMap<u32, (f64, f64)>>,
    minus_shift: i32,
    no_scale: bool,
}

impl PileUp {

    fn new(sinfos: &Vec<SequenceInfo>, minus_shift: i32, no_scale: bool) -> PileUp {
        let mut chroms = Vec::new();
        let mut counts = Vec::new();
        let mut chrom_sizes = Vec::new();

        for sinfo in sinfos {
            chroms.push(sinfo.name.clone());
            chrom_sizes.push(sinfo.length);
            counts.push(BTreeMap::new());
        }

        PileUp { chroms: chroms, chrom_sizes: chrom_sizes, counts: counts, minus_shift: minus_shift, no_scale: no_scale}
    }

    fn add_data<R: ioRead+Seek, C: RecordCheck>(&mut self, table: &mut SeqTable<R>, bamrecs: &mut Peekable<Records<Reader>>, tid: &mut i32, map: &Vec<usize>, scale: &Vec<(f64, f64)>, checker: &C) -> bool {
        // skip unmapped sequences (tid = -1)
        if *tid < 0 {
            match bamrecs.next() {
                Some(Ok(ref rec)) => { *tid = rec.tid(); return true; },
                Some(Err(_)) => return false,
                None => return false,
            }
        }

        let sidx = map[*tid as usize];
        let rlen = table.params.read_length as usize;
	let ksze = table.params.kmer_length as u8;
        let slen = table.len_by_idx(sidx).ok().expect("read sequence length") as i32;
        let mut rdr = table.get_sequence_by_idx(sidx).ok().expect("read sequence");

        loop {
            // check if we changed sequence
            match bamrecs.peek() {
                Some(&Ok(ref rec)) => if rec.tid() != *tid { *tid = rec.tid(); return true; },
                Some(&Err(_)) => return false,
                None => return false,
            }

            // if not count position
            if let Some(Ok(record)) = bamrecs.next() {
                if checker.valid(&record) {
                    let pos = checker.vir_pos(&record);
                    if pos < slen {
                        let (plus_idx, minus_idx) = rdr.vir_get(pos).unwrap();

                        if record.is_reverse() {
                            if minus_idx == 0 {
                                /* no data */
                            } else {
                                let inc = if self.no_scale { 1f64 } else { scale[minus_idx as usize].1 };
                                let minus_pos = (checker.vir_pos(&record) + rlen as i32 - 1i32 + self.minus_shift) as u32;
                                self.counts[sidx as usize].entry(minus_pos).or_insert((0f64, 0f64)).1 += inc;
                            }
                        } else {
                            if plus_idx == 0 {
                                /* no data */
                            } else {
                                let inc = if self.no_scale { 1f64 } else { scale[plus_idx as usize].0 };
                                self.counts[sidx as usize].entry(checker.vir_pos(&record) as u32).or_insert((0f64, 0f64)).0 += inc;
                            }
                        }
                    }
                }
            }
        }
    }

    pub fn write_bed(&self, filename: &str, stranded: bool) -> Result<(),ioError> {
        // open new file
        let mut f = try!(File::create(filename));

        // write data
        for i in 0..self.chroms.len() {
            let chrom : &str = &self.chroms[i];

            for (pos, value) in self.counts[i].iter() {

                if stranded {
                    if value.0 > 0f64 {
                        try!(write!(f, "{}\t{}\t{}\t.\t{}\t+\n", chrom, pos, pos + 1, value.0));
                    }
                    if value.1 > 0f64 {
                        try!(write!(f, "{}\t{}\t{}\t.\t{}\t-\n", chrom, pos, pos + 1, -value.1));
                    }
                } else {
                    try!(write!(f, "{}\t{}\t{}\t.\t{}\n", chrom, pos, pos + 1, value.0 + value.1));
                }
            }
        }
        Ok(())
    }

    fn bw_stranded_filename(filename: &str, strand: Strand) -> OsString {
        let def_ext : &OsStr = OsStr::new("bw");
        let mut basename: OsString = Path::new(filename).file_stem().unwrap_or(OsStr::new(filename)).to_os_string();
        let extension = Path::new(filename).extension().unwrap_or(def_ext).to_os_string();

        match strand {
            Strand::Plus => basename.push("_plus."),
            Strand::Minus => basename.push("_minus."),
            Strand::Both => unreachable!(),
        }
        basename.push(extension);

        return basename;
    }

    pub fn write_bw(&self, filename: &str, stranded: bool) -> Result<(String
    , Option<String>), ioError> {
        if stranded {
            let output_plus = PileUp::bw_stranded_filename(filename, Strand::Plus);
            let output_minus = PileUp::bw_stranded_filename(filename, Strand::Minus);

	        match write_bigwig(&output_plus, &self.chroms, &self.chrom_sizes, &self.counts, Strand::Plus) {
                Ok(_) => {
                    try!(write_bigwig(&output_minus, &self.chroms, &self.chrom_sizes, &self.counts, Strand::Minus));
                    Ok((output_plus.into_string().unwrap(), Some(output_minus.into_string().unwrap())))
                },
                Err(err) => Err(err),
            }
        } else {
            try!(write_bigwig(OsStr::new(filename), &self.chroms, &self.chrom_sizes, &self.counts, Strand::Both));
            Ok((String::from(filename), None))
        }
    }

    pub fn chrom_index(&self, chrom: &str) -> Option<usize> {
        self.chroms.iter().position(|x| x == chrom)
    }

    pub fn chrom_size(&self, index: usize) -> Option<u32> {
        self.chrom_sizes.get(index).map(|&x| x)
    }

    pub fn get(&self, chrom_index: usize, position: u32) -> Option<&(f64, f64)> {
        if chrom_index >= self.counts.len() { return None; }
        self.counts[chrom_index].get(&position)
    }

    pub fn chrom_iter(&self, index: usize) -> Iter<u32, (f64, f64)> {
        self.counts[index].iter()
    }
}

fn scale_factor(exp: u64, etotal: u64, obs: u64, ototal: u64) -> f64 {
    let fexp = if etotal > 0 { exp as f64 / etotal as f64 } else { 0f64 };
    let fobs = if ototal > 0 { obs as f64 / ototal as f64 } else { 0f64 };
    if fobs > 0f64 { fexp / fobs } else { 0f64 }
}

fn compute_scale_factors(counts: &Vec<(u64, u64, u64, u64)>) -> Vec<(f64, f64)> {
    // compute totals
    // skip first row which contains unmappable/unusable position counts
    let totals = counts.iter().skip(1).fold((0u64, 0u64, 0u64, 0u64),
        |acc, &(sp, sm, bp, bm)| ( acc.0 + sp, acc.1 + sm, acc.2 + bp, acc.3 + bm));

    // compute scale
    // x = Obs * ExpFreq / ObsFreq
    // scale = ExpFreq / ObsFreq
    counts.iter().map(|&(sp, sm, bp, bm)| {
        ( scale_factor(sp, totals.0, bp, totals.2),
          scale_factor(sm, totals.1, bm, totals.3)
        )
    }).collect()
}

pub fn scale(seqfile: &str, counts: Vec<(u64, u64, u64, u64)>, bamfiles: &Vec<String>, minqual: u8, shift: bool, no_scale: bool, pair_range: &Option<(i32, i32)>, paired: bool, exact_length: bool, tail_edge: bool) -> PileUp {
    // read
    let file = match File::open(seqfile) {
        Ok(value) => value,
        Err(err) => {
            println!("Error: Failed to open sequence table file '{}': {}", seqfile, err.description());
            exit(1);
        },
    };
    let mut table = match SeqTable::open(file) {
        Ok(value) => value,
        Err(e) => {
            println!("Error:tabulate: {}", e.to_string());
            exit(1);
        },
    };

    let seqinfos = table.sequences();
    let rlen = table.params.read_length as usize;
    let minus_shift = if shift {
        let res = (table.params.plus_offset as i16 - (table.params.kmer_length as i16 - table.params.minus_offset as i16 - 1i16)) as i32;
        println!("# minus strand shift = {} bp", res);
        res
    } else {
        0i32
    };

    let mut pileup = PileUp::new(&seqinfos, minus_shift, no_scale);

    for bamfile in bamfiles {
        println!("# scale {}", &bamfile);
        let bam = match bam::Reader::from_path(&Path::new(bamfile)) {
            Ok(value) => value,
            Err(err) => {
                println!("Error: Failed to open BAM file '{}': {}", bamfile, err.description());
                exit(1);
            },
        };
        let names = bam.header().target_names();
        let mut cur_tid = 0;

        // map BAM tid's to SeqTable idx's
        let map : Vec<usize> = names.iter().map(|&id| {
            let chrom = String::from_utf8_lossy(id);
            for i in 0..seqinfos.len() {
                if seqinfos[i].name.eq(&chrom) {
                    return i;
                }
            }
            println!("Error: Unknown sequence name in BAM: {}", chrom);
            exit(1);
        }
        ).collect();

        // reads
        let mut iter = bam.records().peekable();
        let scale = compute_scale_factors(&counts);

        if pair_range.is_some() || paired {
            let checker = match *pair_range {
                Some((min, max)) => PairedChecker {
                    tail_edge: tail_edge,
                    exact_length: exact_length,
                    read_length: rlen,
                    min_quality: minqual,
                    min_dist: min,
                    max_dist: max,
                    force_paired: paired,
                    max_distance: true,
                },
                None => PairedChecker {
                    tail_edge: tail_edge,
                    exact_length: exact_length,
                    read_length: rlen,
                    min_quality: minqual,
                    min_dist: 0,
                    max_dist: 0,
                    force_paired: paired,
                    max_distance: false,
                },
            };
            while pileup.add_data(&mut table, &mut iter, &mut cur_tid, &map, &scale, &checker) {}
        } else {
            let checker = SingleChecker { tail_edge: tail_edge, exact_length: exact_length, read_length: rlen, min_quality: minqual };
            while pileup.add_data(&mut table, &mut iter, &mut cur_tid, &map, &scale, &checker) {}
        }
    }

    pileup
}
<|endoftext|>


<commit_before>use std::io::BufReader;
use std::fs::File;

use serde_json;

use cgmath::*;
use shape::*;
use vec3d::*;
use light::*;

use color;
use color::Color;

use std;

#[derive(Serialize, Deserialize)]
pub struct Scene {
    shapes: Vec<Shape>,
    light: Light,
    camera_pos: Vec3d,
    camera_dir: Vec3d,
    camera_up: Vec3d,
    max_reflection: i32,
}

impl Scene {
    pub fn new(light: Light, camera_pos: Vec3d, camera_dir: Vec3d, camera_up: Vec3d) -> Scene {
        Scene {
            shapes: Vec::new(),
            light: light,
            camera_pos: camera_pos,
            camera_dir: camera_dir,
            camera_up: camera_up,
            max_reflection: 4,
        }
    }

    pub fn from_file(filename: &str) -> Result<Scene, String> {
        let file_in = File::open(filename)
            .map_err(|e| format!("Can't open input file: {}", e))?;
        let reader = BufReader::new(&file_in);

        let s: Scene = serde_json::from_reader(reader)
            .map_err(|e| format!("JSON Parse error: {}", e))?;
        Ok(s)
    }

    pub fn add_shape(&mut self, s: Shape) {
        self.shapes.push(s);
    }

    pub fn step(&mut self) {
        // self.light.translate(&[1.0, 0.0, 0.0]);
    }

    pub fn mv_camera_fwd(&mut self) {
        self.camera_pos = self.camera_pos + self.camera_dir;
    }

    pub fn mv_camera_back(&mut self) {
        self.camera_pos = self.camera_pos - self.camera_dir;
    }

    pub fn rot_camera(&mut self, x_rot: f64, y_rot: f64) {
        self.camera_dir = vec3_roty(self.camera_dir, x_rot);

        // project camera_dir to X plane
        let mut x_proj = self.camera_dir;
        x_proj.y = 0.0;
        x_proj = x_proj.normalize();

        let angle = if x_proj.x < 0.0 {
            -Vec3d::new(0.0, 0.0, 1.0).dot(x_proj).acos()
        } else {
            Vec3d::new(0.0, 0.0, 1.0).dot(x_proj).acos()
        };

        self.camera_dir = vec3_roty(self.camera_dir, -angle);
        self.camera_dir = vec3_rotx(self.camera_dir, y_rot);
        self.camera_dir = vec3_roty(self.camera_dir, angle);

        self.camera_dir = self.camera_dir.normalize();
    }

    /// Returns an iterator that scans a full frame at given resolution
    pub fn draw_iter(&self, h: usize, v: usize) -> DrawIter {
        DrawIter::new(self, h, v)
    }

    /// draw_iter converted to (u8, u8, u8)
    pub fn draw_iter_u8(&self,
                        h: usize,
                        v: usize)
                        -> std::iter::Map<DrawIter, fn(Color) -> (u8, u8, u8)> {
        self.draw_iter(h, v).map(Color::col_to_u8)
    }

    /// Returns an iterator for a line at given resolution
    pub fn line_iter(&self, h: usize, v: usize, l: usize) -> LineIter {
        LineIter::new(self, h, v, l)
    }

    /// line_iter converted to (u8, u8, u8)
    pub fn line_iter_u8(&self,
                        h: usize,
                        v: usize,
                        l: usize)
                        -> std::iter::Map<LineIter, fn(Color) -> (u8, u8, u8)> {
        self.line_iter(h, v, l).map(Color::col_to_u8)
    }

    // Recursively trace lines
    fn trace(&self, point: &Vec3d, dir: &Vec3d, depth: i32) -> Color {
        if depth >= self.max_reflection {
            return color::BLACK;
        }

        if let Some(intersect) = self.closest_q(point, dir) {
            let feeler_d = self.light.get_pos() - intersect.point;
            let dist_light = feeler_d.magnitude();
            let feeler_d_unit = feeler_d.normalize();
            let direct_light = self.is_direct_light(&intersect.point, &feeler_d_unit, dist_light);

            let local = phong(point, &intersect, &self.light, direct_light);

            let tmp = (intersect.point - point).normalize();
            let reflection_dir = tmp - (intersect.normal * 2.0 * tmp.dot(intersect.normal));

            let reflected = self.trace(&intersect.point, &reflection_dir, depth + 1);

            Color::add(&local,
                       &(Color::scale(&reflected, intersect.material.reflectivity)))
        } else {
            color::BLACK
        }
    }

    // Is there anything on the path to the light
    fn is_direct_light(&self, point: &Vec3d, dir: &Vec3d, dl: f64) -> bool {
        !self.shapes
             .iter()
             .map(|&ref x| x.intersect_dist(point, dir))
             .any(|dist_opt| dist_opt.map_or(false, |i| i < dl))
    }

    // Checks against all objects and returns closest intersection
    fn closest_q(&self, point: &Vec3d, dir: &Vec3d) -> Option<Intersection> {
        let find_min_opt = |min, (idx, op_val)| {
            match (min, op_val) {
                (Some((_, min_val)), Some(val)) if val < min_val => Some((idx, val)),
                (None, Some(val)) => Some((idx, val)),
                _ => min,
            }
        };

        let closest = self.shapes
            .iter()
            .map(|x| x.intersect_dist(point, dir))
            .enumerate()
            .fold(None, find_min_opt);

        // get intersection point info
        if let Some((idx, _)) = closest {
            self.shapes[idx].intersect(point, dir)
        } else {
            None
        }
    }
}

/// Iterator that iterates over a full frame
pub struct DrawIter<'a> {
    h_res: usize,
    v_res: usize,
    x: usize,
    y: usize,
    left: Vec3d,
    right_step: Vec3d,
    down_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> DrawIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize) -> DrawIter {
        let left = scene.camera_dir.cross(scene.camera_up).normalize();
        let up = left.cross(scene.camera_dir).normalize();
        let point = left + up + scene.camera_dir;
        let right_step = left * (-2.0 / h as f64);
        let down_step = up * (-2.0 / v as f64);
        DrawIter {
            h_res: h,
            v_res: v,
            x: 0,
            y: 0,
            left: left,
            point: point,
            right_step: right_step,
            down_step: down_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for DrawIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.y >= self.v_res {
            return None;
        }

        self.point = self.point + self.right_step;

        let c = self.scene
            .trace(&self.scene.camera_pos, &self.point.normalize(), 0);

        self.x += 1;
        if self.x >= self.h_res {
            self.x = 0;
            self.y += 1;
            self.point = self.point + self.left;
            self.point = self.point + self.left;
            self.point = self.point + self.down_step;
        }

        Some(c)
    }
}

/// Iterator that iterates over a single line
pub struct LineIter<'a> {
    h_res: usize,
    x: usize,
    right_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> LineIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize, l: usize) -> LineIter {
        let left = scene.camera_dir.cross(scene.camera_up).normalize();
        let up = left.cross(scene.camera_dir).normalize();
        let mut point = left + up + scene.camera_dir;
        let right_step = left * (-2.0 / h as f64);
        let down_step = up * (-2.0 / v as f64);

        point = point + down_step * (l as f64);
        LineIter {
            h_res: h,
            x: 0,
            point: point,
            right_step: right_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for LineIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.x >= self.h_res {
            return None;
        }
        self.x += 1;

        self.point = self.point + self.right_step;

        let c = self.scene
            .trace(&self.scene.camera_pos, &self.point.normalize(), 0);

        Some(c)
    }
}

// Calculate color with Phong model
fn phong(view_point: &Vec3d,
         intersection: &Intersection,
         light: &Light,
         direct_light: bool)
         -> Color {

    let point_material = intersection.material;
    let light_pos = light.get_pos();
    let light_color = light.get_color();
    let mut d = (light_pos - intersection.point)
        .normalize()
        .dot(intersection.normal);

    if d < 0.0 {
        d = 0.0;
    }

    let r_diffuse = if direct_light {
        light_color.0 * point_material.diffuse_color.0 * d
    } else {
        0.0
    };
    let g_diffuse = if direct_light {
        light_color.1 * point_material.diffuse_color.1 * d
    } else {
        0.0
    };
    let b_diffuse = if direct_light {
        light_color.2 * point_material.diffuse_color.2 * d
    } else {
        0.0
    };

    let r_ambient = point_material.ambient_color.0;
    let g_ambient = point_material.ambient_color.1;
    let b_ambient = point_material.ambient_color.2;

    let v = (view_point - intersection.point).normalize();
    let lt = (light_pos - intersection.point).normalize();
    let r = intersection.normal * (2.0 * intersection.normal.dot(lt)) - lt;

    let mut s = r.dot(v).powf(point_material.shininess);
    if s < 0.0 {
        s = 0.0;
    }

    let r_specular = if direct_light {
        light_color.0 * point_material.specular_color.0 * s
    } else {
        0.0
    };
    let g_specular = if direct_light {
        light_color.1 * point_material.specular_color.1 * s
    } else {
        0.0
    };
    let b_specular = if direct_light {
        light_color.2 * point_material.specular_color.2 * s
    } else {
        0.0
    };

    let mut r_sum = r_ambient + r_diffuse + r_specular;
    let mut g_sum = g_ambient + g_diffuse + g_specular;
    let mut b_sum = b_ambient + b_diffuse + b_specular;

    if r_sum > 1.0 {
        r_sum = 1.0;
    }

    if g_sum > 1.0 {
        g_sum = 1.0;
    }

    if b_sum > 1.0 {
        b_sum = 1.0;
    }

    Color(r_sum, g_sum, b_sum)
}
<commit_msg>Deserialize code update<commit_after>use std::io::BufReader;
use std::fs::File;

use serde_json;

use cgmath::*;
use shape::*;
use vec3d::*;
use light::*;

use color;
use color::Color;

use std;

#[derive(Serialize, Deserialize)]
pub struct Scene {
    shapes: Vec<Shape>,
    light: Light,
    camera_pos: Vec3d,
    camera_dir: Vec3d,
    camera_up: Vec3d,
    max_reflection: i32,
}

impl Scene {
    pub fn new(light: Light, camera_pos: Vec3d, camera_dir: Vec3d, camera_up: Vec3d) -> Scene {
        Scene {
            shapes: Vec::new(),
            light: light,
            camera_pos: camera_pos,
            camera_dir: camera_dir,
            camera_up: camera_up,
            max_reflection: 4,
        }
    }

    pub fn from_file(filename: &str) -> Result<Scene, String> {
        File::open(filename)
            .map_err(|e| format!("Can't open input file: {}", e))
            .and_then(|f| serde_json::from_reader(BufReader::new(f)).map_err(|e| format!("JSON Parse error: {}", e)))
    }

    pub fn add_shape(&mut self, s: Shape) {
        self.shapes.push(s);
    }

    pub fn step(&mut self) {
        // self.light.translate(&[1.0, 0.0, 0.0]);
    }

    pub fn mv_camera_fwd(&mut self) {
        self.camera_pos = self.camera_pos + self.camera_dir;
    }

    pub fn mv_camera_back(&mut self) {
        self.camera_pos = self.camera_pos - self.camera_dir;
    }

    pub fn rot_camera(&mut self, x_rot: f64, y_rot: f64) {
        self.camera_dir = vec3_roty(self.camera_dir, x_rot);

        // project camera_dir to X plane
        let mut x_proj = self.camera_dir;
        x_proj.y = 0.0;
        x_proj = x_proj.normalize();

        let angle = if x_proj.x < 0.0 {
            -Vec3d::new(0.0, 0.0, 1.0).dot(x_proj).acos()
        } else {
            Vec3d::new(0.0, 0.0, 1.0).dot(x_proj).acos()
        };

        self.camera_dir = vec3_roty(self.camera_dir, -angle);
        self.camera_dir = vec3_rotx(self.camera_dir, y_rot);
        self.camera_dir = vec3_roty(self.camera_dir, angle);

        self.camera_dir = self.camera_dir.normalize();
    }

    /// Returns an iterator that scans a full frame at given resolution
    pub fn draw_iter(&self, h: usize, v: usize) -> DrawIter {
        DrawIter::new(self, h, v)
    }

    /// draw_iter converted to (u8, u8, u8)
    pub fn draw_iter_u8(&self,
                        h: usize,
                        v: usize)
                        -> std::iter::Map<DrawIter, fn(Color) -> (u8, u8, u8)> {
        self.draw_iter(h, v).map(Color::col_to_u8)
    }

    /// Returns an iterator for a line at given resolution
    pub fn line_iter(&self, h: usize, v: usize, l: usize) -> LineIter {
        LineIter::new(self, h, v, l)
    }

    /// line_iter converted to (u8, u8, u8)
    pub fn line_iter_u8(&self,
                        h: usize,
                        v: usize,
                        l: usize)
                        -> std::iter::Map<LineIter, fn(Color) -> (u8, u8, u8)> {
        self.line_iter(h, v, l).map(Color::col_to_u8)
    }

    // Recursively trace lines
    fn trace(&self, point: &Vec3d, dir: &Vec3d, depth: i32) -> Color {
        if depth >= self.max_reflection {
            return color::BLACK;
        }

        if let Some(intersect) = self.closest_q(point, dir) {
            let feeler_d = self.light.get_pos() - intersect.point;
            let dist_light = feeler_d.magnitude();
            let feeler_d_unit = feeler_d.normalize();
            let direct_light = self.is_direct_light(&intersect.point, &feeler_d_unit, dist_light);

            let local = phong(point, &intersect, &self.light, direct_light);

            let tmp = (intersect.point - point).normalize();
            let reflection_dir = tmp - (intersect.normal * 2.0 * tmp.dot(intersect.normal));

            let reflected = self.trace(&intersect.point, &reflection_dir, depth + 1);

            Color::add(&local,
                       &(Color::scale(&reflected, intersect.material.reflectivity)))
        } else {
            color::BLACK
        }
    }

    // Is there anything on the path to the light
    fn is_direct_light(&self, point: &Vec3d, dir: &Vec3d, dl: f64) -> bool {
        !self.shapes
             .iter()
             .map(|&ref x| x.intersect_dist(point, dir))
             .any(|dist_opt| dist_opt.map_or(false, |i| i < dl))
    }

    // Checks against all objects and returns closest intersection
    fn closest_q(&self, point: &Vec3d, dir: &Vec3d) -> Option<Intersection> {
        let find_min_opt = |min, (idx, op_val)| {
            match (min, op_val) {
                (Some((_, min_val)), Some(val)) if val < min_val => Some((idx, val)),
                (None, Some(val)) => Some((idx, val)),
                _ => min,
            }
        };

        let closest = self.shapes
            .iter()
            .map(|x| x.intersect_dist(point, dir))
            .enumerate()
            .fold(None, find_min_opt);

        // get intersection point info
        if let Some((idx, _)) = closest {
            self.shapes[idx].intersect(point, dir)
        } else {
            None
        }
    }
}

/// Iterator that iterates over a full frame
pub struct DrawIter<'a> {
    h_res: usize,
    v_res: usize,
    x: usize,
    y: usize,
    left: Vec3d,
    right_step: Vec3d,
    down_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> DrawIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize) -> DrawIter {
        let left = scene.camera_dir.cross(scene.camera_up).normalize();
        let up = left.cross(scene.camera_dir).normalize();
        let point = left + up + scene.camera_dir;
        let right_step = left * (-2.0 / h as f64);
        let down_step = up * (-2.0 / v as f64);
        DrawIter {
            h_res: h,
            v_res: v,
            x: 0,
            y: 0,
            left: left,
            point: point,
            right_step: right_step,
            down_step: down_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for DrawIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.y >= self.v_res {
            return None;
        }

        self.point = self.point + self.right_step;

        let c = self.scene
            .trace(&self.scene.camera_pos, &self.point.normalize(), 0);

        self.x += 1;
        if self.x >= self.h_res {
            self.x = 0;
            self.y += 1;
            self.point = self.point + self.left;
            self.point = self.point + self.left;
            self.point = self.point + self.down_step;
        }

        Some(c)
    }
}

/// Iterator that iterates over a single line
pub struct LineIter<'a> {
    h_res: usize,
    x: usize,
    right_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> LineIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize, l: usize) -> LineIter {
        let left = scene.camera_dir.cross(scene.camera_up).normalize();
        let up = left.cross(scene.camera_dir).normalize();
        let mut point = left + up + scene.camera_dir;
        let right_step = left * (-2.0 / h as f64);
        let down_step = up * (-2.0 / v as f64);

        point = point + down_step * (l as f64);
        LineIter {
            h_res: h,
            x: 0,
            point: point,
            right_step: right_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for LineIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.x >= self.h_res {
            return None;
        }
        self.x += 1;

        self.point = self.point + self.right_step;

        let c = self.scene
            .trace(&self.scene.camera_pos, &self.point.normalize(), 0);

        Some(c)
    }
}

// Calculate color with Phong model
fn phong(view_point: &Vec3d,
         intersection: &Intersection,
         light: &Light,
         direct_light: bool)
         -> Color {

    let point_material = intersection.material;
    let light_pos = light.get_pos();
    let light_color = light.get_color();
    let mut d = (light_pos - intersection.point)
        .normalize()
        .dot(intersection.normal);

    if d < 0.0 {
        d = 0.0;
    }

    let r_diffuse = if direct_light {
        light_color.0 * point_material.diffuse_color.0 * d
    } else {
        0.0
    };
    let g_diffuse = if direct_light {
        light_color.1 * point_material.diffuse_color.1 * d
    } else {
        0.0
    };
    let b_diffuse = if direct_light {
        light_color.2 * point_material.diffuse_color.2 * d
    } else {
        0.0
    };

    let r_ambient = point_material.ambient_color.0;
    let g_ambient = point_material.ambient_color.1;
    let b_ambient = point_material.ambient_color.2;

    let v = (view_point - intersection.point).normalize();
    let lt = (light_pos - intersection.point).normalize();
    let r = intersection.normal * (2.0 * intersection.normal.dot(lt)) - lt;

    let mut s = r.dot(v).powf(point_material.shininess);
    if s < 0.0 {
        s = 0.0;
    }

    let r_specular = if direct_light {
        light_color.0 * point_material.specular_color.0 * s
    } else {
        0.0
    };
    let g_specular = if direct_light {
        light_color.1 * point_material.specular_color.1 * s
    } else {
        0.0
    };
    let b_specular = if direct_light {
        light_color.2 * point_material.specular_color.2 * s
    } else {
        0.0
    };

    let mut r_sum = r_ambient + r_diffuse + r_specular;
    let mut g_sum = g_ambient + g_diffuse + g_specular;
    let mut b_sum = b_ambient + b_diffuse + b_specular;

    if r_sum > 1.0 {
        r_sum = 1.0;
    }

    if g_sum > 1.0 {
        g_sum = 1.0;
    }

    if b_sum > 1.0 {
        b_sum = 1.0;
    }

    Color(r_sum, g_sum, b_sum)
}
<|endoftext|>


<commit_before>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use super::*;
use test::*;

#[test]
fn version() {
    assert_eq!(super::MPV_CLIENT_API_VERSION,
               unsafe { raw::mpv_client_api_version() });
}

#[test]
fn options_properties() {
    // TODO: Cover all `Data` variants.

    let mpv = Parent::new(false).unwrap();
    mpv.set_option(&mut Property::new("cache-initial", Data::new(1))).unwrap();
    mpv.set_option(&mut Property::new("volume", Data::new(0))).unwrap();
    mpv.set_option(&mut Property::new("no-video", Data::new(true))).unwrap();
    mpv.set_option(&mut Property::new("ytdl", Data::new(true))).unwrap();
    mpv.init().unwrap();

    mpv.playlist(&PlaylistOp::Loadfiles(&[File::new(::std::path::Path::new("https://www.youtube.\
                                                                   com/watch?v=DLzxrzFCyOs"),
                                                        FileState::AppendPlay,
                                                        None)]))
           .unwrap();
    ::std::thread::sleep(::std::time::Duration::from_secs(7)); // Guesstime of time required to load

    assert_eq!(Data::new(0),
               mpv.get_property("volume", &Format::Int64)
                  .unwrap());

    mpv.set_property(Property::new("volume", Data::new(4))).unwrap();

    assert_eq!(Data::new(4),
               mpv.get_property("volume", &Format::Int64)
                  .unwrap());
}

#[bench]
fn mpv_error(b: &mut Bencher) {
  let n = black_box(0);

  b.iter(|| {
    for n in -19...n {
      super::wrapper::mpv_err((), n);
    }
  });
}
<commit_msg>Fix typo + doc<commit_after>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use super::*;
use test::*;

#[test]
fn version() {
    assert_eq!(super::MPV_CLIENT_API_VERSION,
               unsafe { raw::mpv_client_api_version() });
}

#[test]
fn options_properties() {
    // TODO: Cover all `Data` variants.

    let mpv = Parent::new(false).unwrap();
    mpv.set_option(&mut Property::new("cache-initial", Data::new(1))).unwrap();
    mpv.set_option(&mut Property::new("volume", Data::new(0))).unwrap();
    mpv.set_option(&mut Property::new("no-video", Data::new(true))).unwrap();
    mpv.set_option(&mut Property::new("ytdl", Data::new(true))).unwrap();
    mpv.init().unwrap();

    // For some reason, the volume is only correctly set when a file is loaded...
    mpv.playlist(&PlaylistOp::Loadfiles(&[File::new(::std::path::Path::new("https://www.youtube.\
                                                                   com/watch?v=DLzxrzFCyOs"),
                                                        FileState::AppendPlay,
                                                        None)]))
           .unwrap();
    // Guesstimate of time required to load
    ::std::thread::sleep(::std::time::Duration::from_secs(7));

    assert_eq!(Data::new(0),
               mpv.get_property("volume", &Format::Int64)
                  .unwrap());

    mpv.set_property(Property::new("volume", Data::new(4))).unwrap();

    assert_eq!(Data::new(4),
               mpv.get_property("volume", &Format::Int64)
                  .unwrap());
}

#[bench]
fn mpv_error(b: &mut Bencher) {
  let n = black_box(0);

  b.iter(|| {
    for n in -19...n {
      super::wrapper::mpv_err((), n);
    }
  });
}
<|endoftext|>