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

use super::ast::ScalarKind::*;
use super::error::*;
use super::parser::*;
use super::parser::Type::*;
use super::parser::ExprKind::*;

#[cfg(test)] use super::grammar::parse_expr;
#[cfg(test)] use super::ast::BinOpKind::*;

type TypeMap = HashMap<String, Option<Type>>;

/// Partially inferred types about a function, which are passed down from parent nodes in ASTs.
struct FunctionTypes {
    params: Vec<Option<Type>>,
    result: Option<Type>
}

/// Infer the missing types of all expressions a tree, modifying it in place to set them.
pub fn infer_types(expr: &mut Expr) -> WeldResult<()> {
    // Note: we should also make sure that the types already set in expr are consistent; this will
    // be done by the first call to infer_up.
    loop {
        let mut env = TypeMap::new();
        let res = try!(infer_up(expr, &mut env, None));
        if res == false {
            if !has_all_types(expr) {
                return weld_err!("Could not infer some types")
            }
            return Ok(())
        }
    }
}

/// Do expr or all of its descendants have types set?
fn has_all_types(expr: &Expr) -> bool {
    if expr.ty.is_none() {
        return false;
    }
    expr.children().all(|c| has_all_types(c))
}

/// Infer the types of expressions upward from the leaves of a tree, using infer_locally.
/// Return true if any new expression's type was inferred, or an error if types are inconsistent.
fn infer_up(expr: &mut Expr, env: &mut TypeMap, fts: Option<FunctionTypes>) -> WeldResult<bool> {
    // Remember whether we inferred any new type
    let mut changed = false;

    // Special case: for Lets and Lambdas, add the types of identifiers they (re-)define to env.
    let mut old_bindings: Vec<(String, Option<Option<Type>>)> = Vec::new();
    match expr.kind {
        Let(ref symbol, ref value, _) => {
            old_bindings.push((symbol.clone(), env.insert(symbol.clone(), value.ty.clone())));
        }

        Lambda(ref params, _) => {
            for p in params {
                old_bindings.push((p.name.clone(), env.insert(p.name.clone(), p.ty.clone())));
            }
        }

        _ => ()
    }

    // Infer types of children first (with new environment)
    match expr.kind {
        Map(ref mut data, ref mut func) => {
            changed |= try!(infer_up(data, env, None));
            let data_type = match data.ty {
                Some(Vector(ref elem_type)) => Some(*elem_type.clone()),
                Some(_) => return weld_err!("Mismatched types for Map"),
                _ => None
            };
            let result_type = match expr.ty {
                Some(Vector(ref elem_type)) => Some(*elem_type.clone()),
                Some(_) => return weld_err!("Mismatched types for Map"),
                _ => None
            };
            let expected_fts = FunctionTypes { params: vec![data_type], result: result_type };
            changed |= try!(infer_up(func, env, Some(expected_fts)));
        }

        _ => {
            for c in expr.children_mut() {
                changed |= try!(infer_up(c, env, None));
            }
        }
    }

    // Infer our type
    changed |= try!(infer_locally(expr, env, fts));

    // Undo the environment changes from Let
    for (symbol, opt) in old_bindings {
        match opt {
            Some(old) => env.insert(symbol, old),
            None => env.remove(&symbol)
        };
    }

    Ok(changed)
}

/// Infer the type of expr or its children locally based on what is known about some of them.
/// Return true if any new expression's type was inferred, or an error if types are inconsistent.
fn infer_locally(expr: &mut Expr, env: &mut TypeMap, fts: Option<FunctionTypes>) -> WeldResult<bool> {
    match expr.kind {
        I32Literal(_) => {
            match expr.ty {
                None => {
                    expr.ty = Some(Scalar(I32));
                    Ok(true)
                }
                Some(Scalar(I32)) => Ok(false),
                Some(_) => weld_err!("Wrong type ascribed to I32Literal")
            }
        }

        BoolLiteral(_) => {
            match expr.ty {
                None => {
                    expr.ty = Some(Scalar(Bool));
                    Ok(true)
                }
                Some(Scalar(Bool)) => Ok(false),
                Some(_) => weld_err!("Wrong type ascribed to BoolLiteral")
            }
        }

        BinOp(_, ref mut lefts, ref mut right) => {
            let mut types_seen = Vec::<Type>::new();
            for &ty in [&expr.ty, &lefts.ty, &right.ty].iter() {
                types_seen.extend(ty.clone());
            }
            if !types_seen.is_empty() {
                let first_type = types_seen.pop().unwrap();
                for ty in &types_seen {
                    if *ty != first_type {
                        return weld_err!("Mismatched types for BinOp")
                    }
                }
                let mut changed = false;
                for ty in [&mut expr.ty, &mut lefts.ty, &mut right.ty].iter_mut() {
                    if ty.is_none() {
                        **ty = Some(first_type.clone());
                        changed = true;
                    }
                }
                return Ok(changed)
            }
            Ok(false)
        }

        Ident(ref symbol) => {
            match env.get(symbol) {
                None => weld_err!("Undefined identifier"),
                Some(ty_opt) => {
                    if ty_opt.is_some() && expr.ty.is_some() && *ty_opt != expr.ty {
                        weld_err!("Mismatched types for Ident")
                    } else if ty_opt.is_some() && expr.ty.is_none() {
                        expr.ty = ty_opt.clone();
                        Ok(true)
                    } else {
                        // Don't try to propagate the type up from this Ident to its Let node.
                        Ok(false)
                    }
                }
            }
        }

        Let (_, _, ref mut body) => {
            if expr.ty.is_some() && body.ty.is_some() && expr.ty != body.ty {
                weld_err!("Mismatched types for Let body")
            } else if body.ty.is_some() && expr.ty.is_none() {
                expr.ty = body.ty.clone();
                Ok(true)
            } else if body.ty.is_none() && expr.ty.is_some() {
                body.ty = expr.ty.clone();
                Ok(true)
            } else {
                Ok(false)
            }
        }

        MakeVector(ref exprs) if exprs.len() > 0 => {
            // TODO: check types of all other vector elements!
            let first_expr = exprs.first().unwrap();
            match first_expr.ty {
                Some(ref elem_type) => {
                    for other_expr in exprs {
                        if other_expr.ty != first_expr.ty {
                            return weld_err!("Mismatched types for MakeVector");
                        }
                    }
                    let vec_type = Some(Vector(Box::new(elem_type.clone())));
                    if expr.ty.is_some() && expr.ty != vec_type {
                        return weld_err!("Mismatched types for MakeVector");
                    } else if expr.ty.is_none() {
                        expr.ty = vec_type;
                        Ok(true)
                    } else {
                        Ok(false)
                    }
                }
                None => Ok(false)
            }
        }

        Lambda(ref mut params, ref mut body) => {
            let (expected_params, expected_result) = match fts {
                Some(FunctionTypes { params, result }) => (params, result),
                None => (vec![None; params.len()], None)
            };

            let mut changed = false;

            // Harmonize parameter types
            for (i, p) in params.iter_mut().enumerate() {
                let expected = expected_params.get(i).unwrap();
                if p.ty.is_some() && expected.is_some() && p.ty != *expected {
                    return weld_err!("Mismatched parameter types for Lambda");
                } else if p.ty.is_none() && expected.is_some() {
                    p.ty = expected.clone();
                    changed = true;
                }
            }

            // Harmonize body type
            if body.ty.is_some() && expected_result.is_some() && body.ty != expected_result {
                return weld_err!("Mismatched return type for Lambda");
            } else if body.ty.is_none() && expected_result.is_some() {
                body.ty = expected_result.clone();
                changed = true;
            }

            // Set our overall type if we can
            let have_params = params.iter().all(|p| p.ty.is_some());
            if have_params && body.ty.is_some() {
                let param_types = params.iter().map(|p| p.ty.clone().unwrap()).collect();
                let func_type = Some(Function(param_types, Box::new(body.ty.clone().unwrap())));
                if expr.ty.is_some() && expr.ty != func_type {
                    return weld_err!("Mismatched overall function type for Lambda");
                } else if expr.ty.is_none() {
                    expr.ty = func_type;
                    changed = true;
                }
            }

            Ok(changed)
        }

        Map(_, ref func) => {
            let expected_type = match func.ty {
                Some(Function(_, ref res)) => Some(Vector(res.clone())),
                _ => None
            };
            if expected_type.is_some() && expr.ty.is_some() && expr.ty != expected_type {
                weld_err!("Mismatched types for Map")
            } else if expected_type.is_some() && expr.ty.is_none() {
                expr.ty = expected_type;
                Ok(true)
            } else {
                Ok(false)
            }
        }

        _ => Ok(false)
    }
}

#[test]
fn infer_types_simple() {
    let int_lit = expr_box(I32Literal(1));
    let bool_lit = expr_box(BoolLiteral(false));
    let sum = expr_box(BinOp(Add, int_lit.clone(), int_lit.clone()));
    let prod = expr_box(BinOp(Multiply, sum.clone(), sum.clone()));

    let mut e = *int_lit.clone();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));

    let mut e = *bool_lit.clone();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(Bool)));

    let mut e = *sum.clone();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));

    let mut e = *prod.clone();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));
}

#[test]
fn infer_types_let() {
    let mut e = *parse_expr("a := 1; a + a").unwrap();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));

    let mut e = *parse_expr("a + a").unwrap();
    assert!(infer_types(&mut e).is_err());

    let mut e = *parse_expr("a:i32 := 1; a").unwrap();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));

    let mut e = *parse_expr("a:bool := 1; a").unwrap();
    assert!(infer_types(&mut e).is_err());

    let mut e = *parse_expr("a := 1; a:bool").unwrap();
    assert!(infer_types(&mut e).is_err());
}
<commit_msg>Simplifying inference<commit_after>use std::collections::HashMap;

use super::ast::ScalarKind::*;
use super::error::*;
use super::parser::*;
use super::parser::Type::*;
use super::parser::ExprKind::*;

#[cfg(test)] use super::grammar::parse_expr;
#[cfg(test)] use super::ast::BinOpKind::*;

type TypeMap = HashMap<String, Option<Type>>;

