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

use node::{NodeKind, FuncDef};
use id;

use parser::EXTENV;

#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Type {
    Unit,
    Bool,
    Int,
    Float,
    Char,
    Func(Vec<Type>, Box<Type>), // (param types, return type)
    Var(usize), // id
}

impl Type {
    pub fn to_string(&self) -> String {
        match self {
            &Type::Unit => "unit".to_string(),
            &Type::Bool => "bool".to_string(),
            &Type::Char => "char".to_string(),
            &Type::Int => "int".to_string(),
            &Type::Float => "float".to_string(),
            &Type::Func(ref param_tys, ref ret_ty) => {
                param_tys.into_iter().fold("".to_string(), |acc, ts| {
                    acc + ts.to_string().as_str() + " -> "
                }) + ret_ty.to_string().as_str() + " = <fun>"
            }
            &Type::Var(id) => format!("var({})", id),
        }
    }
}

use std::fmt;
impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

#[derive(Debug)]
pub enum TypeError {
    Unify(Type, Type),
}

fn deref_ty(ty: &Type, tyenv: &HashMap<usize, Type>) -> Type {
    macro_rules! deref_typ_list {
        ($list:expr) => ($list.iter().map(|x| deref_ty(x, tyenv))
                                  .collect::<Vec<_>>());
    }
    match *ty {
        Type::Func(ref p, ref r) => Type::Func(deref_typ_list!(p), Box::new(deref_ty(r, tyenv))),
        // Type::Tuple(ref ts) => Type::Tuple(deref_ty_list!(ts)),
        // Type::Array(ref t) => Type::Array(Box::new(deref_ty(t, tyenv))),
        Type::Var(ref n) => {
            if let Some(t) = tyenv.get(n) {
                deref_ty(t, tyenv)
            } else {
                Type::Var(*n)
                // panic!("uninstantiated variable is not allowed now")
            }
        }
        _ => ty.clone(),
    }
}

fn deref_term(node: &NodeKind, tyenv: &HashMap<usize, Type>) -> NodeKind {
    macro_rules! apply_deref {
        ($ary:expr) => ($ary.iter().map(|x| deref_term(x, tyenv)).collect::<Vec<_>>());
    }
    match *node {
        NodeKind::IntBinaryOp(ref op, ref lhs, ref rhs) => {
            NodeKind::IntBinaryOp(
                op.clone(),
                Box::new(deref_term(&**lhs, tyenv)),
                Box::new(deref_term(&**rhs, tyenv)),
            )
        }
        NodeKind::FloatBinaryOp(ref op, ref lhs, ref rhs) => {
            NodeKind::FloatBinaryOp(
                op.clone(),
                Box::new(deref_term(&**lhs, tyenv)),
                Box::new(deref_term(&**rhs, tyenv)),
            )
        }
        NodeKind::Call(ref e, ref args) => {
            NodeKind::Call(Box::new(deref_term(e, tyenv)), apply_deref!(args))
        }
        NodeKind::LetExpr((ref name, ref ty), ref expr, ref body) => {
            NodeKind::LetExpr(
                (name.clone(), deref_ty(ty, tyenv)),
                Box::new(deref_term(&**expr, tyenv)),
                Box::new(deref_term(&**body, tyenv)),
            )
        }
        NodeKind::LetDef((ref name, ref ty), ref expr) => {
            NodeKind::LetDef(
                (name.clone(), deref_ty(ty, tyenv)),
                Box::new(deref_term(&**expr, tyenv)),
            )
        }
        NodeKind::LetFuncExpr(ref funcdef, ref expr, ref body) => {
            let (ref name, ref ty) = funcdef.name;
            let params = &funcdef.params;
            NodeKind::LetFuncExpr(
                FuncDef {
                    name: (name.to_string(), deref_ty(ty, tyenv)),
                    params: params
                        .iter()
                        .map(|&(ref x, ref t)| (x.clone(), deref_ty(t, tyenv)))
                        .collect::<Vec<_>>(),
                },
                Box::new(deref_term(expr, tyenv)),
                Box::new(deref_term(body, tyenv)),
            )
        }
        NodeKind::LetFuncDef(ref funcdef, ref expr) => {
            let (ref name, ref ty) = funcdef.name;
            let params = &funcdef.params;
            NodeKind::LetFuncDef(
                FuncDef {
                    name: (name.to_string(), deref_ty(ty, tyenv)),
                    params: params
                        .iter()
                        .map(|&(ref x, ref t)| (x.clone(), deref_ty(t, tyenv)))
                        .collect::<Vec<_>>(),
                },
                Box::new(deref_term(expr, tyenv)),
            )
        }
        _ => node.clone(),
    }
}

fn occur(r1: usize, ty: &Type) -> bool {
    macro_rules! occur_list {
        ($ls:expr) => ($ls.iter().any(|ty| occur(r1, ty)))
    }
    match *ty {
        Type::Func(ref t2s, ref t2) => occur_list!(t2s) || occur(r1, t2),
        // Type::Tuple(ref t2s) => occur_list!(t2s),
        // Type::Array(ref t2) => occur(r1, t2),
        Type::Var(r2) => r1 == r2,
        _ => false,
    }
}

pub fn unify(t1: &Type, t2: &Type, tyenv: &mut HashMap<usize, Type>) -> Result<(), TypeError> {
    match (t1, t2) {
        (&Type::Unit, &Type::Unit) => Ok(()),
        (&Type::Bool, &Type::Bool) => Ok(()),
        (&Type::Char, &Type::Char) => Ok(()),
        (&Type::Int, &Type::Int) => Ok(()),
        (&Type::Float, &Type::Float) => Ok(()),
        (&Type::Func(ref t1p, ref t1r), &Type::Func(ref t2p, ref t2r)) => {
            if t1p.len() != t2p.len() {
                return Err(TypeError::Unify(t1.clone(), t2.clone()));
            }
            for (a, b) in t1p.iter().zip(t2p.iter()) {
                try!(unify(a, b, tyenv));
            }
            unify(t1r, t2r, tyenv)
        }
        (&Type::Var(i1), &Type::Var(i2)) if i1 == i2 => Ok(()),
        (&Type::Var(ref i1), _) => {
            if let Some(t1sub) = tyenv.get(i1).cloned() {
                unify(&t1sub, t2, tyenv)
            } else {
                if occur(*i1, t2) {
                    return Err(TypeError::Unify(t1.clone(), t2.clone()));
                }
                tyenv.insert(*i1, t2.clone());
                Ok(())
            }
        }
        (_, &Type::Var(_)) => unify(t2, t1, tyenv),
        // TODO: implement more types
        _ => Err(TypeError::Unify(t1.clone(), t2.clone())),
    }
}

