<commit_before>use std::f32;
use std::f64;

use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::MessageDescriptor;
use protobuf::reflect::ReflectValueBox;
use protobuf::reflect::RuntimeFieldType;
use protobuf::reflect::RuntimeTypeBox;
use protobuf::reflect::RuntimeTypeDynamic;
use protobuf::well_known_types::Value;
use protobuf::well_known_types::Value_oneof_kind;
use protobuf::Message;

pub fn value_for_runtime_type(field_type: &RuntimeTypeDynamic) -> ReflectValueBox {
    match field_type.to_box() {
        RuntimeTypeBox::U32 => ReflectValueBox::U32(11),
        RuntimeTypeBox::U64 => ReflectValueBox::U64(12),
        RuntimeTypeBox::I32 => ReflectValueBox::I32(13),
        RuntimeTypeBox::I64 => ReflectValueBox::I64(14),
        RuntimeTypeBox::F32 => ReflectValueBox::F32(15.5),
        RuntimeTypeBox::F64 => ReflectValueBox::F64(16.5),
        RuntimeTypeBox::Bool => ReflectValueBox::Bool(true),
        RuntimeTypeBox::String | RuntimeTypeBox::Chars => {
            ReflectValueBox::String("here".to_owned())
        }
        RuntimeTypeBox::VecU8 | RuntimeTypeBox::CarllercheBytes => {
            ReflectValueBox::Bytes(b"there".as_ref().to_owned())
        }
        RuntimeTypeBox::Enum(e) => ReflectValueBox::Enum(&e.values()[0]),
        RuntimeTypeBox::Message(m) => ReflectValueBox::Message(m.new_instance()),
    }
}

fn values_for_message_type(descriptor: &MessageDescriptor) -> Vec<Box<Message>> {
    if descriptor == Value::descriptor_static() {
        // special handling because empty `Value` is not valid
        let mut value = Value::new();
        value.kind = Some(Value_oneof_kind::number_value(23.0));
        vec![Box::new(value)]
    } else {
        vec![
            // TODO: populated messages
            descriptor.new_instance(),
        ]
    }
}

pub fn values_for_runtime_type(field_type: &RuntimeTypeDynamic) -> Vec<ReflectValueBox> {
    match field_type.to_box() {
        RuntimeTypeBox::U32 => vec![
            ReflectValueBox::U32(11),
            ReflectValueBox::U32(0),
            ReflectValueBox::U32(0x7fff_ffff),
            ReflectValueBox::U32(0x8000_0000),
            ReflectValueBox::U32(0xffff_ffff),
        ],
        RuntimeTypeBox::U64 => vec![
            ReflectValueBox::U64(12),
            ReflectValueBox::U64(0),
            ReflectValueBox::U64(0xffff_ffff),
            ReflectValueBox::U64(0xffff_ffff_ffff_ffff),
        ],
        RuntimeTypeBox::I32 => vec![
            ReflectValueBox::I32(13),
            ReflectValueBox::I32(0),
            ReflectValueBox::I32(-1),
            ReflectValueBox::I32(0x7fff_ffff),
            ReflectValueBox::I32(0x1000_0000),
        ],
        RuntimeTypeBox::I64 => vec![
            ReflectValueBox::I64(14),
            ReflectValueBox::I64(0),
            ReflectValueBox::I64(-1),
            ReflectValueBox::I64(0x7fff_ffff_ffff_ffff),
            ReflectValueBox::I64(0x1000_0000_0000_0000),
        ],
        RuntimeTypeBox::F32 => vec![
            ReflectValueBox::F32(15.5),
            ReflectValueBox::F32(0.0),
            ReflectValueBox::F32(-0.0),
            ReflectValueBox::F32(1. / 3.0),
            ReflectValueBox::F32(-1. / 3.0),
            ReflectValueBox::F32(f32::NAN),
            ReflectValueBox::F32(f32::INFINITY),
            ReflectValueBox::F32(-f32::INFINITY),
        ],
        RuntimeTypeBox::F64 => vec![
            ReflectValueBox::F64(16.5),
            ReflectValueBox::F64(0.0),
            ReflectValueBox::F64(-0.0),
            ReflectValueBox::F64(1.0 / 3.0),
            ReflectValueBox::F64(-1.0 / 3.0),
            ReflectValueBox::F64(f64::NAN),
            ReflectValueBox::F64(f64::INFINITY),
            ReflectValueBox::F64(-f64::INFINITY),
        ],
        RuntimeTypeBox::Bool => vec![ReflectValueBox::Bool(true), ReflectValueBox::Bool(false)],
        RuntimeTypeBox::String | RuntimeTypeBox::Chars => vec![
            ReflectValueBox::String("here".to_owned()),
            ReflectValueBox::String("".to_owned()),
            ReflectValueBox::String(" \t\n".to_owned()),
            ReflectValueBox::String("\0".to_owned()),
        ],
        RuntimeTypeBox::VecU8 | RuntimeTypeBox::CarllercheBytes => vec![
            ReflectValueBox::Bytes(b"there".as_ref().to_owned()),
            ReflectValueBox::Bytes(b"".as_ref().to_owned()),
        ],
        RuntimeTypeBox::Enum(e) => vec![
            ReflectValueBox::Enum(&e.values()[0]),
            ReflectValueBox::Enum(&e.values()[e.values().len() - 1]),
        ],
        RuntimeTypeBox::Message(m) => values_for_message_type(m)
            .into_iter()
            .map(ReflectValueBox::from)
            .collect(),
    }
}

pub fn special_values_for_field(f: &FieldDescriptor, d: &MessageDescriptor) -> Vec<Box<Message>> {
    let mut r = Vec::new();
    match f.runtime_field_type() {
        RuntimeFieldType::Singular(t) => {
            for v in values_for_runtime_type(t) {
                let mut m = d.new_instance();
                f.set_singular_field(&mut *m, v);
                r.push(m);
            }
        }
        RuntimeFieldType::Repeated(t) => {
            // TODO: empty repeated
            // TODO: repeated of more than one element
            let mut m = d.new_instance();
            f.mut_repeated(&mut *m).push(value_for_runtime_type(t));
            r.push(m);
        }
        RuntimeFieldType::Map(k, v) => {
            // TODO: empty map
            // TODO: map of more than one element
            let mut m = d.new_instance();
            let k = value_for_runtime_type(k);
            let v = value_for_runtime_type(v);
            f.mut_map(&mut *m).insert(k, v);
            r.push(m);
        }
    }
    r
}

pub fn special_messages(d: &MessageDescriptor) -> Vec<Box<Message>> {
    let mut r = Vec::new();
    for f in d.fields() {
        r.extend(special_values_for_field(f, d));
    }
    r
}

pub fn special_messages_typed<M: Message>() -> Vec<M> {
    let mut r = Vec::new();
    for m in special_messages(M::descriptor_static()) {
        r.push(*m.downcast_box().unwrap());
    }
    r
}
<commit_msg>Fix test compilation<commit_after>use std::f32;
use std::f64;

use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::MessageDescriptor;
use protobuf::reflect::ReflectValueBox;
use protobuf::reflect::RuntimeFieldType;
use protobuf::reflect::RuntimeTypeBox;
use protobuf::reflect::RuntimeTypeDynamic;
use protobuf::well_known_types::Value;
use protobuf::well_known_types::value;
use protobuf::Message;

pub fn value_for_runtime_type(field_type: &RuntimeTypeDynamic) -> ReflectValueBox {
    match field_type.to_box() {
        RuntimeTypeBox::U32 => ReflectValueBox::U32(11),
        RuntimeTypeBox::U64 => ReflectValueBox::U64(12),
        RuntimeTypeBox::I32 => ReflectValueBox::I32(13),
        RuntimeTypeBox::I64 => ReflectValueBox::I64(14),
        RuntimeTypeBox::F32 => ReflectValueBox::F32(15.5),
        RuntimeTypeBox::F64 => ReflectValueBox::F64(16.5),
        RuntimeTypeBox::Bool => ReflectValueBox::Bool(true),
        RuntimeTypeBox::String | RuntimeTypeBox::Chars => {
            ReflectValueBox::String("here".to_owned())
        }
        RuntimeTypeBox::VecU8 | RuntimeTypeBox::CarllercheBytes => {
            ReflectValueBox::Bytes(b"there".as_ref().to_owned())
        }
        RuntimeTypeBox::Enum(e) => ReflectValueBox::Enum(&e.values()[0]),
        RuntimeTypeBox::Message(m) => ReflectValueBox::Message(m.new_instance()),
    }
}

fn values_for_message_type(descriptor: &MessageDescriptor) -> Vec<Box<Message>> {
    if descriptor == Value::descriptor_static() {
        // special handling because empty `Value` is not valid
        let mut value = Value::new();
        value.kind = Some(value::Kind::number_value(23.0));
        vec![Box::new(value)]
    } else {
        vec![
            // TODO: populated messages
            descriptor.new_instance(),
        ]
    }
}