/// Partially inferred types about a function, which are passed down from parent nodes in ASTs.
struct FunctionTypes {
    params: Vec<Option<Type>>,
    result: Option<Type>
}

/// Infer the missing types of all expressions a tree, modifying it in place to set them.
pub fn infer_types(expr: &mut Expr) -> WeldResult<()> {
    // Note: we should also make sure that the types already set in expr are consistent; this will
    // be done by the first call to infer_up.
    loop {
        let mut env = TypeMap::new();
        let res = try!(infer_up(expr, &mut env, None));
        if res == false {
            if !has_all_types(expr) {
                return weld_err!("Could not infer some types")
            }
            return Ok(())
        }
    }
}

/// Do expr or all of its descendants have types set?
fn has_all_types(expr: &Expr) -> bool {
    if expr.ty.is_none() {
        return false;
    }
    expr.children().all(|c| has_all_types(c))
}

/// Infer the types of expressions upward from the leaves of a tree, using infer_locally.
/// Return true if any new expression's type was inferred, or an error if types are inconsistent.
fn infer_up(expr: &mut Expr, env: &mut TypeMap, fts: Option<FunctionTypes>) -> WeldResult<bool> {
    // Remember whether we inferred any new type
    let mut changed = false;

    // Special case: for Lets and Lambdas, add the types of identifiers they (re-)define to env.
    let mut old_bindings: Vec<(String, Option<Option<Type>>)> = Vec::new();
    match expr.kind {
        Let(ref symbol, ref value, _) => {
            old_bindings.push((symbol.clone(), env.insert(symbol.clone(), value.ty.clone())));
        }

        Lambda(ref params, _) => {
            for p in params {
                old_bindings.push((p.name.clone(), env.insert(p.name.clone(), p.ty.clone())));
            }
        }

        _ => ()
    }

    // Infer types of children first (with new environment)
    match expr.kind {
        Map(ref mut data, ref mut func) => {
            changed |= try!(infer_up(data, env, None));
            let data_type = match data.ty {
                Some(Vector(ref elem_type)) => Some(*elem_type.clone()),
                Some(_) => return weld_err!("Mismatched types for Map"),
                _ => None
            };
            let result_type = match expr.ty {
                Some(Vector(ref elem_type)) => Some(*elem_type.clone()),
                Some(_) => return weld_err!("Mismatched types for Map"),
                _ => None
            };
            let expected_fts = FunctionTypes { params: vec![data_type], result: result_type };
            changed |= try!(infer_up(func, env, Some(expected_fts)));
        }

        _ => {
            for c in expr.children_mut() {
                changed |= try!(infer_up(c, env, None));
            }
        }
    }

    // Infer our type
    changed |= try!(infer_locally(expr, env, fts));

    // Undo the environment changes from Let
    for (symbol, opt) in old_bindings {
        match opt {
            Some(old) => env.insert(symbol, old),
            None => env.remove(&symbol)
        };
    }

    Ok(changed)
}

/// Infer the type of expr or its children locally based on what is known about some of them.
/// Return true if any new expression's type was inferred, or an error if types are inconsistent.
fn infer_locally(expr: &mut Expr, env: &mut TypeMap, fts: Option<FunctionTypes>) -> WeldResult<bool> {
    match expr.kind {
        I32Literal(_) =>
            push_concrete_type(&mut expr.ty, Scalar(I32), "Wrong type ascribed to I32Literal"),

        BoolLiteral(_) =>
            push_concrete_type(&mut expr.ty, Scalar(Bool), "Wrong type ascribed to BoolLiteral"),

        BinOp(_, ref mut lefts, ref mut right) => {
            let mut types_seen = Vec::<Type>::new();
            for &ty in [&expr.ty, &lefts.ty, &right.ty].iter() {
                types_seen.extend(ty.clone());
            }
            if !types_seen.is_empty() {
                let first_type = Some(types_seen.pop().unwrap());
                let mut changed = false;
                for ty in [&mut expr.ty, &mut lefts.ty, &mut right.ty].iter_mut() {
                    changed |= try!(push_type(ty, &first_type, "Mismatched types for BinOp"));
                }
                return Ok(changed)
            }
            Ok(false)
        }

        Ident(ref symbol) => {
            match env.get(symbol) {
                None => weld_err!("Undefined identifier"),
                Some(t) => push_type(&mut expr.ty, t, "Mismatched types for Ident")
            }
        }

        Let (_, _, ref mut body) => {
            let mut changed = false;
            changed |= try!(push_type(&mut expr.ty, &body.ty, "Mismatched types for Let body"));
            changed |= try!(push_type(&mut body.ty, &expr.ty, "Mismatched types for Let body"));
            Ok(changed)
        }

        MakeVector(ref exprs) if exprs.len() > 0 => {
            // TODO: check types of all other vector elements!
            let first_expr = exprs.first().unwrap();
            match first_expr.ty {
                Some(ref elem_type) => {
                    for other_expr in exprs {
                        if other_expr.ty != first_expr.ty {
                            return weld_err!("Mismatched types for MakeVector");
                        }
                    }
                    let vec_type = Some(Vector(Box::new(elem_type.clone())));
                    push_type(&mut expr.ty, &vec_type, "Mismatched types for MakeVector")
                }
                None => Ok(false)
            }
        }

        Lambda(ref mut params, ref mut body) => {
            let (expected_params, expected_result) = match fts {
                Some(FunctionTypes { params, result }) => (params, result),
                None => (vec![None; params.len()], None)
            };

            let mut changed = false;

            // Harmonize parameter types
            for (i, p) in params.iter_mut().enumerate() {
                let expected = expected_params.get(i).unwrap();
                changed |= try!(push_type(&mut p.ty, &expected, "Mismatched Lambda param types"));
            }

            // Harmonize body type
            changed |= try!(push_type(
                &mut body.ty, &expected_result, "Mismatched Lambda return type"));

            // Set our overall type if we can
            let have_params = params.iter().all(|p| p.ty.is_some());
            if have_params && body.ty.is_some() {
                let param_types = params.iter().map(|p| p.ty.clone().unwrap()).collect();
                let func_type = Some(Function(param_types, Box::new(body.ty.clone().unwrap())));
                changed |= try!(push_type(&mut expr.ty, &func_type, "Mismatched type for Lambda"))
            }

            Ok(changed)
        }

        Map(_, ref func) => {
            let expected_type = match func.ty {
                Some(Function(_, ref res)) => Some(Vector(res.clone())),
                _ => None
            };
            push_type(&mut expr.ty, &expected_type, "Mismatched types for Map")
        }

        _ => Ok(false)
    }
}

/// Force the given type to be assigned to an Option<Type>, or report an error if it has the wrong
/// type. Return a result indicating whether the option has changed (i.e. a new type as added).
fn push_concrete_type(opt: &mut Option<Type>, expected: Type, error: &str) -> WeldResult<bool> {
    match *opt {
        None => {
            *opt = Some(expected);
            Ok(true)
        }
        Some(ref t) if *t == expected => Ok(false),
        _ => weld_err!("{}", error)
    }
}

/// Force the type of `dest` to be `src` if `src` is set, or report an error if it has the wrong
/// type. Return a result indicating whether the type of `dest` has changed.
fn push_type(dest: &mut Option<Type>, src: &Option<Type>, error: &str) -> WeldResult<bool> {
    if dest.is_some() && src.is_some() && *dest != *src {
        weld_err!("{}", error)
    } else if src.is_some() && dest.is_none() {
        *dest = src.clone();
        Ok(true)
    } else {
        Ok(false)
    }
}

#[test]
fn infer_types_simple() {
    let int_lit = expr_box(I32Literal(1));
    let bool_lit = expr_box(BoolLiteral(false));
    let sum = expr_box(BinOp(Add, int_lit.clone(), int_lit.clone()));
    let prod = expr_box(BinOp(Multiply, sum.clone(), sum.clone()));

    let mut e = *int_lit.clone();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));

    let mut e = *bool_lit.clone();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(Bool)));

    let mut e = *sum.clone();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));

    let mut e = *prod.clone();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));
}

#[test]
fn infer_types_let() {
    let mut e = *parse_expr("a := 1; a + a").unwrap();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));

    let mut e = *parse_expr("a + a").unwrap();
    assert!(infer_types(&mut e).is_err());

    let mut e = *parse_expr("a:i32 := 1; a").unwrap();
    assert!(infer_types(&mut e).is_ok());
    assert_eq!(e.ty, Some(Scalar(I32)));

    let mut e = *parse_expr("a:bool := 1; a").unwrap();
    assert!(infer_types(&mut e).is_err());

    let mut e = *parse_expr("a := 1; a:bool").unwrap();
    assert!(infer_types(&mut e).is_err());
}
<|endoftext|>


<commit_before>use std::convert;
use std::io;
use std::io::Write;
use std::num::ToPrimitive;
use std::result::Result;

use byteorder;
use byteorder::WriteBytesExt;

use super::{
    Marker,
};

#[derive(Debug)]
pub enum WriteError {
    Io(io::Error),
}

impl convert::From<byteorder::Error> for WriteError {
    fn from(err: byteorder::Error) -> WriteError {
        match err {
            byteorder::Error::UnexpectedEOF => unimplemented!(),
            byteorder::Error::Io(err) => WriteError::Io(err),
        }
    }
}

// TODO: Split Error for each function, permitting each function to return variant with impossible values.
#[derive(Debug)]
pub enum Error {
    /// Unable to write the value with the given type
    TypeMismatch,
    /// IO error while writing marker.
    InvalidMarkerWrite(WriteError),
    /// IO error while writing single-byte data.
    InvalidFixedValueWrite(WriteError),
    /// IO error while writing data.
    InvalidDataWrite(WriteError),
}

#[unstable(reason = "unwrap")]
fn write_marker<W>(wr: &mut W, marker: Marker) -> Result<(), Error>
    where W: Write
{
    // TODO: Should never panics, but looks creepy. Use own trait instead.
    let byte = marker.to_u8().unwrap();

    match wr.write_u8(byte) {
        Ok(())   => Ok(()),
        Err(err) => Err(Error::InvalidMarkerWrite(From::from(err)))
    }
}