pub fn g(
    node: &NodeKind,
    env: &HashMap<String, Type>,
    tyenv: &mut HashMap<usize, Type>,
    idgen: &mut id::IdGen,
) -> Result<Type, TypeError> {
    macro_rules! g_seq {
        ($es:expr) => ({
            let mut argtys = Vec::new();
            for e in $es.iter() { argtys.push(try!(g(e, env, tyenv, idgen))); }
            argtys
        });
    }
    match *node {
        NodeKind::Unit => Ok(Type::Unit),
        NodeKind::Bool(_) => Ok(Type::Bool),
        NodeKind::Int(_) => Ok(Type::Int),
        NodeKind::Float(_) => Ok(Type::Float),
        NodeKind::Ident(ref name) => {
            if let Some(t) = env.get(name).cloned() {
                Ok(t)
            } else if let Some(t) = EXTENV.lock().unwrap().get(name).cloned() {
                Ok(t)
            } else {
                panic!("TODO: implement")
            }
        }
        NodeKind::IntBinaryOp(_, ref lhs, ref rhs) => {
            try!(unify(&try!(g(lhs, env, tyenv, idgen)), &Type::Int, tyenv));
            try!(unify(&try!(g(rhs, env, tyenv, idgen)), &Type::Int, tyenv));
            Ok(Type::Int)
        }
        NodeKind::FloatBinaryOp(_, ref lhs, ref rhs) => {
            try!(unify(&try!(g(lhs, env, tyenv, idgen)), &Type::Float, tyenv));
            try!(unify(&try!(g(rhs, env, tyenv, idgen)), &Type::Float, tyenv));
            Ok(Type::Float)
        }
        NodeKind::Call(ref callee, ref args) => {
            let ty = idgen.get_type();
            let functy = Type::Func(g_seq!(args), Box::new(ty.clone()));
            try!(unify(&try!(g(callee, env, tyenv, idgen)), &functy, tyenv));
            Ok(ty)
        }
        NodeKind::LetExpr((ref name, ref ty), ref expr, ref body) => {
            try!(unify(&try!(g(expr, env, tyenv, idgen)), ty, tyenv));
            let mut newenv = HashMap::new();
            newenv.insert(name.clone(), ty.clone());
            g(body, &newenv, tyenv, idgen)
        }
        NodeKind::LetFuncExpr(ref funcdef, ref expr, ref body) => {
            let (name, ty) = funcdef.name.clone();
            let params = &funcdef.params;
            let mut newenv = env.clone();
            newenv.insert(name.clone(), ty.clone());
            let mut newenv_body = newenv.clone();
            for &(ref x, ref t) in params.iter() {
                newenv_body.insert(x.to_string(), t.clone());
            }
            try!(unify(
                &ty,
                &Type::Func(
                    params.iter().map(|p| p.1.clone()).collect::<Vec<_>>(),
                    Box::new(try!(g(expr, &newenv_body, tyenv, idgen))),
                ),
                tyenv,
            ));
            g(body, &newenv, tyenv, idgen)
        }
        NodeKind::LetDef((ref name, ref ty), ref expr) => {
            try!(unify(&try!(g(expr, env, tyenv, idgen)), ty, tyenv));
            Ok(Type::Unit)
        }
        NodeKind::LetFuncDef(ref funcdef, ref expr) => {
            let (name, ty) = funcdef.name.clone();
            let params = &funcdef.params;
            let mut newenv = env.clone();
            newenv.insert(name.clone(), ty.clone());
            let mut newenv_body = newenv.clone();
            for &(ref x, ref t) in params.iter() {
                newenv_body.insert(x.to_string(), t.clone());
            }
            try!(unify(
                &ty,
                &Type::Func(
                    params.iter().map(|p| p.1.clone()).collect::<Vec<_>>(),
                    Box::new(try!(g(expr, &newenv_body, tyenv, idgen))),
                ),
                tyenv,
            ));
            EXTENV.lock().unwrap().insert(name.clone(), ty.clone());
            Ok(Type::Unit)
        }
        _ => panic!(),
    }
}

pub fn f(node: &NodeKind, tyenv: &mut HashMap<usize, Type>, idgen: &mut id::IdGen) -> NodeKind {
    let infered_ty = g(node, &HashMap::new(), tyenv, idgen);
    println!("f: {:?}", infered_ty);
    // TODO: originally maybe infered_ty must be Type::Unit
    let r = deref_term(node, &tyenv);
    println!("{:?}", tyenv);
    r
}
<commit_msg>bug fix<commit_after>use std::boxed::Box;
use std::collections::HashMap;

use node::{NodeKind, FuncDef};
use id;

use parser::EXTENV;

#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Type {
    Unit,
    Bool,
    Int,
    Float,
    Char,
    Func(Vec<Type>, Box<Type>), // (param types, return type)
    Var(usize), // id
}

impl Type {
    pub fn to_string(&self) -> String {
        match self {
            &Type::Unit => "unit".to_string(),
            &Type::Bool => "bool".to_string(),
            &Type::Char => "char".to_string(),
            &Type::Int => "int".to_string(),
            &Type::Float => "float".to_string(),
            &Type::Func(ref param_tys, ref ret_ty) => {
                param_tys.into_iter().fold("".to_string(), |acc, ts| {
                    acc + ts.to_string().as_str() + " -> "
                }) + ret_ty.to_string().as_str() + " = <fun>"
            }
            &Type::Var(id) => format!("var({})", id),
        }
    }
}

use std::fmt;
impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

#[derive(Debug)]
pub enum TypeError {
    Unify(Type, Type),
}

fn deref_ty(ty: &Type, tyenv: &HashMap<usize, Type>) -> Type {
    macro_rules! deref_typ_list {
        ($list:expr) => ($list.iter().map(|x| deref_ty(x, tyenv))
                                  .collect::<Vec<_>>());
    }
    match *ty {
        Type::Func(ref p, ref r) => Type::Func(deref_typ_list!(p), Box::new(deref_ty(r, tyenv))),
        // Type::Tuple(ref ts) => Type::Tuple(deref_ty_list!(ts)),
        // Type::Array(ref t) => Type::Array(Box::new(deref_ty(t, tyenv))),
        Type::Var(ref n) => {
            if let Some(t) = tyenv.get(n) {
                deref_ty(t, tyenv)
            } else {
                Type::Var(*n)
                // panic!("uninstantiated variable is not allowed now")
            }
        }
        _ => ty.clone(),
    }
}

fn deref_term(node: &NodeKind, tyenv: &HashMap<usize, Type>) -> NodeKind {
    macro_rules! apply_deref {
        ($ary:expr) => ($ary.iter().map(|x| deref_term(x, tyenv)).collect::<Vec<_>>());
    }
    match *node {
        NodeKind::IntBinaryOp(ref op, ref lhs, ref rhs) => {
            NodeKind::IntBinaryOp(
                op.clone(),
                Box::new(deref_term(&**lhs, tyenv)),
                Box::new(deref_term(&**rhs, tyenv)),
            )
        }
        NodeKind::FloatBinaryOp(ref op, ref lhs, ref rhs) => {
            NodeKind::FloatBinaryOp(
                op.clone(),
                Box::new(deref_term(&**lhs, tyenv)),
                Box::new(deref_term(&**rhs, tyenv)),
            )
        }
        NodeKind::Call(ref e, ref args) => {
            NodeKind::Call(Box::new(deref_term(e, tyenv)), apply_deref!(args))
        }
        NodeKind::LetExpr((ref name, ref ty), ref expr, ref body) => {
            NodeKind::LetExpr(
                (name.clone(), deref_ty(ty, tyenv)),
                Box::new(deref_term(&**expr, tyenv)),
                Box::new(deref_term(&**body, tyenv)),
            )
        }
        NodeKind::LetDef((ref name, ref ty), ref expr) => {
            NodeKind::LetDef(
                (name.clone(), deref_ty(ty, tyenv)),
                Box::new(deref_term(&**expr, tyenv)),
            )
        }
        NodeKind::LetFuncExpr(ref funcdef, ref expr, ref body) => {
            let (ref name, ref ty) = funcdef.name;
            let params = &funcdef.params;
            NodeKind::LetFuncExpr(
                FuncDef {
                    name: (name.to_string(), deref_ty(ty, tyenv)),
                    params: params
                        .iter()
                        .map(|&(ref x, ref t)| (x.clone(), deref_ty(t, tyenv)))
                        .collect::<Vec<_>>(),
                },
                Box::new(deref_term(expr, tyenv)),
                Box::new(deref_term(body, tyenv)),
            )
        }
        NodeKind::LetFuncDef(ref funcdef, ref expr) => {
            let (ref name, ref ty) = funcdef.name;
            let params = &funcdef.params;
            NodeKind::LetFuncDef(
                FuncDef {
                    name: (name.to_string(), deref_ty(ty, tyenv)),
                    params: params
                        .iter()
                        .map(|&(ref x, ref t)| (x.clone(), deref_ty(t, tyenv)))
                        .collect::<Vec<_>>(),
                },
                Box::new(deref_term(expr, tyenv)),
            )
        }
        _ => node.clone(),
    }
}

fn occur(r1: usize, ty: &Type) -> bool {
    macro_rules! occur_list {
        ($ls:expr) => ($ls.iter().any(|ty| occur(r1, ty)))
    }
    match *ty {
        Type::Func(ref t2s, ref t2) => occur_list!(t2s) || occur(r1, t2),
        // Type::Tuple(ref t2s) => occur_list!(t2s),
        // Type::Array(ref t2) => occur(r1, t2),
        Type::Var(r2) => r1 == r2,
        _ => false,
    }
}