pub fn values_for_runtime_type(field_type: &RuntimeTypeDynamic) -> Vec<ReflectValueBox> {
    match field_type.to_box() {
        RuntimeTypeBox::U32 => vec![
            ReflectValueBox::U32(11),
            ReflectValueBox::U32(0),
            ReflectValueBox::U32(0x7fff_ffff),
            ReflectValueBox::U32(0x8000_0000),
            ReflectValueBox::U32(0xffff_ffff),
        ],
        RuntimeTypeBox::U64 => vec![
            ReflectValueBox::U64(12),
            ReflectValueBox::U64(0),
            ReflectValueBox::U64(0xffff_ffff),
            ReflectValueBox::U64(0xffff_ffff_ffff_ffff),
        ],
        RuntimeTypeBox::I32 => vec![
            ReflectValueBox::I32(13),
            ReflectValueBox::I32(0),
            ReflectValueBox::I32(-1),
            ReflectValueBox::I32(0x7fff_ffff),
            ReflectValueBox::I32(0x1000_0000),
        ],
        RuntimeTypeBox::I64 => vec![
            ReflectValueBox::I64(14),
            ReflectValueBox::I64(0),
            ReflectValueBox::I64(-1),
            ReflectValueBox::I64(0x7fff_ffff_ffff_ffff),
            ReflectValueBox::I64(0x1000_0000_0000_0000),
        ],
        RuntimeTypeBox::F32 => vec![
            ReflectValueBox::F32(15.5),
            ReflectValueBox::F32(0.0),
            ReflectValueBox::F32(-0.0),
            ReflectValueBox::F32(1. / 3.0),
            ReflectValueBox::F32(-1. / 3.0),
            ReflectValueBox::F32(f32::NAN),
            ReflectValueBox::F32(f32::INFINITY),
            ReflectValueBox::F32(-f32::INFINITY),
        ],
        RuntimeTypeBox::F64 => vec![
            ReflectValueBox::F64(16.5),
            ReflectValueBox::F64(0.0),
            ReflectValueBox::F64(-0.0),
            ReflectValueBox::F64(1.0 / 3.0),
            ReflectValueBox::F64(-1.0 / 3.0),
            ReflectValueBox::F64(f64::NAN),
            ReflectValueBox::F64(f64::INFINITY),
            ReflectValueBox::F64(-f64::INFINITY),
        ],
        RuntimeTypeBox::Bool => vec![ReflectValueBox::Bool(true), ReflectValueBox::Bool(false)],
        RuntimeTypeBox::String | RuntimeTypeBox::Chars => vec![
            ReflectValueBox::String("here".to_owned()),
            ReflectValueBox::String("".to_owned()),
            ReflectValueBox::String(" \t\n".to_owned()),
            ReflectValueBox::String("\0".to_owned()),
        ],
        RuntimeTypeBox::VecU8 | RuntimeTypeBox::CarllercheBytes => vec![
            ReflectValueBox::Bytes(b"there".as_ref().to_owned()),
            ReflectValueBox::Bytes(b"".as_ref().to_owned()),
        ],
        RuntimeTypeBox::Enum(e) => vec![
            ReflectValueBox::Enum(&e.values()[0]),
            ReflectValueBox::Enum(&e.values()[e.values().len() - 1]),
        ],
        RuntimeTypeBox::Message(m) => values_for_message_type(m)
            .into_iter()
            .map(ReflectValueBox::from)
            .collect(),
    }
}

pub fn special_values_for_field(f: &FieldDescriptor, d: &MessageDescriptor) -> Vec<Box<Message>> {
    let mut r = Vec::new();
    match f.runtime_field_type() {
        RuntimeFieldType::Singular(t) => {
            for v in values_for_runtime_type(t) {
                let mut m = d.new_instance();
                f.set_singular_field(&mut *m, v);
                r.push(m);
            }
        }
        RuntimeFieldType::Repeated(t) => {
            // TODO: empty repeated
            // TODO: repeated of more than one element
            let mut m = d.new_instance();
            f.mut_repeated(&mut *m).push(value_for_runtime_type(t));
            r.push(m);
        }
        RuntimeFieldType::Map(k, v) => {
            // TODO: empty map
            // TODO: map of more than one element
            let mut m = d.new_instance();
            let k = value_for_runtime_type(k);
            let v = value_for_runtime_type(v);
            f.mut_map(&mut *m).insert(k, v);
            r.push(m);
        }
    }
    r
}

pub fn special_messages(d: &MessageDescriptor) -> Vec<Box<Message>> {
    let mut r = Vec::new();
    for f in d.fields() {
        r.extend(special_values_for_field(f, d));
    }
    r
}

pub fn special_messages_typed<M: Message>() -> Vec<M> {
    let mut r = Vec::new();
    for m in special_messages(M::descriptor_static()) {
        r.push(*m.downcast_box().unwrap());
    }
    r
}
<|endoftext|>


<commit_before>#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;

use std::collections::BTreeMap;
use serde::json::{self, Value};

macro_rules! btreemap {
    () => {
        BTreeMap::new()
    };
    ($($key:expr => $value:expr),+) => {
        {
            let mut map = BTreeMap::new();
            $(map.insert($key, $value);)+
            map
        }
    }
}

/*
trait Trait {
    type Type;
}
*/

#[derive(Debug, PartialEq)]
#[derive_serialize]
#[derive_deserialize]
struct NamedUnit;

#[derive(Debug, PartialEq)]
#[derive_serialize]
enum SerEnum<'a, B: 'a, C: /* Trait + */ 'a, D> where D: /* Trait + */ 'a {
    Unit,
    Seq(
        i8,
        B,
        &'a C,
        //C::Type,
        &'a mut D,
        //<D as Trait>::Type,
    ),
    Map {
        a: i8,
        b: B,
        c: &'a C,
        //d: C::Type,
        e: &'a mut D,
        //f: <D as Trait>::Type,
    },
}

#[derive(Debug, PartialEq)]
#[derive_deserialize]
enum DeEnum<B, C: /* Trait */, D> /* where D: Trait */ {
    Unit,
    Seq(
        i8,
        B,
        C,
        //C::Type,
        D,
        //<D as Trait>::Type,
    ),
    Map {
        a: i8,
        b: B,
        c: C,
        //d: C::Type,
        e: D,
        //f: <D as Trait>::Type,
    },
}

#[test]
fn test_named_unit() {
    let named_unit = NamedUnit;

    assert_eq!(
        json::to_string(&named_unit).unwrap(),
        "null".to_string()
    );

    assert_eq!(
        json::to_value(&named_unit),
        Value::Null
    );

    let v = json::from_str("null").unwrap();
    assert_eq!(v, named_unit);

    let v = json::from_value(Value::Null).unwrap();
    assert_eq!(v, named_unit);
}

#[test]
fn test_ser_named_tuple() {
    #[derive(Debug, PartialEq)]
    #[derive_serialize]
    struct NamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);

    let a = 5;
    let mut b = 6;
    let c = 7;
    let named_tuple = NamedTuple(&a, &mut b, c);

    assert_eq!(
        json::to_string(&named_tuple).unwrap(),
        "[5,6,7]"
    );

    assert_eq!(
        json::to_value(&named_tuple),
        Value::Array(vec![Value::I64(5), Value::I64(6), Value::I64(7)])
    );
}

#[test]
fn test_de_named_tuple() {
    #[derive(Debug, PartialEq)]
    #[derive_deserialize]
    struct NamedTuple<A, B, C>(A, B, C);

    assert_eq!(
        json::from_str("[1,2,3]").unwrap(),
        NamedTuple(1, 2, 3)
    );

    assert_eq!(
        json::from_str("[1,2,3]").unwrap(),
        Value::Array(vec![
            Value::I64(1),
            Value::I64(2),
            Value::I64(3),
        ])
    );
}

#[test]
fn test_ser_named_map() {
    #[derive(Debug, PartialEq)]
    #[derive_serialize]
    struct NamedMap<'a, 'b, A: 'a, B: 'b, C> {
        a: &'a A,
        b: &'b mut B,
        c: C,
    }

    let a = 5;
    let mut b = 6;
    let c = 7;
    let named_map = NamedMap {
        a: &a,
        b: &mut b,
        c: c,
    };

    assert_eq!(
        json::to_string(&named_map).unwrap(),
        "{\"a\":5,\"b\":6,\"c\":7}"
    );

    assert_eq!(
        json::to_value(&named_map),
        Value::Object(btreemap![
            "a".to_string() => Value::I64(5),
            "b".to_string() => Value::I64(6),
            "c".to_string() => Value::I64(7)
        ])
    );
}

#[test]
fn test_de_named_map() {
    #[derive(Debug, PartialEq)]
    #[derive_deserialize]
    struct NamedMap<A, B, C> {
        a: A,
        b: B,
        c: C,
    }

    let v = NamedMap {
        a: 5,
        b: 6,
        c: 7,
    };

    assert_eq!(
        json::from_str("{\"a\":5,\"b\":6,\"c\":7}").unwrap(),
        v
    );

    assert_eq!(
        json::from_value(Value::Object(btreemap![
            "a".to_string() => Value::I64(5),
            "b".to_string() => Value::I64(6),
            "c".to_string() => Value::I64(7)
        ])).unwrap(),
        v
    );
}

#[test]
fn test_ser_enum_unit() {
    assert_eq!(
        json::to_string(&SerEnum::Unit::<u32, u32, u32>).unwrap(),
        "{\"Unit\":[]}"
    );

    assert_eq!(
        json::to_value(&SerEnum::Unit::<u32, u32, u32>),
        Value::Object(btreemap!(
            "Unit".to_string() => Value::Array(vec![]))
        )
    );
}

#[test]
fn test_ser_enum_seq() {
    let a = 1;
    let b = 2;
    let c = 3;
    //let d = 4;
    let mut e = 5;
    //let f = 6;

    assert_eq!(
        json::to_string(&SerEnum::Seq(
            a,
            b,
            &c,
            //d,
            &mut e,
            //f,
        )).unwrap(),
        "{\"Seq\":[1,2,3,5]}".to_string()
    );

    assert_eq!(
        json::to_value(&SerEnum::Seq(
            a,
            b,
            &c,
            //d,
            &mut e,
            //e,
        )),
        Value::Object(btreemap!(
            "Seq".to_string() => Value::Array(vec![
                Value::I64(1),
                Value::I64(2),
                Value::I64(3),
                //Value::I64(4),
                Value::I64(5),
                //Value::I64(6),
            ])
        ))
    );
}