#[unstable(reason = "unwrap")]
fn write_fixval<W>(wr: &mut W, marker: Marker) -> Result<(), Error>
    where W: Write
{
    // TODO: Should never panics, but looks creepy. Use own trait instead.
    let byte = marker.to_u8().unwrap();

    match wr.write_u8(byte) {
        Ok(())   => Ok(()),
        Err(err) => Err(Error::InvalidFixedValueWrite(From::from(err)))
    }
}

#[unstable(reason = "docs; stabilize Result variant")]
pub fn write_nil<W>(wr: &mut W) -> Result<(), Error>
    where W: Write
{
    write_marker(wr, Marker::Null)
}

// With strictly type checking.
pub fn write_pfix<W>(wr: &mut W, val: u8) -> Result<(), Error>
    where W: Write
{
    if val < 128 {
        write_fixval(wr, Marker::PositiveFixnum(val))
    } else {
        Err(Error::TypeMismatch)
    }
}

pub fn write_nfix<W>(wr: &mut W, val: i8) -> Result<(), Error>
    where W: Write
{
    if -32 <= val && val < 0 {
        write_fixval(wr, Marker::NegativeFixnum(val))
    } else {
        Err(Error::TypeMismatch)
    }
}

macro_rules! make_write_data_fn {
    (deduce, $writer:ident, $encoder:ident, 0, $val:ident)
        => ($writer.$encoder($val););
    (deduce, $writer:ident, $encoder:ident, 1, $val:ident)
        => ($writer.$encoder::<byteorder::BigEndian>($val););
    (gen, $t:ty, $d:tt, $name:ident, $encoder:ident) => {
        fn $name<W>(wr: &mut W, val: $t) -> Result<(), Error>
            where W: Write
        {
            match make_write_data_fn!(deduce, wr, $encoder, $d, val) {
                Ok(data) => Ok(data),
                Err(err) => Err(Error::InvalidDataWrite(From::from(err))),
            }
        }
    };
    (u8,    $name:ident, $encoder:ident) => (make_write_data_fn!(gen, u8, 0, $name, $encoder););
    (i8,    $name:ident, $encoder:ident) => (make_write_data_fn!(gen, i8, 0, $name, $encoder););
    ($t:ty, $name:ident, $encoder:ident) => (make_write_data_fn!(gen, $t, 1, $name, $encoder););
}

make_write_data_fn!(u8,  write_data_u8,  write_u8);
make_write_data_fn!(u16, write_data_u16, write_u16);
make_write_data_fn!(u32, write_data_u32, write_u32);
make_write_data_fn!(u64, write_data_u64, write_u64);
make_write_data_fn!(i8,  write_data_i8,  write_i8);
make_write_data_fn!(i16, write_data_i16, write_i16);
make_write_data_fn!(i32, write_data_i32, write_i32);
make_write_data_fn!(i64, write_data_i64, write_i64);

// With strictly type checking.
pub fn write_u8<W>(wr: &mut W, val: u8) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::U8));

    write_data_u8(wr, val)
}

pub fn write_u16<W>(wr: &mut W, val: u16) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::U16));

    write_data_u16(wr, val)
}

pub fn write_u32<W>(wr: &mut W, val: u32) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::U32));

    write_data_u32(wr, val)
}

pub fn write_u64<W>(wr: &mut W, val: u64) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::U64));

    write_data_u64(wr, val)
}

pub fn write_i8<W>(wr: &mut W, val: i8) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::I8));

    write_data_i8(wr, val)
}

pub fn write_i16<W>(wr: &mut W, val: i16) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::I16));

    write_data_i16(wr, val)
}

pub fn write_i32<W>(wr: &mut W, val: i32) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::I32));

    write_data_i32(wr, val)
}

pub fn write_i64<W>(wr: &mut W, val: i64) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::I64));

    write_data_i64(wr, val)
}
<commit_msg>[Misc] Code style.<commit_after>use std::convert;
use std::io;
use std::io::Write;
use std::num::ToPrimitive;
use std::result::Result;

use byteorder;
use byteorder::WriteBytesExt;

use super::{
    Marker,
};

#[derive(Debug)]
pub enum WriteError {
    Io(io::Error),
}

impl convert::From<byteorder::Error> for WriteError {
    fn from(err: byteorder::Error) -> WriteError {
        match err {
            byteorder::Error::UnexpectedEOF => unimplemented!(),
            byteorder::Error::Io(err) => WriteError::Io(err),
        }
    }
}

// TODO: Split Error for each function, permitting each function to return variant with impossible values.
#[derive(Debug)]
pub enum Error {
    /// Unable to write the value with the given type
    TypeMismatch,
    /// IO error while writing marker.
    InvalidMarkerWrite(WriteError),
    /// IO error while writing single-byte data.
    InvalidFixedValueWrite(WriteError),
    /// IO error while writing data.
    InvalidDataWrite(WriteError),
}

#[unstable(reason = "unwrap")]
fn write_marker<W>(wr: &mut W, marker: Marker) -> Result<(), Error>
    where W: Write
{
    // TODO: Should never panics, but looks creepy. Use own trait instead.
    let byte = marker.to_u8().unwrap();

    match wr.write_u8(byte) {
        Ok(())   => Ok(()),
        Err(err) => Err(Error::InvalidMarkerWrite(From::from(err)))
    }
}

#[unstable(reason = "unwrap")]
fn write_fixval<W>(wr: &mut W, marker: Marker) -> Result<(), Error>
    where W: Write
{
    // TODO: Should never panics, but looks creepy. Use own trait instead.
    let byte = marker.to_u8().unwrap();

    match wr.write_u8(byte) {
        Ok(())   => Ok(()),
        Err(err) => Err(Error::InvalidFixedValueWrite(From::from(err)))
    }
}

#[unstable(reason = "docs; stabilize Result variant")]
pub fn write_nil<W>(wr: &mut W) -> Result<(), Error>
    where W: Write
{
    write_marker(wr, Marker::Null)
}

// With strictly type checking.
pub fn write_pfix<W>(wr: &mut W, val: u8) -> Result<(), Error>
    where W: Write
{
    if val < 128 {
        write_fixval(wr, Marker::PositiveFixnum(val))
    } else {
        Err(Error::TypeMismatch)
    }
}

pub fn write_nfix<W>(wr: &mut W, val: i8) -> Result<(), Error>
    where W: Write
{
    if -32 <= val && val < 0 {
        write_fixval(wr, Marker::NegativeFixnum(val))
    } else {
        Err(Error::TypeMismatch)
    }
}

macro_rules! make_write_data_fn {
    (deduce, $writer:ident, $encoder:ident, 0, $val:ident)
        => ($writer.$encoder($val););
    (deduce, $writer:ident, $encoder:ident, 1, $val:ident)
        => ($writer.$encoder::<byteorder::BigEndian>($val););
    (gen, $t:ty, $d:tt, $name:ident, $encoder:ident) => {
        fn $name<W>(wr: &mut W, val: $t) -> Result<(), Error>
            where W: Write
        {
            match make_write_data_fn!(deduce, wr, $encoder, $d, val) {
                Ok(data) => Ok(data),
                Err(err) => Err(Error::InvalidDataWrite(From::from(err))),
            }
        }
    };
    (u8,    $name:ident, $encoder:ident) => (make_write_data_fn!(gen, u8, 0, $name, $encoder););
    (i8,    $name:ident, $encoder:ident) => (make_write_data_fn!(gen, i8, 0, $name, $encoder););
    ($t:ty, $name:ident, $encoder:ident) => (make_write_data_fn!(gen, $t, 1, $name, $encoder););
}

make_write_data_fn!(u8,  write_data_u8,  write_u8);
make_write_data_fn!(u16, write_data_u16, write_u16);
make_write_data_fn!(u32, write_data_u32, write_u32);
make_write_data_fn!(u64, write_data_u64, write_u64);
make_write_data_fn!(i8,  write_data_i8,  write_i8);
make_write_data_fn!(i16, write_data_i16, write_i16);
make_write_data_fn!(i32, write_data_i32, write_i32);
make_write_data_fn!(i64, write_data_i64, write_i64);

// With strictly type checking.
pub fn write_u8<W>(wr: &mut W, val: u8) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::U8));
    write_data_u8(wr, val)
}

pub fn write_u16<W>(wr: &mut W, val: u16) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::U16));
    write_data_u16(wr, val)
}

pub fn write_u32<W>(wr: &mut W, val: u32) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::U32));
    write_data_u32(wr, val)
}

pub fn write_u64<W>(wr: &mut W, val: u64) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::U64));
    write_data_u64(wr, val)
}

pub fn write_i8<W>(wr: &mut W, val: i8) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::I8));
    write_data_i8(wr, val)
}

pub fn write_i16<W>(wr: &mut W, val: i16) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::I16));
    write_data_i16(wr, val)
}

pub fn write_i32<W>(wr: &mut W, val: i32) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::I32));
    write_data_i32(wr, val)
}

pub fn write_i64<W>(wr: &mut W, val: i64) -> Result<(), Error>
    where W: Write
{
    try!(write_marker(wr, Marker::I64));
    write_data_i64(wr, val)
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs;
use std::io::Write;
use std::path::Path;

use super::{capitalize_first, FileWriter, IoResult};
use botocore::Service;
use util::case_insensitive_btreemap_get;
use inflector::Inflector;

const BOTOCORE_TESTS_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"),
                                                 "/botocore/tests/unit/response_parsing/xml/responses/");
const OUR_TESTS_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/unit/responses/");

pub fn generate_tests(writer: &mut FileWriter, service: &Service) -> IoResult {
    writeln!(writer,
             "
            #[cfg(test)]
            mod protocol_tests {{
                {tests_body}
            }}
            ",
             tests_body = generate_tests_body(service).unwrap_or("".to_string()))
}