pub fn unify(t1: &Type, t2: &Type, tyenv: &mut HashMap<usize, Type>) -> Result<(), TypeError> {
    match (t1, t2) {
        (&Type::Unit, &Type::Unit) => Ok(()),
        (&Type::Bool, &Type::Bool) => Ok(()),
        (&Type::Char, &Type::Char) => Ok(()),
        (&Type::Int, &Type::Int) => Ok(()),
        (&Type::Float, &Type::Float) => Ok(()),
        (&Type::Func(ref t1p, ref t1r), &Type::Func(ref t2p, ref t2r)) => {
            if t1p.len() != t2p.len() {
                return Err(TypeError::Unify(t1.clone(), t2.clone()));
            }
            for (a, b) in t1p.iter().zip(t2p.iter()) {
                try!(unify(a, b, tyenv));
            }
            unify(t1r, t2r, tyenv)
        }
        (&Type::Var(i1), &Type::Var(i2)) if i1 == i2 => Ok(()),
        (&Type::Var(ref i1), _) => {
            if let Some(t1sub) = tyenv.get(i1).cloned() {
                unify(&t1sub, t2, tyenv)
            } else {
                if occur(*i1, t2) {
                    return Err(TypeError::Unify(t1.clone(), t2.clone()));
                }
                tyenv.insert(*i1, t2.clone());
                Ok(())
            }
        }
        (_, &Type::Var(_)) => unify(t2, t1, tyenv),
        // TODO: implement more types
        _ => Err(TypeError::Unify(t1.clone(), t2.clone())),
    }
}

pub fn g(
    node: &NodeKind,
    env: &HashMap<String, Type>,
    tyenv: &mut HashMap<usize, Type>,
    idgen: &mut id::IdGen,
) -> Result<Type, TypeError> {
    macro_rules! g_seq {
        ($es:expr) => ({
            let mut argtys = Vec::new();
            for e in $es.iter() { argtys.push(try!(g(e, env, tyenv, idgen))); }
            argtys
        });
    }
    match *node {
        NodeKind::Unit => Ok(Type::Unit),
        NodeKind::Bool(_) => Ok(Type::Bool),
        NodeKind::Int(_) => Ok(Type::Int),
        NodeKind::Float(_) => Ok(Type::Float),
        NodeKind::Ident(ref name) => {
            if let Some(t) = env.get(name).cloned() {
                Ok(t)
            } else if let Some(t) = EXTENV.lock().unwrap().get(name).cloned() {
                Ok(t)
            } else {
                panic!("TODO: implement")
            }
        }
        NodeKind::IntBinaryOp(_, ref lhs, ref rhs) => {
            try!(unify(&try!(g(lhs, env, tyenv, idgen)), &Type::Int, tyenv));
            try!(unify(&try!(g(rhs, env, tyenv, idgen)), &Type::Int, tyenv));
            Ok(Type::Int)
        }
        NodeKind::FloatBinaryOp(_, ref lhs, ref rhs) => {
            try!(unify(&try!(g(lhs, env, tyenv, idgen)), &Type::Float, tyenv));
            try!(unify(&try!(g(rhs, env, tyenv, idgen)), &Type::Float, tyenv));
            Ok(Type::Float)
        }
        NodeKind::Call(ref callee, ref args) => {
            let ty = idgen.get_type();
            let functy = Type::Func(g_seq!(args), Box::new(ty.clone()));
            try!(unify(&try!(g(callee, env, tyenv, idgen)), &functy, tyenv));
            Ok(ty)
        }
        NodeKind::LetExpr((ref name, ref ty), ref expr, ref body) => {
            try!(unify(&try!(g(expr, env, tyenv, idgen)), ty, tyenv));
            let mut newenv = HashMap::new();
            newenv.insert(name.clone(), ty.clone());
            g(body, &newenv, tyenv, idgen)
        }
        NodeKind::LetFuncExpr(ref funcdef, ref expr, ref body) => {
            let (name, ty) = funcdef.name.clone();
            let params = &funcdef.params;
            let mut newenv = env.clone();
            newenv.insert(name.clone(), ty.clone());
            let mut newenv_body = newenv.clone();
            for &(ref x, ref t) in params.iter() {
                newenv_body.insert(x.to_string(), t.clone());
            }
            try!(unify(
                &ty,
                &Type::Func(
                    params.iter().map(|p| p.1.clone()).collect::<Vec<_>>(),
                    Box::new(try!(g(expr, &newenv_body, tyenv, idgen))),
                ),
                tyenv,
            ));
            g(body, &newenv, tyenv, idgen)
        }
        NodeKind::LetDef((ref name, ref ty), ref expr) => {
            try!(unify(&try!(g(expr, env, tyenv, idgen)), ty, tyenv));
            EXTENV.lock().unwrap().insert(name.clone(), ty.clone());
            Ok(Type::Unit)
        }
        NodeKind::LetFuncDef(ref funcdef, ref expr) => {
            let (name, ty) = funcdef.name.clone();
            let params = &funcdef.params;
            let mut newenv = env.clone();
            newenv.insert(name.clone(), ty.clone());
            let mut newenv_body = newenv.clone();
            for &(ref x, ref t) in params.iter() {
                newenv_body.insert(x.to_string(), t.clone());
            }
            try!(unify(
                &ty,
                &Type::Func(
                    params.iter().map(|p| p.1.clone()).collect::<Vec<_>>(),
                    Box::new(try!(g(expr, &newenv_body, tyenv, idgen))),
                ),
                tyenv,
            ));
            EXTENV.lock().unwrap().insert(name.clone(), ty.clone());
            Ok(Type::Unit)
        }
        _ => panic!(),
    }
}

pub fn f(node: &NodeKind, tyenv: &mut HashMap<usize, Type>, idgen: &mut id::IdGen) -> NodeKind {
    let infered_ty = g(node, &HashMap::new(), tyenv, idgen);
    println!("f: {:?}", infered_ty);
    // TODO: originally maybe infered_ty must be Type::Unit
    let r = deref_term(node, &tyenv);
    println!("{:?}", tyenv);
    r
}
<|endoftext|>


<commit_before>use quick_xml::se::{to_string, Serializer};
use quick_xml::writer::Writer;

use pretty_assertions::assert_eq;

use serde::{Serialize, Serializer as SerSerializer};

#[test]
fn serialize_bool() {
    let inputs = [(true, "true"), (false, "false")];

    for (src, should_be) in &inputs {
        let mut buffer = Vec::new();
        let mut ser = Serializer::new(&mut buffer);
        ser.serialize_bool(*src).unwrap();

        assert_eq!(String::from_utf8(buffer).unwrap(), *should_be);
    }
}

#[test]
fn serialize_struct() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        age: u32,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: 42,
    };

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    bob.serialize(&mut ser).unwrap();

    assert_eq!(
        String::from_utf8(buffer).unwrap(),
        "<Person name=\"Bob\" age=\"42\"/>"
    );
}

#[test]
fn serialize_struct_value_number() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        #[serde(rename = "$text")]
        age: u32,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: 42,
    };
    assert_eq!(to_string(&bob).unwrap(), "<Person name=\"Bob\">42</Person>");
}

#[test]
fn serialize_struct_value_string() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        #[serde(rename = "$text")]
        age: String,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: "42".to_string(),
    };
    assert_eq!(to_string(&bob).unwrap(), "<Person name=\"Bob\">42</Person>");
}

#[test]
fn serialize_enum() {
    #[derive(Serialize)]
    #[allow(dead_code)]
    enum Node {
        Boolean(bool),
        Number(f64),
        String(String),
    }

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    let node = Node::Boolean(true);
    node.serialize(&mut ser).unwrap();

    assert_eq!(
        String::from_utf8(buffer).unwrap(),
        "<Boolean>true</Boolean>"
    );
}

#[test]
#[ignore]
fn serialize_a_list() {
    let inputs = vec![1, 2, 3, 4];

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    inputs.serialize(&mut ser).unwrap();

    println!("{}", String::from_utf8(buffer).unwrap());
    panic!();
}

#[derive(Serialize)]
struct Unit;

#[derive(Serialize)]
struct Newtype(bool);