#[test]
fn test_ser_enum_map() {
    let a = 1;
    let b = 2;
    let c = 3;
    //let d = 4;
    let mut e = 5;
    //let f = 6;

    assert_eq!(
        json::to_string(&SerEnum::Map {
            a: a,
            b: b,
            c: &c,
            //d: d,
            e: &mut e,
            //f: f,
        }).unwrap(),
        "{\"Map\":{\"a\":1,\"b\":2,\"c\":3,\"e\":5}}".to_string()
    );

    assert_eq!(
        json::to_value(&SerEnum::Map {
            a: a,
            b: b,
            c: &c,
            //d: d,
            e: &mut e,
            //f: f,
        }),
        Value::Object(btreemap!(
            "Map".to_string() => Value::Object(btreemap![
                "a".to_string() => Value::I64(1),
                "b".to_string() => Value::I64(2),
                "c".to_string() => Value::I64(3),
                //"d".to_string() => Value::I64(4)
                "e".to_string() => Value::I64(5)
                //"f".to_string() => Value::I64(6)
            ])
        ))
    );
}

#[test]
fn test_de_enum_unit() {
    assert_eq!(
        json::from_str("{\"Unit\":[]}").unwrap(),
        DeEnum::Unit::<u32, u32, u32>
    );

    assert_eq!(
        json::from_value(Value::Object(btreemap!(
            "Unit".to_string() => Value::Array(vec![]))
        )).unwrap(),
        DeEnum::Unit::<u32, u32, u32>
    );
}

#[test]
fn test_de_enum_seq() {
    let a = 1;
    let b = 2;
    let c = 3;
    //let d = 4;
    let e = 5;
    //let f = 6;

    assert_eq!(
        json::from_str("{\"Seq\":[1,2,3,5]}").unwrap(),
        DeEnum::Seq(
            a,
            b,
            c,
            //d,
            e,
            //f,
        )
    );

    assert_eq!(
        json::from_value(Value::Object(btreemap!(
            "Seq".to_string() => Value::Array(vec![
                Value::I64(1),
                Value::I64(2),
                Value::I64(3),
                //Value::I64(4),
                Value::I64(5),
                //Value::I64(6),
            ])
        ))).unwrap(),
        DeEnum::Seq(
            a,
            b,
            c,
            //d,
            e,
            //e,
        )
    );
}

#[test]
fn test_de_enum_map() {
    let a = 1;
    let b = 2;
    let c = 3;
    //let d = 4;
    let e = 5;
    //let f = 6;

    assert_eq!(
        json::from_str("{\"Map\":{\"a\":1,\"b\":2,\"c\":3,\"e\":5}}").unwrap(),
        DeEnum::Map {
            a: a,
            b: b,
            c: c,
            //d: d,
            e: e,
            //f: f,
        }
    );

    assert_eq!(
        json::from_value(Value::Object(btreemap!(
            "Map".to_string() => Value::Object(btreemap![
                "a".to_string() => Value::I64(1),
                "b".to_string() => Value::I64(2),
                "c".to_string() => Value::I64(3),
                //"d".to_string() => Value::I64(4)
                "e".to_string() => Value::I64(5)
                //"f".to_string() => Value::I64(6)
            ])
        ))).unwrap(),
        DeEnum::Map {
            a: a,
            b: b,
            c: c,
            //d: d,
            e: e,
            //f: f,
        }
    );
}
<commit_msg>Fix multiple unnamed enum seq/map variants<commit_after>#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;

use std::collections::BTreeMap;
use serde::json::{self, Value};

macro_rules! btreemap {
    () => {
        BTreeMap::new()
    };
    ($($key:expr => $value:expr),+) => {
        {
            let mut map = BTreeMap::new();
            $(map.insert($key, $value);)+
            map
        }
    }
}

/*
trait Trait {
    type Type;
}
*/

#[derive(Debug, PartialEq)]
#[derive_serialize]
#[derive_deserialize]
struct NamedUnit;

#[derive(Debug, PartialEq)]
#[derive_serialize]
enum SerEnum<'a, B: 'a, C: /* Trait + */ 'a, D> where D: /* Trait + */ 'a {
    Unit,
    Seq(
        i8,
        B,
        &'a C,
        //C::Type,
        &'a mut D,
        //<D as Trait>::Type,
    ),
    Map {
        a: i8,
        b: B,
        c: &'a C,
        //d: C::Type,
        e: &'a mut D,
        //f: <D as Trait>::Type,
    },

    // Make sure we can support more than one variant.
    _Unit2,
    _Seq2(
        i8,
        B,
        &'a C,
        //C::Type,
        &'a mut D,
        //<D as Trait>::Type,
    ),
    _Map2 {
        a: i8,
        b: B,
        c: &'a C,
        //d: C::Type,
        e: &'a mut D,
        //f: <D as Trait>::Type,
    },
}

#[derive(Debug, PartialEq)]
#[derive_deserialize]
enum DeEnum<B, C: /* Trait */, D> /* where D: Trait */ {
    Unit,
    Seq(
        i8,
        B,
        C,
        //C::Type,
        D,
        //<D as Trait>::Type,
    ),
    Map {
        a: i8,
        b: B,
        c: C,
        //d: C::Type,
        e: D,
        //f: <D as Trait>::Type,
    },

    // Make sure we can support more than one variant.
    _Unit2,
    _Seq2(
        i8,
        B,
        C,
        //C::Type,
        D,
        //<D as Trait>::Type,
    ),
    _Map2 {
        a: i8,
        b: B,
        c: C,
        //d: C::Type,
        e: D,
        //f: <D as Trait>::Type,
    },
}

#[test]
fn test_named_unit() {
    let named_unit = NamedUnit;

    assert_eq!(
        json::to_string(&named_unit).unwrap(),
        "null".to_string()
    );

    assert_eq!(
        json::to_value(&named_unit),
        Value::Null
    );

    let v = json::from_str("null").unwrap();
    assert_eq!(v, named_unit);

    let v = json::from_value(Value::Null).unwrap();
    assert_eq!(v, named_unit);
}

#[test]
fn test_ser_named_tuple() {
    #[derive(Debug, PartialEq)]
    #[derive_serialize]
    struct NamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);

    let a = 5;
    let mut b = 6;
    let c = 7;
    let named_tuple = NamedTuple(&a, &mut b, c);

    assert_eq!(
        json::to_string(&named_tuple).unwrap(),
        "[5,6,7]"
    );

    assert_eq!(
        json::to_value(&named_tuple),
        Value::Array(vec![Value::I64(5), Value::I64(6), Value::I64(7)])
    );
}

#[test]
fn test_de_named_tuple() {
    #[derive(Debug, PartialEq)]
    #[derive_deserialize]
    struct NamedTuple<A, B, C>(A, B, C);

    assert_eq!(
        json::from_str("[1,2,3]").unwrap(),
        NamedTuple(1, 2, 3)
    );

    assert_eq!(
        json::from_str("[1,2,3]").unwrap(),
        Value::Array(vec![
            Value::I64(1),
            Value::I64(2),
            Value::I64(3),
        ])
    );
}

#[test]
fn test_ser_named_map() {
    #[derive(Debug, PartialEq)]
    #[derive_serialize]
    struct NamedMap<'a, 'b, A: 'a, B: 'b, C> {
        a: &'a A,
        b: &'b mut B,
        c: C,
    }

    let a = 5;
    let mut b = 6;
    let c = 7;
    let named_map = NamedMap {
        a: &a,
        b: &mut b,
        c: c,
    };

    assert_eq!(
        json::to_string(&named_map).unwrap(),
        "{\"a\":5,\"b\":6,\"c\":7}"
    );

    assert_eq!(
        json::to_value(&named_map),
        Value::Object(btreemap![
            "a".to_string() => Value::I64(5),
            "b".to_string() => Value::I64(6),
            "c".to_string() => Value::I64(7)
        ])
    );
}

#[test]
fn test_de_named_map() {
    #[derive(Debug, PartialEq)]
    #[derive_deserialize]
    struct NamedMap<A, B, C> {
        a: A,
        b: B,
        c: C,
    }

    let v = NamedMap {
        a: 5,
        b: 6,
        c: 7,
    };

    assert_eq!(
        json::from_str("{\"a\":5,\"b\":6,\"c\":7}").unwrap(),
        v
    );

    assert_eq!(
        json::from_value(Value::Object(btreemap![
            "a".to_string() => Value::I64(5),
            "b".to_string() => Value::I64(6),
            "c".to_string() => Value::I64(7)
        ])).unwrap(),
        v
    );
}

#[test]
fn test_ser_enum_unit() {
    assert_eq!(
        json::to_string(&SerEnum::Unit::<u32, u32, u32>).unwrap(),
        "{\"Unit\":[]}"
    );

    assert_eq!(
        json::to_value(&SerEnum::Unit::<u32, u32, u32>),
        Value::Object(btreemap!(
            "Unit".to_string() => Value::Array(vec![]))
        )
    );
}

#[test]
fn test_ser_enum_seq() {
    let a = 1;
    let b = 2;
    let c = 3;
    //let d = 4;
    let mut e = 5;
    //let f = 6;

    assert_eq!(
        json::to_string(&SerEnum::Seq(
            a,
            b,
            &c,
            //d,
            &mut e,
            //f,
        )).unwrap(),
        "{\"Seq\":[1,2,3,5]}".to_string()
    );

    assert_eq!(
        json::to_value(&SerEnum::Seq(
            a,
            b,
            &c,
            //d,
            &mut e,
            //e,
        )),
        Value::Object(btreemap!(
            "Seq".to_string() => Value::Array(vec![
                Value::I64(1),
                Value::I64(2),
                Value::I64(3),
                //Value::I64(4),
                Value::I64(5),
                //Value::I64(6),
            ])
        ))
    );
}