fn generate_tests_body(service: &Service) -> Option<String> {
    let responses: HashMap<String, Response> = find_responses();

    let our_responses: Vec<Response> = responses.values()
        .into_iter()
        .filter(|r| r.service.to_lowercase() == service.service_type_name().to_lowercase())
        .map(|r| r.to_owned())
        .collect();

    let test_bodies: Vec<String> = our_responses.into_iter()
        .flat_map(|response| generate_response_parse_test(service, response))
        .collect();

    if !test_bodies.is_empty() {
        let tests_str = test_bodies.join("\n\n");

        Some(format!("
                use mock::*;
                use super::*;
                use super::super::Region as rusoto_region;

                {test_bodies}",
                     test_bodies = tests_str))
    } else {
        None
    }
}

fn generate_response_parse_test(service: &Service, response: Response) -> Option<String> {
    let maybe_operation = case_insensitive_btreemap_get(&service.operations, &response.action);

    if maybe_operation.is_none() {
        return None;
    }

    let operation = maybe_operation.unwrap();
    let request_params;
    let request_constructor;
    if operation.input.is_some() {
        request_constructor = format!("let request = {request_type}::default();",
                                      request_type = operation.input_shape());
        request_params = "&request".to_string();
    } else {
        request_constructor = "".to_string();
        request_params = "".to_string();
    }

    Some(format!("
        #[test]
        fn test_parse_{service_name}_{action}() {{
            let mock_response =  MockResponseReader::read_response(r#\"{response_dir_name}\"#, \"{response_file_name}\");
            let mock = MockRequestDispatcher::with_status(200)
                .with_body(&mock_response);
            let client = {client_type}::new(mock, MockCredentialsProvider, rusoto_region::UsEast1);
            {request_constructor}
            let result = client.{action}({request_params});
            assert!(result.is_ok(), \"parse error: {{:?}}\", result);
        }}",
        service_name = response.service.to_snake_case(),
        action = response.action.to_snake_case(),
        response_dir_name = response.dir_name,
        response_file_name = response.file_name,
        client_type = service.client_type_name(),
        request_constructor = request_constructor,
        request_params = request_params))
}

#[derive(Debug, Clone)]
pub struct Response {
    pub service: String,
    pub action: String,
    pub dir_name: String,
    pub file_name: String,
    pub extension: String,
}

impl Response {
    pub fn from_response_file_name(directory: &Path, f: &str) -> Option<Response> {
        let maybe_file_name_and_extension: Vec<&str> = f.split('.').collect();

        let mut service_name = None;
        let mut action = None;
        let extension = maybe_file_name_and_extension.get(1);

        if let Some(file_name) = maybe_file_name_and_extension.get(0) {
            let file_name_parts: Vec<&str> = file_name.split('-').collect();

            service_name = file_name_parts.get(0).map(|s| capitalize_first(*s));

            action = Some(file_name_parts.into_iter().skip(1).map(capitalize_first).collect());
        }

        service_name.and_then(|s| {
            action.and_then(|a| {
                extension.and_then(|e| {
                    Some(Response {
                        service: s,
                        action: a,
                        dir_name: directory.to_str().unwrap().to_owned(),
                        file_name: f.to_owned(),
                        extension: e.to_string(),
                    })
                })
            })
        })
    }
}

pub fn find_responses_in_dir(dir_path: &Path) -> Vec<Response> {
    let dir = fs::read_dir(dir_path).expect("read_dir");

    dir.map(|d| d.expect("direntry").file_name().into_string().expect("osstr"))
        .flat_map(|f| Response::from_response_file_name(dir_path, &f))
        .filter(|r| r.extension == "xml")
        .collect()
}

pub fn find_responses() -> HashMap<String, Response> {
    let mut responses = HashMap::new();

    for r in find_responses_in_dir(Path::new(BOTOCORE_TESTS_DIR)) {
        responses.insert(r.file_name.clone(), r);
    }

    for r in find_responses_in_dir(Path::new(OUR_TESTS_DIR)) {
        responses.insert(r.file_name.clone(), r);
    }

    responses
}
<commit_msg>Add tests for error responses.<commit_after>use std::collections::HashMap;
use std::fs;
use std::io::Write;
use std::path::Path;

use super::{capitalize_first, FileWriter, IoResult};
use botocore::Service;
use util::case_insensitive_btreemap_get;
use inflector::Inflector;

const BOTOCORE_ERROR_RESPONSE_TESTS_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"),
                                                 "/botocore/tests/unit/response_parsing/xml/errors/");
const BOTOCORE_VALID_RESPONSE_TESTS_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"),
                                                 "/botocore/tests/unit/response_parsing/xml/responses/");
const OUR_TESTS_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/unit/responses/");

pub fn generate_tests(writer: &mut FileWriter, service: &Service) -> IoResult {
    writeln!(writer,
             "
            #[cfg(test)]
            mod protocol_tests {{
                {tests_body}
            }}
            ",
             tests_body = generate_tests_body(service).unwrap_or("".to_string()))
}

fn generate_tests_body(service: &Service) -> Option<String> {
    let valid_tests = generate_response_tests(
        service,
        find_valid_responses(),
        200,
        true,
    );
    // TODO: Find the true status code. Sadly, it isn't stored with the xml response.
    let error_tests = generate_response_tests(
        service,
        find_error_responses(),
        400,
        false,
    );

    if valid_tests.is_some() || error_tests.is_some() {
        Some(format!("
                use mock::*;
                use super::*;
                use super::super::Region as rusoto_region;

                {error_tests}
                {valid_tests}",
                error_tests = error_tests.unwrap_or("".to_string()),
                valid_tests = valid_tests.unwrap_or("".to_string())))
    } else {
        None
    }
}

fn generate_response_tests(
    service: &Service,
    responses: HashMap<String, Response>,
    status_code: i32,
    is_ok: bool,
) -> Option<String> {

    let our_responses: Vec<Response> = responses.values()
        .into_iter()
        .filter(|r| r.service.to_lowercase() == service.service_type_name().to_lowercase())
        .map(|r| r.to_owned())
        .collect();

    let test_bodies: Vec<String> = our_responses.into_iter()
        .flat_map(|response| generate_response_parse_test(service, response, status_code, is_ok))
        .collect();

    if !test_bodies.is_empty() {
        Some(test_bodies.join("\n\n"))
    } else {
        None
    }
}

fn generate_response_parse_test(
    service: &Service,
    response: Response,
    status_code: i32,
    is_ok: bool,
) -> Option<String> {
    let maybe_operation = case_insensitive_btreemap_get(&service.operations, &response.action);

    if maybe_operation.is_none() {
        return None;
    }

    let operation = maybe_operation.unwrap();
    let request_params;
    let request_constructor;
    if operation.input.is_some() {
        request_constructor = format!("let request = {request_type}::default();",
                                      request_type = operation.input_shape());
        request_params = "&request".to_string();
    } else {
        request_constructor = "".to_string();
        request_params = "".to_string();
    }

    Some(format!("
        #[test]
        fn test_parse_{error_or_valid}_{service_name}_{action}() {{
            let mock_response =  MockResponseReader::read_response(r#\"{response_dir_name}\"#, \"{response_file_name}\");
            let mock = MockRequestDispatcher::with_status({status_code})
                .with_body(&mock_response);
            let client = {client_type}::new(mock, MockCredentialsProvider, rusoto_region::UsEast1);
            {request_constructor}
            let result = client.{action}({request_params});
            assert!({is_ok}result.is_ok(), \"parse error: {{:?}}\", result);
        }}",
        error_or_valid = if is_ok { "valid" } else { "error" },
        service_name = response.service.to_snake_case(),
        action = response.action.to_snake_case(),
        status_code = status_code,
        response_dir_name = response.dir_name,
        response_file_name = response.file_name,
        client_type = service.client_type_name(),
        request_constructor = request_constructor,
        request_params = request_params,
        is_ok = if is_ok { "" } else { "!" }))
}

#[derive(Debug, Clone)]
pub struct Response {
    pub service: String,
    pub action: String,
    pub dir_name: String,
    pub file_name: String,
    pub extension: String,
}

impl Response {
    pub fn from_response_file_name(directory: &Path, f: &str) -> Option<Response> {
        let maybe_file_name_and_extension: Vec<&str> = f.split('.').collect();

        let mut service_name = None;
        let mut action = None;
        let extension = maybe_file_name_and_extension.get(1);

        if let Some(file_name) = maybe_file_name_and_extension.get(0) {
            let file_name_parts: Vec<&str> = file_name.split('-').collect();

            service_name = file_name_parts.get(0).map(|s| capitalize_first(*s));

            action = Some(file_name_parts.into_iter().skip(1).map(capitalize_first).collect());
        }

        service_name.and_then(|s| {
            action.and_then(|a| {
                extension.and_then(|e| {
                    Some(Response {
                        service: s,
                        action: a,
                        dir_name: directory.to_str().unwrap().to_owned(),
                        file_name: f.to_owned(),
                        extension: e.to_string(),
                    })
                })
            })
        })
    }
}

pub fn find_responses_in_dir(dir_path: &Path) -> Vec<Response> {
    let dir = fs::read_dir(dir_path).expect("read_dir");

    dir.map(|d| d.expect("direntry").file_name().into_string().expect("osstr"))
        .flat_map(|f| Response::from_response_file_name(dir_path, &f))
        .filter(|r| r.extension == "xml")
        .collect()
}

pub fn find_error_responses() -> HashMap<String, Response> {
    let mut responses = HashMap::new();

    for r in find_responses_in_dir(Path::new(BOTOCORE_ERROR_RESPONSE_TESTS_DIR)) {
        responses.insert(r.file_name.clone(), r);
    }

    responses
}

pub fn find_valid_responses() -> HashMap<String, Response> {
    let mut responses = HashMap::new();

    for r in find_responses_in_dir(Path::new(BOTOCORE_VALID_RESPONSE_TESTS_DIR)) {
        responses.insert(r.file_name.clone(), r);
    }

    for r in find_responses_in_dir(Path::new(OUR_TESTS_DIR)) {
        responses.insert(r.file_name.clone(), r);
    }

    responses
}
<|endoftext|>


<commit_before>//! Issues interface

use std::io::Result;
use self::super::{Github, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;

pub enum Filter {
  Assigned,
  Created,
  Mentioned,
  Subscribed,
  All
}

impl fmt::Display for Filter {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Filter::Assigned => "assigned",
      Filter::Created => "created",
      Filter::Mentioned => "mentioned",
      Filter::Subscribed => "subscribed",
      Filter::All => "all"
    })
  }
}