#[derive(Serialize)]
struct Tuple(f32, &'static str);

#[derive(Serialize)]
struct Struct {
    float: f64,
    string: &'static str,
}

#[derive(Serialize)]
struct NestedStruct {
    nested: Nested,
    string: &'static str,
}

#[derive(Serialize)]
struct FlattenStruct {
    #[serde(flatten)]
    nested: Nested,
    string: &'static str,
}

#[derive(Serialize)]
struct Nested {
    float: f64,
}

#[derive(Serialize)]
struct Empty {}

#[derive(Serialize)]
struct Text {
    #[serde(rename = "$text")]
    float: f64,
    string: &'static str,
}

#[derive(Serialize)]
enum ExternallyTagged {
    Unit,
    #[serde(rename = "$primitive=PrimitiveUnit")]
    PrimitiveUnit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
    Empty {},
    Text {
        #[serde(rename = "$text")]
        float: f64,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(tag = "tag")]
enum InternallyTagged {
    Unit,
    /// Primitives (such as `bool`) are not supported by the serde in the internally tagged mode
    Newtype(Nested),
    // Tuple(f64, &'static str),// Tuples are not supported in the internally tagged mode
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
    Empty {},
    Text {
        #[serde(rename = "$text")]
        float: f64,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(tag = "tag", content = "content")]
enum AdjacentlyTagged {
    Unit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
    Empty {},
    Text {
        #[serde(rename = "$text")]
        float: f64,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(untagged)]
enum Untagged {
    Unit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
    Empty {},
    Text {
        #[serde(rename = "$text")]
        float: f64,
        string: &'static str,
    },
}

mod with_root {
    use super::*;
    use pretty_assertions::assert_eq;

    macro_rules! serialize_as {
        ($name:ident: $data:expr => $expected:literal) => {
            #[test]
            fn $name() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                $data.serialize(&mut ser).unwrap();
                assert_eq!(String::from_utf8(buffer).unwrap(), $expected);
            }
        };
    }

    serialize_as!(unit:
        Unit
        => "<root/>");
    serialize_as!(newtype:
        Newtype(true)
        => "<root>true</root>");
    serialize_as!(tuple:
        (42.0, "answer")
        => "<root>42</root><root>answer</root>");
    serialize_as!(tuple_struct:
        Tuple(42.0, "answer")
        => "<root>42</root><root>answer</root>");
    serialize_as!(struct_:
        Struct {
            float: 42.0,
            string: "answer"
        }
        => r#"<root float="42" string="answer"/>"#);
    serialize_as!(nested_struct:
        NestedStruct {
            nested: Nested { float: 42.0 },
            string: "answer",
        }
        => r#"<root string="answer"><nested float="42"/></root>"#);
    serialize_as!(flatten_struct:
        FlattenStruct {
            nested: Nested { float: 42.0 },
            string: "answer",
        }
        => r#"<root><float>42</float><string>answer</string></root>"#);
    serialize_as!(empty_struct:
        Empty {}
        => "<root/>");
    serialize_as!(text:
        Text {
            float: 42.0,
            string: "answer"
        }
        => r#"<root string="answer">42</root>"#);

    mod enum_ {
        use super::*;

        mod externally_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                ExternallyTagged::Unit
                => "<Unit/>");
            serialize_as!(primitive_unit:
                ExternallyTagged::PrimitiveUnit
                => "PrimitiveUnit");
            serialize_as!(newtype:
                ExternallyTagged::Newtype(true)
                => "<Newtype>true</Newtype>");
            serialize_as!(tuple_struct:
                ExternallyTagged::Tuple(42.0, "answer")
                => "<Tuple>42</Tuple><Tuple>answer</Tuple>");
            serialize_as!(struct_:
                ExternallyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<Struct float="42" string="answer"/>"#);
            serialize_as!(nested_struct:
                ExternallyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<Holder string="answer"><nested float="42"/></Holder>"#);
            serialize_as!(flatten_struct:
                ExternallyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<Flatten><float>42</float><string>answer</string></Flatten>"#);
            serialize_as!(empty_struct:
                ExternallyTagged::Empty {}
                => "<Empty/>");
            serialize_as!(text:
                ExternallyTagged::Text {
                    float: 42.0,
                    string: "answer"
                }
                => r#"<Text string="answer">42</Text>"#);
        }

        mod internally_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                InternallyTagged::Unit
                => r#"<root tag="Unit"/>"#);
            serialize_as!(newtype:
                InternallyTagged::Newtype(Nested { float: 4.2 })
                => r#"<root tag="Newtype" float="4.2"/>"#);
            serialize_as!(struct_:
                InternallyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<root tag="Struct" float="42" string="answer"/>"#);
            serialize_as!(nested_struct:
                InternallyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root tag="Holder" string="answer"><nested float="42"/></root>"#);
            serialize_as!(flatten_struct:
                InternallyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root><tag>Flatten</tag><float>42</float><string>answer</string></root>"#);
            serialize_as!(empty_struct:
                InternallyTagged::Empty {}
                => r#"<root tag="Empty"/>"#);
            serialize_as!(text:
                InternallyTagged::Text {
                    float: 42.0,
                    string: "answer"
                }
                => r#"<root tag="Text" string="answer">42</root>"#);
        }

        mod adjacently_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                AdjacentlyTagged::Unit
                => r#"<root tag="Unit"/>"#);
            serialize_as!(newtype:
                AdjacentlyTagged::Newtype(true)
                => r#"<root tag="Newtype" content="true"/>"#);
            serialize_as!(tuple_struct:
                AdjacentlyTagged::Tuple(42.0, "answer")
                => r#"<root tag="Tuple"><content>42</content><content>answer</content></root>"#);
            serialize_as!(struct_:
                AdjacentlyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<root tag="Struct"><content float="42" string="answer"/></root>"#);
            serialize_as!(nested_struct:
                AdjacentlyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root tag="Holder"><content string="answer"><nested float="42"/></content></root>"#);
            serialize_as!(flatten_struct:
                AdjacentlyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root tag="Flatten"><content><float>42</float><string>answer</string></content></root>"#);
            serialize_as!(empty_struct:
                AdjacentlyTagged::Empty {}
                => r#"<root tag="Empty"><content/></root>"#);
            serialize_as!(text:
                AdjacentlyTagged::Text {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<root tag="Text"><content string="answer">42</content></root>"#);
        }

        mod untagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                Untagged::Unit
                // Unit variant consists just from the tag, and because tags
                // are not written in untagged mode, nothing is written
                => "");
            serialize_as!(newtype:
                Untagged::Newtype(true)
                => "true");
            serialize_as!(tuple_struct:
                Untagged::Tuple(42.0, "answer")
                => "<root>42</root><root>answer</root>");
            serialize_as!(struct_:
                Untagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => r#"<root float="42" string="answer"/>"#);
            serialize_as!(nested_struct:
                Untagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root string="answer"><nested float="42"/></root>"#);
            serialize_as!(flatten_struct:
                Untagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => r#"<root><float>42</float><string>answer</string></root>"#);
            serialize_as!(empty_struct:
                Untagged::Empty {}
                => "<root/>");
            serialize_as!(text:
                Untagged::Text {
                    float: 42.0,
                    string: "answer"
                }
                => r#"<root string="answer">42</root>"#);
        }
    }
}
<commit_msg>Change expectations about results of serializing<commit_after>use quick_xml::se::{to_string, Serializer};
use quick_xml::writer::Writer;

use pretty_assertions::assert_eq;

use serde::{Serialize, Serializer as SerSerializer};

#[test]
fn serialize_bool() {
    let inputs = [(true, "true"), (false, "false")];

    for (src, should_be) in &inputs {
        let mut buffer = Vec::new();
        let mut ser = Serializer::new(&mut buffer);
        ser.serialize_bool(*src).unwrap();

        assert_eq!(String::from_utf8(buffer).unwrap(), *should_be);
    }
}

#[test]
fn serialize_struct() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        age: u32,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: 42,
    };

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    bob.serialize(&mut ser).unwrap();

    assert_eq!(
        String::from_utf8(buffer).unwrap(),
        "<Person name=\"Bob\" age=\"42\"/>"
    );
}

#[test]
fn serialize_struct_value_number() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        #[serde(rename = "$text")]
        age: u32,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: 42,
    };
    assert_eq!(to_string(&bob).unwrap(), "<Person name=\"Bob\">42</Person>");
}

#[test]
fn serialize_struct_value_string() {
    #[derive(Serialize)]
    struct Person {
        name: String,
        #[serde(rename = "$text")]
        age: String,
    }

    let bob = Person {
        name: "Bob".to_string(),
        age: "42".to_string(),
    };
    assert_eq!(to_string(&bob).unwrap(), "<Person name=\"Bob\">42</Person>");
}

#[test]
fn serialize_enum() {
    #[derive(Serialize)]
    #[allow(dead_code)]
    enum Node {
        Boolean(bool),
        Number(f64),
        String(String),
    }

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    let node = Node::Boolean(true);
    node.serialize(&mut ser).unwrap();

    assert_eq!(
        String::from_utf8(buffer).unwrap(),
        "<Boolean>true</Boolean>"
    );
}

#[test]
#[ignore]
fn serialize_a_list() {
    let inputs = vec![1, 2, 3, 4];

    let mut buffer = Vec::new();
    let mut ser = Serializer::new(&mut buffer);
    inputs.serialize(&mut ser).unwrap();

    println!("{}", String::from_utf8(buffer).unwrap());
    panic!();
}

#[derive(Serialize)]
struct Unit;

#[derive(Serialize)]
struct Newtype(bool);

#[derive(Serialize)]
struct Tuple(f32, &'static str);

#[derive(Serialize)]
struct Struct {
    float: f64,
    string: &'static str,
}

#[derive(Serialize)]
struct NestedStruct {
    nested: Nested,
    string: &'static str,
}

#[derive(Serialize)]
struct FlattenStruct {
    #[serde(flatten)]
    nested: Nested,
    string: &'static str,
}

#[derive(Serialize)]
struct Nested {
    float: f64,
}

#[derive(Serialize)]
struct Empty {}

#[derive(Serialize)]
struct Text {
    #[serde(rename = "$text")]
    float: f64,
    string: &'static str,
}

#[derive(Serialize)]
enum ExternallyTagged {
    Unit,
    #[serde(rename = "$primitive=PrimitiveUnit")]
    PrimitiveUnit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
    Empty {},
    Text {
        #[serde(rename = "$text")]
        float: f64,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(tag = "tag")]
enum InternallyTagged {
    Unit,
    /// Primitives (such as `bool`) are not supported by the serde in the internally tagged mode
    Newtype(Nested),
    // Tuple(f64, &'static str),// Tuples are not supported in the internally tagged mode
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
    Empty {},
    Text {
        #[serde(rename = "$text")]
        float: f64,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(tag = "tag", content = "content")]
enum AdjacentlyTagged {
    Unit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
    Empty {},
    Text {
        #[serde(rename = "$text")]
        float: f64,
        string: &'static str,
    },
}

#[derive(Serialize)]
#[serde(untagged)]
enum Untagged {
    Unit,
    Newtype(bool),
    Tuple(f64, &'static str),
    Struct {
        float: f64,
        string: &'static str,
    },
    Holder {
        nested: Nested,
        string: &'static str,
    },
    Flatten {
        #[serde(flatten)]
        nested: Nested,
        string: &'static str,
    },
    Empty {},
    Text {
        #[serde(rename = "$text")]
        float: f64,
        string: &'static str,
    },
}

mod with_root {
    use super::*;
    use pretty_assertions::assert_eq;

    macro_rules! serialize_as {
        ($name:ident: $data:expr => $expected:literal) => {
            #[test]
            fn $name() {
                let mut buffer = Vec::new();
                let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));

                $data.serialize(&mut ser).unwrap();
                assert_eq!(String::from_utf8(buffer).unwrap(), $expected);
            }
        };
    }

    serialize_as!(unit:
        Unit
        => "<root/>");
    serialize_as!(newtype:
        Newtype(true)
        => "<root>true</root>");
    serialize_as!(tuple:
        (42.0, "answer")
        => "<root>42</root>\
            <root>answer</root>");
    serialize_as!(tuple_struct:
        Tuple(42.0, "answer")
        => "<root>42</root>\
            <root>answer</root>");
    serialize_as!(struct_:
        Struct {
            float: 42.0,
            string: "answer"
        }
        => "<root>\
                <float>42</float>\
                <string>answer</string>\
            </root>");
    serialize_as!(nested_struct:
        NestedStruct {
            nested: Nested { float: 42.0 },
            string: "answer",
        }
        => "<root>\
                <nested>\
                    <float>42</float>\
                </nested>\
                <string>answer</string>\
            </root>");
    serialize_as!(flatten_struct:
        FlattenStruct {
            nested: Nested { float: 42.0 },
            string: "answer",
        }
        => "<root>\
                <float>42</float>\
                <string>answer</string>\
            </root>");
    serialize_as!(empty_struct:
        Empty {}
        => "<root/>");
    serialize_as!(text:
        Text {
            float: 42.0,
            string: "answer"
        }
        => "<root>\
                42\
                <string>answer</string>\
            </root>");

    mod enum_ {
        use super::*;

        mod externally_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                ExternallyTagged::Unit
                => "<Unit/>");
            serialize_as!(primitive_unit:
                ExternallyTagged::PrimitiveUnit
                => "PrimitiveUnit");
            serialize_as!(newtype:
                ExternallyTagged::Newtype(true)
                => "<Newtype>true</Newtype>");
            serialize_as!(tuple_struct:
                ExternallyTagged::Tuple(42.0, "answer")
                => "<Tuple>42</Tuple>\
                    <Tuple>answer</Tuple>");
            serialize_as!(struct_:
                ExternallyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => "<Struct>\
                        <float>42</float>\
                        <string>answer</string>\
                    </Struct>");
            serialize_as!(nested_struct:
                ExternallyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => "<Holder>\
                        <nested>\
                            <float>42</float>\
                        </nested>\
                        <string>answer</string>\
                    </Holder>");
            serialize_as!(flatten_struct:
                ExternallyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => "<Flatten>\
                        <float>42</float>\
                        <string>answer</string>\
                    </Flatten>");
            serialize_as!(empty_struct:
                ExternallyTagged::Empty {}
                => "<Empty/>");
            serialize_as!(text:
                ExternallyTagged::Text {
                    float: 42.0,
                    string: "answer"
                }
                => "<Text>\
                        42\
                        <string>answer</string>\
                    </Text>");
        }

        mod internally_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                InternallyTagged::Unit
                => "<root>\
                        <tag>Unit</tag>\
                    </root>");
            serialize_as!(newtype:
                InternallyTagged::Newtype(Nested { float: 4.2 })
                => "<root>\
                        <tag>Newtype</tag>\
                        <float>4.2</float>\
                    </root>");
            serialize_as!(struct_:
                InternallyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => "<root>\
                        <tag>Struct</tag>\
                        <float>42</float>\
                        <string>answer</string>\
                    </root>");
            serialize_as!(nested_struct:
                InternallyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => "<root>\
                        <tag>Holder</tag>\
                        <nested>\
                            <float>42</float>\
                        </nested>\
                        <string>answer</string>\
                    </root>");
            serialize_as!(flatten_struct:
                InternallyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => "<root>\
                        <tag>Flatten</tag>\
                        <float>42</float>\
                        <string>answer</string>\
                    </root>");
            serialize_as!(empty_struct:
                InternallyTagged::Empty {}
                => r#"<root tag="Empty"/>"#);
            serialize_as!(text:
                InternallyTagged::Text {
                    float: 42.0,
                    string: "answer"
                }
                => "<root>\
                        <tag>Text</tag>\
                        42\
                        <string>answer</string>\
                    </root>");
        }

        mod adjacently_tagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                AdjacentlyTagged::Unit
                => "<root>\
                        <tag>Unit</tag>\
                    </root>");
            serialize_as!(newtype:
                AdjacentlyTagged::Newtype(true)
                => "<root>\
                        <tag>Newtype</tag>\
                        <content>true</content>\
                    </root>");
            serialize_as!(tuple_struct:
                AdjacentlyTagged::Tuple(42.0, "answer")
                => "<root>\
                        <tag>Tuple</tag>\
                        <content>42</content>\
                        <content>answer</content>\
                    </root>");
            serialize_as!(struct_:
                AdjacentlyTagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => "<root>\
                        <tag>Struct</tag>\
                        <content>\
                            <float>42</float>\
                            <string>answer</string>\
                        </content>\
                    </root>");
            serialize_as!(nested_struct:
                AdjacentlyTagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => "<root>\
                        <tag>Holder</tag>\
                        <content>\
                            <nested>\
                                <float>42</float>\
                            </nested>\
                            <string>answer</string>\
                        </content>\
                    </root>");
            serialize_as!(flatten_struct:
                AdjacentlyTagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => "<root>\
                        <tag>Flatten</tag>\
                        <content>\
                            <float>42</float>\
                            <string>answer</string>\
                        </content>\
                    </root>");
            serialize_as!(empty_struct:
                AdjacentlyTagged::Empty {}
                => r#"<root tag="Empty"><content/></root>"#);
            serialize_as!(text:
                AdjacentlyTagged::Text {
                    float: 42.0,
                    string: "answer",
                }
                => "<root>\
                        <tag>Text</tag>\
                        <content>\
                            42\
                            <string>answer</string>\
                        </content>\
                    </root>");
        }

        mod untagged {
            use super::*;
            use pretty_assertions::assert_eq;

            serialize_as!(unit:
                Untagged::Unit
                // Unit variant consists just from the tag, and because tags
                // are not written in untagged mode, nothing is written
                => "");
            serialize_as!(newtype:
                Untagged::Newtype(true)
                => "true");
            serialize_as!(tuple_struct:
                Untagged::Tuple(42.0, "answer")
                => "<root>42</root>\
                    <root>answer</root>");
            serialize_as!(struct_:
                Untagged::Struct {
                    float: 42.0,
                    string: "answer",
                }
                => "<root>\
                        <float>42</float>\
                        <string>answer</string>\
                    </root>");
            serialize_as!(nested_struct:
                Untagged::Holder {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => "<root>\
                        <nested>\
                            <float>42</float>\
                        </nested>\
                        <string>answer</string>\
                    </root>");
            serialize_as!(flatten_struct:
                Untagged::Flatten {
                    nested: Nested { float: 42.0 },
                    string: "answer",
                }
                => "<root>\
                        <float>42</float>\
                        <string>answer</string>\
                    </root>");
            serialize_as!(empty_struct:
                Untagged::Empty {}
                => "<root/>");
            serialize_as!(text:
                Untagged::Text {
                    float: 42.0,
                    string: "answer"
                }
                => "<root>\
                        42\
                        <string>answer</string>\
                    </root>");
        }
    }
}
<|endoftext|>


<commit_before>//! Generate update information from dependency information.

use std::rc::Rc;
use std::collections::HashMap;

use semver::Version;

use dependencies;

/// Stores old and new version.
pub struct Bump {
    /// The old version.
    pub old: Version,
    /// The new version.
    pub new: Version,
}

/// Stores update info for dependency.
pub struct Dependency {
    /// The library name.
    pub name: Rc<String>,
    /// Bump info.
    pub bump: Bump,
}

/// Stores information about a package.
pub struct Package {
    /// The package name.
    pub name: Rc<String>,
    /// The order to update library.
    pub order: u32,
    /// Update information.
    pub bump: Bump,
    /// The dependencies.
    pub dependencies: Vec<Dependency>,
}

/// Generates update info.
pub fn generate_update_info_from(dependency_info: &str) -> Result<String, String> {
    use piston_meta::*;
    use std::iter::FromIterator;

    type PackageIndex = usize;
    type Depth = u32;

    fn depth_of(
        package_index: PackageIndex,
        package_indices: &HashMap<Rc<String>, PackageIndex>,
        depths: &mut HashMap<PackageIndex, Depth>,
        dependencies_data: &[dependencies::Package]
    ) -> Depth {
        let package = &dependencies_data[package_index];
        let d = depths.get(&package_index).map(|d| *d);
        match d {
            None => {
                // The depth of a package equals maximum depth of the dependencies + 1.
                let new_depth: Depth = package.dependencies.iter().map(|dep| {
                        package_indices.get(&dep.name).map(|&p| {
                                depth_of(p, package_indices, depths, dependencies_data)
                            }).unwrap_or(0)
                    }).max().unwrap_or(0) + 1;
                depths.insert(package_index, new_depth);
                new_depth
            }
            Some(x) => x
        }
    }

    // Parse and convert to dependencies data.
    let dependencies_meta_syntax = include_str!("../assets/dependencies/syntax.txt");
    let dependencies_meta_rules = stderr_unwrap(dependencies_meta_syntax,
        syntax(dependencies_meta_syntax));
    let dependency_info = stderr_unwrap(dependency_info,
        parse(&dependencies_meta_rules, dependency_info));
    let mut ignored = vec![];
    let dependencies_data = try!(dependencies::convert(&dependency_info, &mut ignored)
        .map_err(|_| String::from("Could not convert dependency info")));

    // Stores the package indices using package name as key.
    let package_indices: HashMap<Rc<String>, PackageIndex> =
        HashMap::from_iter(dependencies_data.iter().enumerate().map(
            |(i, p)| {
                (p.name.clone(), i)
            }));

    // Store the depths of libraries.
    let mut depths: HashMap<PackageIndex, Depth> = HashMap::new();
    for i in 0 .. dependencies_data.len() {
        let _depth = depth_of(i, &package_indices, &mut depths, &dependencies_data);
    }

    let mut new_versions: HashMap<Rc<String>, Version> = HashMap::new();
    for package in &dependencies_data {
        // Get latest version used by any dependency.
        for dep in &package.dependencies {
            let version = try!(Version::parse(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for `{}`",
                    &dep.version, &dep.name)));
            let v = new_versions.get(&dep.name).map(|v| v.clone());
            match v {
                None => {
                    new_versions.insert(dep.name.clone(), version);
                }
                Some(v) => {
                    if v < version {
                        new_versions.insert(dep.name.clone(), version);
                    }
                }
            }
        }
    }

    // Overwrite the versions used by packages.
    for package in &dependencies_data {
        let version = try!(Version::parse(&package.version)
            .map_err(|_| format!("Could not parse version `{}` for `{}`",
                &package.version, &package.name)));
        new_versions.insert(package.name.clone(), version);
    }

    Ok(String::from(""))
}
<commit_msg>Detect libraries that needs update<commit_after>//! Generate update information from dependency information.

use std::rc::Rc;
use std::collections::HashMap;

use semver::Version;

use dependencies;

/// Stores old and new version.
pub struct Bump {
    /// The old version.
    pub old: Version,
    /// The new version.
    pub new: Version,
}

/// Stores update info for dependency.
pub struct Dependency {
    /// The library name.
    pub name: Rc<String>,
    /// Bump info.
    pub bump: Bump,
}

/// Stores information about a package.
pub struct Package {
    /// The package name.
    pub name: Rc<String>,
    /// The order to update library.
    pub order: u32,
    /// Update information.
    pub bump: Bump,
    /// The dependencies.
    pub dependencies: Vec<Dependency>,
}

/// Generates update info.
pub fn generate_update_info_from(dependency_info: &str) -> Result<String, String> {
    use piston_meta::*;
    use std::iter::FromIterator;

    type PackageIndex = usize;
    type Depth = u32;

    fn depth_of(
        package_index: PackageIndex,
        package_indices: &HashMap<Rc<String>, PackageIndex>,
        depths: &mut HashMap<PackageIndex, Depth>,
        dependencies_data: &[dependencies::Package]
    ) -> Depth {
        let package = &dependencies_data[package_index];
        let d = depths.get(&package_index).map(|d| *d);
        match d {
            None => {
                // The depth of a package equals maximum depth of the dependencies + 1.
                let new_depth: Depth = package.dependencies.iter().map(|dep| {
                        package_indices.get(&dep.name).map(|&p| {
                                depth_of(p, package_indices, depths, dependencies_data)
                            }).unwrap_or(0)
                    }).max().unwrap_or(0) + 1;
                depths.insert(package_index, new_depth);
                new_depth
            }
            Some(x) => x
        }
    }

    // Increment first non-zero number.
    fn increment_version(version: &mut Version) {
        if version.major != 0 { version.increment_major(); }
        else if version.minor != 0 { version.increment_minor(); }
        else { version.increment_patch(); }
    }

    // Parse and convert to dependencies data.
    let dependencies_meta_syntax = include_str!("../assets/dependencies/syntax.txt");
    let dependencies_meta_rules = stderr_unwrap(dependencies_meta_syntax,
        syntax(dependencies_meta_syntax));
    let dependency_info = stderr_unwrap(dependency_info,
        parse(&dependencies_meta_rules, dependency_info));
    let mut ignored = vec![];
    let dependencies_data = try!(dependencies::convert(&dependency_info, &mut ignored)
        .map_err(|_| String::from("Could not convert dependency info")));

    // Stores the package indices using package name as key.
    let package_indices: HashMap<Rc<String>, PackageIndex> =
        HashMap::from_iter(dependencies_data.iter().enumerate().map(
            |(i, p)| {
                (p.name.clone(), i)
            }));

    // Store the depths of libraries.
    let mut depths: HashMap<PackageIndex, Depth> = HashMap::new();
    for i in 0 .. dependencies_data.len() {
        let _depth = depth_of(i, &package_indices, &mut depths, &dependencies_data);
    }

    let mut new_versions: HashMap<Rc<String>, Version> = HashMap::new();
    for package in &dependencies_data {
        // Get latest version used by any dependency.
        for dep in &package.dependencies {
            let version = try!(Version::parse(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for `{}`",
                    &dep.version, &dep.name)));
            let v = new_versions.get(&dep.name).map(|v| v.clone());
            match v {
                None => {
                    new_versions.insert(dep.name.clone(), version);
                }
                Some(v) => {
                    if v < version {
                        new_versions.insert(dep.name.clone(), version);
                    }
                }
            }
        }
    }

    // Overwrite the versions used by packages.
    for package in &dependencies_data {
        let version = try!(Version::parse(&package.version)
            .map_err(|_| format!("Could not parse version `{}` for `{}`",
                &package.version, &package.name)));
        new_versions.insert(package.name.clone(), version);
    }

    // Create list of sorted package indices by depth.
    let mut sorted_depths: Vec<_> = depths.iter().collect();
    sorted_depths.sort_by(|&(_, da), &(_, db)| da.cmp(db));

    // Stores the update info.
    let mut update_packages: Vec<Package> = vec![];

    for (&package_index, &order) in sorted_depths {
        let package = &dependencies_data[package_index];
        let mut update_dependencies = vec![];

        // Find dependencies that needs update.
        for dep in &package.dependencies {
            let old_version = try!(Version::parse(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for `{}`",
                    &dep.version, &dep.name)));
            let new_version = new_versions.get(&dep.name).unwrap();
            if *new_version > old_version {
                update_dependencies.push(Dependency {
                        name: dep.name.clone(),
                        bump: Bump {
                            old: old_version,
                            new: new_version.clone(),
                        }
                    });
            }
        }

        // If any dependency needs update, then the package needs update.
        if update_dependencies.len() > 0 {
            let old_version = try!(Version::parse(&package.version)
                .map_err(|_| format!("Could not parse version `{}` for `{}`",
                    &package.version, &package.name)));
            let new_version = new_versions.get_mut(&package.name).unwrap();
            if *new_version == old_version {
                increment_version(new_version);
            }
            update_packages.push(Package {
                    name: package.name.clone(),
                    order: order,
                    bump: Bump {
                        old: old_version,
                        new: new_version.clone(),
                    },
                    dependencies: update_dependencies,
                });
        }
    }

    Ok(String::from(""))
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use super::super::direction::Direction::*;
use super::Wall;

impl Wall {
    /// Print a labyrinth to stdout using UNICODE BOX characters.
    pub fn print(&self) {
        let mut stdout = io::stdout();
        let mut writer = |s: &str| { stdout.write_all(s.as_bytes()).unwrap() };
        self.draw(&mut writer);
    }
    /// Draw a labyrinth as a String using UNICODE BOX characters.
    pub fn to_string(&self) -> String {
        let mut out = String::new();
        self.draw(&mut |s: &str| { out.push_str(s) });
        out
    }
    /// Draw a labyrinth using UNICODE BOX characters to a `writer`.
    pub fn draw(&self, writer: &mut FnMut(&str)) {
        for y in 0..self.rows {
            writer("\n");
            for x in 0..self.cols {
                if x == 0 || self.is_open(x - 1, y, Up) {
                    if y == 0 || self.is_open(x, y - 1, Left) {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "  " } else { "╻ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "╺━" } else { "┏━" });
                        }
                    } else {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "╹ " } else { "┃ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "┗━" } else { "┣━" });
                        }
                    }
                } else {
                    if y == 0 || self.is_open(x, y - 1, Left) {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "╸ " } else { "┓ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "━━" } else { "┳━" });
                        }
                    } else {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "┛ " } else { "┫ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "┻━" } else { "╋━" });
                        }
                    }
                }
            }
            let x = self.cols;
            if self.is_open(x - 1, y, Up) {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Left) { " " } else { "╻" });
                } else {
                    writer(if self.is_open(x, y, Left) { "╹" } else { "┃" });
                }
            } else {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Left) { "╸" } else { "┓" });
                } else {
                    writer(if self.is_open(x, y, Left) { "┛" } else { "┫" });
                }
            }
        }
        let y = self.rows;
        writer("\n");
        for x in 0..self.cols {
            if x == 0 || self.is_open(x - 1, y, Up) {
                if self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Up) { "  " } else { "╺━" });
                } else {
                    writer(if self.is_open(x, y, Up) { "╹ " } else { "┗━" });
                }
            } else {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Up) { "╸ " } else { "━━" });
                } else {
                    writer(if self.is_open(x, y, Up) { "┛ " } else { "┻━" });
                }
            }
        }
        let x = self.cols;
        if self.is_open(x - 1, y, Up) {
            writer(if self.is_open(x, y - 1, Left) { " " } else { "╹" });
        } else {
            writer(if self.is_open(x, y - 1, Left) { "╸" } else { "┛" });
        }
        writer("\n");
    }
}

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

    #[test]
    fn should_draw_a_labyrinth() {
        let mut labyrinth = Wall::new(2, 2);
        assert_eq!("
┏━┳━┓
┣━╋━┫
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Right);
        assert_eq!("
┏━━━┓
┣━┳━┫
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Down);
        assert_eq!("
┏━━━┓
┣━┓ ┃
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Left);
        assert_eq!("
┏━━━┓
┣━╸ ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Up);
        assert_eq!("
┏━━━┓
┃   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Left);
        assert_eq!("
╺━━━┓
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Up);
        assert_eq!("
  ╺━┓
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Up);
        assert_eq!("
    ╻
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Right);
        assert_eq!("

╻   ╻
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Left);
        assert_eq!("

    ╻
╺━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Down);
        assert_eq!("

    ╻
  ╺━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Down);
        assert_eq!("

    ╻
    ╹
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Right);
        assert_eq!("

",      &labyrinth.to_string());

    }
}
<commit_msg>draw doesn't prepend printed labyrinth with a new line<commit_after>use std::io::{self, Write};
use super::super::direction::Direction::*;
use super::Wall;