#[test]
fn test_ser_enum_map() {
    let a = 1;
    let b = 2;
    let c = 3;
    //let d = 4;
    let mut e = 5;
    //let f = 6;

    assert_eq!(
        json::to_string(&SerEnum::Map {
            a: a,
            b: b,
            c: &c,
            //d: d,
            e: &mut e,
            //f: f,
        }).unwrap(),
        "{\"Map\":{\"a\":1,\"b\":2,\"c\":3,\"e\":5}}".to_string()
    );

    assert_eq!(
        json::to_value(&SerEnum::Map {
            a: a,
            b: b,
            c: &c,
            //d: d,
            e: &mut e,
            //f: f,
        }),
        Value::Object(btreemap!(
            "Map".to_string() => Value::Object(btreemap![
                "a".to_string() => Value::I64(1),
                "b".to_string() => Value::I64(2),
                "c".to_string() => Value::I64(3),
                //"d".to_string() => Value::I64(4)
                "e".to_string() => Value::I64(5)
                //"f".to_string() => Value::I64(6)
            ])
        ))
    );
}

#[test]
fn test_de_enum_unit() {
    assert_eq!(
        json::from_str("{\"Unit\":[]}").unwrap(),
        DeEnum::Unit::<u32, u32, u32>
    );

    assert_eq!(
        json::from_value(Value::Object(btreemap!(
            "Unit".to_string() => Value::Array(vec![]))
        )).unwrap(),
        DeEnum::Unit::<u32, u32, u32>
    );
}

#[test]
fn test_de_enum_seq() {
    let a = 1;
    let b = 2;
    let c = 3;
    //let d = 4;
    let e = 5;
    //let f = 6;

    assert_eq!(
        json::from_str("{\"Seq\":[1,2,3,5]}").unwrap(),
        DeEnum::Seq(
            a,
            b,
            c,
            //d,
            e,
            //f,
        )
    );

    assert_eq!(
        json::from_value(Value::Object(btreemap!(
            "Seq".to_string() => Value::Array(vec![
                Value::I64(1),
                Value::I64(2),
                Value::I64(3),
                //Value::I64(4),
                Value::I64(5),
                //Value::I64(6),
            ])
        ))).unwrap(),
        DeEnum::Seq(
            a,
            b,
            c,
            //d,
            e,
            //e,
        )
    );
}

#[test]
fn test_de_enum_map() {
    let a = 1;
    let b = 2;
    let c = 3;
    //let d = 4;
    let e = 5;
    //let f = 6;

    assert_eq!(
        json::from_str("{\"Map\":{\"a\":1,\"b\":2,\"c\":3,\"e\":5}}").unwrap(),
        DeEnum::Map {
            a: a,
            b: b,
            c: c,
            //d: d,
            e: e,
            //f: f,
        }
    );

    assert_eq!(
        json::from_value(Value::Object(btreemap!(
            "Map".to_string() => Value::Object(btreemap![
                "a".to_string() => Value::I64(1),
                "b".to_string() => Value::I64(2),
                "c".to_string() => Value::I64(3),
                //"d".to_string() => Value::I64(4)
                "e".to_string() => Value::I64(5)
                //"f".to_string() => Value::I64(6)
            ])
        ))).unwrap(),
        DeEnum::Map {
            a: a,
            b: b,
            c: c,
            //d: d,
            e: e,
            //f: f,
        }
    );
}
<|endoftext|>


<commit_before>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use libc::{c_void, size_t};
use std::mem;
use std::ptr;

#[repr(C)]
struct __CGColorSpace;

pub type CGColorSpaceRef = *const __CGColorSpace;

pub struct CGColorSpace {
    obj: CGColorSpaceRef,
}

impl Drop for CGColorSpace {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl Clone for CGColorSpace {
    fn clone(&self) -> CGColorSpace {
        unsafe {
            TCFType::wrap_under_get_rule(self.as_concrete_TypeRef())
        }
    }
}

impl TCFType<CGColorSpaceRef> for CGColorSpace {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGColorSpaceRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGColorSpaceRef) -> CGColorSpace {
        let reference: CGColorSpaceRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGColorSpaceRef) -> CGColorSpace {
        CGColorSpace {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CGColorSpaceGetTypeID()
        }
    }
}

