<commit_before>const BAD_KEY: u64 = 0x0123456789ABCDEF;

///Basic sanity tests of the cypto properties of aHash.
#[cfg(test)]
mod aes_tests {
    use std::hash::{Hash, Hasher};
    use crate::aes_hash::*;
    use crate::hash_quality_test::*;

    pub fn ahash<H: Hash>(b: H) -> u64 {
        let mut hasher = AesHasher::new_with_keys(BAD_KEY, BAD_KEY);
        b.hash(&mut hasher);
        hasher.finish()
    }

    #[test]
    fn test_single_bit_flip() {
        let size = 32;
        let compare_value = ahash(0u32);
        for pos in 0..size {
            let test_value = ahash(0 ^ (1u32 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
        let size = 64;
        let compare_value = ahash(0u64);
        for pos in 0..size {
            let test_value = ahash(0 ^ (1u64 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
        let size = 128;
        let compare_value = ahash(0u128);
        for pos in 0..size {
            let test_value = ahash(0 ^ (1u128 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
    }

    #[test]
    fn test_keys_change_output() {
        let mut a = AesHasher::new_with_keys(0, 0);
        let mut b = AesHasher::new_with_keys(0, 1);
        let mut c = AesHasher::new_with_keys(1, 0);
        let mut d = AesHasher::new_with_keys(1, 1);
        "test".hash(&mut a);
        "test".hash(&mut b);
        "test".hash(&mut c);
        "test".hash(&mut d);
        assert_sufficiently_different(a.finish(), b.finish());
        assert_sufficiently_different(a.finish(), c.finish());
        assert_sufficiently_different(a.finish(), d.finish());
        assert_sufficiently_different(b.finish(), c.finish());
        assert_sufficiently_different(b.finish(), d.finish());
        assert_sufficiently_different(c.finish(), d.finish());
    }

    #[test]
    fn test_finish_is_consistant() {
        let mut hasher = AesHasher::new_with_keys(1, 2);
        "Foo".hash(&mut hasher);
        let a = hasher.finish();
        let b = hasher.finish();
        assert_eq!(a, b);
    }

    #[test]
    fn test_single_key_bit_flip() {
        for bit in 0..64 {
            let mut a = AesHasher::new_with_keys(0, 0);
            let mut b = AesHasher::new_with_keys(0, 1 << bit);
            let mut c = AesHasher::new_with_keys(1 << bit, 0);
            "1234".hash(&mut a);
            "1234".hash(&mut b);
            "1234".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
            let mut a = AesHasher::new_with_keys(0, 0);
            let mut b = AesHasher::new_with_keys(0, 1 << bit);
            let mut c = AesHasher::new_with_keys(1 << bit, 0);
            "12345678".hash(&mut a);
            "12345678".hash(&mut b);
            "12345678".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
            let mut a = AesHasher::new_with_keys(0, 0);
            let mut b = AesHasher::new_with_keys(0, 1 << bit);
            let mut c = AesHasher::new_with_keys(1 << bit, 0);
            "1234567812345678".hash(&mut a);
            "1234567812345678".hash(&mut b);
            "1234567812345678".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
        }
    }

    #[test]
    fn test_padding_doesnot_collide() {
        for c in 0..128u8 {
            for string in ["", "1234", "12345678", "1234567812345678"].into_iter() {
                let mut short = AesHasher::default();
                string.hash(&mut short);
                let value = short.finish();
                let mut string = string.to_string();
                for num in 1..=128 {
                    let mut long = AesHasher::default();
                    string.push(c as char);
                    string.hash(&mut long);
                    let same_bytes = count_same_bytes(value, long.finish());
                    assert!(same_bytes <= 2, format!("{} bytes of {} -> {:x} vs {:x}", num, c, value, long.finish()));
                    let flipped_bits = (value ^ long.finish()).count_ones();
                    assert!(flipped_bits > 10);
                }
            }
        }
    }
}

fn assert_sufficiently_different(a: u64, b: u64) {
    let same_byte_count = count_same_bytes(a, b);
    assert!(same_byte_count <= 1);
    let flipped_bits = (a ^ b).count_ones();
    assert!(flipped_bits > 18 && flipped_bits < 48, "{:x} and {:x}: {:}", a, b, flipped_bits);
    for rotate in 0..64 {
        let flipped_bits2 = (a ^ (b.rotate_left(rotate))).count_ones();
        assert!(flipped_bits2 > 14 && flipped_bits2 < 50, "{:x} and {:x}: {:}", a, b.rotate_left(rotate), flipped_bits2);
    }
}

fn count_same_bytes(a: u64, b: u64) -> i32 {
    let mut same_byte_count = 0;
    for byte in 0..8 {
        let ba = a >> 8 * byte as u8;
        let bb = b >> 8 * byte as u8;
        if ba == bb {
            same_byte_count += 1;
        }
    }
    same_byte_count
}

#[cfg(test)]
mod fallback_tests {
    use std::hash::{Hash, Hasher};
    use crate::fallback_hash::*;
    use crate::hash_quality_test::*;

    pub fn fallback<H: Hash>(b: H) -> u64 {
        let mut hasher = FallbackHasher::new_with_keys(BAD_KEY, BAD_KEY);
        b.hash(&mut hasher);
        hasher.finish()
    }

    #[test]
    fn test_single_bit_flip() {
        let size = 32;
        let compare_value = fallback(0u32);
        for pos in 0..size {
            let test_value = fallback(0 ^ (1u32 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
        let size = 64;
        let compare_value = fallback(0u64);
        for pos in 0..size {
            let test_value = fallback(0 ^ (1u64 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
        let size = 128;
        let compare_value = fallback(0u128);
        for pos in 0..size {
            let test_value = fallback(0 ^ (1u128 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
    }

    #[test]
    fn test_keys_change_output() {
        let mut a = FallbackHasher::new_with_keys(0, 0);
        let mut b = FallbackHasher::new_with_keys(0, 1);
        let mut c = FallbackHasher::new_with_keys(1, 0);
        let mut d = FallbackHasher::new_with_keys(1, 1);
        "test".hash(&mut a);
        "test".hash(&mut b);
        "test".hash(&mut c);
        "test".hash(&mut d);
        assert_sufficiently_different(a.finish(), b.finish());
        assert_sufficiently_different(a.finish(), c.finish());
        assert_sufficiently_different(a.finish(), d.finish());
        assert_sufficiently_different(b.finish(), c.finish());
        assert_sufficiently_different(b.finish(), d.finish());
        assert_sufficiently_different(c.finish(), d.finish());
    }

    #[test]
    fn test_finish_is_consistant() {
        let mut hasher = FallbackHasher::new_with_keys(1, 2);
        "Foo".hash(&mut hasher);
        let a = hasher.finish();
        let b = hasher.finish();
        assert_eq!(a, b);
    }

    #[test]
    fn test_single_key_bit_flip() {
        for bit in 0..64 {
            let mut a = FallbackHasher::new_with_keys(0, 0);
            let mut b = FallbackHasher::new_with_keys(0, 1 << bit);
            let mut c = FallbackHasher::new_with_keys(1 << bit, 0);
            "1234".hash(&mut a);
            "1234".hash(&mut b);
            "1234".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
            let mut a = FallbackHasher::new_with_keys(0, 0);
            let mut b = FallbackHasher::new_with_keys(0, 1 << bit);
            let mut c = FallbackHasher::new_with_keys(1 << bit, 0);
            "12345678".hash(&mut a);
            "12345678".hash(&mut b);
            "12345678".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
            let mut a = FallbackHasher::new_with_keys(0, 0);
            let mut b = FallbackHasher::new_with_keys(0, 1 << bit);
            let mut c = FallbackHasher::new_with_keys(1 << bit, 0);
            "1234567812345678".hash(&mut a);
            "1234567812345678".hash(&mut b);
            "1234567812345678".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
        }
    }

    #[test]
    fn test_padding_doesnot_collide() {
        for c in 0..128u8 {
            for string in ["", "1234", "12345678", "1234567812345678"].into_iter() {
                let mut short = FallbackHasher::new_with_keys(BAD_KEY, BAD_KEY);
                string.hash(&mut short);
                let value = short.finish();
                let mut string = string.to_string();
                for num in 1..=128 {
                    let mut long = FallbackHasher::new_with_keys(BAD_KEY, BAD_KEY);
                    string.push(c as char);
                    string.hash(&mut long);
                    let same_bytes = count_same_bytes(value, long.finish());
                    assert!(same_bytes <= 2, format!("{} bytes of {} -> {:x} vs {:x}", num, c, value, long.finish()));
                    let flipped_bits = (value ^ long.finish()).count_ones();
                    assert!(flipped_bits > 10,
                            format!("Too few bits fliped {} -> {:x} vs {} -> {:x}", string, value, c, long.finish()));
                }
            }
        }
    }
}<commit_msg>Add stronger test.<commit_after>const BAD_KEY: u64 = 0x5252_5252_5252_5252; //This encrypts to 0.

///Basic sanity tests of the cypto properties of aHash.
#[cfg(test)]
mod aes_tests {
    use std::hash::{Hash, Hasher};
    use crate::aes_hash::*;
    use crate::hash_quality_test::*;

    pub fn ahash<H: Hash>(b: H) -> u64 {
        let mut hasher = AesHasher::new_with_keys(BAD_KEY, BAD_KEY);
        b.hash(&mut hasher);
        hasher.finish()
    }

    #[test]
    fn test_single_bit_in_byte() {
        let mut hasher1= AesHasher::new_with_keys(64, 64);
        8_u32.hash(&mut hasher1);
        let mut hasher2= AesHasher::new_with_keys(64, 64);
        0_u32.hash(&mut hasher2);
        assert_sufficiently_different(hasher1.finish(), hasher2.finish());
    }

    #[test]
    fn test_single_bit_flip() {
        let size = 32;
        let compare_value = ahash(0u32);
        for pos in 0..size {
            let test_value = ahash(0 ^ (1u32 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
        let size = 64;
        let compare_value = ahash(0u64);
        for pos in 0..size {
            let test_value = ahash(0 ^ (1u64 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
        let size = 128;
        let compare_value = ahash(0u128);
        for pos in 0..size {
            let test_value = ahash(0 ^ (1u128 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
    }

    #[test]
    fn test_keys_change_output() {
        let mut a = AesHasher::new_with_keys(0, 0);
        let mut b = AesHasher::new_with_keys(0, 1);
        let mut c = AesHasher::new_with_keys(1, 0);
        let mut d = AesHasher::new_with_keys(1, 1);
        "test".hash(&mut a);
        "test".hash(&mut b);
        "test".hash(&mut c);
        "test".hash(&mut d);
        assert_sufficiently_different(a.finish(), b.finish());
        assert_sufficiently_different(a.finish(), c.finish());
        assert_sufficiently_different(a.finish(), d.finish());
        assert_sufficiently_different(b.finish(), c.finish());
        assert_sufficiently_different(b.finish(), d.finish());
        assert_sufficiently_different(c.finish(), d.finish());
    }

    #[test]
    fn test_finish_is_consistant() {
        let mut hasher = AesHasher::new_with_keys(1, 2);
        "Foo".hash(&mut hasher);
        let a = hasher.finish();
        let b = hasher.finish();
        assert_eq!(a, b);
    }

    #[test]
    fn test_single_key_bit_flip() {
        for bit in 0..64 {
            let mut a = AesHasher::new_with_keys(0, 0);
            let mut b = AesHasher::new_with_keys(0, 1 << bit);
            let mut c = AesHasher::new_with_keys(1 << bit, 0);
            "1234".hash(&mut a);
            "1234".hash(&mut b);
            "1234".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
            let mut a = AesHasher::new_with_keys(0, 0);
            let mut b = AesHasher::new_with_keys(0, 1 << bit);
            let mut c = AesHasher::new_with_keys(1 << bit, 0);
            "12345678".hash(&mut a);
            "12345678".hash(&mut b);
            "12345678".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
            let mut a = AesHasher::new_with_keys(0, 0);
            let mut b = AesHasher::new_with_keys(0, 1 << bit);
            let mut c = AesHasher::new_with_keys(1 << bit, 0);
            "1234567812345678".hash(&mut a);
            "1234567812345678".hash(&mut b);
            "1234567812345678".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
        }
    }

    #[test]
    fn test_padding_doesnot_collide() {
        for c in 0..128u8 {
            for string in ["", "1234", "12345678", "1234567812345678"].into_iter() {
                let mut short = AesHasher::default();
                string.hash(&mut short);
                let value = short.finish();
                let mut string = string.to_string();
                for num in 1..=128 {
                    let mut long = AesHasher::default();
                    string.push(c as char);
                    string.hash(&mut long);
                    let same_bytes = count_same_bytes(value, long.finish());
                    assert!(same_bytes <= 2, format!("{} bytes of {} -> {:x} vs {:x}", num, c, value, long.finish()));
                    let flipped_bits = (value ^ long.finish()).count_ones();
                    assert!(flipped_bits > 10);
                }
            }
        }
    }
}

fn assert_sufficiently_different(a: u64, b: u64) {
    let same_byte_count = count_same_bytes(a, b);
    assert!(same_byte_count <= 1);
    let flipped_bits = (a ^ b).count_ones();
    assert!(flipped_bits > 18 && flipped_bits < 48, "{:x} and {:x}: {:}", a, b, flipped_bits);
    for rotate in 0..64 {
        let flipped_bits2 = (a ^ (b.rotate_left(rotate))).count_ones();
        assert!(flipped_bits2 > 14 && flipped_bits2 < 50, "{:x} and {:x}: {:}", a, b.rotate_left(rotate), flipped_bits2);
    }
}

fn count_same_bytes(a: u64, b: u64) -> i32 {
    let mut same_byte_count = 0;
    for byte in 0..8 {
        let ba = a >> 8 * byte as u8;
        let bb = b >> 8 * byte as u8;
        if ba == bb {
            same_byte_count += 1;
        }
    }
    same_byte_count
}

#[cfg(test)]
mod fallback_tests {
    use std::hash::{Hash, Hasher};
    use crate::fallback_hash::*;
    use crate::hash_quality_test::*;

    pub fn fallback<H: Hash>(b: H) -> u64 {
        let mut hasher = FallbackHasher::new_with_keys(BAD_KEY, BAD_KEY);
        b.hash(&mut hasher);
        hasher.finish()
    }

    #[test]
    fn test_single_bit_flip() {
        let size = 32;
        let compare_value = fallback(0u32);
        for pos in 0..size {
            let test_value = fallback(0 ^ (1u32 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
        let size = 64;
        let compare_value = fallback(0u64);
        for pos in 0..size {
            let test_value = fallback(0 ^ (1u64 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
        let size = 128;
        let compare_value = fallback(0u128);
        for pos in 0..size {
            let test_value = fallback(0 ^ (1u128 << pos));
            assert_sufficiently_different(compare_value, test_value);
        }
    }

    #[test]
    fn test_keys_change_output() {
        let mut a = FallbackHasher::new_with_keys(0, 0);
        let mut b = FallbackHasher::new_with_keys(0, 1);
        let mut c = FallbackHasher::new_with_keys(1, 0);
        let mut d = FallbackHasher::new_with_keys(1, 1);
        "test".hash(&mut a);
        "test".hash(&mut b);
        "test".hash(&mut c);
        "test".hash(&mut d);
        assert_sufficiently_different(a.finish(), b.finish());
        assert_sufficiently_different(a.finish(), c.finish());
        assert_sufficiently_different(a.finish(), d.finish());
        assert_sufficiently_different(b.finish(), c.finish());
        assert_sufficiently_different(b.finish(), d.finish());
        assert_sufficiently_different(c.finish(), d.finish());
    }

    #[test]
    fn test_finish_is_consistant() {
        let mut hasher = FallbackHasher::new_with_keys(1, 2);
        "Foo".hash(&mut hasher);
        let a = hasher.finish();
        let b = hasher.finish();
        assert_eq!(a, b);
    }

    #[test]
    fn test_single_key_bit_flip() {
        for bit in 0..64 {
            let mut a = FallbackHasher::new_with_keys(0, 0);
            let mut b = FallbackHasher::new_with_keys(0, 1 << bit);
            let mut c = FallbackHasher::new_with_keys(1 << bit, 0);
            "1234".hash(&mut a);
            "1234".hash(&mut b);
            "1234".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
            let mut a = FallbackHasher::new_with_keys(0, 0);
            let mut b = FallbackHasher::new_with_keys(0, 1 << bit);
            let mut c = FallbackHasher::new_with_keys(1 << bit, 0);
            "12345678".hash(&mut a);
            "12345678".hash(&mut b);
            "12345678".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
            let mut a = FallbackHasher::new_with_keys(0, 0);
            let mut b = FallbackHasher::new_with_keys(0, 1 << bit);
            let mut c = FallbackHasher::new_with_keys(1 << bit, 0);
            "1234567812345678".hash(&mut a);
            "1234567812345678".hash(&mut b);
            "1234567812345678".hash(&mut c);
            assert_sufficiently_different(a.finish(), b.finish());
            assert_sufficiently_different(a.finish(), c.finish());
            assert_sufficiently_different(b.finish(), c.finish());
        }
    }

    #[test]
    fn test_padding_doesnot_collide() {
        for c in 0..128u8 {
            for string in ["", "1234", "12345678", "1234567812345678"].into_iter() {
                let mut short = FallbackHasher::new_with_keys(BAD_KEY, BAD_KEY);
                string.hash(&mut short);
                let value = short.finish();
                let mut string = string.to_string();
                for num in 1..=128 {
                    let mut long = FallbackHasher::new_with_keys(BAD_KEY, BAD_KEY);
                    string.push(c as char);
                    string.hash(&mut long);
                    let same_bytes = count_same_bytes(value, long.finish());
                    assert!(same_bytes <= 2, format!("{} bytes of {} -> {:x} vs {:x}", num, c, value, long.finish()));
                    let flipped_bits = (value ^ long.finish()).count_ones();
                    assert!(flipped_bits > 10,
                            format!("Too few bits fliped {} -> {:x} vs {} -> {:x}", string, value, c, long.finish()));
                }
            }
        }
    }
}<|endoftext|>


<commit_before>use app::App;
use texture::Texture;
use transform::Transform;
use component::Component;
use component::Message;
use std::collections::BTreeMap;
use std::any::Any;
use std::any::TypeId;
use physics::nphysics2d::object::{RigidBody, RigidBodyHandle};
use physics::nphysics2d::math::Matrix;
use physics::nalgebra::{Rotation2, Vector2, Vector1};

pub struct GameObject {
    pub transform: Transform,
    pub texture: Texture,
    body: Option<RigidBodyHandle<f64>>,
    components: BTreeMap<i32, Box<Component>>,
    component_types: BTreeMap<i32, TypeId>, // Identical to components just stores their type instead.
}

impl GameObject {
    pub fn new(app: &mut App) -> GameObject {
        GameObject {
            transform: Transform::new(),
            components: BTreeMap::new(),
            component_types: BTreeMap::new(),
            texture: Texture::empty(app),
            body: None,
        }
    }

    pub fn update(&mut self, app: &mut App, delta_time: f64) {
        let message = &Message::Update { delta_time: delta_time };
        for key in self.components.keys().map(|x| *x).collect::<Vec<i32>>() {
            if let Some(mut component) = self.components.remove(&key) {
                component.receive_message(app, self, &message);
                self.components.insert(key, component);
            }
        }
    }

    pub fn component_indices(&self) -> Vec<i32> {
        self.components.keys().map(|x| *x).collect::<Vec<i32>>()
    }

    pub fn get_components_of_type<T>(&self) -> Vec<i32> where T: Component + 'static {
        self.component_types.iter().filter_map(|(k, v)| {
            if *v == TypeId::of::<T>() {Some(*k)}
            else {None}
        }).collect::<Vec<i32>>()
    }

    pub fn get_component(&mut self, index: i32) -> Option<&mut Box<Component>> {
        self.components.get_mut(&index)
    }

    pub fn add_component_at_index(&mut self, component: Box<Component>, index: i32) {
        self.components.insert(index, component);
    }

    pub fn add_component<T>(&mut self, component: T) -> i32 where T: Component + 'static {
        let new_key = self.components.keys().nth(0).unwrap_or(&1) - 1;
        self.component_types.insert(new_key, TypeId::of::<T>());
        self.components.insert(new_key, Box::new(component));
        new_key
    }

    pub fn set_rigid_body(&mut self, app: &mut App, rigid_body: RigidBody<f64>) {
        self.body = Some(app.world.add_rigid_body(rigid_body));
    }
}

pub fn copy_from_physics(game_object: &mut GameObject) {
    if let &Some(ref body_box) = &game_object.body {
        let body_borrow = body_box.borrow();
        *game_object.transform.mut_x() = body_borrow.position().translation.x;
        *game_object.transform.mut_y() = body_borrow.position().translation.y;
        let matrix = body_borrow.position().rotation.submatrix();
        let y = matrix.m12;
        let x = matrix.m11;
        *game_object.transform.mut_rotation() = y.atan2(x);
    }
}

pub fn copy_to_physics(game_object: &mut GameObject) {
    if let Some(ref mut body_box) = game_object.body {
        body_box.borrow_mut().set_transformation(Matrix::<f64> {
            rotation: Rotation2::new(Vector1 { x: *game_object.transform.rotation() }),
            translation: Vector2 {
                x: *game_object.transform.x(),
                y: *game_object.transform.y(),
            },
        });
    }
}
<commit_msg>Refactored components a bit<commit_after>use app::App;
use texture::Texture;
use transform::Transform;
use component::Component;
use component::Message;
use std::collections::BTreeMap;
use std::any::TypeId;
use physics::nphysics2d::object::{RigidBody, RigidBodyHandle};
use physics::nphysics2d::math::Matrix;
use physics::nalgebra::{Rotation2, Vector2, Vector1, Rotation};

pub struct GameObject {
    pub transform: Transform,
    pub texture: Texture,
    pub body: Option<RigidBodyHandle<f64>>,
    components: BTreeMap<i32, (Box<Component>, TypeId)>,
}

impl GameObject {
    pub fn new(app: &mut App) -> GameObject {
        GameObject {
            transform: Transform::new(),
            components: BTreeMap::new(),
            texture: Texture::empty(app),
            body: None,
        }
    }

    pub fn update(&mut self, app: &mut App, delta_time: f64) {
        let message = &Message::Update { delta_time: delta_time };
        for key in self.components.keys().map(|x| *x).collect::<Vec<i32>>() {
            if let Some((mut component, type_id)) = self.components.remove(&key) {
                component.receive_message(app, self, &message);
                self.components.insert(key, (component, type_id));
            }
        }
    }

    pub fn component_keys(&self) -> Vec<i32> {
        self.components.keys().map(|x| *x).collect::<Vec<i32>>()
    }

    pub fn component_keys_with_type<T>(&self) -> Vec<i32> where T: Component + 'static {
        self.components.iter().filter_map(|(k, &(_, type_id))| {
            if type_id == TypeId::of::<T>() {Some(*k)}
            else {None}
        }).collect::<Vec<i32>>()
    }

    pub fn component(&self, index: i32) -> Option<&(Box<Component>, TypeId)> {
        self.components.get(&index)
    }

    pub fn component_mut(&mut self, index: i32) -> Option<&mut (Box<Component>, TypeId)> {
        self.components.get_mut(&index)
    }

    pub fn insert_component<T>(&mut self, component: T, index: i32)
    -> Option<(Box<Component + 'static>, TypeId)>
    where T: Component + 'static {
        self.components.insert(index, (Box::new(component), TypeId::of::<T>()))
    }

    pub fn add_component<T>(&mut self, component: T) -> i32 where T: Component + 'static {
        let new_key = self.components.keys().map(|x| *x).nth(0).unwrap_or(1) - 1;
        self.components.insert(new_key, (Box::new(component), TypeId::of::<T>()));
        new_key
    }

    pub fn set_rigid_body(&mut self, app: &mut App, rigid_body: RigidBody<f64>) {
        self.body = Some(app.world.add_rigid_body(rigid_body));
    }
}

pub fn copy_from_physics(game_object: &mut GameObject) {
    if let &Some(ref body_box) = &game_object.body {
        let body_borrow = body_box.borrow();
        *game_object.transform.mut_x() = body_borrow.position().translation.x;
        *game_object.transform.mut_y() = body_borrow.position().translation.y;
        *game_object.transform.mut_rotation() = body_borrow.position().rotation.rotation().x
    }
}

pub fn copy_to_physics(game_object: &mut GameObject) {
    if let Some(ref mut body_box) = game_object.body {
        body_box.borrow_mut().set_transformation(Matrix::<f64> {
            rotation: Rotation2::new(Vector1 { x: *game_object.transform.rotation() }),
            translation: Vector2 {
                x: *game_object.transform.x(),
                y: *game_object.transform.y(),
            },
        });
    }
}
<|endoftext|>


<commit_before>use super::{RemoteService, ScoreParser, SeriesEntry, SeriesInfo};
use crate::err::{self, Result};

#[derive(Default)]
pub struct Offline;

impl Offline {
    pub fn new() -> Offline {
        Offline {}
    }
}

impl RemoteService for Offline {
    fn search_info_by_name(&self, _: &str) -> Result<Vec<SeriesInfo>> {
        Err(err::Error::NeedExistingSeriesData)
    }

    fn search_info_by_id(&self, _: u32) -> Result<SeriesInfo> {
        Err(err::Error::NeedExistingSeriesData)
    }

    fn get_list_entry(&self, _: u32) -> Result<Option<SeriesEntry>> {
        Ok(None)
    }

    fn update_list_entry(&self, _: &SeriesEntry) -> Result<()> {
        Ok(())
    }

    fn is_offline(&self) -> bool {
        true
    }
}

impl ScoreParser for Offline {}
<commit_msg>anime: add documentation for remote::offline module<commit_after>use super::{RemoteService, ScoreParser, SeriesEntry, SeriesInfo};
use crate::err::{self, Result};

/// A remote service that will not connect to the internet.
///
/// This service is intended to make it easier to implement an offline mode
/// for your application by letting you seamlessly switch between online and offline
/// modes.
///
/// Note that the `search_info_by_name` and `search_info_by_id` methods will always
/// return an error with the variant `NeedExistingSeriesData`. All other methods simply
/// do nothing.
#[derive(Default)]
pub struct Offline;

impl Offline {
    pub fn new() -> Offline {
        Offline {}
    }
}

impl RemoteService for Offline {
    fn search_info_by_name(&self, _: &str) -> Result<Vec<SeriesInfo>> {
        Err(err::Error::NeedExistingSeriesData)
    }

    fn search_info_by_id(&self, _: u32) -> Result<SeriesInfo> {
        Err(err::Error::NeedExistingSeriesData)
    }

    fn get_list_entry(&self, _: u32) -> Result<Option<SeriesEntry>> {
        Ok(None)
    }

    fn update_list_entry(&self, _: &SeriesEntry) -> Result<()> {
        Ok(())
    }

    fn is_offline(&self) -> bool {
        true
    }
}

impl ScoreParser for Offline {}
<|endoftext|>


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

extern crate test;

#[macro_use]
extern crate time_steward;

#[macro_use]
extern crate glium;

extern crate nalgebra;
extern crate rustc_serialize;
extern crate docopt;

use test::Bencher;

use time_steward::{TimeSteward, TimeStewardFromConstants, DeterministicRandomId};

use time_steward::stewards::amortized;

#[path = "../dev-shared/bouncy_circles.rs"] mod bouncy_circles;
use bouncy_circles::*;

#[bench]
fn bouncy_circles_straightforward(bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
  })
}

#[bench]
fn bouncy_circles_disturbed (bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    for index in 1..10 {
      steward.insert_fiat_event (index*SECOND/10, DeterministicRandomId::new (& index), Disturb::new ([ARENA_SIZE/3,ARENA_SIZE/3])).unwrap();
    }
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
  })
}
<commit_msg>Added another benchmark, which I think I caught breaking an invariant.<commit_after>#![feature (test)]
#![feature (plugin, custom_derive)]
#![plugin (serde_macros)]

extern crate test;

#[macro_use]
extern crate time_steward;

#[macro_use]
extern crate glium;

extern crate nalgebra;
extern crate rustc_serialize;
extern crate docopt;

use test::Bencher;

use time_steward::{TimeSteward, TimeStewardFromConstants, DeterministicRandomId};

use time_steward::stewards::amortized;

#[path = "../dev-shared/bouncy_circles.rs"] mod bouncy_circles;
use bouncy_circles::*;

#[bench]
fn bouncy_circles_straightforward(bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
  })
}

#[bench]
fn bouncy_circles_disturbed (bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    for index in 1..10 {
      steward.insert_fiat_event (index*SECOND/10, DeterministicRandomId::new (& index), Disturb::new ([ARENA_SIZE/3,ARENA_SIZE/3])).unwrap();
    }
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
  })
}

#[bench]
fn bouncy_circles_disturbed_retroactive (bencher: &mut Bencher) {
  bencher.iter(|| {
    let mut steward: amortized::Steward<Basics> = amortized::Steward::from_constants(());
    steward.insert_fiat_event(0, DeterministicRandomId::new(&0), Initialize::new()).unwrap();
    steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
    for index in 1..10 {
      steward.insert_fiat_event (index*SECOND/10, DeterministicRandomId::new (& index), Disturb::new ([ARENA_SIZE/3,ARENA_SIZE/3])).unwrap();
      steward.snapshot_before(& SECOND).expect("steward failed to provide snapshot");
    }
  })
}
<|endoftext|>


<commit_before>//! Handle syntactic aspects of inserting a new `use`.
use std::cmp::Ordering;

use hir::Semantics;
use syntax::{
    algo,
    ast::{self, make, AstNode, PathSegmentKind},
    ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
};

use crate::{
    helpers::merge_imports::{try_merge_imports, use_tree_path_cmp, MergeBehavior},
    RootDatabase,
};

pub use hir::PrefixKind;

/// How imports should be grouped into use statements.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ImportGranularity {
    /// Do not change the granularity of any imports and preserve the original structure written by the developer.
    Preserve,
    /// Merge imports from the same crate into a single use statement.
    Crate,
    /// Merge imports from the same module into a single use statement.
    Module,
    /// Flatten imports so that each has its own use statement.
    Item,
}

impl ImportGranularity {
    pub fn merge_behavior(self) -> Option<MergeBehavior> {
        match self {
            ImportGranularity::Crate => Some(MergeBehavior::Crate),
            ImportGranularity::Module => Some(MergeBehavior::Module),
            ImportGranularity::Preserve | ImportGranularity::Item => None,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct InsertUseConfig {
    pub granularity: ImportGranularity,
    pub prefix_kind: PrefixKind,
    pub group: bool,
}

#[derive(Debug, Clone)]
pub enum ImportScope {
    File(ast::SourceFile),
    Module(ast::ItemList),
}

impl ImportScope {
    pub fn from(syntax: SyntaxNode) -> Option<Self> {
        if let Some(module) = ast::Module::cast(syntax.clone()) {
            module.item_list().map(ImportScope::Module)
        } else if let this @ Some(_) = ast::SourceFile::cast(syntax.clone()) {
            this.map(ImportScope::File)
        } else {
            ast::ItemList::cast(syntax).map(ImportScope::Module)
        }
    }

    /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
    pub fn find_insert_use_container_with_macros(
        position: &SyntaxNode,
        sema: &Semantics<'_, RootDatabase>,
    ) -> Option<Self> {
        sema.ancestors_with_macros(position.clone()).find_map(Self::from)
    }

    /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
    pub fn find_insert_use_container(position: &SyntaxNode) -> Option<Self> {
        std::iter::successors(Some(position.clone()), SyntaxNode::parent).find_map(Self::from)
    }

    pub fn as_syntax_node(&self) -> &SyntaxNode {
        match self {
            ImportScope::File(file) => file.syntax(),
            ImportScope::Module(item_list) => item_list.syntax(),
        }
    }

    pub fn clone_for_update(&self) -> Self {
        match self {
            ImportScope::File(file) => ImportScope::File(file.clone_for_update()),
            ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()),
        }
    }
}

/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) {
    let _p = profile::span("insert_use");
    let use_item =
        make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
    // merge into existing imports if possible
    if let Some(mb) = cfg.granularity.merge_behavior() {
        for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) {
            if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
                ted::replace(existing_use.syntax(), merged.syntax());
                return;
            }
        }
    }

    // either we weren't allowed to merge or there is no import that fits the merge conditions
    // so look for the place we have to insert to
    insert_use_(scope, path, cfg.group, use_item);
}

#[derive(Eq, PartialEq, PartialOrd, Ord)]
enum ImportGroup {
    // the order here defines the order of new group inserts
    Std,
    ExternCrate,
    ThisCrate,
    ThisModule,
    SuperModule,
}

impl ImportGroup {
    fn new(path: &ast::Path) -> ImportGroup {
        let default = ImportGroup::ExternCrate;

        let first_segment = match path.first_segment() {
            Some(it) => it,
            None => return default,
        };

        let kind = first_segment.kind().unwrap_or(PathSegmentKind::SelfKw);
        match kind {
            PathSegmentKind::SelfKw => ImportGroup::ThisModule,
            PathSegmentKind::SuperKw => ImportGroup::SuperModule,
            PathSegmentKind::CrateKw => ImportGroup::ThisCrate,
            PathSegmentKind::Name(name) => match name.text().as_str() {
                "std" => ImportGroup::Std,
                "core" => ImportGroup::Std,
                _ => ImportGroup::ExternCrate,
            },
            PathSegmentKind::Type { .. } => unreachable!(),
        }
    }
}

fn insert_use_(
    scope: &ImportScope,
    insert_path: ast::Path,
    group_imports: bool,
    use_item: ast::Use,
) {
    let scope_syntax = scope.as_syntax_node();
    let group = ImportGroup::new(&insert_path);
    let path_node_iter = scope_syntax
        .children()
        .filter_map(|node| ast::Use::cast(node.clone()).zip(Some(node)))
        .flat_map(|(use_, node)| {
            let tree = use_.use_tree()?;
            let path = tree.path()?;
            let has_tl = tree.use_tree_list().is_some();
            Some((path, has_tl, node))
        });

    if !group_imports {
        if let Some((_, _, node)) = path_node_iter.last() {
            cov_mark::hit!(insert_no_grouping_last);
            ted::insert(ted::Position::after(node), use_item.syntax());
        } else {
            cov_mark::hit!(insert_no_grouping_last2);
            ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
            ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
        }
        return;
    }

    // Iterator that discards anything thats not in the required grouping
    // This implementation allows the user to rearrange their import groups as this only takes the first group that fits
    let group_iter = path_node_iter
        .clone()
        .skip_while(|(path, ..)| ImportGroup::new(path) != group)
        .take_while(|(path, ..)| ImportGroup::new(path) == group);

    // track the last element we iterated over, if this is still None after the iteration then that means we never iterated in the first place
    let mut last = None;
    // find the element that would come directly after our new import
    let post_insert: Option<(_, _, SyntaxNode)> = group_iter
        .inspect(|(.., node)| last = Some(node.clone()))
        .find(|&(ref path, has_tl, _)| {
            use_tree_path_cmp(&insert_path, false, path, has_tl) != Ordering::Greater
        });

    if let Some((.., node)) = post_insert {
        cov_mark::hit!(insert_group);
        // insert our import before that element
        return ted::insert(ted::Position::before(node), use_item.syntax());
    }
    if let Some(node) = last {
        cov_mark::hit!(insert_group_last);
        // there is no element after our new import, so append it to the end of the group
        return ted::insert(ted::Position::after(node), use_item.syntax());
    }

    // the group we were looking for actually doesn't exist, so insert

    let mut last = None;
    // find the group that comes after where we want to insert
    let post_group = path_node_iter
        .inspect(|(.., node)| last = Some(node.clone()))
        .find(|(p, ..)| ImportGroup::new(p) > group);
    if let Some((.., node)) = post_group {
        cov_mark::hit!(insert_group_new_group);
        ted::insert(ted::Position::before(&node), use_item.syntax());
        if let Some(node) = algo::non_trivia_sibling(node.into(), Direction::Prev) {
            ted::insert(ted::Position::after(node), make::tokens::single_newline());
        }
        return;
    }
    // there is no such group, so append after the last one
    if let Some(node) = last {
        cov_mark::hit!(insert_group_no_group);
        ted::insert(ted::Position::after(&node), use_item.syntax());
        ted::insert(ted::Position::after(node), make::tokens::single_newline());
        return;
    }
    // there are no imports in this file at all
    if let Some(last_inner_element) = scope_syntax
        .children_with_tokens()
        .filter(|child| match child {
            NodeOrToken::Node(node) => is_inner_attribute(node.clone()),
            NodeOrToken::Token(token) => is_inner_comment(token.clone()),
        })
        .last()
    {
        cov_mark::hit!(insert_group_empty_inner_attr);
        ted::insert(ted::Position::after(&last_inner_element), use_item.syntax());
        ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline());
        return;
    }
    match scope {
        ImportScope::File(_) => {
            cov_mark::hit!(insert_group_empty_file);
            ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
            ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax())
        }
        // don't insert the imports before the item list's opening curly brace
        ImportScope::Module(item_list) => match item_list.l_curly_token() {
            Some(b) => {
                cov_mark::hit!(insert_group_empty_module);
                ted::insert(ted::Position::after(&b), make::tokens::single_newline());
                ted::insert(ted::Position::after(&b), use_item.syntax());
            }
            None => {
                // This should never happens, broken module syntax node
                ted::insert(
                    ted::Position::first_child_of(scope_syntax),
                    make::tokens::blank_line(),
                );
                ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
            }
        },
    }
}

fn is_inner_attribute(node: SyntaxNode) -> bool {
    ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner)
}

fn is_inner_comment(token: SyntaxToken) -> bool {
    ast::Comment::cast(token).and_then(|comment| comment.kind().doc)
        == Some(ast::CommentPlacement::Inner)
}
#[cfg(test)]
mod tests;
<commit_msg>Implement import-granularity guessing<commit_after>//! Handle syntactic aspects of inserting a new `use`.
use std::cmp::Ordering;

use hir::Semantics;
use syntax::{
    algo,
    ast::{self, make, AstNode, ModuleItemOwner, PathSegmentKind},
    ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
};

use crate::{
    helpers::merge_imports::{try_merge_imports, use_tree_path_cmp, MergeBehavior},
    RootDatabase,
};

pub use hir::PrefixKind;

/// How imports should be grouped into use statements.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ImportGranularity {
    /// Do not change the granularity of any imports and preserve the original structure written by the developer.
    Preserve,
    /// Merge imports from the same crate into a single use statement.
    Crate,
    /// Merge imports from the same module into a single use statement.
    Module,
    /// Flatten imports so that each has its own use statement.
    Item,
}

impl ImportGranularity {
    pub fn merge_behavior(self) -> Option<MergeBehavior> {
        match self {
            ImportGranularity::Crate => Some(MergeBehavior::Crate),
            ImportGranularity::Module => Some(MergeBehavior::Module),
            ImportGranularity::Preserve | ImportGranularity::Item => None,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct InsertUseConfig {
    pub granularity: ImportGranularity,
    pub prefix_kind: PrefixKind,
    pub group: bool,
}

#[derive(Debug, Clone)]
pub enum ImportScope {
    File(ast::SourceFile),
    Module(ast::ItemList),
}

impl ImportScope {
    pub fn from(syntax: SyntaxNode) -> Option<Self> {
        if let Some(module) = ast::Module::cast(syntax.clone()) {
            module.item_list().map(ImportScope::Module)
        } else if let this @ Some(_) = ast::SourceFile::cast(syntax.clone()) {
            this.map(ImportScope::File)
        } else {
            ast::ItemList::cast(syntax).map(ImportScope::Module)
        }
    }

    /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
    pub fn find_insert_use_container_with_macros(
        position: &SyntaxNode,
        sema: &Semantics<'_, RootDatabase>,
    ) -> Option<Self> {
        sema.ancestors_with_macros(position.clone()).find_map(Self::from)
    }

    /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
    pub fn find_insert_use_container(position: &SyntaxNode) -> Option<Self> {
        std::iter::successors(Some(position.clone()), SyntaxNode::parent).find_map(Self::from)
    }

    pub fn as_syntax_node(&self) -> &SyntaxNode {
        match self {
            ImportScope::File(file) => file.syntax(),
            ImportScope::Module(item_list) => item_list.syntax(),
        }
    }

    pub fn clone_for_update(&self) -> Self {
        match self {
            ImportScope::File(file) => ImportScope::File(file.clone_for_update()),
            ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()),
        }
    }

    fn guess_merge_behavior_from_scope(&self) -> Option<MergeBehavior> {
        let use_stmt = |item| match item {
            ast::Item::Use(use_) => use_.use_tree(),
            _ => None,
        };
        let use_stmts = match self {
            ImportScope::File(f) => f.items(),
            ImportScope::Module(m) => m.items(),
        }
        .filter_map(use_stmt);
        let mut res = None;
        for tree in use_stmts {
            if let Some(list) = tree.use_tree_list() {
                if list.use_trees().any(|tree| tree.use_tree_list().is_some()) {
                    // double nested tree list, can only be a crate style import at this point
                    return Some(MergeBehavior::Crate);
                }
                // has to be at least a module style based import, might be crate style tho so look further
                res = Some(MergeBehavior::Module);
            }
        }
        res
    }
}

/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) {
    let _p = profile::span("insert_use");
    let mb = match cfg.granularity {
        ImportGranularity::Preserve => scope.guess_merge_behavior_from_scope(),
        ImportGranularity::Crate => Some(MergeBehavior::Crate),
        ImportGranularity::Module => Some(MergeBehavior::Module),
        ImportGranularity::Item => None,
    };

    let use_item =
        make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
    // merge into existing imports if possible
    if let Some(mb) = mb {
        for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) {
            if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
                ted::replace(existing_use.syntax(), merged.syntax());
                return;
            }
        }
    }

    // either we weren't allowed to merge or there is no import that fits the merge conditions
    // so look for the place we have to insert to
    insert_use_(scope, path, cfg.group, use_item);
}

#[derive(Eq, PartialEq, PartialOrd, Ord)]
enum ImportGroup {
    // the order here defines the order of new group inserts
    Std,
    ExternCrate,
    ThisCrate,
    ThisModule,
    SuperModule,
}

impl ImportGroup {
    fn new(path: &ast::Path) -> ImportGroup {
        let default = ImportGroup::ExternCrate;

        let first_segment = match path.first_segment() {
            Some(it) => it,
            None => return default,
        };

        let kind = first_segment.kind().unwrap_or(PathSegmentKind::SelfKw);
        match kind {
            PathSegmentKind::SelfKw => ImportGroup::ThisModule,
            PathSegmentKind::SuperKw => ImportGroup::SuperModule,
            PathSegmentKind::CrateKw => ImportGroup::ThisCrate,
            PathSegmentKind::Name(name) => match name.text().as_str() {
                "std" => ImportGroup::Std,
                "core" => ImportGroup::Std,
                _ => ImportGroup::ExternCrate,
            },
            PathSegmentKind::Type { .. } => unreachable!(),
        }
    }
}

fn insert_use_(
    scope: &ImportScope,
    insert_path: ast::Path,
    group_imports: bool,
    use_item: ast::Use,
) {
    let scope_syntax = scope.as_syntax_node();
    let group = ImportGroup::new(&insert_path);
    let path_node_iter = scope_syntax
        .children()
        .filter_map(|node| ast::Use::cast(node.clone()).zip(Some(node)))
        .flat_map(|(use_, node)| {
            let tree = use_.use_tree()?;
            let path = tree.path()?;
            let has_tl = tree.use_tree_list().is_some();
            Some((path, has_tl, node))
        });

    if !group_imports {
        if let Some((_, _, node)) = path_node_iter.last() {
            cov_mark::hit!(insert_no_grouping_last);
            ted::insert(ted::Position::after(node), use_item.syntax());
        } else {
            cov_mark::hit!(insert_no_grouping_last2);
            ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
            ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
        }
        return;
    }

    // Iterator that discards anything thats not in the required grouping
    // This implementation allows the user to rearrange their import groups as this only takes the first group that fits
    let group_iter = path_node_iter
        .clone()
        .skip_while(|(path, ..)| ImportGroup::new(path) != group)
        .take_while(|(path, ..)| ImportGroup::new(path) == group);

    // track the last element we iterated over, if this is still None after the iteration then that means we never iterated in the first place
    let mut last = None;
    // find the element that would come directly after our new import
    let post_insert: Option<(_, _, SyntaxNode)> = group_iter
        .inspect(|(.., node)| last = Some(node.clone()))
        .find(|&(ref path, has_tl, _)| {
            use_tree_path_cmp(&insert_path, false, path, has_tl) != Ordering::Greater
        });

    if let Some((.., node)) = post_insert {
        cov_mark::hit!(insert_group);
        // insert our import before that element
        return ted::insert(ted::Position::before(node), use_item.syntax());
    }
    if let Some(node) = last {
        cov_mark::hit!(insert_group_last);
        // there is no element after our new import, so append it to the end of the group
        return ted::insert(ted::Position::after(node), use_item.syntax());
    }

    // the group we were looking for actually doesn't exist, so insert

    let mut last = None;
    // find the group that comes after where we want to insert
    let post_group = path_node_iter
        .inspect(|(.., node)| last = Some(node.clone()))
        .find(|(p, ..)| ImportGroup::new(p) > group);
    if let Some((.., node)) = post_group {
        cov_mark::hit!(insert_group_new_group);
        ted::insert(ted::Position::before(&node), use_item.syntax());
        if let Some(node) = algo::non_trivia_sibling(node.into(), Direction::Prev) {
            ted::insert(ted::Position::after(node), make::tokens::single_newline());
        }
        return;
    }
    // there is no such group, so append after the last one
    if let Some(node) = last {
        cov_mark::hit!(insert_group_no_group);
        ted::insert(ted::Position::after(&node), use_item.syntax());
        ted::insert(ted::Position::after(node), make::tokens::single_newline());
        return;
    }
    // there are no imports in this file at all
    if let Some(last_inner_element) = scope_syntax
        .children_with_tokens()
        .filter(|child| match child {
            NodeOrToken::Node(node) => is_inner_attribute(node.clone()),
            NodeOrToken::Token(token) => is_inner_comment(token.clone()),
        })
        .last()
    {
        cov_mark::hit!(insert_group_empty_inner_attr);
        ted::insert(ted::Position::after(&last_inner_element), use_item.syntax());
        ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline());
        return;
    }
    match scope {
        ImportScope::File(_) => {
            cov_mark::hit!(insert_group_empty_file);
            ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
            ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax())
        }
        // don't insert the imports before the item list's opening curly brace
        ImportScope::Module(item_list) => match item_list.l_curly_token() {
            Some(b) => {
                cov_mark::hit!(insert_group_empty_module);
                ted::insert(ted::Position::after(&b), make::tokens::single_newline());
                ted::insert(ted::Position::after(&b), use_item.syntax());
            }
            None => {
                // This should never happens, broken module syntax node
                ted::insert(
                    ted::Position::first_child_of(scope_syntax),
                    make::tokens::blank_line(),
                );
                ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
            }
        },
    }
}

fn is_inner_attribute(node: SyntaxNode) -> bool {
    ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner)
}

fn is_inner_comment(token: SyntaxToken) -> bool {
    ast::Comment::cast(token).and_then(|comment| comment.kind().doc)
        == Some(ast::CommentPlacement::Inner)
}
#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>use super::SeriesParams;
use crate::config::Config;
use crate::database::schema::series_configs;
use crate::database::{self, Database};
use crate::err::{Error, Result};
use anime::local::EpisodeMatcher;
use diesel::prelude::*;
use std::borrow::Cow;
use std::path::{Path, PathBuf};

#[derive(Clone, Debug, Queryable, Insertable)]
pub struct SeriesConfig {
    pub id: i32,
    pub nickname: String,
    path: database::Path,
    pub episode_matcher: EpisodeMatcher,
    pub player_args: database::PlayerArgs,
}

impl SeriesConfig {
    pub fn from_params<S, C>(
        nickname: S,
        id: i32,
        path: C,
        params: SeriesParams,
        config: &Config,
        db: &Database,
    ) -> Result<Self>
    where
        S: Into<String>,
        C: Into<PathBuf>,
    {
        if let Some(existing) = Self::exists(db, id) {
            return Err(Error::SeriesAlreadyExists { name: existing });
        }

        let nickname = nickname.into();

        let path = {
            let source = params.path.unwrap_or_else(|| path.into());
            config.stripped_path(source)
        };

        let episode_matcher = match params.matcher {
            Some(pattern) => super::episode_matcher_with_pattern(pattern)?,
            None => EpisodeMatcher::default(),
        };

        Ok(Self {
            id,
            nickname,
            path: path.into(),
            episode_matcher,
            player_args: database::PlayerArgs::new(),
        })
    }

    pub fn save(&self, db: &Database) -> diesel::QueryResult<usize> {
        use crate::database::schema::series_configs::dsl::*;

        diesel::replace_into(series_configs)
            .values(self)
            .execute(db.conn())
    }

    pub fn delete_by_name<S>(db: &Database, name: S) -> diesel::QueryResult<usize>
    where
        S: AsRef<str>,
    {
        use crate::database::schema::series_configs::dsl::*;

        let name = name.as_ref();

        diesel::delete(series_configs.filter(nickname.eq(name))).execute(db.conn())
    }

    pub fn load_all(db: &Database) -> diesel::QueryResult<Vec<Self>> {
        use crate::database::schema::series_configs::dsl::*;

        series_configs.load(db.conn())
    }

    pub fn load_by_name<S>(db: &Database, name: S) -> diesel::QueryResult<Self>
    where
        S: AsRef<str>,
    {
        use crate::database::schema::series_configs::dsl::*;

        series_configs
            .filter(nickname.eq(name.as_ref()))
            .get_result(db.conn())
    }

    pub fn exists(db: &Database, config_id: i32) -> Option<String> {
        use crate::database::schema::series_configs::dsl::*;

        series_configs
            .filter(id.eq(config_id))
            .select(nickname)
            .get_result(db.conn())
            .ok()
    }

    pub fn full_path(&self, config: &Config) -> Cow<PathBuf> {
        if self.path.is_relative() {
            Cow::Owned(config.series_dir.join(self.path.as_ref()))
        } else {
            Cow::Borrowed(&self.path)
        }
    }

    pub fn set_path<'a, P>(&mut self, path: P, config: &Config)
    where
        P: Into<Cow<'a, Path>>,
    {
        self.path = config.stripped_path(path).into();
    }

    /// Applies the supplied `SeriesParams` to the `SeriesConfig`.
    /// Returns a bool indicating whether or not anything was changed.
    pub fn apply_params(
        &mut self,
        params: &SeriesParams,
        config: &Config,
        db: &Database,
    ) -> Result<bool> {
        let mut any_changed = false;

        if let Some(id) = params.id {
            if let Some(existing) = Self::exists(db, id) {
                return Err(Error::SeriesAlreadyExists { name: existing });
            }

            self.id = id;
            any_changed = true;
        }

        if let Some(path) = &params.path {
            self.set_path(path, config);
            any_changed = true;
        }

        if let Some(pattern) = &params.matcher {
            self.episode_matcher = if !pattern.is_empty() {
                super::episode_matcher_with_pattern(pattern)?
            } else {
                EpisodeMatcher::default()
            };

            any_changed = true;
        }

        Ok(any_changed)
    }
}

impl PartialEq<String> for SeriesConfig {
    fn eq(&self, nickname: &String) -> bool {
        self.nickname == *nickname
    }
}

impl<'a> Into<Cow<'a, Self>> for SeriesConfig {
    fn into(self) -> Cow<'a, Self> {
        Cow::Owned(self)
    }
}

impl<'a> Into<Cow<'a, SeriesConfig>> for &'a SeriesConfig {
    fn into(self) -> Cow<'a, SeriesConfig> {
        Cow::Borrowed(self)
    }
}
<commit_msg>anup: remove unused Into<Cow> impl's for SeriesConfig<commit_after>use super::SeriesParams;
use crate::config::Config;
use crate::database::schema::series_configs;
use crate::database::{self, Database};
use crate::err::{Error, Result};
use anime::local::EpisodeMatcher;
use diesel::prelude::*;
use std::borrow::Cow;
use std::path::{Path, PathBuf};

#[derive(Clone, Debug, Queryable, Insertable)]
pub struct SeriesConfig {
    pub id: i32,
    pub nickname: String,
    path: database::Path,
    pub episode_matcher: EpisodeMatcher,
    pub player_args: database::PlayerArgs,
}

impl SeriesConfig {
    pub fn from_params<S, C>(
        nickname: S,
        id: i32,
        path: C,
        params: SeriesParams,
        config: &Config,
        db: &Database,
    ) -> Result<Self>
    where
        S: Into<String>,
        C: Into<PathBuf>,
    {
        if let Some(existing) = Self::exists(db, id) {
            return Err(Error::SeriesAlreadyExists { name: existing });
        }

        let nickname = nickname.into();

        let path = {
            let source = params.path.unwrap_or_else(|| path.into());
            config.stripped_path(source)
        };

        let episode_matcher = match params.matcher {
            Some(pattern) => super::episode_matcher_with_pattern(pattern)?,
            None => EpisodeMatcher::default(),
        };

        Ok(Self {
            id,
            nickname,
            path: path.into(),
            episode_matcher,
            player_args: database::PlayerArgs::new(),
        })
    }

    pub fn save(&self, db: &Database) -> diesel::QueryResult<usize> {
        use crate::database::schema::series_configs::dsl::*;

        diesel::replace_into(series_configs)
            .values(self)
            .execute(db.conn())
    }

    pub fn delete_by_name<S>(db: &Database, name: S) -> diesel::QueryResult<usize>
    where
        S: AsRef<str>,
    {
        use crate::database::schema::series_configs::dsl::*;

        let name = name.as_ref();

        diesel::delete(series_configs.filter(nickname.eq(name))).execute(db.conn())
    }

    pub fn load_all(db: &Database) -> diesel::QueryResult<Vec<Self>> {
        use crate::database::schema::series_configs::dsl::*;

        series_configs.load(db.conn())
    }

    pub fn load_by_name<S>(db: &Database, name: S) -> diesel::QueryResult<Self>
    where
        S: AsRef<str>,
    {
        use crate::database::schema::series_configs::dsl::*;

        series_configs
            .filter(nickname.eq(name.as_ref()))
            .get_result(db.conn())
    }

    pub fn exists(db: &Database, config_id: i32) -> Option<String> {
        use crate::database::schema::series_configs::dsl::*;

        series_configs
            .filter(id.eq(config_id))
            .select(nickname)
            .get_result(db.conn())
            .ok()
    }

    pub fn full_path(&self, config: &Config) -> Cow<PathBuf> {
        if self.path.is_relative() {
            Cow::Owned(config.series_dir.join(self.path.as_ref()))
        } else {
            Cow::Borrowed(&self.path)
        }
    }

    pub fn set_path<'a, P>(&mut self, path: P, config: &Config)
    where
        P: Into<Cow<'a, Path>>,
    {
        self.path = config.stripped_path(path).into();
    }

    /// Applies the supplied `SeriesParams` to the `SeriesConfig`.
    /// Returns a bool indicating whether or not anything was changed.
    pub fn apply_params(
        &mut self,
        params: &SeriesParams,
        config: &Config,
        db: &Database,
    ) -> Result<bool> {
        let mut any_changed = false;

        if let Some(id) = params.id {
            if let Some(existing) = Self::exists(db, id) {
                return Err(Error::SeriesAlreadyExists { name: existing });
            }

            self.id = id;
            any_changed = true;
        }

        if let Some(path) = &params.path {
            self.set_path(path, config);
            any_changed = true;
        }

        if let Some(pattern) = &params.matcher {
            self.episode_matcher = if !pattern.is_empty() {
                super::episode_matcher_with_pattern(pattern)?
            } else {
                EpisodeMatcher::default()
            };

            any_changed = true;
        }

        Ok(any_changed)
    }
}

impl PartialEq<String> for SeriesConfig {
    fn eq(&self, nickname: &String) -> bool {
        self.nickname == *nickname
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// 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.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, Field, Ident, Type};

use crate::{
    attrs::{Attrs, Kind, ParserKind},
    utils::{sub_type, subty_if_name, Sp, Ty},
};

pub fn gen_for_struct(
    struct_name: &Ident,
    fields: &Punctuated<Field, Comma>,
    parent_attribute: &Attrs,
) -> TokenStream {
    let constructor = gen_constructor(fields, parent_attribute);
    let updater = gen_updater(fields, parent_attribute, true);

    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::FromArgMatches for #struct_name {
            fn from_arg_matches(arg_matches: &::clap::ArgMatches) -> Self {
                #struct_name #constructor
            }

            fn update_from_arg_matches(&mut self, arg_matches: &::clap::ArgMatches) {
                #updater
            }
        }
    }
}

pub fn gen_for_enum(name: &Ident) -> TokenStream {
    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::FromArgMatches for #name {
            fn from_arg_matches(arg_matches: &::clap::ArgMatches) -> Self {
                <#name as ::clap::Subcommand>::from_subcommand(arg_matches.subcommand()).unwrap()
            }
            fn update_from_arg_matches(&mut self, arg_matches: &::clap::ArgMatches) {
                <#name as ::clap::Subcommand>::update_from_subcommand(self, arg_matches.subcommand());
            }
        }
    }
}

fn gen_arg_enum_parse(ty: &Type, attrs: &Attrs) -> TokenStream {
    let ci = attrs.case_insensitive();

    quote_spanned! { ty.span()=>
        |s| <#ty as ::clap::ArgEnum>::from_str(s, #ci).unwrap()
    }
}

fn gen_parsers(
    attrs: &Attrs,
    ty: &Sp<Ty>,
    field_name: &Ident,
    field: &Field,
    update: Option<&TokenStream>,
) -> TokenStream {
    use self::ParserKind::*;

    let parser = attrs.parser();
    let func = &parser.func;
    let span = parser.kind.span();
    let (value_of, values_of, mut parse) = match *parser.kind {
        FromStr => (
            quote_spanned!(span=> value_of),
            quote_spanned!(span=> values_of),
            func.clone(),
        ),
        TryFromStr => (
            quote_spanned!(span=> value_of),
            quote_spanned!(span=> values_of),
            quote_spanned!(func.span()=> |s| #func(s).unwrap()),
        ),
        FromOsStr => (
            quote_spanned!(span=> value_of_os),
            quote_spanned!(span=> values_of_os),
            func.clone(),
        ),
        TryFromOsStr => (
            quote_spanned!(span=> value_of_os),
            quote_spanned!(span=> values_of_os),
            quote_spanned!(func.span()=> |s| #func(s).unwrap()),
        ),
        FromOccurrences => (
            quote_spanned!(span=> occurrences_of),
            quote!(),
            func.clone(),
        ),
        FromFlag => (quote!(), quote!(), func.clone()),
    };

    let flag = *attrs.parser().kind == ParserKind::FromFlag;
    let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
    let name = attrs.cased_name();

    let field_value = match **ty {
        Ty::Bool => {
            if update.is_some() {
                quote_spanned! { ty.span()=>
                    *#field_name || arg_matches.is_present(#name)
                }
            } else {
                quote_spanned! { ty.span()=>
                    arg_matches.is_present(#name)
                }
            }
        }

        Ty::Option => {
            if attrs.is_enum() {
                if let Some(subty) = subty_if_name(&field.ty, "Option") {
                    parse = gen_arg_enum_parse(subty, &attrs);
                }
            }

            quote_spanned! { ty.span()=>
                arg_matches.#value_of(#name)
                    .map(#parse)
            }
        }

        Ty::OptionOption => quote_spanned! { ty.span()=>
            if arg_matches.is_present(#name) {
                Some(arg_matches.#value_of(#name).map(#parse))
            } else {
                None
            }
        },

        Ty::OptionVec => quote_spanned! { ty.span()=>
            if arg_matches.is_present(#name) {
                Some(arg_matches.#values_of(#name)
                     .map(|v| v.map(#parse).collect())
                     .unwrap_or_else(Vec::new))
            } else {
                None
            }
        },

        Ty::Vec => {
            if attrs.is_enum() {
                if let Some(subty) = subty_if_name(&field.ty, "Vec") {
                    parse = gen_arg_enum_parse(subty, &attrs);
                }
            }

            quote_spanned! { ty.span()=>
                arg_matches.#values_of(#name)
                    .map(|v| v.map(#parse).collect())
                    .unwrap_or_else(Vec::new)
            }
        }

        Ty::Other if occurrences => quote_spanned! { ty.span()=>
            #parse(arg_matches.#value_of(#name))
        },

        Ty::Other if flag => quote_spanned! { ty.span()=>
            #parse(arg_matches.is_present(#name))
        },

        Ty::Other => {
            if attrs.is_enum() {
                parse = gen_arg_enum_parse(&field.ty, &attrs);
            }

            quote_spanned! { ty.span()=>
                arg_matches.#value_of(#name)
                    .map(#parse)
                    .unwrap()
            }
        }
    };

    if let Some(access) = update {
        quote_spanned! { field.span()=>
            if arg_matches.is_present(#name) {
                #access
                *#field_name = #field_value
            }
        }
    } else {
        quote_spanned!(field.span()=> #field_name: #field_value )
    }
}

pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
    let fields = fields.iter().map(|field| {
        let attrs = Attrs::from_field(
            field,
            parent_attribute.casing(),
            parent_attribute.env_casing(),
        );
        let field_name = field.ident.as_ref().unwrap();
        let kind = attrs.kind();
        match &*kind {
            Kind::ExternalSubcommand => {
                abort! { kind.span(),
                    "`external_subcommand` can be used only on enum variants"
                }
            }
            Kind::Subcommand(ty) => {
                let subcmd_type = match (**ty, sub_type(&field.ty)) {
                    (Ty::Option, Some(sub_type)) => sub_type,
                    _ => &field.ty,
                };
                let unwrapper = match **ty {
                    Ty::Option => quote!(),
                    _ => quote_spanned!( ty.span()=> .unwrap() ),
                };
                quote_spanned! { kind.span()=>
                    #field_name: {
                        <#subcmd_type as ::clap::Subcommand>::from_subcommand(arg_matches.subcommand())
                        #unwrapper
                    }
                }
            }

            Kind::Flatten => quote_spanned! { kind.span()=>
                #field_name: ::clap::FromArgMatches::from_arg_matches(arg_matches)
            },

            Kind::Skip(val) => match val {
                None => quote_spanned!(kind.span()=> #field_name: Default::default()),
                Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
            },

            Kind::Arg(ty) => gen_parsers(&attrs, ty, field_name, field, None),
        }
    });

    quote! {{
        #( #fields ),*
    }}
}

pub fn gen_updater(
    fields: &Punctuated<Field, Comma>,
    parent_attribute: &Attrs,
    use_self: bool,
) -> TokenStream {
    let fields = fields.iter().map(|field| {
        let attrs = Attrs::from_field(
            field,
            parent_attribute.casing(),
            parent_attribute.env_casing(),
        );
        let field_name = field.ident.as_ref().unwrap();
        let kind = attrs.kind();

        let access = if use_self {
            quote! {
                #[allow(non_snake_case)]
                let #field_name = &mut self.#field_name;
            }
        } else {
            quote!()
        };

        match &*kind {
            Kind::ExternalSubcommand => {
                abort! { kind.span(),
                    "`external_subcommand` can be used only on enum variants"
                }
            }
            Kind::Subcommand(ty) => {
                let subcmd_type = match (**ty, sub_type(&field.ty)) {
                    (Ty::Option, Some(sub_type)) => sub_type,
                    _ => &field.ty,
                };

                let updater = quote_spanned!{ ty.span()=>
                    <#subcmd_type as ::clap::Subcommand>::update_from_subcommand(#field_name, subcmd);
                };

                let updater = match **ty {
                    Ty::Option => quote_spanned! { kind.span()=>
                        if let Some(#field_name) = #field_name.as_mut() {
                            #updater
                        } else {
                            *#field_name = <#subcmd_type as ::clap::Subcommand>::from_subcommand(
                                subcmd
                            )
                        }
                    },
                    _ => quote_spanned!{ kind.span()=>
                        #updater
                    }
                };

                quote_spanned! { kind.span()=>
                    {
                        let subcmd = arg_matches.subcommand();
                        #access
                        #updater
                    }
                }
            }

            Kind::Flatten => quote_spanned! { kind.span()=> {
                    #access
                    ::clap::FromArgMatches::update_from_arg_matches(#field_name, arg_matches);
                }
            },

            Kind::Skip(_) => quote!(),

            Kind::Arg(ty) => {
                gen_parsers(&attrs, ty, field_name, field, Some(&access))
            }
        }
    });

    quote! {
        #( #fields )*
    }
}
<commit_msg>Fix hygiene of `arg_matches` parameter<commit_after>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// 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.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, Field, Ident, Type};

use crate::{
    attrs::{Attrs, Kind, ParserKind},
    utils::{sub_type, subty_if_name, Sp, Ty},
};

pub fn gen_for_struct(
    struct_name: &Ident,
    fields: &Punctuated<Field, Comma>,
    parent_attribute: &Attrs,
) -> TokenStream {
    let constructor = gen_constructor(fields, parent_attribute);
    let updater = gen_updater(fields, parent_attribute, true);

    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::FromArgMatches for #struct_name {
            fn from_arg_matches(arg_matches: &::clap::ArgMatches) -> Self {
                #struct_name #constructor
            }

            fn update_from_arg_matches(&mut self, arg_matches: &::clap::ArgMatches) {
                #updater
            }
        }
    }
}

pub fn gen_for_enum(name: &Ident) -> TokenStream {
    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::FromArgMatches for #name {
            fn from_arg_matches(arg_matches: &::clap::ArgMatches) -> Self {
                <#name as ::clap::Subcommand>::from_subcommand(arg_matches.subcommand()).unwrap()
            }
            fn update_from_arg_matches(&mut self, arg_matches: &::clap::ArgMatches) {
                <#name as ::clap::Subcommand>::update_from_subcommand(self, arg_matches.subcommand());
            }
        }
    }
}

fn gen_arg_enum_parse(ty: &Type, attrs: &Attrs) -> TokenStream {
    let ci = attrs.case_insensitive();

    quote_spanned! { ty.span()=>
        |s| <#ty as ::clap::ArgEnum>::from_str(s, #ci).unwrap()
    }
}

fn gen_parsers(
    attrs: &Attrs,
    ty: &Sp<Ty>,
    field_name: &Ident,
    field: &Field,
    update: Option<&TokenStream>,
) -> TokenStream {
    use self::ParserKind::*;

    let parser = attrs.parser();
    let func = &parser.func;
    let span = parser.kind.span();
    let (value_of, values_of, mut parse) = match *parser.kind {
        FromStr => (
            quote_spanned!(span=> value_of),
            quote_spanned!(span=> values_of),
            func.clone(),
        ),
        TryFromStr => (
            quote_spanned!(span=> value_of),
            quote_spanned!(span=> values_of),
            quote_spanned!(func.span()=> |s| #func(s).unwrap()),
        ),
        FromOsStr => (
            quote_spanned!(span=> value_of_os),
            quote_spanned!(span=> values_of_os),
            func.clone(),
        ),
        TryFromOsStr => (
            quote_spanned!(span=> value_of_os),
            quote_spanned!(span=> values_of_os),
            quote_spanned!(func.span()=> |s| #func(s).unwrap()),
        ),
        FromOccurrences => (
            quote_spanned!(span=> occurrences_of),
            quote!(),
            func.clone(),
        ),
        FromFlag => (quote!(), quote!(), func.clone()),
    };

    let flag = *attrs.parser().kind == ParserKind::FromFlag;
    let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
    let name = attrs.cased_name();
    // Use `quote!` to give this identifier the same hygiene
    // as the `arg_matches` parameter definition. This
    // allows us to refer to `arg_matches` within a `quote_spanned` block
    let arg_matches = quote! { arg_matches };

    let field_value = match **ty {
        Ty::Bool => {
            if update.is_some() {
                quote_spanned! { ty.span()=>
                    *#field_name || #arg_matches.is_present(#name)
                }
            } else {
                quote_spanned! { ty.span()=>
                    #arg_matches.is_present(#name)
                }
            }
        }

        Ty::Option => {
            if attrs.is_enum() {
                if let Some(subty) = subty_if_name(&field.ty, "Option") {
                    parse = gen_arg_enum_parse(subty, &attrs);
                }
            }

            quote_spanned! { ty.span()=>
                #arg_matches.#value_of(#name)
                    .map(#parse)
            }
        }

        Ty::OptionOption => quote_spanned! { ty.span()=>
            if #arg_matches.is_present(#name) {
                Some(#arg_matches.#value_of(#name).map(#parse))
            } else {
                None
            }
        },

        Ty::OptionVec => quote_spanned! { ty.span()=>
            if #arg_matches.is_present(#name) {
                Some(#arg_matches.#values_of(#name)
                     .map(|v| v.map(#parse).collect())
                     .unwrap_or_else(Vec::new))
            } else {
                None
            }
        },

        Ty::Vec => {
            if attrs.is_enum() {
                if let Some(subty) = subty_if_name(&field.ty, "Vec") {
                    parse = gen_arg_enum_parse(subty, &attrs);
                }
            }

            quote_spanned! { ty.span()=>
                #arg_matches.#values_of(#name)
                    .map(|v| v.map(#parse).collect())
                    .unwrap_or_else(Vec::new)
            }
        }

        Ty::Other if occurrences => quote_spanned! { ty.span()=>
            #parse(#arg_matches.#value_of(#name))
        },

        Ty::Other if flag => quote_spanned! { ty.span()=>
            #parse(#arg_matches.is_present(#name))
        },

        Ty::Other => {
            if attrs.is_enum() {
                parse = gen_arg_enum_parse(&field.ty, &attrs);
            }

            quote_spanned! { ty.span()=>
                #arg_matches.#value_of(#name)
                    .map(#parse)
                    .unwrap()
            }
        }
    };

    if let Some(access) = update {
        quote_spanned! { field.span()=>
            if #arg_matches.is_present(#name) {
                #access
                *#field_name = #field_value
            }
        }
    } else {
        quote_spanned!(field.span()=> #field_name: #field_value )
    }
}

pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
    let fields = fields.iter().map(|field| {
        let attrs = Attrs::from_field(
            field,
            parent_attribute.casing(),
            parent_attribute.env_casing(),
        );
        let field_name = field.ident.as_ref().unwrap();
        let kind = attrs.kind();
        let arg_matches = quote! { arg_matches };
        match &*kind {
            Kind::ExternalSubcommand => {
                abort! { kind.span(),
                    "`external_subcommand` can be used only on enum variants"
                }
            }
            Kind::Subcommand(ty) => {
                let subcmd_type = match (**ty, sub_type(&field.ty)) {
                    (Ty::Option, Some(sub_type)) => sub_type,
                    _ => &field.ty,
                };
                let unwrapper = match **ty {
                    Ty::Option => quote!(),
                    _ => quote_spanned!( ty.span()=> .unwrap() ),
                };
                quote_spanned! { kind.span()=>
                    #field_name: {
                        <#subcmd_type as ::clap::Subcommand>::from_subcommand(#arg_matches.subcommand())
                        #unwrapper
                    }
                }
            }

            Kind::Flatten => quote_spanned! { kind.span()=>
                #field_name: ::clap::FromArgMatches::from_arg_matches(#arg_matches)
            },

            Kind::Skip(val) => match val {
                None => quote_spanned!(kind.span()=> #field_name: Default::default()),
                Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
            },

            Kind::Arg(ty) => gen_parsers(&attrs, ty, field_name, field, None),
        }
    });

    quote! {{
        #( #fields ),*
    }}
}

pub fn gen_updater(
    fields: &Punctuated<Field, Comma>,
    parent_attribute: &Attrs,
    use_self: bool,
) -> TokenStream {
    let fields = fields.iter().map(|field| {
        let attrs = Attrs::from_field(
            field,
            parent_attribute.casing(),
            parent_attribute.env_casing(),
        );
        let field_name = field.ident.as_ref().unwrap();
        let kind = attrs.kind();

        let access = if use_self {
            quote! {
                #[allow(non_snake_case)]
                let #field_name = &mut self.#field_name;
            }
        } else {
            quote!()
        };
        let arg_matches = quote! { arg_matches };

        match &*kind {
            Kind::ExternalSubcommand => {
                abort! { kind.span(),
                    "`external_subcommand` can be used only on enum variants"
                }
            }
            Kind::Subcommand(ty) => {
                let subcmd_type = match (**ty, sub_type(&field.ty)) {
                    (Ty::Option, Some(sub_type)) => sub_type,
                    _ => &field.ty,
                };

                let updater = quote_spanned!{ ty.span()=>
                    <#subcmd_type as ::clap::Subcommand>::update_from_subcommand(#field_name, subcmd);
                };

                let updater = match **ty {
                    Ty::Option => quote_spanned! { kind.span()=>
                        if let Some(#field_name) = #field_name.as_mut() {
                            #updater
                        } else {
                            *#field_name = <#subcmd_type as ::clap::Subcommand>::from_subcommand(
                                subcmd
                            )
                        }
                    },
                    _ => quote_spanned!{ kind.span()=>
                        #updater
                    }
                };

                quote_spanned! { kind.span()=>
                    {
                        let subcmd = #arg_matches.subcommand();
                        #access
                        #updater
                    }
                }
            }

            Kind::Flatten => quote_spanned! { kind.span()=> {
                    #access
                    ::clap::FromArgMatches::update_from_arg_matches(#field_name, #arg_matches);
                }
            },

            Kind::Skip(_) => quote!(),

            Kind::Arg(ty) => {
                gen_parsers(&attrs, ty, field_name, field, Some(&access))
            }
        }
    });

    quote! {
        #( #fields )*
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::generate_traffic;
use forge::{NetworkContext, NetworkTest, Result, Test};
use tokio::runtime::Runtime;

pub struct PerformanceBenchmarkWithFN;

impl Test for PerformanceBenchmarkWithFN {
    fn name(&self) -> &'static str {
        "performance benchmark with full nodes"
    }
}

impl NetworkTest for PerformanceBenchmarkWithFN {
    fn run<'t>(&self, ctx: &mut NetworkContext<'t>) -> Result<()> {
        let duration = ctx.global_job.duration;

        let all_fullnodes = ctx
            .swarm()
            .full_nodes()
            .map(|v| v.peer_id())
            .collect::<Vec<_>>();

        // Generate some traffic
        let txn_stat = generate_traffic(ctx, &all_fullnodes, duration, 1)?;
        ctx.report
            .report_txn_stats(self.name().to_string(), &txn_stat, duration);
        // ensure we meet the success criteria
        ctx.check_for_success(&txn_stat, &duration)?;
        let runtime = Runtime::new().unwrap();

        runtime.block_on(ctx.swarm().ensure_no_validator_restart())?;
        runtime.block_on(ctx.swarm().ensure_no_fullnode_restart())?;

        // TODO(skedia) enable them after resolving failure in
        // https://github.com/aptos-labs/aptos-core/runs/7904217460?check_suite_focus=true
        // Threshold of more than 12 CPU cores for 30% of the time
        // let cpu_threshold = MetricsThreshold::new(12, 30);
        // Threshold of more than 3 GB of memory for 30% of the time
        // let memory_threshold = MetricsThreshold::new(3 * 1024 * 1024 * 1024, 30);
        // runtime.block_on(ctx.swarm().ensure_healthy_system_metrics(
        //     start_timestamp as i64,
        //     end_timestamp as i64,
        //     SystemMetricsThreshold::new(cpu_threshold, memory_threshold),
        // ))?;
        Ok(())
    }
}
<commit_msg>[forge] Deflake main performance test<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::generate_traffic;
use forge::{NetworkContext, NetworkTest, Result, Test};

pub struct PerformanceBenchmarkWithFN;

impl Test for PerformanceBenchmarkWithFN {
    fn name(&self) -> &'static str {
        "performance benchmark with full nodes"
    }
}

impl NetworkTest for PerformanceBenchmarkWithFN {
    fn run<'t>(&self, ctx: &mut NetworkContext<'t>) -> Result<()> {
        let duration = ctx.global_job.duration;

        let all_fullnodes = ctx
            .swarm()
            .full_nodes()
            .map(|v| v.peer_id())
            .collect::<Vec<_>>();

        // Generate some traffic
        let txn_stat = generate_traffic(ctx, &all_fullnodes, duration, 1)?;
        ctx.report
            .report_txn_stats(self.name().to_string(), &txn_stat, duration);
        // ensure we meet the success criteria
        ctx.check_for_success(&txn_stat, &duration)?;

        // This is currently flaky in main, turn off to mitigate impact on devs
        // let runtime = Runtime::new().unwrap();
        // runtime.block_on(ctx.swarm().ensure_no_validator_restart())?;
        // runtime.block_on(ctx.swarm().ensure_no_fullnode_restart())?;

        // TODO(skedia) enable them after resolving failure in
        // https://github.com/aptos-labs/aptos-core/runs/7904217460?check_suite_focus=true
        // Threshold of more than 12 CPU cores for 30% of the time
        // let cpu_threshold = MetricsThreshold::new(12, 30);
        // Threshold of more than 3 GB of memory for 30% of the time
        // let memory_threshold = MetricsThreshold::new(3 * 1024 * 1024 * 1024, 30);
        // runtime.block_on(ctx.swarm().ensure_healthy_system_metrics(
        //     start_timestamp as i64,
        //     end_timestamp as i64,
        //     SystemMetricsThreshold::new(cpu_threshold, memory_threshold),
        // ))?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate capnp;

fn try_go() -> ::capnp::Result<()> {
    let segment: &[::capnp::Word] = &[
        capnp_word!(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00),
        capnp_word!(0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00),
    ];

    let segments = &[segment];
    let segment_array = capnp::message::SegmentArray::new(segments);
    let message = capnp::message::Reader::new(segment_array, Default::default());
    let root: capnp::any_pointer::Reader = try!(message.get_root());

    // At one point, this failed with:
    // error: pointer computed at offset 33554448, outside bounds of allocation Runtime(702) which has size 16
    try!(root.target_size());

    Ok(())
}

pub fn main() {
    let _ = try_go();
}
<commit_msg>assert that total_size() returns an Err<commit_after>#[macro_use]
extern crate capnp;

fn try_go() -> ::capnp::Result<()> {
    let segment: &[::capnp::Word] = &[
        capnp_word!(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00),
        capnp_word!(0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00),
    ];

    let segments = &[segment];
    let segment_array = capnp::message::SegmentArray::new(segments);
    let message = capnp::message::Reader::new(segment_array, Default::default());
    let root: capnp::any_pointer::Reader = try!(message.get_root());

    // At one point, this failed with:
    // error: pointer computed at offset 33554448, outside bounds of allocation Runtime(702) which has size 16
    let result = root.target_size();

    assert!(result.is_err()); // pointer out-of-bounds error

    Ok(())
}

pub fn main() {
    let _ = try_go();
}
<|endoftext|>


<commit_before>use std::time::Instant;

/// A metrics counter storing only latest `N` records.
pub struct MetricsCounter<const N: usize> {
    /// Slots to store metrics.
    slots: [(usize, Instant); N],
    /// The slot of the oldest record.
    /// Also the next slot to store the new record.
    index: usize,
}

impl<const N: usize> MetricsCounter<N> {
    /// Creates a new counter with an initial value.
    pub fn new(init: usize, init_at: Instant) -> Self {
        debug_assert!(N > 0, "number of slots must be greater than zero");
        Self {
            slots: [(init, init_at); N],
            index: 0,
        }
    }

    /// Adds record to the counter.
    pub fn add(&mut self, data: usize, added_at: Instant) {
        self.slots[self.index] = (data, added_at);
        self.index = (self.index + 1) % N;
    }

    /// Calculates per-second average rate of all slots.
    pub fn rate(&self) -> f32 {
        let latest = self.slots[self.index.checked_sub(1).unwrap_or(N - 1)];
        let oldest = self.slots[self.index];
        let duration = (latest.1 - oldest.1).as_secs_f32();
        let avg = (latest.0 - oldest.0) as f32 / duration;
        if f32::is_nan(avg) {
            0f32
        } else {
            avg
        }
    }
}

#[cfg(test)]
mod tests {
    use super::MetricsCounter;
    use std::time::{Duration, Instant};

    #[test]
    fn counter() {
        let now = Instant::now();
        let mut counter = MetricsCounter::<3>::new(0, now);
        assert_eq!(counter.rate(), 0f32);
        counter.add(1, now + Duration::from_secs(1));
        assert_eq!(counter.rate(), 1f32);
        counter.add(4, now + Duration::from_secs(2));
        assert_eq!(counter.rate(), 2f32);
        counter.add(7, now + Duration::from_secs(3));
        assert_eq!(counter.rate(), 3f32);
        counter.add(12, now + Duration::from_secs(4));
        assert_eq!(counter.rate(), 4f32);
    }

    #[test]
    #[should_panic(expected = "number of slots must be greater than zero")]
    fn counter_zero_slot() {
        let _counter = MetricsCounter::<0>::new(0, Instant::now());
    }
}
<commit_msg>Fix problem with metrics test.<commit_after>use std::time::Instant;

/// A metrics counter storing only latest `N` records.
pub struct MetricsCounter<const N: usize> {
    /// Slots to store metrics.
    slots: [(usize, Instant); N],
    /// The slot of the oldest record.
    /// Also the next slot to store the new record.
    index: usize,
}

impl<const N: usize> MetricsCounter<N> {
    /// Creates a new counter with an initial value.
    pub fn new(init: usize, init_at: Instant) -> Self {
        assert!(N > 0, "number of slots must be greater than zero");
        Self {
            slots: [(init, init_at); N],
            index: 0,
        }
    }

    /// Adds record to the counter.
    pub fn add(&mut self, data: usize, added_at: Instant) {
        self.slots[self.index] = (data, added_at);
        self.index = (self.index + 1) % N;
    }

    /// Calculates per-second average rate of all slots.
    pub fn rate(&self) -> f32 {
        let latest = self.slots[self.index.checked_sub(1).unwrap_or(N - 1)];
        let oldest = self.slots[self.index];
        let duration = (latest.1 - oldest.1).as_secs_f32();
        let avg = (latest.0 - oldest.0) as f32 / duration;
        if f32::is_nan(avg) {
            0f32
        } else {
            avg
        }
    }
}

#[cfg(test)]
mod tests {
    use super::MetricsCounter;
    use std::time::{Duration, Instant};

    #[test]
    fn counter() {
        let now = Instant::now();
        let mut counter = MetricsCounter::<3>::new(0, now);
        assert_eq!(counter.rate(), 0f32);
        counter.add(1, now + Duration::from_secs(1));
        assert_eq!(counter.rate(), 1f32);
        counter.add(4, now + Duration::from_secs(2));
        assert_eq!(counter.rate(), 2f32);
        counter.add(7, now + Duration::from_secs(3));
        assert_eq!(counter.rate(), 3f32);
        counter.add(12, now + Duration::from_secs(4));
        assert_eq!(counter.rate(), 4f32);
    }

    #[test]
    #[should_panic(expected = "number of slots must be greater than zero")]
    fn counter_zero_slot() {
        let _counter = MetricsCounter::<0>::new(0, Instant::now());
    }
}
<|endoftext|>