impl Default for Filter {
  fn default() -> Filter {
    Filter::Assigned
  }
}

pub enum Sort {
  Created,
  Updated,
  Comments
}

impl fmt::Display for Sort {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Sort::Created => "created",
      Sort::Updated => "updated",
      Sort::Comments => "comments"
    })
  }
}

impl Default for Sort {
  fn default() -> Sort {
    Sort::Created
  }
}

pub struct IssueLabels<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: i64
}

impl<'a> IssueLabels<'a> {
  pub fn new(
    github: &'a Github<'a>,
    owner: &'static str,
    repo: &'static str,
    number: i64) -> IssueLabels<'a> {
    IssueLabels {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}/labels{}", self.owner, self.repo, self.number, more)
  }

  /// add a set of labels to this issue ref
  pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.post(
      &self.path(""),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  /// remove a label from this issue
  pub fn remove(&self, label: &'static str) -> Result<()> {
    self.github.delete(
      &self.path(
        &format!("/{}", label)
      )
    ).map(|_| ())
  }

  /// replace all labels associated with this issue with a new set.
  /// providing an empty set of labels is the same as clearing the
  /// current labels
  pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.patch(
      &self.path(""),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  /// remove all labels from an issue
  pub fn clear(&self) -> Result<()> {
    self.github.delete(
      &self.path("")
    ).map(|_| ())
  }
}

pub struct IssueRef<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: i64
}

impl<'a> IssueRef<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>,
    owner: &'static str,
    repo: &'static str,
    number: i64) -> IssueRef<'a> {
    IssueRef {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}{}", self.owner, self.repo, self.number, more)
  }

  pub fn labels(&self) -> IssueLabels {
    IssueLabels::new(self.github, self.owner, self.repo, self.number)
  }

  pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.patch(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }
}

pub struct Issues<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

/// an mutable issue list builder
pub struct ListBuilder<'a> {
  issues: &'a Issues<'a>,
  state: State,
  sort: Sort,
  direction: SortDirection,
  assignee: Option<&'static str>,
  creator: Option<&'static str>,
  mentioned: Option<&'static str>,
  labels: Vec<&'static str>,
  since: Option<&'static str>
}

impl<'a> ListBuilder<'a> {

  pub fn new(is: &'a Issues<'a>) -> ListBuilder<'a> {
    ListBuilder {
      issues: is,
      state: Default::default(),
      sort: Default::default(),
      direction: Default::default(),
      assignee: None,
      creator: None,
      mentioned: None,
      labels: vec![],
      since: None
    }
  }

  pub fn state(&mut self, state: State) -> &mut ListBuilder<'a> {
    self.state = state;
    self
  }

  pub fn sort(&mut self, sort: Sort) -> &mut ListBuilder<'a> {
    self.sort = sort;
    self
  }

  pub fn direction(&mut self, direction: SortDirection) -> &mut ListBuilder<'a> {
    self.direction = direction;
    self
  }

  pub fn assignee(&mut self, assignee: &'static str) -> &mut ListBuilder<'a> {
    self.assignee = Some(assignee);
    self
  }

  pub fn creator(&mut self, creator: &'static str) -> &mut ListBuilder<'a> {
    self.creator = Some(creator);
    self
  }

  pub fn mentioned(&mut self, mentioned: &'static str) -> &mut ListBuilder<'a> {
    self.mentioned = Some(mentioned);
    self
  }

  pub fn labels(&mut self, labels: Vec<&'static str>) -> &mut ListBuilder<'a> {
    self.labels = labels;
    self
  }

  pub fn since(&mut self, since: &'static str) -> &mut ListBuilder<'a> {
    self.since = Some(since);
    self
  }

  pub fn get(&self) -> Result<Vec<Issue>> {
    let mut params = Vec::new();
    params.push(format!("state={}", self.state));
    params.push(format!("sort={}", self.sort));
    params.push(format!("direction={}", self.direction));
    if let Some(a) = self.assignee {
      params.push(format!("assignee={}", a));
    }
    if let Some(c) = self.creator {
      params.push(format!("creator={}", c));
    }
    if let Some(m) = self.mentioned {
      params.push(format!("mentioned={}", m));
    }
    if let Some(s) = self.since {
      params.push(format!("since={}", s));
    }
    if !self.labels.is_empty() {
      params.push(format!("labels={}", self.labels.connect(",")));
    }
    println!("params {:?}", params);
    let url = self.issues.path(
      &format!("?{}", params.connect("&"))
    );
    let body = try!(
      self.issues.github.get(
        &url
      )
    );
    Ok(json::decode::<Vec<Issue>>(&body).unwrap())
  }

}

impl<'a> Issues<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Issues<'a> {
    Issues {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
  }

  pub fn get(&self, number: i64) -> IssueRef {
    IssueRef::new(self.github, self.owner, self.repo, number)
  }

  pub fn create(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.post(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }

  pub fn list(&self) -> ListBuilder {
    ListBuilder::new(self)
  }
}
<commit_msg>put not patch<commit_after>//! Issues interface

use std::io::Result;
use self::super::{Github, SortDirection, State};
use rep::{Issue, IssueReq, Label};
use rustc_serialize::json;
use std::fmt;
use std::default::Default;

pub enum Filter {
  Assigned,
  Created,
  Mentioned,
  Subscribed,
  All
}

impl fmt::Display for Filter {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Filter::Assigned => "assigned",
      Filter::Created => "created",
      Filter::Mentioned => "mentioned",
      Filter::Subscribed => "subscribed",
      Filter::All => "all"
    })
  }
}

impl Default for Filter {
  fn default() -> Filter {
    Filter::Assigned
  }
}

pub enum Sort {
  Created,
  Updated,
  Comments
}

impl fmt::Display for Sort {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Sort::Created => "created",
      Sort::Updated => "updated",
      Sort::Comments => "comments"
    })
  }
}

impl Default for Sort {
  fn default() -> Sort {
    Sort::Created
  }
}

pub struct IssueLabels<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: i64
}

impl<'a> IssueLabels<'a> {
  pub fn new(
    github: &'a Github<'a>,
    owner: &'static str,
    repo: &'static str,
    number: i64) -> IssueLabels<'a> {
    IssueLabels {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}/labels{}", self.owner, self.repo, self.number, more)
  }

  /// add a set of labels to this issue ref
  pub fn add(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.post(
      &self.path(""),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  /// remove a label from this issue
  pub fn remove(&self, label: &'static str) -> Result<()> {
    self.github.delete(
      &self.path(
        &format!("/{}", label)
      )
    ).map(|_| ())
  }

  /// replace all labels associated with this issue with a new set.
  /// providing an empty set of labels is the same as clearing the
  /// current labels
  pub fn set(&self, labels: Vec<&str>) -> Result<Vec<Label>> {
    let body = try!(self.github.put(
      &self.path(""),
      json::encode(&labels).unwrap().as_bytes()
    ));
    Ok(json::decode::<Vec<Label>>(&body).unwrap())
  }

  /// remove all labels from an issue
  pub fn clear(&self) -> Result<()> {
    self.github.delete(
      &self.path("")
    ).map(|_| ())
  }
}

pub struct IssueRef<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: i64
}

impl<'a> IssueRef<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>,
    owner: &'static str,
    repo: &'static str,
    number: i64) -> IssueRef<'a> {
    IssueRef {
      github: github,
      owner: owner,
      repo: repo,
      number: number
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues/{}{}", self.owner, self.repo, self.number, more)
  }

  pub fn labels(&self) -> IssueLabels {
    IssueLabels::new(self.github, self.owner, self.repo, self.number)
  }

  pub fn edit(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.patch(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }
}

pub struct Issues<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

/// an mutable issue list builder
pub struct ListBuilder<'a> {
  issues: &'a Issues<'a>,
  state: State,
  sort: Sort,
  direction: SortDirection,
  assignee: Option<&'static str>,
  creator: Option<&'static str>,
  mentioned: Option<&'static str>,
  labels: Vec<&'static str>,
  since: Option<&'static str>
}

impl<'a> ListBuilder<'a> {