impl CGColorSpace {
    pub fn create_device_rgb() -> CGColorSpace {
        unsafe {
            let result = CGColorSpaceCreateDeviceRGB();
            TCFType::wrap_under_create_rule(result)
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    fn CGColorSpaceCreateDeviceRGB() -> CGColorSpaceRef;
    fn CGColorSpaceGetTypeID() -> CFTypeID;
}

<commit_msg>Remove some unused imports<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use std::mem;

#[repr(C)]
struct __CGColorSpace;

pub type CGColorSpaceRef = *const __CGColorSpace;

pub struct CGColorSpace {
    obj: CGColorSpaceRef,
}

impl Drop for CGColorSpace {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl Clone for CGColorSpace {
    fn clone(&self) -> CGColorSpace {
        unsafe {
            TCFType::wrap_under_get_rule(self.as_concrete_TypeRef())
        }
    }
}

impl TCFType<CGColorSpaceRef> for CGColorSpace {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGColorSpaceRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGColorSpaceRef) -> CGColorSpace {
        let reference: CGColorSpaceRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGColorSpaceRef) -> CGColorSpace {
        CGColorSpace {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CGColorSpaceGetTypeID()
        }
    }
}

impl CGColorSpace {
    pub fn create_device_rgb() -> CGColorSpace {
        unsafe {
            let result = CGColorSpaceCreateDeviceRGB();
            TCFType::wrap_under_create_rule(result)
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    fn CGColorSpaceCreateDeviceRGB() -> CGColorSpaceRef;
    fn CGColorSpaceGetTypeID() -> CFTypeID;
}

<|endoftext|>


<commit_before>// Copyright © 2018 Cormac O'Brien
//
// 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 std::ops::Neg;

use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Zero;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum HyperplaneSide {
    Positive = 0,
    Negative = 1,
}

impl Neg for HyperplaneSide {
    type Output = HyperplaneSide;

    fn neg(self) -> Self::Output {
        match self {
            HyperplaneSide::Positive => HyperplaneSide::Negative,
            HyperplaneSide::Negative => HyperplaneSide::Positive,
        }
    }
}

impl HyperplaneSide {
    // TODO: check this against the original game logic. Note that the current implementation will
    // treat both 0.0 and -0.0 as Positive.
    pub fn from_dist(dist: f32) -> HyperplaneSide {
        if dist >= 0.0 {
            HyperplaneSide::Positive
        } else {
            HyperplaneSide::Negative
        }
    }
}

#[derive(Debug)]
/// The intersection of a line or segment and a plane at a point.
pub struct PointIntersection {
    // percentage of distance between start and end where crossover occurred
    ratio: f32,

    // crossover point
    point: Vector3<f32>,

    // plane crossed over
    plane: Hyperplane,
}

impl PointIntersection {
    pub fn ratio(&self) -> f32 {
        self.ratio
    }

    pub fn point(&self) -> Vector3<f32> {
        self.point
    }

    pub fn plane(&self) -> &Hyperplane {
        &self.plane
    }
}

#[derive(Debug)]
/// The intersection of a line or line segment with a plane.
///
/// A true mathematical representation would account for lines or segments contained entirely within
/// the plane, but here a distance of 0.0 is considered Positive. Thus, lines or segments contained
/// by the plane are considered to be `NoIntersection(Positive)`.
pub enum LinePlaneIntersect {
    /// The line or line segment never intersects with the plane.
    NoIntersection(HyperplaneSide),

    /// The line or line segment intersects with the plane at precisely one point.
    PointIntersection(PointIntersection),
}

#[derive(Copy, Clone, Debug, FromPrimitive)]
pub enum Axis {
    X = 0,
    Y = 1,
    Z = 2,
}

#[derive(Clone, Debug)]
enum Alignment {
    Axis(Axis),
    Normal(Vector3<f32>),
}

#[derive(Clone, Debug)]
pub struct Hyperplane {
    alignment: Alignment,
    dist: f32,
}

impl Neg for Hyperplane {
    type Output = Self;

    fn neg(self) -> Self::Output {
        let normal = match self.alignment {
            Alignment::Axis(a) => {
                let mut n = Vector3::zero();
                n[a as usize] = -1.0;
                n
            }
            Alignment::Normal(n) => -n,
        };

        Hyperplane::new(normal, -self.dist)
    }
}

impl Hyperplane {
    /// Creates a new hyperplane aligned along the given normal, `dist` units away from the origin.
    ///
    /// If the given normal is equivalent to one of the axis normals, the hyperplane will be optimized
    /// to only consider that axis when performing point comparisons.
    pub fn new(normal: Vector3<f32>, dist: f32) -> Hyperplane {
        match normal {
            n if n == Vector3::unit_x() => Self::axis_x(dist),
            n if n == Vector3::unit_y() => Self::axis_y(dist),
            n if n == Vector3::unit_z() => Self::axis_z(dist),
            _ => Self::normal(normal, dist),
        }
    }

    /// Creates a new hyperplane aligned along the x-axis, `dist` units away from the origin.
    ///
    /// This hyperplane will only consider the x-axis when performing point comparisons.
    pub fn axis_x(dist: f32) -> Hyperplane {
        Hyperplane {
            alignment: Alignment::Axis(Axis::X),
            dist,
        }
    }

    /// Creates a new hyperplane aligned along the y-axis, `dist` units away from the origin.
    ///
    /// This hyperplane will only consider the y-axis when performing point comparisons.
    pub fn axis_y(dist: f32) -> Hyperplane {
        Hyperplane {
            alignment: Alignment::Axis(Axis::Y),
            dist,
        }
    }

    /// Creates a new hyperplane aligned along the z-axis, `dist` units away from the origin.
    ///
    /// This hyperplane will only consider the z-axis when performing point comparisons.
    pub fn axis_z(dist: f32) -> Hyperplane {
        Hyperplane {
            alignment: Alignment::Axis(Axis::Z),
            dist,
        }
    }

    /// Creates a new hyperplane aligned along the given normal, `dist` units away from the origin.
    ///
    /// This function will force the hyperplane alignment to be represented as a normal even if it
    /// is aligned along an axis.
    pub fn normal(normal: Vector3<f32>, dist: f32) -> Hyperplane {
        Hyperplane {
            alignment: Alignment::Normal(normal),
            dist,
        }
    }

    /// Calculates the shortest distance between this hyperplane and the given point.
    pub fn point_dist(&self, point: Vector3<f32>) -> f32 {
        match self.alignment {
            Alignment::Axis(a) => point[a as usize] - self.dist,
            Alignment::Normal(n) => point.dot(n) - self.dist,
        }
    }

    /// Calculates which side of this hyperplane the given point belongs to.
    ///
    /// Points with a distance of 0.0 are considered to be on the positive side.
    pub fn point_side(&self, point: Vector3<f32>) -> HyperplaneSide {
        let point_dist_greater = match self.alignment {
            Alignment::Axis(a) => point[a as usize] >= self.dist,
            Alignment::Normal(n) => point.dot(n) - self.dist >= 0.0,
        };

        match point_dist_greater {
            true => HyperplaneSide::Positive,
            false => HyperplaneSide::Negative,
        }
    }

    /// Calculates the intersection of a line segment with this hyperplane.
    pub fn line_segment_intersection(
        &self,
        start: Vector3<f32>,
        end: Vector3<f32>,
    ) -> LinePlaneIntersect {
        let start_dist = self.point_dist(start);
        let end_dist = self.point_dist(end);

        debug!(
            "line_segment_intersection: alignment={:?} plane_dist={} start_dist={} end_dist={}",
            self.alignment, self.dist, start_dist, end_dist
        );

        let start_side = HyperplaneSide::from_dist(start_dist);
        let end_side = HyperplaneSide::from_dist(end_dist);

        // if both points fall on the same side of the hyperplane, there is no intersection
        if start_side == end_side {
            return LinePlaneIntersect::NoIntersection(start_side);
        }

        // calculate how far along the segment the intersection occurred
        let ratio = start_dist / (start_dist - end_dist);

        let point = start + ratio * (end - start);

        let plane = match start_side {
            HyperplaneSide::Positive => self.to_owned(),
            HyperplaneSide::Negative => -self.to_owned(),
        };

        LinePlaneIntersect::PointIntersection(PointIntersection {
            ratio,
            point,
            plane,
        })
    }
}

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

    #[test]
    fn test_hyperplane_point_dist_x() {
        let plane = Hyperplane::axis_x(1.0);
        assert_eq!(plane.point_dist(Vector3::unit_x() * 2.0), 1.0);
    }

    #[test]
    fn test_hyperplane_side_x() {
        let plane = Hyperplane::axis_x(1.0);
        assert_eq!(
            plane.point_side(Vector3::unit_x() * 2.0),
            HyperplaneSide::Positive
        );
        assert_eq!(
            plane.point_side(Vector3::unit_x() * -2.0),
            HyperplaneSide::Negative
        );
    }

    #[test]
    fn test_hyperplane_side_y() {
        let plane = Hyperplane::axis_y(1.0);
        assert_eq!(
            plane.point_side(Vector3::unit_y() * 2.0),
            HyperplaneSide::Positive
        );
        assert_eq!(
            plane.point_side(Vector3::unit_y() * -2.0),
            HyperplaneSide::Negative
        );
    }

    #[test]
    fn test_hyperplane_side_z() {
        let plane = Hyperplane::axis_z(1.0);
        assert_eq!(
            plane.point_side(Vector3::unit_z() * 2.0),
            HyperplaneSide::Positive
        );
        assert_eq!(
            plane.point_side(Vector3::unit_z() * -2.0),
            HyperplaneSide::Negative
        );
    }

    #[test]
    fn test_hyperplane_point_dist_y() {
        let plane = Hyperplane::axis_y(1.0);
        assert_eq!(plane.point_dist(Vector3::unit_y() * 2.0), 1.0);
    }

    #[test]
    fn test_hyperplane_point_dist_z() {
        let plane = Hyperplane::axis_z(1.0);
        assert_eq!(plane.point_dist(Vector3::unit_z() * 2.0), 1.0)
    }

    #[test]
    fn test_hyperplane_point_dist_x_no_axis() {
        let plane = Hyperplane::normal(Vector3::unit_x(), 1.0);
        assert_eq!(plane.point_dist(Vector3::unit_x() * 2.0), 1.0);
    }

    #[test]
    fn test_hyperplane_point_dist_y_no_axis() {
        let plane = Hyperplane::normal(Vector3::unit_y(), 1.0);
        assert_eq!(plane.point_dist(Vector3::unit_y() * 2.0), 1.0);
    }

    #[test]
    fn test_hyperplane_point_dist_z_no_axis() {
        let plane = Hyperplane::normal(Vector3::unit_z(), 1.0);
        assert_eq!(plane.point_dist(Vector3::unit_z() * 2.0), 1.0)
    }

    #[test]
    fn test_hyperplane_line_segment_intersection_x() {
        let plane = Hyperplane::axis_x(1.0);
        let start = Vector3::new(0.0, 0.5, 0.5);
        let end = Vector3::new(2.0, 0.5, 0.5);

        match plane.line_segment_intersection(start, end) {
            LinePlaneIntersect::PointIntersection(p_i) => {
                assert_eq!(p_i.ratio(), 0.5);
                assert_eq!(p_i.point(), Vector3::new(1.0, 0.5, 0.5));
            }
            _ => panic!(),
        }
    }

    #[test]
    fn test_hyperplane_line_segment_intersection_y() {
        let plane = Hyperplane::axis_y(1.0);
        let start = Vector3::new(0.5, 0.0, 0.5);
        let end = Vector3::new(0.5, 2.0, 0.5);

        match plane.line_segment_intersection(start, end) {
            LinePlaneIntersect::PointIntersection(p_i) => {
                assert_eq!(p_i.ratio(), 0.5);
                assert_eq!(p_i.point(), Vector3::new(0.5, 1.0, 0.5));
            }
            _ => panic!(),
        }
    }

    #[test]
    fn test_hyperplane_line_segment_intersection_z() {
        let plane = Hyperplane::axis_z(1.0);
        let start = Vector3::new(0.5, 0.5, 0.0);
        let end = Vector3::new(0.5, 0.5, 2.0);

        match plane.line_segment_intersection(start, end) {
            LinePlaneIntersect::PointIntersection(p_i) => {
                assert_eq!(p_i.ratio(), 0.5);
                assert_eq!(p_i.point(), Vector3::new(0.5, 0.5, 1.0));
            }
            _ => panic!(),
        }
    }
}
<commit_msg>More Hyperplane unit tests<commit_after>// Copyright © 2018 Cormac O'Brien
//
// 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 std::ops::Neg;

use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Zero;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum HyperplaneSide {
    Positive = 0,
    Negative = 1,
}

impl Neg for HyperplaneSide {
    type Output = HyperplaneSide;

    fn neg(self) -> Self::Output {
        match self {
            HyperplaneSide::Positive => HyperplaneSide::Negative,
            HyperplaneSide::Negative => HyperplaneSide::Positive,
        }
    }
}

impl HyperplaneSide {
    // TODO: check this against the original game logic. Note that the current implementation will
    // treat both 0.0 and -0.0 as Positive.
    pub fn from_dist(dist: f32) -> HyperplaneSide {
        if dist >= 0.0 {
            HyperplaneSide::Positive
        } else {
            HyperplaneSide::Negative
        }
    }
}

#[derive(Debug)]
/// The intersection of a line or segment and a plane at a point.
pub struct PointIntersection {
    // percentage of distance between start and end where crossover occurred
    ratio: f32,

    // crossover point
    point: Vector3<f32>,

    // plane crossed over
    plane: Hyperplane,
}

impl PointIntersection {
    pub fn ratio(&self) -> f32 {
        self.ratio
    }

    pub fn point(&self) -> Vector3<f32> {
        self.point
    }

    pub fn plane(&self) -> &Hyperplane {
        &self.plane
    }
}

#[derive(Debug)]
/// The intersection of a line or line segment with a plane.
///
/// A true mathematical representation would account for lines or segments contained entirely within
/// the plane, but here a distance of 0.0 is considered Positive. Thus, lines or segments contained
/// by the plane are considered to be `NoIntersection(Positive)`.
pub enum LinePlaneIntersect {
    /// The line or line segment never intersects with the plane.
    NoIntersection(HyperplaneSide),

    /// The line or line segment intersects with the plane at precisely one point.
    PointIntersection(PointIntersection),
}

#[derive(Copy, Clone, Debug, FromPrimitive)]
pub enum Axis {
    X = 0,
    Y = 1,
    Z = 2,
}

#[derive(Clone, Debug)]
enum Alignment {
    Axis(Axis),
    Normal(Vector3<f32>),
}

#[derive(Clone, Debug)]
pub struct Hyperplane {
    alignment: Alignment,
    dist: f32,
}

impl Neg for Hyperplane {
    type Output = Self;

    fn neg(self) -> Self::Output {
        let normal = match self.alignment {
            Alignment::Axis(a) => {
                let mut n = Vector3::zero();
                n[a as usize] = -1.0;
                n
            }
            Alignment::Normal(n) => -n,
        };

        Hyperplane::new(normal, -self.dist)
    }
}

impl Hyperplane {
    /// Creates a new hyperplane aligned along the given normal, `dist` units away from the origin.
    ///
    /// If the given normal is equivalent to one of the axis normals, the hyperplane will be optimized
    /// to only consider that axis when performing point comparisons.
    pub fn new(normal: Vector3<f32>, dist: f32) -> Hyperplane {
        match normal {
            n if n == Vector3::unit_x() => Self::axis_x(dist),
            n if n == Vector3::unit_y() => Self::axis_y(dist),
            n if n == Vector3::unit_z() => Self::axis_z(dist),
            _ => Self::normal(normal.normalize(), dist),
        }
    }

    /// Creates a new hyperplane aligned along the x-axis, `dist` units away from the origin.
    ///
    /// This hyperplane will only consider the x-axis when performing point comparisons.
    pub fn axis_x(dist: f32) -> Hyperplane {
        Hyperplane {
            alignment: Alignment::Axis(Axis::X),
            dist,
        }
    }

    /// Creates a new hyperplane aligned along the y-axis, `dist` units away from the origin.
    ///
    /// This hyperplane will only consider the y-axis when performing point comparisons.
    pub fn axis_y(dist: f32) -> Hyperplane {
        Hyperplane {
            alignment: Alignment::Axis(Axis::Y),
            dist,
        }
    }

    /// Creates a new hyperplane aligned along the z-axis, `dist` units away from the origin.
    ///
    /// This hyperplane will only consider the z-axis when performing point comparisons.
    pub fn axis_z(dist: f32) -> Hyperplane {
        Hyperplane {
            alignment: Alignment::Axis(Axis::Z),
            dist,
        }
    }

    /// Creates a new hyperplane aligned along the given normal, `dist` units away from the origin.
    ///
    /// This function will force the hyperplane alignment to be represented as a normal even if it
    /// is aligned along an axis.
    pub fn normal(normal: Vector3<f32>, dist: f32) -> Hyperplane {
        Hyperplane {
            alignment: Alignment::Normal(normal.normalize()),
            dist,
        }
    }

    /// Calculates the shortest distance between this hyperplane and the given point.
    pub fn point_dist(&self, point: Vector3<f32>) -> f32 {
        match self.alignment {
            Alignment::Axis(a) => point[a as usize] - self.dist,
            Alignment::Normal(n) => point.dot(n) - self.dist,
        }
    }

    /// Calculates which side of this hyperplane the given point belongs to.
    ///
    /// Points with a distance of 0.0 are considered to be on the positive side.
    pub fn point_side(&self, point: Vector3<f32>) -> HyperplaneSide {
        let point_dist_greater = match self.alignment {
            Alignment::Axis(a) => point[a as usize] >= self.dist,
            Alignment::Normal(n) => point.dot(n) - self.dist >= 0.0,
        };

        match point_dist_greater {
            true => HyperplaneSide::Positive,
            false => HyperplaneSide::Negative,
        }
    }

    /// Calculates the intersection of a line segment with this hyperplane.
    pub fn line_segment_intersection(
        &self,
        start: Vector3<f32>,
        end: Vector3<f32>,
    ) -> LinePlaneIntersect {
        let start_dist = self.point_dist(start);
        let end_dist = self.point_dist(end);

        debug!(
            "line_segment_intersection: alignment={:?} plane_dist={} start_dist={} end_dist={}",
            self.alignment, self.dist, start_dist, end_dist
        );

        let start_side = HyperplaneSide::from_dist(start_dist);
        let end_side = HyperplaneSide::from_dist(end_dist);

        // if both points fall on the same side of the hyperplane, there is no intersection
        if start_side == end_side {
            return LinePlaneIntersect::NoIntersection(start_side);
        }

        // calculate how far along the segment the intersection occurred
        let ratio = start_dist / (start_dist - end_dist);

        let point = start + ratio * (end - start);

        let plane = match start_side {
            HyperplaneSide::Positive => self.to_owned(),
            HyperplaneSide::Negative => -self.to_owned(),
        };

        LinePlaneIntersect::PointIntersection(PointIntersection {
            ratio,
            point,
            plane,
        })
    }
}

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

    #[test]
    fn test_hyperplane_side_x() {
        let plane = Hyperplane::axis_x(1.0);
        assert_eq!(
            plane.point_side(Vector3::unit_x() * 2.0),
            HyperplaneSide::Positive
        );
        assert_eq!(
            plane.point_side(Vector3::unit_x() * -2.0),
            HyperplaneSide::Negative
        );
    }

    #[test]
    fn test_hyperplane_side_y() {
        let plane = Hyperplane::axis_y(1.0);
        assert_eq!(
            plane.point_side(Vector3::unit_y() * 2.0),
            HyperplaneSide::Positive
        );
        assert_eq!(
            plane.point_side(Vector3::unit_y() * -2.0),
            HyperplaneSide::Negative
        );
    }

    #[test]
    fn test_hyperplane_side_z() {
        let plane = Hyperplane::axis_z(1.0);
        assert_eq!(
            plane.point_side(Vector3::unit_z() * 2.0),
            HyperplaneSide::Positive
        );
        assert_eq!(
            plane.point_side(Vector3::unit_z() * -2.0),
            HyperplaneSide::Negative
        );
    }

    #[test]
    fn test_hyperplane_side_arbitrary() {
        // test 16 hyperplanes around the origin
        for x_comp in [1.0, -1.0].into_iter() {
            for y_comp in [1.0, -1.0].into_iter() {
                for z_comp in [1.0, -1.0].into_iter() {
                    for dist in [1, -1].into_iter() {
                        let base_vector = Vector3::new(*x_comp, *y_comp, *z_comp);
                        let plane = Hyperplane::new(base_vector, *dist as f32);
                        assert_eq!(
                            plane.point_side(Vector3::zero()),
                            match *dist {
                                1 => HyperplaneSide::Negative,
                                -1 => HyperplaneSide::Positive,
                                _ => unreachable!(),
                            }
                        );
                        assert_eq!(
                            plane.point_side(base_vector * 2.0 * *dist as f32),
                            match *dist {
                                1 => HyperplaneSide::Positive,
                                -1 => HyperplaneSide::Negative,
                                _ => unreachable!(),
                            }
                        );
                    }
                }
            }
        }
    }

    #[test]
    fn test_hyperplane_point_dist_x() {
        let plane = Hyperplane::axis_x(1.0);
        assert_eq!(plane.point_dist(Vector3::unit_x() * 2.0), 1.0);
        assert_eq!(plane.point_dist(Vector3::zero()), -1.0);
    }

    #[test]
    fn test_hyperplane_point_dist_y() {
        let plane = Hyperplane::axis_y(1.0);
        assert_eq!(plane.point_dist(Vector3::unit_y() * 2.0), 1.0);
        assert_eq!(plane.point_dist(Vector3::zero()), -1.0);
    }

    #[test]
    fn test_hyperplane_point_dist_z() {
        let plane = Hyperplane::axis_z(1.0);
        assert_eq!(plane.point_dist(Vector3::unit_z() * 2.0), 1.0);
        assert_eq!(plane.point_dist(Vector3::zero()), -1.0);
    }

    #[test]
    fn test_hyperplane_point_dist_x_no_axis() {
        let plane = Hyperplane::normal(Vector3::unit_x(), 1.0);
        assert_eq!(plane.point_dist(Vector3::unit_x() * 2.0), 1.0);
        assert_eq!(plane.point_dist(Vector3::zero()), -1.0);
    }

    #[test]
    fn test_hyperplane_point_dist_y_no_axis() {
        let plane = Hyperplane::normal(Vector3::unit_y(), 1.0);
        assert_eq!(plane.point_dist(Vector3::unit_y() * 2.0), 1.0);
        assert_eq!(plane.point_dist(Vector3::zero()), -1.0);
    }

    #[test]
    fn test_hyperplane_point_dist_z_no_axis() {
        let plane = Hyperplane::normal(Vector3::unit_z(), 1.0);
        assert_eq!(plane.point_dist(Vector3::unit_z() * 2.0), 1.0);
        assert_eq!(plane.point_dist(Vector3::zero()), -1.0);
    }

    #[test]
    fn test_hyperplane_line_segment_intersection_x() {
        let plane = Hyperplane::axis_x(1.0);
        let start = Vector3::new(0.0, 0.5, 0.5);
        let end = Vector3::new(2.0, 0.5, 0.5);

        match plane.line_segment_intersection(start, end) {
            LinePlaneIntersect::PointIntersection(p_i) => {
                assert_eq!(p_i.ratio(), 0.5);
                assert_eq!(p_i.point(), Vector3::new(1.0, 0.5, 0.5));
            }
            _ => panic!(),
        }
    }

    #[test]
    fn test_hyperplane_line_segment_intersection_y() {
        let plane = Hyperplane::axis_y(1.0);
        let start = Vector3::new(0.5, 0.0, 0.5);
        let end = Vector3::new(0.5, 2.0, 0.5);

        match plane.line_segment_intersection(start, end) {
            LinePlaneIntersect::PointIntersection(p_i) => {
                assert_eq!(p_i.ratio(), 0.5);
                assert_eq!(p_i.point(), Vector3::new(0.5, 1.0, 0.5));
            }
            _ => panic!(),
        }
    }

    #[test]
    fn test_hyperplane_line_segment_intersection_z() {
        let plane = Hyperplane::axis_z(1.0);
        let start = Vector3::new(0.5, 0.5, 0.0);
        let end = Vector3::new(0.5, 0.5, 2.0);

        match plane.line_segment_intersection(start, end) {
            LinePlaneIntersect::PointIntersection(p_i) => {
                assert_eq!(p_i.ratio(), 0.5);
                assert_eq!(p_i.point(), Vector3::new(0.5, 0.5, 1.0));
            }
            _ => panic!(),
        }
    }
}
<|endoftext|>


<commit_before>use common::types::FnType;
use common::types::StructType;
use common::link::*;

use common::entity::FromEntity;
use common::entity::Entity;

use std::collections::HashMap;
use common::tree_id::*;

#[derive(Debug, Clone)]
pub struct Node {
    id: i32,
    name: String,
    url: String,
    fn_type: FnType,
    links: Vec<Link>,
    nodes: Vec<Node>,
}

impl Node {
    fn push(&mut self, entity: &Entity) {
        match entity.struct_type {
            StructType::Link => {
                self.links.push(Link::from_entity(&entity));
            },
            StructType::Node => {
                self.nodes.push(Node::from_entity(&entity));
            }
        }
    }
}

impl FromEntity for Node {
    fn from_entity(entity: &Entity) -> Self {
        let clone = entity.clone();

        Node {
            id: clone.id,
            name: clone.name,
            url: clone.url,
            fn_type: clone.fn_type,
            links: Vec::new(),
            nodes: Vec::new()
        }
    }

    fn from_entities(entities: Vec<Entity>) -> Vec<Self> {
        let mut node_map: HashMap<String, Node> = HashMap::new();
        let mut node_dir: HashMap<i32, TreeId> = HashMap::new();
        let mut lower = usize::max_value();
        let mut pre_links: Vec<Entity> = Vec::new();

        for e in entities {
            let ref path = e.tree_id;

            if e.struct_type == StructType::Node {
                if level(path) < lower {
                    lower = level(path);
                }

                node_dir.insert(e.id, path.clone());
                node_map.insert(path.id(), Node::from_entity(&e));
            } else {
                pre_links.push(e.clone());
            }
        }

        for e in pre_links {
            let inner = level(&e.tree_id);

            let parent = match key(&e.tree_id, inner - 1) {
                Some(p) => p,
                None => panic!("{:?}", e),
            };

            if let Some(node) = node_map.get_mut(&parent) {
                node.push(&e);
            }
        }

        let mut roots = Vec::new();
        for (_, node) in node_map {
            push_node(&node_dir, &mut roots, lower, node);
        }

        roots
    }
}

fn push_node<'a>(dir: &HashMap<i32, TreeId>, roots: &mut Vec<Node>, search: usize, node: Node) {
    let path = match dir.get(&node.id) {
        Some(tree_id) => tree_id,
        None => panic!("{:?}", node)
    };

    if level(path) == search {
        roots.push(node.clone());
    } else {
        for root in roots {
            let parent = match key(path, search) {
                Some(key) => key,
                None => panic!("{:?}", path)
            };

            let root_key = match dir.get(&root.id) {
                Some(key) => key,
                None => panic!("{:?}", root)
            };

            if parent == root_key.id() {
                push_node(dir, &mut root.nodes, search + 1, node.clone());
                break;
            }
        }
    }
}
<commit_msg>clean algorithm<commit_after>use common::types::FnType;
use common::types::StructType;
use common::link::*;

use common::entity::FromEntity;
use common::entity::Entity;

use std::collections::HashMap;
use common::tree_id::*;

#[derive(Debug, Clone)]
pub struct Node {
    id: i32,
    name: String,
    url: String,
    fn_type: FnType,
    links: Vec<Link>,
    nodes: Vec<Node>,
}

impl Node {
    fn push(&mut self, entity: &Entity) {
        match entity.struct_type {
            StructType::Link => {
                self.links.push(Link::from_entity(&entity));
            },
            StructType::Node => {
                self.nodes.push(Node::from_entity(&entity));
            }
        }
    }
}

impl FromEntity for Node {
    fn from_entity(entity: &Entity) -> Self {
        let clone = entity.clone();

        Node {
            id: clone.id,
            name: clone.name,
            url: clone.url,
            fn_type: clone.fn_type,
            links: Vec::new(),
            nodes: Vec::new()
        }
    }