impl Wall {
    /// Print a labyrinth to stdout using UNICODE BOX characters.
    pub fn print(&self) {
        let mut stdout = io::stdout();
        let mut writer = |s: &str| { stdout.write_all(s.as_bytes()).unwrap() };
        self.draw(&mut writer);
    }
    /// Draw a labyrinth as a String using UNICODE BOX characters.
    pub fn to_string(&self) -> String {
        let mut out = String::new();
        self.draw(&mut |s: &str| { out.push_str(s) });
        out
    }
    /// Draw a labyrinth using UNICODE BOX characters to a `writer`.
    pub fn draw(&self, writer: &mut FnMut(&str)) {
        for y in 0..self.rows {
            for x in 0..self.cols {
                if x == 0 || self.is_open(x - 1, y, Up) {
                    if y == 0 || self.is_open(x, y - 1, Left) {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "  " } else { "╻ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "╺━" } else { "┏━" });
                        }
                    } else {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "╹ " } else { "┃ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "┗━" } else { "┣━" });
                        }
                    }
                } else {
                    if y == 0 || self.is_open(x, y - 1, Left) {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "╸ " } else { "┓ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "━━" } else { "┳━" });
                        }
                    } else {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "┛ " } else { "┫ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "┻━" } else { "╋━" });
                        }
                    }
                }
            }
            let x = self.cols;
            if self.is_open(x - 1, y, Up) {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Left) { " " } else { "╻" });
                } else {
                    writer(if self.is_open(x, y, Left) { "╹" } else { "┃" });
                }
            } else {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Left) { "╸" } else { "┓" });
                } else {
                    writer(if self.is_open(x, y, Left) { "┛" } else { "┫" });
                }
            }
            writer("\n");
        }
        let y = self.rows;
        for x in 0..self.cols {
            if x == 0 || self.is_open(x - 1, y, Up) {
                if self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Up) { "  " } else { "╺━" });
                } else {
                    writer(if self.is_open(x, y, Up) { "╹ " } else { "┗━" });
                }
            } else {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Up) { "╸ " } else { "━━" });
                } else {
                    writer(if self.is_open(x, y, Up) { "┛ " } else { "┻━" });
                }
            }
        }
        let x = self.cols;
        if self.is_open(x - 1, y, Up) {
            writer(if self.is_open(x, y - 1, Left) { " " } else { "╹" });
        } else {
            writer(if self.is_open(x, y - 1, Left) { "╸" } else { "┛" });
        }
        writer("\n");
    }
}

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

    #[test]
    fn should_draw_a_labyrinth() {
        let mut labyrinth = Wall::new(2, 2);
        assert_eq!(
"┏━┳━┓
┣━╋━┫
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Right);
        assert_eq!(
"┏━━━┓
┣━┳━┫
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Down);
        assert_eq!(
"┏━━━┓
┣━┓ ┃
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Left);
        assert_eq!(
"┏━━━┓
┣━╸ ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Up);
        assert_eq!(
"┏━━━┓
┃   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Left);
        assert_eq!(
"╺━━━┓
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Up);
        assert_eq!(
"  ╺━┓
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Up);
        assert_eq!(
"    ╻
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Right);
        assert_eq!(
"
╻   ╻
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Left);
        assert_eq!(
"
    ╻
╺━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Down);
        assert_eq!(
"
    ╻
  ╺━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Down);
        assert_eq!(
"
    ╻
    ╹
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Right);
        assert_eq!(
"

",      &labyrinth.to_string());

    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Sandstorm Development Group, Inc.
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use gj::{Promise};
use capnp::Error;
use std::cell::Cell;
use std::rc::Rc;
use sandstorm::web_session_capnp::web_session::web_socket_stream;

pub enum Message {
  Text(String),
  Data(Vec<u8>),
}

pub trait MessageHandler {
    fn handle_message(&mut self, message: Message) -> Promise<(), Error>;
}

fn do_ping_pong(client_stream: web_socket_stream::Client,
                timer: ::gjio::Timer,
                awaiting_pong: Rc<Cell<bool>>) -> Promise<(), Error>
{
    let mut req = client_stream.send_bytes_request();
    req.get().set_message(&[0x89, 0]); // PING
    let promise = req.send().promise;
    awaiting_pong.set(true);
    promise.then(move|_| {
        timer.after_delay(::std::time::Duration::new(10, 0)).lift().then(move |_| {
            if awaiting_pong.get() {
                Promise::err(Error::failed("pong not received within 10 seconds".into()))
            } else {
                do_ping_pong(client_stream, timer, awaiting_pong)
            }
        })
    })
}

pub struct Adapter<T> where T: MessageHandler {
    handler: T,
    awaiting_pong: Rc<Cell<bool>>,
    _ping_pong_promise: Promise<(), Error>,
}

impl <T> Adapter<T> where T: MessageHandler {
    pub fn new(handler: T,
               client_stream: web_socket_stream::Client,
               timer: ::gjio::Timer)
               -> Adapter<T> {
        let awaiting = Rc::new(Cell::new(false));
        let ping_pong_promise = do_ping_pong(client_stream.clone(),
                                             timer,
                                             awaiting.clone()).map_else(|r| match r {
            Ok(_) => Ok(()),
            Err(e) => {println!("ERROR {}", e); Ok(())  }
        }).eagerly_evaluate();

        Adapter {
            handler: handler,
            awaiting_pong: awaiting,
            _ping_pong_promise: ping_pong_promise,
        }
    }
}

impl <T> web_socket_stream::Server for Adapter<T> where T: MessageHandler {
    fn send_bytes(&mut self,
                  params: web_socket_stream::SendBytesParams,
                  _results: web_socket_stream::SendBytesResults)
                  -> Promise<(), Error>
    {
        let message = pry!(pry!(params.get()).get_message());
        if message.len() < 2 {
            return Promise::err(Error::failed(format!("message must be larger than 2 bytes")))
        }

        let opcode = message[0] & 0xf;
        if message[0] & 0x80 == 0 {
            return Promise::err(Error::failed(format!("non-FIN messages are unsupported")))
        }

        let masked = (message[1] & 0x80) != 0;
        let mut payload_start = 2;
        if masked {
            payload_start += 4;
        }

        let payload_length: usize = match message[1] & 0x7f {
            126 => {
                if message.len() < 4 {
                    return Promise::err(
                        Error::failed(format!("message must be larger than 2 bytes")))
                }
                payload_start += 2;
                (((message[3] as u16) << 8) + message[4] as u16) as usize
            }
            127 => {
                payload_start += 8;
                (((message[3] as u64) << 56) +
                 ((message[4] as u64) << 48) +
                 ((message[5] as u64) << 32) +
                 ((message[6] as u64) << 24) +
                 ((message[7] as u64) << 16) +
                 ((message[8] as u64) << 8) +
                 ((message[9] as u64) << 0)
                ) as usize
            }
            n => n as usize,
        };

        //let mut payload: Vec<u8> = Vec::new();

        println!("length {}, payload_start {}", payload_length, payload_start);

        match opcode {
            0x0 => { // CONTINUE
            }
            0x1 => { // UTF-8 PAYLOAD
            }
            0x2 => { // BINARY PAYLOAD
            }
            0x8 => { // TERMINATE
                // TODO: drop things to get them to close.
            }
            0x9 => { // PING
                //TODO
                println!("the client sent us a ping!");
            }
            0xa => { // PONG
                self.awaiting_pong.set(false);
            }
            _ => { // OTHER
                println!("unrecognized websocket opcode {}", opcode);
            }
        }

        &self.handler; // TODO dispatch parsed message to handler
        Promise::ok(())
    }
}

<commit_msg>drop things on TERMINATE<commit_after>// Copyright (c) 2016 Sandstorm Development Group, Inc.
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use gj::{Promise};
use capnp::Error;
use std::cell::Cell;
use std::rc::Rc;
use sandstorm::web_session_capnp::web_session::web_socket_stream;

pub enum Message {
  Text(String),
  Data(Vec<u8>),
}

pub trait MessageHandler {
    fn handle_message(&mut self, message: Message) -> Promise<(), Error>;
}

fn do_ping_pong(client_stream: web_socket_stream::Client,
                timer: ::gjio::Timer,
                awaiting_pong: Rc<Cell<bool>>) -> Promise<(), Error>
{
    let mut req = client_stream.send_bytes_request();
    req.get().set_message(&[0x89, 0]); // PING
    let promise = req.send().promise;
    awaiting_pong.set(true);
    promise.then(move|_| {
        timer.after_delay(::std::time::Duration::new(10, 0)).lift().then(move |_| {
            if awaiting_pong.get() {
                Promise::err(Error::failed("pong not received within 10 seconds".into()))
            } else {
                do_ping_pong(client_stream, timer, awaiting_pong)
            }
        })
    })
}

pub struct Adapter<T> where T: MessageHandler {
    handler: Option<T>,
    awaiting_pong: Rc<Cell<bool>>,
    ping_pong_promise: Promise<(), Error>,
}

impl <T> Adapter<T> where T: MessageHandler {
    pub fn new(handler: T,
               client_stream: web_socket_stream::Client,
               timer: ::gjio::Timer)
               -> Adapter<T> {
        let awaiting = Rc::new(Cell::new(false));
        let ping_pong_promise = do_ping_pong(client_stream.clone(),
                                             timer,
                                             awaiting.clone()).map_else(|r| match r {
            Ok(_) => Ok(()),
            Err(e) => {println!("ERROR {}", e); Ok(())  }
        }).eagerly_evaluate();

        Adapter {
            handler: Some(handler),
            awaiting_pong: awaiting,
            ping_pong_promise: ping_pong_promise,
        }
    }
}

impl <T> web_socket_stream::Server for Adapter<T> where T: MessageHandler {
    fn send_bytes(&mut self,
                  params: web_socket_stream::SendBytesParams,
                  _results: web_socket_stream::SendBytesResults)
                  -> Promise<(), Error>
    {
        let message = pry!(pry!(params.get()).get_message());
        if message.len() < 2 {
            return Promise::err(Error::failed(format!("message must be larger than 2 bytes")))
        }

        let opcode = message[0] & 0xf;
        if message[0] & 0x80 == 0 {
            return Promise::err(Error::failed(format!("non-FIN messages are unsupported")))
        }

        let masked = (message[1] & 0x80) != 0;
        let mut payload_start = 2;
        if masked {
            payload_start += 4;
        }

        let payload_length: usize = match message[1] & 0x7f {
            126 => {
                if message.len() < 4 {
                    return Promise::err(
                        Error::failed(format!("message must be larger than 2 bytes")))
                }
                payload_start += 2;
                (((message[3] as u16) << 8) + message[4] as u16) as usize
            }
            127 => {
                payload_start += 8;
                (((message[3] as u64) << 56) +
                 ((message[4] as u64) << 48) +
                 ((message[5] as u64) << 32) +
                 ((message[6] as u64) << 24) +
                 ((message[7] as u64) << 16) +
                 ((message[8] as u64) << 8) +
                 ((message[9] as u64) << 0)
                ) as usize
            }
            n => n as usize,
        };

        //let mut payload: Vec<u8> = Vec::new();

        println!("length {}, payload_start {}", payload_length, payload_start);

        match opcode {
            0x0 => { // CONTINUE
            }
            0x1 => { // UTF-8 PAYLOAD
            }
            0x2 => { // BINARY PAYLOAD
            }
            0x8 => { // TERMINATE
                self.handler = None;
                self.ping_pong_promise = Promise::ok(())
            }
            0x9 => { // PING
                //TODO
                println!("the client sent us a ping!");
            }
            0xa => { // PONG
                self.awaiting_pong.set(false);
            }
            _ => { // OTHER
                println!("unrecognized websocket opcode {}", opcode);
            }
        }

        &self.handler; // TODO dispatch parsed message to handler
        Promise::ok(())
    }
}

<|endoftext|>