  pub fn new(is: &'a Issues<'a>) -> ListBuilder<'a> {
    ListBuilder {
      issues: is,
      state: Default::default(),
      sort: Default::default(),
      direction: Default::default(),
      assignee: None,
      creator: None,
      mentioned: None,
      labels: vec![],
      since: None
    }
  }

  pub fn state(&mut self, state: State) -> &mut ListBuilder<'a> {
    self.state = state;
    self
  }

  pub fn sort(&mut self, sort: Sort) -> &mut ListBuilder<'a> {
    self.sort = sort;
    self
  }

  pub fn direction(&mut self, direction: SortDirection) -> &mut ListBuilder<'a> {
    self.direction = direction;
    self
  }

  pub fn assignee(&mut self, assignee: &'static str) -> &mut ListBuilder<'a> {
    self.assignee = Some(assignee);
    self
  }

  pub fn creator(&mut self, creator: &'static str) -> &mut ListBuilder<'a> {
    self.creator = Some(creator);
    self
  }

  pub fn mentioned(&mut self, mentioned: &'static str) -> &mut ListBuilder<'a> {
    self.mentioned = Some(mentioned);
    self
  }

  pub fn labels(&mut self, labels: Vec<&'static str>) -> &mut ListBuilder<'a> {
    self.labels = labels;
    self
  }

  pub fn since(&mut self, since: &'static str) -> &mut ListBuilder<'a> {
    self.since = Some(since);
    self
  }

  pub fn get(&self) -> Result<Vec<Issue>> {
    let mut params = Vec::new();
    params.push(format!("state={}", self.state));
    params.push(format!("sort={}", self.sort));
    params.push(format!("direction={}", self.direction));
    if let Some(a) = self.assignee {
      params.push(format!("assignee={}", a));
    }
    if let Some(c) = self.creator {
      params.push(format!("creator={}", c));
    }
    if let Some(m) = self.mentioned {
      params.push(format!("mentioned={}", m));
    }
    if let Some(s) = self.since {
      params.push(format!("since={}", s));
    }
    if !self.labels.is_empty() {
      params.push(format!("labels={}", self.labels.connect(",")));
    }
    println!("params {:?}", params);
    let url = self.issues.path(
      &format!("?{}", params.connect("&"))
    );
    let body = try!(
      self.issues.github.get(
        &url
      )
    );
    Ok(json::decode::<Vec<Issue>>(&body).unwrap())
  }

}

impl<'a> Issues<'a> {
  /// create a new instance of a github repo issue ref
  pub fn new(
    github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Issues<'a> {
    Issues {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/issues{}", self.owner, self.repo, more)
  }

  pub fn get(&self, number: i64) -> IssueRef {
    IssueRef::new(self.github, self.owner, self.repo, number)
  }

  pub fn create(&self, is: &IssueReq) -> Result<Issue> {
    let data = json::encode(&is).unwrap();
    let body = try!(
      self.github.post(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Issue>(&body).unwrap())
  }

  pub fn list(&self) -> ListBuilder {
    ListBuilder::new(self)
  }
}
<|endoftext|>


<commit_before>use async_input::AsyncInput;
use base::*;
use crossover;
use downmixer;
use filters::*;
use output;
use state;
use std;
use std::cmp;
use time::*;

struct InputMixer {
    input: AsyncInput,
    current_frame: Frame,
    current_frame_pos: usize,
    gain: Gain,
}

impl InputMixer {
    fn new(input: AsyncInput, gain: Gain) -> InputMixer {
        InputMixer {
            input: input,
            current_frame: Frame::new(1.0, Time::zero(), 0),
            current_frame_pos: 0,
            gain: gain,
        }
    }

    fn set_gain(&mut self, gain: Gain) {
        self.gain = gain;
    }

    fn receive_frame(&mut self, deadline: Time, stream_time: Time) -> Result<bool> {
        loop {
            match self.input.read(deadline - Time::now())? {
                None => return Ok(false),
                Some(frame) => {
                    // If the frame is too old then drop it.
                    if frame.end_timestamp() < stream_time {
                        println!("WARNING: Dropping old frame.");
                        continue;
                    }
                    self.current_frame = frame;
                    self.current_frame_pos = 0;
                    return Ok(true);
                }
            }
        }
    }

    fn min_delay(&self) -> TimeDelta {
        self.input.min_delay()
    }

    fn get_frame(&mut self, deadline: Time, stream_time: Time) -> Result<Option<Frame>> {
        if !self.receive_frame(deadline, stream_time)? {
            return Ok(None);
        }
        let mut frame = Frame::new(1.0, Time::zero(), 0);
        std::mem::swap(&mut frame, &mut self.current_frame);
        self.current_frame_pos = 0;

        frame.gain += self.gain;

        Ok(Some(frame))
    }

    fn mix_into(&mut self, mixed_frame: &mut Frame, deadline: Time) -> Result<bool> {
        let multiplier = self.gain.get_multiplier();
        let mut pos = 0;
        while pos < mixed_frame.len() {
            if self.current_frame_pos >= self.current_frame.len() {
                if !self.receive_frame(deadline, mixed_frame.timestamp)? {
                    return Ok(pos > 0);
                }
            }

            let samples = cmp::min(
                self.current_frame.len() - self.current_frame_pos,
                mixed_frame.len() - pos,
            );

            for (c, src_pcm) in self.current_frame.iter_channels() {
                let dst_pcm = mixed_frame.ensure_channel(c);
                for i in 0..samples {
                    dst_pcm[pos + i] += multiplier * src_pcm[self.current_frame_pos + i];
                }
            }

            self.current_frame_pos += samples;
            pos += samples;
        }

        Ok(true)
    }
}

pub struct FilteredOutput {
    output: Box<output::Output>,
    fir_filter: Option<Box<StreamFilter>>,
    biquad_filter: Option<Box<StreamFilter>>,
    subwoofer_config: Option<state::SubwooferConfig>,

    drc_enabled: bool,
    subwoofer_enabled: bool,

    downmixer: downmixer::Downmixer,
    crossover: Option<crossover::CrossoverFilter>,
    state_observer: state::StateObserver,
}

impl FilteredOutput {
    pub fn new(
        output: Box<output::Output>,
        out_channels: PerChannel<bool>,
        fir_filter: Option<Box<StreamFilter>>,
        biquad_filter: Option<Box<StreamFilter>>,
        subwoofer_config: Option<state::SubwooferConfig>,
        shared_state: &state::SharedState,
    ) -> Box<output::Output> {
        let enable_drc = shared_state.lock().state().enable_drc.unwrap_or(false);
        let enable_subwoofer = shared_state
            .lock()
            .state()
            .enable_subwoofer
            .unwrap_or(false);
        let mut result = Box::new(FilteredOutput {
            output: output,
            fir_filter: fir_filter,
            biquad_filter: biquad_filter,
            subwoofer_config: subwoofer_config,

            drc_enabled: enable_drc,
            subwoofer_enabled: enable_subwoofer,

            downmixer: downmixer::Downmixer::new(out_channels),
            crossover: None,
            state_observer: shared_state.lock().add_observer(),
        });
        result.update_crossover();
        result
    }

    fn update_crossover(&mut self) {
        self.crossover = match (self.subwoofer_enabled, self.subwoofer_config) {
            (false, _) => None,
            (true, None) => None,
            (
                true,
                Some(state::SubwooferConfig {
                    crossover_frequency,
                }),
            ) => Some(crossover::CrossoverFilter::new(crossover_frequency)),
        };
    }
}

impl output::Output for FilteredOutput {
    fn write(&mut self, frame: Frame) -> Result<()> {
        let mut need_reset = false;
        for msg in self.state_observer.try_iter() {
            match msg {
                state::StateChange::SetEnableDrc { enable } => {
                    self.drc_enabled = enable;
                    need_reset = true;
                }
                state::StateChange::SetEnableSubwoofer { enable } => {
                    self.subwoofer_enabled = enable;
                    need_reset = true;
                }
                _ => (),
            }
        }

        if need_reset {
            self.update_crossover();
            self.fir_filter.as_mut().map(|f| f.reset());
            self.biquad_filter.as_mut().map(|f| f.reset());
        }

        let frame = self.downmixer.process(frame);

        let frame = match self.crossover.as_mut() {
            Some(c) => c.apply(frame),
            None => frame,
        };

        let frame = match (self.drc_enabled, self.fir_filter.as_mut()) {
            (true, Some(f)) => f.apply(frame),
            _ => frame,
        };

        let frame = match (self.drc_enabled, self.biquad_filter.as_mut()) {
            (true, Some(f)) => f.apply(frame),
            _ => frame,
        };

        self.output.write(frame)
    }

    fn deactivate(&mut self) {
        self.output.deactivate();
    }

    fn sample_rate(&self) -> f64 {
        self.output.sample_rate()
    }

    fn min_delay(&self) -> TimeDelta {
        self.output.min_delay()
    }
}

const OUTPUT_SHUTDOWN_SECONDS: i64 = 30;
const STANDBY_SECONDS: i64 = 3600;

fn get_stream_stats(pcm: Option<&[f32]>) -> state::StreamStats {
    if pcm.is_none() {
        return state::StreamStats {
            rms: 0.0,
            peak: 0.0,
        };
    }
    let pcm = pcm.unwrap();
    let mut sq_sum = 0.0;
    let mut peak = 0.0f32;
    for s in pcm {
        sq_sum += s * s;
        peak = peak.max(s.abs());
    }
    state::StreamStats {
        rms: (2.0 * sq_sum / pcm.len() as f32).sqrt(),
        peak: peak,
    }
}

pub fn run_mixer_loop(
    mut inputs: Vec<AsyncInput>,
    mut outputs: Vec<Box<output::Output>>,
    sample_rate: f64,
    period_duration: TimeDelta,
    shared_state: state::SharedState,
    shared_stream_state: state::SharedStreamInfo,
) -> Result<()> {
    let ui_channel = shared_state.lock().add_observer();

    let mut mixers: Vec<Box<InputMixer>> = {
        let mut pos = 0;
        let state = shared_state.lock();
        inputs
            .drain(..)
            .map(|i| {
                let gain = state.state().inputs[pos].gain;
                pos += 1;
                Box::new(InputMixer::new(i, gain))
            })
            .collect()
    };

    let mut output_gain = shared_state.lock().current_gain();

    let mut last_data_time = Time::now();
    let mut state = state::StreamState::Active;
    let mut selected_output = 0;

    let mut loudness_filter =
        MultichannelFilter::<LoudnessFilter>::new(SimpleFilterParams::new(sample_rate, 10.0));

    let mut crossfeed_filter = CrossfeedFilter::new(sample_rate);
    crossfeed_filter.set_enabled(
        shared_state
            .lock()
            .state()
            .enable_crossfeed
            .unwrap_or(false),
    );

    let mut exclusive_mux_mode = true;

    let period_size = (period_duration * sample_rate as i64 / TimeDelta::seconds(1)) as usize;

    let mut stream_start_time = Time::now();
    let mut stream_pos: i64 = 0;

    loop {
        let min_input_delay = mixers
            .iter()
            .fold(TimeDelta::zero(), |max, i| cmp::max(max, i.min_delay()));

        let stream_time = get_sample_timestamp(stream_start_time, sample_rate, stream_pos);
        let mix_delay = min_input_delay + period_duration * 2;
        let mix_deadline = stream_time + mix_delay;

        let now = Time::now();
        if now > mix_deadline + period_duration {
            println!("ERROR: Mixer missed deadline. Resetting stream.");
            stream_start_time = now;
            stream_pos = 0;
            continue;
        }

        let mut frame = Frame::new(sample_rate, stream_time, period_size);
        let mut have_data = false;

        if exclusive_mux_mode {
            for m in mixers.iter_mut() {
                match m.get_frame(mix_deadline, stream_time)? {
                    Some(f) => {
                        frame = f;
                        have_data = true;
                        break;
                    }
                    None => (),
                }
            }
            stream_start_time = frame.end_timestamp();
            stream_pos = 0;
        } else {
            for m in mixers.iter_mut() {
                have_data |= try!(m.mix_into(&mut frame, mix_deadline));
            }
            stream_pos += frame.len() as i64;
        }

        let old_state = state;

        state = match (have_data, (Time::now() - last_data_time).in_seconds()) {
            (true, _) => {
                last_data_time = now;
                state::StreamState::Active
            }
            (false, t) if t < OUTPUT_SHUTDOWN_SECONDS => state::StreamState::Active,
            (false, t) if t < STANDBY_SECONDS => state::StreamState::Inactive,
            (false, _) => state::StreamState::Standby,
        };

        if state != old_state {
            println!("INFO: state: {}", state.as_str());
            shared_state.lock().set_stream_state(state);
        }

        match state {
            state::StreamState::Active => {
                let stream_info_packet = state::StreamInfoPacket {
                    time: frame.timestamp,
                    left: get_stream_stats(frame.get_channel(ChannelPos::FL)),
                    right: get_stream_stats(frame.get_channel(ChannelPos::FR)),
                };
                {
                    let mut stream_info = shared_stream_state.lock();
                    let expire_time = stream_info_packet.time
                        - TimeDelta::milliseconds(state::STREAM_INFO_PERIOD_MS);
                    while stream_info.packets.len() > 0 && stream_info.packets[0].time < expire_time
                    {
                        stream_info.packets.pop_front();
                    }
                    stream_info.packets.push_back(stream_info_packet);
                }

                frame.gain += output_gain;
                frame = loudness_filter.apply(frame);
                frame = crossfeed_filter.apply(frame);

                frame.timestamp +=
                    mix_delay + period_duration * 4 + outputs[selected_output].min_delay();
                outputs[selected_output].write(frame)?;
            }

            _ => {
                if old_state == state::StreamState::Active {
                    // Send an empty frame with gain -100 db to mute the output device. It will
                    // be unmuted when the device is active again.
                    frame.gain = Gain { db: -100.0 };
                    outputs[selected_output].write(frame)?;

                    for ref mut out in &mut outputs {
                        out.deactivate();
                    }
                }

                std::thread::sleep(TimeDelta::milliseconds(500).as_duration());
                stream_start_time = Time::now() - mix_delay;
                stream_pos = 0;
            }
        }

        for msg in ui_channel.try_iter() {
            match msg {
                state::StateChange::SelectOutput { output } => {
                    outputs[selected_output].deactivate();
                    selected_output = output;
                }
                state::StateChange::SetMasterVolume {
                    gain,
                    volume_spl: _,
                    loudness_gain,
                } => {
                    output_gain = gain;
                    loudness_filter
                        .set_params(SimpleFilterParams::new(sample_rate, loudness_gain.db));
                }
                state::StateChange::SetInputGain { device, gain } => {
                    mixers[device as usize].set_gain(gain);
                }
                state::StateChange::SetCrossfeed { enable } => {
                    crossfeed_filter.set_enabled(enable);
                }
                state::StateChange::SetMuxMode { mux_mode } => {
                    exclusive_mux_mode = mux_mode == state::MuxMode::Exclusive;
                }
                _ => {}
            }
        }
    }
}
<commit_msg>Reduce standby delay<commit_after>use async_input::AsyncInput;
use base::*;
use crossover;
use downmixer;
use filters::*;
use output;
use state;
use std;
use std::cmp;
use time::*;

struct InputMixer {
    input: AsyncInput,
    current_frame: Frame,
    current_frame_pos: usize,
    gain: Gain,
}

impl InputMixer {
    fn new(input: AsyncInput, gain: Gain) -> InputMixer {
        InputMixer {
            input: input,
            current_frame: Frame::new(1.0, Time::zero(), 0),
            current_frame_pos: 0,
            gain: gain,
        }
    }

    fn set_gain(&mut self, gain: Gain) {
        self.gain = gain;
    }

    fn receive_frame(&mut self, deadline: Time, stream_time: Time) -> Result<bool> {
        loop {
            match self.input.read(deadline - Time::now())? {
                None => return Ok(false),
                Some(frame) => {
                    // If the frame is too old then drop it.
                    if frame.end_timestamp() < stream_time {
                        println!("WARNING: Dropping old frame.");
                        continue;
                    }
                    self.current_frame = frame;
                    self.current_frame_pos = 0;
                    return Ok(true);
                }
            }
        }
    }

    fn min_delay(&self) -> TimeDelta {
        self.input.min_delay()
    }

    fn get_frame(&mut self, deadline: Time, stream_time: Time) -> Result<Option<Frame>> {
        if !self.receive_frame(deadline, stream_time)? {
            return Ok(None);
        }
        let mut frame = Frame::new(1.0, Time::zero(), 0);
        std::mem::swap(&mut frame, &mut self.current_frame);
        self.current_frame_pos = 0;

        frame.gain += self.gain;

        Ok(Some(frame))
    }

    fn mix_into(&mut self, mixed_frame: &mut Frame, deadline: Time) -> Result<bool> {
        let multiplier = self.gain.get_multiplier();
        let mut pos = 0;
        while pos < mixed_frame.len() {
            if self.current_frame_pos >= self.current_frame.len() {
                if !self.receive_frame(deadline, mixed_frame.timestamp)? {
                    return Ok(pos > 0);
                }
            }

            let samples = cmp::min(
                self.current_frame.len() - self.current_frame_pos,
                mixed_frame.len() - pos,
            );

            for (c, src_pcm) in self.current_frame.iter_channels() {
                let dst_pcm = mixed_frame.ensure_channel(c);
                for i in 0..samples {
                    dst_pcm[pos + i] += multiplier * src_pcm[self.current_frame_pos + i];
                }
            }

            self.current_frame_pos += samples;
            pos += samples;
        }

        Ok(true)
    }
}

pub struct FilteredOutput {
    output: Box<output::Output>,
    fir_filter: Option<Box<StreamFilter>>,
    biquad_filter: Option<Box<StreamFilter>>,
    subwoofer_config: Option<state::SubwooferConfig>,

    drc_enabled: bool,
    subwoofer_enabled: bool,

    downmixer: downmixer::Downmixer,
    crossover: Option<crossover::CrossoverFilter>,
    state_observer: state::StateObserver,
}

impl FilteredOutput {
    pub fn new(
        output: Box<output::Output>,
        out_channels: PerChannel<bool>,
        fir_filter: Option<Box<StreamFilter>>,
        biquad_filter: Option<Box<StreamFilter>>,
        subwoofer_config: Option<state::SubwooferConfig>,
        shared_state: &state::SharedState,
    ) -> Box<output::Output> {
        let enable_drc = shared_state.lock().state().enable_drc.unwrap_or(false);
        let enable_subwoofer = shared_state
            .lock()
            .state()
            .enable_subwoofer
            .unwrap_or(false);
        let mut result = Box::new(FilteredOutput {
            output: output,
            fir_filter: fir_filter,
            biquad_filter: biquad_filter,
            subwoofer_config: subwoofer_config,

            drc_enabled: enable_drc,
            subwoofer_enabled: enable_subwoofer,

            downmixer: downmixer::Downmixer::new(out_channels),
            crossover: None,
            state_observer: shared_state.lock().add_observer(),
        });
        result.update_crossover();
        result
    }

    fn update_crossover(&mut self) {
        self.crossover = match (self.subwoofer_enabled, self.subwoofer_config) {
            (false, _) => None,
            (true, None) => None,
            (
                true,
                Some(state::SubwooferConfig {
                    crossover_frequency,
                }),
            ) => Some(crossover::CrossoverFilter::new(crossover_frequency)),
        };
    }
}

impl output::Output for FilteredOutput {
    fn write(&mut self, frame: Frame) -> Result<()> {
        let mut need_reset = false;
        for msg in self.state_observer.try_iter() {
            match msg {
                state::StateChange::SetEnableDrc { enable } => {
                    self.drc_enabled = enable;
                    need_reset = true;
                }
                state::StateChange::SetEnableSubwoofer { enable } => {
                    self.subwoofer_enabled = enable;
                    need_reset = true;
                }
                _ => (),
            }
        }

        if need_reset {
            self.update_crossover();
            self.fir_filter.as_mut().map(|f| f.reset());
            self.biquad_filter.as_mut().map(|f| f.reset());
        }

        let frame = self.downmixer.process(frame);

        let frame = match self.crossover.as_mut() {
            Some(c) => c.apply(frame),
            None => frame,
        };

        let frame = match (self.drc_enabled, self.fir_filter.as_mut()) {
            (true, Some(f)) => f.apply(frame),
            _ => frame,
        };

        let frame = match (self.drc_enabled, self.biquad_filter.as_mut()) {
            (true, Some(f)) => f.apply(frame),
            _ => frame,
        };

        self.output.write(frame)
    }

    fn deactivate(&mut self) {
        self.output.deactivate();
    }

    fn sample_rate(&self) -> f64 {
        self.output.sample_rate()
    }

    fn min_delay(&self) -> TimeDelta {
        self.output.min_delay()
    }
}

const OUTPUT_SHUTDOWN_SECONDS: i64 = 30;
const STANDBY_SECONDS: i64 = 600;

fn get_stream_stats(pcm: Option<&[f32]>) -> state::StreamStats {
    if pcm.is_none() {
        return state::StreamStats {
            rms: 0.0,
            peak: 0.0,
        };
    }
    let pcm = pcm.unwrap();
    let mut sq_sum = 0.0;
    let mut peak = 0.0f32;
    for s in pcm {
        sq_sum += s * s;
        peak = peak.max(s.abs());
    }
    state::StreamStats {
        rms: (2.0 * sq_sum / pcm.len() as f32).sqrt(),
        peak: peak,
    }
}

pub fn run_mixer_loop(
    mut inputs: Vec<AsyncInput>,
    mut outputs: Vec<Box<output::Output>>,
    sample_rate: f64,
    period_duration: TimeDelta,
    shared_state: state::SharedState,
    shared_stream_state: state::SharedStreamInfo,
) -> Result<()> {
    let ui_channel = shared_state.lock().add_observer();

    let mut mixers: Vec<Box<InputMixer>> = {
        let mut pos = 0;
        let state = shared_state.lock();
        inputs
            .drain(..)
            .map(|i| {
                let gain = state.state().inputs[pos].gain;
                pos += 1;
                Box::new(InputMixer::new(i, gain))
            })
            .collect()
    };

    let mut output_gain = shared_state.lock().current_gain();

    let mut last_data_time = Time::now();
    let mut state = state::StreamState::Active;
    let mut selected_output = 0;

    let mut loudness_filter =
        MultichannelFilter::<LoudnessFilter>::new(SimpleFilterParams::new(sample_rate, 10.0));

    let mut crossfeed_filter = CrossfeedFilter::new(sample_rate);
    crossfeed_filter.set_enabled(
        shared_state
            .lock()
            .state()
            .enable_crossfeed
            .unwrap_or(false),
    );

    let mut exclusive_mux_mode = true;

    let period_size = (period_duration * sample_rate as i64 / TimeDelta::seconds(1)) as usize;

    let mut stream_start_time = Time::now();
    let mut stream_pos: i64 = 0;

    loop {
        let min_input_delay = mixers
            .iter()
            .fold(TimeDelta::zero(), |max, i| cmp::max(max, i.min_delay()));

        let stream_time = get_sample_timestamp(stream_start_time, sample_rate, stream_pos);
        let mix_delay = min_input_delay + period_duration * 2;
        let mix_deadline = stream_time + mix_delay;

        let now = Time::now();
        if now > mix_deadline + period_duration {
            println!("ERROR: Mixer missed deadline. Resetting stream.");
            stream_start_time = now;
            stream_pos = 0;
            continue;
        }

        let mut frame = Frame::new(sample_rate, stream_time, period_size);
        let mut have_data = false;

        if exclusive_mux_mode {
            for m in mixers.iter_mut() {
                match m.get_frame(mix_deadline, stream_time)? {
                    Some(f) => {
                        frame = f;
                        have_data = true;
                        break;
                    }
                    None => (),
                }
            }
            stream_start_time = frame.end_timestamp();
            stream_pos = 0;
        } else {
            for m in mixers.iter_mut() {
                have_data |= try!(m.mix_into(&mut frame, mix_deadline));
            }
            stream_pos += frame.len() as i64;
        }

        let old_state = state;

        state = match (have_data, (Time::now() - last_data_time).in_seconds()) {
            (true, _) => {
                last_data_time = now;
                state::StreamState::Active
            }
            (false, t) if t < OUTPUT_SHUTDOWN_SECONDS => state::StreamState::Active,
            (false, t) if t < STANDBY_SECONDS => state::StreamState::Inactive,
            (false, _) => state::StreamState::Standby,
        };

        if state != old_state {
            println!("INFO: state: {}", state.as_str());
            shared_state.lock().set_stream_state(state);
        }

        match state {
            state::StreamState::Active => {
                let stream_info_packet = state::StreamInfoPacket {
                    time: frame.timestamp,
                    left: get_stream_stats(frame.get_channel(ChannelPos::FL)),
                    right: get_stream_stats(frame.get_channel(ChannelPos::FR)),
                };
                {
                    let mut stream_info = shared_stream_state.lock();
                    let expire_time = stream_info_packet.time
                        - TimeDelta::milliseconds(state::STREAM_INFO_PERIOD_MS);
                    while stream_info.packets.len() > 0 && stream_info.packets[0].time < expire_time
                    {
                        stream_info.packets.pop_front();
                    }
                    stream_info.packets.push_back(stream_info_packet);
                }

                frame.gain += output_gain;
                frame = loudness_filter.apply(frame);
                frame = crossfeed_filter.apply(frame);

                frame.timestamp +=
                    mix_delay + period_duration * 4 + outputs[selected_output].min_delay();
                outputs[selected_output].write(frame)?;
            }

            _ => {
                if old_state == state::StreamState::Active {
                    // Send an empty frame with gain -100 db to mute the output device. It will
                    // be unmuted when the device is active again.
                    frame.gain = Gain { db: -100.0 };
                    outputs[selected_output].write(frame)?;

                    for ref mut out in &mut outputs {
                        out.deactivate();
                    }
                }

                std::thread::sleep(TimeDelta::milliseconds(500).as_duration());
                stream_start_time = Time::now() - mix_delay;
                stream_pos = 0;
            }
        }

        for msg in ui_channel.try_iter() {
            match msg {
                state::StateChange::SelectOutput { output } => {
                    outputs[selected_output].deactivate();
                    selected_output = output;
                }
                state::StateChange::SetMasterVolume {
                    gain,
                    volume_spl: _,
                    loudness_gain,
                } => {
                    output_gain = gain;
                    loudness_filter
                        .set_params(SimpleFilterParams::new(sample_rate, loudness_gain.db));
                }
                state::StateChange::SetInputGain { device, gain } => {
                    mixers[device as usize].set_gain(gain);
                }
                state::StateChange::SetCrossfeed { enable } => {
                    crossfeed_filter.set_enabled(enable);
                }
                state::StateChange::SetMuxMode { mux_mode } => {
                    exclusive_mux_mode = mux_mode == state::MuxMode::Exclusive;
                }
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::stdin;
use std::collections::VecDeque;

// DFS receives a graph and the start point
fn bfs(graph: &mut Vec<Vec<usize>>, start: usize) {
    let mut visited: Vec<bool> = Vec::new();
    visited.resize(graph.len(), false);

    let mut queue = VecDeque::new();
    visited[start] = true;
    queue.push_back(start);

    while !queue.is_empty() {
        let node = queue.pop_front().unwrap();
        println!("{}", node);

        let adj_list = &graph[node];
        for neighbor in adj_list {
            if !visited[*neighbor] {
                visited[*neighbor] = true;
                queue.push_back(*neighbor);
            }
        }
    }
}

fn add_edge(graph: &mut Vec<Vec<usize>>, u: usize, v: usize) {
    graph[u].push(v);
}

fn main() {
    let mut edges: usize;
    let mut graph: Vec<Vec<usize>> = Vec::new();
    graph.resize(100, vec![]);

    // Read number of edges from user
    let mut input: String = String::new();
    stdin().read_line(&mut input).unwrap();
    edges = input.trim().parse::<u32>().unwrap() as usize;

    while edges > 0 {
        let u: usize;
        let v: usize;

        // Read u and v by splitting input into words and reading the first words found
        let mut input: String = String::new();
        stdin().read_line(&mut input).unwrap();
        let mut words = input.split_whitespace();
        u = words.next().unwrap().parse::<u32>().unwrap() as usize;
        v = words.next().unwrap().parse::<u32>().unwrap() as usize;

        add_edge(&mut graph, u, v);

        edges = edges - 1;
    }

    let start: usize;
    let mut input: String = String::new();
    stdin().read_line(&mut input).unwrap();
    start = input.trim().parse::<u32>().unwrap() as usize;

    bfs(&mut graph, start);
}

#[test]
fn test_bfs_with_graph() {
    let mut graph: Vec<Vec<usize>> = Vec::new();
    graph.resize(4, vec![]);

    add_edge(&mut graph, 0, 1);
    add_edge(&mut graph, 0, 2);
    add_edge(&mut graph, 1, 2);
    add_edge(&mut graph, 2, 0);
    add_edge(&mut graph, 2, 3);
    add_edge(&mut graph, 3, 3);

    println!("BFS Starting from vertex 2");

    bfs(&mut graph, 2);
}
<commit_msg>Add relevant comments to code<commit_after>use std::io::stdin;
use std::collections::VecDeque;

// BFS receives a graph and the start point
fn bfs(graph: &mut Vec<Vec<usize>>, start: usize) {
    let mut visited: Vec<bool> = Vec::new();
    visited.resize(graph.len(), false);

    // Create a VecDeque, it will function as a Queue if we use push_back(value: T) and pop_front(),
    // push starting node to queue and set as visited
    let mut queue = VecDeque::new();
    visited[start] = true;
    queue.push_back(start);

    while !queue.is_empty() {
        let node = queue.pop_front().unwrap();
        println!("{}", node);

        // While queue is not empty, get a slice of the neighbors of chosen node and visit them
        // A slice allows us to traverse the vector read-only by borrowing a section of an array
        let adj_list = &graph[node];
        for neighbor in adj_list {
            if !visited[*neighbor] {
                visited[*neighbor] = true;
                queue.push_back(*neighbor);
            }
        }
    }
}

fn add_edge(graph: &mut Vec<Vec<usize>>, u: usize, v: usize) {
    graph[u].push(v);
}

fn main() {
    let mut edges: usize;
    let mut graph: Vec<Vec<usize>> = Vec::new();
    graph.resize(100, vec![]);

    // Read number of edges from user
    let mut input: String = String::new();
    stdin().read_line(&mut input).unwrap();
    edges = input.trim().parse::<u32>().unwrap() as usize;

    while edges > 0 {
        let u: usize;
        let v: usize;

        // Read u and v by splitting input into words and reading the first words found
        let mut input: String = String::new();
        stdin().read_line(&mut input).unwrap();
        let mut words = input.split_whitespace();
        u = words.next().unwrap().parse::<u32>().unwrap() as usize;
        v = words.next().unwrap().parse::<u32>().unwrap() as usize;

        add_edge(&mut graph, u, v);

        edges = edges - 1;
    }

    let start: usize;
    let mut input: String = String::new();
    stdin().read_line(&mut input).unwrap();
    start = input.trim().parse::<u32>().unwrap() as usize;

    bfs(&mut graph, start);
}

#[test]
fn test_bfs_with_graph() {
    let mut graph: Vec<Vec<usize>> = Vec::new();
    graph.resize(4, vec![]);

    add_edge(&mut graph, 0, 1);
    add_edge(&mut graph, 0, 2);
    add_edge(&mut graph, 1, 2);
    add_edge(&mut graph, 2, 0);
    add_edge(&mut graph, 2, 3);
    add_edge(&mut graph, 3, 3);

    println!("BFS Starting from vertex 2");

    bfs(&mut graph, 2);
}
<|endoftext|>