    fn from_entities(entities: Vec<Entity>) -> Vec<Self> {
        let mut node_map: HashMap<String, Node> = HashMap::new();
        let mut node_dir: HashMap<i32, TreeId> = HashMap::new();
        let mut lower = usize::max_value();
        let mut pre_links: Vec<Entity> = Vec::new();

        for e in entities {
            let ref path = e.tree_id;
            if e.struct_type == StructType::Node {
                if level(path) < lower {
                    lower = level(path);
                }

                node_dir.insert(e.id, path.clone());
                node_map.insert(path.id(), Node::from_entity(&e));
            } else {
                pre_links.push(e.clone());
            }
        }

        for e in pre_links {
            let ref path = e.tree_id;
            let parent = match key(&path, level(&path) - 1) {
                Some(p) => p,
                None => panic!("{:?}", e),
            };

            if let Some(node) = node_map.get_mut(&parent) {
                node.push(&e);
            }
        }

        let mut roots = Vec::new();
        for (_, node) in node_map {
            push_node(&node_dir, &mut roots, lower, node);
        }

        roots
    }
}

fn push_node<'a>(dir: &HashMap<i32, TreeId>, roots: &mut Vec<Node>, search_level: usize, node: Node) {
    let path = match dir.get(&node.id) {
        Some(tree_id) => tree_id,
        None => panic!("{:?}", node)
    };

    if level(path) == search_level {
        roots.push(node.clone());
    } else {
        for root in roots {
            let parent_id = match key(path, search_level) {
                Some(id) => id,
                None => panic!("{:?}", path)
            };

            let root_key = match dir.get(&root.id) {
                Some(key) => key,
                None => panic!("{:?}", root)
            };

            if parent_id == root_key.id() {
                push_node(dir, &mut root.nodes, search_level + 1, node.clone());
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>use torrent::{Torrent, Status};
use std::collections::HashMap;
use std::time;
use control::cio;

pub trait Job<T: cio::CIO> {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>);
}

pub struct JobManager<T: cio::CIO> {
    jobs: Vec<JobData<T>>,
}

struct JobData<T: cio::CIO> {
    job: Box<Job<T>>,
    last_updated: time::Instant,
    interval: time::Duration,
}

impl<T: cio::CIO> JobManager<T> {
    pub fn new() -> JobManager<T> {
        JobManager { jobs: Vec::new() }
    }

    pub fn add_job<J: Job<T> + 'static>(&mut self, job: J, interval: time::Duration) {
        self.jobs.push(JobData {
            job: Box::new(job),
            interval,
            last_updated: time::Instant::now(),
        })
    }

    pub fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for j in &mut self.jobs {
            if j.last_updated.elapsed() > j.interval {
                j.job.update(torrents);
                j.last_updated = time::Instant::now();
            }
        }
    }
}

pub struct TrackerUpdate;

impl<T: cio::CIO> Job<T> for TrackerUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (_, torrent) in torrents.iter_mut() {
            torrent.update_tracker();
        }
    }
}

pub struct UnchokeUpdate;

impl<T: cio::CIO> Job<T> for UnchokeUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (_, torrent) in torrents.iter_mut() {
            torrent.update_unchoked();
        }
    }
}

pub struct SessionUpdate;

impl<T: cio::CIO> Job<T> for SessionUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (_, torrent) in torrents.iter_mut() {
            if torrent.dirty() {
                torrent.serialize();
            }
        }
    }
}

pub struct TorrentTxUpdate {
    speeds: HashMap<usize, Speed>,
}

impl TorrentTxUpdate {
    pub fn new() -> TorrentTxUpdate {
        TorrentTxUpdate { speeds: HashMap::new() }
    }
}

struct Speed {
    ul: u64,
    dl: u64,
    linger: u8,
}

impl<T: cio::CIO> Job<T> for TorrentTxUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (id, torrent) in torrents.iter_mut() {
            let (ul, dl) = torrent.get_last_tx_rate();
            if !self.speeds.contains_key(id) {
                self.speeds.insert(
                    *id,
                    Speed {
                        dl: 0,
                        ul: 0,
                        linger: 0,
                    },
                );
            }
            let ls = self.speeds.get_mut(id).unwrap();
            // TODO: Use this result to get a better estimate
            if ls.ul != ul || ls.dl != dl || ls.linger != 0 {
                torrent.update_rpc_transfer();
                torrent.reset_last_tx_rate();
                ls.ul = ul;
                ls.dl = dl;
                if ls.linger == 0 {
                    ls.linger = 2;
                } else {
                    ls.linger -= 1;
                }
            }
        }
        self.speeds.retain(|id, _| torrents.contains_key(id));
    }
}

impl TorrentStatusUpdate {
    pub fn new() -> TorrentStatusUpdate {
        TorrentStatusUpdate { transferred: HashMap::new() }
    }
}

pub struct TorrentStatusUpdate {
    transferred: HashMap<usize, (u64, u64)>,
}

impl<T: cio::CIO> Job<T> for TorrentStatusUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (id, torrent) in torrents.iter_mut() {
            let (ul, dl) = (torrent.uploaded(), torrent.downloaded());
            if !self.transferred.contains_key(id) {
                self.transferred.insert(*id, (
                    torrent.uploaded(),
                    torrent.downloaded(),
                ));
            }
            let tx = self.transferred.get_mut(id).unwrap();
            if torrent.status() == Status::Seeding && ul == tx.0 {
                torrent.set_status(Status::Idle);
            }
            if torrent.status() == Status::Leeching && dl == tx.1 {
                torrent.set_status(Status::Pending);
            }
        }
        self.transferred.retain(|id, _| torrents.contains_key(id));
    }
}
<commit_msg>Properly update torrent status<commit_after>use torrent::{Torrent, Status};
use std::collections::HashMap;
use std::time;
use control::cio;

pub trait Job<T: cio::CIO> {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>);
}

pub struct JobManager<T: cio::CIO> {
    jobs: Vec<JobData<T>>,
}

struct JobData<T: cio::CIO> {
    job: Box<Job<T>>,
    last_updated: time::Instant,
    interval: time::Duration,
}

impl<T: cio::CIO> JobManager<T> {
    pub fn new() -> JobManager<T> {
        JobManager { jobs: Vec::new() }
    }

    pub fn add_job<J: Job<T> + 'static>(&mut self, job: J, interval: time::Duration) {
        self.jobs.push(JobData {
            job: Box::new(job),
            interval,
            last_updated: time::Instant::now(),
        })
    }

    pub fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for j in &mut self.jobs {
            if j.last_updated.elapsed() > j.interval {
                j.job.update(torrents);
                j.last_updated = time::Instant::now();
            }
        }
    }
}

pub struct TrackerUpdate;

impl<T: cio::CIO> Job<T> for TrackerUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (_, torrent) in torrents.iter_mut() {
            torrent.update_tracker();
        }
    }
}

pub struct UnchokeUpdate;

impl<T: cio::CIO> Job<T> for UnchokeUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (_, torrent) in torrents.iter_mut() {
            torrent.update_unchoked();
        }
    }
}

pub struct SessionUpdate;

impl<T: cio::CIO> Job<T> for SessionUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (_, torrent) in torrents.iter_mut() {
            if torrent.dirty() {
                torrent.serialize();
            }
        }
    }
}

pub struct TorrentTxUpdate {
    speeds: HashMap<usize, Speed>,
}

impl TorrentTxUpdate {
    pub fn new() -> TorrentTxUpdate {
        TorrentTxUpdate { speeds: HashMap::new() }
    }
}

struct Speed {
    ul: u64,
    dl: u64,
    linger: u8,
}

impl<T: cio::CIO> Job<T> for TorrentTxUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (id, torrent) in torrents.iter_mut() {
            let (ul, dl) = torrent.get_last_tx_rate();
            if !self.speeds.contains_key(id) {
                self.speeds.insert(
                    *id,
                    Speed {
                        dl: 0,
                        ul: 0,
                        linger: 0,
                    },
                );
            }
            let ls = self.speeds.get_mut(id).unwrap();
            // TODO: Use this result to get a better estimate
            if ls.ul != ul || ls.dl != dl || ls.linger != 0 {
                torrent.update_rpc_transfer();
                torrent.reset_last_tx_rate();
                ls.ul = ul;
                ls.dl = dl;
                if ls.linger == 0 {
                    ls.linger = 2;
                } else {
                    ls.linger -= 1;
                }
            }
        }
        self.speeds.retain(|id, _| torrents.contains_key(id));
    }
}

impl TorrentStatusUpdate {
    pub fn new() -> TorrentStatusUpdate {
        TorrentStatusUpdate { transferred: HashMap::new() }
    }
}

pub struct TorrentStatusUpdate {
    transferred: HashMap<usize, (u64, u64)>,
}

impl<T: cio::CIO> Job<T> for TorrentStatusUpdate {
    fn update(&mut self, torrents: &mut HashMap<usize, Torrent<T>>) {
        for (id, torrent) in torrents.iter_mut() {
            let (ul, dl) = (torrent.uploaded(), torrent.downloaded());
            if !self.transferred.contains_key(id) {
                self.transferred.insert(*id, (
                    torrent.uploaded(),
                    torrent.downloaded(),
                ));
            }
            let tx = self.transferred.get_mut(id).unwrap();
            if torrent.status() == Status::Seeding && ul == tx.0 {
                torrent.set_status(Status::Idle);
            }
            if torrent.status() == Status::Leeching && dl == tx.1 {
                torrent.set_status(Status::Pending);
            }
            tx.0 = ul;
            tx.1 = dl;
        }
        self.transferred.retain(|id, _| torrents.contains_key(id));
    }
}
<|endoftext|>


<commit_before>use http::status::Status;
use nickel::{
    Continue,
    ErrorWithStatusCode,
    Halt,
    MiddlewareResult,
    NickelError,
    Request,
    Response,
};
use nickel::mimes::MediaType;
use rustdoc::html::markdown::Markdown;
use std::collections::HashMap;
use std::io::{
    BufferedReader,
    File
};

/// Render the index page.
pub fn root_handler(_request: &Request, response: &mut Response) {
    let mut data = HashMap::<&str, &str>::new();
    data.insert("name", "user");
    response.render("assets/templates/index.tpl", &data);
}

pub fn get_blog_post(request: &Request, response: &mut Response) {
    // Retrieve the post id from the request URL.
    let post_year = request.param("post_year");
    let post_id = request.param("post_id");
    let post_path = Path::new("assets/content/posts/".to_string() +
            post_year.to_string() +
            "/".to_string() +
            post_id.to_string() +
            ".md".to_string());

    // Read the post markdown from the disk.
    let content = File::open(&post_path).read_to_end().unwrap();
    let content = String::from_utf8(content).unwrap();
    let mut content = content.as_slice().split_str("\n\n");
    //let mut file = BufferedReader::new(File::open(&post_path));
    //let mut contents = "";
    let heading = content.next().unwrap();
    let mut content = content.map(|x| x.to_string());
    let content = content.fold("".to_string(), |a, b| a + "\n\n".to_string() + b);
    /*for line in file.lines() {
        let line = line.unwrap();
        let split: Vec<&str> = line.as_slice().rsplitn(1, ": ").collect();
        match split.get(1) {
            Ok(value) => {
                println!("value");
            }
            Err(e) => {
                contents.push_str(split.get(0));
            }
        }
        //print!("{}", line.unwrap());
        println!("{}", split);
    }*/
    let html_content = format!("{}", Markdown(content.as_slice()));

    let mut data = HashMap::<&str, &str>::new();
    data.insert("content", html_content.as_slice());
    response.render("assets/templates/post.tpl", &data);
}

pub fn custom_errors(err: &NickelError, _req: &Request, response: &mut Response) -> MiddlewareResult {
    use http::status::Status::{Forbidden, NotFound, InternalServerError};

    match err.kind {
        ErrorWithStatusCode(Forbidden) => {
            handle_error(Forbidden, "403", "You are not authorized to view this page", response);
            Ok(Halt)
        },
        ErrorWithStatusCode(NotFound) => {
            handle_error(NotFound, "404", "That file could not be found.", response);
            Ok(Halt)
        },
        ErrorWithStatusCode(InternalServerError) => {
            handle_error(InternalServerError, "500", "An error has occured!", response);
            Ok(Halt)
        },
        _ => Ok(Continue)
    }
}

fn handle_error(status_code: Status, error_code: &str, error_message: &str, res: &mut Response) {
    let mut data = HashMap::<&str, &str>::new();

    data.insert("site_url", "http://nikitapek.in");
    data.insert("error_code", error_code);
    data.insert("error_message", error_message);

    res.content_type(MediaType::Html)
       .status_code(status_code)
       .render("assets/templates/error.tpl", &data);
}
<commit_msg>Move import<commit_after>use http::status::Status;
use http::status::Status::{Forbidden, NotFound, InternalServerError};
use nickel::{
    Continue,
    ErrorWithStatusCode,
    Halt,
    MiddlewareResult,
    NickelError,
    Request,
    Response,
};
use nickel::mimes::MediaType;
use rustdoc::html::markdown::Markdown;
use std::collections::HashMap;
use std::io::{
    BufferedReader,
    File
};

/// Render the index page.
pub fn root_handler(_request: &Request, response: &mut Response) {
    let mut data = HashMap::<&str, &str>::new();
    data.insert("name", "user");
    response.render("assets/templates/index.tpl", &data);
}

pub fn get_blog_post(request: &Request, response: &mut Response) {
    // Retrieve the post id from the request URL.
    let post_year = request.param("post_year");
    let post_id = request.param("post_id");
    let post_path = Path::new("assets/content/posts/".to_string() +
            post_year.to_string() +
            "/".to_string() +
            post_id.to_string() +
            ".md".to_string());

    // Read the post markdown from the disk.
    let content = File::open(&post_path).read_to_end().unwrap();
    let content = String::from_utf8(content).unwrap();
    let mut content = content.as_slice().split_str("\n\n");
    //let mut file = BufferedReader::new(File::open(&post_path));
    //let mut contents = "";
    let heading = content.next().unwrap();
    let mut content = content.map(|x| x.to_string());
    let content = content.fold("".to_string(), |a, b| a + "\n\n".to_string() + b);
    /*for line in file.lines() {
        let line = line.unwrap();
        let split: Vec<&str> = line.as_slice().rsplitn(1, ": ").collect();
        match split.get(1) {
            Ok(value) => {
                println!("value");
            }
            Err(e) => {
                contents.push_str(split.get(0));
            }
        }
        //print!("{}", line.unwrap());
        println!("{}", split);
    }*/
    let html_content = format!("{}", Markdown(content.as_slice()));

    let mut data = HashMap::<&str, &str>::new();
    data.insert("content", html_content.as_slice());
    response.render("assets/templates/post.tpl", &data);
}

pub fn custom_errors(err: &NickelError, _req: &Request, response: &mut Response) -> MiddlewareResult {
    match err.kind {
        ErrorWithStatusCode(Forbidden) => {
            handle_error(Forbidden, "403", "You are not authorized to view this page", response);
            Ok(Halt)
        },
        ErrorWithStatusCode(NotFound) => {
            handle_error(NotFound, "404", "That file could not be found.", response);
            Ok(Halt)
        },
        ErrorWithStatusCode(InternalServerError) => {
            handle_error(InternalServerError, "500", "An error has occured!", response);
            Ok(Halt)
        },
        _ => Ok(Continue)
    }
}

fn handle_error(status_code: Status, error_code: &str, error_message: &str, res: &mut Response) {
    let mut data = HashMap::<&str, &str>::new();

    data.insert("site_url", "http://nikitapek.in");
    data.insert("error_code", error_code);
    data.insert("error_message", error_message);

    res.content_type(MediaType::Html)
       .status_code(status_code)
       .render("assets/templates/error.tpl", &data);
}
<|endoftext|>